[net.micro.amiga] make for amiga

fnf@unisoft.UUCP (12/05/85)

Here is a much hacked up version of a make posted to net.sources
earlier this year.  This particular copy is known to run on
the amiga under version 1.0 of AmigaDos, and on unix under
system V.  One thing I have not yet tested is the local archiver
facility (lar).

-Fred

#--------CUT---------CUT---------CUT---------CUT--------#
#########################################################
#                                                       #
# This is a shell archive file.  To extract files:      #
#                                                       #
#    1)	Make a directory for the files.                 #
#    2) Write a file, such as "file.shar", containing   #
#       this archive file into the directory.           #
#    3) Type "sh file.shar".  Do not use csh.           #
#                                                       #
#########################################################
#
#
echo Extracting Makefile:
sed 's/^Z//' >Makefile <<\STUNKYFLUFF
Z#
Z# MSDOS Make utility
Z# (compile with Wizard C version 2.0)
Z#
Z
ZCC =		cc
Z#CFLAGS =	-O -DDBUG
ZCFLAGS =	-O
Z#LIBS =		-ldbug
ZLIBS =
Z
ZH =		make.h
Z
ZFILES =		$H make.c macro.c token.c parsedir.c file.c osdate.c execute.c
Z
Z#  This version of make currently does not grok continuation lines with
Z#  escaped newlines.  To avoid extra long lines, we define some intermediate
Z#  macros.
Z
ZOBJS1 =		make.o macro.o token.o parsedir.o file.o osdate.o
ZOBJS2 =		getdir.o lwtol.o execute.o sys.o
ZOBJS =		$(OBJS1) $(OBJS2)
Z
ZLSRC1 =		make.c macro.c token.c parsedir.c file.c osdate.c
ZLSRC2 =		getdir.c lwtol.c execute.c sys.c
ZLSRC =		$(LSRC1) $(LSRC2)
Z
ZDOCUMENTATION = readme make.man makefile
Z
Zall :		pdmake
Z
Zpdmake :	$(OBJS)
Z		$(CC) -o pdmake $(OBJS) $(LIBS)
Z
Zmake.o :	make.c $H
Z		$(CC) $(CFLAGS) -c make.c
Z
Zmacro.o :	macro.c $H
Z		$(CC) $(CFLAGS) -c macro.c
Z
Ztoken.o :	token.c $H
Z		$(CC) $(CFLAGS) -c token.c
Z
Zparsedir.o :	parsedir.c $H
Z		$(CC) $(CFLAGS) -c parsedir.c
Z
Zfile.o :	file.c $H
Z		$(CC) $(CFLAGS) -c file.c
Z
Zexecute.o :	execute.c $H
Z		$(CC) $(CFLAGS) -c execute.c
Z
Zosdate.o :	osdate.c $H lar.h
Z		$(CC) $(CFLAGS) -c osdate.c
Z
Zsys.o :		sys.c $H
Z		$(CC) $(CFLAGS) -c sys.c
Z
Z#
Z#	Makefile for lar.
Z#
Z
Zlar.exe : lwtol.o getdir.o lar.o 
Z	link lar+lwtol+getdir,lar,lar/map
Z
Zlar.o : lar.lar ( lar.c lar.h )
Z	cc -c lar.c
Z
Z#
Z# Files shared by lar and make.
Z#
Z
Zgetdir.o :	getdir.c lar.h
Z		$(CC) $(CFLAGS) -c getdir.c
Z
Zlwtol.o :	lwtol.c lar.h
Z		$(CC) $(CFLAGS) -c lwtol.c
Z
Z#
Z# Print files associated with MAKE
Z#
Z
Zprint :
Z	print make.man $(FILES) makefile
Z
Z#
Z# collect source and documentation files
Z#
Z
Zcollect :
Z	lar uv make.lar $(FILES) $(DOCUMENTATION)
Z	lar uv lar.lar lar.c lar.h lwtol.c getdir.c
Z	lar rv make.lar
Z	lar rv lar.lar
Z
Z#
Z# copy to distribution disk (on A:)
Z#
Zdistribution :
Z	copy readme a:
Z	copy make.man a:
Z	copy makefile a:
Z	copy make.c a:
Z	copy macro.c a:
Z	copy token.c a:
Z	copy parsedir.c a:
Z	copy file.c a:
Z	copy osdate.c a:
Z	copy execute.c a:
Z	copy lar.h a:
Z	copy lar.c a:
Z	copy getdir.c a:
Z	copy lwtol.c a:
Z	copy makemake.exe a:
Z
Z
Z
Zlint:
Z	lint $(LSRC) >lint.out
STUNKYFLUFF
set `sum Makefile`
if test 03906 != $1
then
echo Makefile: Checksum error. Is: $1, should be: 03906.
fi
#
#
echo Extracting execute.c:
sed 's/^Z//' >execute.c <<\STUNKYFLUFF
Z#ifndef AMIGA
Z#  include <errno.h>
Z#endif
Z
Z#ifdef MSDOS
Z#  include <bdos.h>
Z#endif
Z
Z#include <stdio.h>
Z#include <ctype.h>
Z#include "make.h"
Z
Z#ifndef FALSE
Z#  define FALSE (0)
Z#endif
Z
Z#ifndef TRUE
Z#  define TRUE (1)
Z#endif
Z
Z#define BUFFSIZ (256)
Z
Z#ifdef MSDOS
Zextern char *searchpath ();
Z#endif
Z
Zextern char *getenv ();
Z
Z#ifdef MSDOS
Zextern int _envseg;
Z#ifndef NOREALEXECUTE
Zstatic char param[256];
Zstatic char cmd[256];
Zstatic char *cmds[] = {
Z    "break",
Z    "chdir",
Z    "cd",
Z    "cls",
Z    "copy",
Z    "ctty",
Z    "date",
Z    "del",
Z    "erase",
Z    "dir",
Z    "echo",
Z    "exit",
Z    "for",
Z    "goto",
Z    "if",
Z    "mkdir",
Z    "md",
Z    "path",
Z    "pause",
Z    "prompt",
Z    "rem",
Z    "ren",
Z    "rename",
Z    "rmdir",
Z    "rd",
Z    "set",
Z    "shift",
Z    "time",
Z    "type",
Z    "ver",
Z    "verify",
Z    "vol",
Z    0
Z};
Z#endif	/* !NOREALEXECUTE */
Z#endif	/* MSDOS */
Z
Zexecute (str, noexecflag)
Zchar *str;
Zint noexecflag;
Z{
Z    auto char tmp[BUFFSIZ];
Z    auto char buf[10];
Z    register int index = 0;
Z    register int rval;
Z    extern int ignore_errors;
Z
Z    DBUG_ENTER ("execute");
Z    tmp[0] = EOS;
Z    while (*str != EOS) {
Z	if (*str == '\n') {
Z	    tmp[index] = EOS;
Z	    index = 0;
Z	    str++;
Z	    if ((rval = run (tmp, noexecflag)) != 0 && !ignore_errors) {
Z		fputs ("***Error Code ", stderr);
Z		itoa (rval, buf);
Z		fputs (buf, stderr);
Z		fputc ('\n', stderr);
Z		DBUG_RETURN (rval);
Z	    }
Z	} else if (index == (BUFFSIZ - 1)) {
Z	    fputs ("Command Too Long: ", stderr);
Z	    fputs (str, stderr);
Z	    fputs ("\nShorten.\n", stderr);
Z	    DBUG_RETURN (-1);
Z	} else {
Z	    tmp[index++] = *str++;
Z	}
Z    }
Z    DBUG_RETURN (0);
Z}
Z
Z
Z
Z#ifdef TESTING
Zmain ()
Z{
Z    auto char temp[128];
Z
Z    for (;;) {
Z	printf ("Command: ");
Z	gets (temp);
Z	if (temp[0] == EOS) {
Z	    break;
Z	}
Z	printf ("        Execute: %d\n", run (temp));
Z    }
Z}
Z#endif
Z
Z/* run(str)
Z * char *str;
Z *		returns the value of the executed command.  If the command is
Z *		an MS-DOS resident command the command.com is executed else
Z *		the program is invoked (looking down the PATH).
Z *
Z *		Written: Bradley N. Davis  University of Utah VCIS group
Z *		Date: 4-Jan-84
Z *
Z */
Z
Zstatic int run (str, noexecflag)
Zchar *str;
Zint noexecflag;
Z{
Z#ifdef MSDOS
Z    auto struct execp ep;
Z    auto struct SREGS segs;
Z#else
Z    extern int system ();
Z#endif
Z    auto int status = 0;
Z
Z    DBUG_ENTER ("run");
Z    while (*str == '\t' || *str == ' ') {
Z	str++;
Z    }
Z    putchar ('\t');
Z    puts (str);
Z    fflush (stdout);
Z    if (!noexecflag) {
Z#ifndef NOREALEXECUTE
Z#ifdef MSDOS
Z	if (str[0] == EOS) {	/* Blank Line? push to subshell */
Z	    strcpy (cmd, getenv ("COMSPEC"));
Z	    param[0] = EOS;
Z	    segread (&segs);
Z	    ep.ex_envseg = _envseg;
Z	    ep.ex_cmdadd = (unsigned) param;
Z	    ep.ex_cmdseg = segs.ss;
Z	    ep.ex_fcb1ad = 0;
Z	    ep.ex_fcb1sg = 0;
Z	    ep.ex_fcb2ad = 0;
Z	    ep.ex_fcb2sg = 0;
Z	    status = (exec (cmd, 0, &ep));
Z	} else if (resident (str)) {
Z	    status = (system (str));
Z	} else {
Z	    status = (program (cmd, param));
Z	}
Z#else
Z	CHECK_ABORT;
Z	status = system (str);
Z#endif	/* MSDOS */
Z#endif  /* !NOREALEXECUTE */
Z    }
Z    DBUG_3 ("sys", "subcommand returns status %d", status);
Z    DBUG_RETURN (status);
Z}
Z
Z/*
Z * resident(str)
Z * char *str;
Z *		returns true if the command in str is an MS-DOS resident
Z *		command.
Z *
Z *		Written: Bradley N. Davis  University of Utah VCIS group
Z *		Date: 4-Jan-84
Z *
Z */
Z
Z#define iswhite(ch) (ch == ' ' || ch == '\t')
Z
Z#ifdef MSDOS
Z#ifndef NOREALEXECUTE
Zstatic int resident (str)
Zchar *str;
Z{
Z    register char **t;
Z    extern char *strpbrk ();
Z    register int i;
Z    register int j;
Z
Z    DBUG_ENTER ("resident");
Z    while (iswhite (*str)) {
Z	str++;			/* trim blanks */
Z    }
Z    if (str[1] == ':' && isalpha (str[0])) {	/* look for x: */
Z	DBUG_RETURN (TRUE);
Z    }
Z    if (strpbrk (str, "<>|") != NULL) {		/* redirection? use system */
Z	DBUG_RETURN (TRUE);
Z    }
Z    i = 0;
Z    while (isalnum (*str)) {
Z	if (isupper (*str)) {
Z	    cmd[i++] = *str++ - 'A' + 'a';
Z	} else {
Z	    cmd[i++] = *str++;
Z	}
Z    }
Z    cmd[i] = EOS;
Z    for (t = cmds; *t; t++) {
Z	if (strcmp (*t, cmd) == 0) {
Z	    DBUG_RETURN (TRUE);
Z	}
Z    }
Z    strcat (cmd, ".bat");	/* Batch file? use system */
Z    if (searchpath (cmd) != 0) {
Z	cmd[i] = EOS;
Z	DBUG_RETURN (TRUE);
Z    }
Z    cmd[i] = EOS;
Z    j = strlen (str);
Z    i = 1;
Z    while ((param[i++] = *str++) != 0);
Z    param[0] = j;
Z    param[j + 1] = '\r';
Z    DBUG_RETURN (FALSE);
Z}
Z
Zstatic int program (pcmd, pparam)
Zchar *pcmd;
Zchar *pparam;
Z{
Z#ifdef MSDOS
Z    auto struct execp ep;
Z    auto struct SREGS segs;
Z    register char *pathp;
Z    register int len;
Z
Z    DBUG_ENTER ("program");
Z    len = strlen (pcmd);
Z    strcat (pcmd, ".com");
Z    pathp = searchpath (pcmd);
Z    if (pathp == 0) {
Z	pcmd[len] = EOS;
Z	strcat (pcmd, ".exe");
Z	pathp = searchpath (pcmd);
Z	if (pathp == 0) {
Z	    pcmd[len] = EOS;
Z	    errno = ENOENT;
Z	    DBUG_RETURN (-1);
Z	}
Z    }
Z    segread (&segs);
Z    ep.ex_envseg = _envseg;
Z    ep.ex_cmdadd = (unsigned) pparam;
Z    ep.ex_cmdseg = segs.ss;
Z    ep.ex_fcb1ad = 0;
Z    ep.ex_fcb1sg = 0;
Z    ep.ex_fcb2ad = 0;
Z    ep.ex_fcb2sg = 0;
Z    DBUG_RETURN (exec (pathp, 0, &ep));
Z#else
Z    fprintf (stderr, "Urk -- 'program()' unimplemented!\n");
Z    DBUG_RETURN (0);
Z#endif
Z}
Z#endif	/* !NOREALEXECUTE */
Z#endif	/* MSDOS */
Z
Z
Z#ifdef AMIGA
Z/*
Z *	Do explicit check for abort.  When Enable_Abort is non-zero,
Z *	Chk_Abort() cause program termination if CNTRL-C or CNTRL-D has
Z *	been received.  Thus, we temporarily set it back to zero while we
Z *	do the explicit test, so we can do our own clean up and exit.
Z *	Note that if the -V flag was used, we spit out a confirming message
Z *	that we are quitting.
Z *
Z */
Z 
Zvoid Check_Abort ()
Z{
Z    DBUG_ENTER ("Check_Abort");
Z    DBUG_2 ("abort", "do explicit test for CNTRL-C");
Z    DISABLE_ABORT;
Z    if (Chk_Abort () != 0) {
Z	exit (1);
Z    }
Z    ENABLE_ABORT;
Z    DBUG_VOID_RETURN;
Z}
Z
Z#endif	/* AMIGA */
STUNKYFLUFF
set `sum execute.c`
if test 63439 != $1
then
echo execute.c: Checksum error. Is: $1, should be: 63439.
fi
#
#
echo Extracting file.c:
sed 's/^Z//' >file.c <<\STUNKYFLUFF
Z#include <stdio.h>
Z#include "make.h"
Z
Zstatic FILENODE *addtolist ();
Zstatic FILENODE *afnode ();
Z
Z/*
Z * Return file-node for 'fname'.
Z * If it doesn't exist, then create one.
Z */
Z
ZFILENODE *filenode (fname)
Zchar *fname;
Z{
Z    register FILENODE *f;
Z
Z    DBUG_ENTER ("filenode");
Z    DBUG_3 ("fnode", "locate or create node for file '%s'", fname);
Z    if ((f = gfile (fname)) == (FILENODE *) NULL) {
Z	f = afnode (fname);
Z    }
Z    DBUG_RETURN (f);
Z}
Z
Z/*
Z * Add a dependency to the node 'fnd'.
Z * 'fnd' will depend on 'fname'.
Z *
Z * Returns dependent node associated with 'fname'.
Z */
Z
ZFILENODE *addfile (fnd, fname)
ZFILENODE *fnd;
Zchar *fname;
Z{
Z    register NODE *n;
Z    register FILENODE *f;
Z
Z    DBUG_ENTER ("addfile");
Z    if (fnd == (FILENODE *) NULL) {	/* punt if no root file */
Z	fputs ("No current root, can't add dependency '", stderr);
Z	fputs (fname, stderr);
Z	fputs ("%s'\n", stderr);
Z	DBUG_RETURN ((FILENODE *) NULL);
Z    }
Z    DBUG_4 ("fdep", "add dependency of '%s' on '%s'", fnd -> fname, fname);
Z    f = filenode (fname);
Z    if ((n = (NODE *) Calloc (1, sizeof (NODE))) == (NODE *) NULL) {
Z	allerr ();
Z    }
Z    n -> nnext = fnd -> fnode;
Z    fnd -> fnode = n;
Z    n -> nfile = f;
Z    DBUG_RETURN (f);
Z}
Z
Z
Z/*
Z * Add a line of method-text to the node 'fnode'.
Z */
Z
Zvoid addmeth (fnode, methtext)
ZFILENODE *fnode;
Zchar *methtext;
Z{
Z    register int len;
Z    register char *new;
Z    extern void free ();
Z
Z    DBUG_ENTER ("addmeth");
Z    if (fnode != (FILENODE *) NULL && methtext != NULL) {
Z	len = strlen (methtext) + 2;
Z	if (fnode -> fmake == NULL) {
Z	    if ((fnode -> fmake = (char *) Calloc (1, 1)) == NULL) {
Z		allerr ();
Z	    }
Z	    *(fnode -> fmake) = '\0';
Z	}
Z	len += strlen (fnode -> fmake);
Z	/* Lattice C does not have 'realloc()', so this kludges around it: */
Z	if ((new = (char *) Calloc (1, len)) == NULL) {
Z	    allerr ();
Z	}
Z	strcpy (new, fnode -> fmake);
Z	free (fnode -> fmake);
Z	fnode -> fmake = new;
Z	strcat (fnode -> fmake, methtext);
Z	len = strlen (fnode -> fmake);
Z	if (len > 0 && fnode -> fmake[len - 1] != '\n') {
Z	    strcat (fnode -> fmake, "\n");
Z	}
Z    }
Z    DBUG_VOID_RETURN;
Z}
Z
Z/*
Z * Add token to the parent list.  Return the pointer to the new parent.
Z * If token is already on the parent list, simply return the pointer found.
Z */
Z
Zstatic FILENODE *addtolist (tok, list)
Zchar *tok;
ZNODE **list;
Z{
Z    register NODE *search;
Z    register NODE *newnode;
Z
Z    DBUG_ENTER ("addtolist");
Z    for (search = *list; search != (NODE *) NULL; search = search -> nnext) {
Z	if (STRSAME (search -> nfile -> fname, tok)) {
Z	    DBUG_RETURN (search -> nfile);
Z	}
Z    }
Z    /* token not found so far... add it to list */
Z    if ((newnode = (NODE *) Calloc (1, sizeof (NODE))) == (NODE *) NULL) {
Z	allerr ();
Z    }
Z    search = *list;
Z    *list = newnode;
Z    newnode -> nnext = search;
Z    if ((newnode -> nfile = (FILENODE *) Calloc (1, sizeof (FILENODE))) == (FILENODE *) NULL) {
Z	allerr ();
Z    }
Z    if ((newnode -> nfile -> fname = (char *) Calloc (1, strlen (tok) + 1)) == NULL) {
Z	allerr ();
Z    }
Z    strcpy (newnode -> nfile -> fname, tok);
Z    newnode -> nfile -> fdate = (DATE) NULL;
Z    newnode -> nfile -> fnode = (NODE *) NULL;
Z    newnode -> nfile -> parent = (FILENODE *) NULL;
Z    newnode -> nfile -> fflag = 0;
Z    newnode -> nfile -> fnext = NULL;
Z    DBUG_RETURN (newnode -> nfile);
Z}
Z
Zstatic  NODE *parentlist = (NODE *) NULL;
Z
ZFILENODE *addparent (tok)
Zchar *tok;
Z{
Z    FILENODE *np;
Z    
Z    DBUG_ENTER ("addparent");
Z    np = addtolist (tok, &parentlist);
Z    DBUG_RETURN (np);
Z}
Z
Z#ifdef FUNNYLIBS
Z
Zisonlibrary (f)			/* return SUCCEED if f is a library. */
ZFILENODE *f;			/* set f->fdate to parent's date */
Z{
Z    DBUG_ENTER ("isonlibrary");
Z    if (f -> fflag & LIBRARY) {
Z	getdate (f -> parent);
Z	f -> fdate = f -> parent -> fdate;
Z	DBUG_RETURN (SUCCEED);
Z    }
Z    DBUG_RETURN (FAILURE);
Z}
Z
Z#else
Z
Z/*
Z * Add file node fnd to library list.
Z */
Z
Zstatic FILENODE *librarylist = (FILENODE *) NULL;
Z
Zvoid AddToLibrary (fnd)
ZFILENODE *fnd;
Z{
Z    register NODE *n;
Z
Z    DBUG_ENTER ("AddToLibrary");
Z    DBUG_3 ("lib", "add node for '%s' to library list", fnd -> fname);
Z    if (librarylist == (FILENODE *) NULL) {
Z	if ((librarylist = (FILENODE *) Calloc (1, sizeof (FILENODE))) == (FILENODE *) NULL) {
Z	    allerr ();
Z	}
Z	librarylist -> fnode = (NODE *) NULL;
Z    }
Z    if ((n = (NODE *) Calloc (1, sizeof (NODE))) == (NODE *) NULL) {
Z	allerr ();
Z    }
Z    n -> nnext = librarylist -> fnode;
Z    librarylist -> fnode = n;
Z    n -> nfile = fnd;
Z    DBUG_VOID_RETURN;
Z}
Z
Z/*
Z * Return SUCCEED if filenode f is a direct descendant of a library;
Z * set f->fdate to parent's time.
Z */
Z
Zisonlibrary (f)
ZFILENODE *f;
Z{
Z    register NODE *lib;
Z    register NODE *dep;
Z
Z    DBUG_ENTER ("isonlibrary");
Z    DBUG_3 ("isonlib", "Searching for: %s", f -> fname);
Z    if (librarylist == (FILENODE *) NULL) {
Z	DBUG_RETURN (FAILURE);
Z    }
Z    for (lib = librarylist->fnode; lib != (NODE *)NULL; lib = lib->nnext) {
Z	for (dep = lib->nfile->fnode; dep != (NODE *)NULL; dep = dep->nnext) {
Z	    DBUG_3 ("dep", "Examining: %s", dep -> nfile -> fname);
Z	    if (f == dep -> nfile) {		/* found it!! */
Z		DBUG_3 ("dep", "found %s", dep -> nfile -> fname);
Z		DBUG_3 ("dep", "depends on %s", lib -> nfile -> fname);
Z		f -> fdate = lib -> nfile -> fdate;	/* update time */
Z		DBUG_RETURN (SUCCEED);
Z	    }
Z	}
Z    }
Z    DBUG_RETURN (FAILURE);
Z}
Z#endif
Z
Zisanarchive (f)			/* return SUCCEED if f is an archive */
ZFILENODE *f;			/* set f->fdate to date in parent's */
Z{				/* archive directory */
Z    DATE getarchdate ();
Z
Z    DBUG_ENTER ("isanarchive");
Z    if (f -> fflag & ARCHIVE) {
Z	f -> fdate = getarchdate (f -> parent -> fname, f -> fname);
Z	DBUG_RETURN (SUCCEED);
Z    }
Z    DBUG_RETURN (FAILURE);
Z}
Z
ZNODE *deletelist = (NODE *) NULL;
Z
Z#ifdef LAR
Zextract (f)
ZFILENODE *f;
Z{
Z    DBUG_ENTER ("extract");
Z    DBUG_3 ("extr", "extracting %s for archivehood", f -> fname);
Z    if (f -> fflag & ARCHIVE) {
Z	DBUG_3 ("extr", "copying %s for archivehood", f -> fname);
Z#ifndef NOREALEXTRACT
Z	copyfile (f -> parent -> fname, f -> fname);
Z#endif
Z	/* delete f->fname at end of run */
Z	(void) addtolist (f -> fname, &deletelist);
Z	DBUG_RETURN (SUCCEED);
Z    }
Z    DBUG_RETURN (FAILURE);
Z}
Z#endif
Z
Zvoid cleanuparchives ()
Z{
Z    register NODE *search;
Z
Z    DBUG_ENTER ("cleanuparchives");
Z    for (search=deletelist; search != (NODE *)NULL; search = search->nnext) {
Z	fputs ("Purging ", stdout);
Z	puts (search -> nfile -> fname);
Z#ifndef NOREALDELETE
Z	unlink (search -> nfile -> fname);
Z#endif
Z    }
Z    DBUG_VOID_RETURN;
Z}
Z
Z
Z/*
Z * Get a filenode for the file called 'fn'.
Z * Returns (FILENODE *) NULL if the node doesn't exist.
Z */
Z
ZFILENODE *gfile (fn)
Zchar *fn;
Z{
Z    register FILENODE *f;
Z
Z    DBUG_ENTER ("gfile");
Z    DBUG_3 ("fnode", "look for file node '%s'", fn);
Z    for (f = froot; f != (FILENODE *) NULL; f = f -> fnext) {
Z	if (STRSAME (fn, f -> fname)) {
Z	    DBUG_2 ("fnode", "found it");
Z	    break;
Z	}
Z    }
Z    DBUG_RETURN (f);
Z}
Z
Z
Z/*
Z * Alloc space for a new file node.
Z *
Z * Note that when this routine is called, it has already been
Z * determined that there is no existing node with this name, so
Z * we don't need to check again.
Z *
Z * Also note that the method string pointer is set to a dynamically
Z * allocated null string, rather than a static null string (""), because
Z * it is latter freed when expanding the method string.
Z *
Z */
Z
Zstatic FILENODE *afnode (name)
Zchar *name;
Z{
Z    FILENODE *f;
Z
Z    DBUG_ENTER ("afnode");
Z    DBUG_3 ("fnode", "allocate a new node for file '%s'", name);
Z    if ((f = (FILENODE *) Calloc (1, sizeof (FILENODE))) == (FILENODE *) NULL) {
Z	allerr ();
Z    }
Z    if ((f -> fname = (char *) Calloc (1, strlen (name) + 1)) == NULL) {
Z	allerr ();
Z    }
Z    strcpy (f -> fname, name);
Z    if ((f -> fmake = (char *) Calloc (1, 1)) == NULL) {
Z	allerr ();
Z    }
Z    *(f -> fmake) = '\0';
Z    f -> fdate = (DATE) NULL;
Z    f -> fnode = (NODE *) NULL;
Z    f -> parent = (FILENODE *) NULL;
Z    f -> fflag = 0;
Z    f -> fnext = froot;
Z    froot = f;
Z    DBUG_RETURN (f);
Z}
Z
Z/*
Z * Print dependency tree.
Z */
Z
Zvoid prtree ()
Z{
Z    register FILENODE *f;
Z    register NODE *n;
Z    extern char *printdate ();
Z
Z    DBUG_ENTER ("prtree");
Z    for (f = froot; f != (FILENODE *) NULL; f = f -> fnext) {
Z	fputs (f -> fname, stdout);
Z	fputs ((f -> fflag & ROOTP) ? " (root)" : "", stdout);
Z	fputs ((f -> fflag & REBUILT) ? " (rebuilt)" : "", stdout);
Z	fputs ((f -> fflag & LIBRARY) ? " (library)" : "", stdout);
Z	fputs ((f -> fflag & EXTRACT) ? " (extracted)" : "", stdout);
Z	fputs ((f -> fflag & ARCHIVE) ? " (archive)" : "", stdout);
Z	fputs (printdate (f -> fdate), stdout);
Z	fputc ('\n', stdout);
Z	if (f -> parent != (FILENODE *) NULL) {
Z	    fputs ("Parent is: ", stdout);
Z	    fputs (f -> parent -> fname, stdout);
Z	    fputc ('\n', stdout);
Z	    fputs ("Parental Date:", stdout);
Z	    fputs (printdate (f -> parent -> fdate), stdout);
Z	    fputc ('\n', stdout);
Z	}
Z	if (f -> fmake != NULL) {
Z	    puts (f -> fmake);
Z	}
Z	puts ("Dependents: ");
Z	for (n = f -> fnode; n != (NODE *) NULL; n = n -> nnext) {
Z	    fputc ('\t', stdout);
Z	    puts ((n -> nfile) -> fname);
Z	}
Z	fputc ('\n', stdout);
Z    }
Z    DBUG_VOID_RETURN;
Z}
STUNKYFLUFF
set `sum file.c`
if test 36039 != $1
then
echo file.c: Checksum error. Is: $1, should be: 36039.
fi
#
#
echo Extracting getdir.c:
sed 's/^Z//' >getdir.c <<\STUNKYFLUFF
Z#include "lar.h"
Z
Z#if unix || AMIGA
Z#  include "make.h"		/* To pick up remappings */
Z#endif
Z
Zvoid getdir (f)
Zfildesc f;
Z{
Z    extern int nslots;
Z    extern struct ludir ldir[MAXFILES];
Z    char *getname ();
Z    static void error ();
Z
Z    DBUG_ENTER ("getdir");
Z    lseek (f, 0L, 0);		/* rewind f */
Z    if (_read (f, (char *) & ldir[0], DSIZE) != DSIZE) {
Z	error ("No directory\n");
Z    }
Z    if (!equal (getname ((char *)ldir[0].l_name, (char *)ldir[0].l_ext),"larformt.arc")) {
Z	error ("This is not a LAR format archive!!");
Z    }
Z    if (lwtol (ldir[0].l_datetime) != -1L) {
Z	error ("This is not a LAR format archive!!");
Z    }
Z    nslots = (int) (lwtol (ldir[0].l_len) / DSIZE);
Z    if (_read (f, (char *) & ldir[1], DSIZE * nslots) != DSIZE * nslots) {
Z	error ("Can't read directory - is it a library?");
Z    }
Z    DBUG_VOID_RETURN;
Z}
Z
Z/* convert nm.ex to a Unix style string */
Zchar *getname (nm, ex)
Zchar *nm;
Zchar *ex;
Z{
Z    static char namebuf[14];
Z    register char *cp;
Z    register char *dp;
Z    register char *ocp;
Z
Z    DBUG_ENTER ("getname");
Z    for (cp = namebuf, dp = nm; *dp != ' ' && dp != nm + 8;) {
Z	*cp++ = isupper (*dp) ? tolower (*dp++) : *dp++;
Z    }
Z    *cp++ = '.';
Z    ocp = cp;
Z    for (dp = ex; *dp != ' ' && dp != ex + 3;) {
Z	*cp++ = isupper (*dp) ? tolower (*dp++) : *dp++;
Z    }
Z    if (cp == ocp) {		/* no extension */
Z	--cp;			/* eliminate dot */
Z    }
Z    *cp = '\0';
Z    DBUG_RETURN (namebuf);
Z}
Z
Zvoid cant (name)
Zchar *name;
Z{
Z#ifdef unix
Z    extern int errno;
Z    extern char *sys_errlist[];
Z#endif
Z
Z    fputs (name, stderr);
Z    fputs (": ", stderr);
Z#ifdef unix
Z    fputs (sys_errlist[errno], stderr);
Z#else
Z    fputs ("<unknown error>", stderr);
Z#endif
Z    fputs ("\n", stderr);
Z    fflush (stderr);
Z    exit (1);
Z}
Z
Zvoid error (str)
Zchar *str;
Z{
Z    fputs ("lar: ", stderr);
Z    fputs (str, stderr);
Z    fputs ("\n", stderr);
Z    fflush (stderr);
Z    exit (1);
Z}
Z
Z/*
Z * This itoa doesn't call in the floating point library:
Z *   CI C86 does an sprintf!
Z */
Z
Zvoid itoa (val, buf)
Zint val;
Zchar *buf;
Z{
Z    register int i;
Z    register int j;
Z    auto char tbuf[10];
Z
Z    if (val == 0) {
Z	buf[0] = '0';
Z	buf[1] = '\0';
Z	return;
Z    }
Z    i = 9;
Z    while (val != 0) {
Z	tbuf[i--] = (val % 10) + '0';
Z	val /= 10;
Z    }
Z    i++;
Z    for (j = 0; i <= 9; i++, j++) {
Z	buf[j] = tbuf[i];
Z    }
Z    buf[j] = '\0';
Z}
STUNKYFLUFF
set `sum getdir.c`
if test 58729 != $1
then
echo getdir.c: Checksum error. Is: $1, should be: 58729.
fi
#
#
echo Extracting lar.c:
sed 's/^Z//' >lar.c <<\STUNKYFLUFF
Z/*
Z * Lar - LAR format library file maintainer
Z * by Stephen C. Hemminger
Z *	linus!sch	or	sch@Mitre-Bedford
Z *
Z * Heavily hacked for MS-DOS by Eric C. Brown
Z *      utah-cs!brownc	or	brownc@utah-cs
Z *
Z *  Usage: lar key library [files] ...
Z *
Z *  Key functions are:
Z *	u - Update, add files to library
Z *	t - Table of contents
Z *	e - Extract files from library
Z *      a - extract All files from library
Z *	p - Print files in library
Z *	d - Delete files in library
Z *	r - Reorganize library
Z *  Other keys:
Z *	v - Verbose
Z *
Z *  This program is public domain software, no warranty intended or
Z *  implied.
Z *
Z *  DESCRPTION
Z *	Lar is a MS-DOS program to manipulate program libraries.
Z *	The primary use of lar is to combine several files together
Z *	to reduce disk space used.
Z *	Lar maintains the date and time of files in the library, so
Z *	that Make can extract the date/time for rebuilding a file.
Z *	When files are restored, the file has the original date/time
Z *	rather than the date/time when the file was extracted.
Z *     The original CP/M library program LU is the product
Z *     of Gary P. Novosielski. 
Z *
Z *  PORTABILITY
Z *     The code is modeled after the Software tools archive program,
Z *     and is setup for Version 7 Unix.  It does not make any assumptions
Z *     about byte ordering, explict and's and shift's are used.
Z *     If you have a dumber C compiler, you may have to recode new features
Z *     like structure assignment, typedef's and enumerated types.
Z *
Z *  * Unix is a trademark of Bell Labs.
Z *  ** CP/M is a trademark of Digital Research.
Z */
Z#include "lar.h"
Z
Z/* Globals */
Zchar   *fname[MAXFILES];
Zbool ftouched[MAXFILES];
Z
Zstruct ludir ldir[MAXFILES];
Zint     errcnt, nfiles, nslots;
Zbool	verbose = false;
Z
Zchar   *getname(), *malloc(), *fgets();
Zlong	fcopy(), lseek(), rlwtol();
Zint	update(), reorg(), table(), extract(), print(), delete(), getall();
Z
Ztypedef int (*PFI)();
Z
Zmain (argc, argv)
Zint	argc;
Zchar  **argv;
Z{
Z	register char *flagp;
Z	char   *aname;			/* name of library file */
Z	PFI function = (PFI) NULL;	/* function to do on library */
Z	/* set the function to be performed, but detect conflicts */
Z#define setfunc(val)	if(function != (PFI) NULL) conflict(); else function = val
Z
Z	if (argc < 3)
Z	help ();
Z
Z	aname = argv[2];
Z	filenames (argc, argv);
Z
Z	for(flagp = argv[1]; *flagp; flagp++)
Z	switch (*flagp) {
Z		case 'u': 
Z		    setfunc(update);
Z		    break;
Z		case 't': 
Z		    setfunc(table);
Z		    break;
Z		case 'e': 
Z		    setfunc(extract);
Z		    break;
Z		case 'a': 
Z		    setfunc(getall);
Z		    break;
Z		case 'p': 
Z		    setfunc(print);
Z		    break;
Z		case 'd': 
Z		    setfunc(delete);
Z		    break;
Z		case 'r': 
Z		    setfunc(reorg);
Z		    break;
Z		case 'v':
Z		    verbose = true;
Z		    break;
Z		default: 
Z		    help ();
Z		}
Z
Z	if(function == (PFI) NULL) {
Z	   fputs("No function key letter specified\n", stderr);
Z	   help();
Z	}
Z
Z	(*function)(aname);
Z	exit(0);
Z}
Z
Z/* print error message and exit */
Zhelp () {
Zfputs ("Usage: lar {uteapdr}[v] library [files] ...\n", stderr);
Zfputs ("Functions are:\n\tu - Update, add files to library\n", stderr);
Zfputs ("\tt - Table of contents\n", stderr);
Zfputs ("\te - Extract files from library\n", stderr);
Zfputs ("\ta - extract All files from library\n", stderr);
Zfputs ("\tp - Print files in library\n", stderr);
Zfputs ("\td - Delete files in library\n", stderr);
Zfputs ("\tr - Reorganize library\n", stderr);
Z
Zfputs ("Flags are:\n\tv - Verbose\n", stderr);
Zexit (1);
Z}
Z
Zconflict() {
Zfputs ("Conficting keys\n", stderr);
Zhelp();
Z}
Z
Z/*
Z * This ltoa doesn't call in the floating point library:
Z *   CI C86 does an sprintf!
Z */
Zltoa(val, buf)
Zlong val;
Zregister char *buf;
Z{
Z	register int i;
Z	int j;
Z	char tbuf[20];
Z
Z	if (val == 0) {
Z		buf[0] = '0';
Z		buf[1] = '\0';
Z		return;
Z	}
Z
Z	i = 19;
Z	while (val != 0) {
Z		tbuf[i--] = (val % 10) + '0';
Z		val /= 10;
Z	}
Z
Z	i++;
Z	for (j = 0; i <= 19; i++, j++)
Z		buf[j] = tbuf[i];
Z
Z	buf[j] = '\0';
Z}
Z
Z/* Get file names, check for dups, and initialize */
Zfilenames (ac, av)
Zint ac;
Zchar  **av;
Z{
Z	register int i, j=0;
Z	int k, loop;
Z	struct ffblk ff;
Z	bool iswild();
Z
Z	errcnt = 0;
Z	for (i = 0; i < ac - 3; i++) {
Z	    if (iswild(av[i + 3])) {
Z	        k = findfirst(av[i + 3], &ff, 0);
Z		while (k == 0) {
Z	            fname[j] = malloc(strlen(ff.ff_name)+1);
Z	            if (fname[j] == NULL)
Z                        error("Out of core..");
Z		    strcpy(fname[j], ff.ff_name);
Z		    for (loop = 0; ff.ff_name[loop] != 0; loop++)
Z		        fname[j][loop] = tolower(ff.ff_name[loop]);
Z	            ftouched[j] = false;
Z	            if (j == MAXFILES)
Z	                error ("Too many file names.");
Z	            j++;
Z	            k = findnext(&ff);
Z	        }				/* while */
Z	    }				/* if-then */
Z	    else {		/* not a wildcard */
Z	        fname[j] = av[i+3];
Z	        ftouched[j] = false;
Z	        if (j == MAXFILES)
Z	            error ("Too many file names.");
Z	        j++;
Z	    }				/* else */
Z	}					/* for */
Z	checkdups(j);
Z}
Z
Zbool iswild(str)
Zregister char *str;
Z{
Z	while (*str != '\0') {
Z            if (*str == '*' || *str == '?')
Z                return true;
Z            else str++;
Z	}
Z	return false;
Z}
Z
Zcheckdups(i)
Zregister int i;
Z{
Z	register int j;
Z
Z	fname[i] = NULL;
Z	nfiles = i;
Z	for (i = 0; i < nfiles; i++)
Z            for (j = i + 1; j < nfiles; j++)
Z	        if (equal (fname[i], fname[j])) {
Z	            fputs (fname[i], stderr);
Z	            error (": duplicate file name");
Z                }
Z}	
Z
Ztable (lib)
Zchar   *lib;
Z{
Z	fildesc lfd;
Z	register int i;
Z	register struct ludir *lptr;
Z	long total, offset, size;
Z	int active = 0, unused = 0, deleted = 0, k;
Z	char *uname, buf[20];
Z
Z	if ((lfd = _open (lib, O_RDWR)) == SYS_ERROR)
Z	    cant (lib);
Z
Z	getdir (lfd);
Z	total = lwtol(ldir[0].l_len);
Z	if (verbose) {
Z	    puts("Name             Index          Length");
Z	   fputs("Directory                       ", stdout);
Z	    ltoa(total, buf);
Z	    puts(buf);
Z	}
Z
Z	for (i = 1, lptr = &ldir[1]; i < nslots; i++,lptr++)
Z	    switch(lptr->l_stat) {
Z		case ACTIVE:
Z	            active++;
Z 		    uname = getname(lptr->l_name, lptr->l_ext);
Z	            if (filarg (uname))
Z            		if(verbose) {
Z		            offset = lwtol(lptr->l_off);
Z                	    size = lwtol(lptr->l_len);
Z			    fputs(uname, stdout);
Z			    for (k = 1; k < 18 - strlen(uname); k++)
Z			       fputc(' ', stdout);
Z			    ltoa(offset, buf);
Z			    fputs(buf, stdout);
Z			    for (k = 1; k < 16 - strlen(buf); k++)
Z			       fputc(' ', stdout);
Z			    ltoa(size, buf);
Z			    puts(buf, stdout);
Z    			}
Z 		        else
Z			   puts(uname);
Z		    total += lwtol(lptr->l_len);
Z		break;
Z	case UNUSED:
Z		unused++;
Z		break;
Z	default:
Z		deleted++;
Z	}
Z	if(verbose) {
Z	    puts("--------------------------------------");
Z	    fputs("Total bytes      ", stdout);
Z	    ltoa(total, buf);
Z	    puts(buf);
Z	    fputs("\nLibrary ", stdout);
Z	    fputs(lib, stdout);
Z	    fputs(" has ", stdout);
Z	    itoa(nslots, buf);
Z	    fputs(buf, stdout);
Z	    fputs(" slots, ", stdout);
Z	    itoa(deleted, buf);
Z	    fputs(buf, stdout);
Z	    fputs(" deleted ", stdout);
Z	    itoa(active, buf);
Z	    fputs(buf, stdout);
Z	    fputs(" active, ", stdout);
Z	    itoa(unused, buf);
Z	    fputs(buf, stdout);
Z	    puts(" unused");
Z          }
Z
Z    VOID _close (lfd);
Z    not_found ();
Z}
Z
Zputdir (f)
Zfildesc f;
Z{
Z
Z    lseek(f, 0L, 0);		/* rewind f */
Z    if (_write (f, (char *) ldir, DSIZE * nslots) != nslots * DSIZE)
Z	error ("Can't write directory - library may be botched");
Z}
Z
Zinitdir (f)
Zfildesc f;
Z{
Z    register int    i;
Z    long    numbytes;
Z    char    line[80];
Z    static struct ludir blankentry = {
Z	UNUSED,
Z	{ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' },
Z	{ ' ', ' ', ' ' },
Z    };
Z    static struct ludir nameentry = {
Z	ACTIVE,
Z	{ 'l', 'a', 'r', 'f', 'o', 'r', 'm', 't' },
Z	{ 'a', 'r', 'c' },
Z    };
Z
Z    for (;;) {
Z	fputs ("Number of slots to allocate (1-255): ", stdout);
Z	if (fgets (line, 80, stdin) == NULL)
Z	    error ("Eof when reading input");
Z	nslots = atoi (line);
Z	if (nslots < 1)
Z	    puts ("Must have at least one!");
Z	else if (nslots > MAXFILES)
Z	    puts ("Too many slots");
Z	else
Z	    break;
Z    }
Z
Z    numbytes = nslots * DSIZE;
Z
Z    for (i = 1; i < nslots; i++)
Z	ldir[i] = blankentry;
Z    ldir[0] = nameentry;
Z    ltolw (ldir[0].l_len, numbytes);
Z    ltolw (ldir[0].l_datetime, -1L);	/* make funny date field */
Z
Z    putdir (f);
Z}
Z
Zputname (cpmname, unixname)
Zchar   *cpmname, *unixname;
Z{
Z    register char  *p1, *p2;
Z
Z    for (p1 = unixname, p2 = cpmname; *p1; p1++, p2++) {
Z	while (*p1 == '.') {
Z	    p2 = cpmname + 8;
Z	    p1++;
Z	}
Z	if (p2 - cpmname < 11)
Z	    *p2 = islower(*p1) ? toupper(*p1) : *p1;
Z	else {
Z	    fputs (unixname, stderr);
Z	    fputs (": name truncated\n", stderr);
Z	    break;
Z	}
Z    }
Z    while (p2 - cpmname < 11)
Z	*p2++ = ' ';
Z}
Z
Z/* filarg - check if name matches argument list */
Zfilarg (name)
Zchar   *name;
Z{
Z    register int    i;
Z
Z    if (nfiles <= 0)
Z	return 1;
Z
Z    for (i = 0; i < nfiles; i++)
Z	if (equal (name, fname[i])) {
Z	    ftouched[i] = true;
Z	    return 1;
Z	}
Z
Z    return 0;
Z}
Z
Znot_found () {
Z    register int    i;
Z
Z    for (i = 0; i < nfiles; i++)
Z	if (!ftouched[i]) {
Z	    fputs(fname[i], stderr);
Z	    fputs(": not in library.\n", stderr);
Z	    errcnt++;
Z	}
Z}
Z
Zextract(name)
Zchar *name;
Z{
Z	getfiles(name, false);
Z}
Z
Zprint(name)
Zchar *name;
Z{
Z	getfiles(name, true);
Z}
Z
Zgetall (libname)
Zchar   *libname;
Z{
Z    fildesc lfd, ofd;
Z    register int    i;
Z    register struct ludir *lptr;
Z    union timer timeunion;
Z    extern int errno;
Z    char   *unixname;
Z
Z    if ((lfd = _open (libname, O_RDWR)) == SYS_ERROR)
Z	cant (libname);
Z
Z    getdir (lfd);
Z
Z    for (i = 1, lptr = &ldir[1]; i < nslots; i++, lptr++) {
Z	if(lptr->l_stat != ACTIVE)
Z		continue;
Z	unixname = getname (lptr->l_name, lptr->l_ext);
Z	fputs(unixname, stderr);
Z	ofd = _creat(unixname, 0);
Z	if (ofd == SYS_ERROR) {
Z	    fputs ("  - can't create", stderr);
Z	    errcnt++;
Z	}
Z	else {
Z	    VOID lseek (lfd, (long) lwtol (lptr->l_off), 0);
Z	    acopy (lfd, ofd, lwtol (lptr->l_len));
Z	    timeunion.realtime = lwtol(lptr->l_datetime);
Z            VOID setftime(ofd, &(timeunion.ftimep));
Z	    VOID _close (ofd);
Z	}
Z	putc('\n', stderr);
Z    }
Z    VOID _close (lfd);
Z    not_found ();
Z}
Z
Zgetfiles (name, pflag)
Zchar   *name;
Zbool	pflag;
Z{
Z    fildesc lfd, ofd;
Z    register int    i;
Z    register struct ludir *lptr;
Z    union timer timeunion;
Z    extern int errno;
Z    char   *unixname;
Z
Z    if ((lfd = _open (name, O_RDWR)) == SYS_ERROR)
Z	cant (name);
Z
Z    ofd = pflag ? fileno(stdout) : SYS_ERROR;
Z    getdir (lfd);
Z
Z    for (i = 1, lptr = &ldir[1]; i < nslots; i++, lptr++) {
Z	if(lptr->l_stat != ACTIVE)
Z		continue;
Z	unixname = getname (lptr->l_name, lptr->l_ext);
Z	if (!filarg (unixname))
Z	    continue;
Z	fputs(unixname, stderr);
Z	if (ofd != fileno(stdout))
Z	    ofd = _creat(unixname, 0);
Z	if (ofd == SYS_ERROR) {
Z	    fputs ("  - can't create", stderr);
Z	    errcnt++;
Z	}
Z	else {
Z	    VOID lseek (lfd, (long) lwtol (lptr->l_off), 0);
Z	    acopy (lfd, ofd, lwtol (lptr->l_len));
Z	    timeunion.realtime = lwtol(lptr->l_datetime);
Z	    if (ofd != fileno(stdout)) {
Z                VOID setftime(ofd, &(timeunion.ftimep));
Z		VOID _close (ofd);
Z	    }
Z	}
Z	putc('\n', stderr);
Z    }
Z    VOID _close (lfd);
Z    not_found ();
Z}
Z
Zacopy (fdi, fdo, nbytes)		/* copy nbytes from fdi to fdo */
Zfildesc fdi, fdo;
Zlong nbytes;
Z{
Z    register int btr, retval;
Z    char blockbuf[BLOCK];
Z    
Z    for (btr = (nbytes > BLOCK) ? BLOCK : (int) nbytes; btr > 0; 
Z    	 nbytes -= BLOCK, btr = (nbytes > BLOCK) ? BLOCK : (int) nbytes)  {
Z        if ((retval = _read(fdi, blockbuf, btr)) != btr) {
Z	    if( retval == 0 ) {
Z		error("Premature EOF\n");
Z	     }
Z	     if( retval == SYS_ERROR)
Z	        error ("Can't read");
Z	}
Z	if ((retval = _write(fdo, blockbuf, btr)) != btr) {
Z	     if( retval == SYS_ERROR )
Z	        error ("Write Error");
Z	}
Z    }
Z}
Z
Zupdate (name)
Zchar   *name;
Z{
Z    fildesc lfd;
Z    register int    i;
Z
Z    if ((lfd = _open(name, O_RDWR)) == SYS_ERROR) {
Z	if ((lfd = _creat (name, 0)) == SYS_ERROR) {
Z	    cant (name);
Z	}
Z	else 
Z	    initdir (lfd);
Z    }
Z    else
Z	getdir (lfd);		/* read old directory */
Z
Z    if(verbose)
Z	    fputs ("Updating files:\n", stderr);
Z    for (i = 0; i < nfiles; i++)
Z	addfil (fname[i], lfd);
Z    if (errcnt == 0)
Z	putdir (lfd);
Z    else
Z	fputs("fatal errors - library not changed\n", stderr);
Z    VOID _close (lfd);
Z}
Z
Zaddfil (name, lfd)
Zchar   *name;
Zfildesc lfd;
Z{
Z    fildesc ifd;
Z    register int i;
Z    register struct ludir *lptr;
Z    long byteoffs, numbytes;
Z    union timer timeunion;
Z
Z    if ((ifd = _open(name, O_RDWR)) == SYS_ERROR) {
Z        fputs("LAR: can't find ", stderr);
Z	fputs(name, stderr);
Z	fputs(" to add\n", stderr);
Z	errcnt++;
Z	return;
Z    }
Z    if(verbose) {
Z	fputs(name, stderr);
Z	fputs("\n", stderr);
Z    }
Z    for (i = 1, lptr = ldir+1; i < nslots; i++, lptr++) {
Z	if (equal( getname (lptr->l_name, lptr->l_ext), name) ) /* update */
Z	    break;
Z	if (lptr->l_stat != ACTIVE)
Z		break;
Z    }
Z    if (i >= nslots) {
Z	fputs(name, stderr);
Z	fputs(": can't add library is full\n",stderr);
Z	errcnt++;
Z	return;
Z    }
Z
Z    lptr->l_stat = ACTIVE;
Z    putname (lptr->l_name, name);
Z    byteoffs = lseek(lfd, 0L, 2);	/* append to end; return byte offset */
Z
Z    ltolw (lptr->l_off, byteoffs);
Z    numbytes = fcopy (ifd, lfd);
Z    ltolw (lptr->l_len, numbytes);
Z    getftime(ifd, &(timeunion.ftimep));
Z    ltolw (lptr->l_datetime, timeunion.realtime);
Z    VOID _close (ifd);
Z}
Z
Zlong fcopy (ifd, ofd)		/*  copy file ifd (file) to ofd (library) */
Zfildesc ifd, ofd;
Z{
Z    long total = 0L;
Z    register int n;
Z    char blockbuf[BLOCK];
Z
Z    while ( (n = _read(ifd, blockbuf, BLOCK)) > 0) {
Z	if (_write(ofd, blockbuf, n) != n)
Z		error("write error");
Z	total += (long) n;
Z    }
Z    return total;
Z}
Z
Zdelete (lname)
Zchar   *lname;
Z{
Z    fildesc f;
Z    register int    i;
Z    register struct ludir *lptr;
Z
Z    if ((f = _open(lname, O_RDWR)) == SYS_ERROR)
Z	cant (lname);
Z
Z    if (nfiles <= 0)
Z	error("delete by name only");
Z
Z    getdir (f);
Z    for (i = 0, lptr = ldir; i < nslots; i++, lptr++) {
Z	if (!filarg ( getname (lptr->l_name, lptr->l_ext)))
Z	    continue;
Z	lptr->l_stat = DELETED;
Z    }
Z
Z    not_found();
Z    if (errcnt > 0)
Z	fputs ("errors - library not updated\n", stderr);
Z    else
Z	putdir (f);
Z    VOID _close (f);
Z}
Z
Zreorg (name)
Zchar  *name;
Z{
Z    fildesc olib, nlib;
Z    int oldsize, k;
Z    register struct ludir *optr;
Z    register int i, j;
Z    struct ludir odir[MAXFILES], *nptr;
Z    char tmpname[80], buf[10];
Z    char *mktemp();
Z
Z    strcpy(tmpname, mktemp("libXXXXXX"));
Z
Z    if( (olib = _open(name, O_RDWR)) == SYS_ERROR)
Z	cant(name);
Z
Z    if( (nlib = _creat(tmpname, 0)) == SYS_ERROR)
Z	cant(tmpname);
Z
Z    getdir(olib);
Z    fputs("Old library has ", stdout);
Z    itoa(oldsize = nslots, buf);
Z    fputs(buf, stdout);
Z    puts(" slots.");
Z/* copy ldir into odir */
Z    for(i = 0, optr = ldir, nptr = odir ; i < nslots ; i++, optr++, nptr++)
Z	movmem((char *) optr, (char *) nptr, sizeof(struct ludir));
Z/* reinit ldir */
Z    initdir(nlib);
Z    errcnt = 0;
Z
Z/* copy odir's files into ldir */
Z    for (i = j = 1, optr = odir+1; i < oldsize; i++, optr++) {
Z	if( optr->l_stat == ACTIVE ) {
Z	    if(verbose) {
Z	        fputs("Copying: ", stderr);
Z		for (k = 0; k < 8; k++) 
Z		    fputc(optr->l_name[k], stderr);
Z		fputc('.', stderr);
Z		for (k = 0; k < 3; k++)
Z		    fputc(optr->l_ext[k], stderr);
Z		fputc('\n', stderr);
Z	    }
Z	    copyentry( optr, olib,  &ldir[j], nlib);
Z	    if (++j >= nslots) {
Z		errcnt++;
Z		fputs("Not enough room in new library\n", stderr);
Z		break;
Z	    }
Z        }
Z    }
Z
Z    VOID _close(olib);
Z    putdir(nlib);
Z    VOID _close (nlib);
Z
Z    if(errcnt == 0) {
Z	if (unlink(name) < 0 || rename(tmpname, name) < 0) {
Z	    cant(name);
Z	    exit(1);
Z	}
Z    }
Z    else
Z	fputs("Errors, library not updated\n", stderr);
Z    VOID unlink(tmpname);
Z}
Z
Zcopyentry( old, of, new, nf )
Zstruct ludir *old, *new;
Zfildesc of, nf;
Z{
Z    long byteoffs, numbytes;
Z    register int btr;
Z    char blockbuf[BLOCK];
Z    
Z    new->l_stat = ACTIVE;
Z    movmem(old->l_name, new->l_name, 8);		/* copy name */
Z    movmem(old->l_ext, new->l_ext, 3);			/* copy extension */
Z    numbytes = lwtol(old->l_datetime);			/* copy date & time */
Z    ltolw(new->l_datetime, numbytes);
Z    VOID lseek(of, (long) lwtol(old->l_off), 0);
Z    byteoffs = lseek(nf, 0L, 2);	/* append to end; return new pos. */
Z
Z    ltolw (new->l_off, byteoffs);
Z    numbytes = lwtol(old->l_len);
Z    ltolw (new->l_len, numbytes);
Z
Z    for (btr = (numbytes > BLOCK) ? BLOCK : (int) numbytes; btr > 0; 
Z    	 numbytes -= BLOCK, btr = (numbytes > BLOCK) ? BLOCK : (int) numbytes
Z        )  {
Z        if (_read(of, blockbuf, btr) != btr) {
Z	    error ("Read Error in CopyEntry");
Z	}
Z	if (_write(nf, blockbuf, btr) != btr) {
Z	    error ("Write Error in CopyEntry");
Z	}
Z    }
Z}
STUNKYFLUFF
set `sum lar.c`
if test 33295 != $1
then
echo lar.c: Checksum error. Is: $1, should be: 33295.
fi
#
#
echo Extracting lar.h:
sed 's/^Z//' >lar.h <<\STUNKYFLUFF
Z/* LAR Version 2.0 */
Z
Z#include <stdio.h>
Z#include <ctype.h>
Z#include <fcntl.h>
Z
Z#ifdef MSDOS
Z#  include <findfirs.h>
Z#  include <bdos.h>
Z#endif
Z
Z#define ACTIVE	00
Z#define UNUSED	0xff
Z#define DELETED 0xfe
Z
Z#define MAXFILES (256)
Z#define BLOCK	(8192)
Z#define DSIZE	(sizeof(struct ludir))
Z
Z#define equal(s1,s2) (strcmp(s1,s2)==0)
Z
Z/* if you don't have void type just define as int */
Z#define VOID void
Z
Z#define false (0)
Z#define true ((char)0xff)
Ztypedef unsigned char bool;
Ztypedef unsigned char byte;
Z
Ztypedef struct {
Z    byte hibyte;
Z    byte mbyte2;
Z    byte mbyte1;
Z    byte lobyte;
Z} lword;
Z
Ztypedef struct {
Z    byte hibyte;
Z    byte lobyte;
Z} word;
Z
Z/* convert word to int */
Z#define wtoi(w) ((w.hibyte<<8)+w.lobyte)
Z
Z/* convert int to word */
Z#define itow(dst,src) (dst.hibyte=((src & 0xff00)>>8),dst.lobyte=(src&0x00ff))
Z
Z/* convert lword to long */
Z/* works, but is much slower than stupid assembler routine
Z#define lwtol(lw) (((long)lw.hibyte<<24)+((long)lw.mbyte2<<16)+((long)lw.mbyte1<<8)+(long)lw.lobyte)
Z*/
Z
Z
Z/* cheap hack */
Zlong rlwtol ();
Z#define lwtol(lw) rlwtol(&lw)
Z
Z#define ltolw(dst,src) (dst.hibyte = ((src & 0xff000000L) >> 24);\
Z			dst.mbyte2 = ((src & 0x00ff0000L) >> 16);\
Z			dst.mbyte1 = ((src & 0x0000ff00L) >> 8);\
Z			dst.lobyte = (src & 0x000000ffL);)
Z
Z#ifdef MSDOS
Zunion timer {
Z    struct ftime ftimep;
Z    long realtime;
Z};
Z#endif
Z
Ztypedef int fildesc;
Z
Zstruct ludir {			/* Internal library ldir structure */
Z    byte l_stat;		/*  status of file */
Z    byte l_name[8];		/*  name */
Z    byte l_ext[3];		/*  extension */
Z    lword l_off;		/*  offset in library */
Z    lword l_len;		/*  length of file */
Z    lword l_datetime;		/*  date and time of file. */
Z    byte l_attrib;		/* attributes of file */
Z    byte l_startvol;		/* starting disk number */
Z    byte l_endvol;		/* ending volume number */
Z    word l_cksum;		/* crc checksum */
Z    char l_fill[3];		/*  pad to 32 bytes */
Z};
Z
Z#define SYS_ERROR (-1)
STUNKYFLUFF
set `sum lar.h`
if test 06463 != $1
then
echo lar.h: Checksum error. Is: $1, should be: 06463.
fi
#
#
echo Extracting lwtol.c:
sed 's/^Z//' >lwtol.c <<\STUNKYFLUFF
Z#include "lar.h"
Z/* cheap hack */
Z
Zlong rlwtol (lwa)
Zregister lword *lwa;
Z{
Z#ifdef ibmpc
Z    asm mov dh,[lwa]		/* hibyte */
Z	asm mov dl,[lwa + 1]	/* mbyte1 */
Z	asm mov ah,[lwa + 2]	/* mbyte2 */
Z	asm mov al,[lwa + 3]	/* lobyte */
Z#else
Z    fprintf (stderr, "urk!! -- rlwtol not implemented, bye\n");
Z    exit (1);
Z#endif
Z}
STUNKYFLUFF
set `sum lwtol.c`
if test 05248 != $1
then
echo lwtol.c: Checksum error. Is: $1, should be: 05248.
fi
echo ALL DONE BUNKY!
exit 0

