482 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			482 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *	Do the actual making for make
 | 
						|
 *
 | 
						|
 *	$Header$
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#ifdef unix
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <errno.h>
 | 
						|
#endif
 | 
						|
#ifdef eon
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <sys/err.h>
 | 
						|
#endif
 | 
						|
#ifdef os9
 | 
						|
#include <time.h>
 | 
						|
#include <os9.h>
 | 
						|
#include <modes.h>
 | 
						|
#include <direct.h>
 | 
						|
#include <errno.h>
 | 
						|
#endif
 | 
						|
#include "h.h"
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Exec a shell that returns exit status correctly (/bin/esh).
 | 
						|
 *	The standard EON shell returns the process number of the last
 | 
						|
 *	async command, used by the debugger (ugg).
 | 
						|
 *	[exec on eon is like a fork+exec on unix]
 | 
						|
 */
 | 
						|
int
 | 
						|
dosh(string, shell)
 | 
						|
char *			string;
 | 
						|
char *			shell;
 | 
						|
{
 | 
						|
	int	number;
 | 
						|
 | 
						|
#ifdef unix
 | 
						|
	return system(string);
 | 
						|
#endif
 | 
						|
#ifdef eon
 | 
						|
	return ((number = execl(shell, shell,"-c", string, 0)) == -1) ?
 | 
						|
		-1:	/* couldn't start the shell */
 | 
						|
		wait(number);	/* return its exit status */
 | 
						|
#endif
 | 
						|
#ifdef os9
 | 
						|
	int	status, pid;
 | 
						|
 | 
						|
	strcat(string, "\n");
 | 
						|
	if ((number = os9fork(shell, strlen(string), string, 0, 0, 0)) == -1)
 | 
						|
		return -1;		/* Couldn't start a shell */
 | 
						|
	do
 | 
						|
	{
 | 
						|
		if ((pid = wait(&status)) == -1)
 | 
						|
			return -1;	/* child already died!?!? */
 | 
						|
	} while (pid != number);
 | 
						|
 | 
						|
	return status;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Do commands to make a target
 | 
						|
 */
 | 
						|
void
 | 
						|
docmds1(np, lp)
 | 
						|
struct name *		np;
 | 
						|
struct line *		lp;
 | 
						|
{
 | 
						|
	bool			ssilent;
 | 
						|
	bool			signore;
 | 
						|
	int			estat;
 | 
						|
	register char *		q;
 | 
						|
	register char *		p;
 | 
						|
	char *			shell;
 | 
						|
	register struct cmd *	cp;
 | 
						|
 | 
						|
 | 
						|
	if (*(shell = getmacro("SHELL")) == '\0')
 | 
						|
#ifdef eon
 | 
						|
		shell = ":bin/esh";
 | 
						|
#endif
 | 
						|
#ifdef unix
 | 
						|
		shell = "/bin/sh";
 | 
						|
#endif
 | 
						|
#ifdef os9
 | 
						|
		shell = "shell";
 | 
						|
#endif
 | 
						|
 | 
						|
	for (cp = lp->l_cmd; cp; cp = cp->c_next)
 | 
						|
	{
 | 
						|
		strcpy(str1, cp->c_cmd);
 | 
						|
		expand(str1);
 | 
						|
		q = str1;
 | 
						|
		ssilent = silent;
 | 
						|
		signore = ignore;
 | 
						|
		while ((*q == '@') || (*q == '-'))
 | 
						|
		{
 | 
						|
			if (*q == '@')	   /*  Specific silent  */
 | 
						|
				ssilent = TRUE;
 | 
						|
			else		   /*  Specific ignore  */
 | 
						|
				signore = TRUE;
 | 
						|
			q++;		   /*  Not part of the command  */
 | 
						|
		}
 | 
						|
 | 
						|
		if (!domake)
 | 
						|
			ssilent = 0;
 | 
						|
 | 
						|
		if (!ssilent)
 | 
						|
			fputs("    ", stdout);
 | 
						|
 | 
						|
		for (p=q; *p; p++)
 | 
						|
		{
 | 
						|
			if (*p == '\n' && p[1] != '\0')
 | 
						|
			{
 | 
						|
				*p = ' ';
 | 
						|
				if (!ssilent)
 | 
						|
					fputs("\\\n", stdout);
 | 
						|
			}
 | 
						|
			else if (!ssilent)
 | 
						|
				putchar(*p);
 | 
						|
		}
 | 
						|
		if (!ssilent) {
 | 
						|
			putchar('\n');
 | 
						|
			fflush(stdout);
 | 
						|
		}
 | 
						|
 | 
						|
		if (domake)
 | 
						|
		{			/*  Get the shell to execute it  */
 | 
						|
			if ((estat = dosh(q, shell)) != 0)
 | 
						|
			{
 | 
						|
				if (estat == -1)
 | 
						|
					fatal("Couldn't execute %s", shell);
 | 
						|
				else
 | 
						|
				{
 | 
						|
					printf("%s: Error code %d", myname, estat);
 | 
						|
					if (signore)
 | 
						|
						fputs(" (Ignored)\n", stdout);
 | 
						|
					else
 | 
						|
					{
 | 
						|
						putchar('\n');
 | 
						|
						if (!(np->n_flag & N_PREC))
 | 
						|
							if (unlink(np->n_name) == 0)
 | 
						|
								printf("%s: '%s' removed.\n", myname, np->n_name);
 | 
						|
						exit(1);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				fflush(stdout);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
docmds(np)
 | 
						|
struct name *		np;
 | 
						|
{
 | 
						|
	register struct line *	lp;
 | 
						|
 | 
						|
 | 
						|
	for (lp = np->n_line; lp; lp = lp->l_next)
 | 
						|
		docmds1(np, lp);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef os9
 | 
						|
/*
 | 
						|
 *	Some stuffing around to get the modified time of a file
 | 
						|
 *	in an os9 file system
 | 
						|
 */
 | 
						|
getmdate(fd, tbp)
 | 
						|
struct sgtbuf *		tbp;
 | 
						|
{
 | 
						|
	struct registers	regs;
 | 
						|
	static struct fildes	fdbuf;
 | 
						|
 | 
						|
 | 
						|
	regs.rg_a = fd;
 | 
						|
	regs.rg_b = SS_FD;
 | 
						|
	regs.rg_x = &fdbuf;
 | 
						|
	regs.rg_y = sizeof (fdbuf);
 | 
						|
 | 
						|
	if (_os9(I_GETSTT, ®s) == -1)
 | 
						|
	{
 | 
						|
		errno = regs.rg_b & 0xff;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	if (tbp)
 | 
						|
	{
 | 
						|
		_strass(tbp, fdbuf.fd_date, sizeof (fdbuf.fd_date));
 | 
						|
		tbp->t_second = 0;	/* Files are only acurate to mins */
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Kludge routine to return an aproximation of how many
 | 
						|
 *	seconds since 1980.  Dates will be in order, but will not
 | 
						|
 *	be lineer
 | 
						|
 */
 | 
						|
time_t
 | 
						|
cnvtime(tbp)
 | 
						|
struct sgtbuf		*tbp;
 | 
						|
{
 | 
						|
	long			acc;
 | 
						|
 | 
						|
 | 
						|
	acc = tbp->t_year - 80;		/* Baseyear is 1980 */
 | 
						|
	acc = acc * 12 + tbp->t_month;
 | 
						|
	acc = acc * 31 + tbp->t_day;
 | 
						|
	acc = acc * 24 + tbp->t_hour;
 | 
						|
	acc = acc * 60 + tbp->t_minute;
 | 
						|
	acc = acc * 60 + tbp->t_second;
 | 
						|
 | 
						|
	return acc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Get the current time in the internal format
 | 
						|
 */
 | 
						|
time(tp)
 | 
						|
time_t *		tp;
 | 
						|
{
 | 
						|
	struct sgtbuf		tbuf;
 | 
						|
 | 
						|
 | 
						|
	if (getime(&tbuf) < 0)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	if (tp)
 | 
						|
		*tp = cnvtime(&tbuf);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Get the modification time of a file.  If the first
 | 
						|
 *	doesn't exist, it's modtime is set to 0.
 | 
						|
 */
 | 
						|
void
 | 
						|
modtime(np)
 | 
						|
struct name *		np;
 | 
						|
{
 | 
						|
#ifdef unix
 | 
						|
	struct stat		info;
 | 
						|
 | 
						|
 | 
						|
	if (stat(np->n_name, &info) < 0)
 | 
						|
	{
 | 
						|
		if (errno != ENOENT)
 | 
						|
			fatal("Can't open %s; error %d", np->n_name, errno);
 | 
						|
 | 
						|
		np->n_time = 0L;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		np->n_time = info.st_mtime;
 | 
						|
#endif
 | 
						|
#ifdef eon
 | 
						|
	struct stat		info;
 | 
						|
	int			fd;
 | 
						|
 | 
						|
 | 
						|
	if ((fd = open(np->n_name, 0)) < 0)
 | 
						|
	{
 | 
						|
		if (errno != ER_NOTF)
 | 
						|
			fatal("Can't open %s; error %02x", np->n_name, errno);
 | 
						|
 | 
						|
		np->n_time = 0L;
 | 
						|
	}
 | 
						|
	else if (getstat(fd, &info) < 0)
 | 
						|
		fatal("Can't getstat %s; error %02x", np->n_name, errno);
 | 
						|
	else
 | 
						|
		np->n_time = info.st_mod;
 | 
						|
 | 
						|
	close(fd);
 | 
						|
#endif
 | 
						|
#ifdef os9
 | 
						|
	struct sgtbuf		info;
 | 
						|
	int			fd;
 | 
						|
 | 
						|
 | 
						|
	if ((fd = open(np->n_name, 0)) < 0)
 | 
						|
	{
 | 
						|
		if (errno != E_PNNF)
 | 
						|
			fatal("Can't open %s; error %02x", np->n_name, errno);
 | 
						|
 | 
						|
		np->n_time = 0L;
 | 
						|
	}
 | 
						|
	else if (getmdate(fd, &info) < 0)
 | 
						|
		fatal("Can't getstat %s; error %02x", np->n_name, errno);
 | 
						|
	else
 | 
						|
		np->n_time = cnvtime(&info);
 | 
						|
 | 
						|
	close(fd);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Update the mod time of a file to now.
 | 
						|
 */
 | 
						|
void
 | 
						|
touch(np)
 | 
						|
struct name *		np;
 | 
						|
{
 | 
						|
	char			c;
 | 
						|
	int			fd;
 | 
						|
 | 
						|
 | 
						|
	if (!domake || !silent)
 | 
						|
		printf("    touch(%s)\n", np->n_name);
 | 
						|
 | 
						|
	if (domake)
 | 
						|
	{
 | 
						|
#ifdef unix
 | 
						|
		long		a[2];
 | 
						|
		long		time();
 | 
						|
 | 
						|
		a[0] = a[1] = time((long *)0);
 | 
						|
		if (utime(np->n_name, &a[0]) < 0)
 | 
						|
			printf("%s: '%s' not touched - non-existant\n",
 | 
						|
					myname, np->n_name);
 | 
						|
#endif
 | 
						|
#ifdef eon
 | 
						|
		if ((fd = open(np->n_name, 0)) < 0)
 | 
						|
			printf("%s: '%s' not touched - non-existant\n",
 | 
						|
					myname, np->n_name);
 | 
						|
		else
 | 
						|
		{
 | 
						|
			uread(fd, &c, 1, 0);
 | 
						|
			uwrite(fd, &c, 1);
 | 
						|
		}
 | 
						|
		close(fd);
 | 
						|
#endif
 | 
						|
#ifdef os9
 | 
						|
		/*
 | 
						|
		 *	Strange that something almost as totally useless
 | 
						|
		 *	as this is easy to do in os9!
 | 
						|
		 */
 | 
						|
		if ((fd = open(np->n_name, S_IWRITE)) < 0)
 | 
						|
			printf("%s: '%s' not touched - non-existant\n",
 | 
						|
					myname, np->n_name);
 | 
						|
		close(fd);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Recursive routine to make a target.
 | 
						|
 */
 | 
						|
int
 | 
						|
make(np, level)
 | 
						|
struct name *		np;
 | 
						|
int			level;
 | 
						|
{
 | 
						|
	register struct depend *	dp;
 | 
						|
	register struct line *		lp;
 | 
						|
	register struct depend *	qdp;
 | 
						|
	time_t				dtime = 1;
 | 
						|
	bool				didsomething = 0;
 | 
						|
	int				dynamic = 0;
 | 
						|
 | 
						|
 | 
						|
	if (np->n_flag & N_DONE)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (!np->n_time)
 | 
						|
		modtime(np);		/*  Gets modtime of this file  */
 | 
						|
 | 
						|
	if (rules)
 | 
						|
	{
 | 
						|
		for (lp = np->n_line; lp; lp = lp->l_next)
 | 
						|
			if (lp->l_cmd)
 | 
						|
				break;
 | 
						|
		if (!lp) {
 | 
						|
			dyndep(np);
 | 
						|
			dynamic = 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!(np->n_flag & N_TARG) && np->n_time == 0L)
 | 
						|
		fatal("Don't know how to make %s", np->n_name);
 | 
						|
 | 
						|
	for (qdp = (struct depend *)0, lp = np->n_line; lp; lp = lp->l_next)
 | 
						|
	{
 | 
						|
		for (dp = lp->l_dep; dp; dp = dp->d_next)
 | 
						|
		{
 | 
						|
			char *sv = 0;
 | 
						|
			if (dynamic) {
 | 
						|
				char *s = getmacro("<");
 | 
						|
 | 
						|
				if (s) {
 | 
						|
					sv = malloc((unsigned)(strlen(s)+1));
 | 
						|
					if (!sv) {
 | 
						|
						fatal("no space for saved $<");
 | 
						|
					}
 | 
						|
					strcpy(sv, s);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			make(dp->d_name, level+1);
 | 
						|
			if (dynamic && sv) {
 | 
						|
				setmacro("<", sv, 4);
 | 
						|
				free(sv);
 | 
						|
			}
 | 
						|
			if (np->n_time < dp->d_name->n_time)
 | 
						|
				qdp = newdep(dp->d_name, qdp);
 | 
						|
			dtime = max(dtime, dp->d_name->n_time);
 | 
						|
		}
 | 
						|
		if (!quest && (np->n_flag & N_DOUBLE) && (np->n_time < dtime))
 | 
						|
		{
 | 
						|
			make1(np, lp, qdp);	/* free()'s qdp */
 | 
						|
			dtime = 1;
 | 
						|
			qdp = (struct depend *)0;
 | 
						|
			didsomething++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	np->n_flag |= N_DONE;
 | 
						|
 | 
						|
	if (quest)
 | 
						|
	{
 | 
						|
		long		t;
 | 
						|
 | 
						|
		t = np->n_time;
 | 
						|
		time(&np->n_time);
 | 
						|
		return t < dtime;
 | 
						|
	}
 | 
						|
	else if (np->n_time < dtime && !(np->n_flag & N_DOUBLE))
 | 
						|
	{
 | 
						|
		make1(np, (struct line *)0, qdp);	/* free()'s qdp */
 | 
						|
		time(&np->n_time);
 | 
						|
	}
 | 
						|
	else if (level == 0 && !didsomething)
 | 
						|
		printf("%s: '%s' is up to date\n", myname, np->n_name);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
make1(np, lp, qdp)
 | 
						|
register struct depend *	qdp;
 | 
						|
struct line *			lp;
 | 
						|
struct name *			np;
 | 
						|
{
 | 
						|
	register struct depend *	dp;
 | 
						|
	register char *p;
 | 
						|
	char *rindex();
 | 
						|
 | 
						|
 | 
						|
	if (dotouch)
 | 
						|
		touch(np);
 | 
						|
	else
 | 
						|
	{
 | 
						|
		strcpy(str1, "");
 | 
						|
		for (dp = qdp; dp; dp = qdp)
 | 
						|
		{
 | 
						|
			if (strlen(str1))
 | 
						|
				strcat(str1, " ");
 | 
						|
			strcat(str1, dp->d_name->n_name);
 | 
						|
			qdp = dp->d_next;
 | 
						|
			free((char *)dp);
 | 
						|
		}
 | 
						|
		setmacro("?", str1, 4);
 | 
						|
		setmacro("@", np->n_name, 4);
 | 
						|
		p = rindex(np->n_name, '.');
 | 
						|
		if (p) *p = 0;
 | 
						|
		setmacro("*", np->n_name, 4);
 | 
						|
		if (p) *p = '.';
 | 
						|
		if (lp)		/* lp set if doing a :: rule */
 | 
						|
			docmds1(np, lp);
 | 
						|
		else
 | 
						|
			docmds(np);
 | 
						|
	}
 | 
						|
}
 |