# to unbundle, sh this file (in an empty directory)
echo ftw.body 1>&2
sed >ftw.body <<'//GO.SYSIN DD ftw.body' 's/^-//'
-/* This is the real ftw source code.  It assumes that the following
- * includes have been given:
- *
- * #include <sys/types.h>
- * #include <sys/stat.h>
- * #include "ftw.h"
- *
- * Struct FTW (whose definition starts at the end of ftw.h) must
- * must include at least the integers quit, base, and level.
- */
-
-#define FTW_PATHLEN0 1000
-#define FTW_PATHINC 1000
-#ifndef S_IFLNK
-#define lstat stat
-#endif
-#ifdef S_IFSOCK
-#include <sys/dir.h>
-#else
-#ifdef S_ICCTYP
-#include "ndir.h"
-#else
-#include "dirent.h"
-#define direct dirent
-#endif
-#endif
-#ifndef ENOMEM
-#include <errno.h>
-#endif
-
-	extern int errno;
-
-/*
- *  Each generation of ftw1 (the real ftw) allocates one copy, R, of the
- *  following structure; it passes a pointer to this structure when it
- *  recursively invokes itself.  These structures are chained together,
- *  so that if it becomes necessary to recycle file descriptors, then
- *  the oldest descriptor (the one at the shallowest depth still open)
- *  can be recycled.
- */
-
-	struct FTW_rec {
-		struct FTW_rec *prev;
-		long here;	/* seek to here when reopening at this level */
-		DIR *fd;	/* file descriptor at this level */
-		};
-
-/*
- *  One instance, T, of the following structure is allocated by ftw; a
- *  pointer to it is passed to all generations of ftw1 (the real ftw).
- *  T could often be a global variable, but this way the parameter fn
- *  can invoke ftw for an independent tree walk.
- *  Component T->path points to storage for the object path-names;
- *  this storage may be relocated by realloc if T->path needs to be
- *  more than T->pathlast characters long.
- *  T->path[T->pathnext] is the next free character in the pathnames.
- *  T->depth = parameter depth to ftw.  T->lastout is the deepest level at
- *  which a file descriptor has been recycled.
- */
-
-	struct FTW_top {
-		int (*fn)();
-		char *path;
-		unsigned pathlast, pathnext;
-		int lastout;
-		int depth;
-		};
-
-static ftw_1_();
-
-int
-ftw (path, fn, depth)
-	char *path;
-	int (*fn)();
-	int depth;
-{
-	struct FTW_top T;
-	struct FTW_rec R;
-	struct FTW S;
-	int rc;
-	char *malloc(), *strcpy();
-
-	T.depth = depth;
-	T.lastout = -1;
-	T.fn = fn;
-	S.quit = 0;
-	S.level = -1;
-
-	/* initialize S.base, T.pathnext... */
-		{
-		register char c, *p, *q;
-		for (p = q = path; c = *p; p++) if (c == '/') q = p + 1;
-		S.base = q - path;
-		T.pathnext = p - path;
-		}
-
-	T.pathlast = T.pathnext + FTW_PATHLEN0;
-	T.path = malloc(T.pathlast);
-	if (!T.path) { errno = ENOMEM; return -1; }
-	strcpy(T.path, path);
-	rc = ftw_1_(&R, &T, 0, &S);
-	free(T.path);
-	return rc;
-}
-
-static int
-ftw_1_ (R, T, level, S1)
-	register struct FTW_rec *R;
-	register struct FTW_top *T;
-	int level;
-	struct FTW *S1;
-{
-	int rc, n;
-	DIR *fd;
-	struct direct *dirp;
-	char *component, *path;
-	struct stat sb;
-	struct FTW_rec mr;
-	unsigned nextsave;
-	struct FTW S;
-	char *realloc();
-	long lseek();
-
-	mr.prev = R;
-	path = T->path;
-	S.level = level;
-	S.quit = 0;
-	S.base = S1->base;
-
-	/* Try to get file status.  If unsuccessful, errno will say why. */
-	if (lstat(path, &sb) < 0) {
-		rc = (*T->fn) (path, &sb, FTW_NS, &S);
-		S1->quit = S.quit;
-		return rc;
-		};
-
-	/*
-	 *	The stat succeeded, so we know the object exists.
-	 *	If not a directory, call the user function and return.
-	 */
-#ifdef S_IFLNK
-	if ((sb.st_mode & S_IFMT) == S_IFLNK) {
-		rc = (*T->fn) (path, &sb, FTW_SL, &S);
-		S1->quit = S.quit;
-		if (rc || S.quit == FTW_SKR) return rc;
-		if (S.quit != FTW_FOLLOW) return 0;
-		S1->quit = S.quit = 0;
-		if (stat(path, &sb) < 0) {
-			rc = (*T->fn) (path, &sb, FTW_NSL, &S);
-			S1->quit = S.quit;
-			return rc;
-			};
-		}
-#endif
-
-	if ((sb.st_mode & S_IFMT) != S_IFDIR) {
-		rc = (*T->fn) (path, &sb, FTW_F, &S);
-		S1->quit = S.quit;
-		return rc;
-		}
-
-	/*
-	 *	The object was a directory.
-	 *
-	 *	Open a file to read the directory
-	 */
-	mr.fd = fd = opendir(path);
-
-	/*
-	 *	Call the user function, telling it whether
-	 *	the directory can be read.  If it can't be read
-	 *	call the user function or indicate an error,
-	 *	depending on the reason it couldn't be read.
-	 */
-	if (!fd) {
-		rc = (*T->fn) (path, &sb, FTW_DNR, &S);
-		S1->quit = S.quit;
-		return rc;
-		}
-
-	/* We could read the directory.  Call user function. */
-	rc = (*T->fn) (path, &sb, FTW_D, &S);
-	if (rc != 0)
-		goto rtrn;
-	if (S.quit == FTW_SKD) goto rtrn;
-	if (S.quit == FTW_SKR) {S1->quit = FTW_SKR; goto rtrn;}
-
-	/* Make sure path is big enough to hold generated pathnames. */
-
-	n = nextsave = T->pathnext;
-	if (n + MAXNAMLEN + 1 >= T->pathlast) {
-		T->pathlast += FTW_PATHINC;
-		path = T->path = realloc(T->path, T->pathlast);
-		if (!path) {
-			errno = ENOMEM;
-			rc = -1;
-			goto rtrn;
-			}
-		}
-
-	/* Create a prefix to which we will append component names */
-
-	if (n > 0 && path[n-1] != '/') path[n++] = '/';
-	component = path + n;
-
-	/*
-	 *	Read the directory one component at a time.
-	 *	We must ignore "." and "..", but other than that,
-	 *	just create a path name and call self to check it out.
-	 */
-	while (dirp = readdir(fd)) {
-		if (dirp->d_ino != 0
-		    && strcmp (dirp->d_name, ".") != 0
-		    && strcmp (dirp->d_name, "..") != 0) {
-			int i;
-			struct FTW_rec *pr;
-
-			/* Append the component name to the working path */
-			strcpy(component, dirp->d_name);
-			T->pathnext = n + strlen(dirp->d_name);
-
-			/*
-			 *	If we are about to exceed our depth,
-			 *	remember where we are and close the file.
-			 */
-			if (level - T->lastout >= T->depth) {
-				pr = &mr;
-				i = T->lastout++;
-				while (++i < level) pr = pr->prev;
-				pr->here = telldir(pr->fd);
-				closedir(pr->fd);
-			}
-
-			/*
-			 *	Do a recursive call to process the file.
-			 */
-			S.quit = 0;
-			S.base = n;
-			rc = ftw_1_(&mr, T, level+1, &S);
-			if (rc != 0 || S.quit == FTW_SKR) {
-				if (level > T->lastout) closedir(fd);
-				T->pathnext = nextsave;
-				return rc;
-			}
-
-			/*
-			 *	If we closed the file, try to reopen it.
-			 */
-			if (level <= T->lastout) {
-				char c = path[nextsave];
-				path[nextsave] = 0;
-				T->lastout = level - 1;
-				mr.fd = fd = opendir(path);
-				if (!fd) {
-					rc = (*T->fn) (path, &sb, FTW_DNR, &S);
-					S1->quit = S.quit;
-					T->pathnext = nextsave;
-					return rc;
-					}
-				path[nextsave] = c;
-				seekdir(fd, mr.here);
-				}
-			}
-		}
-	T->pathnext = nextsave;
-	path[nextsave] = 0;
-
-	/*
-	 *	We got out of the subdirectory loop.  Call the user
-	 *	function again at the end and clean up.
-	 */
-
-	rc = (*T->fn) (path, &sb, FTW_DP, &S);
-	S1->quit = S.quit;
-rtrn:
-	closedir(fd);
-	return rc;
-}
//GO.SYSIN DD ftw.body
echo ftw.c 1>&2
sed >ftw.c <<'//GO.SYSIN DD ftw.c' 's/^-//'
-/*
- *	ftw - file tree walk
- *
- *	int ftw (path, fn, depth)  char *path; int (*fn)(); int depth;
- *
- *	Given a path name, ftw starts from the file given by that path
- *	name and visits each file and directory in the tree beneath
- *	that file.  If a single file has multiple links within the
- *	structure, it will be visited once for each such link.
- *	For each object visited, fn is called with four arguments.
- *	The fourth can often be ignored; it is a pointer, say S,
- *	declared "struct FTW *S", discussed in more detail below.
- *	The first contains the path name of the object, the second
- *	contains a pointer to a stat buffer which will usually hold
- *	appropriate information for the object and the third contains
- *	an integer value giving additional information about the
- *	object, as follows:
- *
- *		FTW_F	The object is a file for which stat was
- *			successful.  It does not guarantee that the
- *			file can actually be read.
- *
- *		FTW_D	The object is a directory for which stat and
- *			open for read were both successful.  This is
- *			a preorder visit -- objects in the directory
- *			are yet to be visited.
- *
- *		FTW_DNR	The object is a directory for which stat
- *			succeeded, but which cannot be read.  Because
- *			the directory cannot be read, fn will not be
- *			called for any descendants of this directory.
- *
- *		FTW_DP	The object is a directory for which stat and
- *			open for read were both successful.  This is
- *			a postorder visit -- everything in the directory
- *			has already been visited.
- *
- *		FTW_NS	Lstat failed on the object.  If errno is EACCES,
- *			then the failure stems from lack of
- *			appropriate permission.  This indication will
- *			be given, for example, for each file in a directory
- *			with read but no execute permission.  Whenever
- *			stat fails, it is not possible to determine
- *			whether this object is a file or a directory.
- *			The stat buffer passed to fn will contain garbage.
- *
- *		FTW_SL  The object is a symbolic link.  Set S->quit
- *			(a component of the structure pointed to by
- *			the fourth parameter to fn) to FTW_FOLLOW to
- *			have the link followed and the object to which
- *			it points visited.
- *
- *		FTW_NSL Lstat succeeded, but stat failed on the object.
- *			This is only possible when following a symbolic
- *			link.
- *
- *	Among the components of the structure to which the fourth
- *	parameter, S, to fn points is S->quit.  If the caller sets
- *	S->quit to FTW_SKR, then no more files in the current directory
- *	will be visited.  (The current directory is the one containing
- *	the object being visited.)  If the third parameter to fn is
- *	FTW_D and the caller sets S->quit to FTW_SKD, then this directory
- *	(the one named in the first parameter to fn) will be skipped.
- *
- *	Other components pointed to by the fourth parameter S are
- *	the current recursion level S->level (top level = 0) and
- *	the offset S->base in the pathname of the current object
- *	(the first parameter to fn) of the object's base name.
- *	By expanding the definition of struct FTW given below and
- *	including the files included below, one can arrange for
- *	S to point to a larger structure, components of which can
- *	be initialized (for example) on calls to fn with third
- *	parameter FTW_D.
- *
- *	If fn returns nonzero, ftw stops and returns the same value
- *	to its caller.  Ftw only initiates a nonzero return if malloc
- *	fails; in this case ftw sets errno to ENOMEM and returns -1.
- *
- *	The third argument to ftw does not limit the depth to which
- *	ftw will go.  Rather, it limits the depth to which ftw will
- *	go before it starts recycling file descriptors.  In general,
- *	it is necessary to use a file descriptor for each level of the
- *	tree, but they can be recycled for deep trees by saving the position,
- *	closing, re-opening, and seeking.  It is possible to start
- *	recycling file descriptors by sensing when we have run out, but
- *	in general this will not be terribly useful if fn expects to be
- *	able to open files.  We could also figure out how many file descriptors
- *	are available and guarantee a certain number to fn, but we would not
- *	know how many to guarantee, and we do not want to impose the extra
- *	overhead on a caller who knows how many are available without
- *	having to figure it out.
- *
- *	It is possible for ftw to die with a memory fault in the event
- *	of a file system so deeply nested that the stack overflows.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "ftw.h"
-#include "ftw.body"
//GO.SYSIN DD ftw.c
echo ftw.h 1>&2
sed >ftw.h <<'//GO.SYSIN DD ftw.h' 's/^-//'
-/*
- *	Codes for the third argument to the user-supplied function
- *	which is passed as the second argument to ftw...
- */
-
-#define	FTW_F	0	/* file */
-#define	FTW_D	1	/* directory */
-#define	FTW_DNR	2	/* directory without read permission */
-#define	FTW_NS	3	/* unknown type, stat failed */
-#define FTW_DP	4	/* directory, postorder visit */
-#define FTW_SL	5	/* symbolic link */
-#define FTW_NSL 6	/* stat failed (errno = ENOENT) on symbolic link */
-
-/*	Values the user-supplied function may wish to assign to
-	component quit of struct FTW...
- */
-
-#define FTW_SKD 1	/* skip this directory (2nd par = FTW_D) */
-#define FTW_SKR 2	/* skip rest of current directory */
-#define FTW_FOLLOW 3	/* follow symbolic link */
-
-struct FTW { int quit, base, level;
-#ifndef FTW_more_to_come
-	};
-#endif
//GO.SYSIN DD ftw.h
echo getpats.c 1>&2
sed >getpats.c <<'//GO.SYSIN DD getpats.c' 's/^-//'
-#include "patlist.h"
-
-void
-getpats(argc, argv, keep, drop)
-int argc;
-char **argv;
-struct patlist **keep, **drop;
-{
-int i, j, m;
-char c, *malloc(), *s, *t;
-struct patlist *d, *k, **p, *q;
-
-d = (struct patlist *) drop;
-k = (struct patlist *) keep;
-for (i = 1; i < argc; i++) {
-	s = argv[i];
-	for (j = 0;;) {
-		for (; (c=s[j]) == ' ' || c == '\t' || c == '\n'; j++);
-		if (!c) break;
-		if (c == '!') {p = &d; s++;}
-		else p = &k;
-		for (m = j; (c=s[m]) && c != ' ' && c != '\t' &&
-			c != '\n'; m++);
-		if (m == j) continue;
-		*p = (*p)->nextpat = q = (struct patlist *)
-			malloc((unsigned) (m-j+sizeof(struct patlist)));
-		t = q->namepat;
-		while (j < m) *t++ = s[j++];
-		*t = 0;
-		}
-	}
-d->nextpat = k->nextpat = 0;
-}
-
-int
-skipit(name, keep, drop)
-char *name;
-struct patlist *keep, *drop;
-{
-if (!keep) goto kept;
-for (; keep; keep = keep->nextpat)
-	{if (match(keep->namepat, name)) goto kept;}
-return 1;
-
-kept:
-for (; drop; drop = drop->nextpat)
-	{if (match(drop->namepat, name)) return 1;}
-return 0;
-}
//GO.SYSIN DD getpats.c
echo makefile 1>&2
sed >makefile <<'//GO.SYSIN DD makefile' 's/^-//'
-.SUFFIXES: .c .o
-u = ustree.o
-p = prune.o
-m = getpats.o match.o
-h = patlist.h
-mtest = matchtst.o match.o
-g = -O
-s =  stree.o ftw.o
-b = ftw.body ftw.c ftw.h getpats.c makefile match.c matchtst.c ok.c \
-	patlist.h prune.c stree.1 stree.c ustree.c
-
-all: stree ustree prune
-stree: $s $m $h
-	cc $g -o stree $s $m
-stree.o: stree.c ok.c
-	cc -c $g stree.c
-ustree: $u $m $h
-	cc $g -o ustree $u $m
-prune: $p $m
-	cc $g -o prune $p $m
-mtest: $(mtest)
-	cc $g -o mtest $(mtest)
-lint:
-	lint stree.c getpats.c match.c ftw.c
-stree.t: stree.1
-	troff -man stree.1 >stree.t
-.c.o: $h
-	cc -c $g $*.c
-
-bundle: $b
-	stree -u $b >bundle
-clean:
-	rm -f *.[to] bundle
//GO.SYSIN DD makefile
echo match.c 1>&2
sed >match.c <<'//GO.SYSIN DD match.c' 's/^-//'
-#include <stdio.h>
-int
-match(pat, s)	/* return 1 if s matches pat, 0 ow; match in the sense of */
-char *pat, *s;	/* UNIX file names, plus ``~'' = empty | '/' | '/'.*'/'	  */
-{		/* with `empty' possible only at ends. */
-
-#define STMAX 50
-int i, j, k, l, pst[STMAX], sst[STMAX];
-char c, clast, p, tst[STMAX];
-
-k = -1;
-c = '/';
-for(i=j=0;; j++){
-	p = pat[j];
-	clast = c;
-	c = s[i];
-	switch(p) {
-		case '?':
-			if (!c || c == '/' || c == '.' && clast == '/') goto fail;
-			i++; break;
-
-		case '[':
-			if (c == '/') goto fail;
-			for (l = ++j; (p = pat[l]) != ']'; l++) {
-				if (!p) {fprintf(stderr,
-					"match: missing ``]'' in ``%s''\n",
-						pat);
-					exit(1);
-					}
-				}
-			if (pat[j] == '^') {
-				for (j++; j < l; j++) {
-					p = pat[j];
-					if (p == c) goto fail;
-					if (pat[j+1] == '-' && j+2 < l) {
-						j += 2;
-						if ((c >= p && c <= pat[j]) ||
-						    (c <= p && c >= pat[j])) goto fail;
-						}
-					}
-				if (!c || clast == '/' && c == '.') goto fail;
-				goto havit;
-				}
-			else for (; j < l; j++) {
-				p = pat[j];
-				if (p == c) goto havit;
-				if (pat[j+1] == '-' && j+2 < l) {
-					j += 2;
-					if ((c >= p && c <= pat[j]) ||
-					    (c <= p && c >= pat[j])) goto havit;
-					}
-				}
-			goto fail;
-
-		havit:	j = l;
-			i++; break;
-
-		case '~':
-			if (!pat[j+1] && (c == '/' || !c)) return 1;
-			if (j > 0 && c != '/') goto fail;
-			if (c == '/') i++;
-			else c = '/';
-			if (++k >= STMAX) {
-toomany:
-				fprintf(stderr,
-				"match: more than %d *'s and ~'s in ``%s''\n",
-					STMAX, pat);
-				exit(1);
-				}
-			pst[k] = j;
-			sst[k] = i;
-			tst[k] = '~';
-			break;
-
-		case '*':
-			if (++k >= STMAX) goto toomany;
-			pst[k] = j;
-			sst[k] = i;
-			tst[k] = '*';
-			break;
-
-		default:
-			if (p != c) goto fail;
-			if (!c) return 1;
-			i++; break;
-
-		fail:
-			if (k < 0) return 0;
-			j = pst[k];
-			i = sst[k]++;
-			c = s[i++];
-			if (!c) {--k; goto fail;}
-			if (tst[k] == '~') {
-				while (c = s[i++]) {if (c == '/') goto loop;}
-				--i;
-				}
-			else if (c == '/') {--k; goto fail;}
-			}
-loop:;
-	}
-}
//GO.SYSIN DD match.c
echo matchtst.c 1>&2
sed >matchtst.c <<'//GO.SYSIN DD matchtst.c' 's/^-//'
-#include <stdio.h>
-
-main(){
-char s[256], pat[256];
-int i;
-
-while(fgets(pat,sizeof(pat),stdin)) {
-	if ((i = strlen(pat)) && pat[--i] == '\n')
-		pat[i] = 0;
-	printf("pattern ``%s''\n", pat);
-	for(;;){
-		if (!fgets(s,sizeof(s),stdin)) exit(0);
-		if ((i = strlen(s)) && s[--i] == '\n')
-			s[i] = 0;
-		if (!s[0]) break;
-		printf("``%s'' %s\n", s, match(pat,s) ? "matches" : "fails");
-		}
-	}
-exit(0);
-}
//GO.SYSIN DD matchtst.c
echo ok.c 1>&2
sed >ok.c <<'//GO.SYSIN DD ok.c' 's/^-//'
-/* #include <pagsiz.h> */
-#include <ctype.h>
-#include <a.out.h>
-
-#define OK return(1)
-#define NOT_OK return(0)
-int
-ok(file)
-char *file;
-{
- char *s;
- register char *Buf = buf;
-
-   s = strrchr(file,'/'); if (!s) s = file - 1;
-   if(!strcmp(s+1,"core")){ NOT_OK; }
-   if (in <= 1) OK;
-   if( (((unsigned char)Buf[0])==247) && (Buf[1]==2) ) NOT_OK; /* Tex dvi */
-
-#ifdef ZMAGIC
-#ifdef mips
-	switch(*(unsigned short *)Buf) {
-	case 0x0160:
-	case 0x0162:
-	case 0x6001:
-	case 0x6201:
-	case 0x0180:
-	case 0x0182:
-	case 070707:	/* cpio data */
-	case 0135246:	/* andrew/ehg */ /* view2d input file */
-	case 0135256:	/* andrew */ /* apl file */
-	case 0164200:	/* td */ /* Lucasfilm picture */
-      NOT_OK;
-   }
-   if(Buf[0] == 0x7f && Buf[1] == 'E' && Buf[2] == 'L' && Buf[3] == 'F')
-	NOT_OK;	/* ELF object */
-   if( !strncmp(Buf, "!<arch>\n",8) &&
-	(Buf[8] == '/' /* ELF object file archive */
-	 || !strncmp(Buf+8,"__________EBEB_ ", 16)))	/* random archive */
-		NOT_OK;
-   if( !strncmp(Buf, "#!/bin/echo ", 12) /* cyntax object file */ ) NOT_OK;
-#else
-#ifdef sun
-	switch(*(int *)Buf & 0xffff) {
-#else
-	switch(*(int *)Buf) {
- 	case 0600560:	/* mux downloadable file */
-#endif
-	case 0413:	/* demand paged */
-	case 0410:	/* pure */
-	case 0411:	/* executable */
-	case 0407:	/* executable */
-	case 0406:	/* mpx 68000 */
-	case 0177555:	/* very old archive */
-	case 0177545:	/* old archive */
-	case 070707:	/* cpio data */
-	case 0135246:	/* andrew/ehg */ /* view2d input file */
-	case 0135256:	/* andrew */ /* apl file */
-	case 0164200:	/* td */ /* Lucasfilm picture */
-      NOT_OK;
-   }
-   if( !strncmp(Buf, "!<arch>\n__.SYMDEF", 17) /* archive random */ ) NOT_OK;
-   if( !strncmp(Buf, "#!/bin/echo ", 12) /* cyntax object file */ ) NOT_OK;
-#endif
-#else
-#ifdef __hpux
-   switch(((MAGIC *)Buf)->file_type) {
-	case RELOC_MAGIC:
-	case SHARE_MAGIC:
-	case EXEC_MAGIC:
-		NOT_OK;
-	}
-   if( !strncmp(Buf, "!<arch>\n/               ", 24) /* archive random */ )
-	NOT_OK;
-#else
-/* # if u3b || vax || M32 || u3b15 || u3b5 || u3b2 */
-   switch(*(short *)Buf) {
-	case 0407:	/* pdp11/pre System V vax executable */
-	case 0401:	/* unix-rt ldp */
-	case 0405:	/* pdp11 overlay */
-	case 0410:	/* pdp11/pre System V vax pure executable */
-	case 0411:	/* pdp11 separate I&D */
-	case 0437:	/* pdp11 kernel overlay */
-	case 0570:	/* vax executable */
-	case 0575:	/* vax pure executable */
-	case 0502:	/* basic-16 executable */
-	case 0503:	/* basic-16 executable (TV) */
-	case 0510:	/* x86 executable */
-	case 0511:	/* x86 executable (TV) */
-	case 0520:	/* mc68k executable */
-	case 0521:	/* mc68k executable */
-	case 0522:	/* mc68k executable (shared) */
-	case 0550:	/* 3b20 executable */
-	case 0551:	/* 3b20 executable (TV) */
-	case 0560:	/* WE32000 executable */
-	case 0561:	/* WE32000 executable (TV) */
-	NOT_OK;
-	}
-   if ( !strncmp(Buf,"!<arch>\n",8) || !strncmp(Buf,"<ar>",4) ) NOT_OK;
-#endif
-#endif
-   if ( troffint(Buf,in) /* new troff intermediate format */ ) NOT_OK;
-   if ( Buf[0]=='\100' && Buf[1]=='\357' )
-	/* troff CAT output */ NOT_OK;
-   if (in >= 32 && Buf[0] == 0 && Buf[1] == 0 && Buf[3] == 7
-	&& (Buf[2] == 1 || Buf[2] == 4))
-		NOT_OK;	/* plan9 executables */
-   OK;
-}
-
-troffint(buf, n)	/* taken from file.c and made stricter */
-register char *buf;
-register n;
-{
-	register i, k;
-
-	i = 0;
-	for (k = 0; k < 8 && i < n; k++, i++) {
-		if (buf[i] == 'x' && buf[i+1] == ' ') {
-			i += 2;
-			if (!strncmp(buf+i, "T ", 2)
-			 || !strncmp(buf+i, "init\n", 5)
-			 || !strncmp(buf+i, "font ", 5)
-			 || !strncmp(buf+i, "res ", 4))
-		   		/* x [T|init|font|res] */
-				while (++i < n && buf[i] != '\n') ;
-			else return 0;
-			}
-		else if (buf[i] == 'f' || buf[i] == 's' ||
-			  buf[i] == 'p' || buf[i] == 'V' || buf[i] == 'H') {
-				/* p1 | f2 | s3 | V4... */
-			while (++i < n && buf[i] != '\n')
-				if (!isdigit(buf[i])) return 0;
-			}
-		else
-			return k >= 4;
-	}
-	return 1;
-}
-
-lookup(I, tab)
-int *I;
-register char *tab[];
-{
-	register char *B, *b, r, *s;
-	static char goodnext[256];
-
-	if (!goodnext[' '])
-		for(s = " \t\n\t{/"; r = *s++;) goodnext[r] = 1;
-
-	B = buf + *I;
-	while((r = *B) == ' ' || r == '\t' || r == '\n') B++;
-	if (r == 'p' && (B == buf || B[-1] == '\n')) {
-		while((r = *++B) >= '0' && r <= '9');
-		if (r == '\n') { *I = B - buf; return 1; }
-		return 0;
-		}
-	while(s = *tab++) {
-		for(b = B; (r = *s++) && r == *b; b++);
-		if (!r && goodnext[*b]) { *I = b - buf; return 1; }
-		}
-	return 0;
-	}
//GO.SYSIN DD ok.c
echo patlist.h 1>&2
sed >patlist.h <<'//GO.SYSIN DD patlist.h' 's/^-//'
-struct patlist {
-	struct patlist *nextpat;
-	char namepat[1];
-	};
//GO.SYSIN DD patlist.h
echo prune.c 1>&2
sed >prune.c <<'//GO.SYSIN DD prune.c' 's/^-//'
-/* This reads output from stree on stdin and passes a subset to stdout.
-   Invocation is:  prune pat1 pat2 ...
-   Arguments to prune are pathname shell pathname patterns, possibly
-   preceded by a ! .  The patterns may also contain the metacharacter ~ ,
-   which matches an arbitrary string that must start with / unless ~ is
-   at the beginning of the pattern and must end with / unless ~ is at
-   the end of the pattern.
-      An excluding pattern is one that starts with ! , a selecting
-   pattern one that does not.  A file is passed to stdout if its pathname
-   matches one of the selecting patterns but not one of the excluding ones.
-   Giving no selecting patterns is the same as giving the single selecting
-   pattern ~ (which matches all names).
-*/
-#include <stdio.h>
-#include "patlist.h"
-#define BUFLEN 800
-
-main(argc, argv)
-int argc;
-char **argv;
-{
-struct patlist *drop, *keep;
-int copy, endup, i;
-char buf[BUFLEN+2], c;
-
-endup = copy = 0;
-buf[BUFLEN] = '\n';
-buf[BUFLEN+1] = 0;
-getpats(argc, argv, &keep, &drop);
-while(fgets(buf, BUFLEN, stdin)) {
-	endup = 0;
-	if (!strncmp(buf, "./ ADD NAME=", 12)) {
-		for (i=12; (c=buf[i]) && c != ' ' && c != '\n'; i++);
-		buf[i] = 0;
-		copy = !skipit(buf+12, keep, drop);
-		buf[i] = c;
-		}
-	else if (!strncmp(buf, "./ ENDUP", 8)) {copy = 0; endup = 1;}
-	if (copy) fputs(buf, stdout);
-	}
-if (!endup) fprintf(stderr, "./ ENDUP line added\n");
-fputs(endup ? buf : "./ ENDUP\n", stdout);
-}
-
-fputs(s, f)
-char *s;
-FILE *f;
-{
-	register char *s1 = s;
-	while(*s1++ != '\n');
-	fwrite(s, s1-s, 1, f);
-	}
//GO.SYSIN DD prune.c
echo stree.1 1>&2
sed >stree.1 <<'//GO.SYSIN DD stree.1' 's/^-//'
-.if n .ds ~ ~
-.if t .ds ~ \v'7p'\s+6~\s-6\v'-7p'
-.TH STREE 1
-.SH NAME
-stree, ustree, prune  \(em  collapse (restore) file trees into (from) a single file
-.SH SYNOPSIS
-.B stree
-[\fIoptions\fR] \fIfile1\fR [\fIoptions\fR] \fIfile2\fR ...
-.br
-.B ustree
-[!]\fIpat1 \fR[!]\fIpat2 \fR...
-.br
-.B prune
-[!]\fIpat1 \fR[!]\fIpat2 \fR...
-.SH DESCRIPTION
-.I Stree
-copies the
-.IR file s
-(or, in the case of directories,
-all descendants) to the standard output,
-along with control information.
-Piping the output of
-.I stree
-into
-.I ustree
-will recreate the files,
-restoring the last-modified date
-and executable mode and honoring link information saved by stree.
-.PP
-Executable and troff output files, files named "core", and
-archives on which ranlib has been run
-are skipped by default; shell scripts and packed and encrypted files, however,
-.I are
-saved.  When it encounters a symbolic
-link, stree merely records the name of the file to which the
-link points.  Options for stree:
-.TP
-.BI "\-a\ " oldfile
-Save only files with \fImtime\fR newer than that of \fIoldfile\fR.
-.BI "\-A\ " oldfile
-Save only files with \fIctime\fR newer than that of \fIoldfile\fR.
-(The \fIctime\fR changes whenever one changes a file or
-its permissions or \fImtime\fR; it cannot be faked.
-The \fImtime\fR changes whenever
-the bits in the file change, but it can also be set
-arbitrarily, e.g. to an old value when a file is restored.)
-.TP
-.BI "\-b\ " nnn
-Save only files of length < \fInnn\fR.  (\fInnn\fR may include a
-trailing k to denote kilobytes, m to denote megabytes, or b
-to denote 512-byte blocks.)
-.TP
-.B \(pll
-(default) Save the text of a file (inode) the first time it is seen;
-if it is seen again, record only that it should be linked to its
-first occurrence.
-.TP
-.B \-l
-Ignore link information:  save the text of a file each time it is seen.
-.TP
-.B \(plo
-(default) Apply default omission tests described above.
-.TP
-.B \-o
-Skip the default omission tests; honor only
-the !\fIpat\fR omissions described below.
-.TP
-.B \-u
-save files in
-.IR bundle (1)
-format.
-.TP
-.BI ! pat
-Do not save files whose name matches \fIpat\fR.  The pattern \fIpat\fR
-may contain shell metacharacters (\(**, ?,  and [...], which may have to
-be quoted).  It may also contain the metacharacter \*~ described below.
-.PP
-!\fIpat\fR options are global; the others apply when seen.
-Quoted white space is treated as though unquoted:  the single
-argument \(fm!\*~\(**.o !\*~junk\(fm is treated the same as the two
-arguments \(fm!\*~\(**.o\(fm and \(fm!\*~junk\(fm .
-.PP
-\*~ works as follows:  at the beginning of a pattern,
-\*~ matches the null string and strings that end with / ; in the middle
-of a pattern, \*~ matches an arbitrary string
-that starts and ends with / ; at the end of a pattern, \*~ matches the
-null string and strings that start with / .  Examples:
-.in +.3i
-.ll -.3i
-.sp .5
-    \(fm\*~nohup.out\(fm
-matches \(fmnohup.out\(fm, \(fmtest/nohup.out\(fm, and
-\(fm/usr/me/src/nohup.out\(fm, but matches neither \(fmxnohup.out\(fm
-nor \(fm/tmp/ynohup.out.
-.sp .5
-    \(fmdoc\*~junk\(fm matches \(fmdoc/junk\(fm and
-\(fmdoc/some/old/junk\(fm, but not \(fmdoc1/junk\(fm.
-.sp .5
-    \(fmzap\*~\(fm matches \(fmzap\(fm,
-\(fmzap/zip\(fm, and \(fmzap/zot/zork\(fm but not \(fmzap1\(fm.
-.sp .5
-    \(fm\*~*out\*~\(fm matches \(fmout\(fm, \(fmtest/nohup.out\(fm,
-\(fmcur/testout/stuff\(fm, but not \(fmout1\(fm.
-.ll
-.in
-.PP
-The format was chosen so that normally all characters are printing ascii
-characters and the file contents are unchanged.
-ASCII escape and newline characters are added
-as necessary to make each file appear to be a sequence of reasonably
-sized lines, none starting with "./";
-but if any escapes have to be added, a warning message is printed.
-The control lines are of the form:
-.br
-  ./ ADD NAME=pathname/of/file TIME=123456789 X
-.br
-  ./ ADD NAME=pathname/of/file LINK=pathname/to/link/to
-.br
-  ./ ADD NAME=pathname/of/file SLNK=pathname/to/link/to/symbolically
-.br
-and
-.br
-  ./ ENDUP
-.br
-This format was chosen for compatibility with
-the IEBUPDTE utility on some IBM systems.
-.PP
-.B Ustree
-reads stree output on its standard input and restores
-some or all of the files it sees.  The arguments
-.RI [!] pat1 ", [!]" pat2 ", ..."
-select the files to be restored.  Patterns preceded by ! are
-\fIrejecting\fR patterns; the others are \fIselecting\fR patterns.
-These patterns are like the \fIpat\fR in !\fIpat\fR arguments to \fIstree\fR.
-Only files whose names match at least one selecting pattern and do not match
-any rejecting patterns are restored.  If there are no selecting patterns,
-then the selecting pattern \*~ (matching all filenames) is assumed.
-.PP
-.B Prune
-is like ustree, except that it passes selected files to its standard
-output (in \fIstree\fR format) instead of restoring them.
-.SH "SEE ALSO"
-.IR tar (1),
-.IR cpio (1)
//GO.SYSIN DD stree.1
echo stree.c 1>&2
sed >stree.c <<'//GO.SYSIN DD stree.c' 's/^-//'
-/*  version of stree that saves link information by adding LINK= or
-   SLNK= field after NAME= field of ./ ADD line.  LINK is for ``hard''
-   links, SLNK for symbolic links.
- options:
-  -a limitfile  copy only files modified after limitfile.
-  -A limitfile  (for wmc) like -a, but times are ctime rather than mtime.
-  -b limitsize	copy only files smaller than limitsize.
-  +l      (default) supply LINK field, don't copy file.
-  -l      do not supply LINK field and copy entire file instead.
-  +o	  (default) apply normal omission tests (ok())
-  -o	  consider all files ok
-  !<pat>  skip files whose names match pat
-  -u      use Unix "bundle" format for output
-
- Options and pathnames can be intermixed.  !<pat> options are global: they
- apply to all files; the other options take effect when seen.
- Patterns <pat> are the same as for the shell, with the addition of the
- metacharacter ~ , which matches an arbitrary string that must start
- with / unless ~ is at the beginning of the pattern and must end with /
- unless ~ is at the end of the pattern.
-
- Last changed Sun Aug  9 18:59:40 EDT 1987.
- This was written at AT&T Bell Laboratories by David Gay and Eric Grosse for
- personal use.  It is not copyrighted, and people may copy it at will
- if they retain this notice.  This program is not guaranteed either!  But
- since we depend on it for our own backups, we would welcome bug reports
- (to research!dmg or research!ehg).
-
-*/
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "patlist.h"
-#include "ftw.h"
-#include "string.h"
-
-struct stat stbuf;
-struct patlist *drop;
-
-char buf[BUFSIZ];
-char *progname;
-int copyall;	/* -o option: omit ok() checks */
-int bundle, nla, nonascii, npa;	/* counters for funny characters in bundle */
-int linemax;
-int in;     /* number of chars in buf */
-ino_t outino;  /* inode number of output file */
-dev_t outdev;  /* device numbers of output file */
-int escap;	/* number of escapes added on output */
-int Linkct;	/* number of links seen more than once */
-int Slnkct;	/* number of symbolic nondirectory links saved */
-int Slnkdir;	/* number of symbolic directories skipped */
-int abspath;	/* number of absolute path names saved */
-#define MAXLEVEL 96
-#define isdir(b) (((b).st_mode & S_IFMT) == S_IFDIR)
-int ifile;
-extern void exit();
-
-off_t bsize;
-
-long thresh;  /* "old file" time threshold */
-long cthresh; /* "old file" time for -A */
-#ifndef ESC
-#define ESC '\033'   /* ascii escape character */
-#endif
-#ifndef MLINLEN   /* max line length, plus or minus a few */
-#define MLINLEN 590
-#endif
-
-#define IHTABLEN 287
-#define MAXNAME 1023
-
-char linkname[MAXNAME+1];
-
-struct inodetab {
-  struct inodetab *nextint;
-  ino_t i_st_ino;
-  dev_t i_st_dev;
-  char iname[1];
-  };
-
-struct inodetab *ihtab[IHTABLEN];
-char Link = 'o';
-
-options(rc)
-{
-	static char *opt[] = {
-	 "-a limitfile	{copy only files modified after limitfile}",
-	 "-A limitfile	{like -a, but relative to ctime rather than mtime}",
-	 "-b limitsize	{copy only files smaller than limitsize}",
-	 "+o		{(default) apply normal omission checks\n\
-			 (to exclude object files, binary executables, etc.)}",
-	 "-o		{omit normal omission checks:\n\
-			 only exclude files matching !<pat>'s}",
-	 "+l		{(default) supply LINK fields instead of\n\
-			 making new copies of linked files}",
-	 "-l		{copy entire file rather than supply LINK field}",
-	 "!<pat>		{(global) skip files whose names match pat}",
-	 "-u		{(global) use \"bundle\" format for output}",
-	 0};
-	char **o = opt;
-	fprintf(stderr,
-		"usage:  %s [options] file1 [[options] file2 ...]\noptions:\n",
-		progname);
-	while(*o) fprintf(stderr, "\t%s\n", *o++);
-	exit(rc);
-	}
-
-main(argc, argv)
-  int argc;
-  char **argv;
-{
-  char c, *s;
-  int i;
-  long time();
-  struct patlist *k, *keep;
-  int copy(), ftw();
-  void getpats();
-
-  if(fstat(fileno(stdout),&stbuf) != 0){
-    fprintf(stderr,"%s: can't stat output\n", progname);
-    exit(1);
-    }
-  outino = stbuf.st_ino;
-  outdev = stbuf.st_dev;
-
-  progname = *argv;
-  getpats(argc, argv, &keep, &drop);
-
-  for (i=0; i<IHTABLEN; ) ihtab[i++] = 0;
-  for(k = keep; k; k = k->nextpat)
-    if (!strncmp(k->namepat, "-u",2)) {
-	bundle = 1;
-	printf("# to unbundle, sh this file (in an empty directory)\n");
-	}
-  for (; keep; keep = keep->nextpat){
-    s = keep->namepat;
-    if ( *s == '-' ) switch(s[1]) {
-	case 'A':
-		if (keep = keep->nextpat) {
-			if (stat(s=keep->namepat,&stbuf)<0)
-				scream("can't stat %s",s);
-			cthresh = stbuf.st_ctime;
-			thresh = 0;
-			}
-		else goto missing;
-		break;
-	case 'a':
-		if (keep = keep->nextpat) {
-			if (stat(s=keep->namepat,&stbuf)<0)
-				scream("can't stat %s",s);
-			thresh = stbuf.st_mtime;
-			cthresh = 0;
-			}
-		else {
-missing:
-		  fprintf(stderr, "%s: trailing %s ignored\n", progname, s);
-		  goto done;
-		  }
-		break;
-	case 'b':
-		if (!(keep = keep->nextpat)) goto missing;
-		bsize = 0;
-		s = keep->namepat;
-		while(c = *s++) {
-			if (c >= '0' && c <= '9') bsize = 10*bsize + c - '0';
-			else if (c == 'b' || c == 'B') { bsize <<= 9; break; }
-			else if (c == 'k' || c == 'K') { bsize <<= 10; break; }
-			else if (c == 'm' || c == 'M') { bsize <<= 20; break; }
-			else scream("bad limit size in \"-b %s\"", keep->namepat);
-			}
-		break;
-      	case 'l':
-		Link = 0;
-		break;
-	case 'o':
-		copyall = 1;
-		break;
-	case 'u':
-		break; /* already checked for -u */
-	case '?':
-		options(0);
-	default:
-		fprintf(stderr, "unknown option %s",s);
-		options(1);
-	}
-    else if (!strcmp(s, "+l")) Link = 'o';
-    else if (!strcmp(s, "+o")) copyall = 0;
-    else {
-      if(stat(s, &stbuf))
-        fprintf(stderr, "%s: can't stat %s\n", progname, s);
-      else if (ftw(s,copy,15)) exit(1);
-    }
-  }
-
-done:
-  if (bundle) {
-	squawk(nla, "newlines added");
-	squawk(nonascii, "non-ASCII characters");
-	squawk(npa, "non-printing ASCII characters");
-	if (linemax > 121) squawk(linemax-1, "characters in longest line");
-	}
-  else {
-	printf("./ ENDUP\n");
-	squawk(escap, "escapes were added");
-	}
-  squawk(Linkct,  "files saved as (hard) links");
-  squawk(Slnkdir, "directories skipped and saved as symbolic links");
-  squawk(Slnkct,  "nondirectories saved as symbolic links");
-  squawk(abspath, "absolute path names saved");
-  exit(0);
-}
-
-squawk(n, msg)
-char *msg;
-{ if (n) fprintf(stderr, "%s: %d %s\n", progname, n, msg); }
-
-int
-copy(source, sbuf, info, follow)
-   char *source;
-   struct stat *sbuf;
-   int info, *follow;
-{
-   static int level = 0;
-   long time;
-   int n;
-
-   if (sbuf->st_ino == outino && sbuf->st_dev == outdev)  {
-	fprintf(stderr,"skipped {outputfile} %s\n",source);
-	return 0;
-	}
-
-   switch(info) {
-
-  case FTW_F:  /* ordinary file */
-    if (strchr(source,' ')) {
-    	fprintf(stderr, "Skipping \"%s\" because of blanks in name.\n",source);
-	break;
-	}
-    if (skipit(source, (struct patlist *) 0, drop)) break;
-    if ( (time = sbuf->st_mtime) > thresh && sbuf->st_ctime > cthresh) {
-      if( (ifile = open(source,0)) < 0) {
-        fprintf(stderr, "can't open %s\n", source);
-        break;
-        }
-      if ( ( in = read(ifile,buf,BUFSIZ) ) < 0 )
-        scream("input error on %s", source);
-      if (copyall || ok(source)) {
-	if (!bsize || sbuf->st_size < bsize)
-		copyfil(sbuf, source, time);
-	else
-		fprintf(stderr, "Skipped big (%ld) %s\n", sbuf->st_size, source);
-	}
-      else fprintf(stderr,"skipped %s\n",source);
-      if (close(ifile) < 0) scream("can't close %s", source);
-      }
-    break;
-
-  case FTW_D:  /* preorder directory visit */
-    if (skipit(source, (struct patlist *) 0, drop))
-      *follow = FTW_SKD;
-    else if (++level > MAXLEVEL)
-      scream("directories nested too deep","");
-    if(bundle&&(strcmp(".",source)!=0)) printf("mkdir %s\n",source);
-    break;
-
-  case FTW_DNR:  /* unreadable directory */
-          fprintf(stderr,"skipped unreadable directory %s\n",source);
-    break;
-
-  case FTW_NS:  /* unstatable file */
-    fprintf(stderr,"skipped unstatable file %s\n", source);
-    break;
-
-  case FTW_DP:  /* postorder directory visit */
-    level--;
-    break;
-
-#ifdef S_IFLNK
-  case FTW_SL:  /* symbolic link */
-    if ( sbuf->st_mtime <= thresh ) break;
-    if ( sbuf->st_ctime <= cthresh ) break;
-    if (!stat(source, &stbuf) && isdir(stbuf)) Slnkdir++;
-    else Slnkct++;
-    n = readlink(source, linkname, MAXNAME);
-    if (n > MAXNAME)
-      scream("Symbolic path to %s too long.\n", source);
-    linkname[n] = 0;
-    if(bundle) printf("ln -s %s %s\n", linkname, source);
-     else printf("./ ADD NAME=%s SLNK=%s\n", source, linkname);
-    break;
-#endif
-
-  default:
-    fprintf(stderr, "stree: ftw called copy with info = %d\n",
-      info);
-    exit(1);
-  }
-   return 0;
-}
-
-copyfil( sbuf, source, time )
-  char *source;
-  long time;
-  struct stat *sbuf;
-{
-  register int i;
-  register int j=0;      /* number of chars output on current line */
-  register int p;
-  register char *Buf = buf;
-  char *x;
-  char *s=source;
-  int execut;
-
-  if (*source == '/') abspath++;
-  if (bundle) {
-    if (linkchk(linkname, sbuf, source)) {
-      printf("ln %s %s\n", linkname,s);
-      return;
-      }
-    printf("echo %s 1>&2\nsed >%s <<'//GO.SYSIN DD %s' 's/^-//'\n",s,s,s);
-    execut = sbuf->st_mode & S_IEXEC;
-    for(i=0; i<in; ){
-	if (!j++) putchar('-');
-	putchar(Buf[i]);
-	switch(p = (unsigned char) Buf[i]) {
-		case '\n': if (linemax < j) linemax = j;
-			   j = 0; break;
-		case '\t': break;
-		case 0x7f: npa++; break; /* DEL */
-		default:
-			if (p < ' ') npa++;
-			else if (p > 0x7f) nonascii++;
-		}
-	if (++i >= in) {
-		if( (in = read (ifile, Buf, BUFSIZ)) < 0)
-			scream("input error on %s", source);
-		if(!in && j) /* ensure each file is terminated by a newline */
-			{ putchar('\n'); nla++; }
-		i=0;
-		}
-	}
-     printf("//GO.SYSIN DD %s\n",s);
-     if(execut) printf("chmod +x %s\n",s);
-     }
-
-  else { /* not bundle */
-    printf("./ ADD NAME=%s", source);
-    if (linkchk(linkname, sbuf, source)) {
-      printf(" LINK=%s\n", linkname);
-      return;
-      }
-    p = 0;	/* p == 1 ==> just saw a . at the start of a line */
-    x = (sbuf->st_mode & S_IEXEC) ? " X" : "";
-    printf(" TIME=%ld%s\n", time, x);
-    for(i=0; i<in; ){
-	if( p==1 ){
-		if( (Buf[i]=='/') ){ putchar(ESC); j++; escap++; }
-		else p = 0;
-		}
-	if( Buf[i]==ESC ) { putchar(ESC); j++; escap++; }
-	else if(j == 0 && Buf[i] == '.') p=1;
-	putchar(Buf[i]); j++;
-	if( Buf[i]=='\n' ) j = 0;
-	/*  break long lines */
-	else if( j > MLINLEN-2 )
-		{ putchar(ESC); putchar('\n'); j = 0; escap++; }
-	i++;
-	if( i>=in ){
-		if ( (in = read (ifile, Buf, BUFSIZ)) < 0)
-			scream("input error on %s", source);
-		if (in == 0 && j) {
-			/* ensure that each file is terminated by a newline */
-			putchar(ESC); putchar('\n');
-			escap++;
-			}
-		i=0;
-		}
-	}
-    }
-}
-
-scream (s1, s2)
-   char *s1, *s2;
-{
-   fprintf (stderr, "stree: ");
-   fprintf (stderr, s1, s2);
-   putc ('\n', stderr);
-   exit(1);
-}
-
-int linkchk(ln,sbuf,source)
-char *ln, *source;
-struct stat *sbuf;
-{
-  struct inodetab *p, *p0;
-  char *malloc();
-  int i;
-  register char c, *s;
-
-  if (!Link) return (0);
-  if (sbuf->st_nlink < 2) return(0);
-  p0 = (struct inodetab *)
-  (((sbuf->st_dev + sbuf->st_ino) % IHTABLEN) + ihtab);
-  while ((p = p0->nextint) &&
-    (p->i_st_ino != sbuf->st_ino ||
-     p->i_st_dev != sbuf->st_dev)) p0 = p;
-
-  if (p) {/* If this is a link to a file already seen... */
-    /* then set ln to the overall path name... */
-
-    for (s = p->iname, i = 0; (c = *s++) && i < MAXNAME; ) ln[i++] = c;
-    if (i >= MAXNAME) scream("Path name to link too long.\n","");
-    ln[i] = '\0';
-    Linkct++;
-    return 1;
-    }
-
-  /* This file has more than one link to it -- add it to the list of files */
-  /* that may be seen later. */
-
-  p = (struct inodetab *)
-  malloc((unsigned) (sizeof(struct inodetab) + strlen(source)));
-  p0->nextint = p;
-  p->nextint = 0;
-  p->i_st_ino = sbuf->st_ino;
-  p->i_st_dev = sbuf->st_dev;
-  strcpy(p->iname, source);
-  return (0);
-  }
-
-#include "ok.c"
//GO.SYSIN DD stree.c
echo ustree.c 1>&2
sed >ustree.c <<'//GO.SYSIN DD ustree.c' 's/^-//'
-/*  version of ustree that restores links (including symbolic links)
-    and ignores extra ./ ENDUP lines.  This ustree also takes arguments:
-    it reads output from stree on stdin and restores a subset.
-
-   Invocation is:  ustree pat1 pat2 ...
-
-   Arguments to ustree are pathname shell pathname patterns, possibly
-   preceded by a ! .  The patterns may also contain the metacharacter ~ ,
-   which matches an arbitrary string that must start with / unless ~ is
-   at the beginning of the pattern and must end with / unless ~ is at
-   the end of the pattern.
-      An excluding pattern is one that starts with ! , a selecting
-   pattern one that does not.  A file is restored if its pathname
-   matches one of the selecting patterns but not one of the excluding ones.
-   Giving no selecting patterns is the same as giving the single selecting
-   pattern ~ (which matches all names).
-*/
-
-#include "patlist.h"
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/dir.h>
-#include <ctype.h>
-#include "string.h"
-#ifndef ESC
-#define ESC '\033'
-#endif
-#define LMAX 600
-#define MAXNAME 1000
-char buf[LMAX];
-char *getline();
-FILE *ofile = 0;
-struct stat stbuf;
-char olddir[MAXNAME];
-
-main(argc,argv)
-int argc;
-char **argv;
-{
-  char linkname[MAXNAME], name[MAXNAME], nname[MAXNAME];
-  long time, ntime;
-  int execut, nexecut;
-  time_t timep[2];
-  int canend=0, copytext=0, cntl, endup=0, rc=0;
-  struct patlist *keep, *drop;
-  struct stat sbuf;
-
-  /* body */
-
-  getpats(argc, argv, &keep, &drop);
-  olddir[0] = '\0';
-  name[0] = '\0';
-  for(;;){
-    if(!getline(buf,LMAX)) {
-	if (endup > 1) printf("ustree: %d ./ ENDUP lines seen\n", endup);
-	if (canend) exit(rc);
-	scream("missing `./ ENDUP' after `%s'?", name);
-	}
-    canend = 0;
-    if( (cntl=dotslash(linkname,nname,&ntime,&nexecut)) != 0 ){
-       if(ofile){
-	 if (execut) {
-		fstat(fileno(ofile), &sbuf);
-		/* could use fchmod, but that's less portable */
-		chmod(name, sbuf.st_mode | 0111);
-		}
-	 fclose(ofile);
-	 if(time){ timep[0]=time; timep[1]=time; utime(name,timep); }
-	 ofile = 0;
-	 }
-       copytext = 0;
-       if(cntl==2) { /* ./ ENDUP  */
-		endup++;
-		canend = 1;
-		continue;
-		}
-       strcpy(name,nname);
-       if (skipit(name,keep,drop)) continue;
-       dirchk(name);
-       if (cntl==1) /* non-link */ {
-	  time = ntime;
-	  execut = nexecut;
-	  if (ofile = fopen(name,"w"))
-	  	copytext = 1;
-	  else
-		printf("ustree: can't create %s\n",name);
-	  }
-	else /*link*/ {
-	  unlink(name); /* get rid of old copy, if any */
-	  if (cntl==3 && !link(linkname,name)) continue;
-#ifdef S_IFLNK
-	  if (symlink(linkname,name))
-		{printf("can't link %s to %s\n",name,linkname); exit(1);}
-	  if (cntl==3) printf("hard link %s to %s fails; symbolic link made\n",
-				name, linkname);
-#else
-		printf("Can't symbolically link %s to %s\n", name, linkname);
-		rc = 1;
-#endif
-	  }
-       }
-    else if (copytext) putline(buf);
-    }
-}
-
-int
-dotslash (linkname,name,time,execut)
-  char *linkname, name[];
-  long *time;
-  int *execut;
-{
-  int i;
-  char c;
-
-  name[0]='\0';
-  *time=0;
-  if( (buf[0]=='.') && (buf[1]=='/') ){
-    if(!strncmp(buf+2," ADD NAME=",10)){
-      for(i=12; i<LMAX-1 && buf[i]!=' ' && buf[i] != '\n'; i++)
-		name[i-12] = buf[i];
-      name[i-12]='\0';
-      if (!strncmp(buf+i," LINK=",6)) {
-	 for(i += 6; i<LMAX-1 && (c = buf[i]) != ' ' && c != '\n'; )
-		*linkname++ = buf[i++];
-	 *linkname = '\0';
-	 return(3);
-	 }
-      if (!strncmp(buf+i," SLNK=",6)) {
-	 for(i += 6; i<LMAX-1 && (c = buf[i]) != ' ' && c != '\n'; )
-		*linkname++ = buf[i++];
-	 *linkname = '\0';
-	 return(4);
-	 }
-      if (!strncmp(buf+i," TIME=",6)){sscanf(buf+i+6,"%ld",time);}
-      *execut = (!strncmp(strchr(buf,'\n')-2," X",2)) ? 1 : 0;
-      return(1);
-      }
-    else if( !strncmp(buf+2," ENDUP",6) ){ return(2); }
-    }
-  return(0);
-}
-
-scream (s1, s2)
-   char *s1, *s2;
-{
-   printf ( "ustree: ");
-   printf ( s1, s2);
-   putchar ('\n');
-   exit(1);
-}
-
-char *
-getline ( b, l )
-  char b[];
-  int l;
-{
-  int c;
-  int i=0;
-  int j;
-  for(;;){
-    c=getchar();
-    if(c==EOF) return(NULL);  /* error or end-of-file */
-    if(i==l){
-      printf("line too long %d\n",i);
-      for(j=0;j<=i;j++){
-	c=buf[j];
-	if(isprint(c)){ printf(" %c",c); }
-	 else{ printf(" %o",(int)c); }
-	}
-      return(NULL);
-      }
-    b[i++]=c;
-    if(c=='\n') return(b);  /* full line */
-    }
-}
-
-putline(b)
-  char b[];
-{
-  int i;
-  for(i=0;;i++){
-    if(b[i]==ESC){ if( b[++i]=='\n' ) break; }
-    putc(b[i],ofile);
-    if( b[i]=='\n' ) break;
-    }
-}
-
-dirchk(name)
-char *name;
-{
-int i, j;
-char c;
-for (i=j=0; (c = name[i]) == olddir[i] && c;) {i++; if (c == '/') j = i;}
-if (!c && !olddir[i]) scream("`%s' is a directory already seen", name);
-for (i=j; c = name[i]; i++) {
-	if (c == '/' && i) {
-		j = i+1;
-		olddir[i] = '\0';
-		if (stat(olddir,&stbuf)) {
-#ifdef USE_SYSTEM
-			/* Compile with -DUSE_SYSTEM if the */
-			/* mkdir system call is missing... */
-			char cmd[MAXNAME+16];
-			sprintf(cmd, "mkdir %s", olddir);
-			if (system(cmd))
-#else
-			if (mkdir(olddir, 0777))
-#endif
-				scream("mkdir fails on %s", olddir);
-			}
-		else if (!(stbuf.st_mode & S_IFDIR))
-			scream("`%s' is not a directory", olddir);
-		}
-	olddir[i] = c;
-	}
-olddir[j] = '\0';
-}
//GO.SYSIN DD ustree.c