[comp.os.minix] make

ast@cs.vu.nl (Andy Tanenbaum) (10/06/88)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'ReadMe'
sed 's/^X//' > 'ReadMe' << '+ END-OF-FILE ''ReadMe'
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 ReadMe
chmod 'u=rw,g=r,o=r' 'ReadMe'
set `wc -c 'ReadMe'`
count=$1
case $count in
1803)	:;;
*)	echo 'Bad character count in ''ReadMe' >&2
		echo 'Count should be 1803' >&2
esac
echo Extracting 'check.c'
sed 's/^X//' > 'check.c' << '+ END-OF-FILE ''check.c'
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	{
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		{
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)
Xstruct 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 check.c
chmod 'u=rw,g=r,o=r' 'check.c'
set `wc -c 'check.c'`
count=$1
case $count in
2100)	:;;
*)	echo 'Bad character count in ''check.c' >&2
		echo 'Count should be 2100' >&2
esac
echo Extracting 'h.h'
sed 's/^X//' > 'h.h' << '+ END-OF-FILE ''h.h'
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/* 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{
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{
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{
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{
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{
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 h.h
chmod 'u=rw,g=r,o=r' 'h.h'
set `wc -c 'h.h'`
count=$1
case $count in
2457)	:;;
*)	echo 'Bad character count in ''h.h' >&2
		echo 'Count should be 2457' >&2
esac
echo Extracting 'input.c'
sed 's/^X//' > 'input.c' << '+ END-OF-FILE ''input.c'
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)
Xchar *			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(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/*
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)
Xstruct name *		np;
Xstruct 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
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)
Xchar *			str;
Xstruct 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;
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(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
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)
Xstruct name *		np;
Xstruct depend *		dp;
Xstruct cmd *		cp;
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	{
X		for (rp = np->n_line; rp; rp = rrp)
X		{
X			rrp = rp->l_next;
X			free(rp);
X		}
X		np->n_line = (struct line *)0;
X		np->n_flag &= ~N_TARG;
X		return;
X	}
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		{
X			np->n_line->l_cmd = cp;
X			return;
X		}
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)
XFILE *			fd;
X{
X	char *			p;		/*  General  */
X	char *			q;
X	struct name *		np;
X	struct depend *		dp;
X	struct cmd *		cp;
X	bool			dbl;
X
X
X	if (getline(str1, fd))	/*  Read the first line  */
X		return;
X
X	for(;;)
X	{
X#ifdef os9
X		if (*str1 == ' ')	/*  Rules without targets  */
X#else
X		if (*str1 == '\t')	/*  Rules without targets  */
X#endif
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		{
X			register char *		a;
X
X			a = q - 1;	/*  Del \ chr; move rest back  */
X			p = q;
X			while(*a++ = *q++)
X				;
X		}
X
X		if (q != (char *)0)
X		{
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
X		expand(str1);
X		p = str1;
X
X		while (((q = index(p, ':')) != (char *)0) &&
X		    (p != q) && (q[-1] == '\\'))	/*  Find dependents  */
X		{
X			register char *		a;
X
X			a = q - 1;	/*  Del \ chr; move rest back  */
X			p = q;
X			while(*a++ = *q++)
X				;
X		}
X
X		if (q == (char *)0)
X			error("No targets provided");
X
X		*q++ = '\0';	/*  Separate targets and dependents  */
X
X		if (*q == ':')		/* Double colon */
X		{
X			dbl = 1;
X			q++;
X		}
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		{
X#ifdef os9
X			while (*str2 == ' ')
X#else
X			while (*str2 == '\t')
X#endif
X			{
X				cp = newcmd(&str2[0], cp);
X				if (getline(str2, fd))
X					break;
X			}
X		}
X
X		while ((p = gettok(&q)) != (char *)0)	/* Get list of targ's */
X		{
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 input.c
chmod 'u=rw,g=r,o=r' 'input.c'
set `wc -c 'input.c'`
count=$1
case $count in
6577)	:;;
*)	echo 'Bad character count in ''input.c' >&2
		echo 'Count should be 6577' >&2
esac
echo Extracting 'macro.c'
sed 's/^X//' > 'macro.c' << '+ END-OF-FILE ''macro.c'
X/*
X *	Macro control for make
X */
X
X
X#include "h.h"
X
X
Xstruct macro *		macrohead;
X
X
Xstruct macro *
Xgetmp(name)
Xchar *			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)
Xchar *			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)
Xchar *			name;
Xchar *			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		{
X			free(rp->m_val);	/*  Free space from old  */
X			break;
X		}
X
X	if (!rp)		/*  If not defined, allocate space for new  */
X	{
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(strlen(name)+1)) == (char *)0)
X			fatal("No memory for macro");
X		strcpy(cp, name);
X		rp->m_name = cp;
X	}
X
X	if ((cp = malloc(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)
Xchar **			to;
Xchar *			from;
Xint *			len;
Xchar *			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	{
X		if (*rp != '$')
X		{
X			*p++ = *rp++;
X			(*len)--;
X		}
X		else
X		{
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			{
X				*p++ = '$';
X				break;
X			}
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 line");
X	}
X	*p = '\0';
X	*to = p;
X}
X
X
X/*
X *	Expand any macros in str.
X */
Xvoid
Xexpand(str)
Xchar *		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 macro.c
chmod 'u=rw,g=r,o=r' 'macro.c'
set `wc -c 'macro.c'`
count=$1
case $count in
2366)	:;;
*)	echo 'Bad character count in ''macro.c' >&2
		echo 'Count should be 2366' >&2
