[comp.sources.amiga] v90i020: make - a re-implementation of the UNIX make utility, Part01/02

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (01/18/90)

Submitted-by: Olaf 'Rhialto' Seibert <U211344@HNYKUN11.BITNET>
Posting-number: Volume 90, Issue 020
Archive-name: unix/make/part01

- A modified Make, the ubiquitous (sp?) one, with some bugs removed
  as reported in comp.os.minix, and an extra sourcefile searching
  feature. May also be useful when compiling NetHack 3.0.

Freely_Distributable=Greetings(Not_For_Any_Commercial_Purpose)->
        Olaf.Seibert;

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  Makefile README README.amiga an check.c h.h input.c
#   macro.c main.c make.n reader.c rules.c
# Wrapped by tadguy@xanth on Wed Jan 17 18:16:22 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(230 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile for make (Amiga Aztec version for use with PDC)
X
XCFLAGS=-Damiga #-Dpdc
XCC=cc
X
XOBJS = main.o make.o rules.o reader.o \
X       input.o macro.o check.o
X
Xm:	$(OBJS)
X	ln -o m $(OBJS) -lc
X
Xdf0:test:df1:test
Xtest1:file1 file2
END_OF_FILE
if test 230 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1803 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XFollowing is a repost of the public domain 'make' that I posted
Xto net.sources a couple of months ago.  I have fixed a few bugs, and
Xadded some more features, and the resulting changes amounted to
Xabout as much text as the whole program (hence the repost).
X
XFor those that missed the net.sources posting, this is a public domain
Xre-implementation of the UNIX make program.  There is no manual included;
Xfor documentation, refer to a UNIX manual, or the source.
X
XHere is a list of the changes made:
X
Xi)	If '-' (ignore) or '@' (silent) where used at the start
X	of a command, their effect was not turned off for the following
X	commands.
Xii)	A special target (.SUFFIXES, .PRECIOUS) or a rule (.c.o, .a.o),
X	if first in the file would be taken as the default target.
X	This resulted in error messages like "Don't know how to
X	make .c", because things like .SUFFIXES were being made.
X	This was further complicated by ---
Xiii)	Special target lines with no dependents (ie. .SUFFIXES:\n)
X	were not clearing out the existing dependents like
X	they should.
Xiv)	Default rules could not be redefined because of the error
X	checking for commands being defined twice.  Now you are
X	allowed to define a target beinging with '.', having
X	no dependents with commands.
Xv)	The -q option didn't do the time comparison correctly,
X	or clear the variable used to keep track of this.  Thus
X	it didn't work very well.
Xvi)	The syntax ${..} for macro's supported by UNIX make was
X	not supported.
Xvii)	There wuz a couple of spelling errors.
Xviii)	When make checked for implicit rules on targets without
X	a suffix, there were problems.  (Note: The ~ feature of
X	UNIX make wasn't and still isn't supported)
Xix)	The -n option did not print @ lines like it was supposed to.
Xx)	:: added.  (See UNIX manual)
Xxi)	$? added.  (see UNIX manual)
END_OF_FILE
if test 1803 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'README.amiga' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README.amiga'\"
else
echo shar: Extracting \"'README.amiga'\" \(4397 characters\)
sed "s/^X//" >'README.amiga' <<'END_OF_FILE'
XThis program is the public domain Make program which appeared on
Xmod.sources, Volume 7, number 91.  I have ported it to the Amiga under
XManx Aztec C version 3.40a.  This short document assumes you know
XMake, and simply points out the Amiga specific features of the
Xprogram.  The supported switches are listed in the comment block at
Xthe beginning of module main.c.  I offer no apologies for the fact that
XI ran the code through "indent -i4 -nfc1" on the 4.3BSD system at work
Xbefore I started working on it.
X   The program has been compiled under Manx Aztec C Version 3.40.
XIt uses Manx's fexecv() function to execute commands and get
Xtheir return value, and the Manx dos_packet() function to send an
XAmigaDOS packet to the file system for touch'ing purposes.  Lattice
Xrecompilers need to change these (at least).  Peculiar features
Xof the Amiga version are:
X
X(1) The Amiga-specific sections of the code are #ifdef'd on the symbol
X    amiga (note the lower case).  I endorse Fred Fish's effort to
X    have system and compiler-supplied #define's in lower case to
X    ensure no collisions with user-supplied ones.
X(2) The file rules.c, routine makerules(), contains the definitions of
X    the default built-in rules. For the Amiga, these are equivalent to
X    the Makefile:
X
X	CC = cc
X	CFLAGS =
X	AS = as
X	AFLAGS =
X
X	.c.o:
X		$(CC) $(CFLAGS) $<
X	.s.o:
X		$(AS) $(AFLAGS) -o $@ $<
X
X    (indented for clarity only).  Thus, one could conceivably do:
X	make CC=lc CFLAGS= AS=asm
X    to run this make under Lattice C.
X(3) If the file S:builtins.make exists, its contents are read in
X    instead of the built-in rules defined in makerules().  Thus, you
X    can use different default rules on different disks and change
X    the default rules without recompiling make.
X(4) A Control-D typed during execution of a command by make will cause
X    an abort with exit status 1 AFTER the completion of that command.
X    Control-C is an immediate abort, as you might expect.
X(5) Not really Amiga specific, but worth mentioning, is that characters
X    special both to the local operating system (such as : in AmigaDOS) and
X    to make may be used in the makefile by preceding them with \
X    to temporarily override their special meaning.  For example, to tell
X    make that RAM:foo depends on AC:foo.c, write:
X
X	RAM\:foo : AC\:foo.c
X
X(6) The Aztec fexecv() function, which is used by make to execute its
X    commands, only works on programs in directories stored along the
X    AmigaDOS PATH, so make sure your PATH includes the appropriate
X    directories.
X
X    Finally, I added one new feature in the non-machine-specific code:
Xthe name of the makefile can be a single dash "-", in which case a
Xmakefile is read from the standard input.
X    About the only feature of "real" make missing here is the
Xsemicolon construct which allows a pair of lines such as the .c.o:
Xrule and command above to be written as one line, viz:
X	.c.o: ; $(CC) $(CFLAGS) $<
X
XEnjoy!	Bug reports in the Amiga-specific stuff should be directed to
Xme;  others should go to caret@fairlight.OZ, the author of the rest of it.
XBy the way, this code is superior to the Manx-supplied make--more switches
Xand a better parser;  in fact, this make will handle the Makefile for
XMicroGnuEmacs while Manx make chokes on the ln command.
X
X				Steve Walton
X				ametek!walton@csvax.caltech.edu (ARPA)
X				WALTON@CALTECH (BITNET)
X				...!ucbvax!sun!megatest!ametek!walton
X
XSome notes by Olaf Seibert, KosmoSoft:
X
XI adapted this version of make to PDC, and enhanced it a little. In
Xparticular, if a line end with a backslash, the following newline and
Xleading white space of the next line are now ignored. Previously, the
Xnewline was merely turned into a space. Also, comparison of filenames now
Xis case-insignificant. Makefiles need not be internally consistent in the
Xcase of filenames. Also, the builtin rules are slightly different, for use
Xwith PDC.
X
X	CC = ccx -c
X	CFLAGS =
X	AS = ccx -c
X	AFLAGS =
X
X	.c.o:
X		$(CC) $(CFLAGS) $<
X	.s.o:
X		$(AS) $(AFLAGS) $<
X
X				/*OIS*0.80*/
X
XI took out the \: feature, which worked only in target names, and not in
Xprerequisite files. Instead, I added a more rational interpretation of
Xcolons. There is now at most one colon possible in a target name, which may
Xnot contain any spaces.
X
XI incorporared a few bug fixes relating to $< and $*, from the minix newsgroup.
XI added a new feature: the .PATH special target. See manual.
X
END_OF_FILE
if test 4397 -ne `wc -c <'README.amiga'`; then
    echo shar: \"'README.amiga'\" unpacked with wrong size!
