[comp.os.minix] V1.3, posting #14 - four new programs for commands

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