esac
echo Extracting 'main.c'
sed 's/^X//' > 'main.c' << '+ END-OF-FILE ''main.c'
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 <errno.h>
X#endif
X#ifdef eon
X#include <sys/err.h>
X#endif
X#ifdef os9
X#include <errno.h>
X#endif
X
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)
Xint			argc;
Xchar **			argv;
X{
X	register char *		p;		/*  For argument processing  */
X	int			estat = 0;	/*  For question  */
X	register struct name *	np;
X
X
X	myname = (argc-- < 1) ? "make" : *argv++;
X
X	while ((argc > 0) && (**argv == '-'))
X	{
X		argc--;		/*  One less to process  */
X		p = *argv++;	/*  Now processing this one  */
X
X		while (*++p != '\0')
X		{
X			switch(*p)
X			{
X			case 'f':	/*  Alternate file name  */
X				if (*++p == '\0')
X				{
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				{
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		}
X	end_of_args:;
X	}
X
X#ifdef eon
X	if (initalloc(memspace) == 0xffff)  /*  Must get memory for alloc  */
X		fatal("Cannot initalloc memory");
X#endif
X
X	if (strcmp(makefile, "-") == 0)	/*  Can use stdin as makefile  */
X		ifd = stdin;
X	else
X		if (!makefile)		/*  If no file, then use default */
X		{
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#ifndef os9
X			if ((ifd == (FILE *)0)
X				  && ((ifd = fopen(DEFN2, "r")) == (FILE *)0))
X				fatal("Can't open %s", DEFN2);
X#else
X				fatal("Can't open %s", DEFN1);
X#endif
X		}
X		else
X			if ((ifd = fopen(makefile, "r")) == (FILE *)0)
X				fatal("Can't open %s", makefile);
X
X	makerules();
X
X	setmacro("$", "$");
X
X	while (argc && (p = index(*argv, '=')))
X	{
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 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 while (argc--)
X	{
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)
Xchar	*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}
+ END-OF-FILE main.c
chmod 'u=rw,g=r,o=r' 'main.c'
set `wc -c 'main.c'`
count=$1
case $count in
4332)	:;;
*)	echo 'Bad character count in ''main.c' >&2
		echo 'Count should be 4332' >&2
esac
echo Extracting 'make.c'
sed 's/^X//' > 'make.c' << '+ END-OF-FILE ''make.c'
X/*
X *	Do the actual making for make
X */
X
X#include <stdio.h>
X
X#ifdef unix
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X#endif
X
X#ifdef eon
X#include <sys/stat.h>
X#include <sys/err.h>
X#endif
X
X#ifdef os9
X#include <time.h>
X#include <os9.h>
X#include <modes.h>
X#include <direct.h>
X#include <errno.h>
X#endif
X
X#include "h.h"
X
X
X
X/*
X *	Exec a shell that returns exit status correctly (/bin/esh).
X *	The standard EON shell returns the process number of the last
X *	async command, used by the debugger (ugg).
X *	[exec on eon is like a fork+exec on unix]
X */
Xint
Xdosh(string, shell)
Xchar *			string;
Xchar *			shell;
X{
X	int	number;
X
X#ifdef unix
X	return system(string);
X#endif
X#ifdef eon
X	return ((number = execl(shell, shell,"-c", string, 0)) == -1) ?
X		-1:	/* couldn't start the shell */
X		wait(number);	/* return its exit status */
X#endif
X#ifdef os9
X	int	status, pid;
X
X	strcat(string, "\n");
X	if ((number = os9fork(shell, strlen(string), string, 0, 0, 0)) == -1)
X		return -1;		/* Couldn't start a shell */
X	do
X	{
X		if ((pid = wait(&status)) == -1)
X			return -1;	/* child already died!?!? */
X	} while (pid != number);
X
X	return status;
X#endif
X}
X
X
X/*
X *	Do commands to make a target
X */
Xvoid
Xdocmds1(np, lp)
Xstruct name *		np;
Xstruct line *		lp;
X{
X	bool			ssilent;
X	bool			signore;
X	int			estat;
X	register char *		q;
X	register char *		p;
X	char *			shell;
X	register struct cmd *	cp;
X
X
X	if (*(shell = getmacro("SHELL")) == '\0')
X#ifdef eon
X		shell = ":bin/esh";
X#endif
X#ifdef unix
X		shell = "/bin/sh";
X#endif
X#ifdef os9
X		shell = "shell";
X#endif
X
X	for (cp = lp->l_cmd; cp; cp = cp->c_next)
X	{
X		strcpy(str1, cp->c_cmd);
X		expand(str1);
X		q = str1;
X		ssilent = silent;
X		signore = ignore;
X		while ((*q == '@') || (*q == '-'))
X		{
X			if (*q == '@')	   /*  Specific silent  */
X				ssilent = TRUE;
X			else		   /*  Specific ignore  */
X				signore = TRUE;
X			q++;		   /*  Not part of the command  */
X		}
X
X		if (!domake)
X			ssilent = 0;
X
X		if (!ssilent)
X			fputs("    ", stdout);
X
X		for (p=q; *p; p++)
X		{
X			if (*p == '\n' && p[1] != '\0')
X			{
X				*p = ' ';
X				if (!ssilent)
X					fputs("\\\n", stdout);
X			}
X			else if (!ssilent)
X				putchar(*p);
X		}
X		if (!ssilent)
X			printf("\n");
X
X		if (domake)
X		{			/*  Get the shell to execute it  */
X			if ((estat = dosh(q, shell)) != 0)
X			{
X				if (estat == -1)
X					fatal("Couldn't execute %s", shell);
X				else
X				{
X					printf("%s: Error code %d", myname, estat);
X					if (signore)
X						fputs(" (Ignored)\n", stdout);
X					else
X					{
X						putchar('\n');
X						if (!(np->n_flag & N_PREC))
X							if (unlink(np->n_name) == 0)
X								printf("%s: '%s' removed.\n", myname, np->n_name);
X						exit(estat);
X					}
X				}
X			}
X		}
X	}
X}
X
X
Xdocmds(np)
Xstruct name *		np;
X{
X	register struct line *	lp;
X
X
X	for (lp = np->n_line; lp; lp = lp->l_next)
X		docmds1(np, lp);
X}
X
X
X#ifdef os9
X/*
X *	Some stuffing around to get the modified time of a file
X *	in an os9 file system
X */
Xgetmdate(fd, tbp)
Xstruct sgtbuf *		tbp;
X{
X	struct registers	regs;
X	static struct fildes	fdbuf;
X
X
X	regs.rg_a = fd;
X	regs.rg_b = SS_FD;
X	regs.rg_x = &fdbuf;
X	regs.rg_y = sizeof (fdbuf);
X
X	if (_os9(I_GETSTT, &regs) == -1)
X	{
X		errno = regs.rg_b & 0xff;
X		return -1;
X	}
X	if (tbp)
X	{
X		_strass(tbp, fdbuf.fd_date, sizeof (fdbuf.fd_date));
X		tbp->t_second = 0;	/* Files are only acurate to mins */
X	}
X	return 0;
X}
X
X
X/*
X *	Kludge routine to return an aproximation of how many
X *	seconds since 1980.  Dates will be in order, but will not
X *	be lineer
X */
Xtime_t
Xcnvtime(tbp)
Xstruct sgtbuf		*tbp;
X{
X	long			acc;
X
X
X	acc = tbp->t_year - 80;		/* Baseyear is 1980 */
X	acc = acc * 12 + tbp->t_month;
X	acc = acc * 31 + tbp->t_day;
X	acc = acc * 24 + tbp->t_hour;
X	acc = acc * 60 + tbp->t_minute;
X	acc = acc * 60 + tbp->t_second;
X
X	return acc;
X}
X
X
X/*
X *	Get the current time in the internal format
X */
Xtime(tp)
Xtime_t *		tp;
X{
X	struct sgtbuf		tbuf;
X
X
X	if (getime(&tbuf) < 0)
X		return -1;
X
X	if (tp)
X		*tp = cnvtime(&tbuf);
X
X	return 0;
X}
X#endif
X
X
X/*
X *	Get the modification time of a file.  If the first
X *	doesn't exist, it's modtime is set to 0.
X */
Xvoid
Xmodtime(np)
Xstruct name *		np;
X{
X#ifdef unix
X	struct stat		info;
X	int			fd;
X
X
X	if (stat(np->n_name, &info) < 0)
X	{
X		if (errno != ENOENT)
X			fatal("Can't open %s; error %d", np->n_name, errno);
X
X		np->n_time = 0L;
X	}
X	else
X		np->n_time = info.st_mtime;
X#endif
X#ifdef eon
X	struct stat		info;
X	int			fd;
X
X
X	if ((fd = open(np->n_name, 0)) < 0)
X	{
X		if (errno != ER_NOTF)
X			fatal("Can't open %s; error %02x", np->n_name, errno);
X
X		np->n_time = 0L;
X	}
X	else if (getstat(fd, &info) < 0)
X		fatal("Can't getstat %s; error %02x", np->n_name, errno);
X	else
X		np->n_time = info.st_mod;
X
X	close(fd);
X#endif
X#ifdef os9
X	struct sgtbuf		info;
X	int			fd;
X
X
X	if ((fd = open(np->n_name, 0)) < 0)
X	{
X		if (errno != E_PNNF)
X			fatal("Can't open %s; error %02x", np->n_name, errno);
X
X		np->n_time = 0L;
X	}
X	else if (getmdate(fd, &info) < 0)
X		fatal("Can't getstat %s; error %02x", np->n_name, errno);
X	else
X		np->n_time = cnvtime(&info);
X
X	close(fd);
X#endif
X}
X
X
X/*
X *	Update the mod time of a file to now.
X */
Xvoid
Xtouch(np)
Xstruct name *		np;
X{
X	char			c;
X	int			fd;
X
X
X	if (!domake || !silent)
X		printf("    touch(%s)\n", np->n_name);
X
X	if (domake)
X	{
X#ifdef unix
X		long		a[2];
X
X		a[0] = a[1] = time(0);
X		if (utime(np->n_name, &a[0]) < 0)
X			printf("%s: '%s' not touched - non-existant\n",
X					myname, np->n_name);
X#endif
X#ifdef eon
X		if ((fd = open(np->n_name, 0)) < 0)
X			printf("%s: '%s' not touched - non-existant\n",
X					myname, np->n_name);
X		else
X		{
X			uread(fd, &c, 1, 0);
X			uwrite(fd, &c, 1);
X		}
X		close(fd);
X#endif
X#ifdef os9
X		/*
X		 *	Strange that something almost as totally useless
X		 *	as this is easy to do in os9!
X		 */
X		if ((fd = open(np->n_name, S_IWRITE)) < 0)
X			printf("%s: '%s' not touched - non-existant\n",
X					myname, np->n_name);
X		close(fd);
X#endif
X	}
X}
X
X
X/*
X *	Recursive routine to make a target.
X */
Xint
Xmake(np, level)
Xstruct name *		np;
Xint			level;
X{
X	register struct depend *	dp;
X	register struct line *		lp;
X	register struct depend *	qdp;
X	time_t				dtime = 1;
X	bool				didsomething = 0;
X
X
X	if (np->n_flag & N_DONE)
X		return 0;
X
X	if (!np->n_time)
X		modtime(np);		/*  Gets modtime of this file  */
X
X	if (rules)
X	{
X		for (lp = np->n_line; lp; lp = lp->l_next)
X			if (lp->l_cmd)
X				break;
X		if (!lp)
X			dyndep(np);
X	}
X
X	if (!(np->n_flag & N_TARG) && np->n_time == 0L)
X		fatal("Don't know how to make %s", np->n_name);
X
X	for (qdp = (struct depend *)0, lp = np->n_line; lp; lp = lp->l_next)
X	{
X		for (dp = lp->l_dep; dp; dp = dp->d_next)
X		{
X			make(dp->d_name, level+1);
X			if (np->n_time < dp->d_name->n_time)
X				qdp = newdep(dp->d_name, qdp);
X			dtime = max(dtime, dp->d_name->n_time);
X		}
X		if (!quest && (np->n_flag & N_DOUBLE) && (np->n_time < dtime))
X		{
X			make1(np, lp, qdp);	/* free()'s qdp */
X			dtime = 1;
X			qdp = (struct depend *)0;
X			didsomething++;
X		}
X	}
X
X	np->n_flag |= N_DONE;
X
X	if (quest)
X	{
X		long		t;
X
X		t = np->n_time;
X		time(&np->n_time);
X		return t < dtime;
X	}
X	else if (np->n_time < dtime && !(np->n_flag & N_DOUBLE))
X	{
X		make1(np, (struct line *)0, qdp);	/* free()'s qdp */
X		time(&np->n_time);
X	}
X	else if (level == 0 && !didsomething)
X		printf("%s: '%s' is up to date\n", myname, np->n_name);
X	return 0;
X}
X
X
Xmake1(np, lp, qdp)
Xregister struct depend *	qdp;
Xstruct line *			lp;
Xstruct name *			np;
X{
X	register struct depend *	dp;
X
X
X	if (dotouch)
X		touch(np);
X	else
X	{
X		strcpy(str1, "");
X		for (dp = qdp; dp; dp = qdp)
X		{
X			if (strlen(str1))
X				strcat(str1, " ");
X			strcat(str1, dp->d_name->n_name);
X			qdp = dp->d_next;
X			free(dp);
X		}
X		setmacro("?", str1);
X		setmacro("@", np->n_name);
X		if (lp)		/* lp set if doing a :: rule */
X			docmds1(np, lp);
X		else
X			docmds(np);
X	}
X}
+ END-OF-FILE make.c
chmod 'u=rw,g=r,o=r' 'make.c'
set `wc -c 'make.c'`
count=$1
case $count in
7681)	:;;
*)	echo 'Bad character count in ''make.c' >&2
		echo 'Count should be 7681' >&2