fi
# end of 'README.amiga'
fi
if test -f 'an' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'an'\"
else
echo shar: Extracting \"'an'\" \(2210 characters\)
sed "s/^X//" >'an' <<'END_OF_FILE'
X.*
X.*	Macro package for NRO in KosmoSoft version
X.*
X.nr h 5 	 @" header indent
X.nr i 10	 @" normal text indent
X.nr s @ni-@nh	 @" section heading indent (to the LEFT)
X.*
X.de TH
X.in @nh;.rm 80-@nh;.he |$0($1)|$2|$0($1)|
X.fo |$3|-#-|$4|
X.in @ni;.rm 80-@ni
X.ta +0 +5
X.en
X.*  Paragraph
X.de PP
X.sp 1;.ne 2;.ti +5
X.en
X.*  Bulleted Paragraph. Needs .RE after last para.
X.*  Must be last on line. Relies on first tab stop.
X.de BP
X.br;.in @ni+5;.ti -3;o@t@@
X.en
X.*  Section Heading
X.de SH
X.sp 1;.ne 3;.ti -@@ns;.bo "$0 $1 $2 $3 $4 $6 $6 $7 $8 $9
X.br
X.en
X.*  SubSection
X.de SS
X.br;.ne 2;.ti -@@ns+1/2;$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
X.br
X.en
X.*  Relative indent Start
X.de RS
X.in +0$0
X.en
X.*  Relative indent End
X.de RE
X.in @ni
X.en
X.*  Italics
X.de I
X.it 1
X$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
X.en
X.*  Bold
X.de B
X.bo 1
X$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
X.en
X.*  Underline
X.de U
X.ul 1
X$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
X.en
X.*  UC
X.de UC
X.*  Empty
X.en
X.*  Italics and Roman
X.de IR
X.if !''$0' .it "$0
X.if !''$1' $1
X.if !''$2' .it "$2
X.if !''$3' $3
X.if !''$4' .it "$4
X.if !''$5' $5
X.if !''$6' .it "$6
X.if !''$7' $7
X.if !''$8' .it "$8
X.if !''$9' $9
X.en
X.*  Roman and Italic
X.de RI
X.if !''$0' $0
X.if !''$1' .it "$1
X.if !''$2' $2
X.if !''$3' .it "$3
X.if !''$4' $4
X.if !''$5' .it "$5
X.if !''$6' $6
X.if !''$7' .it "$7
X.if !''$8' $8
X.if !''$9' .it "$9
X.en
X.*  Bold and Roman
X.de BR
X.if !''$0' .bo "$0
X.if !''$1' $1
X.if !''$2' .bo "$2
X.if !''$3' $3
X.if !''$4' .bo "$4
X.if !''$5' $5
X.if !''$6' .bo "$6
X.if !''$7' $7
X.if !''$8' .bo "$8
X.if !''$9' $9
X.en
X.*  Bold and Italic
X.de BI
X.if !''$0' .bo "$0
X.if !''$1' .it "$1
X.if !''$2' .bo "$2
X.if !''$3' .it "$3
X.if !''$4' .bo "$4
X.if !''$5' .it "$5
X.if !''$6' .bo "$6
X.if !''$7' .it "$7
X.if !''$8' .bo "$8
X.if !''$9' .it "$9
X.en
X.*  Italic and Bold
X.de IB
X.if !''$0' .it "$0
X.if !''$1' .bo "$1
X.if !''$2' .it "$2
X.if !''$3' .bo "$3
X.if !''$4' .it "$4
X.if !''$5' .bo "$5
X.if !''$6' .it "$6
X.if !''$7' .bo "$7
X.if !''$8' .it "$8
X.if !''$9' .bo "$9
X.en
X.*  Italic and Roman
X.de IR
X.if !''$0' .it "$0
X.if !''$1' $1
X.if !''$2' .it "$2
X.if !''$3' $3
X.if !''$4' .it "$4
X.if !''$5' $5
X.if !''$6' .it "$6
X.if !''$7' $7
X.if !''$8' .it "$8
X.if !''$9' $9
X.en
X.*  SMall, do nothing
X.de SM
X$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
X.en
END_OF_FILE
if test 2210 -ne `wc -c <'an'`; then
    echo shar: \"'an'\" unpacked with wrong size!
fi
# end of 'an'
fi
if test -f 'check.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'check.c'\"
else
echo shar: Extracting \"'check.c'\" \(2152 characters\)
sed "s/^X//" >'check.c' <<'END_OF_FILE'
X/*
X *	Check structures for make.
X */
X
X#include <stdio.h>
X#include "h.h"
X
X
X/*
X *	Prints out the structures as defined in memory.  Good for check
X *	that you make file does what you want (and for debugging make).
X */
Xvoid
Xprt()
X{
X    register struct name *np;
X    register struct depend *dp;
X    register struct line *lp;
X    register struct cmd *cp;
X    register struct macro *mp;
X
X
X    for (mp = macrohead; mp; mp = mp->m_next)
X	fprintf(stderr, "%s = %s\n", mp->m_name, mp->m_val);
X
X    fputc('\n', stderr);
X
X    for (np = namehead.n_next; np; np = np->n_next) {
X	if (np->n_flag & N_DOUBLE)
X	    fprintf(stderr, "%s::\n", np->n_name);
X	else
X	    fprintf(stderr, "%s:\n", np->n_name);
X	if (np == firstname)
X	    fprintf(stderr, "(MAIN NAME)\n");
X	for (lp = np->n_line; lp; lp = lp->l_next) {
X	    fputc(':', stderr);
X	    for (dp = lp->l_dep; dp; dp = dp->d_next)
X		fprintf(stderr, " %s", dp->d_name->n_name);
X	    fputc('\n', stderr);
X
X	    for (cp = lp->l_cmd; cp; cp = cp->c_next)
X#ifdef os9
X		fprintf(stderr, "-   %s\n", cp->c_cmd);
X#else
X		fprintf(stderr, "-\t%s\n", cp->c_cmd);
X#endif
X	    fputc('\n', stderr);
X	}
X	fputc('\n', stderr);
X    }
X}
X
X
X/*
X *	Recursive routine that does the actual checking.
X */
Xvoid
Xcheck(np)
X    struct name    *np;
X{
X    register struct depend *dp;
X    register struct line *lp;
X
X
X    if (np->n_flag & N_MARK)
X	fatal("Circular dependency from %s", np->n_name);
X
X    np->n_flag |= N_MARK;
X
X    for (lp = np->n_line; lp; lp = lp->l_next)
X	for (dp = lp->l_dep; dp; dp = dp->d_next)
X	    check(dp->d_name);
X
X    np->n_flag &= ~N_MARK;
X}
X
X
X/*
X *	Look for circular dependancies.
X *	ie.
X *		a: b
X *		b: a
X *	is a circular dep
X */
Xvoid
Xcirch()
X{
X    register struct name *np;
X
X
X    for (np = namehead.n_next; np; np = np->n_next)
X	check(np);
X}
X
X
X/*
X *	Check the target .PRECIOUS, and mark its dependentd as precious
X */
Xvoid
Xprecious()
X{
X    register struct depend *dp;
X    register struct line *lp;
X    register struct name *np;
X
X
X    if (!((np = newname(".PRECIOUS"))->n_flag & N_TARG))
X	return;
X
X    for (lp = np->n_line; lp; lp = lp->l_next)
X	for (dp = lp->l_dep; dp; dp = dp->d_next)
X	    dp->d_name->n_flag |= N_PREC;
X}
END_OF_FILE
if test 2152 -ne `wc -c <'check.c'`; then
    echo shar: \"'check.c'\" unpacked with wrong size!
