[comp.sources.misc] v13i019: PD make V1.6

greggy@zebra.UUCP (Greg Yachuk) (06/03/90)

Posting-number: Volume 13, Issue 19
Submitted-by: greggy@zebra.UUCP (Greg Yachuk)
Archive-name: make1.6/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  build.c default.mk default.msc make.h makefile
#   makefile.msc parse.c tstring.c tstring.h
# Wrapped by greggy@etude on Thu May 31 10:55:31 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'build.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'build.c'\"
else
echo shar: Extracting \"'build.c'\" \(7577 characters\)
sed "s/^X//" >'build.c' <<'END_OF_FILE'
X/*
X * build.c	An imitation of the Unix MAKE facility
X *
X * 88-10-01 v1.0	created by greg yachuk, placed in the public domain
X * 88-10-06 v1.1	changed prerequisite list handling
X * 88-11-11 v1.2	fixed some bugs and added environment variables
X * 89-07-12 v1.3	stop appending shell commands, and flush output
X * 89-08-01 v1.4 AB	lots of new options and code
X * 89-10-30 v1.5	-f -S -q options, took some changes from v1.4
X * 90-04-18 v1.6	-b -- -W options, emulate <<, non-BSD cleanup
X */
X
X#include <stdio.h>
X#include <string.h>
X#ifdef	MSDOS
X#include <stdlib.h>
X#include <process.h>
X#endif
X#ifdef	BSD
X#include <sys/wait.h>
X#endif
X
X#include "make.h"
X#include "tstring.h"
X#include "decl.h"
X
X#ifndef	MSDOS
Xchar  **bsearch();
X#endif
X
Xchar   *tmpfn = NULL;
X#define	shellunlink()	if(tmpfn!=NULL)unlink(tmpfn),tfree(tmpfn),tmpfn=NULL
X
X/*
X * shell_cmpr	- comparison routine for "shell command" binary search.
X */
Xshell_cmpr(key, list)
Xchar   *key;
Xchar  **list;
X{
X	return (strcmp(key, *list));
X}
X
X/*
X * build	- process the shell commands
X */
Xbuild(shellp)
Xshellptr *shellp;
X{
X	char  **argv;		/* argified version of scmd */
X	int     runst;		/* exec return status */
X	char   *scmd;		/* command with symbols broken out */
X	char   *tcmd;		/* copy of scmd for `tokenize' */
X	char   *errnum;		/* error number in ascii */
X	char   *errmsg;		/* error message */
X	int     i;
X	char   *sp;
X	char   *tp;
X	char  **shcp;		/* pointer to shell command list */
X
X	if (shellp == NULL || opts.query)
X		return (0);
X
X	/* process every shell line */
X
X	for (; *shellp != NULL;
X	     tfree(scmd), tfree(tcmd), tfree(argv), ++shellp)
X	{
X		/* breakout runtime symbols (e.g. $* $@ $<) */
X		scmd = breakout((*shellp)->scmd);
X
X		/* make a copy because tokenize litters '\0's */
X		tcmd = tstrcpy(scmd);
X		argv = tokenize(tcmd);
X
X		for (tp = scmd, i = 0; argv[i]; i++)
X		{
X			/* pretend to handle inline input ("<<" operator) */
X			while ((sp = strchr(argv[i], '<')) != NULL)
X			{
X				if (*++sp != '<')
X					continue;
X
X				sp[-1] = '\0';
X
X				/* got "<<".  collect commands into a file */
X				if (*++sp != '\0')	/* got "<<TAG" */
X					sp = shellinput(&shellp, sp);
X				else
X				{
X					/* got "<< TAG" (note space before TAG) */
X					sp = shellinput(&shellp, argv[i + 1]);
X					if (argv[i + 1])
X					{
X						tfree(argv[i + 1]);
X						argv[i + 1] = tstrcpy("");
X					}
X				}
X
X				/* add the filename to the argument */
X				sp = tstrcat(argv[i], sp);
X				tfree(argv[i]);
X				argv[i] = sp;
X			}
X
X			/* now strip the quotes from the argument */
X			strcpy(tp, tunquote(argv[i]));
X			while (*tp++);
X			tp[-1] = ' ';
X		}
X
X		/* finally, terminate the command line (scmd) */
X		tp[-1] = '\0';
X
X		if (!opts.silent && (opts.noexec || !(*shellp)->s_silent))
X		{
X			puts(scmd);
X			fflush(stdout);
X		}
X
X		/* look for $(MAKE) */
X		if (equal(argv[0], opts.make))
X		{
X			/* call ourselves recursively */
X			new_make(argv);
X			continue;
X		}
X
X		if (opts.noexec)
X			continue;
X
X		/* any SHELL meta-characters MUST be handled by the shell */
X		if (!(*shellp)->s_shell && strpbrk(scmd, SHELL_METAS))
X			(*shellp)->s_shell = 1;
X
X		if (shell_cmds && !(*shellp)->s_shell)
X		{
X			/* check for COMMAND.COM builtin commands */
X			for (shcp = shell_cmds; *shcp; ++shcp);
X			shcp = bsearch(argv[0], shell_cmds,
X				       shcp - shell_cmds - 1,
X				       sizeof(char *), shell_cmpr);
X			(*shellp)->s_shell = (shcp != NULL);
X		}
X
X		/* run without COMMAND.COM if possible, 'cause it uses RAM */
X		if (!(*shellp)->s_shell)
X			runst = spawnvp(P_WAIT, argv[0], argv);
X		else
X			runst = system(scmd);
X
X		shellunlink();
X
X		if (runst == 0)
X			continue;
X
X		/* uh-oh, an error */
X		if (runst == -1)
X			perror("make");
X
X		errnum = talloc(18);
X#ifdef	MSDOS
X		errnum = itoa(runst, errnum, 10);
X#else
X		sprintf(errnum, "%d", runst);
X#endif
X		errmsg = (opts.keepon) ? "\007*** Ignoring Error code "
X			: "\007*** Error code ";
X		errmsg = tstrcat(errmsg, errnum);
X		terror(0, errmsg);
X		tfree(errmsg);
X		tfree(errnum);
X
X		if (opts.keepon)
X			return (1);
X
X		if (!opts.ignore && !(*shellp)->s_ignore)
X			exit(1);
X	}
X
X	return (0);
X}
X
X
X/*
X * shellinput	- write the list of commands into a temp file, and return name
X */
Xchar   *shellinput(shellp, eof)
Xshellptr **shellp;
Xchar   *eof;
X{
X	int     eoflen;
X	char   *scmd;
X	FILE   *tfp;
X
X	/* get rid of obvious errors */
X	if (shellp == NULL || *shellp == NULL)
X		return (NULL);
X
X	eoflen = (eof) ? strlen(eof) : 0;
X
X	/* find the name of a candidate temporary file */
X	tmpfn = tempnam(NULL, "mk");
X
X	/* write contents to stdout when '-n' is specified */
X	if (opts.noexec && !opts.silent && !(**shellp)->s_silent)
X		tfp = stdout;
X	else
X		tfp = fopen(tmpfn, "w");
X
X	while (*++*shellp)
X	{
X		/* break out the current shell command */
X		scmd = breakout((**shellp)->scmd);
X
X		/* propogate the shell command attributes */
X		(**shellp)->s_silent = ((*shellp)[-1])->s_silent;
X		(**shellp)->s_ignore = ((*shellp)[-1])->s_ignore;
X		(**shellp)->s_shell = ((*shellp)[-1])->s_shell;
X
X		/* see if we've reached the eof-word */
X		if (eof && !strncmp(scmd, eof, eoflen))
X			break;
X
X		/* no there, so write out the command to the temp file */
X		if (tfp)
X		{
X			fputs(scmd, tfp);
X			fputc('\n', tfp);
X		}
X
X		/* free the string allocated by breakout() */
X		tfree(scmd);
X	}
X
X	if (tfp != stdout)
X		fclose(tfp);
X
X	if (**shellp == NULL)
X		--* shellp;	/* point at last shell command */
X	else
X		tfree(scmd);	/* free EOF-word */
X
X	return (tmpfn);
X}
X
X
X/*
X * new_make	- save current environment
X *		- call make() recursively (actually main())
X *		- clean up new environment
X *		- restore environment
X */
Xnew_make(argv)
Xchar  **argv;
X{
X	targptr thead, tnext, tsuffix;
X	fileptr fhead, fnext;
X	symptr  shead, snext;
X	shellptr shhead, shnext;
X	char  **shcmds;
X	char  **ttlist;
X	long    tnow;
X	optnode topts;
X	int     i;
X
X	/* save all the globals */
X	tsuffix = suffix_targ;
X	thead = target_list;
X	fhead = file_list;
X	shead = symbol_list;
X	shhead = shell_list;
X	shcmds = shell_cmds;
X	ttlist = tlist;
X	tnow = now;
X	topts = opts;
X
X	/* count the arguments */
X	for (i = 0; argv[i]; ++i)
X		tunquote(argv[i]);
X
X	/* call ourselves recursively; this inherits flags */
X	++make_level;
X	main(i, argv);
X	--make_level;
X
X	/* we're back, so gotta clean up and dispose of a few things */
X	while (target_list)
X	{
X		tnext = target_list->tnext;
X		if (target_list->tpreq)
X			tfree(target_list->tpreq);
X		if (target_list->tshell)
X			tfree(target_list->tshell);
X		tfree(target_list);
X		target_list = tnext;
X	}
X
X	while (file_list)
X	{
X		fnext = file_list->fnext;
X		tfree(file_list->fname);
X		tfree(file_list);
X		file_list = fnext;
X	}
X
X	/* don't drop all symbols, just the new ones */
X
X	while (symbol_list != shead)
X	{
X		snext = symbol_list->snext;
X		tfree(symbol_list->sname);
X		tfree(symbol_list->svalue);
X		tfree(symbol_list);
X		symbol_list = snext;
X	}
X
X	while (shell_list)
X	{
X		shnext = shell_list->slink;
X		tfree(shell_list->scmd);
X		tfree(shell_list);
X		shell_list = shnext;
X	}
X
X	/* restore our original globals */
X	suffix_targ = tsuffix;
X	target_list = thead;
X	file_list = fhead;
X	symbol_list = shead;
X	shell_list = shhead;
X	shell_cmds = shcmds;
X	tlist = ttlist;
X	now = tnow;
X	opts = topts;
X}
X
X
X#ifndef	MSDOS
Xint     spawnvp(mode, path, args)
Xint     mode;
Xchar   *path;
Xchar  **args;
X{
X	int     pid = 0;
X	int     retpid;
X#ifdef	BSD
X	union wait waitword;
X#else
X	int     waitword;
X#endif
X
X	if (mode != P_OVERLAY)
X		pid = fork();
X
X	if (pid == 0)
X		execvp(path, args);
X
X	while (((retpid = wait(&waitword)) != pid) && (retpid > 0))
X		;
X#ifdef	BSD
X	return ((retpid == pid) ? waitword.w_retcode : (-1));
X#else
X	return ((retpid == pid) ? ((waitword >> 8) & 0x00ff) : (-1));
X#endif
X}
X#endif
END_OF_FILE
if test 7577 -ne `wc -c <'build.c'`; then
    echo shar: \"'build.c'\" unpacked with wrong size!
