ast@cs.vu.nl (Andy Tanenbaum) (06/10/88)
: 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 'a.out.h' sed 's/^X//' > 'a.out.h' << '+ END-OF-FILE ''a.out.h' X/* a.out header file */ X Xstruct exec { /* a.out header */ X unsigned char a_magic[2]; /* magic number */ X unsigned char a_flags; /* flags, see below */ X unsigned char a_cpu; /* cpu id */ X unsigned char a_hdrlen; /* length of header */ X unsigned char a_unused; /* reserved for future use */ X unsigned short a_version; /* version stamp */ X /* not used */ X long a_text; /* size of text segement in bytes */ X long a_data; /* size of data segment in bytes */ X long a_bss; /* size of bss segment in bytes */ X long a_no_entry; /* in fact: entry point, a_entry */ X long a_total; /* total memory allocated */ X long a_syms; /* size of symbol table */ X /* SHORT FORM ENDS HERE */ X long a_trsize; /* text relocation size */ X long a_drsize; /* data relocation size */ X long a_tbase; /* text relocation base */ X long a_dbase; /* data relocation base */ X}; X X#define A_MAGIC0 (unsigned char) 0x01 X#define A_MAGIC1 (unsigned char) 0x03 X#define BADMAG(X) ((X).a_magic[0] != A_MAGIC0 ||\ X (X).a_magic[1] != A_MAGIC1) X X/* CPU Id of TARGET machine */ X /* byte order coded in low order two bits */ X#define A_NONE 0x00 /* unknown */ X#define A_I8086 0x04 /* intel i8086/8088 */ X#define A_M68K 0x0B /* motorola m68000 */ X#define A_NS16K 0x0C /* national semiconductor 16032 */ X X#define A_BLR(cputype) ((cputype&0x01)!=0) /* TRUE if bytes left-to-right */ X#define A_WLR(cputype) ((cputype&0x02)!=0) /* TRUE if words left-to-right */ X X/* flags: */ X#define A_EXEC 0x10 /* executable */ X#define A_SEP 0x20 /* separate I/D */ X#define A_PURE 0x40 /* pure text */ /* not used */ X#define A_TOVLY 0x80 /* text overlay */ /* not used */ X X/* offsets of various things: */ X#define A_MINHDR 32 X#define A_TEXTPOS(X) ((long)(X).a_hdrlen) X#define A_DATAPOS(X) (A_TEXTPOS(X) + (X).a_text) X#define A_HASRELS(X) ((X).a_hdrlen > (unsigned char) A_MINHDR) X#define A_HASEXT(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 8)) X#define A_HASLNS(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 16)) X#define A_HASTOFF(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 24)) X#define A_TRELPOS(X) (A_DATAPOS(X) + (X).a_data) X#define A_DRELPOS(X) (A_TRELPOS(X) + (X).a_trsize) X#define A_SYMPOS(X) (A_TRELPOS(X) + (A_HASRELS(X) ? \ X ((X).a_trsize + (X).a_drsize) : 0)) X Xstruct reloc { X long r_vaddr; /* virtual address of reference */ X unsigned short r_symndx; /* internal segnum or extern symbol num */ X unsigned short r_type; /* relocation type */ X}; X X/* r_tyep values: */ X#define R_ABBS 0 X#define R_RELLBYTE 2 X#define R_PCRBYTE 3 X#define R_RELWORD 4 X#define R_PCRWORD 5 X#define R_RELLONG 6 X#define R_PCRLONG 7 X#define R_REL3BYTE 8 X#define R_KBRANCHE 9 X X/* r_symndx for internal segments */ X#define S_ABS ((unsigned short)-1) X#define S_TEXT ((unsigned short)-2) X#define S_DATA ((unsigned short)-3) X#define S_BSS ((unsigned short)-4) X Xstruct nlist { /* symbol table entry */ X char n_name[8]; /* symbol name */ X long n_value; /* value */ X unsigned char n_sclass; /* storage class */ X unsigned char n_numaux; /* number of auxiliary entries */ X /* not used */ X unsigned short n_type; /* language base and derived type */ X /* not used */ X}; X X/* low bits of storage class (section) */ X#define N_SECT 07 /* section mask */ X#define N_UNDF 00 /* undefined */ X#define N_ABS 01 /* absolute */ X#define N_TEXT 02 /* text */ X#define N_DATA 03 /* data */ X#define N_BSS 04 /* bss */ X#define N_COMM 05 /* (common) */ X X/* high bits of storage class */ X#define N_CLASS 0370 /* storage class mask */ X#define C_NULL X#define C_EXT 0020 /* external symbol */ X#define C_STAT 0030 /* static */ X /* there are many others, but they are not supported */ + END-OF-FILE a.out.h chmod 'u=rw,g=r,o=r' 'a.out.h' set `wc -c 'a.out.h'` count=$1 case $count in 3646) :;; *) echo 'Bad character count in ''a.out.h' >&2 echo 'Count should be 3646' >&2 esac echo Extracting 'ast.c' sed 's/^X//' > 'ast.c' << '+ END-OF-FILE ''ast.c' X/* ast - add symbol table. Author: Dick van Veen, veench@cs.vu.nl */ X X#include <a.out.h> X#include <stdio.h> X X/* X * Since the a.out file in MINIX does not contain any symbol table, X * we use the symbol table produced with the -s option of asld, e.g. X * cc -s file.c >symbol.out X * X * Read symbol table in memory, remove compiler generated labels, X * sort the labels and add it to the a.out file. X * X * When finally there comes a real as and ld, we may also get X * a symbol table in the a.out file, and we can forget this program. X * X */ X X/* X * Usage: ast [flags] [file] [symbolfile] X * X * flags: X * -x do not preserve local symbols X * -X preserve local symbols except for those whose name begin X * with 'I' or 'L', these are compiler generated. X * X * - when no symbol file is present, symbol.out is assumed. X * - when no file is present, a.out is assumed. X * - when one file name is present it must be the executable file X * - just one flag may be pressent. X * X */ X X#define A_OUT "a.out" X#define SYMBOL_FILE "symbol.out" /* contains symbol table */ X#define LINE_LENGTH 24 X X#define WORTH_LESS 1 /* lines contain no symbol */ X#define LAST_LINE 2 /* end of file reached */ X Xstruct exec header; /* header info of a.out file */ X Xint x_flag; /* flags to ast */ Xint X_flag; Xint o_flag; X Xchar *s_file, *o_file; /* names of files used by ast */ XFILE *s_fd, *o_fd; /* file descriptors of those files */ Xint nr_symbols; /* number of symbols added */ Xchar buffer[LINE_LENGTH]; /* contains line of symbol file */ X Xchar io_buf[BUFSIZ]; /* for buffered output on stderr */ Xunsigned int get_value(); /* forward definition */ X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X extern FILE *fopen(); X X argv++; X if (*argv != NULL && **argv == '-') { X *argv += 1; X if (**argv == 'x') x_flag = 1; X else if (**argv == 'X') X_flag = 1; X else { X fprintf(stderr, "illegal flag: -%c\n", **argv); X Exit(-1); X } X argv++; X } X if (*argv != NULL) { X o_file = *argv; X argv++; X } X if (*argv != NULL) { X s_file = *argv; X argv++; X } X if (*argv != NULL) { X fprintf(stderr, "Usage: ast [-xX] [file] [symbolfile]\n"); X Exit(-1); X } X if (o_file == NULL) o_file = A_OUT; X o_fd = fopen(o_file, "a"); X if (o_fd == NULL) { X fprintf(stderr, "can't open %s\n", o_file); X Exit(-1); X } X if (s_file == NULL) s_file = SYMBOL_FILE; X s_fd = fopen(s_file, "r"); X if (s_fd == NULL) { X fprintf(stderr, "can't open %s\n", s_file); X Exit(-1); X } X setbuf(s_fd, io_buf); X ast(s_fd, o_fd); X Exit(0); X} X XExit(val) Xint val; X{ X _cleanup(); X exit(val); X} X Xast(s_fd, o_fd) XFILE *s_fd, *o_fd; X{ X struct nlist symbol; X int line_type; X X do_header(); X for(;;) { X read_line(s_fd, buffer); X line_type = transform_line(buffer, &symbol); X if (line_type == WORTH_LESS) continue; X if (line_type == LAST_LINE) break; X save_line(o_fd, &symbol); X } X redo_header(o_fd); X} X Xread_line(fd, buffer) XFILE *fd; Xchar *buffer; X{ X char ch; X char *buf1; X X buf1 = buffer; X *buffer = '\n'; X ch = fgetc(fd); X while (ch != '\n' && ch != EOF) { X *buffer = ch; X buffer++; X ch = fgetc(fd); X } X if (ch == EOF) X *buffer = '\0'; X else *buffer = '\n'; X buffer[1] = '\0'; X} X Xtransform_line(buffer, symbol) Xchar *buffer; Xstruct nlist *symbol; X{ X switch(*buffer) { X case 'a': /* absolute symbol */ X symbol->n_sclass = N_ABS; X break; X case 'A': X symbol->n_sclass = N_ABS | C_EXT; X break; X case 'u': /* undefined symbol */ X symbol->n_sclass = N_UNDF; X break; X case 'U': X symbol->n_sclass = N_UNDF | C_EXT; X break; X X case 't': /* text symbol */ X symbol->n_sclass = N_TEXT; X break; X case 'T': X symbol->n_sclass = N_TEXT | C_EXT; X break; X case 'd': X symbol->n_sclass = N_DATA; X case 'D': /* data symbol */ X symbol->n_sclass = N_DATA | C_EXT; X break; X case 'b': X symbol->n_sclass = N_BSS; X case 'B': /* bss symbol */ X symbol->n_sclass = N_BSS | C_EXT; X break; X case '\0': /* reached end of file */ X return(LAST_LINE); X default: /* one of first two lines */ X return(WORTH_LESS); X } X X if (buffer[1] != ' ') { X fprintf(stderr, "illegal file format\n"); X Exit(-1); X } X symbol->n_value = get_value(buffer + 2); X X if (buffer[6] != ' ') { X fprintf(stderr, "illegal file format\n"); X Exit(-1); X } X get_name(buffer + 7, symbol->n_name); X return(0); /* yeah, found a symbol */ X} X Xsave_line(fd, symbol) XFILE *fd; Xstruct nlist *symbol; X{ X if (!(symbol->n_sclass & C_EXT)) { /* local symbol */ X if (x_flag) return; X if (X_flag && (symbol->n_name[0] == 'I' || X symbol->n_name[0] == 'L')) return; X } X if (fwrite(symbol, sizeof(struct nlist), 1, fd) != 1) { X fprintf(stderr, "can't write %s\n", o_file); X Exit(-1); X } X nr_symbols++; X} X Xunsigned get_value(string) Xchar *string; X{ X unsigned value; X int shift, bits; X X value = 0; X for (shift = 0; shift < 16; shift += 4) { X bits = get_bits(*string); X value = (value << 4) | bits; X string++; X } X return(value); X} X Xget_bits(ch) Xchar ch; X{ X if (ch >= '0' && ch <= '9') X return (ch - '0'); X if (ch >= 'A' && ch <= 'F') X return (ch - 'A' + 10); X if (ch >= 'a' && ch <= 'f') X return (ch - 'a' + 10); X fprintf(stderr, "illegal file format\n"); X Exit(-1); X} X Xget_name(str1, str2) Xregister char *str1, *str2; X{ X int count; X X for (count = 0; count < 8; count++) { X if (*str1 == '\n') break; X *str2++ = *str1++; X } X while (count < 8) { X *str2++ = '\0'; X count++; X } X} X Xdo_header() X{ X int fd; X X fd = open(o_file, 0); X if (read(fd, &header, sizeof(struct exec)) != sizeof(struct exec)) { X fprintf(stderr, "%s: no executable file\n", o_file); X Exit(-1); X } X if (BADMAG(header)) { X fprintf(stderr, "%s: bad header\n", o_file); X Exit(-1); X } X if (header.a_syms != 0L) { X fprintf(stderr, "%s: symbol table is installed\n", o_file); X Exit(-1); X } X fseek(o_fd, A_SYMPOS(header), 0); X nr_symbols = 0; X close(fd); X} X Xredo_header(fd) XFILE *fd; X{ X header.a_syms = nr_symbols * sizeof(struct nlist); X fseek(fd, 0L, 0); X if (fwrite(&header, sizeof(header), 1, fd) != 1) { X fprintf(stderr, "%s: can't write\n", o_file); X Exit(-1); X } X} X + END-OF-FILE ast.c chmod 'u=rw,g=r,o=r' 'ast.c' set `wc -c 'ast.c'` count=$1 case $count in 5931) :;; *) echo 'Bad character count in ''ast.c' >&2 echo 'Count should be 5931' >&2 esac echo Extracting 'nm.c' sed 's/^X//' > 'nm.c' << '+ END-OF-FILE ''nm.c' X/* nm - print name list. Author: Dick van Veen, veench@cs.vu.nl */ X X#include <a.out.h> X#include <stdio.h> X X/* X * Read the name list in memory, sort it, and print it. X * X */ X X/* X * nm [-gnopru] [file] ... X * X * flags: X * -g print only external symbols. X * -n sort numerically rather than alphabetically. X * -o prepend file name to each line rather than only once. X * -p don't sort, print in symbol-table order. X * -r sort in reverse order. X * -u print only undefined symbols. X * X * - when no file name is present, a.out is assumed. X * X * NOTE: no archives are supported because assembly files don't X * have symbol tables. X * X */ X X#define A_OUT "a.out" X Xint g_flag; Xint n_flag; Xint o_flag; Xint p_flag; Xint r_flag; Xint u_flag; X Xchar io_buf[BUFSIZ]; /* io buffer */ Xstruct exec header; /* header of a.out file */ Xint stbl_elems; /* #elements in symbol table */ X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X argv++; X while (*argv != 0 && **argv == '-') { X *argv += 1; X while (**argv != '\0') { X switch (**argv) { X case 'g': X g_flag = 1; X break; X case 'n': X n_flag = 1; X break; X case 'o': X o_flag = 1; X break; X case 'p': X p_flag = 1; X break; X case 'r': X r_flag = 1; X break; X case 'u': X u_flag = 1; X break; X default: X fprintf(stderr, "illegal flag: -%c\n", **argv); X Exit(-1); X } X *argv += 1; X } X argv++; X } X setbuf(stdin, io_buf); X if (*argv == 0) nm(A_OUT); X else while (*argv != 0) { X nm(*argv); X argv++; X } X Exit(0); X} X XExit(val) Xint val; X{ X _cleanup(); X exit(val); X} X Xnm_sort(stbl1, stbl2) Xstruct nlist *stbl1, *stbl2; X{ X int cmp; X X if (n_flag) { /* sort numerically */ X if ((stbl1->n_sclass & N_SECT) < X (stbl2->n_sclass & N_SECT)) cmp = -1; X else if ((stbl1->n_sclass & N_SECT) > X (stbl2->n_sclass & N_SECT)) cmp = 1; X else if (stbl1->n_value < stbl2->n_value) X cmp = -1; X else if (stbl1->n_value > stbl2->n_value) X cmp = 1; X else cmp = strncmp(stbl1->n_name, stbl2->n_name, 8); X } else { X cmp = strncmp(stbl1->n_name, stbl2->n_name, 8); X if (cmp == 0) { X if (stbl1->n_value < stbl2->n_value) X cmp = -1; X else if (stbl1->n_value > stbl2->n_value) X cmp = 1; X } X } X X if (r_flag) cmp = -cmp; /* reverse sort */ X return(cmp); X} X Xnm(file) Xchar *file; X{ X struct nlist *stbl; X int fd; X X fd = open(file, 0); X if (fd == -1) { X fprintf(stderr, "can't open %s\n", file); X return; X } X X if (read_header(fd)) { X fprintf(stderr, "%s: no executable file\n", file); X return; X } X X stbl = (struct nlist *) malloc((int) (header.a_syms & 0xFFFF)); X if (stbl == NULL) { X fprintf(stderr, "%s: can't allocate symbol table\n", file); X return; X } X if (read(fd, stbl, (int) (header.a_syms & 0xFFFF)) X != (int) (header.a_syms & 0xFFFF)) { X fprintf(stderr, "%s: can't read symbol table\n", file); X return; X } X stbl_elems = (int) header.a_syms/sizeof(struct nlist); X if (!p_flag) qsort(stbl, stbl_elems, sizeof(struct nlist), nm_sort); X nm_print(file, stbl); X close(fd); X} X Xread_header(fd) Xint fd; X{ X if (read(fd, &header, sizeof(struct exec)) != sizeof(struct exec)) X return(1); X if (BADMAG(header)) return(1); X lseek(fd, A_SYMPOS(header), 0); X X return(0); X} X Xnm_print(file, stbl) Xchar *file; Xregister struct nlist *stbl; X{ X struct nlist *last; X char name[9]; X int n_sclass; X char type; X X name[8] = '\0'; X if (!o_flag) printf("%s:\n", file); X for (last = &stbl[stbl_elems]; stbl != last; stbl++) { X if (g_flag && !(stbl->n_sclass & C_EXT)) continue; X if (u_flag && stbl->n_sclass & N_SECT != N_UNDF) continue; X X n_sclass = stbl->n_sclass & N_SECT; X if (n_sclass == N_ABS) type = 'a'; X else if (n_sclass == N_TEXT) type = 't'; X else if (n_sclass == N_DATA) type = 'd'; X else if (n_sclass == N_BSS) type = 'b'; X else type = 'u'; X if (stbl->n_sclass & C_EXT) type += 'A' -'a'; X strncpy(name, stbl->n_name, 8); X if (o_flag) printf("%s:%04X %c %s\n", file, X stbl->n_value, type, name); X else printf("%04X %c %s\n", stbl->n_value, type, name); X } X} + END-OF-FILE nm.c chmod 'u=rw,g=r,o=r' 'nm.c' set `wc -c 'nm.c'` count=$1 case $count in 3949) :;; *) echo 'Bad character count in ''nm.c' >&2 echo 'Count should be 3949' >&2 esac echo Extracting 'strip.c' sed 's/^X//' > 'strip.c' << '+ END-OF-FILE ''strip.c' X/* strip - remove symbols. Author: Dick van Veen, veench@cs.vu.nl */ X X#include <a.out.h> X#include <stdio.h> X#include <sys/stat.h> X X/* X * strip [file] ... X * X * - when no file is present, a.out is assumed. X * X */ X X#define A_OUT "a.out" X#define NAME_LENGTH 128 /* max file path name */ X Xchar buffer[BUFSIZ]; /* used to copy executable */ Xchar new_file[NAME_LENGTH]; /* contains name of temporary */ Xstruct exec header; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X argv++; X if (*argv == NULL) strip(A_OUT); X else while (*argv != NULL) { X strip(*argv); X argv++; X } X exit(0); X} X Xstrip(file) Xchar *file; X{ X int fd, new_fd; X struct stat buf; X X fd = open(file, 0); X if (fd == -1) { X fprintf(stderr, "can't open %s\n", file); X close(fd); X return; X } X if (read_header(fd)) { X fprintf(stderr, "%s: not an executable file\n", file); X close(fd); X return; X } X if (header.a_syms == 0L) { X close(fd); /* no symbol table present */ X return; X } X header.a_syms = 0L; /* remove table size */ X fstat(fd, &buf); X new_fd = make_tmp(new_file, file); X if (new_fd == -1) { X fprintf(stderr, "can't create temporary file\n"); X close(fd); X return; X } X if (write_header(new_fd)) { X fprintf(stderr, "%s: can't write temporary file\n"); X unlink(new_file); X close(fd); X close(new_fd); X return; X } X if (copy_file(fd, new_fd, header.a_text + header.a_data)) { X fprintf(stderr, "can't copy %s\n", file); X unlink(new_file); X close(fd); X close(new_fd); X return; X } X close(fd); X close(new_fd); X if (unlink(file) == -1) { X fprintf(stderr, "can't unlink %s\n", file); X unlink(new_file); X return; X } X link(new_file, file); X unlink(new_file); X chmod(file, buf.st_mode); X} X Xread_header(fd) Xint fd; X{ X if (read(fd, &header, A_MINHDR) != A_MINHDR) return(1); X if (BADMAG(header)) return(1); X if (header.a_hdrlen > sizeof(struct exec)) return(1); X lseek(fd, 0L, 0); /* variable size header */ X if (read(fd, &header, (int) header.a_hdrlen) != (int) header.a_hdrlen) X return(1); X return(0); X} X Xwrite_header(fd) Xint fd; X{ X lseek(fd, 0L, 0); X if(write(fd, &header, (int)header.a_hdrlen) != (int)header.a_hdrlen) X return(1); X return(0); X} X Xint make_tmp(new_name, name) Xchar *new_name, *name; X{ X int len; X char *nameptr; X extern char *rindex(); X X len = strlen(name); X if (len + 1 > NAME_LENGTH) return(-1); X strcpy(new_name, name); X nameptr = rindex(new_name, '/'); X if (nameptr == NULL) nameptr = new_name-1; X if (nameptr - new_name + 6 + 1 > NAME_LENGTH) return(-1); X strcpy(nameptr+1, "XXXXXX"); X mktemp(new_name); X return(creat(new_name, 0777)); X} X Xcopy_file(fd1, fd2, size) Xint fd1, fd2; Xlong size; X{ X long count; X int length; X X count = 0; X while (count < size) { X length = (int) (size - count); X if (length > sizeof(buffer)) length = sizeof(buffer); X length = read(fd1, buffer, length); X if (length == 0) break; X if (write(fd2, buffer, length) != length) return(1); X count += length; X } X if (count < size) return(1); X return(0); X} + END-OF-FILE strip.c chmod 'u=rw,g=r,o=r' 'strip.c' set `wc -c 'strip.c'` count=$1 case $count in 2925) :;; *) echo 'Bad character count in ''strip.c' >&2 echo 'Count should be 2925' >&2 esac echo Extracting 'traverse.c' sed 's/^X//' > 'traverse.c' << '+ END-OF-FILE ''traverse.c' X/* traverse - traverse a tree Author: Gary Perlman */ X X#include <stdio.h> X#include <sys/types.h> X#include <sys/dir.h> X X#define STANDALONE X X#define DIR FILE X#define MAXNAME (DIRSIZ+2) X#define opendir(path) fopen (path, "r") X#define closedir(dirp) fclose (dirp) Xstruct direct * Xreaddir (dirp) XDIR *dirp; X { X static struct direct entry; X if (dirp == NULL) return (NULL); X for (;;) X { X if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) return (NULL); X if (entry.d_ino) return (&entry); X } X } Xchar *strncpy (); Xchar * Xnamedir (entry) Xstruct direct *entry; X { X static char name[MAXNAME]; X return (strncpy (name, entry->d_name, DIRSIZ)); X } X X X#include <sys/stat.h> X#define isdir(path) (stat(path, &buf) ? 0 : (buf.st_mode&S_IFMT)==S_IFDIR) X Xtraverse (path, func) Xchar *path; Xint (*func) (); X { X DIR *dirp; X struct direct *entry; X struct stat buf; X int filetype = isdir (path) ? 'd' : 'f'; X (*func) (path, filetype, 0); X if (filetype == 'd') X { X if (chdir (path) == 0) X { X if (dirp = opendir (".")) X { X while (entry = readdir (dirp)) X { X char name[MAXNAME]; X (void) strcpy (name, namedir (entry)); X if (strcmp(name, ".") && strcmp(name, "..")) X traverse (name, func); X } X (void) closedir(dirp); X } X (void) chdir (".."); X } X } X (*func) (path, filetype, 1); X } X X#ifdef STANDALONE X Xstatic Indent = 0; Xtryverse (file, type, pos) Xchar *file; X { X int in; X if (pos == 0) X { X for (in = 0; in < Indent; in++) putchar ('\t'); X if (type == 'd') X { X printf ("%s/\n", file); X Indent++; X } X else puts (file); X } X else if (type == 'd') Indent--; X } X Xmain (argc, argv) char **argv; X { X int tryverse (); X char *root = argc > 1 ? argv[1] : "."; X traverse (root, tryverse); X } X#endif + END-OF-FILE traverse.c chmod 'u=rw,g=rw,o=rw' 'traverse.c' set `wc -c 'traverse.c'` count=$1 case $count in 1737) :;; *) echo 'Bad character count in ''traverse.c' >&2 echo 'Count should be 1737' >&2 esac exit 0