fi
# end of 'check.c'
fi
if test -f 'h.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'h.h'\"
else
echo shar: Extracting \"'h.h'\" \(2546 characters\)
sed "s/^X//" >'h.h' <<'END_OF_FILE'
X/*
X *	Include header for make
X */
X
X
X#ifndef uchar
X#ifdef os9
X#define uchar		char
X#define void		int
X#define fputc		putc
X#else
X#define uchar		unsigned char
X#endif
X#endif
X
X#define bool		uchar
X#define time_t		long
X#define TRUE		(1)
X#define FALSE		(0)
X#define max(a,b)	((a)>(b)?(a):(b))
X
X#define DEFN1		"makefile"      /* Default names  */
X#ifdef unix
X#define DEFN2		"Makefile"
X#endif
X#ifdef eon
X#define DEFN2		"Makefile"
X#endif
X
X#ifdef amiga
X#define strcmp		stricmp
X#endif
X
X/* os9 is case insensitive */
X
X#define LZ		(1024)	/* Line size  */
X
X
X
X/*
X *	A name.  This represents a file, either to be made, or existant
X */
X
Xstruct name {
X    struct name    *n_next;	/* Next in the list of names */
X    char	   *n_name;	/* Called */
X    struct line    *n_line;	/* Dependencies */
X    time_t	    n_time;	/* Modify time of this name */
X    uchar	    n_flag;	/* Info about the name */
X};
X
X#define N_MARK		0x01	/* For cycle check */
X#define N_DONE		0x02	/* Name looked at */
X#define N_TARG		0x04	/* Name is a target */
X#define N_PREC		0x08	/* Target is precious */
X#define N_DOUBLE	0x10	/* Double colon target */
X
X/*
X *	Definition of a target line.
X */
Xstruct line {
X    struct line    *l_next;	/* Next line (for ::) */
X    struct depend  *l_dep;	/* Dependents for this line */
X    struct cmd	   *l_cmd;	/* Commands for this line */
X};
X
X
X/*
X *	List of dependents for a line
X */
Xstruct depend {
X    struct depend  *d_next;	/* Next dependent */
X    struct name    *d_name;	/* Name of dependent */
X};
X
X
X/*
X *	Commands for a line
X */
Xstruct cmd {
X    struct cmd	   *c_next;	/* Next command line */
X    char	   *c_cmd;	/* Command line */
X};
X
X
X/*
X *	Macro storage
X */
Xstruct macro {
X    struct macro   *m_next;	/* Next variable */
X    char	   *m_name;	/* Called ... */
X    char	   *m_val;	/* Its value */
X    uchar	    m_flag;	/* Infinite loop check */
X};
X
Xextern char    *myname;
Xextern struct name namehead;
Xextern struct macro *macrohead;
Xextern struct name *firstname;
Xextern bool	silent;
Xextern bool	ignore;
Xextern bool	rules;
Xextern bool	dotouch;
Xextern bool	quest;
Xextern bool	domake;
Xextern char	str1[];
Xextern char	str2[];
Xextern int	lineno;
X
Xchar	       *fgets();
Xchar	       *index();
Xchar	       *rindex();
Xchar	       *malloc();
Xextern int	errno;
X
Xchar	       *getmacro();
Xstruct macro   *setmacro();
Xvoid		input();
Xvoid		error();
Xvoid		fatal();
Xint		make();
Xstruct name    *newname();
Xstruct depend  *newdep();
Xstruct cmd     *newcmd();
Xvoid		newline();
Xchar	       *suffix();
Xvoid		touch();
Xvoid		makerules();
Xchar	       *gettok();
Xvoid		precious();
END_OF_FILE
if test 2546 -ne `wc -c <'h.h'`; then
    echo shar: \"'h.h'\" unpacked with wrong size!
fi
# end of 'h.h'
fi
if test -f 'input.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'input.c'\"
else
echo shar: Extracting \"'input.c'\" \(7435 characters\)
sed "s/^X//" >'input.c' <<'END_OF_FILE'
X/*
X *	Parse a makefile
X */
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include "h.h"
X
X
Xstruct name	namehead;
Xstruct name    *firstname;
X
Xchar		str1[LZ];	/* General store  */
Xchar		str2[LZ];
X
X
X/*
X *	Intern a name.	Return a pointer to the name struct
X */
Xstruct name    *
Xnewname(name)
X    char	   *name;
X{
X    register struct name *rp;
X    register struct name *rrp;
X    register char  *cp;
X
X
X    for
X	(
X	 rp = namehead.n_next, rrp = &namehead;
X	 rp;
X	 rp = rp->n_next, rrp = rrp->n_next
X	)
X	if (strcmp(name, rp->n_name) == 0)
X	    return rp;
X
X    if ((rp = (struct name *) malloc(sizeof(struct name)))
X	== (struct name *) 0)
X	fatal("No memory for name");
X    rrp->n_next = rp;
X    rp->n_next = (struct name *) 0;
X    if ((cp = malloc((unsigned) strlen(name) + 1)) == (char *) 0)
X	fatal("No memory for name");
X    strcpy(cp, name);
X    rp->n_name = cp;
X    rp->n_line = (struct line *) 0;
X    rp->n_time = (time_t) 0;
X    rp->n_flag = 0;
X
X    return rp;
X}
X
X/*
X *  Delete the last created name.
X */
X
Xdelname(np)
Xstruct name *np;
X{
X    if (namehead.n_next == np) {
X	namehead.n_next = np->n_next;
X	free(np);
X    }
X}
X
X/*
X *	Add a dependant to the end of the supplied list of dependants.
X *	Return the new head pointer for that list.
X */
Xstruct depend  *
Xnewdep(np, dp)
X    struct name    *np;
X    struct depend  *dp;
X{
X    register struct depend *rp;
X    register struct depend *rrp;
X
X
X    if ((rp = (struct depend *) malloc(sizeof(struct depend)))
X	== (struct depend *) 0)
X	fatal("No memory for dependant");
X    rp->d_next = (struct depend *) 0;
X    rp->d_name = np;
X
X    if (dp == (struct depend *) 0)
X	return rp;
X
X    for (rrp = dp; rrp->d_next; rrp = rrp->d_next);
X
X    rrp->d_next = rp;
X
X    return dp;
X}
X
X
X/*
X *	Add a command to the end of the supplied list of commands.
X *	Return the new head pointer for that list.
X */
Xstruct cmd     *
Xnewcmd(str, cp)
X    char	   *str;
X    struct cmd	   *cp;
X{
X    register struct cmd *rp;
X    register struct cmd *rrp;
X    register char  *rcp;
X
X
X    if (rcp = rindex(str, '\n'))
X	*rcp = '\0';            /* Loose newline  */
X
X    while (isspace(*str))
X	str++;
X
X    if (*str == '\0')           /* If nothing left, the exit  */
X	return (struct cmd *) 0;
X
X    if ((rp = (struct cmd *) malloc(sizeof(struct cmd)))
X	== (struct cmd *) 0)
X	fatal("No memory for command");
X    rp->c_next = (struct cmd *) 0;
X    if ((rcp = malloc((unsigned) strlen(str) + 1)) == (char *) 0)
X	fatal("No memory for command");
X    strcpy(rcp, str);
X    rp->c_cmd = rcp;
X
X    if (cp == (struct cmd *) 0)
X	return rp;
X
X    for (rrp = cp; rrp->c_next; rrp = rrp->c_next);
X
X    rrp->c_next = rp;
X
X    return cp;
X}
X
X
X/*
X *	Add a new 'line' of stuff to a target.  This check to see
X *	if commands already exist for the target.  If flag is set,
X *	the line is a double colon target.
X *
X *	Kludges:
X *	i)  If the new name begins with a '.', and there are no dependents,
X *	    then the target must cease to be a target.	This is for .SUFFIXES.
X *	ii) If the new name begins with a '.', with no dependents and has
X *	    commands, then replace the current commands.  This is for
X *	    redefining commands for a default rule.
X *	Neither of these free the space used by dependents or commands,
X *	since they could be used by another target.
X */
Xvoid
Xnewline(np, dp, cp, flag)
X    struct name    *np;
X    struct depend  *dp;
X    struct cmd	   *cp;
X    bool	    flag;
X{
X    bool	    hascmds = FALSE;	/* Target has commands	*/
X    register struct line *rp;
X    register struct line *rrp;
X
X
X    /* Handle the .SUFFIXES case */
X    if (np->n_name[0] == '.' && !dp && !cp) {
X	for (rp = np->n_line; rp; rp = rrp) {
X	    rrp = rp->l_next;
X	    free((char *) rp);
X	}
X	np->n_line = (struct line *) 0;
X	np->n_flag &= ~N_TARG;
X	return;
X    }
X    /* This loop must happen since rrp is used later. */
X    for
X	(
X	 rp = np->n_line, rrp = (struct line *) 0;
X	 rp;
X	 rrp = rp, rp = rp->l_next
X	)
X	if (rp->l_cmd)
X	    hascmds = TRUE;
X
X    if (hascmds && cp && !(np->n_flag & N_DOUBLE))
X	/* Handle the implicit rules redefinition case */
X	if (np->n_name[0] == '.' && dp == (struct depend *) 0) {
X	    np->n_line->l_cmd = cp;
X	    return;
X	} else
X	    error("Commands defined twice for target %s", np->n_name);
X    if (np->n_flag & N_TARG)
X	if (!(np->n_flag & N_DOUBLE) != !flag)  /* like xor */
X	    error("Inconsistent rules for target %s", np->n_name);
X
X    if ((rp = (struct line *) malloc(sizeof(struct line)))
X	== (struct line *) 0)
X	fatal("No memory for line");
X    rp->l_next = (struct line *) 0;
X    rp->l_dep = dp;
X    rp->l_cmd = cp;
X
X    if (rrp)
X	rrp->l_next = rp;
X    else
X	np->n_line = rp;
X
X    np->n_flag |= N_TARG;
X    if (flag)
X	np->n_flag |= N_DOUBLE;
X}
X
X
X/*
X *	Parse input from the makefile, and construct a tree structure
X *	of it.
X */
Xvoid
Xinput(fd)
X    FILE	   *fd;
X{
X    char	   *p;		/* General  */
X    char	   *q;
X    struct name    *np;
X    struct depend  *dp;
X    struct cmd	   *cp;
X    bool	    dbl, getline();
X
X
X    if (getline(str1, fd))      /* Read the first line  */
X	return;
X
X    for (;;) {
X	if (str1[0] == '\t' || str1[0] == ' ')  /* Rules without targets  */
X		error("Rules not allowed here");
X
X	p = str1;
X
X	while (isspace(*p))     /* Find first target  */
X	    p++;
X
X	while (((q = index(p, '=')) != (char *) 0) &&
X	       (p != q) && (q[-1] == '\\')) {   /* Find value */
X	    register char  *a;
X
X	    a = q - 1;		/* Del \ chr; move rest back  */
X	    p = q;
X	    while (*a++ = *q++);
X	}
X
X	if (q != (char *) 0) {
X	    register char  *a;
X
X	    *q++ = '\0';        /* Separate name and val  */
X	    while (isspace(*q))
X		q++;
X	    if (p = rindex(q, '\n'))
X		*p = '\0';
X
X	    p = str1;
X	    if ((a = gettok(&p)) == (char *) 0)
X		error("No macro name");
X
X	    setmacro(a, q);
X
X	    if (getline(str1, fd))
X		return;
X	    continue;
X	}
X	expand(str1);
X	p = str1;
X
X#if 0
X	while (((q = index(p, ':')) != (char *) 0) &&
X	       (p != q) && (q[-1] == '\\')) {   /* Find dependents  */
X	    register char  *a;
X
X	    a = q - 1;		/* Del \ chr; move rest back  */
X	    p = q;
X	    while (*a++ = *q++);
X	}
X#else
X	q = index(p, ':');
X#endif
X
X	if (q == (char *) 0)
X	    error("No targets provided");
X
X	/* Added by OIS to allow at most one : in target names */
X
X	{
X	    register char *a = q;
X
X	    while (*++a) {
X		if (*a == ' ' || *a == '\t') {
X		    /* Found no more colons. Must have been first one. */
X		    break;
X		}
X		if (*a == ':') {
X		    /* Found second colon. This must be the separator. */
X		    if (a != q+1)   /* No double colon */
X			q = a;
X		    break;
X		}
X	    }
X	}
X
X	*q++ = '\0';            /* Separate targets and dependents  */
X
X	if (*q == ':') {        /* Double colon */
X	    dbl = 1;
X	    q++;
X	} else
X	    dbl = 0;
X
X	for (dp = (struct depend *) 0; ((p = gettok(&q)) != (char *) 0);)
X	    /* get list of dep's */
X	{
X	    np = newname(p);    /* Intern name  */
X	    dp = newdep(np, dp);/* Add to dep list */
X	}
X
X	*((q = str1) + strlen(str1) + 1) = '\0';
X	/* Need two nulls for gettok (Remember separation)  */
X
X	cp = (struct cmd *) 0;
X	if (getline(str2, fd) == FALSE) {       /* Get commands  */
X	    while (str2[0] == '\t' || str2[0] == ' ') { /*OIS*0.80*/
X		cp = newcmd(&str2[0], cp);
X		if (getline(str2, fd))
X		    break;
X	    }
X	}
X	while ((p = gettok(&q)) != (char *) 0) {        /* Get list of targ's */
X	    np = newname(p);    /* Intern name  */
X	    newline(np, dp, cp, dbl);
X	    if (!firstname && p[0] != '.')
X		firstname = np;
X	}
X
X	if (feof(fd))           /* EOF?  */
X	    return;
X
X	strcpy(str1, str2);
X    }
X}
END_OF_FILE
if test 7435 -ne `wc -c <'input.c'`; then
    echo shar: \"'input.c'\" unpacked with wrong size!