fi
# end of 'build.c'
fi
if test -f 'default.mk' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'default.mk'\"
else
echo shar: Extracting \"'default.mk'\" \(2487 characters\)
sed "s/^X//" >'default.mk' <<'END_OF_FILE'
X### this is the default makefile for Unix: default.mk
X
XSUFFIXES = .o .C .cxx .ec .c .y .l .s .sh 
X.SUFFIXES: $(SUFFIXES)
X
X#	ASM section
XAS	 = as
XASFLAGS	 =
XCOMPILE.s= $(AS) $(ASFLAGS)
X.s:
X	$(AS) $(ASFLAGS) $<
X.s.o:
X	$(AS) $(ASFLAGS) -o $@ $<
X
X#	C section
XCC	 = cc
XCFLAGS	 = -O
XCDEBUG	 = -g
XCOMPILE.c= $(CC) $(CFLAGS) -c
X.c:
X	$(LINK.c) -o $@ $< $(LDFLAGS)
X
X.c.o:
X	$(COMPILE.c) $<
X
X.c.i:
X	$(COMPILE.c) -P $<
X
X#	CPP Section
XCPP	 = CC
XCPPFLAGS = -O
XCPPDEBUG = -g
XCOMPILE.cpp = $(CPP) $(CPPFLAGS)
X.C .cxx:
X	$(CPP) $(CPPFLAGS) -o $@ $< $(LDFLAGS)
X
X.C.o .cxx.o:
X	$(COMPILE.cpp) $<
X
X.C.c .cxx.c:
X	$(COMPILE.cpp) -P $<
X
X#	ESQL/C section
XESQL	 = esql
XEFLAGS	 =
XCOMPILE.e= $(ESQL) $(EFLAGS)
X.ec:
X	$(COMPILE.e) -e $<
X	$(LINK.c) -o $@ $*.c $(LDFLAGS)
X
X.ec.o:
X	$(COMPILE.e) -e $<
X	$(COMPILE.c) $*.c
X
X.ec.c:
X	$(COMPILE.e) -e $<
X
X#	Lex section
XLEX	 = lex
XLFLAGS	 =
XLEX.l	 = $(LEX) $(LFLAGS) -t
X.l:
X	$(LEX.l) $< > $*.c
X	$(LINK.c) -o $@ $*.c $(LDFLAGS) -ll
X
X.l.o:
X	$(LEX.l) $< > $*.c
X	$(COMPILE.c) $*.c
X
X.l.c:
X	$(LEX.l) $< > $*.c
X
X#	YACC section
XYACC	 = yacc
XYFLAGS	 =
XYACC.y	 = $(YACC) $(YFLAGS)
X.y:
X	$(YACC.y) $<
X	$(LINK.c) -o $@ y.tab.c $(LDFLAGS) -ly
X	$(RM) y.tab.c
X
X.y.o:
X	$(YACC.y) $<
X	$(COMPILE.c) -o $*.o y.tab.c
X	$(RM) y.tab.c
X
X.y.c:
X	$(YACC) $(YFLAGS) $<
X	$(MV) y.tab.c $@
X
X.y.h:
X	$(YACC) $(YFLAGS) -d $<
X	$(RM) y.tab.c
X	$(MV) y.tab.h $@
X
X#	Shell script section
X.sh:
X	cp $< $@
X
X#	BSD Unix Misc section
XA        = .a
XAR       = ar
XARFLAGS  =
XBIN      = /usr/local/bin
XCP       = cp
XE        =
XEDITOR   = /usr/bin/vi
XGFLAGS   =
XGET      = get
XLDEBUG   =
XLDFLAGS  =
XLD       = ld
XLIBDIR   =
XLINK.c   = $(CC) $(CFLAGS)
XMAKE     = make
XMKDEPEND = makedepend
XMODEL    =
XMV       = mv
XO        = .o
XRANLIB   = ranlib
XRM       = rm -f
XSHELL    = /bin/csh
XSHELLCMD =
XSTACK    =
X
X#	DOS Misc section
X#A        = .lib
X#AR       = lib
X#ARFLAGS  =
X#BIN      = C:\bin
X#CP       = cp
X#E        = .exe
X#EDITOR   = $(BIN)\vi
X#GFLAGS   =
X#GET      = echo cannot get
X#LDEBUG   = /link /noe /noi /co /st:$(STACK) $(LIBS)
X#LDFLAGS  = /link /noe /noi /st:$(STACK) $(LIBS)
X#LD       = $(CC) $(CFLAGS)
X#LIBDIR   = c:\msc5.1\lib
X#LINK.c   = $(CC) $(CFLAGS)
X#MAKE     = make
X#MKDEPEND = mkdepend
X#MODEL    = S
X#MV       = mv
X#O        = .o
X#RANLIB   = echo cannot ranlib 
X#RM       = rm -f
X#SHELL    = command /c
X#SHELLCMD = break call cd chcp chdir cls copy ctty date del dir \
X#	   echo erase exit for goto if md mkdir path pause prompt \
X#	   rd rem ren rename rmdir set shift time type ver verify vol
X#STACK    = 2000
END_OF_FILE
if test 2487 -ne `wc -c <'default.mk'`; then
    echo shar: \"'default.mk'\" unpacked with wrong size!