esac
echo Extracting 'makefile'
sed 's/^X//' > 'makefile' << '+ END-OF-FILE ''makefile'
X# Makefile for make!
X
XCFLAGS = -Dunix -DMINIX
X
XOBJS	=	check.s input.s macro.s main.s \
X		make.s reader.s rules.s
X
Xmake:		$(OBJS)
X	cc -o make $(OBJS)
X
Xcheck.s:	h.h check.c
X	$(CC) -S $(CFLAGS) check.c
X
Xinput.s:	h.h input.c
X	$(CC) -S $(CFLAGS) input.c
X
Xmacro.s:	h.h macro.c
X	$(CC) -S $(CFLAGS) macro.c
X
Xmain.s:		h.h main.c
X	$(CC) -S $(CFLAGS) main.c
X
Xmake.s:		h.h make.c
X	$(CC) -S $(CFLAGS) make.c
X
Xreader.s:	h.h reader.c
X	$(CC) -S $(CFLAGS) reader.c
X
Xrules.s:	h.h rules.c
X	$(CC) -S $(CFLAGS) rules.c
+ END-OF-FILE makefile
chmod 'u=rw,g=r,o=r' 'makefile'
set `wc -c 'makefile'`
count=$1
case $count in
498)	:;;
*)	echo 'Bad character count in ''makefile' >&2
		echo 'Count should be 498' >&2