fi
# end of 'input.c'
fi
if test -f 'macro.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'macro.c'\"
else
echo shar: Extracting \"'macro.c'\" \(2582 characters\)
sed "s/^X//" >'macro.c' <<'END_OF_FILE'
X/*
X *	Macro control for make
X */
X
X
X#include "h.h"
X#undef strcmp	/*OIS*0.80*/
X
Xstruct macro   *macrohead;
X
X
Xstruct macro   *
Xgetmp(name)
X    register char	  *name;
X{
X    register struct macro *rp;
X
X    for (rp = macrohead; rp; rp = rp->m_next)
X	if (strcmp(name, rp->m_name) == 0)
X	    return rp;
X    return (struct macro *) 0;
X}
X
X
Xchar	       *
Xgetmacro(name)
X    char	   *name;
X{
X    struct macro   *mp;
X
X    if (mp = getmp(name))
X	return mp->m_val;
X    else
X	return "";
X}
X
X
Xstruct macro   *
Xsetmacro(name, val)
X    char	   *name;
X    char	   *val;
X{
X    register struct macro *rp;
X    register char  *cp;
X
X
X    /* Replace macro definition if it exists  */
X    for (rp = macrohead; rp; rp = rp->m_next)
X	if (strcmp(name, rp->m_name) == 0) {
X	    free(rp->m_val);	/* Free space from old	*/
X	    break;
X	}
X    if (!rp) {			/* If not defined, allocate space for new  */
X	if ((rp = (struct macro *) malloc(sizeof(struct macro)))
X	    == (struct macro *) 0)
X	    fatal("No memory for macro");
X
X	rp->m_next = macrohead;
X	macrohead = rp;
X	rp->m_flag = FALSE;
X
X	if ((cp = malloc((unsigned) strlen(name) + 1)) == (char *) 0)
X	    fatal("No memory for macro");
X	strcpy(cp, name);
X	rp->m_name = cp;
X    }
X    if ((cp = malloc((unsigned) strlen(val) + 1)) == (char *) 0)
X	fatal("No memory for macro");
X    strcpy(cp, val);		/* Copy in new value  */
X    rp->m_val = cp;
X
X    return rp;
X}
X
X
X/*
X *	Do the dirty work for expand
X */
Xvoid
Xdoexp(to, from, len, buf)
X    char	  **to;
X    char	   *from;
X    int 	   *len;
X    char	   *buf;
X{
X    register char  *rp;
X    register char  *p;
X    register char  *q;
X    register struct macro *mp;
X
X
X    rp = from;
X    p = *to;
X    while (*rp) {
X	if (*rp != '$') {
X	    *p++ = *rp++;
X	    (*len)--;
X	} else {
X	    q = buf;
X	    if (*++rp == '{')
X		while (*++rp && *rp != '}')
X		    *q++ = *rp;
X	    else if (*rp == '(')
X		while (*++rp && *rp != ')')
X		    *q++ = *rp;
X	    else if (!*rp) {
X		*p++ = '$';
X		break;
X	    } else
X		*q++ = *rp;
X	    *q = '\0';
X	    if (*rp)
X		rp++;
X	    if (!(mp = getmp(buf)))
X		mp = setmacro(buf, "");
X	    if (mp->m_flag)
X		fatal("Infinitely recursive macro %s", mp->m_name);
X	    mp->m_flag = TRUE;
X	    *to = p;
X	    doexp(to, mp->m_val, len, buf);
X	    p = *to;
X	    mp->m_flag = FALSE;
X	}
X	if (*len <= 0)
X	    error("Expanded line too long");    /*OIS*0.80*/
X    }
X    *p = '\0';
X    *to = p;
X}
X
X
X/*
X *	Expand any macros in str.
X */
Xvoid
Xexpand(str)
X    char	   *str;
X{
X    static char     a[LZ];
X    static char     b[LZ];
X    char	   *p = str;
X    int 	    len = LZ - 1;
X
X    strcpy(a, str);
X    doexp(&p, a, &len, b);
X}
END_OF_FILE
if test 2582 -ne `wc -c <'macro.c'`; then
    echo shar: \"'macro.c'\" unpacked with wrong size!