fnf@unisoft.UUCP (12/05/85)

#--------CUT---------CUT---------CUT---------CUT--------#
#########################################################
#                                                       #
# This is a shell archive file.  To extract files:      #
#                                                       #
#    1)	Make a directory for the files.                 #
#    2) Write a file, such as "file.shar", containing   #
#       this archive file into the directory.           #
#    3) Type "sh file.shar".  Do not use csh.           #
#                                                       #
#########################################################
#
#
echo Extracting macro.c:
sed 's/^Z//' >macro.c <<\STUNKYFLUFF
Z#include <stdio.h>
Z#include "make.h"
Z
Z/*
Z * Macro processing
Z */
Z
Z/*
Z * Perform macro substitution from 'orig' to 'dest'.
Z * Return number of macro substitutions made.
Z * A macro reference is in one of two forms:
Z *		<MACCHAR>(macro-name)
Z *  	or	<MACCHAR><single-character>
Z *
Z * "<MACCHAR><MACCHAR>" expands to a single '<MACCHAR>'
Z */
Z
Zmexpand (orig, dest, destsiz, macchar)
Zchar *orig;
Zchar *dest;
Zint destsiz;
Zchar macchar;
Z{
Z    register char *s;
Z    register char *d;
Z    auto char mname[STRSIZ];
Z    register int di;
Z    register int count;
Z    /* MACRO *m; */
Z
Z    DBUG_ENTER ("mexpand");
Z    di = count = 0;
Z    for (s = orig; *s;) {
Z	if (*s == macchar) {
Z	    if (*++s == macchar) {
Z		if (di < destsiz - 1) {
Z		    dest[di++] = *s++;
Z		}
Z		continue;
Z	    }
Z	    if (!*s) {
Z		break;
Z	    }
Z	    d = mname;
Z	    if (*s != '(') {
Z		*d++ = *s++;
Z	    } else {
Z		for (++s; *s && *s != ')';) {
Z		    *d++ = *s++;
Z		}
Z		if (*s != ')') {
Z		    puts ("Missed matching ')'");
Z		} else {
Z		    ++s;
Z		}
Z	    }
Z	    *d = 0;
Z	    if ((d = gmacro (mname)) == NULL) {
Z#ifdef VAXVMS || MSDOS
Z		/* Preserve old behavior.  Someone else can remove it */
Z		/* if desired.  The prefered behavior, at least for */
Z		/* unix types, is to simply ignore undefined macros. */
Z		/* Fred Fish, 28-Nov-85 */
Z		fputs ("Undefined macro: ", stderr);
Z		fputs (mname, stderr);
Z		fputc ('\n', stderr);
Z#endif	
Z	    } else {
Z		while (*d && di < (destsiz - 1)) {
Z		    dest[di++] = *d++;
Z		}
Z		++count;
Z	    }
Z	} else if (di < destsiz - 1) {
Z	    dest[di++] = *s++;
Z	}
Z    }
Z    dest[di] = 0;
Z    DBUG_3 ("mac", "expanded %d macros", count);
Z    DBUG_RETURN (count);
Z}
Z
Z/*
Z * Define a macro.
Z * Give the macro called 'name' the string expansion 'def'.
Z * Old macro-names are superseded, NOT replaced.
Z */
Z
Zvoid defmac (name, def)
Zchar *name;
Zchar *def;
Z{
Z    register MACRO *m;
Z
Z    DBUG_ENTER ("defmac");
Z    DBUG_4 ("mdef", "define macro '%s' to be '%s'", name, def);
Z    if ((m = (MACRO *) Calloc (1, sizeof (MACRO))) == (MACRO *) NULL) {
Z	allerr ();
Z    }
Z    if ((m -> mname = (char *) Calloc (1, strlen (name) + 1)) == NULL) {
Z	allerr ();
Z    }
Z    if ((m -> mvalue = (char *) Calloc (1, strlen (def) + 1)) == NULL) {
Z	allerr ();
Z    }
Z    strcpy (m -> mname, name);
Z    strcpy (m -> mvalue, def);
Z    m -> mnext = mroot;
Z    mroot = m;
Z    DBUG_VOID_RETURN;
Z}
Z
Z
Z/*
Z * undefmac - undefine a macro.
Z * Return 0 if macro was successfully undefined, -1 if not found.
Z */
Z
Zint undefmac (name)
Zchar *name;
Z{
Z    register MACRO *m = mroot;
Z    register MACRO *prev = (MACRO *) NULL;
Z    int result = -1;
Z    extern void free ();
Z
Z    DBUG_ENTER ("undefmac");
Z    DBUG_3 ("mundef", "undefine macro '%s'", name);
Z    while (m != (MACRO *) NULL && !STRSAME (name, m -> mname)) {
Z	prev = m;
Z	m = m -> mnext;
Z    }
Z    if (m != (MACRO *) NULL) {
Z	result = 0;
Z	if (prev == (MACRO *) NULL) {
Z	    mroot = m -> mnext;
Z	} else {
Z	    prev -> mnext = m -> mnext;
Z	}
Z	free (m -> mname);
Z	free (m -> mvalue);
Z	free (m);
Z    }
Z    DBUG_RETURN (result);
Z}
Z
Z
Z/*
Z * Lookup a macro called 'name'.
Z * Return a pointer to its definition,
Z * or NULL if it does not exist.
Z */
Z
Zchar *gmacro (name)
Zchar *name;
Z{
Z    register MACRO *m;
Z    register char *def = NULL;
Z
Z    DBUG_ENTER ("gmacro");
Z    DBUG_3 ("mname", "look up macro '%s'", name);
Z    for (m = mroot; m != (MACRO *) NULL; m = m -> mnext) {
Z	if (STRSAME (name, m -> mname)) {
Z	    def = m -> mvalue;
Z	    DBUG_3 ("mexp", "found expansion '%s'", def);
Z	    break;
Z	}
Z    }
Z    DBUG_RETURN (def);
Z}
STUNKYFLUFF
set `sum macro.c`
if test 49948 != $1
then
echo macro.c: Checksum error. Is: $1, should be: 49948.
fi
#
#
echo Extracting make.c:
sed 's/^Z//' >make.c <<\STUNKYFLUFF
Z#include <stdio.h>
Z#include <ctype.h>
Z#include "make.h"
Z
Z/*
Z *    MAKE - Maintain separate source files
Z *
Z *    SYNOPSIS
Z *        MK [-f file] [-a] [-n] [-d] [-i] [-k] [name] ...
Z *           f: use 'file' instead of default makefile
Z *           a: assume all modules are obsolete (recompile everything)
Z *           n: don't recompile, just list steps to recompile
Z *           d: debugging (print tree, file info)
Z *	     i: ignore return statuses from execution
Z *	     k: if errors occur, propagate error status up tree; continue.
Z *           name: module name to recompile
Z *
Z *    AUTHOR
Z *        Landon M. Dyer, Atari Inc.
Z *
Z *    INCREDIBLY HACKED OVER BY
Z *        Eric C. Brown University of Utah.
Z *	  Fred Fish, UniSoft Systems Inc  (for Commodore AMIGA)
Z *
Z *    HACKS
Z *        Added object library support (dummy names that inherit dates)
Z *	  Added source library support (real parents)
Z *	  Added direct execution capability.
Z *	  Removed script file.
Z *	  Added support for my macro based debugging package (fnf)
Z *	  Ran through "indent" to change formatting (fnf)
Z */
Z
Z#define INIT	"~INIT"		/* initialization macro */
Z#define DEINIT	"~DEINIT"	/* de-init macro */
Z#define BEFORE	"~BEFORE"	/* the per-root 'startup' method */
Z#define AFTER	"~AFTER"	/* the per-root 'wrapup' method */
Z
Zchar *mfiles[] = {		/* default makefiles */
Z    "makefile",
Z    "Makefile",
Z
Z#ifdef VAXVMS
Z    "[-]makefile",
Z    "sys$login:makefile",
Z#endif
Z
Z#ifdef MSDOS
Z    "..\makefile",
Z#endif
Z    ""
Z};
Z
ZMACRO *mroot = (MACRO *) NULL;		/* root of macro-list */
ZFILENODE *froot = (FILENODE *) NULL;	/* root of filenode-list */
ZFILENODE *firstf = (FILENODE *) NULL;	/* the very first filenode */
Z
Zchar *modnames[MAXMODS];	/* module-names mentioned in commandline */
Zint execstat = 0;		/* nonzero if started executing */
Zint modcount = 0;		/* #of module-names */
Zint debug = 0;			/* nonzero: turn on debugging */
Zint obsolete = 0;		/* nonzero: every file should be recompiled */
Zint noscript = 0;		/* nonzero: print methods on stdout */
Zint ignore_errors = 0;		/* nonzero: ignore error return codes */
Zint prop_errors = 0;		/* nonzero: propagate error status up tree */
ZDATE bigbang;			/* a date, the very earliest possible */
ZDATE endoftime;			/* a date, the very last possible */
Z
Z/*
Z *	The following are used to save macro definitions given on the
Z *	command line.  In the unix make, it is very common to override
Z *	a definition in the makefile via a definition on the command line.
Z *	However, this make expands macros in each line as they are read,
Z *	which conflicts with the need to wait until the entire file is read
Z *	before adding command line macros to the table (to override those
Z *	from the file).  Thus the code needs to be modified to delay macro
Z *	expansions until the last minute, before shipping the line off to
Z *	be executed. The alternative is to implement a macro locking or
Z *	precedence scheme.  Either solution requires more work than I can
Z *	do at the moment.  Fred Fish  28-Nov-85
Z */
Zchar *cmdmacros[MAXCMDMACS];	/* Macro defs given on command line */
Zint cmdmcount = 0;		/* Number of macro defs on command line */
Z
Zstatic void fparse ();
Zstatic void yankdependents ();
Zstatic void addmanydepend ();
Zstatic void determ ();
Zstatic void recomp ();
Z
Zmain (argc, argv)
Zint argc;
Zchar *argv[];
Z{
Z    register int arg;
Z    register int i;
Z    register char *mfile = NULL;
Z    extern DATE adate ();
Z    extern void initrootdates ();
Z    extern void prtree ();
Z
Z    DBUG_ENTER ("main");
Z    ENABLE_ABORT;
Z    initrootdates ();
Z    for (arg = 1; arg < argc; ++arg) {
Z	if (*argv[arg] == '-') {
Z	    switch (tolower (argv[arg][1])) {
Z		case '#':
Z		    DBUG_PUSH (&argv[arg][2]);
Z		    break;
Z		case 'f': 
Z		    if (++arg >= argc) {
Z			fputs ("-f needs filename argument.\n", stderr);
Z			DBUG_RETURN (1);
Z		    }
Z		    mfile = argv[arg];
Z		    break;
Z		case 'a': 
Z		    obsolete = 1;
Z		    break;
Z		case 'n': 
Z		    noscript = 1;
Z		    break;
Z		case 'd': 
Z		    debug = 1;
Z		    break;
Z		case 'i': 
Z		    ignore_errors = 1;
Z		    break;
Z		case 'k': 
Z		    prop_errors = 1;
Z		    break;
Z		default: 
Z		    fputs ("Unknown switch: ", stderr);
Z		    fputc (argv[arg][1], stderr);
Z		    fputc ('\n', stderr);
Z		    break;
Z	    }
Z	} else {
Z	    if (strchr (argv[arg], '=') != NULL) {
Z		if (cmdmcount < MAXCMDMACS) {
Z		    cmdmacros[cmdmcount++] = argv[arg];
Z		} else {
Z		    fputs ("Too many command line macros.\n", stderr);
Z		    DBUG_RETURN (1);
Z		}
Z	    } else {
Z		if (modcount < MAXMODS) {
Z		    modnames[modcount++] = argv[arg];
Z		} else {
Z		    fputs ("Too many module names.\n", stderr);
Z		    DBUG_RETURN (1);
Z		}
Z	    }
Z	}
Z    }
Z    if (mfile != NULL) {
Z	if (fmake (mfile) == -1) {
Z	    fputs ("Cannot open makefile '", stderr);
Z	    fputs (mfile, stderr);
Z	    fputs ("'.\n", stderr);
Z	}
Z    } else {
Z	for (i = 0; *mfiles[i]; ++i) {
Z	    if (fmake (mfiles[i]) != -1) {
Z		break;
Z	    }
Z	}
Z	if (!*mfiles[i]) {
Z	    fputs ("Cannot open makefile.\n", stderr);
Z	}
Z    }
Z    if (debug) {
Z	prtree ();
Z    }
Z    DBUG_RETURN (0);
Z}
Z
Z
Z/*
Z * Construct dependency tree from the makefile 'fn'.
Z * Figure out what has to be recompiled, and write a script file to do that.
Z */
Z
Zfmake (fn)
Zchar *fn;
Z{
Z    FILE * fp;
Z
Z    DBUG_ENTER ("fmake");
Z    if ((fp = fopen (fn, "r")) == (FILE *) NULL) {
Z	DBUG_RETURN (-1);
Z    }
Z    fparse (fp);
Z    determ ();
Z    fclose (fp);
Z    DBUG_RETURN (0);
Z}
Z
Z
Z/*
Z * Parse the input file, defining macros and building the dependency tree.
Z */
Z
Zstatic void fparse (fp)
ZFILE *fp;
Z{
Z    auto char ibuf[STRSIZ];
Z    auto char ebuf[STRSIZ];
Z    auto char *strp;
Z    register char *tok1;
Z    register char *tok2;
Z    register char *s;
Z    extern char *fgets ();
Z    register FILENODE *lastf = (FILENODE *)NULL;
Z    extern FILENODE *addfile ();
Z    extern void defmac ();
Z    extern void AddToLibrary ();
Z    extern void escape ();
Z    extern void addmeth ();
Z
Z    DBUG_ENTER ("fparse");
Z    for (;;) {
Z	if (fgets (ibuf, STRSIZ, fp) == NULL) {
Z	    break;
Z	}
Z	DBUG_3 ("inline", "got line '%s'", ibuf);
Z	mexpand (ibuf, ebuf, STRSIZ, MACCHAR);
Z	escape (ebuf, COMCHAR);
Z	s = ebuf + strlen (ebuf) - 1;	/* clobber last newline in string */
Z	if (s >= ebuf && *s == '\n') {
Z	    *s = '\0';
Z	}
Z	DBUG_3 ("inline2", "after macro and excape processing is '%s'", ebuf);
Z	if (ebuf[0] == '\t' || ebuf[0] == ' ') {
Z	    DBUG_2 ("meth", "looks like a method line to me");
Z	    addmeth (lastf, ebuf);
Z	    continue;
Z	}
Z	strp = ebuf;
Z	if ((tok1 = token (&strp)) == NULL) {
Z	    continue;
Z	}
Z	if ((tok2 = token (&strp)) != NULL) {
Z	    if (STRSAME (tok2, DEFMAC)) {
Z		DBUG_2 ("mac", "looks like a macro definition to me");
Z		if (*strp) {
Z		    defmac (tok1, strp);
Z		}
Z#if VAXVMS || MSDOS
Z		/* Preserve old behavior.  Unix and amiga behavior is */
Z		/* to never undefine any macros, in the sense used here. */
Z		/* This also allows macros with null expansions, which */
Z		/* are very useful.  Fred Fish */
Z		if (!*strp) {
Z		    if (undefmac (tok1) < 0) {
Z			fputs ("Can't undefine macro '", stderr);
Z			fputs (tok1, stderr);
Z			fputs ("'.\n", stderr);
Z		    }
Z		}
Z#endif
Z		continue;
Z	    } else if (STRSAME (tok2, DEPEND)) {
Z		DBUG_2 ("mac", "looks like a dependency line to me");
Z		addmeth (lastf, gmacro (AFTER)); /* terminate last method */
Z		lastf = filenode (tok1);	/* init lastf */
Z		if (firstf == (FILENODE *) NULL) {
Z		    firstf = lastf;
Z		}
Z		lastf -> fmake = NULL;
Z		addmeth (lastf, gmacro (BEFORE));
Z		lastf -> fflag |= ROOTP;
Z		addmanydepend (strp, lastf);
Z		continue;
Z#ifndef FUNNYLIBS
Z	    } else if (STRSAME (tok2, ISLIB)) {
Z		addmeth (lastf, gmacro (AFTER));
Z		lastf = filenode (tok1);
Z		if (firstf == (FILENODE *) NULL) {
Z		    firstf = lastf;
Z		}
Z		lastf -> fmake = NULL;
Z		addmeth (lastf, gmacro (BEFORE));
Z		lastf -> fflag |= LIBRARY;
Z		lastf -> fflag |= ROOTP;
Z
Z		AddToLibrary (lastf);
Z		/* no archives here */
Z		/* archives and libraries are mutually exclusive */
Z		while ((tok1 = token (&strp)) != NULL) {
Z		    (void) addfile (lastf, tok1);
Z		}
Z		continue;
Z#endif
Z	    } else {
Z		DBUG_2 ("uh", "what kinda line is this?");
Z		addmanydepend (strp, lastf);
Z	    }
Z	}
Z    }
Z    addmeth (lastf, gmacro (AFTER));
Z    DBUG_VOID_RETURN;
Z}
Z
Z/*
Z * scan tokens from strbuf and search for libraries and archives.
Z * libraries look like foo [ bar baz mumble ]
Z * archives look like foo ( bar baz mumble )
Z * in either case, bar, baz, and mumble have parents of foo.
Z * foo is added to the parentlist, if not already on the list.
Z * bar, baz, and mumble are added to the dependency list of depend.
Z * the command *cannot* be split across newlines without causing errors.
Z * if you don't like that, well, life's a bitch and then you die.
Z */
Z
Zstatic void addmanydepend (strbuf, depend)
Zchar *strbuf;
ZFILENODE *depend;
Z{
Z    register char *tok1;
Z    register char *tok2;
Z    register FILENODE *parent;
Z    register FILENODE *child;
Z    extern FILENODE *addfile ();
Z    extern FILENODE *addparent ();
Z    extern void exit ();
Z
Z    DBUG_ENTER ("addmanydepend");
Z    DBUG_4 ("dep", "add dependencies '%s' to '%s'", strbuf, depend -> fname);
Z    tok1 = token (&strbuf);
Z    if (tok1 == NULL) {
Z	DBUG_VOID_RETURN;
Z    }
Z    tok2 = token (&strbuf);
Z    while (tok2 != NULL) {
Z#ifdef FUNNYLIBS
Z	if (STRSAME (tok2, BGNLIB)) {
Z	    parent = addparent (tok1);	/* add tok1 to parent list */
Z	    for (tok1 = token (&strbuf);	/* skip over token in tok2 */
Z		 tok1 != NULL && strcmp (tok1, ENDLIB);	/* go eol or end */
Z		 tok1 = token (&strbuf)) {	/* get next token */
Z		if (tok1 == NULL) {
Z		    fputs ("MAKE: Error in library defn.\n", stderr);
Z		    exit (2);
Z		}
Z		child = addfile (depend, tok1);
Z		child -> fflag = LIBRARY;
Z		child -> parent = parent;
Z	    }			/* for */
Z	    tok1 = token (&strbuf);
Z	    tok2 = token (&strbuf);
Z	    continue;		/* the while */
Z	}			/* if islib */
Z#endif
Z	if (STRSAME (tok2, BGNARC)) {
Z	    parent = addparent (tok1);		/* add tok1 to parent list */
Z	    for (tok1 = token (&strbuf);	/* skip over token in tok2 */
Z		 tok1 != NULL && strcmp (tok1, ENDARC);	/* go eol or end */
Z		 tok1 = token (&strbuf)) {	/* get next token */
Z		if (tok1 == NULL) {
Z		    fputs ("MAKE: Error in archive defn.\n", stderr);
Z		    exit (2);
Z		}
Z		child = addfile (depend, tok1);
Z		child -> fflag = ARCHIVE;
Z		child -> parent = parent;
Z	    }			/* for */
Z	    tok1 = token (&strbuf);/* get current token */
Z	    tok2 = token (&strbuf);/* get lookahead token */
Z	    continue;		/* the while */
Z	}			/* if isarc */
Z	else {			/* nothing special -- */
Z	    (void) addfile (depend, tok1);/* add dependency */
Z	    tok1 = tok2;	/* shift token */
Z	    tok2 = token (&strbuf);
Z	}
Z    }				/* while */
Z    if (tok2 == NULL && tok1 != NULL) {		/* last token = not special */
Z	(void) addfile (depend, tok1);
Z    }
Z    DBUG_VOID_RETURN;
Z}
Z
Z/*
Z * Determine sequence of recompiles from the creation dates.
Z * If have anything to recompile, then create a script file full of commands.
Z */
Z
Zstatic void determ ()
Z{
Z    register FILENODE *f;
Z    register int i;
Z    register char *m;
Z    extern void cleanuparchives ();
Z
Z    DBUG_ENTER ("determ");
Z    if (firstf == (FILENODE *) NULL) {		/* empty tree */
Z	puts ("No changes.");
Z	DBUG_VOID_RETURN;
Z    }
Z    if (modcount == 0) {
Z	examine (firstf, endoftime);
Z    } else {
Z	for (i = 0; i < modcount; ++i) {
Z	    if ((f = gfile (modnames[i])) == (FILENODE *) NULL) {
Z		fputs ("Don't know how to make ", stderr);
Z		fputs (modnames[i], stderr);
Z		fputs (".\n", stderr);
Z		continue;
Z	    }
Z	    if ((f -> fflag & ROOTP) == 0) {
Z		fputc ('\'', stderr);
Z		fputs (f -> fname, stderr);
Z		fputs ("' is not a root!\n", stderr);
Z		continue;
Z	    }
Z	    examine (f, endoftime);
Z	}
Z    }
Z    if (execstat) {
Z	if ((m = gmacro (DEINIT)) != NULL) {
Z	    execute (m, noscript);
Z	}
Z	cleanuparchives ();
Z    } else {
Z	puts ("No changes.");
Z    }
Z    DBUG_VOID_RETURN;
Z}
Z
Z
Z/*
Z * Examine filenode 'fnd' and see if it has to be recompiled.
Z * 'date' is the last-touched date of the node's father
Z * (or 'endoftime' if its a root file.)
Z * Root files with NO dependencies are assumed not to be up to date.
Z */
Z
Zexamine (fnd, date)
ZFILENODE *fnd;
ZDATE date;
Z{
Z    register int rebuildp = 0;
Z    register int rval;
Z    register int errcode = 0;
Z    register NODE *n;
Z    extern void getdate ();
Z    extern char *printdate ();
Z
Z    DBUG_ENTER ("examine");
Z    DBUG_3 ("ex", "parent node date '%s'", printdate (date));
Z    DBUG_3 ("ex", "examine node '%s'", fnd -> fname);
Z    getdate (fnd);
Z    DBUG_3 ("ex", "modification date '%s'", printdate (fnd -> fdate));
Z    DBUG_3 ("ex", "parent node date '%s'", printdate (date));
Z    if (fnd -> fnode == (NODE *) NULL && fnd -> fflag & ROOTP) {
Z	DBUG_2 ("root", "node, is rootnode with no dependents, rebuild");
Z	rebuildp = 1;
Z    } else {			/* see if dependents need to be recompiled */
Z	for (n = fnd -> fnode; n != (NODE *) NULL; n = n -> nnext) {
Z	    if ((rval = examine (n -> nfile, fnd -> fdate)) != 0) {
Z		if (rval == ERROR) {
Z		    errcode = ERROR;/* if error occurred, propagate up */
Z		    fnd -> fflag |= ERROR;
Z		    fputs ("Couldn't remake ", stderr);
Z		    fputs (fnd -> fname, stderr);
Z		    fputs (" because of errors.\n", stderr);
Z		}
Z		rebuildp = 1;
Z	    }
Z	}
Z    }
Z    DBUG_3 ("ex", "parent node date '%s'", printdate (date));
Z    DBUG_3 ("rebuildp", "rebuild flag is %d", rebuildp);
Z    /* if ancestor recompiled or root, recompile, */
Z    /* but not if error in ancestor */
Z    if (rebuildp && (fnd -> fflag & ERROR) == 0) {
Z	DBUG_3 ("rebuild", "'%s' needs remaking", fnd -> fname);
Z	recomp (fnd);
Z	if (fnd -> fflag & ERROR) {
Z	    DBUG_3 ("err", "got an error remaking %s", fnd -> fname);
Z	    DBUG_RETURN (ERROR);
Z	}
Z    }
Z    DBUG_3 ("ex", "current node date now '%s'", printdate (fnd -> fdate));
Z    DBUG_3 ("ex", "parent node date '%s'", printdate (date));
Z    if (obsolete || laterdt (fnd -> fdate, date) >= 0) {
Z	DBUG_2 ("date", "looks like parent needs remaking now");
Z	rebuildp = 1;
Z    }
Z    if (errcode) {
Z	DBUG_RETURN (errcode);
Z    } else {
Z	DBUG_RETURN (rebuildp);
Z    }
Z}
Z
Z/*
Z * Make sure a filenode gets recompiled.
Z */
Z
Zstatic void recomp (f)
ZFILENODE *f;
Z{
Z    register char *m;
Z
Z    DBUG_ENTER ("recomp");
Z    if (!execstat) {
Z	execstat = 1;
Z	if ((m = gmacro (INIT)) != NULL) {
Z	    execute (m, noscript);
Z	}
Z    }
Z    if (f -> fflag & REBUILT) {
Z	DBUG_VOID_RETURN;
Z    }
Z    if (!noscript) {		/* don't extract if printing steps */
Z	yankdependents (f);
Z    }
Z    if (f -> fmake != NULL) {
Z	if (execute (f -> fmake, noscript) != 0) {
Z	    if (!ignore_errors && !prop_errors) {
Z		exit (2);
Z	    } else if (prop_errors) {
Z		f -> fflag |= ERROR;
Z	    }
Z	}
Z    }
Z    f -> fflag |= REBUILT;
Z    DBUG_VOID_RETURN;
Z}
Z
Zstatic void yankdependents (fnd)
ZFILENODE *fnd;
Z{
Z    register NODE *n;
Z    extern int extract ();
Z
Z    DBUG_ENTER ("yankdependents");
Z    for (n = fnd -> fnode; n != (NODE *) NULL; n = n -> nnext) {
Z#ifdef YANKDESCENDANTS
Z	yankdependents (n -> nfile);
Z#endif
Z	DBUG_3 ("dep", "yanking %s", n -> nfile -> fname);
Z	DBUG_3 ("dep", "flags %d", n -> nfile -> fflag);
Z	if ((n -> nfile -> fflag & ARCHIVE) && ((n -> nfile -> fflag & EXTRACT) == 0)) {
Z	    /* if archived and not extracted */
Z	    fputs ("Extracting ", stdout);
Z	    puts (n -> nfile -> fname);
Z	    if (!noscript) {
Z#ifdef LAR
Z		if (extract (n -> nfile) == FAILURE) {
Z		    fputs ("Extract failed -- I think I'll die now.\n", stderr);
Z		    exit (1);
Z		}
Z#else
Z		fputs ("No support for archives, bye!\n", stderr);
Z		exit (1);
Z#endif
Z	    }
Z	    n -> nfile -> fflag |= EXTRACT;
Z	}
Z    }
Z    DBUG_VOID_RETURN;
Z}
Z
Z/*
Z * Complain about being out of memory, and then die.
Z */
Z
Zallerr ()
Z{
Z    fputs ("Can't alloc -- no space left (I give up!)\n", stderr);
Z    exit (1);
Z}
STUNKYFLUFF
set `sum make.c`
if test 20207 != $1
then
echo make.c: Checksum error. Is: $1, should be: 20207.
fi
#
#
echo Extracting make.h:
sed 's/^Z//' >make.h <<\STUNKYFLUFF
Z/* #define	VAXVMS	1 */		/* uncomment for VAX/VMS */
Z/* #define	MSDOS	1 */		/* uncomment for MSDOS */
Z
Z/* NOTE: other two supported systems, "unix" and "AMIGA" have these symbols */
Z/* built into the preprocessor.  Redefining them may cause problems, or at */
Z/* least irritating warning messages. */
Z
Z#if VAXVMS
Z#  define ESCCHAR `\\`		/* ok to use backslash on VMS */
Z#endif
Z
Z#ifdef MSDOS
Z#  define ESCCHAR '`'		/* since pathname char is backslash (yech) */
Z#endif
Z
Z#if unix || AMIGA
Z#  define ESCCHAR '\\'
Z#endif
Z
Z#define EOS '\000'		/* End of string character */
Z
Z#define	MACCHAR '$'		/* macro-definition char */
Z#define	COMCHAR	'#'		/* comment char */
Z#define	DEFMAC	"="		/* macro-definition token */
Z#define	DEPEND	":"		/* dependency-definition token */
Z
Z#ifdef FUNNYLIBS
Z#  define BGNLIB  "["		/* start library token */
Z#  define ENDLIB  "]"		/* end library token */
Z#else
Z#  define ISLIB   "|"		/* Library definition token */
Z#endif
Z
Z#define BGNARC  "("		/* start archive token */
Z#define ENDARC  ")"		/* end archive token */
Z
Z#define	DEBUG	(0)
Z#define	STRSIZ	(1024)		/* Size of input buffer */
Z#define	MAXMODS	(50)		/* Max number of targets on command line */
Z#define MAXCMDMACS (16)		/* Max number of macro defs on command line */
Z
Z#if DEBUG
Z#  define NOREALEXECUTE		/* if set, don't really execute commands */
Z#  define NOREALEXTRACT		/* if set, don't really extract files */
Z#  define NOREALDELETE		/* if set, don't really delete files */
Z#endif
Z
Z#define SUCCEED (0)
Z#define FAILURE (-1)
Z
Z/* file attributes */
Z
Z#define	REBUILT	0x01		/* file has been reconstructed */
Z#define	ROOTP	0x02		/* file was named on left side of DEPEND */
Z#define LIBRARY 0x04		/* file is library; inherit parent's time */
Z#define ARCHIVE 0x08		/* file is archive; search through parent */
Z				/* archive directory for time */
Z#define EXTRACT 0x10		/* extract from archive when rebuilding */
Z#define ERROR   0x20		/* error occurred while rebuilding */
Z
Z#ifdef VAXVMS
Zstruct date_str {
Z    unsigned ds_low;
Z    unsigned ds_high;
Z};
Ztypedef struct date_str *DATE;
Z#endif
Z
Z#ifdef MSDOS
Z#  ifndef FA_ARCH
Z#    include <bdos.h>
Z#  endif
Z   typedef struct ftime *DATE;
Z#endif
Z
Z#ifdef unix
Z  typedef long *DATE;
Z#endif
Z
Z#ifdef AMIGA
Z#  include <libraries/dos.h>
Z   typedef struct DateStamp *DATE;
Z#endif
Z
Z#ifdef DBUG
Z#  include <local/dbug.h>
Z#else
Z#  define DBUG_ENTER(a1)
Z#  define DBUG_RETURN(a1) return(a1)
Z#  define DBUG_VOID_RETURN return
Z#  define DBUG_EXECUTE(keyword,a1)
Z#  define DBUG_2(keyword,format)
Z#  define DBUG_3(keyword,format,a1)
Z#  define DBUG_4(keyword,format,a1,a2)
Z#  define DBUG_5(keyword,format,a1,a2,a3)
Z#  define DBUG_PUSH(a1)
Z#  define DBUG_POP()
Z#  define DBUG_PROCESS(a1)
Z#  define DBUG_FILE (stderr)
Z#  define DBUG_SETJMP setjmp
Z#  define DBUG_LONGJMP longjmp
Z#endif
Z
Zstruct node {
Z    struct filenode *nfile;	/* this node's file */
Z    struct node *nnext;		/* the next node */
Z};
Ztypedef struct node NODE;
Z
Z
Zstruct filenode {
Z    char *fname;		/* the filename */
Z    char *fmake;		/* remake string for file */
Z    DATE fdate;			/* last modification date */
Z    NODE *fnode;		/* files this file depends on */
Z    char fflag;			/* magic flag bits */
Z    struct filenode *parent;	/* pointer to parent for archives,libraries */
Z    struct filenode *fnext;	/* the next file */
Z};
Ztypedef struct filenode FILENODE;
Z
Z
Zstruct macro {
Z    char *mname;		/* the macro's name */
Z    char *mvalue;		/* the macro's definition */
Z    struct macro *mnext;	/* the next macro */
Z};
Ztypedef struct macro MACRO;
Z
Z
Zextern long *Calloc ();		/* Private gateway to system calloc() */
Zextern MACRO *mroot;
Zextern FILENODE *froot;
Zextern DATE bigbang;		/* Far, far in the past */
Zextern DATE endoftime;		/* Far, far in the future */
Zchar *gmacro ();
ZFILENODE *gfile ();
ZFILENODE *filenode ();
Zchar *token ();
Z
Z#if unix || AMIGA
Z#  define _open open
Z#  define _close close
Z#  define _read read
Z#  define _write write
Z#endif
Z
Z/*
Z *	On the Amiga, we must do an explicit check for an abort at various
Z *	places of interest.  To avoid #ifdefs all through the code, define
Z *	some macros that just expand to null on other systems.
Z *
Z */
Z 
Z#ifdef AMIGA
Z   void Check_Abort ();
Z   extern int Enable_Abort;			/* Enable abort on CNTL-C */
Z#  define ENABLE_ABORT (Enable_Abort = 1)
Z#  define DISABLE_ABORT (Enable_Abort = 0)
Z#  define CHECK_ABORT Check_Abort();
Z#else
Z#  define CHECK_ABORT				/* Null expansions */
Z#  define ENABLE_ABORT
Z#  define DISABLE_ABORT
Z#endif	/* AMIGA */
Z
Z/*
Z *	Some useful macros to make things slightly less error prone.
Z */
Z
Z#define STRSAME(a,b) (strcmp(a,b)==0)		/* Strings are the same */
Z
STUNKYFLUFF
set `sum make.h`
if test 05045 != $1
then
echo make.h: Checksum error. Is: $1, should be: 05045.
fi
#
#
echo Extracting make.man:
sed 's/^Z//' >make.man <<\STUNKYFLUFF
ZMAKE(I)				3/10/84					MAKE(I)
Z
Z
Z
ZNAME
Z	MAKE - maintain multiple source files (VAX/VMS and MSDOS 2.0)
Z
Z
ZSYNOPSIS
Z	MAKE [-N] [-A] [-D] [-I] [-K] [-F makefile] [name ...]
Z
Z
ZDESCRIPTION
Z	MAKE is a utility inspired by the Unix(tm) command of the same
Z	name.  MAKE helps maintain programs that are constructed from
Z	many files.  MAKE processes a "makefile", a file which describes
Z	how to build a program from its source files, and produces a
Z	script file containing the commands necessary to recompile the
Z	program.
Z
Z	Be careful: this MAKE is NOT compatible with Unix(tm) MAKE!
Z
Z	The 'N' option causes MAKE to print out the steps it would follow
Z	in order to rebuild the program.  The 'A' option tells MAKE to
Z	assume that all files are obsolete, and that everything should be
Z	recompiled.  The 'I' option tells MAKE to ignore any error statuses
Z	returned when MAKE executes a program.  The 'K' option tells MAKE
Z	to continue compiling anything that does not depend on an entry
Z	that had an error during the compilation.  The 'F' option, followed
Z	by a filename, can be used to specify a makefile other than the
Z	default one.
Z
Z	If no names are specified in the commandline, the first dependency
Z	in the makefile is examined.  Otherwise, the specified root names
Z	are brought up to date.
Z
Z	The default makefiles are:
Z
Z		for VAX/VMS:	MAKEFILE
Z				[-]MAKEFILE
Z				SYS$LOGIN:MAKEFILE
Z
Z		for MSDOS:	MAKEFILE
Z				..\MAKEFILE
Z
Z	If the first makefile cannot be found, MAKE attempts to use the
Z	next one.  If no makefile is ever found, MAKE prints a diagnostic
Z	and aborts.
Z
ZTHE MAKEFILE
Z	Comments begin with '#' and extend to the end of the line.  A
Z	'#' (or almost any other character) may be escaped with the escape
Z	character (backslash (\) on VMS, backquote (`) on MSDOS).  An escape
Z	character may be typed by doubling it (\\ or ``).  The standard
Z	Unix escape codes are recognized (\n, \r, \t, \b, \f, `n, `r, `t,
Z	`b and `f).
Z
Z	A makefile is a list of dependencies and library definitions.  A 
Z	dependency consists of a root name, a colon, and zero or more names
Z	of dependent files.  (The colon MUST be preceeded by whitespace.)
Z	For instance, in:
Z
Z		make.exe : make.obj parsedir.obj file.obj macro.obj mk.h
Z
Z	the file 'make.exe' depends on five other files.  A library definition 
Z	consists of a root name, a vertical bar (|), and zero or more names of
Z	library entry points.  (The vertical bar MUST be preceded by 
Z	whitespace.)  For instance, in:
Z
Z		ibm.lib | ibmtext ibmsound ibmkeys ibmser ibm_com
Z
Z	the file 'ibm.lib' has five entry points.  Library definitions are
Z	useful for updating libraries without maintaining copies of the object
Z	files for the source files.  The library entry points have the same
Z	date and time as the library itself, and so if the entry depend on the
Z	proper source files, all modified source files will be recompiled
Z	whenever necessary.
Z
Z	A dependent file may be a member of an ARCHIVE.  An ARCHIVE is a
Z        collection of files with date and time stamps.  An example of an
Z        archive definition is:
Z	
Z	make.obj : make.lar ( make.c make.h )
Z	
Z	In this definition, make.c and make.h are members of the archive
Z        make.lar.  If make.obj must be rebuilt and either make.c or make.h
Z        is not found in the current directory, they will be copied out of
Z        the archive, compiled, and deleted at the end of the make session.
Z	
Z	Archive definitions are meaningless in a library definition, and so
Z        should not be used.	
Z
Z	A root name with an empty dependency, as in:
Z
Z		print :
Z
Z	is assumed NEVER up to date, and will always be recompiled.
Z
Z	The dependency list or library definition may be continued on
Z	successive lines:
Z
Z		bigfile.exe : one.obj two.obj three.obj four.obj
Z		five.obj six.obj gronk.obj freeple.obj scuzzy.lnk
Z		frog.txt greeble.out
Z
Z			OR
Z
Z		msdos.lib | alloc char_io disk_io file_io exec filesize
Z		freedisk freemem insert mouse port_io randg syscall 
Z		sysclock sysint textsf timer ttime ucsd ucsdhelp unix
Z
Z	Any number of 'method' lines may follow a dependency.  Method lines
Z	begin with an ascii tab.  When a file is to be rebuilt, MAKE
Z	executes these method lines (minus the tab).  
Z	For example, in:
Z
Z		make.exe : make.obj parsedir.obj file.obj macro.obj mk.h
Z			$link make, parsedir, file, macro
Z			$write sys$output "Just another version of MAKE ..."
Z			$purge
Z
Z	the three lines following the dependency make up the method for
Z	recompiling (or in this case, re-linking) the file 'make.exe'.
Z
Z	Library definitions may have method lines.  These methods will 
Z	*always* be executed, since the entry points have the same date
Z	as the library.
Z
Z	If the macro "~INIT" is defined, its text will be executed first. 
Z	If the macro "~DEINIT" is defined, its text will be executed last.
Z	By defining these two macros, it is possible to configure the shell 
Z	enviroment:
Z
Z		~INIT = $set term/nowrap\n$on error then goto err_handler
Z		~DEINIT = $set term/wrap\n$exit\$err_handler:\n
Z		~DEINIT = #(~DEINIT)$type err.log\n$exit
Z
Z	will be executed as:
Z
Z		$set term/nowrap
Z		$on error then goto err_handler
Z		.
Z		.
Z		$set term/wrap
Z		$exit
Z		$err_handler:
Z		$type err.log
Z		$exit
Z
Z	When a root's method is defined, the value of the macro "~BEFORE"
Z	is prefixed to the method, and the value of the macro "~AFTER" is
Z	appended to it.
Z
Z	Frequently one wants to maintain more than one program with a single
Z	makefile.  In this case, a "master dependency" can appear first in
Z	the file:
Z
Z		allOfMyToolsAndHorribleHacks : cat peek poke.exe grunge
Z		cat : cat.exe
Z		cat.exe : ....
Z			(stuff for CAT.EXE)
Z		peek : peek.exe
Z		peek.exe : (stuff for PEEK.EXE)
Z		poke.exe : (stuff for POKE.EXE)
Z		grunge : grunge.com
Z		grunge.com : (stuff for grung)
Z
Z	In other words, make will bring everything up to date that is somehow
Z	connected to the first dependency (its assumed that the incredibly
Z	lengthy filename specified in this example won't actually exist).
Z
ZMACROS
Z	A macro is defined by a line of the form (the '=' MUST be surrounded
Z	by whitespace):
Z
Z		<macro-name> = <macro-body>
Z
Z	A macro may be deleted by assigning an empty value to it.  Macros
Z	may be redefined, but old definitions stay around.  If a macro is
Z	redefined, and the redefinition is later deleted, the first definition
Z	will take effect:
Z
Z		MAC = first			! MAC = "first"
Z		MAC = second			! MAC = "second"
Z		MAC = #(MAC) third		! MAC = "second third"
Z		MAC =				! MAC = "second"
Z		MAC =				! MAC = "first"
Z		MAC =				! MAC has no definition
Z
Z	A macro may be referenced in two ways:
Z
Z			#<char>	  or	#(macro-name)
Z
Z	The first way only works if the macro's name is a single character.
Z	If the macro's name is longer than one character, it must be
Z	enclosed in parenthesis.  ['#' may be escaped by doubling it ("##".)]
Z	For example, in:
Z
Z		G = mk.h mk1.h
Z		OBJS = make.obj file.obj parsedir.obj macro.obj
Z		BOTH = #(OBJS) #G
Z	
Z		make.exe : #(OBJS) #G
Z		make.exe : #(BOTH)
Z		make.exe : mk.h mk1.h make.obj file.obj parsedir.obj macro.obj
Z			$write sys$output "This is a number sign --> ##"
Z
Z	after macro expansion, the three dependencies will appear identical
Z	and the two '#'s in the last line will turn into one '#'.
Z
ZUNIX(tm) MAKE AND THIS ONE
Z	They are NOT the same.  Do not expect Unix makefiles to work with
Z	this MAKE, even if you change the pathnames.  There are some major
Z	differences between this version and the standard Unix(tm) MAKE:
Z
Z	1. The Unix(tm) comment character is '#', VAX/VMS's is '!'.
Z
Z	2. The Unix(tm) macro-expansion character is '$'.  While this would
Z	   have been easy to leave the same, the '$' character is used so
Z	   often in VAX/VMS command-lines that I thought it best to change
Z	   it to '#'.
Z
Z	3. Multiple root names are not allowed.  Unix(tm) MAKE accepts lines
Z	   of the form:
Z
Z		name1 name2 : depend1 depend2
Z
Z	   but this one doesn't.
Z
Z	4. There is no equivalent of double-colon ("::".)
Z
Z	5. There is no equivalent of .SUFFIXES, or the corresponding special
Z	   macros.
Z
ZSAMPLE MAKEFILE
Z	!
Z	! VAX/VMS MAKE
Z	! Landon Dyer
Z	!
Z	H = make.h
Z	FILES = #H, make.c, macro.c, token.c, parsedir.c, file.c
Z	DOCUMENTATION = distr.mem make.man makefile. make.com
Z	
Z	make.exe : make.obj macro.obj token.obj parsedir.obj file.obj
Z		$link make.obj, macro, token, parsedir, file
Z		$purge
Z	
Z	make.obj : make.c #H
Z		$cc make.c
Z	
Z	macro.obj : macro.c #H
Z		$cc macro
Z	
Z	token.obj : token.c #H
Z		$cc token
Z	
Z	parsedir.obj : parsedir.c #H
Z		$cc parsedir
Z	
Z	file.obj : file.c
Z		$cc file
Z	
Z	!
Z	! Print files associated with MAKE
Z	!
Z	print :
Z		$print make.man, #(FILES), make.com, makefile.
Z	
Z	!
Z	! Type out source to MAKE
Z	!
Z	type :
Z		$type #(FILES), make.com, makefile.
Z	
Z	!
Z	! Make backup of source files.
Z	!
Z	BACKUP = [.bak]
Z	backup :
Z		$copy #(FILES) #(BACKUP)
Z		$copy make.man, make.com, makefile. #(BACKUP)
Z	
Z	!
Z	! Collect MAKE into a distribution file.
Z	!
Z	collect :
Z		$collect collect distr.mem make.man makefile make.com make.h -
Z			make.c macro.c token.c parsedir.c file.c
Z
Z
ZAUTHOR
Z	Landon Dyer			G.DYER@SU-SCORE.ARPA
Z	175 Calvert Dr. #F-211		BASHFL::DYER (Atari Coinop)
Z	Cupertino, CA 95014
Z
ZMODIFIED BY
Z	Eric C. Brown			brownc@utah-cs.arpa
Z	1302 Austin Hall		...!harpo!utah-cs!brownc
Z	University of Utah, SLC, UT 84112
STUNKYFLUFF
set `sum make.man`
if test 17762 != $1
then
echo make.man: Checksum error. Is: $1, should be: 17762.
fi
#
#
echo Extracting osdate.c:
sed 's/^Z//' >osdate.c <<\STUNKYFLUFF
Z/*
Z; OSDATE - return file's creation-date (called from Lattice), or -1
Z;	   if can't find the file.
Z; Synopsis:
Z;		int osdate(filename, time1, time2)
Z;			char *filename;
Z;			int *time1, *time2;
Z;
Z*/
Z
Z#include "lar.h"
Z#define FILERR (-1)
Z#include "make.h"
Z
Zstatic void getftime ();
Zextern char *printdate ();
Z
ZDATE osdate (filename, success)
Zchar *filename;
Zint *success;
Z{
Z    extern DATE adate ();
Z    auto DATE newdate;
Z#ifndef AMIGA
Z    register int handle;
Z#endif
Z
Z    DBUG_ENTER ("osdate");
Z#ifdef AMIGA
Z    newdate = adate ();
Z    getftime (filename, newdate, success);
Z#else
Z    if ((handle = _open (filename, O_RDONLY)) == FILERR) {
Z	*success = FAILURE;
Z	newdate = (DATE) NULL;
Z    } else {
Z	newdate = adate ();
Z	getftime (handle, newdate);
Z	_close (handle);
Z	*success = SUCCEED;
Z    }
Z#endif
Z    DBUG_RETURN (newdate);
Z}
Z
Zstruct ludir ldir[MAXFILES];
Zint nslots;
Zextern char *getname ();
Z
ZDATE getarchdate (archname, filename)
Zchar *archname;
Zchar *filename;
Z{
Z    register fildesc lfd;
Z    register int i;
Z    register struct ludir *lptr;
Z    union timing {
Z	DATE ftimeptr;
Z	long *longptr;
Z    } unionptr;
Z    extern DATE adate ();
Z    auto DATE newdate;
Z    register char *realname;
Z    extern void cant ();
Z
Z    DBUG_ENTER ("getarchdate");
Z    DBUG_4 ("ard", "looking for %s inside %s", filename, archname);
Z    if ((lfd = _open (archname, O_RDONLY)) == FILERR) {
Z	cant (archname);
Z    }
Z    getdir (lfd);
Z    for (i = 1, lptr = ldir + 1; i < nslots; i++, lptr++) {
Z	if (lptr -> l_stat != ACTIVE) {
Z	    continue;
Z	}
Z	realname = getname ((char *) lptr -> l_name, (char *) lptr -> l_ext);
Z	if (strcmp (realname, filename) != 0) {
Z	    continue;
Z	}
Z	DBUG_3 ("ard", "found name %s", realname);
Z	DBUG_3 ("ard", "time %lx", lwtol (lptr -> l_datetime));
Z	newdate = adate ();
Z	unionptr.ftimeptr = newdate;
Z	*(unionptr.longptr) = lwtol (lptr -> l_datetime);
Z	break;
Z    }
Z    (void) _close (lfd);
Z    DBUG_3 ("ard", "date is %s", printdate (newdate));
Z    DBUG_RETURN (newdate);
Z}
Z
Z#ifdef LAR
Zcopyfile (archname, filename)
Zchar *archname;
Zchar *filename;
Z{
Z    register int i;
Z    register struct ludir *lptr;
Z    register fildesc lfd;
Z    register fildesc ofd;
Z    union timer timeunion;
Z    extern int errno;
Z    register char *realname;
Z    auto char outname[64];
Z    register char *tmpptr;
Z    extern char *strrchr ();
Z    extern void cant ();
Z
Z    DBUG_ENTER ("copyfile");
Z    DBUG_4 ("cpf", "looking for %s inside %s", filename, archname);
Z    if ((lfd = _open (archname, O_RDWR)) == FILERR) {
Z	cant (archname);
Z    }
Z    getdir (lfd);
Z    for (i = 1, lptr = &ldir[1]; i < nslots; i++, lptr++) {
Z	if (lptr -> l_stat != ACTIVE) {
Z	    continue;
Z	}
Z	realname = getname (lptr -> l_name, lptr -> l_ext);
Z	if (strcmp (realname, filename) != 0) {
Z	    continue;
Z	}
Z	/* generate real filename */
Z	tmpptr = strrchr (archname, '/');	/* should be path chr */
Z	if (tmpptr != NULL) {
Z	    i = (int) (tmpptr - archname);
Z	    i++;
Z	    DBUG_3 ("tmpptr", "tmpptr was not NULL; i is %d", i);
Z	    strncpy (outname, archname, i);
Z	} else {
Z	    DBUG_2 ("tmpptr", "tmpptr was NULL");
Z	    i = 0;
Z	    *outname = '\0';
Z	}
Z	strcat (outname, realname);
Z	DBUG_3 ("outn", "got it; about to extract %s", outname);
Z	ofd = _creat (outname, 0);
Z	if (ofd == FILERR) {
Z	    fputs (outname, stderr);
Z	    fputs ("  - can't create\n", stderr);
Z	    DBUG_VOID_RETURN;
Z	} else {
Z	    (void) lseek (lfd, (long) lwtol (lptr -> l_off), 0);
Z	    acopy (lfd, ofd, lwtol (lptr -> l_len));
Z	    timeunion.realtime = lwtol (lptr -> l_datetime);
Z	    if (ofd != fileno (stdout)) {
Z		(void) setftime (ofd, &(timeunion.ftimep));
Z		(void) _close (ofd);
Z	    }
Z	    break;		/* exit after copy */
Z	}
Z    }
Z    (void) _close (lfd);
Z    DBUG_VOID_RETURN;
Z}
Z
Zstatic void acopy (fdi, fdo, nbytes)	/* copy nbytes from fdi to fdo */
Zfildesc fdi;
Zfildesc fdo;
Zlong nbytes;
Z{
Z    register int btr;
Z    register int retval;
Z    char blockbuf[BLOCK];
Z
Z    for (btr = (nbytes > BLOCK) ? BLOCK : (int) nbytes; btr > 0;
Z	    nbytes -= BLOCK, btr = (nbytes > BLOCK) ? BLOCK : (int) nbytes) {
Z	if ((retval = _read (fdi, blockbuf, btr)) != btr) {
Z	    if (retval == 0) {
Z		error ("Premature EOF\n");
Z	    }
Z	    if (retval == FILERR) {
Z		error ("Can't read");
Z	    }
Z	}
Z	if ((retval = _write (fdo, blockbuf, btr)) != btr) {
Z	    if (retval == FILERR) {
Z		error ("Write Error");
Z	    }
Z	}
Z    }
Z}
Z#endif				/* LAR */
Z
Z#ifdef unix
Z#include <sys/types.h>
Z#include <sys/stat.h>
Z
Zstatic void getftime (handle, date)
Zint handle;
ZDATE date;
Z{
Z    struct stat statb;
Z
Z    DBUG_ENTER ("getftime");
Z    fstat (handle, &statb);
Z    *date = statb.st_mtime;
Z    DBUG_3 ("date", "got date %lu", *date);
Z    DBUG_VOID_RETURN;
Z}
Z#endif
Z
Z#ifdef AMIGA
Z#include <libraries/dosextens.h>
Z#include <libraries/dos.h>
Z
Zstatic void getftime (filename, date, success)
Zchar *filename;
ZDATE date;
Zint *success;
Z{
Z    struct FileInfoBlock *fib;
Z    struct FileLock *lockp;    
Z    int status = FAILURE;
Z    extern struct FileLock *Lock ();
Z
Z    DBUG_ENTER ("getftime");
Z    lockp = Lock (filename, ACCESS_READ);
Z    if (lockp != NULL) {
Z	fib = (struct FileInfoBlock *) Calloc (1, sizeof (struct FileInfoBlock));
Z	DBUG_3 ("fib", "fib = %x", fib);
Z	if (fib == NULL) {
Z	    allerr ();
Z	} else {
Z	    if (Examine (lockp, fib)) {
Z		DBUG_3 ("date", "file '%s'", filename);
Z		DBUG_3 ("date", "date is %s", printdate (&(fib -> fib_Date)));
Z		date -> ds_Days = fib -> fib_Date.ds_Days;
Z		date -> ds_Minute = fib -> fib_Date.ds_Minute;
Z		date -> ds_Tick = fib -> fib_Date.ds_Tick;
Z		status = SUCCEED;
Z	    } else {
Z		fprintf (stderr, "Examine() failed!\n");
Z	    }
Z	    free (fib);
Z	    UnLock (lockp);
Z	}
Z    }
Z    *success = status;
Z    DBUG_VOID_RETURN;
Z}
Z#endif
STUNKYFLUFF
set `sum osdate.c`
if test 50612 != $1
then
echo osdate.c: Checksum error. Is: $1, should be: 50612.
fi
#
#
echo Extracting parsedir.c:
sed 's/^Z//' >parsedir.c <<\STUNKYFLUFF
Z#include <stdio.h>
Z#include "make.h"
Z
Z#ifdef VAXVMS
Z#  include <rms.h>
Z#endif
Z
Zextern DATE bigbang;
Zextern DATE endoftime;
Z
Zchar *printdate ();
Z
Z/*
Z * Get a file's creation date.
Z *
Z * First try for a normal file, then library, then archive.
Z */
Z
Zvoid getdate (f)
ZFILENODE *f;
Z{
Z    extern int isonlibrary ();
Z    extern int isanarchive ();
Z    
Z    DBUG_ENTER ("getdate");
Z    if (f -> fdate == (DATE) NULL) {
Z	if (filedate (f) != SUCCEED) {
Z	    if (isonlibrary (f) != SUCCEED) {
Z		if (isanarchive (f) != SUCCEED) {
Z		    if ((f -> fflag & ROOTP) == 0) {
Z			fprintf (stderr, "Can't get date for file '%s'\n",
Z				f -> fname);
Z			f -> fdate = endoftime;
Z		    } else {
Z			f -> fdate = bigbang;
Z		    }
Z		}
Z	    }
Z	}
Z    }
Z    DBUG_VOID_RETURN;
Z}
Z
Z
Z#ifdef VAXVMS
Z/*
Z * filedate - return file's creation date (VAX/VMS only.)
Z * Returns -1 if file cannot be found, 0 if succesful.
Z */
Zfiledate (fnd)
ZFILENODE *fnd;
Z{
Z    register unsigned *datetime;
Z    static DATE adate ();
Z    register struct FAB *fptr;
Z    register struct XABDAT *dptr;
Z
Z    fptr = Calloc (1, sizeof (struct FAB));	/* allocate FAB and XABDAT */
Z    dptr = Calloc (1, sizeof (struct XABDAT));
Z    if (fptr == NULL || dptr == NULL) {
Z	allerr ();
Z    }
Z    *fptr = cc $ rms_fab;	/* initialize FAB and XABDAT */
Z    *dptr = cc $ rms_xabdat;
Z    fptr -> fab $ l_xab = (char *) dptr;/* FAB -> XABDAT */
Z    fptr -> fab $ l_fna = fnd -> fname;/* setup filename */
Z    fptr -> fab $ b_fns = strlen (fnd -> fname);
Z    if (sys$open (fptr) != RMS$_NORMAL ||	/* open the file */
Z	sys$display (fptr) != RMS$_NORMAL) {	/* get XABDAT info */
Z	return (-1)
Z    }
Z    datetime = &(dptr -> xab$q_cdt);	/* record 64-bit date */
Z    fnd -> fdate = adate (datetime[0], datetime[1]);
Z    sys$close (fptr);		/* close the file */
Z    free (dptr);		/* clean up and return */
Z    free (fptr);
Z    return (0);
Z}
Z
Z/*
Z * laterdt - compare two dates.
Z * Return -1, 0 or 1 if date1 < date2, date1 == date2, or date1 > date2
Z */
Z
Zlaterdt (date1, date2)
ZDATE date1, date2;
Z{
Z    if (date1 -> ds_high > date2 -> ds_high ||
Z	(date1 -> ds_high >= date2 -> ds_high &&
Z	date1 -> ds_low > date2 -> ds_low)) {
Z	return (1);
Z    } else if (date1 -> ds_high == date2 -> ds_high &&
Z		date1 -> ds_low == date2 -> ds_low)
Z	return (0);
Z    } else {
Z	return (-1);
Z    }
Z}
Z
Z
Z/*
Z * adate - allocate a date with the given time
Z */
Z
ZDATE adate (time1, time2)
Zunsigned time1;
Zunsigned time2;
Z{
Z    auto DATE d;
Z
Z    if ((d = (DATE) Calloc (1, sizeof (struct date_str))) == NULL) {
Z	allerr ();
Z    }
Z    d -> ds_low = time1;
Z    d -> ds_high = time2;
Z    return (d);
Z}
Z
Zinitrootdates ()
Z{
Z    bigbang = adate (0, 0);		/* init root dates */
Z    endoftime = adate (~0, ~0);
Z}
Z
Zchar *printdate (fdate)
ZDATE fdate;
Z{
Z    static char *buffer[64];
Z
Z    sprintf (buffer, "( %u, %u )",
Z	    (f -> fdate != NULL) ? (f -> fdate) -> ds_high : 0,
Z	    (f -> fdate != NULL) ? (f -> fdate) -> ds_low : 0);
Z    return (buffer);
Z}
Z#endif
Z
Z
Z#ifdef MSDOS
Z
Z/*
Z * filedate - return file's creation date (MSDOS only.)
Z * Returns -1 if file cannot be found, 0 if successful
Z */
Z
Zfiledate (fnd)
ZFILENODE *fnd;
Z{
Z    extern DATE osdate ();
Z    auto DATE newdate;
Z    auto int success;
Z
Z    success = FAILURE;
Z    newdate = osdate (fnd -> fname, &success);
Z    if (success == FAILURE) {
Z	return (FAILURE);
Z    }
Z    fnd -> fdate = newdate;
Z    fnd -> fflag |= EXTRACT;	/* don't extract this file again */
Z    return (SUCCEED);
Z}
Z
Z/*
Z * laterdt - compare two dates.
Z * Return -1, 0 or 1 if date1 < date2, date1 == date2, or date1 > date2
Z */
Z
Zlaterdt (date1, date2)
ZDATE date1;
ZDATE date2;
Z{
Z    if (date1 -> ft_year > date2 -> ft_year) {
Z	return (1);
Z    }
Z    if (date1 -> ft_year < date2 -> ft_year) {
Z	return (-1);
Z    }
Z    /* years are equal */
Z    if (date1 -> ft_month > date2 -> ft_month) {
Z	return (1);
Z    }
Z    if (date1 -> ft_month < date2 -> ft_month) {
Z	return (-1);
Z    }
Z    /* months are equal */
Z    if (date1 -> ft_day > date2 -> ft_day) {
Z	return (1);
Z    }
Z    if (date1 -> ft_day < date2 -> ft_day) {
Z	return (-1);
Z    }
Z    /* days are equal */
Z    if (date1 -> ft_hour > date2 -> ft_hour) {
Z	return (1);
Z    }
Z    if (date1 -> ft_hour < date2 -> ft_hour) {
Z	return (-1);
Z    }
Z    /* hours are equal */
Z    if (date1 -> ft_min > date2 -> ft_min) {
Z	return (1);
Z    }
Z    if (date1 -> ft_min < date2 -> ft_min) {
Z	return (-1);
Z    }
Z    /* minutes are equal */
Z    if (date1 -> ft_tsec > date2 -> ft_tsec) {
Z	return (1);
Z    }
Z    if (date1 -> ft_tsec < date2 -> ft_tsec) {
Z	return (-1);
Z    }
Z    /* everything is equal */
Z    return (0);
Z}
Z
Z/*
Z * adate - allocate a date struct to be filled out later.
Z */
Z
ZDATE adate ()
Z{
Z    auto DATE d;
Z
Z    if ((d = (DATE) Calloc (1, sizeof (struct ftime))) == (DATE) NULL) {
Z	allerr ();
Z    }
Z    return (d);
Z}
Z
Zinitrootdates ()
Z{		/* init root dates */
Z    bigbang = adate ();
Z    bigbang -> ft_tsec = 0;
Z    bigbang -> ft_min = 0;
Z    bigbang -> ft_hour = 0;
Z    bigbang -> ft_day = 1;
Z    bigbang -> ft_month = 1;
Z    bigbang -> ft_year = 0;
Z    endoftime = adate ();
Z    endoftime- > ft_tsec = 29;
Z    endoftime- > ft_min = 59;
Z    endoftime- > ft_hour = 23;
Z    endoftime- > ft_day = 31;
Z    endoftime- > ft_month = 11;
Z    endoftime- > ft_year = 127;
Z}
Z
Zchar *printdate (fdate)
ZDATE fdate;
Z{
Z    auto char buf[10];
Z
Z#ifdef NOTYETCONVERTED
Z    fputs ("( ", stdout);
Z    itoa (fdate- > ft_hour, buf);
Z    fputs (buf, stdout);
Z    fputc (':', stdout);
Z    itoa (fdate- > ft_min, buf);
Z    fputs (buf, stdout);
Z    fputc (':', stdout);
Z    itoa (fdate- > ft_tsec, buf);
Z    fputs (buf, stdout);
Z    fputs (", ", stdout);
Z    itoa (fdate- > ft_month, buf);
Z    fputs (buf, stdout);
Z    fputc ('-', stdout);
Z    itoa (fdate- > ft_day, buf);
Z    fputs (buf, stdout);
Z    fputc ('-', stdout);
Z    itoa (fdate- > ft_year + 80, buf);
Z    fputs (buf, stdout);
Z    puts (" )");
Z#else
Z    return ("<not available>");
Z#endif
Z}
Z#endif
Z
Z#ifdef unix
Z
Z/*
Z * filedate - return file's creation date (unix only.)
Z * Returns -1 if file cannot be found, 0 if successful
Z */
Z
Zfiledate (fnd)
ZFILENODE *fnd;
Z{
Z    extern DATE osdate ();
Z    auto DATE newdate;
Z    auto int success = FAILURE;
Z
Z    DBUG_ENTER ("filedate");
Z    DBUG_3 ("date", "find date for '%s'", fnd -> fname);
Z    newdate = osdate (fnd -> fname, &success);
Z    DBUG_3 ("date", "has date %s", printdate (newdate));
Z    if (success != FAILURE) {
Z	fnd -> fdate = newdate;
Z	fnd -> fflag |= EXTRACT;	/* do not extract this file again */
Z	success = SUCCEED;
Z    }
Z    DBUG_RETURN (success);
Z}
Z
Z/*
Z * laterdt - compare two dates.
Z * Return -1, 0 or 1 if date1 < date2, date1 == date2, or date1 > date2
Z */
Z
Zlaterdt (date1, date2)
ZDATE date1;
ZDATE date2;
Z{
Z    int result;
Z    
Z    DBUG_ENTER ("laterdt");
Z    DBUG_4 ("dcmp", "compare %lu vs %lu", *date1, *date2);
Z    if (*date1 > *date2) {
Z	result = 1;
Z    } else if (*date1 < *date2) {
Z	result = -1;
Z    } else {
Z	result = 0;
Z    }
Z    DBUG_3 ("dcmp", "result is %d", result);
Z    DBUG_RETURN (result);
Z}
Z
Z/*
Z * adate - allocate a date struct to be filled out later.
Z */
Z
ZDATE adate ()
Z{
Z    auto DATE d;
Z
Z    DBUG_ENTER ("adate");
Z    if ((d = (DATE) Calloc (1, sizeof (long))) == (DATE) NULL) {
Z	allerr ();
Z    }
Z    DBUG_RETURN (d);
Z}
Z
Zvoid initrootdates ()
Z{		/* init root dates */
Z    DBUG_ENTER ("initrootdates");
Z    bigbang = adate ();
Z    *bigbang = 0;
Z    endoftime = adate ();
Z    *endoftime = ~0;
Z    DBUG_VOID_RETURN;
Z}
Z
Zchar *printdate (fdate)
ZDATE fdate;
Z{
Z    static char datebuf[64];
Z
Z    if (fdate == NULL) {
Z	sprintf (datebuf, "<null date>");
Z    } else {
Z	sprintf (datebuf, "%lu", *fdate);
Z    }
Z    return (datebuf);
Z}
Z
Z#endif
Z
Z#ifdef AMIGA
Z
Z/*
Z * filedate - return file's creation date (Amiga only.)
Z * Returns -1 if file cannot be found, 0 if successful
Z */
Z
Zfiledate (fnd)
ZFILENODE *fnd;
Z{
Z    extern DATE osdate ();
Z    auto DATE newdate;
Z    auto int success = FAILURE;
Z
Z    DBUG_ENTER ("filedate");
Z    newdate = osdate (fnd -> fname, &success);
Z    if (success == SUCCEED) {
Z	DBUG_3 ("fdate", "found date for '%s'", fnd -> fname);
Z	fnd -> fdate = newdate;
Z	fnd -> fflag |= EXTRACT;	/* don't extract this file again */
Z    }
Z    DBUG_RETURN (success);
Z}
Z
Z/*
Z * laterdt - compare two dates.
Z * Return -1, 0 or 1 if date1 < date2, date1 == date2, or date1 > date2
Z */
Z
Zint laterdt (date1, date2)
ZDATE date1;
ZDATE date2;
Z{
Z    register int result;
Z    
Z    DBUG_ENTER ("laterdt");
Z    DBUG_3 ("dcmp", "compare date1 %s", printdate (date1));
Z    DBUG_3 ("dcmp", "with    date2 %s", printdate (date2));
Z    if (date1 -> ds_Days > date2 -> ds_Days) {
Z	result = 1;
Z    } else if (date1 -> ds_Days < date2 -> ds_Days) {
Z	result = -1;
Z    } else {
Z	if (date1 -> ds_Minute > date2 -> ds_Minute) {
Z	    result = 1;
Z	} else if (date1 -> ds_Minute < date2 -> ds_Minute) {
Z	    result = -1;
Z	} else {
Z	    if (date1 -> ds_Tick > date2 -> ds_Tick) {
Z		result = 1;
Z	    } if (date1 -> ds_Tick < date2 -> ds_Tick) {
Z		result = -1;
Z	    } else {
Z		result = 0;
Z	    }
Z	}
Z    }
Z    DBUG_3 ("dcmp", "result is %d", result);
Z    DBUG_RETURN (result);
Z}
Z
Z/*
Z * adate - allocate a date struct to be filled out later.
Z */
Z
ZDATE adate ()
Z{
Z    auto DATE d;
Z
Z    DBUG_ENTER ("adate");
Z    if ((d = (DATE) Calloc (1, sizeof (struct DateStamp))) == (DATE) NULL) {
Z	allerr ();
Z    }
Z    DBUG_RETURN (d);
Z}
Z
Zvoid initrootdates ()
Z{		/* init root dates */
Z    DBUG_ENTER ("initrootdates");
Z    bigbang = adate ();
Z    bigbang -> ds_Days = 0;
Z    bigbang -> ds_Minute = 0;
Z    bigbang -> ds_Tick = 0;
Z    endoftime = adate ();
Z    endoftime -> ds_Days = ~0;
Z    endoftime -> ds_Minute = ~0;
Z    endoftime -> ds_Tick = ~0;
Z    DBUG_VOID_RETURN;
Z}
Z
Zchar *printdate (fdate)
ZDATE fdate;
Z{
Z    static char datebuf[64];
Z
Z    if (fdate == NULL) {
Z	sprintf (datebuf, "<null date>");
Z    } else {
Z	sprintf (datebuf, "days:%lu min:%lu ticks:%lu", fdate -> ds_Days,
Z    			fdate -> ds_Minute, fdate -> ds_Tick);
Z    }
Z    return (datebuf);
Z}
Z#endif
STUNKYFLUFF
set `sum parsedir.c`
if test 17360 != $1
then
echo parsedir.c: Checksum error. Is: $1, should be: 17360.
fi
#
#
echo Extracting readme:
sed 's/^Z//' >readme <<\STUNKYFLUFF
Z
Z
Z
Z
ZLast month I wrote a version of the Unix(tm) utility MAKE.  It runs under
ZVAX/VMS and MSDOS 2.0.  I am placing it in the public domain, and it is yours
Zfor the asking.  You may copy it, or give it away.  You can make any changes
Zyou like to it.  All I ask is that you DO NOT TRY TO SELL IT.
Z
ZAnyway, there is now a MAKE for MSDOS.  It is free, and it works pretty well.
ZI'm giving it away because it might do the world some good.  Who knows?
Z
ZCaveat: this version of MAKE is NOT compatible with the Unix(tm) version.
ZSome differences are explained in the documentation.  Most of the problem stems
Zfrom the fact that I've never had a chance to use the original version of MAKE,
Zand the documentation I've seen on it has been poor.  My idea of what a make
Zprogram should do is almost certainly different from what you Unix(tm) hackers
Zare used to.  Well, hell -- the software is worth what you paid for it.  Have
Zfun.
Z
ZIn order to get MAKE running on your system, you need to:
Z
Z	1.  Read the documentation file MAKE.MAN.  (Yes, read the
Z	    directions.)
Z
Z	2.  Edit the file MAKE.H to represent your system (VAX/VMS or
Z	    MSDOS 2.0.)
Z
Z	3.  Recompile the source code by following the script file
Z	    CMAKE.COM (for VAX/VMS) or CMAKE.BAT (for MSDOS 2.0.)
Z
Z	    VAX/VMS requires the DEC C compiler; MSDOS 2.0 requires
Z	    Lattice C (or another C compiler of comparable quality)
Z	    and the Macro Assembler.
Z
Z	4.  Test out MAKE by running it on itself.  (Make a backup
Z	    first!)
Z
Z
Z
Z			Good luck,
Z
Z			Landon Dyer (G.DYER @ SU-SCORE)
Z
Z
Z
Z
Z
STUNKYFLUFF
set `sum readme`
if test 53184 != $1
then
echo readme: Checksum error. Is: $1, should be: 53184.
fi
#
#
echo Extracting sys.c:
sed 's/^Z//' >sys.c <<\STUNKYFLUFF
Z/*
Z *	Routines which provide a single entry point to system routines,
Z *	for easier debugging and porting.
Z */
Z
Z#include <stdio.h>
Z#include "make.h"
Z
Z/*
Z *	The system calls malloc()/calloc() really return a pointer suitable
Z *	for use to store any object (satisfies worst case alignment
Z *	restrictions).  As such, it should really have been declared as
Z *	anything BUT "char *".
Z *
Z *	Also, this gives us the opportunity to verify that the memory
Z *	allocator really does align things properly.
Z *
Z *	Note that we choose to make calloc () the standard memory
Z *	allocator, rather than malloc (), because it has a potentially
Z *	bigger "bite" (total is product of two ints, rather than a
Z *	single int).
Z */
Z
Zlong *Calloc (nelem, elsize)
Zunsigned int nelem;
Zunsigned int elsize;
Z{
Z    extern char *calloc ();
Z    long *newmem;
Z    long total;
Z    
Z    DBUG_ENTER ("malloc");
Z    DBUG_4 ("mem1", "allocate %u elements of %u bytes", nelem, elsize);
Z    DBUG_3 ("mem2", "total of %ul bytes", total = nelem * elsize);
Z    newmem = (long *) calloc (nelem, elsize);
Z    if ((((int)newmem) % 4) != 0) {
Z	fprintf (stderr, "urk -- Calloc screwed up!\n");
Z    }
Z    DBUG_3 ("mem", "allocated at %x", newmem);
Z    DBUG_RETURN (newmem);
Z}
Z
Z#ifdef AMIGA
Z
Zint system (cmd)
Zchar *cmd;
Z{
Z    int status = -1;
Z    extern int Execute ();
Z    
Z    DBUG_ENTER ("system");
Z    if (Execute (cmd, 0 ,0)) {
Z	status = 0;		/* Really should get exit status! */
Z    }
Z    DBUG_RETURN (status);
Z}
Z
Z#endif	/* AMIGA */
STUNKYFLUFF
set `sum sys.c`
if test 58319 != $1
then
echo sys.c: Checksum error. Is: $1, should be: 58319.
fi
#
#
echo Extracting token.c:
sed 's/^Z//' >token.c <<\STUNKYFLUFF
Z#include <stdio.h>
Z#include <ctype.h>
Z#include "make.h"
Z
Zstatic char *stripwh ();
Z
Z/*
Z * Get next token from the string.  Return a pointer to it, or NULL.
Z * Adjust pointer to point to next part of string.
Z * The string is modified.
Z * A token consists of any number of non-white characters.
Z */
Z
Zchar *token (strpp)
Zchar **strpp;
Z{
Z    register char *s;
Z    register char *beg = NULL;
Z
Z    DBUG_ENTER ("token");
Z    DBUG_3 ("tok", "get next token from '%s'", *strpp);
Z    (void) stripwh (strpp);
Z    if (**strpp) {
Z	beg = s = *strpp;
Z	while (*s && !isspace (*s)) {
Z	    ++s;
Z	}
Z	if (*s) {
Z	    *s++ = '\0';
Z	}
Z	*strpp = s;
Z	DBUG_3 ("tok", "found token '%s'", beg);
Z    }
Z    DBUG_RETURN (beg);
Z}
Z
Z
Z/*
Z * Parse character escape-sequences in a line of text.
Z *	<EscChar><EscChar> = <EscChar>
Z *	<EscChar>n = newline, and so on
Z *	<EscChar><char> = <char>
Z * The string is truncated at the first non-escaped occurance of 'comchar'.
Z */
Z
Zvoid escape (str, comchar)
Zchar *str;
Zchar comchar;
Z{
Z    register char *d;
Z    register char c;
Z
Z    DBUG_ENTER ("escape");
Z    for (d = str; *str && *str != comchar; ++str) {
Z	if (*str == ESCCHAR && *(str + 1)) {
Z	    switch ((c = *++str)) {
Z		case ESCCHAR: 
Z		    *d++ = ESCCHAR;
Z		    break;
Z		case 'n': 
Z		    *d++ = '\n';
Z		    break;
Z		case 'r': 
Z		    *d++ = '\r';
Z		    break;
Z		case 't': 
Z		    *d++ = '\t';
Z		    break;
Z		case 'b': 
Z		    *d++ = '\b';
Z		    break;
Z		case 'f': 
Z		    *d++ = '\f';
Z		    break;
Z		default: 
Z		    *d++ = c;
Z		    break;
Z	    }
Z	} else {
Z	    *d++ = *str;
Z	}
Z    }
Z    *d++ = 0;
Z    DBUG_VOID_RETURN;
Z}
Z
Zstatic char *stripwh (strpp)
Zchar **strpp;
Z{
Z    register char *s;
Z
Z    s = *strpp;
Z    while (isspace (*s)) {
Z	++s;
Z    }
Z    return (*strpp = s);
Z}
STUNKYFLUFF
set `sum token.c`
if test 46598 != $1
then
echo token.c: Checksum error. Is: $1, should be: 46598.
fi
echo ALL DONE BUNKY!
exit 0