esac
echo Extracting 'reader.c'
sed 's/^X//' > 'reader.c' << '+ END-OF-FILE ''reader.c'
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)
Xchar *			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)
Xchar *		str;
XFILE *		fd;
X{
X	register char *		p;
X	char *			q;
X	int			pos = 0;
X
X
X	for (;;)
X	{
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		{
X			p[-1] = '\n';
X			pos = p - str;
X			continue;
X		}
X
X		p = str;
X		while (((q = index(p, '#')) != (char *)0) &&
X		    (p != q) && (q[-1] == '\\'))
X		{
X			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		{
X			q[0] = '\n';
X			q[1] = '\0';
X		}
X
X		p = str;
X		while (isspace(*p))	/*  Checking for blank  */
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)
Xchar	**ptr;
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 reader.c
chmod 'u=rw,g=r,o=r' 'reader.c'
set `wc -c 'reader.c'`
count=$1
case $count in
1795)	:;;
*)	echo 'Bad character count in ''reader.c' >&2
		echo 'Count should be 1795' >&2
esac
echo Extracting 'rules.c'
sed 's/^X//' > 'rules.c' << '+ END-OF-FILE ''rules.c'
X/*
X *	Control of the implicit suffix rules
X */
X
X
X#include "h.h"
X
X
X/*
X *	Return a pointer to the suffix of a name
X */
Xchar *
Xsuffix(name)
Xchar *			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)
Xstruct name *		np;
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	char *			newsuff;
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	basename = setmacro("*", str1)->m_val;
X
X	if (!((sp = newname(".SUFFIXES"))->n_flag & N_TARG))
X		return FALSE;
X
X	for (lp = sp->n_line; lp; lp = lp->l_next)
X		for (dp = lp->l_dep; dp; dp = dp->d_next)
X		{
X			newsuff = dp->d_name->n_name;
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				;
X			p--;
X			q = suff;
X			while (*p++ = *q++)
X				;
X			sp = newname(str1);
X			if (sp->n_flag & N_TARG)
X			{
X				p = str1;
X				q = basename;
X				if (strlen(basename) + strlen(newsuff)+1 >= LZ)
X					fatal("Implicit name too long");
X				while (*p++ = *q++)
X					;
X				p--;
X				q = newsuff;
X				while (*p++ = *q++)
X					;
X				op = newname(str1);
X				if (!op->n_time)
X					modtime(op);
X				if (op->n_time)
X				{
X					dp = newdep(op, 0);
X					newline(np, dp, sp->n_line->l_cmd, 0);
X					setmacro("<", op->n_name);
X					return TRUE;
X				}
X			}
X		}
X	return FALSE;
X}
X
X
X/*
X *	Make the default rules
X */
Xvoid
Xmakerules()
X{
X	struct cmd *		cp;
X	struct name *		np;
X	struct depend *		dp;
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 MINIX
X	cp = newcmd("$(CC) $(CFLAGS) -S $<", 0);
X	np = newname(".c.s");
X#else
X	cp = newcmd("$(CC) $(CFLAGS) -c $<", 0);
X	np = newname(".c.o");
X#endif MINIX
X	newline(np, 0, cp, 0);
X
X	setmacro("AS", "as");
X	cp = newcmd("$(AS) -o $@ $<", 0);
X	np = newname(".s.o");
X	newline(np, 0, cp, 0);
X
X	setmacro("YACC", "yacc");
X	/*	setmacro("YFLAGS", "");	*/
X	cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
X	cp = newcmd("mv y.tab.c $@", cp);
X	np = newname(".y.c");
X	newline(np, 0, cp, 0);
X
X	cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
X	cp = newcmd("$(CC) $(CFLAGS) -c y.tab.c", cp);
X	cp = newcmd("rm y.tab.c", cp);
X	cp = newcmd("mv y.tab.o $@", cp);
X	np = newname(".y.o");
X	newline(np, 0, cp, 0);
X
X	np = newname(".s");
X	dp = newdep(np, 0);
X	np = newname(".o");
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(".SUFFIXES");
X	newline(np, dp, 0, 0);
X#endif
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}
+ END-OF-FILE rules.c
chmod 'u=rw,g=r,o=r' 'rules.c'
set `wc -c 'rules.c'`
count=$1
case $count in
4916)	:;;
*)	echo 'Bad character count in ''rules.c' >&2
		echo 'Count should be 4916' >&2