fi
# end of 'default.mk'
fi
if test -f 'default.msc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'default.msc'\"
else
echo shar: Extracting \"'default.msc'\" \(3930 characters\)
sed "s/^X//" >'default.msc' <<'END_OF_FILE'
X### this is the default makefile for DOS: default.mk
X
XSUFFIXES = .cpp .c .asm .l .y .ec
X.SUFFIXES: $(SUFFIXES)
X
X#	ASM section
XAS	 = masm
XASFLAGS	 = /mx			# don't convert to upper case
XCOMPILE.s= $(AS) $(ASFLAGS)
X.asm .asm.com:
X	 $(COMPILE.s) $<;
X	 $(LINK.c) -o $*.exe $*.obj $(LDFLAGS)
X	 $(RM) $*.obj
X	 exe2bin $*.exe $*.com
X	 $(RM) $*.exe
Xasm.exe:
X	 $(COMPILE.s) $<;
X	 $(LINK.c) -o $@ $*.obj $(LDFLAGS)
X	 $(RM) $*.obj
X.asm.obj:
X	 $(COMPILE.s) $<;
X.asm.o:
X	 $(COMPILE.s) $<;
X	 mv $*.obj $@
X
X#	C section
XCC	 = cl -A$(MODEL)
XCFLAGS	 = /Ox /G2		# full optimization, 80286 opcodes
XCDEBUG	 = /Od /Zi		# no optimization, Codeview debuggable
XCOMPILE.c= $(CC) $(CFLAGS) -c
X.c.com:
X	 $(COMPILE.cpp) -mt $< $(LIBS)
X	 $(RM) $*.obj
X.c .c.exe:
X	 $(LINK.c) -o $@ $< $(LDFLAGS)
X	 $(RM) $*.obj
X.c.o:
X	 $(COMPILE.c) /Fo$*.o $<
X.c.obj:
X	 $(COMPILE.c) $<
X
X#	D section (ANSI C declaration headers)
X.c.d:
X	 echo "#ifndef NOPROTOTYPES" > $*.tmp
X	-$(COMPILE.c) -DNOPROTOTYPES -Zg $< >> $*.tmp
X	 echo "#endif" >> $*.tmp
X	+updexhdr $*.tmp $*.d
X	 $(RM) $*.tmp
X
X#	I section (preprocessed C files)
X.c.i:
X	 $(COMPILE.c) -P $<
X
X#	CPP Section
XCPPINCDIR= c:\zortech\include
XCPP	 = ztc -DNO_EXT_KEYS -I$(CPPINCDIR) -B -m$(MODEL)i	# integer only
XCPPF	 = ztc -DNO_EXT_KEYS -I$(CPPINCDIR) -B -m$(MODEL)	# floats also
XCPPFLAGS = -o					# full optimization
XCPPDEBUG = -g -co -s				# codeview and stack checking
XCOMPILE.cpp=$(CPP) $(CPPFLAGS)
X.cpp .cpp.com:
X	 $(COMPILE.cpp) -mt $<
X	 $(RM) $*.obj
X.cpp.exe:
X	 $(COMPILE.cpp) $<
X	 $(RM) $*.obj
X.cpp.obj:
X	 $(COMPILE.cpp) -c $<
X.cpp.o:
X	 $(COMPILE.cpp) -c $<
X	 $(MV) $*.obj $@
X.cpp.c:
X	$(COMPILE.cpp) -c -e -l$*.c $<
X
X#	ESQL/C section
XESQL	 = esql
XEFLAGS	 =
XCOMPILE.e= $(ESQL) $(EFLAGS)
X.ec .ec.exe:
X	 $(COMPILE.e) -e $<
X	 $(LINK.c) -o $@ $*.c $(LDFLAGS) $(MODEL)libsql
X	 $(RM) $*.obj $*.c
X.ec.o:
X	 $(COMPILE.e) -e $<
X	 $(COMPILE.c) /Fo$*.o $*.c
X	 $(RM) $*.c
X.ec.obj:
X	 $(COMPILE.e) -e $<
X	 $(COMPILE.c) $*.c
X	 $(RM) $*.c
X.ec.c:
X	 $(COMPILE.e) -e $<
X
X#	Lex section
XLEX	 = flex
XLFLAGS	 = -I				# interactive scanner
XLEX.l	 = $(LEX) $(LFLAGS) -t
X.l.com:
X	 $(LEX.l) $< > $*.c
X	 $(COMPILE.cpp) -mt $*.c
X	 $(RM) $*.obj $*.c
X.l .l.exe:
X	 $(LEX.l) $< > $*.c
X	 $(LINK.c) -o $@ $*.c $(LDFLAGS)
X	 $(RM) $*.obj $*.c
X.l.o:
X	 $(LEX.l) $< > $*.c
X	 $(COMPILE.c) /Fo$*.o $*.c
X	 $(RM) $*.c
X.l.obj:
X	 $(LEX.l) $< > $*.c
X	 $(COMPILE.c) $*.c
X	 $(RM) $*.c
X.l.c:
X	 $(LEX.l) $< > $@
X
X#	YACC Section
XYACC	 = yacc
XYFLAGS	 =
XYACC.y	 = $(YACC) $(YFLAGS)
X.y.com:
X	 $(YACC.y) $<
X	 $(COMPILE.cpp) -mt ytab.c
X	 $(RM) $*.obj ytab.c
X.y .y.exe:
X	 $(YACC.y) $<
X	 $(LINK.c) -o $@ ytab.c $(LDFLAGS)
X	 $(RM) $*.obj ytab.c
X.y.o:
X	 $(YACC.y) $<
X	 $(COMPILE.c) /Fo$*.o ytab.c
X	 $(RM) ytab.c
X.y.obj:
X	 $(YACC.y) $<
X	 $(COMPILE.c) ytab.c
X	 $(RM) ytab.c
X.y.h:
X	 $(YACC.y) -d $<
X	 $(RM) ytab.c
X	 $(MV) ytab.h $@
X.y.c:
X	 $(YACC.y) $<
X	 $(MV) ytab.c $@
X
X#	BSD Unix Misc section
X#A        = .a
X#AR       = ar
X#ARFLAGS  =
X#BIN      = /usr/local/bin
X#CP       = cp
X#E        =
X#EDITOR   = /usr/bin/vi
X#GFLAGS   =
X#GET      = get
X#LDEBUG   =
X#LDFLAGS  =
X#LD       = ld
X#LIBDIR   =
X#LINK.c   = $(CC) $(CFLAGS)
X#MAKE     = make
X#MKDEPEND = makedepend
X#MODEL    =
X#MV       = mv
X#O        = .o
X#RANLIB   = ranlib
X#RM       = rm -f
X#SHELL    = /bin/csh
X#SHELLCMD =
X#STACK    =
X
X#	DOS Misc section
XA        = .lib
XAR       = lib
XARFLAGS  =
XBIN      = C:\bin
XCP       = cp
XE        = .exe
XEDITOR   = $(BIN)\vi
XGFLAGS   =
XGET      = echo cannot get
XLDEBUG   = /link /noe /noi /co /st:$(STACK) $(LIBS)
XLDFLAGS  = /link /noe /noi /st:$(STACK) $(LIBS)
XLD       = $(CC) $(CFLAGS)
XLIBDIR   = c:\msc5.1\lib
XLINK.c   = $(CC) $(CFLAGS)
XMAKE     = make
XMKDEPEND = mkdepend
XMODEL    = S
XMV       = mv
XO        = .o
XRANLIB   = echo cannot ranlib 
XRM       = rm -f
XSHELL    = command /c
XSHELLCMD = break call cd chcp chdir cls copy ctty date del dir \
X	   echo erase exit for goto if md mkdir path pause prompt \
X	   rd rem ren rename rmdir set shift time type ver verify vol
XSTACK    = 2000
END_OF_FILE
if test 3930 -ne `wc -c <'default.msc'`; then
    echo shar: \"'default.msc'\" unpacked with wrong size!