fi
# end of 'macro.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(5539 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/*
X *	make [-f makefile] [-ins] [target(s) ...]
X *
X *	(Better than EON mk but not quite as good as UNIX make)
X *
X *	-f makefile name
X *	-i ignore exit status
X *	-n Pretend to make
X *	-p Print all macros & targets
X *	-q Question up-to-dateness of target.  Return exit status 1 if not
X *	-r Don't not use inbuilt rules
X *	-s Make silently
X *	-t Touch files instead of making them
X *	-m Change memory requirements (EON only)
X */
X
X#include <stdio.h>
X#include "h.h"
X
X#ifdef unix
X#include <sys/errno.h>
X#endif
X#ifdef eon
X#include <sys/err.h>
X#endif
X#ifdef os9
X#include <errno.h>
X#endif
X#ifdef amiga
X#include <errno.h>
X#endif
X
X#ifdef eon
X#define MEMSPACE	(16384)
X#endif
X
X
Xchar	       *myname;
Xchar	       *makefile;	/* The make file  */
X#ifdef eon
Xunsigned	memspace = MEMSPACE;
X#endif
X
XFILE	       *ifd;		/* Input file desciptor  */
Xbool		domake = TRUE;	/* Go through the motions option  */
Xbool		ignore = FALSE; /* Ignore exit status option  */
Xbool		silent = FALSE; /* Silent option  */
Xbool		print = FALSE;	/* Print debuging information  */
Xbool		rules = TRUE;	/* Use inbuilt rules  */
Xbool		dotouch = FALSE;/* Touch files instead of making  */
Xbool		quest = FALSE;	/* Question up-to-dateness of file  */
X
X
Xvoid
Xmain(argc, argv)
X    register int    argc;
X    register char **argv;
X{
X    register char  *p;		/* For argument processing  */
X    int 	    estat = 0;	/* For question  */
X    register struct name *np;
X    void	    prt(), circh();
X
X
X    myname = (argc-- < 1) ? "make" : *argv++;
X
X    while ((argc > 0) && (**argv == '-')) {
X	argc--; 		/* One less to process	*/
X	p = *argv++;		/* Now processing this one  */
X
X	while (*++p != '\0') {
X	    switch (*p) {
X	    case 'f':           /* Alternate file name  */
X		if (*++p == '\0') {
X		    if (argc-- <= 0)
X			usage();
X		    p = *argv++;
X		}
X		makefile = p;
X		goto end_of_args;
X#ifdef eon
X	    case 'm':           /* Change space requirements  */
X		if (*++p == '\0') {
X		    if (argc-- <= 0)
X			usage();
X		    p = *argv++;
X		}
X		memspace = atoi(p);
X		goto end_of_args;
X#endif
X	    case 'n':           /* Pretend mode  */
X		domake = FALSE;
X		break;
X	    case 'i':           /* Ignore fault mode  */
X		ignore = TRUE;
X		break;
X	    case 's':           /* Silent about commands  */
X		silent = TRUE;
X		break;
X	    case 'p':
X		print = TRUE;
X		break;
X	    case 'r':
X		rules = FALSE;
X		break;
X	    case 't':
X		dotouch = TRUE;
X		break;
X	    case 'q':
X		quest = TRUE;
X		break;
X	    default:		/* Wrong option  */
X		usage();
X	    }
X	}
Xend_of_args:;
X    }
X
X#ifdef amiga
X    if ((ifd = fopen("s:builtins.make", "r")) != (FILE *) 0) {
X	input(ifd);
X	fclose(ifd);
X    } else
X#endif
X    makerules();
X
X#ifdef eon
X    if (initalloc(memspace) == 0xffff)	/* Must get memory for alloc  */
X	fatal("Cannot initalloc memory");
X#endif
X
X    if (!makefile) {	/* If no file, then use default */
X	if ((ifd = fopen(DEFN1, "r")) == (FILE *) 0)
X#ifdef eon
X	    if (errno != ER_NOTF)
X		fatal("Can't open %s; error %02x", DEFN1, errno);
X#endif
X#ifdef unix
X	if (errno != ENOENT)
X	    fatal("Can't open %s; error %02x", DEFN1, errno);
X#endif
X#ifdef amiga
X	if (errno != ENOENT)
X	    fatal("Can't open %s; error %02x", DEFN1, errno);
X#endif
X#ifdef DEFN2
X	if ((ifd == (FILE *) 0)
X	    && ((ifd = fopen(DEFN2, "r")) == (FILE *) 0))
X	    fatal("Can't open %s", DEFN2);
X#else
X	else
X	    fatal("Can't open %s", DEFN1);
X#endif
X    } else if (strcmp(makefile, "-") == 0)      /* Can use stdin as makefile  */
X	ifd = stdin;
X    else if ((ifd = fopen(makefile, "r")) == (FILE *) 0)
X	fatal("Can't open %s", makefile);
X
X    setmacro("$", "$");
X
X    while (argc && (p = index(*argv, '='))) {
X	char		c;
X
X	c = *p;
X	*p = '\0';
X	setmacro(*argv, p + 1);
X	*p = c;
X
X	argv++;
X	argc--;
X    }
X
X    input(ifd); 		/* Input all the gunga	*/
X    fclose(ifd);		/* Finished with makefile  */
X    lineno = 0; 		/* Any calls to error now print no line
X				 * number */
X
X    if (print)
X	prt();			/* Print out structures  */
X
X    np = newname(".SILENT");
X    if (np->n_flag & N_TARG)
X	silent = TRUE;
X
X    np = newname(".IGNORE");
X    if (np->n_flag & N_TARG)
X	ignore = TRUE;
X
X    precious();
X
X    if (!firstname)
X	fatal("No targets defined");
X
X    circh();			/* Check circles in target definitions	*/
X
X    if (!argc)
X	estat = make(firstname, 0);
X    else
X	while (argc--) {
X	    if (!print && !silent && strcmp(*argv, "love") == 0)
X		printf("Not war!\n");
X	    estat |= make(newname(*argv++), 0);
X	}
X
X    if (quest)
X	exit(estat);
X    else
X	exit(0);
X}
X
X
Xusage()
X{
X    fprintf(stderr, "Usage: %s [-f makefile] [-inpqrst] [macro=val ...] [target(s) ...]\n", myname);
X    exit(1);
X}
X
X
Xvoid
Xfatal(msg, a1, a2, a3, a4, a5, a6)
X    char	   *msg;
X{
X    fprintf(stderr, "%s: ", myname);
X    fprintf(stderr, msg, a1, a2, a3, a4, a5, a6);
X    fputc('\n', stderr);
X    exit(1);
X}
X
X#ifdef amiga	/*OIS*0.80*/
X
X/*
X * The Amiga case-insensitive filing system needs a case-insensitive
X * filename comparison. Since strcmp() in this make is only applied to
X * filenames, we simply replace it.
X * Unfortunately, this also affects .PRECIOUS, .IGNORE, .SUFFIXES and
X * .SILENT. Therefore, we need a hack, but that costs space, so we don't.
X */
X
Xint lower(c)
Xregister unsigned int c;
X{
X    if (c >= 'A' && c <= 'Z')
X	return c - 'A' + 'a';
X
X    return c;
X}
X
Xint stricmp(first, second)	/* Case-insensitive strcmp() */
Xregister unsigned char *first, *second;
X{
X    register int cmp;
X
X    while (!(cmp = lower(*first++) - lower(*second++))) {
X	if (!first[-1]) return 0;
X    }
X
X    return (cmp < 0) ? -1 : 1;
X}
X
X/* Manx and PDC allow you to leave out Workbench code */
X
X_wb_parse(){}
X
X#endif
END_OF_FILE
if test 5539 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'make.n' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'make.n'\"
else
echo shar: Extracting \"'make.n'\" \(7344 characters\)
sed "s/^X//" >'make.n' <<'END_OF_FILE'
X.so an
X.de HP
X.ti -5
X.en
X.TH MAKE 1 "AMIGA Programmer's Manual"
X.SH NAME
Xmake - maintain program groups
X.SH SYNTAX
Xmake [ -f makefile ] [ option ] ... file ...
X.SH DESCRIPTION
X.I Make
Xexecutes commands in
X.I makefile
Xto update one or more target
X.I names. Name
Xis typically a program. If no -f option
Xis present, `makefile' and `Makefile' are tried in order.
XIf
X.I makefile
Xis `-', the standard input is taken. More than one -f option may appear.
X
X.I Make
Xupdates a target if it depends on prerequisite files that have been
Xmodified since the target was last modified, or if the target does not
Xexist.
X
X.I Makefile
Xcontains a sequence of entries that specify dependencies. The first line of
Xan entry is a blank-separated list of targets, then a colon, then a list of
Xprerequisite files. Text following a semicolon, and all following lines
Xthat begin with a tab, are shell commands to be executed to update the
Xtarget. If a name appears on the left of more than one `colon' line, then
Xit depends on all of the names on the right of the colon on those lines,
Xbut only one command sequence may be specified for it. If a name appears on
Xa line with a double colon :: then the command sequence following that line
Xis performed only if the name is out of date with respect to the names to
Xthe right of the double colon, and is not affected by other double colon
Xlines on which that name may appear.
X
XTwo special forms of a name are recognized. A name like
X.I a(b)
Xmeans the file named
X.I b
Xstored in the archive named
X.I a.
XA name like
X.I a((b))
Xmeans the file stored in archive a containing the entry point
X.I b.
X
XSharp and newline surround comments.
X
XThe following makefile says that `pgm' depends on two files `a.o' and
X`b.o', and that they in turn depend on `.c' files and a common file `incl'.
X
X        pgm: a.o b.o
X                cc a.o b.o -lm -o pgm
X        a.o: incl a.c
X                cc -c a.c
X        b.o: incl b.c
X                cc -c b.c
X
X.I Makefile
Xentries of the form
X
X        string1 = string2
X
Xare macro definitions. Subsequent appearances of
X.I $(string1)
Xor
X.I ${string1}
Xare replaced by
X.I string2.
XIf
X.I string1
Xis a single character, the parentheses or braces are optional.
X
X.I Make
Xinfers prerequisites for files for which
X.I makefile
Xgives no construction commands. For example, a `.c' file may be inferred as
Xprerequisite for a `.o' file and be compiled to produce the `.o' file. Thus
Xthe preceding example can be done more briefly:
X
X        pgm: a.o b.o
X                cc a.o b.o -lm -o pgm
X        a.o b.o: incl
X
XPrerequisites are inferred according to selected suffixes listed as the
X`prerequisites' for the special name `.SUFFIXES'; multiple lists
Xaccumulate; an empty list clears what came before. Order is significant;
Xthe first possible name for which both a file and a rule as described in
Xthe next paragraph exist is inferred. The default list is
X
X        .SUFFIXES: .out .o .c .e .r .f .y .l .s .p
X
XThe rule to create a file with suffix
X.I s2
Xthat depends on a similarly named file with suffix
X.I s1
Xis specified as an entry for the `target'
X.I s1s2.
XIn such an entry, the special macro $* stands for the target name with
Xsuffix deleted, $@@ for the full target name, $< for the complete list of
Xprerequisites, and $? for the list of prerequisites that are out of date.
XFor example, a rule for making optimized `.o' files from `.c' files is
X
X        .c.o: ; cc -c -O -o $@@ $*.c
X
XCertain macros are used by the default inference rules to communicate
Xoptional arguments to any resulting compilations. In particular, `CFLAGS'
Xis used for
X.I cc(1)
Xoptions, `FFLAGS' for
X.I f77(1)
Xoptions, `PFLAGS' for
X.I pc(1)
Xoptions, and `LFLAGS' and `YFLAGS' for
X.I lex
Xand
X.I yacc(1)
Xoptions. In addition, the macro `MFLAGS' is filled in with the initial
Xcommand line options supplied to
X.I make.
XThis simplifies maintaining a hierarchy of makefiles as one may then invoke
X.I make
Xon makefiles in subdirectories and pass along useful options such as -k.
X
XCommand lines are executed one at a time, each by its own shell. A line is
Xprinted when it is executed unless the special target `.SILENT' is in
X.I makefile,
Xor the first character of the command is `@@'.
X
XCommands returning nonzero status (see
X.I intro(1))
Xcause
X.I make
Xto terminate unless the special target `.IGNORE' is in
X.I makefile
Xor the command begins with <tab><hyphen>.
X
XInterrupt and quit cause the target to be deleted unless the target is a
Xdirectory or depends on the special name `.PRECIOUS'.
X
XOther options:
X
X.RS +5
X.HP
X-i@tEquivalent to the special entry `.IGNORE:'.
X
X.HP
X-k@tWhen a command returns nonzero status, abandon work on the current
Xentry, but continue on branches that do not depend on the current entry.
X
X.HP
X-n@tTrace and print, but do not execute the commands needed to update the
Xtargets.
X
X.HP
X-t@tTouch, i.e. update the modified date of targets, without executing any
Xcommands.
X
X.HP
X-r@tEquivalent to an initial special entry `.SUFFIXES:' with no list.
X
X.HP
X-s@tEquivalent to the special entry `.SILENT:'.
X
X.HP
X-q@tQuestion up-to-dateness of target. Return exit status 1 if not;
Xotherwise, return 0.
X
X.HP
X-r@tDon't use built-in rules.
X.RE
X.SH FILES
Xmakefile, Makefile
X.SH "SEE ALSO"
Xsh(1), touch(1), f77(1), pc(1)
X.br
XS. I. Feldman
X.I "Make - A Program for Maintaining Computer Programs"
X.SH BUGS
XSome commands return nonzero status inappropriately. Use -i
Xto overcome the difficulty.
XCommands that are directly executed by the shell, notably
X.I cd(1),
Xare ineffectual across newlines in
X.I make.
X.SH "AMIGA VERSION"
XNot all of the above applies to the Amiga version of
X.I make.
XIn particular, the default rules and suffixes are different.
X
XOmissions:
X.br
XLibraries and the related notation are not implemented.
X.br
XThe -k option is not supported.
X.br
XThe `;' construct is not implemented.
X.br
XThe remarks related to
X.I MFLAGS, lex(1), yacc(1), f77(1)
Xand
X.I pc(1)
Xdo not apply.
X.br
X$< and $? are not exactly as specified: $< is ONE prerequisite that is out
Xof date (including path name), and $? is ALL prerequisites (without path
Xnames).
X
XAdditions:
X.br
XIf a file
X.I s:builtins.make
Xexists, this file is used instead of the built-in rules.
X.br
XFilenames are not case-significant. Unfortunately, this also applies to the
Xspecial target names .PRECIOUS, .IGNORE and .SILENT. These can also be
Xspecified as .Precious, or .iGnOrE.
X.br
X.I Cd
Xcommands are effective.
X.br
XComment characters (#) may be escaped with a backslash (\).
X.br
XAt most 1 colon is allowed in a target file name (for including device
Xnames). In that case, the trailing colon must follow the target name
Ximmediately, without any intervening white space. Spaces in the names are
Xnot allowed.
X.br
XA new special target name has been added:
X.it "@.PATH.
XAny prerequisite names for
X.it "@.PATH
Xare used for finding source files for implicit rules. You name one or more
Xdirectories, and if the source file for an implicit rule cannot be found
Xin the current directory, each of the the given pathnames is prepended (in
Xthe order given) to the source name, until the file is found.
X
XFor instance, the Makefile
X
X        .PATH:  src/ include/ src/old
X
X        pgm:    pgm.o
X
Xwill look (according to the .c.o rule) for pgm.c, src/pgm.c, include/pgm.c
Xand src/oldpgm.c, in that order. Of course, due to other implicit rules,
Xother files (with other suffixes) may be tried as well.
END_OF_FILE
if test 7344 -ne `wc -c <'make.n'`; then
    echo shar: \"'make.n'\" unpacked with wrong size!
fi
# end of 'make.n'
fi
if test -f 'reader.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader.c'\"
else
echo shar: Extracting \"'reader.c'\" \(2183 characters\)
sed "s/^X//" >'reader.c' <<'END_OF_FILE'
X/*
X *	Read in makefile
X */
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include "h.h"
X
X
Xint		lineno;
X
X
X/*
X *	Syntax error handler.  Print message, with line number, and exits.
X */
Xvoid
Xerror(msg, a1, a2, a3)
X    char	   *msg;
X{
X    fprintf(stderr, "%s: ", myname);
X    fprintf(stderr, msg, a1, a2, a3);
X    if (lineno)
X	fprintf(stderr, " near line %d", lineno);
X    fputc('\n', stderr);
X    exit(1);
X}
X
X
X/*
X *	Read a line into the supplied string of length LZ.  Remove
X *	comments, ignore blank lines. Deal with quoted (\) #, and
X *	quoted newlines.  If EOF return TRUE.
X */
Xbool
Xgetline(str, fd)
X    char	   *str;
X    FILE	   *fd;
X{
X    register char  *p;
X    register char  *q;		/*OIS*0.80*/
X    int 	    pos = 0;
X
X
X    for (;;) {
X	if (fgets(str + pos, LZ - pos, fd) == (char *) 0)
X	    return TRUE;	/* EOF	*/
X
X	lineno++;
X
X	if ((p = index(str + pos, '\n')) == (char *) 0)
X	    error("Line too long");
X
X	if (p[-1] == '\\') {
X	    register char space; /*OIS*0.80*/
X	    /* p[-1] = '\n';  */ /*OIS*0.80*/
X	    /* Skip the leading spaces of the next line */
X	    while (space = getc(fd), space == ' ' || space == '\t');
X	    p[-1] = space;
X	    if (space != '\n') {
X		pos = p - str;
X		continue;   /* read next line */
X	    }
X	}
X	p = str;
X	while (((q = index(p, '#')) != (char *) 0) &&
X	       (p != q) && (q[-1] == '\\')) {
X	    char	   *a;
X
X	    a = q - 1;		/* Del \ chr; move rest back  */
X	    p = q;
X	    while (*a++ = *q++);
X	}
X	if (q != (char *) 0) {
X	    q[0] = '\n';
X	    q[1] = '\0';
X	}
X	p = str;
X	while (isspace(*p))	/* Checking for blank line */
X	    p++;
X
X	if (*p != '\0')
X	    return FALSE;
X	pos = 0;
X    }
X}
X
X
X/*
X *	Get a word from the current line, surounded by white space.
X *	return a pointer to it. String returned has no white spaces
X *	in it.
X */
Xchar	       *
Xgettok(ptr)
X    register char  **ptr;	/*OIS*0.80*/
X{
X    register char  *p;
X
X
X    while (isspace(**ptr))	/* Skip spaces	*/
X	(*ptr)++;
X
X    if (**ptr == '\0')          /* Nothing after spaces  */
X	return NULL;
X
X    p = *ptr;			/* word starts here  */
X
X    while ((**ptr != '\0') && (!isspace(**ptr)))
X	(*ptr)++;		/* Find end of word  */
X
X    *(*ptr)++ = '\0';           /* Terminate it  */
X
X    return (p);
X}
END_OF_FILE
if test 2183 -ne `wc -c <'reader.c'`; then
    echo shar: \"'reader.c'\" unpacked with wrong size!
fi
# end of 'reader.c'
fi
if test -f 'rules.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rules.c'\"
else
echo shar: Extracting \"'rules.c'\" \(8196 characters\)
sed "s/^X//" >'rules.c' <<'END_OF_FILE'
X/*
X *	Control of the implicit suffix rules
X */
X
X
X#include "h.h"
X#ifndef NULL
X#define NULL ((void *) 0)
X#endif
X
X/*
X * Return a pointer to the suffix of a name
X */
Xchar	       *
Xsuffix(name)
X    char	   *name;
X{
X    return rindex(name, '.');
X}
X
X
X/*
X *	Dynamic dependency.  This routine applies the suffis rules
X *	to try and find a source and a set of rules for a missing
X *	target.  If found, np is made into a target with the implicit
X *	source name, and rules.  Returns TRUE if np was made into
X *	a target.
X */
Xbool
Xdyndep(np, pbasename, pinputname)
X    struct name    *np;
X    char	  **pbasename;	/*  Name without suffix  */
X    char	  **pinputname;
X{
X    register char  *p;
X    register char  *q;
X    register char  *suff;	/* Old suffix  */
X    register char  *basename;	/* Name without suffix	*/
X    struct name    *op; 	/* New dependent  */
X    struct name    *sp; 	/* Suffix  */
X    struct line    *lp;
X    struct depend  *dp;
X    struct name    *pathnp;	/* .PATH */
X    struct line    *pathlp;
X    struct depend  *pathdp;
X    struct depend  *pathdp1;
X    char	   *newsuff;
X    char	   *path;
X    void	    modtime();
X
X
X    p = str1;
X    q = np->n_name;
X    if (!(suff = suffix(q)))
X	return FALSE;		/* No suffix */
X    while (q < suff)
X	*p++ = *q++;
X    *p = '\0';
X    if ((*pbasename = basename = malloc(strlen(str1)+1)) == NULL)
X	fatal("No memory for basename");
X    strcpy(*pbasename, str1);
X
X    if (!((sp = newname(".SUFFIXES"))->n_flag & N_TARG))
X	return FALSE;
X
X    if (!((pathnp = newname(".PATH"))->n_flag & N_TARG))
X	pathnp = NULL;
X
X    if ((pathnp) && (pathlp = pathnp->n_line))
X	pathdp = pathlp->l_dep;
X    else
X	pathdp = NULL;
X
X    for (lp = sp->n_line; lp; lp = lp->l_next)
X	for (dp = lp->l_dep; dp; dp = dp->d_next) {
X	    newsuff = dp->d_name->n_name;   /* .c .o .asm etc */
X	    if (strlen(suff) + strlen(newsuff) + 1 >= LZ)
X		fatal("Suffix rule too long");
X	    p = str1;
X	    q = newsuff;
X	    while (*p++ = *q++);
X	    p--;
X	    q = suff;
X	    while (*p++ = *q++);
X	    sp = newname(str1);     /* Form for example .c.o */
X	    if (sp->n_flag & N_TARG) {
X		path = "";
X		pathdp1 = pathdp;
X	nextpath:
X		p = str1;
X		if (strlen(path) + strlen(basename) + strlen(newsuff) + 2 >= LZ)
X		    fatal("Implicit name too long");
X		q = path;
X		while (*p++ = *q++);    /* copy path */
X		p--;
X		q = basename;
X		while (*p++ = *q++);    /* copy basename */
X		p--;
X		q = newsuff;
X		while (*p++ = *q++);    /* copy new suffix */
X		op = newname(str1);
X		if (!op->n_line && !op->n_time)
X		    modtime(op);
X		if (op->n_line || op->n_time) {     /* file exists? */
X		    dp = newdep(op, NULL);
X		    newline(np, dp, sp->n_line->l_cmd, 0);
X		    *pinputname = op->n_name;	/* $< = path/basename.suffix */
X		    return TRUE;
X		} else {
X		    delname(op);        /* Forget non-existing file */
X		    if (pathdp1) {      /* But is there a path? */
X			path = pathdp1->d_name->n_name;
X			pathdp1 = pathdp1->d_next;
X			goto nextpath;
X		    }
X		}
X	    }
X	}
X    return FALSE;
X}
X
X
X/*
X *	Make the default rules
X */
Xvoid
Xmakerules()
X{
X    register struct cmd     *cp;    /*OIS*0.80*/
X    register struct name    *np;    /*OIS*0.80*/
X    register struct depend  *dp;    /*OIS*0.80*/
X
X
X#ifdef eon
X    setmacro("BDSCC", "asm");
X    /* setmacro("BDSCFLAGS", "");        */
X    cp = newcmd("$(BDSCC) $(BDSCFLAGS) -n $<", 0);
X    np = newname(".c.o");
X    newline(np, 0, cp, 0);
X
X    setmacro("CC", "c");
X    setmacro("CFLAGS", "-O");
X    cp = newcmd("$(CC) $(CFLAGS) -c $<", 0);
X    np = newname(".c.obj");
X    newline(np, 0, cp, 0);
X
X    setmacro("M80", "asm -n");
X    /* setmacro("M80FLAGS", "");         */
X    cp = newcmd("$(M80) $(M80FLAGS) $<", 0);
X    np = newname(".mac.o");
X    newline(np, 0, cp, 0);
X
X    setmacro("AS", "zas");
X    /* setmacro("ASFLAGS", "");  */
X    cp = newcmd("$(ZAS) $(ASFLAGS) -o $@ $<", 0);
X    np = newname(".as.obj");
X    newline(np, 0, cp, 0);
X
X    np = newname(".as");
X    dp = newdep(np, 0);
X    np = newname(".obj");
X    dp = newdep(np, dp);
X    np = newname(".c");
X    dp = newdep(np, dp);
X    np = newname(".o");
X    dp = newdep(np, dp);
X    np = newname(".mac");
X    dp = newdep(np, dp);
X    np = newname(".SUFFIXES");
X    newline(np, dp, 0, 0);
X#endif
X
X/*
X *	Some of the UNIX implicit rules
X */
X#ifdef unix
X    setmacro("CC", "cc");
X    setmacro("CFLAGS", "-O");
X#ifdef MINIXPC
X    cp = newcmd("$(CC) $(CFLAGS) -S $<", (struct cmd *)0);
X    np = newname(".c.s");
X#else
X    cp = newcmd("$(CC) $(CFLAGS) -c $<", (struct cmd *)0);
X    np = newname(".c.o");
X#endif MINIXPC
X    newline(np, (struct depend *)0, cp, 0);
X
X    setmacro("AS", "as");
X    cp = newcmd("$(AS) -o $@ $<", (struct cmd *)0);
X    np = newname(".s.o");
X    newline(np, (struct depend *)0, cp, 0);
X
X    setmacro("YACC", "yacc");
X    /*	    setmacro("YFLAGS", ""); */
X    cp = newcmd("$(YACC) $(YFLAGS) $<", (struct cmd *)0);
X    cp = newcmd("mv y.tab.c $@", cp);
X    np = newname(".y.c");
X    newline(np, (struct depend *)0, cp, 0);
X
X    cp = newcmd("$(YACC) $(YFLAGS) $<", (struct cmd *)0);
X#ifdef MINIXPC
X    cp = newcmd("$(CC) $(CFLAGS) -S y.tab.c", cp);
X    cp = newcmd("mv y.tab.s $@", cp);
X    np = newname(".y.s");
X#else
X    cp = newcmd("$(CC) $(CFLAGS) -c y.tab.c", cp);
X    cp = newcmd("mv y.tab.o $@", cp);
X    np = newname(".y.o");
X#endif MINIXPC
X    cp = newcmd("rm y.tab.c", cp);
X    newline(np, (struct depend *)0, cp, 0);
X
X    setmacro("FLEX", "flex");
X    cp = newcmd("$(FLEX) $(FLEX_FLAGS) $<", (struct cmd *)0);
X    cp = newcmd("mv lex.yy.c $@", cp);
X    np = newname(".l.c");
X    newline(np, (struct depend *)0, cp, 0);
X
X    cp = newcmd("$(FLEX) $(FLEX_FLAGS) $<", (struct cmd *)0);
X#ifdef MINIXPC
X    cp = newcmd("$(CC) $(CFLAGS) -S lex.yy.s", cp);
X    cp = newcmd("mv lex.yy.s $@", cp);
X    np = newname(".l.s");
X#else
X    cp = newcmd("$(CC) $(CFLAGS) -c lex.yy.c", cp);
X    cp = newcmd("mv lex.yy.o $@", cp);
X    np = newname(".l.o");
X#endif MINIXPC
X    cp = newcmd("rm lex.yy.c", cp);
X    newline(np, (struct depend *)0, cp, 0);
X
X    np = newname(".o");
X    dp = newdep(np, (struct depend *)0);
X    np = newname(".s");
X    dp = newdep(np, dp);
X    np = newname(".c");
X    dp = newdep(np, dp);
X    np = newname(".y");
X    dp = newdep(np, dp);
X    np = newname(".l");
X    dp = newdep(np, dp);
X    np = newname(".SUFFIXES");
X    newline(np, dp, (struct cmd *)0, 0);
X#endif
X
X#ifdef os9
X/*
X *	Fairlight use an enhanced version of the C sub-system.
X *	They have a specialised macro pre-processor.
X */
X    setmacro("CC", "cc");
X    setmacro("CFLAGS", "-z");
X    cp = newcmd("$(CC) $(CFLAGS) -r $<", 0);
X
X    np = newname(".c.r");
X    newline(np, 0, cp, 0);
X    np = newname(".ca.r");
X    newline(np, 0, cp, 0);
X    np = newname(".a.r");
X    newline(np, 0, cp, 0);
X    np = newname(".o.r");
X    newline(np, 0, cp, 0);
X    np = newname(".mc.r");
X    newline(np, 0, cp, 0);
X    np = newname(".mca.r");
X    newline(np, 0, cp, 0);
X    np = newname(".ma.r");
X    newline(np, 0, cp, 0);
X    np = newname(".mo.r");
X    newline(np, 0, cp, 0);
X
X    np = newname(".r");
X    dp = newdep(np, 0);
X    np = newname(".mc");
X    dp = newdep(np, dp);
X    np = newname(".mca");
X    dp = newdep(np, dp);
X    np = newname(".c");
X    dp = newdep(np, dp);
X    np = newname(".ca");
X    dp = newdep(np, dp);
X    np = newname(".ma");
X    dp = newdep(np, dp);
X    np = newname(".mo");
X    dp = newdep(np, dp);
X    np = newname(".o");
X    dp = newdep(np, dp);
X    np = newname(".a");
X    dp = newdep(np, dp);
X    np = newname(".SUFFIXES");
X    newline(np, dp, 0, 0);
X#endif
X
X#ifdef amiga
X
X#ifdef pdc	/*OIS*0.80*/
X    static char ccx_c[] = "ccx -c";
X
X    setmacro("CC", ccx_c);
X#else
X    setmacro("CC", "cc");
X#endif
X    cp = newcmd("$(CC) $(CFLAGS) $<", NULL);
X    np = newname(".c.o");
X    newline(np, NULL, cp, 0);
X
X#ifdef pdc	/*OIS*0.80*/
X    setmacro("AS", ccx_c);
X    cp = newcmd("$(AS) $(AFLAGS) $<", NULL);        /*OIS*0.80*/
X#else
X    setmacro("AS", "as");
X    cp = newcmd("$(AS) $(AFLAGS) -o $@ $<", NULL);  /*OIS*0.80*/
X#endif
X    np = newname(".s.o");
X    newline(np, NULL, cp, NULL);
X
X    np = newname(".o");
X    dp = newdep(np, NULL);
X    np = newname(".s");
X    dp = newdep(np, dp);
X    np = newname(".c");
X    dp = newdep(np, dp);
X    np = newname(".SUFFIXES");
X    newline(np, dp, NULL, 0);
X#endif
X}
END_OF_FILE
if test 8196 -ne `wc -c <'rules.c'`; then
    echo shar: \"'rules.c'\" unpacked with wrong size!
fi
# end of 'rules.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
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
-- 
Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
	amiga@cs.odu.edu	
or	amiga@xanth.cs.odu.edu	( obsolescent mailers may need this address )
or	...!uunet!xanth!amiga	( very obsolescent mailers need this address )

Comments, questions, and suggestions s should be addressed to ``amiga-request''
(only use ``amiga'' for submissions) at the above addresses.