esac
exit 0

F35KER%DHHDESY3.BITNET@cunyvm.cuny.edu (Kerst van Raden) (09/16/89)

Hello World!
Some days ago I posted a cry for help with a strange behaving
make(1). First of all I'd like to thank all those who who tried to
help me locate the problem. Unfortunately no one came up with the
right idea: I had mistyped the date when I logged in the day before.
After several hours of looking through the code of make and filling
it with debug printfs I finally found make spotting a header file
with a modification time of september 1990. This caused make to
recompile all .c files in one directoy everytime I started it.
So this was really not makes fault. On the other hand I had expected
ls(1) to tell me the year of modification if it was not 1989. Instead
ls gave me the date and time, so I thought the year was '89. I did
not look into the code of ls (the ST 1.1 version) yet, but I suppose
ls prints the year of modification if it is older then the current
year instaed of printing it when it is not the current year.
Anyway I plan to install one of the ls's recently posted on the net.
I just wanted to warn you: mistyping the date and touching a file may
couse you a lot of grief. And ls may not tell you...
Wiser now
           Kerst van Raden

jrstu@cbnewsd.ATT.COM (james.stuhlmacher) (01/03/90)

This is a reposting.

About a month ago I posted an article stating that make(1)
does not quit completely when you press the interrupt key.  It
just stops the one compile and starts the next.  I blamed this on
system(3) that was ignoring the SIGINT signal.  Terrence Holm wrote
me a letter explaining that system(3) should ignore signals in
case you start an interactive shell via it.  He also said that
make(1) should look at the exit status of system(3) to determine
whether it should completely stop or not.