fi
# end of 'default.msc'
fi
if test -f 'make.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'make.h'\"
else
echo shar: Extracting \"'make.h'\" \(3424 characters\)
sed "s/^X//" >'make.h' <<'END_OF_FILE'
X/*
X * make.h
X *
X * 88-10-01 v1.0	created by greg yachuk, placed in the public domain
X * 88-10-06 v1.1	changed prerequisite list handling
X * 88-11-11 v1.2	fixed some bugs and added environment variables
X * 89-07-12 v1.3	stop appending shell commands, and flush output
X * 89-08-01 v1.4 AB	lots of new options and code
X * 89-10-30 v1.5	-f -S -q options, took some changes from v1.4
X * 90-04-18 v1.6	-b -- -W options, emulate <<, non-BSD cleanup
X */
X
X#define MAKEINI "default.mk"
X
X#ifdef	MSDOS
X#define	PATH_SEPARATOR	";"
X#define	FILE_SEPARATOR	":/\\"
X#define	SHELL_METAS	"<|>"
X#else
X#define	PATH_SEPARATOR	":"
X#define	FILE_SEPARATOR	"/"
X#define	SHELL_METAS	"<|>`*?()[];&$"
X#endif
X
X#define	MAXNEGTIME	0x80000000
X
X#define	equal(s,t)		(!strcmp((s),(t)))
X#define	get_target(t)		hash_target((t), NULL)
X#define	get_file(f)		hash_file((f), NULL)
X#define	append_preq(t,p)	(fileptr*)append_node((char**)(t),(char**)(p),sizeof(fileptr*))
X#define	append_shell(t,s)	(shellptr*)append_node((char**)(t),(char**)(s),sizeof(shellptr*))
X
Xtypedef unsigned short t_mask;
X
Xtypedef struct targnode
X{
X	t_mask  tmask;		/* mask to avoid string compares */
X	struct targnode *tnext;	/* next target in global target list */
X	struct filenode *tfile;	/* file node for this target */
X	struct filenode **tpreq;/* pre-req list for this target */
X	struct shellnode **tshell;	/* command list for this target */
X}       targnode, *targptr;
X
Xtypedef struct filenode
X{
X	t_mask  fmask;		/* mask to avoid string compares */
X	char   *fname;		/* name of this file (targ, preq...) */
X	long    ftime;		/* last MODIFY time for this file */
X	struct filenode *fnext;	/* next file node in global file list */
X}       filenode, *fileptr;
X
Xtypedef struct shellnode
X{
X	char   *scmd;		/* text of command */
X	unsigned s_silent:1;	/* don't echo before executing */
X	unsigned s_ignore:1;	/* ignore exit status */
X	unsigned s_shell:1;	/* force spawning of command.com */
X	struct shellnode *slink;/* next shell node in global list */
X}       shellnode, *shellptr;
X
Xtypedef struct symnode
X{
X	t_mask  smask;		/* mask to avoid string compares */
X	char   *sname;		/* name of a symbol */
X	char   *svalue;		/* value of a symbol */
X	struct symnode *snext;	/* next symbol node in global list */
X	int     scmd;		/* command line macro? */
X	int     slevel;		/* level of new_make() */
X}       symnode, *symptr;
X
Xtypedef struct optnode
X{
X	unsigned depend;	/* -d */
X	unsigned display:1;	/* -D */
X	unsigned envirn:1;	/* -e */
X	unsigned ignore:1;	/* -i */
X	unsigned keepon:1;	/* -k */
X	unsigned noexec:1;	/* -n */
X	unsigned query:1;	/* -q */
X	unsigned silent:1;	/* -s */
X	unsigned touch:1;	/* -t */
X	char   *make;		/* current value of $(MAKE) */
X}       optnode;
X
Xextern targptr target_list;	/* global list of targets */
Xextern fileptr file_list;	/* global list of file nodes */
Xextern symptr symbol_list;	/* global list of symbol nodes */
Xextern shellptr shell_list;	/* global list of shell nodes */
X
Xextern char **shell_cmds;	/* commands which force usage of SHELL */
X
Xextern int make_level;		/* level of new_make() */
X
Xextern targptr first_targ;	/* first target (if nothing named) */
Xextern targptr suffix_targ;	/* target node of ".SUFFIXES" */
X
Xextern optnode opts;		/* various options */
Xextern char **tlist;		/* list of command line targets */
Xextern long now;		/* current time */
X
X#ifndef	MSDOS
Xchar   *getenv();
X
X#define	P_WAIT		1
X#define	P_NOWAIT	2
X#define	P_OVERLAY	3
X#endif				/* MSDOS */
END_OF_FILE
if test 3424 -ne `wc -c <'make.h'`; then
    echo shar: \"'make.h'\" unpacked with wrong size!
fi
# end of 'make.h'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(1286 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X# name of this program
XNAME	= make
X
X# define the FLAGS as required for MSDOS or Unix
XCFLAGS	= -O
XLDFLAGS	=
X
XSRCS	= make.c parse.c build.c tstring.c
XOBJS	= make.o parse.o build.o tstring.o
XPROG	= $(NAME)$E
X
X# define your installation directory
XBIN	= $(HOME)/bin
X
X# archive utility
XARCADD	= zoo a
X
X# files to archive
XARCS	= decl.h make.h tstring.h make.c parse.c build.c tstring.c \
X	  default.mk default.bsd makefile makefile.bsd make.doc \
X	  README $(PROG)
X
Xall:	$(PROG)
X
X$(PROG):	$(OBJS)
X	$(CC) $(CFLAGS) $(OBJS) -o $(PROG) $(LDFLAGS)
X
Xarc:	$(NAME).zoo
Xzoo:	$(NAME).zoo
X
X$(NAME).zoo:	$(ARCS)
X	$(RM) $(NAME).zoo
X	$(ARCADD) $(NAME).zoo $(ARCS)
X
Xinstall:	$(BIN)/$(PROG) $(BIN)/default.mk
X$(BIN)/$(PROG):	$(PROG)
X	cp $(PROG) $(BIN)/$(PROG)
X$(BIN)/default.mk: default.mk
X	cp default.mk $(BIN)/default.mk
X
Xclean:
X	-$(RM) *.o
X	-$(RM) *.bak
X
X# use this to check the size of the program (use chkdsk if necessary)
Xsize:
X	pmap
X
Xdepend:
X	$(MKDEPEND) $(SRCS) > makefile.new
X	$(MV) makefile makefile.BAK
X	$(MV) makefile.new makefile
X
Xtest:	$(OBJS)
X	link @<<END_OF_LINK
X		$(OBJS)
X		x$(NAME)
X		/cparmaxalloc:1 /noe /stack:2000
X		$(LIBS)
X	END_OF_LINK
X
X# DO NOT DELETE THIS LINE
X
Xmake.o: make.h tstring.h decl.h 
Xparse.o: make.h tstring.h decl.h 
Xbuild.o: make.h tstring.h decl.h
Xtstring.o: tstring.h 
END_OF_FILE
if test 1286 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'makefile.msc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile.msc'\"
else
echo shar: Extracting \"'makefile.msc'\" \(1483 characters\)
sed "s/^X//" >'makefile.msc' <<'END_OF_FILE'
X# name of this program
XNAME	= make
X
X# define the FLAGS as required for MSDOS or Unix
XCFLAGS	= /Oals /Gs /G2
XLDFLAGS = /link /cparmaxalloc:1 /noe /stack:2000 $(LIBS)
X
XSRCS	= make.c parse.c build.c tstring.c
XOBJS	= make.o parse.o build.o tstring.o
XPROG	= $(NAME)$E
X
X# define your installation directory
XBIN	= c:/bin
X
X# archive utility
XARCADD	= zoo a
X
X# files to archive
XARC1	= decl.h make.h tstring.h make.c parse.c build.c tstring.c default.mk
XARC2	= default.bsd makefile makefile.bsd make.doc README $(PROG)
XARCS	= $(ARC1) $(ARC2)
X
Xall:	$(PROG)
X
X$(PROG):	$(OBJS)
X	echo out of date dependents($@): $?
X	$(CC) $(CFLAGS) $(OBJS) -o $(PROG) $(LDFLAGS)
X
Xarc:	$(NAME).zoo
Xzoo:	$(NAME).zoo
X
X$(NAME).zoo:	$(ARCS)
X	$(RM) $(NAME).zoo
X	$(ARCADD) $(NAME).zoo $(ARC1)
X	$(ARCADD) $(NAME).zoo $(ARC2)
X
Xinstall:	$(BIN)/$(PROG) $(BIN)/default.mk
X$(BIN)/$(PROG):	$(PROG)
X	cp $(PROG) $(BIN)/$(PROG)
X$(BIN)/default.mk: default.mk
X	cp default.mk $(BIN)/default.mk
X
Xclean:
X	-$(RM) *.o
X	-$(RM) *.bak
X
X# use this to check the size of the program (use chkdsk if necessary)
Xsize:
X	pmap
X
Xdepend:
X	$(MKDEPEND) $(SRCS) > makefile.new
X	$(MV) makefile makefile.BAK
X	$(MV) makefile.new makefile
X
Xtest:	$(OBJS)
X	echo out of date dependents($@): $?
X	link @<<END_OF_LINK
X		$(OBJS)
X		x$(NAME)
X		/cparmaxalloc:1 /noe /stack:2000
X		$(LIBS)
X	END_OF_LINK
X	echo End Of Link
X
X# DO NOT DELETE THIS LINE
X
Xmake.o: make.h tstring.h decl.h 
Xparse.o: make.h tstring.h decl.h 
Xbuild.o: make.h tstring.h decl.h 
Xtstring.o: tstring.h 
END_OF_FILE
if test 1483 -ne `wc -c <'makefile.msc'`; then
    echo shar: \"'makefile.msc'\" unpacked with wrong size!
