343 lines
6.5 KiB
C
343 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);
|
||
|
}
|
||
|
}
|