This made sense so I looked at the code for make(1) and it DOES
look at the exit status.  Before I could proceed, Bruce Evans
wrote a letter to me saying its all sh(1)s fault because it does
not return the interrupt status of its interrupted child.  (System(3)
calls "sh -c command".)  Thus sh(1) was returning 0 when it should
have been returning the number of the signal that aborted its child.
System(3) simply passes on the exit status of sh(1) to the program
that called system(3).

Bruce also sent me the patch below to fix the bug.  After looking
through the code, I think this is the correct fix.  This patch has
been redone for v1.5.0.

#! /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 shell archive."
# Contents:  sh3.cdif
# Wrapped by jims@stu on Tue Jan  2 11:14:54 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'sh3.cdif' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sh3.cdif'\"
else
echo shar: Extracting \"'sh3.cdif'\" \(343 characters\)
sed "s/^X//" >'sh3.cdif' <<'END_OF_FILE'
X*** osh3.c	Tue Jan  2 10:39:45 1990
X--- nsh3.c	Tue Jan  2 11:06:00 1990
X***************
X*** 509,516 ****
X  			if (canintr)
X  				intr = 0;
X  		}
X! 		else
X! 			onintr();
X  	return(rv);
X  }
X  
X--- 509,519 ----
X  			if (canintr)
X  				intr = 0;
X  		}
X! 		else {
X! 			if (exstat == 0)
X! 				exstat = rv;
X! 			onintr();
X! 		}
X  	return(rv);
X  }
X  
END_OF_FILE
if test 343 -ne `wc -c <'sh3.cdif'`; then
    echo shar: \"'sh3.cdif'\" unpacked with wrong size!