fi
# end of 'makefile.msc'
fi
if test -f 'parse.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'parse.c'\"
else
echo shar: Extracting \"'parse.c'\" \(17139 characters\)
sed "s/^X//" >'parse.c' <<'END_OF_FILE'
X/*
X * parse.c
X *
X * 88-10-01 v1.0	created by greg yachuk, placed in the public domain
X * 88-10-06 v1.1	changed prerequisite list handling
X * 88-11-11 v1.2	fixed some bugs and added environment variables
X * 89-07-12 v1.3	stop appending shell commands, and flush output
X * 89-08-01 v1.4 AB	lots of new options and code
X * 89-10-30 v1.5	-f -S -q options, took some changes from v1.4
X * 90-04-18 v1.6	-b -- -W options, emulate <<, non-BSD cleanup
X */
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#ifdef	MSDOS
X#include <stdlib.h>
X#endif
X
X#include "make.h"
X#include "tstring.h"
X#include "decl.h"
X
X/*
X * parse	- read (text) makefile, and parse
X *		- close file before returing
X *
X * lines have the following format:
X *	# with or without preceeding spaces/tabs	(comment line)
X *	<TAB> commands					(shell line)
X *	name = stuff					(macro)
X *	name += stuff					(macro)
X *	targ [targ...] : [pre-req...] [; shell cmd ]	(target line)
X */
Xparse(fd)
XFILE   *fd;
X{
X	char   *input;
X	char   *ip;
X	char   *colonp;
X	char    schar;
X	int     ntargs, npreqs, nshell;
X	int     tmax, pmax, smax;
X	targptr *targs;
X	fileptr *preqs;
X	shellptr *shells;
X
X	if (fd == NULL)
X		return (0);
X
X	/* start off with a short list of targets */
X	targs = (targptr *) grow_list(NULL, &tmax);
X	preqs = (fileptr *) grow_list(NULL, &pmax);
X	shells = (shellptr *) grow_list(NULL, &smax);
X
X	ntargs = npreqs = nshell = 0;
X
X	/* maximize buffering */
X	setvbuf(fd, NULL, _IOFBF, 2048);
X
X	while ((input = tgets(fd)) != NULL)
X	{
X		/* punt on comments and blank lines */
X		for (ip = input; isspace(*ip); ++ip);
X		if (*ip == '#' || *ip == '\0')
X			continue;
X
X		/* process include files */
X		if (!strncmp(ip, "include", 7))
X		{
X			/* skip spaces AFTER "include" */
X			for (ip += 7; isspace(*ip); ++ip);
X
X			/* process macros in the filename */
X			ip = breakout(ip);
X
X			/* parse the makefile */
X			if (!parse(fopen(ip, "r")))
X				terror(1, tstrcat("cannot open ", ip));
X
X			/* free up the broken-out string */
X			tfree(ip);
X			continue;	/* get next input line */
X		}
X
X		/* display the makefile line ? */
X		if (opts.display)
X			puts(input);
X
X		/* get rid of comments and preceeding spaces */
X		for (colonp = ip; *colonp && *colonp != '#'; ++colonp)
X		{
X			if (*colonp == '\'' || *colonp == '"')
X				colonp = tstrspan(colonp);
X		}
X
X		for (--colonp; colonp >= ip && isspace(*colonp); --colonp);
X
X		/* we *know* that some non-space is on this line, from above */
X		if (colonp >= ip)
X			*++colonp = '\0';
X
X		/* see if we have a shell command */
X		if (isspace(*input))
X		{
X			if (ntargs == 0)
X				terror(1, "rules must be after target");
X	got_shell:
X			if (nshell == smax)
X			{
X				shells = (shellptr *)
X					grow_list((char **) shells, &smax);
X			}
X			shells[nshell++] = add_shell(ip);
X			continue;
X		}
X
X		/* not a shell line, so must be a target or a macro */
X		if (ntargs != 0)
X		{
X			/* link previous preq's and shell's */
X			targs[ntargs] = NULL;
X			preqs[npreqs] = NULL;
X			shells[nshell] = NULL;
X			link_targs(targs, preqs, shells);
X			ntargs = npreqs = nshell = 0;
X		}
X
X		/* don't break out symbols until macro is invoked */
X		if (add_macro(ip, 0))
X			continue;
X
X		/* okay, we have a target line; break out macro symbols */
X		input = breakout(ip);
X
X		/* just look for tokens with standard isspace() separators */
X		ip = token(input, NULL, &schar);
X		while (ip)
X		{
X			colonp = strchr(ip, ':');
X#ifdef	MSDOS
X			/* need to allow c:/bin/make.exe as a target */
X			if (colonp && colonp - ip == 1)
X				colonp = strchr(colonp + 1, ':');
X#endif
X			if (colonp)
X			{
X				/* got a separator */
X				*colonp = '\0';
X
X				/* if at front of token, target is done */
X				if (colonp == ip)
X					break;
X			}
X
X			if (ntargs == tmax)
X				targs = (targptr *) grow_list((char **) targs,
X							      &tmax);
X			targs[ntargs] = add_target(ip);
X
X			/* make sure we don't save .INIT as our 1st target */
X			if (first_targ == NULL && *ip != '.')
X				first_targ = targs[ntargs];
X			++ntargs;
X
X			if (colonp)
X				break;
X			ip = token(NULL, NULL, &schar);
X		}
X
X		/* a target line without a colon?  naughty, naughty! */
X		if (!colonp)
X			terror(-1, "Unexpected end of line seen");
X
X/*
X *		 taking care of four possible cases:
X *			1)	object : source
X *			2)	object: source
X *			3)	object :source
X *			4)	object:source
X */
X
X		if (colonp && *++colonp)
X			ip = colonp;
X		else
X			ip = token(NULL, NULL, &schar);
X
X		/* link the pre-req's */
X		while (ip)
X		{
X			if ((colonp = strchr(ip, ';')) != NULL)
X			{
X				ip[strlen(ip)] = schar;
X				*colonp = '\0';
X			}
X
X			if (*ip)
X			{
X				if (npreqs == pmax)
X				{
X					preqs = (fileptr *)
X						grow_list((char **) preqs,
X							  &pmax);
X				}
X
X				preqs[npreqs++] = add_file(ip);
X			}
X
X			if (colonp)
X			{
X				ip = colonp + 1;
X				goto got_shell;
X			}
X
X			ip = token(NULL, NULL, &schar);
X		}
X
X		/* gotta free the line allocated by breakout() */
X		tfree(input);
X	}
X
X	/* link up any dangling dependants */
X	if (ntargs != 0)
X	{
X		targs[ntargs] = NULL;
X		preqs[npreqs] = NULL;
X		shells[nshell] = NULL;
X		link_targs(targs, preqs, shells);
X	}
X
X	/* clean up our mallocs */
X	tfree(targs);
X	tfree(preqs);
X	tfree(shells);
X
X	fclose(fd);
X	return (1);
X}
X
X
X/*
X * link_targs	- force a list of targs to point to same preq's and shell's
X */
Xlink_targs(targs, preqs, shells)
Xtargptr *targs;
Xfileptr *preqs;
Xshellptr *shells;
X{
X	while (targs && *targs)
X	{
X		/* process some special targets */
X		if ((*targs)->tfile->fname[0] == '.')
X		{
X			if (equal((*targs)->tfile->fname, ".SILENT"))
X				opts.silent = 1;
X			else
X			if (equal((*targs)->tfile->fname, ".IGNORE"))
X				opts.ignore = 1;
X			else
X			if (equal((*targs)->tfile->fname, ".SUFFIXES"))
X				/*
X				 * set `suffix_targ' to speed up
X				 * `default_rule' 
X				 */
X				suffix_targ = *targs;
X
X			/* special rule has preq's reset */
X			/* normally, preq's are merely appended */
X			if (*preqs == NULL && (*targs)->tpreq != NULL)
X			{
X				tfree((*targs)->tpreq);
X				(*targs)->tpreq = NULL;
X			}
X
X			/* special rules have their shell commands replaced */
X			if ((*targs)->tshell != NULL && *shells != NULL)
X			{
X				shellptr *sp;
X
X				for (sp = (*targs)->tshell; *sp; ++sp)
X					tfree(*sp);
X				tfree((*targs)->tshell);
X				(*targs)->tshell = NULL;
X			}
X		}
X
X		/* each target in the list points to the preq's and shell's */
X		(*targs)->tpreq = append_preq((*targs)->tpreq, preqs);
X
X		/* we cannot expand the list of shell commands */
X		if ((*targs)->tshell != NULL && *shells != NULL)
X		{
X			terror(1, tstrcat("Too many rules defined for target ",
X					  (*targs)->tfile->fname));
X		}
X		(*targs)->tshell = append_shell((*targs)->tshell, shells);
X		++targs;
X	}
X}
X
X
X/* macros must have the format: WORD = more stuff
X *			     	WORD= more stuff
X *				WORD =more stuff
X *				WORD=more stuff
X *			or:	WORD += more stuff
X *				WORD +=more stuff
X *
X * it is assumed that there is no leading whitespace in `input'
X */
Xadd_macro(input, scmd)
Xchar   *input;
Xint     scmd;
X{
X	char   *eqsign;
X	char   *value;
X	symptr  symp;
X
X	/* gotta have an '=' to be a macro */
X	eqsign = strchr(input, '=');
X	if (eqsign == NULL)
X		return (0);
X
X	/* make sure we catch imbedded '='s (e.g. MACRO=STUFF) */
X	for (value = input; *value && !isspace(*value); ++value);
X	if (value > eqsign)
X		value = eqsign;
X
X	/* terminate the macro name */
X	*value = '\0';
X
X	/* find start of value */
X	for (value = eqsign + 1; isspace(*value); ++value);
X
X	/* look for concat character */
X	--eqsign;
X
X	if (eqsign < input || (eqsign == input && *eqsign == '+'))
X		terror(1, "Badly formed macro");
X
X	if (*eqsign == '+')
X	{
X		/* append to the current macro definition */
X		*eqsign = '\0';
X		symp = get_symbol(input, scmd);
X		if (symp->scmd && !scmd)
X			return (1);
X		if (symp->slevel < make_level)
X			symp = dup_symbol(symp, symp->svalue);
X		if (symp->svalue)
X		{
X			eqsign = tstrcat(symp->svalue, " ");
X			value = tstrcat(eqsign, value);
X			tfree(eqsign);
X			tfree(symp->svalue);
X			symp->svalue = value;
X			return (1);
X		}
X	}
X
X	add_symbol(input, value, scmd);
X	return (1);
X}
X
X
X/*
X * add_symbol	- add a <name,value> pair to the symbol table
X *		- override existing symbol value
X *		- mark as either command-line macro or not
X */
Xadd_symbol(name, value, scmd)
Xchar   *name;
Xchar   *value;
Xint     scmd;
X{
X	symptr  symp;
X
X	symp = get_symbol(name, scmd);
X	if (symp->scmd & !scmd)
X		return;
X	if (symp->slevel < make_level)
X		symp = dup_symbol(symp, NULL);	/* don't dup the value */
X	if (symp->svalue)
X		tfree(symp->svalue);
X	symp->svalue = tstrcpy(value);
X	symp->scmd = scmd;
X}
X
X
X/*
X * get_symbol	- find a symbol in the symbol table
X *		- if non-extant, create <name,NULL>
X *		- return created or found symbol node
X */
Xsymptr  get_symbol(name, scmd)
Xchar   *name;
Xint     scmd;
X{
X	symptr  symp;
X	t_mask  mask;
X	char   *np;
X
X	/* use `mask' to screen out most string comparisons */
X	mask = 0;
X	np = name;
X	while (*np)
X		mask += *np++;
X
X	/* linear search through symbol list */
X	for (symp = symbol_list; symp != NULL; symp = symp->snext)
X	{
X		if (mask != symp->smask)
X			continue;
X
X		if (equal(name, symp->sname))
X			return (symp);
X	}
X
X	symp = tnew(symnode);	/* allocate symbol node */
X	symp->smask = mask;	/* record mask for later */
X	symp->sname = tstrcpy(name);	/* allocate string and copy name */
X	symp->scmd = scmd;	/* command line macro? */
X	symp->slevel = make_level;	/* current new_make() level */
X
X	/* get the value from the environment, if it is there */
X
X	if ((symp->svalue = getenv(name)) != NULL)
X	{
X		symp->svalue = tstrcpy(symp->svalue);
X
X		/*
X		 * if `-e', let command line macros override, but not macro
X		 * assignments in the makefile. 
X		 */
X		if (opts.envirn)
X			symp->scmd = 1;
X	}
X
X	symp->snext = symbol_list;	/* link to head of symbol list */
X	symbol_list = symp;
X
X	return (symp);
X}
X
X
X/*
X * dup_sym	- duplicate a symbol node, but at current new_make() level
X */
Xsymptr  dup_symbol(symp, value)
Xsymptr  symp;
Xchar   *value;
X{
X	symptr  nsp;
X
X	nsp = tnew(symnode);	/* allocate symbol node */
X	nsp->smask = symp->smask;	/* record mask for later */
X	nsp->sname = tstrcpy(symp->sname);	/* allocate string and copy
X						 * name */
X	nsp->svalue = (value == NULL) ? NULL : tstrcpy(value);
X	nsp->scmd = symp->scmd;	/* command line macro? */
X	nsp->slevel = make_level;	/* current new_make() level */
X
X	nsp->snext = symbol_list;	/* link to head of symbol list */
X	symbol_list = nsp;
X
X	return (nsp);
X}
X
X
X/*
X * add_target	- return extant target node, or create new one
X */
Xtargptr add_target(name)
Xchar   *name;
X{
X	t_mask  mask;
X	targptr targp;
X	fileptr filep;
X
X	/* each target must have a file node */
X	filep = add_file(name);
X
X	/* see if target already exists */
X	targp = hash_target(name, &mask);
X	if (targp)
X		return (targp);
X
X	/* oh well, gotta create one */
X	targp = tnew(targnode);	/* allocate a target node */
X	targp->tmask = mask;	/* save mask for later */
X	targp->tfile = filep;	/* save pointer to file node */
X	targp->tpreq = NULL;	/* no pre-req's yet */
X	targp->tshell = NULL;	/* no shell lines yet */
X
X	targp->tnext = target_list;	/* link to front of target list */
X	target_list = targp;
X
X	return (targp);
X}
X
X
X/*
X * hash_target	- look up target (by name) in target list
X *		- return target node or NULL
X *		- if requested, also return the mask
X */
Xtargptr hash_target(name, maskp)
Xchar   *name;
Xt_mask *maskp;
X{
X	targptr targp;
X	t_mask  mask;
X	char   *np;
X
X	/* use `mask' to screen out most string comparisons */
X	mask = 0;
X	np = name;
X	while (*np)
X		mask += *np++;
X
X	/* see if we gotta return it */
X	if (maskp != NULL)
X		*maskp = mask;
X
X	/* linear search through target list */
X	for (targp = target_list; targp != NULL; targp = targp->tnext)
X	{
X		if (mask != targp->tmask)
X			continue;
X
X		/* target name is ONLY stored in the file node */
X		if (equal(name, targp->tfile->fname))
X			return (targp);
X	}
X
X	/* nope, no target here */
X	return (NULL);
X}
X
X
X/*
X * add_file	- return a found or created file node
X */
Xfileptr add_file(name)
Xchar   *name;
X{
X	t_mask  mask;
X	fileptr filep;
X
X	/* see if file node already exists */
X	filep = hash_file(name, &mask);
X	if (filep)
X		return (filep);
X
X	filep = tnew(filenode);	/* allocate new file node */
X	filep->fmask = mask;	/* save mask for later */
X	filep->fname = tstrcpy(name);	/* allocate string and copy name */
X	filep->ftime = MAXNEGTIME;	/* init MODIFY time to long time ago */
X
X	filep->fnext = file_list;	/* link to head of file list */
X	file_list = filep;
X
X	return (filep);
X}
X
X
X/*
X * hash_file	- look up file (by name) in file list
X *		- return file node or NULL
X *		- if requested, also return the mask
X */
Xfileptr hash_file(name, maskp)
Xchar   *name;
Xt_mask *maskp;
X{
X	fileptr filep;
X	t_mask  mask;
X	char   *np;
X
X	/* use `mask' to screen out most string comparisons */
X	mask = 0;
X	np = name;
X	while (*np)
X		mask += *np++;
X
X	/* see if we gotta return it */
X	if (maskp != NULL)
X		*maskp = mask;
X
X	/* linear search through file list */
X	for (filep = file_list; filep != NULL; filep = filep->fnext)
X	{
X		if (filep->fmask != mask)
X			continue;
X
X		if (equal(filep->fname, name))
X			return (filep);
X	}
X
X	/* nope, no file here */
X	return (NULL);
X}
X
X
X/*
X * append_node	- add a node to the end of an array of nodes
X */
Xchar  **append_node(node, adds, size)
Xchar  **node;
Xchar  **adds;
Xint     size;
X{
X	int     addlen, len;
X
X	for (addlen = 0; adds[addlen] != NULL; ++addlen);
X	if (addlen++ == 0)
X		return (node);
X
X	len = 0;
X
X	if (node != NULL)
X	{
X		for (; node[len] != NULL; ++len);
X		node = (char **) trealloc((char *) node, (len + addlen) * size);
X	}
X	else
X		node = (char **) talloc(addlen * size);
X
X	memcpy(node + len, adds, addlen * size);
X	return (node);
X}
X
X/*
X * add_shell	- create a new shell node, and add to end of given list
X */
Xshellptr add_shell(input)
Xchar   *input;
X{
X	shellptr snode;
X
X	snode = tnew(shellnode);/* allocate a new shell node */
X	snode->s_shell = snode->s_ignore = snode->s_silent = 0;
X
X	for (; isspace(*input); ++input);	/* skip over leading spaces */
X	for (;; ++input)
X	{
X		if (*input == '+')
X			snode->s_shell = 1;	/* must use command.com */
X		else
X		if (*input == '-')
X			snode->s_ignore = 1;	/* ignore return value */
X		else
X		if (*input == '@')
X			snode->s_silent = 1;	/* don't echo command */
X		else
X			break;
X	}
X
X	snode->scmd = tstrcpy(input);	/* allocate string and copy command */
X
X	snode->slink = shell_list;	/* attach to global list */
X	shell_list = snode;
X
X	return (snode);
X}
X
X
X/*
X * breakout	- replace macro names with values
X *		- apply recursively
X * note: allocates (and returns) a string which must be freed
X */
Xchar   *breakout(input)
Xchar   *input;
X{
X	char   *dest, *dend;
X	char   *dp;
X	int     dlen;
X	int     tlen;
X	int     state;
X	char    symname[100];
X	char   *sp;
X	symptr  symp;
X	int     slen;
X	char    endch;
X
X	/* allocate a string twice as long as input string */
X
X	dlen = strlen(input) * 2;
X	dest = dp = talloc(dlen);
X	dend = dest + dlen;
X
X/*
X *	 state machine with 4 states
X *		0)	normal text	-- just copy
X *		1)	starting macro	-- define end char (e.g. ')', '}')
X *		2)	macro name	-- copy to a buffer
X *		3)	end of macro	-- look up value, and copy
X */
X	state = 0;
X
X	while (*input || state == 3)
X	{
X		/* if we don't have enough room, double size of string */
X		if (dp == dend)
X		{
X			dlen *= 2;
X			tlen = dp - dest;
X			dest = trealloc(dest, dlen);
X			dp = dest + tlen;
X			dend = dest + dlen;
X		}
X
X		switch (state)
X		{
X		case 0:
X			if (*input == '$')
X				state = 1;	/* found a macro */
X			else
X				*dp++ = *input++;
X			break;
X
X		case 1:
X			state = 2;	/* only in this state for 1 char */
X			sp = symname;
X			switch (*++input)
X			{
X			case '$':
X				*dp++ = '$';
X				state = 0;
X				break;
X			case '(':
X				endch = ')';
X				break;
X			case '{':
X				endch = '}';
X				break;
X			default:
X				/* single char; go to state 3 immediately */
X				*sp++ = *input;
X				state = 3;
X				break;
X			}
X			++input;/* skip bracket (or character) */
X			break;
X
X		case 2:
X			if (*input == endch)
X				state = 3;
X			else
X				*sp++ = *input;
X
X			if ((sp - symname) >= (sizeof symname / sizeof symname[0]))
X			{
X				sp[-1] = '\0';
X				terror(1,
X				tstrcat("Macro too long (limit 100 chars): ",
X					symname));
X			}
X
X			++input;/* make sure we skip end char */
X			break;
X
X		case 3:
X			*sp = '\0';
X			symp = get_symbol(symname, 0);
X			sp = symp->svalue;
X			slen = -1;
X			while (sp && *sp)
X			{
X				/*
X				 * if value has a macro in it, we must
X				 * process recursively 
X				 */
X				if (*sp == '$')
X				{
X					sp = breakout(symp->svalue);
X					/* now guaranteed not to have a '$' */
X					slen = strlen(sp);
X					break;
X				}
X				++sp;
X			}
X
X			if (slen == -1)
X			{
X				/* value did NOT have a macro */
X				slen = (sp - symp->svalue);
X				sp = symp->svalue;
X			}
X
X			/* if we have not enough room, expand */
X			if (slen >= (dend - dp))
X			{
X				/* use slen to make sure that we can fit */
X				dlen = dlen * 2 + slen;
X				tlen = dp - dest;
X				dest = trealloc(dest, dlen);
X				dp = dest + tlen;
X				dend = dest + dlen;
X			}
X
X			/* if length is zero, don't bother to copy */
X			if (slen)
X			{
X				strcpy(dp, sp);
X				dp += slen;
X			}
X
X			if (sp != symp->svalue)
X				tfree(sp);	/* must've called `breakout' */
X
X			state = 0;	/* and we are back to text */
X			break;
X		}
X	}
X
X	if (state != 0)
X		terror(1, tstrcat("Improper macro.\n", dest));
X
X	*dp = '\0';		/* terminate the string */
X	return (dest);		/* and return it */
X}
END_OF_FILE
if test 17139 -ne `wc -c <'parse.c'`; then
    echo shar: \"'parse.c'\" unpacked with wrong size!
