342 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *	Parse a makefile
 | 
						|
 *
 | 
						|
 *	$Header$
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include	<ctype.h>
 | 
						|
#include "h.h"
 | 
						|
 | 
						|
 | 
						|
struct name		namehead;
 | 
						|
struct name *		firstname;
 | 
						|
 | 
						|
char 			str1[LZ];		/*  General store  */
 | 
						|
char			str2[LZ];
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Intern a name.  Return a pointer to the name struct
 | 
						|
 */
 | 
						|
struct name *
 | 
						|
newname(name)
 | 
						|
char *			name;
 | 
						|
{
 | 
						|
	register struct name *	rp;
 | 
						|
	register struct name *	rrp;
 | 
						|
	register char *		cp;
 | 
						|
 | 
						|
 | 
						|
	for
 | 
						|
	(
 | 
						|
		rp = namehead.n_next, rrp = &namehead;
 | 
						|
		rp;
 | 
						|
		rp = rp->n_next, rrp = rrp->n_next
 | 
						|
	)
 | 
						|
		if (strcmp(name, rp->n_name) == 0)
 | 
						|
			return rp;
 | 
						|
 | 
						|
	if ((rp = (struct name *)malloc(sizeof (struct name)))
 | 
						|
				== (struct name *)0)
 | 
						|
		fatal("No memory for name");
 | 
						|
	rrp->n_next = rp;
 | 
						|
	rp->n_next = (struct name *)0;
 | 
						|
	if ((cp = malloc((unsigned)(strlen(name)+1))) == (char *)0)
 | 
						|
		fatal("No memory for name");
 | 
						|
	strcpy(cp, name);
 | 
						|
	rp->n_name = cp;
 | 
						|
	rp->n_line = (struct line *)0;
 | 
						|
	rp->n_time = (time_t)0;
 | 
						|
	rp->n_flag = 0;
 | 
						|
 | 
						|
	return rp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Add a dependant to the end of the supplied list of dependants.
 | 
						|
 *	Return the new head pointer for that list.
 | 
						|
 */
 | 
						|
struct depend *
 | 
						|
newdep(np, dp)
 | 
						|
struct name *		np;
 | 
						|
struct depend *		dp;
 | 
						|
{
 | 
						|
	register struct depend *	rp;
 | 
						|
	register struct depend *	rrp;
 | 
						|
 | 
						|
 | 
						|
	if ((rp = (struct depend *)malloc(sizeof (struct depend)))
 | 
						|
				== (struct depend *)0)
 | 
						|
		fatal("No memory for dependant");
 | 
						|
	rp->d_next = (struct depend *)0;
 | 
						|
	rp->d_name = np;
 | 
						|
 | 
						|
	if (dp == (struct depend *)0)
 | 
						|
		return rp;
 | 
						|
 | 
						|
	for (rrp = dp; rrp->d_next; rrp = rrp->d_next)
 | 
						|
		;
 | 
						|
 | 
						|
	rrp->d_next = rp;
 | 
						|
 | 
						|
	return dp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Add a command to the end of the supplied list of commands.
 | 
						|
 *	Return the new head pointer for that list.
 | 
						|
 */
 | 
						|
struct cmd *
 | 
						|
newcmd(str, cp)
 | 
						|
char *			str;
 | 
						|
struct cmd *		cp;
 | 
						|
{
 | 
						|
	register struct cmd *	rp;
 | 
						|
	register struct cmd *	rrp;
 | 
						|
	register char *		rcp;
 | 
						|
 | 
						|
 | 
						|
	if (rcp = rindex(str, '\n'))
 | 
						|
		*rcp = '\0';		/*  Loose newline  */
 | 
						|
 | 
						|
	while (isspace(*str))
 | 
						|
		str++;
 | 
						|
 | 
						|
	if (*str == '\0')		/*  If nothing left, the exit  */
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if ((rp = (struct cmd *)malloc(sizeof (struct cmd)))
 | 
						|
				== (struct cmd *)0)
 | 
						|
		fatal("No memory for command");
 | 
						|
	rp->c_next = (struct cmd *)0;
 | 
						|
	if ((rcp = malloc((unsigned)(strlen(str)+1))) == (char *)0)
 | 
						|
		fatal("No memory for command");
 | 
						|
	strcpy(rcp, str);
 | 
						|
	rp->c_cmd = rcp;
 | 
						|
 | 
						|
	if (cp == (struct cmd *)0)
 | 
						|
		return rp;
 | 
						|
 | 
						|
	for (rrp = cp; rrp->c_next; rrp = rrp->c_next)
 | 
						|
		;
 | 
						|
 | 
						|
	rrp->c_next = rp;
 | 
						|
 | 
						|
	return cp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Add a new 'line' of stuff to a target.  This check to see
 | 
						|
 *	if commands already exist for the target.  If flag is set,
 | 
						|
 *	the line is a double colon target.
 | 
						|
 *
 | 
						|
 *	Kludges:
 | 
						|
 *	i)  If the new name begins with a '.', and there are no dependents,
 | 
						|
 *	    then the target must cease to be a target.  This is for .SUFFIXES.
 | 
						|
 *	ii) If the new name begins with a '.', with no dependents and has
 | 
						|
 *	    commands, then replace the current commands.  This is for
 | 
						|
 *	    redefining commands for a default rule.
 | 
						|
 *	Neither of these free the space used by dependents or commands,
 | 
						|
 *	since they could be used by another target.
 | 
						|
 */
 | 
						|
void
 | 
						|
newline(np, dp, cp, flag)
 | 
						|
struct name *		np;
 | 
						|
struct depend *		dp;
 | 
						|
struct cmd *		cp;
 | 
						|
{
 | 
						|
	bool			hascmds = FALSE;  /*  Target has commands  */
 | 
						|
	register struct line *	rp;
 | 
						|
	register struct line *	rrp;
 | 
						|
 | 
						|
 | 
						|
	/* Handle the .SUFFIXES case */
 | 
						|
	if (! strcmp(np->n_name, ".SUFFIXES") && !dp && !cp)
 | 
						|
	{
 | 
						|
		for (rp = np->n_line; rp; rp = rrp)
 | 
						|
		{
 | 
						|
			rrp = rp->l_next;
 | 
						|
			free((char *)rp);
 | 
						|
		}
 | 
						|
		np->n_line = (struct line *)0;
 | 
						|
		np->n_flag &= ~N_TARG;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* This loop must happen since rrp is used later. */
 | 
						|
	for
 | 
						|
	(
 | 
						|
		rp = np->n_line, rrp = (struct line *)0;
 | 
						|
		rp;
 | 
						|
		rrp = rp, rp = rp->l_next
 | 
						|
	)
 | 
						|
		if (rp->l_cmd)
 | 
						|
			hascmds = TRUE;
 | 
						|
 | 
						|
	if (hascmds && cp && !(np->n_flag & N_DOUBLE))
 | 
						|
		/* Handle the implicit rules redefinition case */
 | 
						|
		if (np->n_name[0] == '.' && dp == (struct depend *)0)
 | 
						|
		{
 | 
						|
			np->n_line->l_cmd = cp;
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			error("Commands defined twice for target %s", np->n_name);
 | 
						|
	if (np->n_flag & N_TARG)
 | 
						|
		if (!(np->n_flag & N_DOUBLE) != !flag)		/* like xor */
 | 
						|
			error("Inconsistent rules for target %s", np->n_name);
 | 
						|
 | 
						|
	if ((rp = (struct line *)malloc(sizeof (struct line)))
 | 
						|
				== (struct line *)0)
 | 
						|
		fatal("No memory for line");
 | 
						|
	rp->l_next = (struct line *)0;
 | 
						|
	rp->l_dep = dp;
 | 
						|
	rp->l_cmd = cp;
 | 
						|
 | 
						|
	if (rrp)
 | 
						|
		rrp->l_next = rp;
 | 
						|
	else
 | 
						|
		np->n_line = rp;
 | 
						|
 | 
						|
	np->n_flag |= N_TARG;
 | 
						|
	if (flag)
 | 
						|
		np->n_flag |= N_DOUBLE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	Parse input from the makefile, and construct a tree structure
 | 
						|
 *	of it.
 | 
						|
 */
 | 
						|
void
 | 
						|
input(fd)
 | 
						|
FILE *			fd;
 | 
						|
{
 | 
						|
	char *			p;		/*  General  */
 | 
						|
	char *			q;
 | 
						|
	struct name *		np;
 | 
						|
	struct depend *		dp;
 | 
						|
	struct cmd *		cp;
 | 
						|
	bool			dbl;
 | 
						|
 | 
						|
 | 
						|
	if (getline(str1, fd))	/*  Read the first line  */
 | 
						|
		return;
 | 
						|
 | 
						|
	for(;;)
 | 
						|
	{
 | 
						|
#ifdef os9
 | 
						|
		if (*str1 == ' ')	/*  Rules without targets  */
 | 
						|
#else
 | 
						|
		if (*str1 == '\t')	/*  Rules without targets  */
 | 
						|
#endif
 | 
						|
			error("Rules not allowed here");
 | 
						|
 | 
						|
		p = str1;
 | 
						|
 | 
						|
		while (isspace(*p))	/*  Find first target  */
 | 
						|
			p++;
 | 
						|
 | 
						|
		while (((q = index(p, '=')) != (char *)0) &&
 | 
						|
		    (p != q) && (q[-1] == '\\'))	/*  Find value */
 | 
						|
		{
 | 
						|
			register char *		a;
 | 
						|
 | 
						|
			a = q - 1;	/*  Del \ chr; move rest back  */
 | 
						|
			p = q;
 | 
						|
			while(*a++ = *q++)
 | 
						|
				;
 | 
						|
		}
 | 
						|
 | 
						|
		if (q != (char *)0)
 | 
						|
		{
 | 
						|
			register char *		a;
 | 
						|
 | 
						|
			*q++ = '\0';		/*  Separate name and val  */
 | 
						|
			while (isspace(*q))
 | 
						|
				q++;
 | 
						|
			if (p = rindex(q, '\n'))
 | 
						|
				*p = '\0';
 | 
						|
 | 
						|
			p = str1;
 | 
						|
			if ((a = gettok(&p)) == (char *)0)
 | 
						|
				error("No macro name");
 | 
						|
 | 
						|
			setmacro(a, q, 2);
 | 
						|
 | 
						|
			if (getline(str1, fd))
 | 
						|
				return;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		expand(str1);
 | 
						|
		p = str1;
 | 
						|
 | 
						|
		while (((q = index(p, ':')) != (char *)0) &&
 | 
						|
		    (p != q) && (q[-1] == '\\'))	/*  Find dependents  */
 | 
						|
		{
 | 
						|
			register char *		a;
 | 
						|
 | 
						|
			a = q - 1;	/*  Del \ chr; move rest back  */
 | 
						|
			p = q;
 | 
						|
			while(*a++ = *q++)
 | 
						|
				;
 | 
						|
		}
 | 
						|
 | 
						|
		if (q == (char *)0)
 | 
						|
			error("No targets provided");
 | 
						|
 | 
						|
		*q++ = '\0';	/*  Separate targets and dependents  */
 | 
						|
 | 
						|
		if (*q == ':')		/* Double colon */
 | 
						|
		{
 | 
						|
			dbl = 1;
 | 
						|
			q++;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			dbl = 0;
 | 
						|
 | 
						|
		for (dp = (struct depend *)0; ((p = gettok(&q)) != (char *)0);)
 | 
						|
					/*  get list of dep's */
 | 
						|
		{
 | 
						|
			np = newname(p);		/*  Intern name  */
 | 
						|
			dp = newdep(np, dp);		/*  Add to dep list */
 | 
						|
		}
 | 
						|
 | 
						|
		*((q = str1) + strlen(str1) + 1) = '\0';
 | 
						|
			/*  Need two nulls for gettok (Remember separation)  */
 | 
						|
 | 
						|
		cp = (struct cmd *)0;
 | 
						|
		if (getline(str2, fd) == FALSE)		/*  Get commands  */
 | 
						|
		{
 | 
						|
#ifdef os9
 | 
						|
			while (*str2 == ' ')
 | 
						|
#else
 | 
						|
			while (*str2 == '\t')
 | 
						|
#endif
 | 
						|
			{
 | 
						|
				cp = newcmd(&str2[0], cp);
 | 
						|
				if (getline(str2, fd))
 | 
						|
					break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		while ((p = gettok(&q)) != (char *)0)	/* Get list of targ's */
 | 
						|
		{
 | 
						|
			np = newname(p);		/*  Intern name  */
 | 
						|
			newline(np, dp, cp, dbl);
 | 
						|
			if (!firstname && p[0] != '.')
 | 
						|
				firstname = np;
 | 
						|
		}
 | 
						|
 | 
						|
		if (feof(fd))				/*  EOF?  */
 | 
						|
			return;
 | 
						|
 | 
						|
		strcpy(str1, str2);
 | 
						|
	}
 | 
						|
}
 |