ast@cs.vu.nl (Andy Tanenbaum) (05/30/88)
Here is a listing of new files in commands:
-rw-r--r-- 1 ast 1615 May 16 15:03 ascii.c
-rw-r--r-- 1 ast 14134 May 16 15:03 badblocks.c
-rw-r--r-- 1 ast 749 May 16 15:03 chgrp.c
-rw-r--r-- 1 ast 38532 May 16 15:03 compress.c
-rw-r--r-- 1 ast 3885 May 16 15:03 diskcheck.c
-rw-r--r-- 1 ast 42036 May 16 15:03 ed.c
-rw-r--r-- 1 ast 693 May 16 15:03 factor.c
-rw-rw-rw- 1 ast 5443 May 29 15:13 fgrep.c
-rw-r--r-- 1 ast 3073 May 16 15:03 file.c
-rw-r--r-- 1 ast 7542 May 16 15:04 lorder.c
-rw-r--r-- 1 ast 2025 May 16 15:04 prep.c
-rw-r--r-- 1 ast 441 May 16 15:04 readall.c
-rw-r--r-- 1 ast 45735 May 16 15:04 sed.c
-rw-r--r-- 1 ast 4052 May 16 15:04 strings.c
-rw-r--r-- 1 ast 6938 May 16 15:04 treecmp.c
-rw-r--r-- 1 ast 6563 May 16 15:04 tsort.c
-rw-r--r-- 1 ast 437 May 16 15:04 tty.c
-rw-r--r-- 1 ast 279 May 16 15:04 whoami.c
I believe all of these have been posted. Correct me if I am wrong.
Below are some of the smaller ones.
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'ascii.c'
sed 's/^X//' > 'ascii.c' << '+ END-OF-FILE ''ascii.c'
X/* ascii - list lines with/without ASCII chars Author: Andy Tanenbaum */
X
X#define BUFSIZE 30000
X
Xchar buf[BUFSIZE]; /* input buffer */
Xchar *next; /* start of line */
Xchar *limit; /* last char of line */
Xint count; /* # chars in buffer not yet processed */
Xint used; /* how many chars used at start of buf */
Xint eof; /* set when eof seen */
Xint nflag; /* set if -n option given */
Xint exitstatus; /* 0 if pure ASCII, 1 if junk seen */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X int yes;
X char *p;
X
X if (argc > 3) usage();
X if (strcmp(argv[1], "-n") == 0) nflag++;
X
X if ((argc == 2 && nflag == 0) || argc == 3) {
X close(0);
X if (open(argv[argc-1], 0) < 0) {
X std_err("ascii: cannot open ");
X std_err(argv[1]);
X std_err("\n");
X exit(1);
X }
X }
X
X while(eof == 0) {
X yes = getline();
X if (nflag != yes) output();
X next = limit;
X }
X exit(exitstatus);
X}
X
Xint getline()
X{
X char *p, c;
X int asc = 1;
X
X if (count == 0) load();
X if (eof) exit(exitstatus);
X
X p = next;
X while (count > 0) {
X c = *p++;
X if (c & 0200) {asc = 0; exitstatus = 1;}
X count--;
X if (c == '\n') {
X limit = p;
X return(asc);
X }
X if (count == 0) {
X /* Move the residual characters to the bottom of buf */
X used = &buf[BUFSIZE] - next;
X copy(next, buf, used);
X load();
X p = &buf[used];
X used = 0;
X if (eof) return(asc);
X }
X }
X}
X
Xload()
X{
X count = read(0, &buf[used], BUFSIZE-used);
X if (count <= 0) eof = 1;
X next = buf;
X}
X
Xoutput()
X{
X write(1, next, limit-next);
X}
X
Xusage()
X{
X std_err("Usage: ascii [-n] file\n");
X exit(1);
X}
X
Xcopy(s,d,ct)
Xregister char *s, *d;
Xint ct;
X{
X while (ct--) *d++ = *s++;
X}
X
+ END-OF-FILE ascii.c
chmod 'u=rw,g=r,o=r' 'ascii.c'
set `wc -c 'ascii.c'`
count=$1
case $count in
1615) :;;
*) echo 'Bad character count in ''ascii.c' >&2
echo 'Count should be 1615' >&2
esac
echo Extracting 'badblocks.c'
sed 's/^X//' > 'badblocks.c' << '+ END-OF-FILE ''badblocks.c'
X/* badblocks - collect bad blocks in a file Author: Jacob Bunschoten */
X
X/* Usage "badblocks block_special" */
X
X/*
X * This program is written to handle BADBLOCKS on a hard or floppy disk.
X * The program asks for block_numbers. These numbers can be obtained with
X * the program disk_check; written by A. Tanenbaum. It then creates a
X * file on the disk containing up to 7 bad blocks.
X *
X * BUG:
X *
X * When the zone_size > block_size it can happen that
X * the zone is already allocated. This means some
X * file is using this zone and may use all the blocks including
X * the bad one. This can be cured by inspecting the zone_bitmap
X * (is already done) and change the file if this zone is used.
X * This means that another zone must be allocated and
X * the inode wich claims this zone must be found and changed.
X *
X */
X
X#include <sys/stat.h>
X#include <stdio.h>
X#include <minix/type.h>
X
X
X/* Super block table.
X *
X * The disk layout is:
X *
X * Item # block
X * boot block 1
X * super block 1
X * inode map s_imap_blocks
X * zone map s_zmap_blocks
X * inodes (s_ninodes + 1 + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK
X * unused
X * data zones (s_nzones - s_firstdatazone) << s_log_zone_size
X *
X */
X
X
Xstruct super_block {
X inode_nr s_ninodes; /* # usable inodes on the minor device */
X zone_nr s_nzones; /* total device size, including bit maps etc */
X unshort s_imap_block; /* # of block used by inode bit map */
X unshort s_zmap_block; /* # of block used by zone bit map */
X zone_nr s_firstdatazone; /* number of first data zone */
X short int s_log_zone_size; /* log2 of block/zone */
X file_pos s_max_size; /* maximum file size on this device */
X int s_magic; /* magic number to recognize super-block */
X} super_block;
X
X#define SUPER_MAGIC 0x137F
X
X
X#define NR_ZONE_NUMS 9
X#define NR_DZONE_NUMS (NR_ZONE_NUMS -2 )
X
Xstruct d_inode { /* disk inode. */
X mask_bits i_mode; /* file type, protection, etc. */
X uid i_uid; /* user id of the file's owner */
X file_pos i_size; /* current file size in bytes */
X real_time i_modtime; /* when was file data last changed */
X gid i_gid; /* group number */
X links i_nlinks; /* how many links to this file */
X zone_nr i_zone[NR_ZONE_NUMS]; /* blocks nums for direct, ind, and dbl ind */
X} d_inode;
X
X
X
X#define OK 0
X#define NOT_OK 1
X#define QUIT 2
X
X#define READ 0
X#define WRITE 1
X
X#define HARMLESS 0
X#define DIR_CREATED 1
X#define DEV_MOUNTED 2
X#define FILE_EXISTS 3
X#define SUCCESS 4
X
X#define BLOCK_SIZE 1024
X#define INODES_PER_BLOCK (BLOCK_SIZE/sizeof(struct d_inode))
X
X#define INODE_SIZE (sizeof (struct d_inode) )
X#define SUPER_SIZE (sizeof (struct super_block) )
X#define INT_SIZE (sizeof (int) )
X
X /* ====== globals ======= */
X
Xchar *dev_name;
Xchar f_name[] = ".Bad_XXXXXX";
Xchar file_name[50];
Xchar dir_name[] = "/tmpXXXXXX";
X
Xint block[NR_DZONE_NUMS+1]; /* last block contains zero */
X
XFILE *fp, *fopen();
Xint fd;
Xint eofseen; /* set if '\n' seen */
X
Xstruct stat stat_buf;
Xstruct d_inode *ip;
Xstruct super_block *sp;
X
Xextern char *strcat();
X#ifdef DEBUG
Xextern char *itoa();
Xchar *utobin();
X#endif
X
X /* ====== super block routines ======= */
X
Xrw_super(flag) /* read or write a superblock */
X{
X int rwd;
X
X lseek(fd, 0L, 0); /* rewind */
X lseek(fd, (long) BLOCK_SIZE, 0); /* seek */
X
X if (flag == READ )
X rwd = read( fd, sp, SUPER_SIZE );
X else
X rwd = write (fd, sp, SUPER_SIZE );
X if (rwd != SUPER_SIZE ) { /* ok ? */
X printf("Bad %s in get_super() (should be %d is %d)\n",
X flag == READ ? "read" : "write",
X SUPER_SIZE, rwd );
X done(DIR_CREATED);
X }
X}
X
Xget_super()
X /* get super_block. global pointer sp is used */
X{
X rw_super(READ);
X
X if (sp->s_magic != SUPER_MAGIC) { /* check */
X printf("Bad magic number in super_block?!\n");
X done(DIR_CREATED);
X }
X#ifdef DEBUG
X /* give some information of the super_block */
X
X printf("# Inodes %d\n",sp->s_ninodes);
X printf("# Zones %d\n",sp->s_nzones);
X printf("# inode map block %d\n",sp->s_imap_block);
X printf("# zone map block %d\n",sp->s_zmap_block);
X printf(" Firstdatazone %d\n\n",sp->s_firstdatazone);
X#endif
X}
X
X
Xput_super()
X{
X rw_super(WRITE);
X}
X
X /* ========== inode routines =========== */
X
Xrw_inode(stat_ptr, rw_mode)
X struct stat *stat_ptr;
X{
X int rwd, i_num;
X long blk, offset;
X
X
X i_num = stat_ptr->st_ino;
X
X blk = (long ) (2 + sp->s_imap_block + sp->s_zmap_block);
X blk += (long) ((i_num -1 ) / INODES_PER_BLOCK );
X blk *= (long) (BLOCK_SIZE); /* this block */
X
X offset = (long) ((i_num -1 ) % INODES_PER_BLOCK);
X offset *= (long) (INODE_SIZE); /* and this offset */
X
X lseek(fd, 0L, 0); /* rewind */
X lseek(fd, (long) (blk + offset), 0); /* seek */
X
X /* pointer is at the inode */
X if (rw_mode == READ) { /* read it */
X rwd = read(fd, ip, INODE_SIZE );
X } else { /* write it */
X rwd = write (fd, ip, INODE_SIZE );
X }
X if (rwd != INODE_SIZE ) { /* ok ? */
X printf("Bad %s in get_inode()\n",(rw_mode == READ)? "read":
X "write");
X done(DIR_CREATED);
X }
X
X}
X
Xget_inode( stat_ptr)
X struct stat *stat_ptr;
X{
X
X#ifdef DEBUG
X int tst;
X#endif
X int cnt;
X
X rw_inode(stat_ptr, READ);
X
X#ifdef DEBUG
X tst = 0;
X printf("\ni_zone[0]=%d, st_rdev=%d\n", (int) ip->i_zone[0],
X (int) stat_ptr->st_rdev);
X printf("File size %D\n",(long) ip->i_size);
X for (cnt =0 ; cnt < NR_ZONE_NUMS; cnt++ )
X if (ip->i_zone[cnt] != 0 ) {
X tst = 1;
X printf("zone[%d] contains %d\n",cnt,
X (int) ip->i_zone[cnt]);
X }
X if ( tst ) {
X printf("Possible wrong inode. Inode must be clean");
X done(DIR_CREATED);
X }
X printf("\n");
X#endif
X for (cnt=0; cnt < NR_ZONE_NUMS; cnt++)
X ip->i_zone[cnt] = 0; /* Just to be safe */
X}
X
Xput_inode(stat_ptr)
X struct stat *stat_ptr;
X{
X rw_inode(stat_ptr, WRITE);
X}
X
X
X /* ============== main program ================= */
Xmain(argc, argv)
X char *argv[];
X{
X int cnt, blk_nr, finished;
X struct stat dev_stat;
X
X sp = &super_block;
X ip = &d_inode;
X
X if (argc != 2) {
X fprintf(stderr,"Usage: %s block_special\n",argv[0]);
X done(HARMLESS);
X }
X
X /* Do some test. */
X if (geteuid()) {
X printf("Sorry, not in superuser mode \n");
X printf("Set_uid bit must be on or you must become super_user\n");
X done(HARMLESS);
X }
X
X dev_name = argv[1];
X mktemp(dir_name);
X#ifdef DEBUG
X printf("Dir_name is %s\n",dir_name);
X#endif
X if (mknod(dir_name,040777,0) == -1) {
X fprintf(stderr,"%s is already used in system\n",dir_name);
X done(HARMLESS);
X }
X
X /* Mount device. This call may fail. */
X mount(dev_name, dir_name, 0);
X /* succes. dev was mounted, try to umount */
X
X /* Umount device. Playing with the file system while
X * other processes have access to this device
X * is asking for trouble
X */
X if (umount(dev_name) == -1 ) {
X printf("Could not umount device %s.\n",dev_name);
X done(HARMLESS);
X }
X
X
X mktemp(f_name);
X /* create "/tmpXXXXpid/.BadXXpid" */
X strcat(file_name, dir_name);
X strcat(file_name, "/");
X strcat(file_name, f_name);
X
X if (mount(dev_name, dir_name, 0) == -1) { /* this call should work */
X fprintf(stderr,"Could not mount device anymore\n");
X done(HARMLESS);
X }
X if (stat( file_name, &stat_buf) != -1 ) {
X printf("File %s does already exists\n",file_name);
X done(DEV_MOUNTED);
X }
X if ( (fp = fopen( file_name, "w" )) == NULL) {
X printf("Can not create file %s\n", file_name);
X done(DEV_MOUNTED);
X }
X chmod(file_name, 0); /* "useless" file */
X if (stat( file_name, &stat_buf) == -1 ) {
X printf("What? Second call from stat failed\n");
X done(FILE_EXISTS);
X }
X /* stat buf must be safed. We can now calculate the inode on disk */
X fclose(fp);
X
X /* ===== the badblock file is created ===== */
X
X if (umount(dev_name) == -1 ) {
X printf("Can not umount device anymore??? \n");
X done(DIR_CREATED);
X }
X
X if ( (fd = open(dev_name, 2)) == -1 ) {
X printf("Can not open device %s\n",dev_name);
X done(DEV_MOUNTED);
X }
X if (fstat(fd, &dev_stat) == -1 ) {
X printf("fstat on device %s failed\n",dev_name);
X done(DEV_MOUNTED);
X }
X if ( (dev_stat.st_mode & S_IFMT ) != S_IFBLK ) {
X printf("Device \"%s\" is not a block_special.\n",dev_name);
X done(DEV_MOUNTED);
X }
X
X get_super();
X if (sp->s_log_zone_size ) {
X printf("Block_size != zone_size.");
X printf("This program can not handle it\n");
X done(DIR_CREATED);
X }
X get_inode(&stat_buf);
X
X for(finished = 0; !finished; ) {
X printf("Give up to %d bad block numbers separated by spaces\n",
X NR_DZONE_NUMS);
X reset_blks();
X cnt = 0; /* cnt keep track of the zone's */
X while (cnt < NR_DZONE_NUMS ) {
X int tst;
X
X blk_nr = rd_num();
X tst = blk_ok(blk_nr);
X /* test if this block is free */
X if (tst == OK ) {
X cnt++;
X save_blk( blk_nr );
X }
X else if (tst == QUIT )
X break;
X }
X show_blks();
X if (!cnt)
X done(FILE_EXISTS);
X switch( ok("All these blocks ok <y/n/q> (y:Device will change) ") ) {
X case OK: finished = 1; break;
X case NOT_OK: break;
X case QUIT: done(FILE_EXISTS);
X }
X }
X
X modify(cnt);
X close(fd); /* free device */
X done(FILE_EXISTS);
X}
X
Xmodify(nr_blocks)
X{
X int i;
X
X if (nr_blocks == 0) return;
X for (i=0; i<nr_blocks; i++) {
X set_bit(block[i]);
X ip->i_zone[i] = block[i];
X }
X ip->i_size = (long) (BLOCK_SIZE * nr_blocks); /* give file size */
X put_inode(&stat_buf); /* save the inode on disk */
X put_super(); /* bit_maps too */
X}
X
X
Xstatic blk_cnt=0;
X
Xsave_blk(blk_num)
X int blk_num;
X{
X block[blk_cnt++] = blk_num;
X}
X
Xreset_blks()
X{
X int i;
X
X for (i=0;i<=NR_DZONE_NUMS;i++)
X block[i] = 0; /* Note: Last block_number is set to zero */
X blk_cnt =0;
X}
X
Xshow_blks()
X{
X int i;
X
X for (i=0; i<blk_cnt; i++)
X printf("Block[%d] = %d\n",i,block[i]);
X}
X
Xblk_is_used(blk_num)
X int blk_num;
X{ /* return TRUE(1) if used */
X int i;
X
X for (i=0; block[i] && block[i] != blk_num; i++);
X return (block[i] != 0)? 1: 0;
X}
X
X
X /* ===== bitmap handling ====== */
X
X#define BIT_MAP_SHIFT 13
X#define INT_BITS (INT_SIZE << 3)
X
Xblk_ok(num) /* is this zone free (y/n) */
X int num;
X{
X long blk_offset;
X int rd;
X int block, offset, words, bit, tst_word;
X int z_num;
X
X if ( num < 0 ) {
X return QUIT; /* negative number is not allowed */
X }
X if (blk_is_used (num)) {
X printf("Duplicate block (%d) given\n",num);
X return NOT_OK;
X }
X /* assumption zone_size == block_size */
X
X z_num = num + 1 - sp->s_firstdatazone; /* account offset */
X
X /* calculate the word in the bitmap */
X block = z_num >> BIT_MAP_SHIFT; /* which block */
X offset = z_num - (block << BIT_MAP_SHIFT); /* offset */
X words = offset/INT_BITS; /* which word */
X
X blk_offset = (long) (2 + sp->s_imap_block); /* zone map */
X blk_offset *= (long) BLOCK_SIZE; /* of course in block */
X blk_offset += (long) (words * INT_SIZE) ; /* offset */
X
X
X lseek(fd, 0L, 0); /* rewind */
X lseek(fd, blk_offset, 0); /* set pointer at word */
X
X rd = read(fd, &tst_word, INT_SIZE );
X if (rd != INT_SIZE ) {
X printf("Read error in bitmap\n");
X done(DIR_CREATED);
X }
X
X /* we have the tst_word, check if bit was off */
X bit = offset % INT_BITS;
X
X if ( ((tst_word >> bit )&01 ) == 0) /* free */
X return OK;
X else {
X printf("Bad number %d. ",num);
X printf("This zone (block) is marked in bitmap\n");
X return NOT_OK;
X }
X}
X
Xset_bit(num) /* write in the bitmap */
X int num;
X{
X int rwd;
X long blk_offset;
X int block, offset, words, tst_word, bit;
X int z_num;
X char wrd_str[17], bit_str[17];
X
X z_num = num + 1 - sp->s_firstdatazone;
X
X block = z_num >> BIT_MAP_SHIFT; /* which block */
X offset = z_num - (block << BIT_MAP_SHIFT); /* offset in block */
X words = offset/INT_BITS; /* which word */
X
X blk_offset = (long) (2 + sp->s_imap_block) ;
X blk_offset *= (long) BLOCK_SIZE ;
X blk_offset += (long) (words * INT_SIZE);
X
X
X lseek(fd, 0L, 0); /* rewind */
X lseek(fd, blk_offset, 0);
X
X rwd = read(fd, &tst_word, INT_SIZE );
X if (rwd != INT_SIZE ) {
X printf("Read error in bitmap\n");
X done(DEV_MOUNTED);
X }
X
X bit = offset % INT_BITS;
X if ( ((tst_word >> bit) & 01 ) == 0) { /* free */
X lseek(fd, 0L, 0); /* rewind */
X lseek(fd, blk_offset, 0);
X#ifdef DEBUG
X printf("blk= %D ", blk_offset);
X printf("block= %D ",(long) blk_offset/BLOCK_SIZE);
X printf("offset= %d\n",offset);
X printf("\t\tword= %s ", utobin(tst_word, wrd_str));
X printf("bit_nr = %d\n", bit);
X#endif
X tst_word |= (1 << bit); /* not free anymore */
X#ifdef DEBUG
X printf("The word is now %s\n", utobin(tst_word, wrd_str) );
X#endif
X rwd = write (fd, &tst_word, INT_SIZE );
X if (rwd != INT_SIZE ) {
X printf("Bad write in zone map\n");
X printf("Check file system \n");
X done(DIR_CREATED);
X }
X return;
X }
X printf("Bit was on block %d; ==> internal error\n",num);
X done(DIR_CREATED);
X}
X
X /* ======= interactive interface ======= */
X
Xrd_num() /* read a number from stdin */
X{
X static num;
X int c;
X
X if (eofseen) return(-1);
X do {
X c = getchar();
X if (c == EOF || c == '\n') return(-1);
X } while ( c != '-' && (c < '0' || c > '9') );
X
X if (c == '-') {
X printf("Block numbers must be positive\n");
X exit(1);
X }
X num = 0;
X while (c >= '0' && c <= '9' ) {
X num *= 10;
X num += c - '0';
X c = getchar();
X if (c == '\n') eofseen = 1;
X }
X return num;
X}
X
X
X
Xok(str)
Xchar *str;
X{
X int c;
X
X for (;;) {
X printf("%s",str);
X while ( ( c = getchar() ) != EOF &&
X c != 'y' && c != 'n' && c != 'q' )
X if (c != '\n' )
X printf(" Bad character %c\n", (char) c);
X switch ( c ) {
X case EOF:
X return QUIT;
X case 'y':
X return OK;
X case 'n':
X return NOT_OK;
X case 'q':
X return QUIT;
X#ifdef DEBUG
X default:
X printf("Unknown option %c\n\t",*c);
X#endif
X }
X printf("\n");
X }
X}
X
X
Xdone(nr)
Xint nr;
X{
X switch(nr) {
X case FILE_EXISTS: unlink(file_name);
X case SUCCESS:
X case DEV_MOUNTED: umount(dev_name);
X case DIR_CREATED: unlink(dir_name);
X case HARMLESS: ;
X }
X sync();
X exit(nr == SUCCESS ? 0: 1);
X}
X
X#ifdef DEBUG
X /* ===== print integer in binairy format ====== */
X
Xchar *chtobin(num, str)
X /* char to binair. Convert the numerical value num
X to a binairy string (0|1)
X str[] is at least 8 chars wide
X */
X unsigned char num;
X char *str;
X{
X int i;
X
X for (i=7; i>=0; i-- ) {
X str[i] = (num&01)? '1':'0';
X num >>= 1;
X num &= 0xFF;
X }
X str[8] = '\0';
X return str;
X}
X
X
Xchar *utobin(num, str)
X /* unsigned to binair. Used to print a binairy word */
X unsigned num;
X char *str;
X{
X chtobin( (num >> 8 ) & 0xFF, str);
X chtobin( num & 0xFF , &str[8]);
X return str;
X}
X#endif DEBUG
+ END-OF-FILE badblocks.c
chmod 'u=rw,g=r,o=r' 'badblocks.c'
set `wc -c 'badblocks.c'`
count=$1
case $count in
14134) :;;
*) echo 'Bad character count in ''badblocks.c' >&2
echo 'Count should be 14134' >&2
esac
echo Extracting 'factor.c'
sed 's/^X//' > 'factor.c' << '+ END-OF-FILE ''factor.c'
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X/* Factor a number */
X
X long i, n, flag = 0, first(), atol();
X
X if (argc != 2 || (n = atol(argv[1])) < 2) {
X printf("Usage: factor n (2 <= n < 2**31)\n");
X exit(1);
X }
X if (n == 2) {
X printf("2 is a prime\n");
X exit(0);
X }
X
X while (1) {
X i = first(n);
X if (i == 0) {
X if (flag == 0)
X printf("%D is a prime\n", n);
X else
X printf("%D\n", n);
X exit(0);
X }
X printf("%D ", i);
X n = n / i;
X flag = 1;
X }
X}
X
X
Xlong first(k)
Xlong k;
X{
X/* Return the first factor of k. If it is a prime, return 0; */
X
X long i;
X
X if (k == 2) return(0);
X if (k % 2 == 0) return(2);
X for (i = 3; i <= k/3; i+=2)
X if (k % i == 0) return(i);
X return(0);
X}
+ END-OF-FILE factor.c
chmod 'u=rw,g=r,o=r' 'factor.c'
set `wc -c 'factor.c'`
count=$1
case $count in
693) :;;
*) echo 'Bad character count in ''factor.c' >&2
echo 'Count should be 693' >&2
esac
echo Extracting 'fgrep.c'
sed 's/^X//' > 'fgrep.c' << '+ END-OF-FILE ''fgrep.c'
X/* fgrep - fast grep Author: Jan Christiaan van Winkel */
X
X#include <stdio.h>
X
Xint argc;
Xchar **argv;
Xint stringlen,offset,boundary;
Xint i,j,k,count,linum;
Xchar stringarea[1024];
Xint strptr;
Xint strcount;
Xunsigned char tbl[32][256];
Xint lengths[32];
Xchar *tststring[32];
Xchar string[512];
Xchar tmpstring[512];
Xint vflag,cflag,nofname,hadone,lflag,nflag,sflag,hflag,eflag,fflag;
Xint fp;
X
Xmain(oargc,oargv)
Xint oargc;
Xchar * oargv[];
X
X{
X int find();
X void exparg();
X void getargs();
X void maktbl();
X void gotone();
X
X argc=oargc;
X argv=oargv;
X getargs();
X
X fp=0;
X if (i>=argc-2 || hflag) /* stdin, 1 file, hflag */
X nofname=1;
X
X do {
X if(i<argc && (fp=open(argv[i],0)) <0) {
X fprintf(stderr, "%s: can't open %s\n",argv[0],argv[i]);
X continue;
X }
X count=0;
X linum=0;
X
X while ((stringlen=getlin(fp,string,512))!=EOF) {
X linum++;
X for (j=0; j<strcount; j++) {
X if (find(tststring[j],tbl[j],lengths[j])!=vflag) {
X gotone();
X break;
X }
X }
X if (lflag && count) break;
X }
X close(fp);
X
X if (cflag) {
X printf("%s: %d times\n",argv[i],count);
X }
X
X if (lflag && count>0) {
X printf("%s\n",argv[i]);
X }
X } while (++i<argc);
X
X fflush(stdout);
X if (hadone) exit(0); else exit(1);
X}
X
Xvoid getargs()
X{
X int tmp;
X for (i=1; i< argc && argv[i][0]=='-'; i++) {
X switch (argv[i][1]) {
X case 'e':
X eflag=1;
X if (fflag) {
X fprintf(stderr,"%s: can't have -e and -f at the same time\n",argv[0]);
X exit(2);
X }
X if (i<argc-1) {
X i++;
X tststring[0]=argv[i];
X strcount=1;
X } else {
X fprintf(stderr,"%s: not enough arguments\n");
X exit(2);
X }
X break;
X case 'v':
X vflag=1;
X break;
X case 'c':
X cflag=1;
X break;
X case 'l':
X lflag=1;
X break;
X case 's':
X sflag=1;
X break;
X case 'h':
X hflag=1;
X break;
X case 'n':
X nflag=1;
X break;
X case 'f':
X fflag=1;
X if (eflag) {
X fprintf(stderr,"%s: can't have -e and -f at the same time\n",argv[0]);
X exit(2);
X }
X if (i>=argc-1) {
X fprintf(stderr,"%s: not enough arguments\n");
X exit(2);
X } else {
X i++;
X if ((fp=open(argv[i],0))<0) {
X fprintf(stderr,"%s: can't open %s\n",argv[0],argv[i]);
X exit(2);
X }
X strcount=0;
X while ((tmp=getlin(fp,&stringarea[strptr],128))!=EOF) {
X tststring[strcount++] = &stringarea[strptr];
X strptr = strptr+tmp+1;
X if (strptr>=1024-128 || strcount==32) {
X fprintf(stderr,"%s: not enough room\n",argv[0]);
X exit(2);
X }
X }
X close(fp);
X }
X break;
X default:
X fprintf(stderr,"%s: invalid command line option\n",argv[0]);
X exit(2);
X break;
X }
X if (cflag && lflag) {
X fprintf(stderr,"%s: cannot have -l and -c at the same time\n",argv[0]);
X exit(2);
X }
X }
X
X if (! eflag && ! fflag) {
X if (i<argc) {
X tststring[0]=argv[i++];
X strcount=1;
X } else {
X fprintf(stderr,"%s: no search string.\n",argv[0]);
X exit(2);
X }
X }
X
X for (j=0; j<strcount; j++) {
X if (tststring[j][0]=='"') {
X count=strlen(tststring[j]);
X movmem(&tststring[j][1],tststring[j],count-2);
X tststring[j][count-2]='\0';
X }
X maktbl(tststring[j],tbl[j],&lengths[j]);
X }
X}
X
X
Xmovmem(src, dst, len)
Xchar *src, *dst;
Xint len;
X{
X while (len--) *dst++ = *src++;
X}
X
Xsetmem(mem, len, filler)
Xchar *mem;
Xint len;
Xchar filler;
X{
X while (len--) *mem++ = filler;
X}
X
X
Xint find(findword,table,wordlen)
Xunsigned char * findword;
Xunsigned char * table;
Xint wordlen;
X{
X auto int lastletter,tmp;
X
X boundary=stringlen-wordlen;
X lastletter=wordlen-1;
X offset=0;
X while (offset<=boundary) {
X tmp=table[string[offset+lastletter]];
X if (tmp) {
X offset+=tmp;
X } else {
X for(k=lastletter-1; k>=0; k--) {
X if ((string[k+offset])!=findword[k]) {
X offset++;
X break;
X }
X }
X if (k<0) return (1);
X }
X }
X return(0);
X}
X
X
Xvoid maktbl(findword,table,wordlen)
Xunsigned char * findword;
Xunsigned char * table;
Xint * wordlen;
X{
X
X auto int i,len;
X
X *wordlen=len=strlen(findword);
X setmem(table,256,len);
X for (i=0; i<len; i++)
X table[findword[i]]=len-i-1;
X}
X
X
Xvoid gotone()
X{
X hadone=1;
X
X if (cflag || lflag || sflag)
X {
X count++;
X return;
X }
X
X if (! nofname) printf("%s:",argv[i]);
X
X if (nflag) printf("%d:",linum);
X
X printf("%s\n",string);
X}
X
X
Xint getlin(infile, buf, maxlen)
Xint infile;
Xchar *buf;
Xint maxlen;
X{
X static char mybuf[2048];
X static char * low;
X static char * high;
X
X auto int status;
X auto char * p=buf;
X auto int endline;
X
X *p='\0';
X maxlen--;
X while (1)
X {
X endline=0;
X while (low < high && ! endline)
X {
X if (p >= &buf[maxlen])
X { /* overflow, skip all until \n */
X while (low < high && *low != '\n') low++;
X endline = (*low == '\n');
X }
X else endline =((*p++ = *low++) == '\n');
X
X } /* exhausted buffer or found \n */
X
X if (endline) break; /* don't continue if \n found */
X status=read(infile,mybuf,2048);
X if (status==0) break;
X
X low=mybuf;
X high= &mybuf[status];
X
X }
X
X if (endline)
X {
X *(p-1)='\0';
X return (p-buf-1);
X }
X
X /* empty line or a bit filled ? */
X *p='\0';
X if (p-buf) return(p-buf);
X return(EOF);
X
X} /* of getlin() */
X
+ END-OF-FILE fgrep.c
chmod 'u=rw,g=rw,o=rw' 'fgrep.c'
set `wc -c 'fgrep.c'`
count=$1
case $count in
5443) :;;
*) echo 'Bad character count in ''fgrep.c' >&2
echo 'Count should be 5443' >&2
esac
echo Extracting 'prep.c'
sed 's/^X//' > 'prep.c' << '+ END-OF-FILE ''prep.c'
X/* prep - prepare file for statistics Author: Andy Tanenbaum */
X
X#include <stdio.h>
X#include <ctype.h>
X
X#define TROFF_CHAR '.' /* troff commands begin with this char */
X#define EOL '\n' /* end of line char */
X#define APOSTROPHE 047 /* single quote */
X#define BACKSLASH '\\' /* troff code */
X
Xint lfread; /* set when last char read was lf */
Xint lfwritten; /* set when last char written was lf */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X char c, backslash();
X FILE *freopen();
X
X if (argc > 2) usage();
X if (argc == 2) {
X if (freopen(argv[1], "r", stdin) == NULL) {
X printf("prep: cannot open %s\n", argv[1]);
X exit(1);
X }
X }
X
X while ( (c = getchar()) != EOF) {
X /* Lines beginning with "." are troff commands -- skip them. */
X if (lfread && c == TROFF_CHAR) {
X skipline();
X continue;
X }
X if (c == BACKSLASH) c = backslash(); /* eat troff stuff */
X
X if (isupper(c)) {
X putchar(tolower(c));
X lfwritten = 0;
X lfread = 0;
X continue;
X }
X if (islower(c)) {
X putchar(c);
X lfwritten = 0;
X lfread = 0;
X continue;
X }
X if (c == APOSTROPHE) {
X putchar(c);
X lfwritten = 0;
X lfread = 0;
X continue;
X }
X lfread = (c == EOL ? 1 : 0);
X if (lfwritten) continue;
X putchar(EOL);
X lfwritten = 1;
X }
X}
X
X
Xskipline()
X{
X char c;
X
X while ( (c = getchar()) != EOL) ;
X}
X
X
Xchar backslash()
X{
X/* A backslash has been seen. Eat troff stuff. */
X
X char c;
X
X c = getchar();
X switch(c) {
X case 'f':
X c = getchar();
X c = getchar();
X return(c);
X
X case 's': /* \s7 or \s14 */
X c = getchar();
X c = getchar();
X if (isdigit(c)) c = getchar();
X return(c);
X
X case 'n': /* \na or \n(xx */
X c = getchar();
X if (c == '(') {
X c = getchar();
X c = getchar();
X }
X c = getchar();
X return(c);
X
X case '*': /* / * (XX */
X c = getchar();
X if (c == '(') {
X c = getchar();
X c = getchar();
X c = getchar();
X return(c);
X }
X
X case '(': /* troff 4-character escape sequence */
X c = getchar();
X c = getchar();
X c = getchar();
X return(c);
X
X }
X}
X
Xusage()
X{
X printf("Usage: prep [file]\n");
X exit(1);
X}
X
+ END-OF-FILE prep.c
chmod 'u=rw,g=r,o=r' 'prep.c'
set `wc -c 'prep.c'`
count=$1
case $count in
2025) :;;
*) echo 'Bad character count in ''prep.c' >&2
echo 'Count should be 2025' >&2
esac
echo Extracting 'readall.c'
sed 's/^X//' > 'readall.c' << '+ END-OF-FILE ''readall.c'
X#define BLK 30
X
Xchar a[32000];
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X int fd;
X unsigned b=0;
X if (argc != 2) {printf("Usage: readall file\n"); exit(1);}
X fd = open(argv[1], 0);
X if (fd < 0) {printf("%s is not readable\n", argv[1]); exit(1);}
X
X while(1) {
X if (read(fd, a, 1024*BLK) == 0) {output(b); exit(0);}
X b++;
X if (b % 100 == 0) output(b);
X }
X}
X
Xoutput(b)
Xunsigned b;
X{
X printf("%D blocks read\n",(long)b * (long) BLK);
X}
+ END-OF-FILE readall.c
chmod 'u=rw,g=r,o=r' 'readall.c'
set `wc -c 'readall.c'`
count=$1
case $count in
441) :;;
*) echo 'Bad character count in ''readall.c' >&2
echo 'Count should be 441' >&2
esac
echo Extracting 'treecmp.c'
sed 's/^X//' > 'treecmp.c' << '+ END-OF-FILE ''treecmp.c'
X/* treecmp - compare two trees Author: Andy Tanenbaum */
X
X/* This program recursively compares two trees and reports on differences.
X * It can be used, for example, when a project consists of a large number
X * of files and directories. When a new release (i.e., a new tree) has been
X * prepared, the old and new tree can be compared to give a list of what has
X * changed. The algorithm used is that the first tree is recursively
X * descended and for each file or directory found, the corresponding one in
X * the other tree checked. The two arguments are not completely symmetric
X * because the first tree is descended, not the second one, but reversing
X * the arguments will still detect all the differences, only they will be
X * printed in a different order. The program needs lots of stack space
X * because routines with local arrays are called recursively. The call is
X * treecmp [-v] dir1 dir2
X * The -v flag (verbose) prints the directory names as they are processed.
X */
X
X#include <sys/stat.h>
X
X#define BUFSIZE 4096 /* size of file buffers */
X#define MAXPATH 128 /* longest acceptable path */
X#define DIRENTLEN 14 /* number of characters in a file name */
X
Xstruct dirstruct { /* layout of a directory entry */
X unsigned inum;
X char fname[DIRENTLEN];
X};
X
Xstruct stat stat1, stat2; /* stat buffers */
X
Xchar buf1[BUFSIZE]; /* used for comparing bufs */
Xchar buf2[BUFSIZE]; /* used for comparing bufs */
X
Xint verbose; /* set if mode is verbose */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X char *p;
X
X if (argc < 3 || argc > 4) usage();
X p = argv[1];
X if (argc == 4) {
X if (*p == '-' && *(p+1) == 'v')
X verbose++;
X else
X usage();
X }
X
X if (argc == 3)
X compare(argv[1], argv[2]);
X else
X compare(argv[2], argv[3]);
X
X exit(0);
X}
X
Xcompare(f1, f2)
Xchar *f1, *f2;
X{
X/* This is the main comparision routine. It gets two path names as arguments
X * and stats them both. Depending on the results, it calls other routines
X * to compare directories or files.
X */
X
X int type1, type2;
X
X if (stat(f1, &stat1) < 0) {
X printf("Cannot stat %s\n", f1);
X return;
X }
X
X if (stat(f2, &stat2) < 0) {
X printf("Missing file: %s\n", f2);
X return;
X }
X
X /* Examine the types of the files. */
X type1 = stat1.st_mode & S_IFMT;
X type2 = stat2.st_mode & S_IFMT;
X if (type1 != type2) {
X printf("Type diff: %s and %s\n", f1, f2);
X return;
X }
X
X /* The types are the same. */
X switch(type1) {
X case S_IFREG: regular(f1, f2);
X break;
X
X case S_IFDIR: directory(f1, f2);
X break;
X
X case S_IFCHR:
X case S_IFBLK: break;
X
X default: printf("Unknown file type %o\n", type1);
X }
X return;
X}
X
Xregular(f1, f2)
Xchar *f1, *f2;
X{
X/* Compare to regular files. If they are different, complain. */
X
X int fd1, fd2, n1, n2, i;
X unsigned bytes;
X long count;
X char *p1, *p2;
X
X if (stat1.st_size != stat2.st_size) {
X printf("Size diff: %s and %s\n", f1, f2);
X return;
X }
X
X /* The sizes are the same. We actually have to read the files now. */
X fd1 = open(f1, 0);
X if (fd1 < 0) {
X printf("Cannot open %s for reading\n", f1);
X return;
X }
X
X fd2 = open(f2, 0);
X if (fd2 < 0) {
X printf("Cannot open %s for reading\n", f2);
X return;
X }
X
X count = stat1.st_size;
X while (count > 0L) {
X bytes = (unsigned) (count > BUFSIZE ? BUFSIZE : count); /* rd count */
X n1 = read(fd1, buf1, bytes);
X n2 = read(fd2, buf2, bytes);
X if (n1 != n2) {
X printf("Length diff: %s and %s\n", f1, f2);
X close(fd1);
X close(fd2);
X return;
X }
X
X /* Compare the buffers. */
X i = n1;
X p1 = buf1;
X p2 = buf2;
X while (i--) {
X if (*p1++ != *p2++) {
X printf("File diff: %s and %s\n", f1, f2);
X close(fd1);
X close(fd2);
X return;
X }
X }
X count -= n1;
X }
X close(fd1);
X close(fd2);
X}
X
Xdirectory(f1, f2)
Xchar *f1, *f2;
X{
X/* Recursively compare two directories by reading them and comparing their
X * contents. The order of the entries need not be the same.
X */
X
X int fd1, fd2, n1, n2, ent1, ent2, i, used1 = 0, used2 = 0;
X char *dir1buf, *dir2buf;
X char name1buf[MAXPATH], name2buf[MAXPATH];
X struct dirstruct *dp1, *dp2;
X unsigned dir1bytes, dir2bytes;
X extern char *malloc();
X
X /* Allocate space to read in the directories */
X dir1bytes = (unsigned) stat1.st_size;
X dir1buf = malloc(dir1bytes);
X if (dir1buf == 0) {
X printf("Cannot process directory %s: out of memory\n", f1);
X return;
X }
X
X dir2bytes = (unsigned) stat2.st_size;
X dir2buf = malloc(dir2bytes);
X if (dir2buf == 0) {
X printf("Cannot process directory %s: out of memory\n", f2);
X free(dir1buf);
X return;
X }
X
X /* Read in the directories. */
X fd1 = open(f1, 0);
X if (fd1 > 0) n1 = read(fd1, dir1buf, dir1bytes);
X if (fd1 < 0 || n1 != dir1bytes) {
X printf("Cannot read directory %s\n", f1);
X free(dir1buf);
X free(dir2buf);
X if (fd1 > 0) close(fd1);
X return;
X }
X close(fd1);
X
X fd2 = open(f2, 0);
X if (fd2 > 0) n2 = read(fd2, dir2buf, dir2bytes);
X if (fd2 < 0 || n2 != dir2bytes) {
X printf("Cannot read directory %s\n", f2);
X free(dir1buf);
X free(dir2buf);
X close(fd1);
X if (fd2 > 0) close(fd2);
X return;
X }
X close(fd2);
X
X /* Linearly search directories */
X ent1 = dir1bytes/sizeof(struct dirstruct);
X dp1 = (struct dirstruct *) dir1buf;
X for (i = 0; i < ent1; i++) {
X if (dp1->inum != 0) used1++;
X dp1++;
X }
X
X ent2 = dir2bytes/sizeof(struct dirstruct);
X dp2 = (struct dirstruct *) dir2buf;
X for (i = 0; i < ent2; i++) {
X if (dp2->inum != 0) used2++;
X dp2++;
X }
X
X if (verbose) printf("Directory %s: %d entries\n", f1, used1);
X
X /* Check to see if any entries in dir2 are missing from dir1. */
X dp1 = (struct dirstruct *) dir1buf;
X dp2 = (struct dirstruct *) dir2buf;
X for (i = 0; i < ent2; i++) {
X if (dp2->inum == 0 || strcmp(dp2->fname, ".") == 0 ||
X strcmp(dp2->fname, "..") == 0) {
X dp2++;
X continue;
X }
X check(dp2->fname, dp1, ent1, f1);
X dp2++;
X }
X
X /* Recursively process all the entries in dir1. */
X dp1 = (struct dirstruct *) dir1buf;
X for (i = 0; i < ent1; i++) {
X if (dp1->inum == 0 || strcmp(dp1->fname, ".") == 0 ||
X strcmp(dp1->fname, "..") == 0) {
X dp1++;
X continue;
X }
X if (strlen(f1) + DIRENTLEN >= MAXPATH) {
X printf("Path too long: %s\n", f1);
X free(dir1buf);
X free(dir2buf);
X return;
X }
X if (strlen(f2) + DIRENTLEN >= MAXPATH) {
X printf("Path too long: %s\n", f2);
X free(dir1buf);
X free(dir2buf);
X return;
X }
X
X strcpy(name1buf, f1);
X strcat(name1buf, "/");
X strncat(name1buf, dp1->fname, DIRENTLEN);
X strcpy(name2buf, f2);
X strcat(name2buf, "/");
X strncat(name2buf, dp1->fname, DIRENTLEN);
X
X /* Here is the recursive call to process an entry. */
X compare(name1buf, name2buf); /* recursive call */
X dp1++;
X }
X
X free(dir1buf);
X free(dir2buf);
X}
X
Xcheck(s, dp1, ent1, f1)
Xchar *s;
Xstruct dirstruct *dp1;
Xint ent1;
Xchar *f1;
X{
X/* See if the file name 's' is present in the directory 'dirbuf'. */
X int i;
X
X for (i = 0; i < ent1; i++) {
X if (strncmp(dp1->fname, s, DIRENTLEN) == 0) return;
X dp1++;
X }
X printf("Missing file: %s/%s\n", f1, s);
X}
X
Xusage()
X{
X printf("Usage: treecmp [-v] dir1 dir2\n");
X exit(0);
X}
X
+ END-OF-FILE treecmp.c
chmod 'u=rw,g=r,o=r' 'treecmp.c'
set `wc -c 'treecmp.c'`
count=$1
case $count in
6938) :;;
*) echo 'Bad character count in ''treecmp.c' >&2
echo 'Count should be 6938' >&2
esac
exit 0