fi
# end of 'parse.c'
fi
if test -f 'tstring.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tstring.c'\"
else
echo shar: Extracting \"'tstring.c'\" \(5480 characters\)
sed "s/^X//" >'tstring.c' <<'END_OF_FILE'
X/*
X * tstring.c
X *
X * 88-10-01 v1.0	created by greg yachuk, placed in the public domain
X * 88-10-06 v1.1	changed prerequisite list handling
X * 88-11-11 v1.2	fixed some bugs and added environment variables
X * 89-07-12 v1.3	stop appending shell commands, and flush output
X * 89-08-01 v1.4 AB	lots of new options and code
X * 89-10-30 v1.5	-f -S -q options, took some changes from v1.4
X * 90-04-18 v1.6	-b -- -W options, emulate <<, non-BSD cleanup
X */
X#include <stdio.h>
X#include <ctype.h>
X#include <malloc.h>
X#include <string.h>
X
X#include "tstring.h"
X
X
Xchar   *talloc(n)
Xint     n;
X{
X	char   *s;
X
X	s = malloc(n);
X	if (s == NULL)
X		terror(1, "no free memory");
X	return (s);
X}
X
X
Xchar   *trealloc(s, n)
Xchar   *s;
Xint     n;
X{
X	s = realloc(s, n);
X	if (s == NULL)
X		talloc(n);	/* force an error */
X	return (s);
X}
X
X
Xchar   *tstrncpy(s, n)
Xchar   *s;
Xint     n;
X{
X	s = strncpy(talloc(n + 1), s, n);
X	s[n] = '\0';
X	return (s);
X}
X
X
Xterror(n, s)
Xint     n;
Xchar   *s;
X{
X	fputs("Make: ", stderr);
X	fputs(s, stderr);
X	putc('\n', stderr);
X	if (n)
X		exit(n);
X}
X
X
X/*
X * tstrspan -	move to the end of a quoted string, ignoring escaped quotes
X */
Xchar   *tstrspan(str)
Xchar   *str;
X{
X	char    quote;
X
X	if (*str != '\'' && *str != '"')
X		return (str + 1);
X
X	quote = *str++;
X
X	while (*str && *str != quote)
X	{
X		/* check for escaped quote */
X		if (*str == '\\' && str[1] == quote)
X			++str;
X		++str;
X	}
X
X	return (str);
X}
X
X
X/*
X * tunquote -	remove quotes from a string
X */
Xchar   *tunquote(str)
Xchar   *str;
X{
X	char   *s;
X	char   *d;
X
X	d = s = str;
X
X	while (*s)
X	{
X		while (*s && *s == '"')
X			++s;
X
X		while (*s && *s != '"')
X			*d++ = *s++;
X	}
X
X	*d = '\0';
X
X	return (str);
X}
X
X
X/*
X * tsplit -	split a string into two components, normally a directory
X *		path and a filename.  If a pointer to a directory is
X *		supplied, a string is allocated to contain the directory.
X *		The filename is returned as a pointer into the supplied
X *		string.
X */
Xchar   *tsplit(s, seps, dp)
Xchar   *s;
Xchar   *seps;
Xchar  **dp;
X{
X	char   *d;		/* directory portion */
X	char   *f;		/* file portion */
X
X	d = s;
X
X	/* find the final separator */
X	while ((f = strpbrk(d, seps)) != NULL)
X		d = f + 1;
X
X	/* back up to final component */
X	f = d;
X
X	/* if we are still at the beginning, there was no Directory */
X	if (d == s || dp == NULL)
X		d = NULL;
X	else
X	{
X		int     len;
X
X		/*
X		 * by the time we get here, d points to the final separator
X		 * char.  we can substitute a NULL for this sep-char.  Thus,
X		 * we don't need to add 1 in the following length
X		 * calculation. 
X		 */
X		len = d - s;
X
X		d = talloc(len);
X		d[--len] = '\0';
X		while (--len >= 0)
X			d[len] = s[len];
X	}
X
X	if (dp != NULL)
X		*dp = d;
X
X	return (f);
X}
X
X
X/*
X * token	- take an input string and return a token each call
X *		- default token delimiter characters are `isspace()'
X *		- separator chars are in addition to `isspace()'
X *		- text between quotes (" and ') is a single token
X *		- if requested, the separator char is returned
X *
X *	called as	s = token(string, seps, &schar);
X *		or	s = token(string, NULL, NULL);
X *
X *	followed by	s = token(NULL, seps, NULL);
X *		or	s = token(NULL, NULL, &schar);
X *
X *	returns NULL when no more tokens are available
X */
Xchar   *token(s, sep, schar)
Xchar   *s;
Xchar   *sep;
Xchar   *schar;
X{
X	static char *olds = NULL;
X
X	if (s)
X		olds = s;	/* we are starting all over again */
X
X	if (schar)
X		*schar = '\0';
X
X	if (!olds || !*olds)
X		return (NULL);	/* no tokens left */
X
X	while (isspace(*olds) || (sep && strchr(sep, *olds)))
X		++olds;		/* skip leading spaces and sep's */
X
X	if (*olds == NULL)
X		return (NULL);	/* remainder is all separator's */
X
X	s = olds;
X
X	while (*olds)
X	{
X		if (isspace(*olds) || (sep && strchr(sep, *olds)))
X		{
X			if (schar)
X				*schar = *olds;
X			*olds++ = '\0';	/* delimit the token */
X			return (s);
X		}
X		else
X		if (*olds == '"' || *olds == '\'')
X		{
X			olds = tstrspan(olds);
X			if (*olds != '\0')
X				++olds;	/* didn't hit eos, so skip quote */
X		}
X		else
X			++olds;	/* otherwise, pass over char */
X	}
X
X	olds = NULL;
X	return (s);		/* return last token */
X}
X
X
X/*
X * tokenize	- chop a string up into an array of (char *)'s
X */
Xchar  **tokenize(input)
Xchar   *input;
X{
X	char  **argv;
X	int     argc = 0;
X	int     alen;
X
X	alen = 20;		/* good initial guess */
X	argv = (char **) talloc((alen + 1) * sizeof(char *));
X
X	input = token(input, NULL, NULL);	/* use default separators */
X	while (input)
X	{
X		if (alen == argc)
X			argv = (char **) trealloc((char *) argv,
X					     (alen <<= 1) * sizeof(char *));
X		argv[argc++] = input;
X		input = token(NULL, NULL, NULL);
X	}
X
X	argv[argc] = NULL;	/* mark end of array */
X
X	return (argv);
X}
X
X
X/*
X * tgets	- read input, swallowing escaped newlines as necessary
X */
Xchar   *tgets(fd)
XFILE   *fd;
X{
X	static char *input = NULL;
X	static int inlen = 0;
X	char   *ep;
X	int     len;
X
X	if (inlen == 0)
X		input = talloc(inlen = 162);
X
X	input[inlen - 2] = '\n';
X	ep = input - 1;
X	while ((fgets(input, inlen, fd)) != NULL)
X	{
X		for (;;)
X		{
X			while (input[inlen - 2] != '\n' && input[inlen - 2] != '\0')
X			{
X				len = inlen;
X				input = trealloc(input, inlen <<= 1);
X				ep = &input[len - 2];
X				input[inlen - 2] = '\n';
X				fgets(ep + 1, len + 1, fd);
X			}
X
X			while (*++ep);
X			*--ep = '\0';
X			do
X			{
X				--ep;
X			} while (ep >= input && isspace(*ep));
X
X			if (ep > input && *ep == '\\' && *--ep != '\\')
X				fgets(ep + 1, inlen - (ep - input) - 1, fd);
X			else
X				break;
X		}
X
X		return (input);
X	}
X
X	inlen = 0;
X	tfree(input);
X	input = NULL;
X
X	return (NULL);
X}
END_OF_FILE
if test 5480 -ne `wc -c <'tstring.c'`; then
    echo shar: \"'tstring.c'\" unpacked with wrong size!
