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