fi
# end of 'sh3.cdif'
fi
echo shar: End of shell archive.
exit 0


Jim Stuhlmacher
j.stuhlmacher@ATT.com
..!att!ihlpb!jims

jca@pnet01.cts.com (John C. Archambeau) (06/04/90)

kjh@pollux.usc.edu (Kenneth J. Hendrickson) writes:
>Stupid question time.  I can't make(1) fs, mm, or the kernel.  I get an
>error message about running out of memory.  I have scads of memory.  I
>have a RAM disk with more than 2 Megs free.  I have 640 k to run
>processes in.  I tried the chmem(1) thing, but I'm not sure exactly
>which program I should be using it on, or exactly how.
>
>Everything else compiled fine, including the library!  I have everything
>else for 1.5.10 built.  I need to build the important parts of the
>kernel now.  I can't figure out the Makefile, to do it by hand.  What
>does:
>
>	file:	Makefile [some file names]
>
>mean?  Makefile is not an executable.  It is also not a shell script.

That's a rule for make on how to make file.  File depends on Makefile and
[some file names].  I could go on for awhile on how make works on your typical
system since make is a fairly powerful utility.  It sure beats doing cc by
hand all the time.

>How do you 'run' the 'Makefile' program?  Please help.  Thanks.

The command to execute a makefile is called make.  When you do a 'make' it
goes through the makefile and executes the necessary commands to make the
program.  I don't know the differences between 1.5.10 and 1.3, but I'd assume
that the semantics would be the same.  Say you only wanted to make the fs
module, well, there's a rule in the makefile which tells the make proggram how
to make fs.  So to make the fs, you do the following from your shell prompt:

make fs

Just be sure you're in the directory where the makefile in question lies.  If
you want to know what make is going to do, but not execute any of the
commands, you can do this:

make -n

Make will print to standard output what it intends to do without doing it. 
See the man/help page for make or in the back of the text for more
information.

As for the memory problem, I'd bump up the memory to the maxmum on all the
compiler passes and make.

Ex.: chmem +64000 /usr/lib/asld

This should get you rolling.  If not, let us know, somebody will answer you.
 
     // JCA

 /*
 **--------------------------------------------------------------------------*
 ** Flames  : /dev/null                     | Small memory model only for
 ** ARPANET : crash!pnet01!jca@nosc.mil     | Unix?  Get the (*bleep*) out
 ** INTERNET: jca@pnet01.cts.com            | of here!
 ** UUCP    : {nosc ucsd hplabs!hd-sdd}!crash!pnet01!jca
 **--------------------------------------------------------------------------*
 */