fi
# end of 'tstring.c'
fi
if test -f 'tstring.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tstring.h'\"
else
echo shar: Extracting \"'tstring.h'\" \(1310 characters\)
sed "s/^X//" >'tstring.h' <<'END_OF_FILE'
X/*
X * tstring.h
X *
X * 88-10-01 v1.0	created by greg yachuk, placed in the public domain
X * 88-10-06 v1.1	changed prerequisite list handling
X * 88-11-11 v1.2	fixed some bugs and added environment variables
X * 89-07-12 v1.3	stop appending shell commands, and flush output
X * 89-08-01 v1.4 AB	lots of new options and code
X * 89-10-30 v1.5	-f -S -q options, took some changes from v1.4
X * 90-04-18 v1.6	-b -- -W options, emulate <<, non-BSD cleanup
X */
X#define	tnew(t)		((t *) talloc(sizeof(t)))
X#define	tfree(t)	(free((char *) t))
X
X#define	tstrcat(s,p)	(strcat(strcpy(talloc(strlen(s)+strlen(p)+1),(s)),(p)))
X#define	tstrcpy(s)	(strcpy(talloc(strlen(s)+1), (s)))
X
X#ifdef	__STDC__
Xextern char *talloc(int n);
Xextern char *trealloc(char *s, int n);
Xextern char *tstrncpy(char *s, int n);
Xextern int terror(int n, char *s);
Xextern char *tstrspan(char *str);
Xextern char *tunquote(char *str);
Xextern char *tsplit(char *s, char *seps, char **dp);
Xextern char *token(char *s, char *sep, char *schar);
Xextern char **tokenize(char *input);
Xextern char *tgets(FILE * fd);
X#else
Xextern char *talloc();
Xextern char *trealloc();
Xextern char *tstrncpy();
Xextern int terror();
Xextern char *tstrspan();
Xextern char *tunquote();
Xextern char *tsplit();
Xextern char *token();
Xextern char **tokenize();
Xextern char *tgets();
X#endif
END_OF_FILE
if test 1310 -ne `wc -c <'tstring.h'`; then
    echo shar: \"'tstring.h'\" unpacked with wrong size!
fi
# end of 'tstring.h'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0