470 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			470 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*************************************************************************
 | 
						|
 *
 | 
						|
 *  m a k e :   i n p u t . c
 | 
						|
 *
 | 
						|
 *  Parse a makefile
 | 
						|
 *========================================================================
 | 
						|
 * Edition history
 | 
						|
 *
 | 
						|
 *  #    Date                         Comments                       By
 | 
						|
 * --- -------- ---------------------------------------------------- ---
 | 
						|
 *   1    ??                                                         ??
 | 
						|
 *   2 23.08.89 new name tree structure introduced to speed up make,
 | 
						|
 *              testname introduced to shrink the memory usage       RAL
 | 
						|
 *   3 30.08.89 indention changed                                    PSH,RAL
 | 
						|
 *   4 03.09.89 fixed LZ eliminated                                  RAL
 | 
						|
 *   5 06.09.89 ; command added                                      RAL
 | 
						|
 * ------------ Version 2.0 released ------------------------------- RAL
 | 
						|
 *
 | 
						|
 *************************************************************************/
 | 
						|
 | 
						|
 | 
						|
#include "h.h"
 | 
						|
 | 
						|
 | 
						|
static struct name *lastrrp;
 | 
						|
static struct name *freerp = (struct name *)NULL;
 | 
						|
 | 
						|
void init()
 | 
						|
{
 | 
						|
  if( (suffparray = (struct name **) malloc( sizesuffarray *
 | 
						|
           sizeof(struct name *)))  == (struct name **) NULL)
 | 
						|
     fatal("No memory for suffarray",(char *)0,0);
 | 
						|
  if ((*suffparray = (struct name *)malloc(sizeof (struct name)))
 | 
						|
                          == (struct name *)0)
 | 
						|
     fatal("No memory for name",(char *)0,0);
 | 
						|
  (*suffparray)->n_next = (struct name *)0;
 | 
						|
 | 
						|
  if ((str1 = (char *) malloc(LZ1)) == ((char *)0))
 | 
						|
     fatal("No memory for str1",(char *)0,0);
 | 
						|
  str1s.ptr = &str1;
 | 
						|
  str1s.len = LZ1;
 | 
						|
  if ((str2 = (char *) malloc(LZ2)) == (char *)0)
 | 
						|
     fatal("No memory for str2",(char *)0,0);
 | 
						|
  str2s.ptr = &str2;
 | 
						|
  str2s.len = LZ2;
 | 
						|
}
 | 
						|
 | 
						|
void strrealloc(strs)
 | 
						|
struct str *strs;
 | 
						|
{
 | 
						|
  strs->len *= 2;
 | 
						|
  *strs->ptr = (char *) realloc(*strs->ptr, strs->len + 16);
 | 
						|
  if(*strs->ptr == (char *) NULL)
 | 
						|
       fatal("No memory for string reallocation",(char *)0,0);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *	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;
 | 
						|
 | 
						|
  register int           i;
 | 
						|
  register char         *suff;   /* ptr. to suffix in current name */
 | 
						|
  register struct name **sp;     /* ptr. to ptr. to chain of names */
 | 
						|
 | 
						|
  if ( (suff = suffix(name)) != (char *)NULL) {
 | 
						|
     for (i = 1, sp = suffparray, sp++;
 | 
						|
          i <= maxsuffarray && strcmp(suff, (*sp)->n_name) != 0;
 | 
						|
          sp++,i++);
 | 
						|
     if (i > maxsuffarray) {
 | 
						|
        if ( i >= sizesuffarray) { /* must realloc suffarray */
 | 
						|
           sizesuffarray *= 2;
 | 
						|
           if( (suffparray = (struct name **) realloc((char *) suffparray,
 | 
						|
                sizesuffarray * sizeof(struct name *))) == (struct name **) NULL)
 | 
						|
              fatal("No memory for suffarray",(char *)0,0);
 | 
						|
        }
 | 
						|
        maxsuffarray++;
 | 
						|
        sp = &suffparray[i];
 | 
						|
        if ((*sp = (struct name *)malloc(sizeof (struct name)))
 | 
						|
                                   == (struct name *)0)
 | 
						|
           fatal("No memory for name",(char *)0,0);
 | 
						|
        (*sp)->n_next = (struct name *)0;
 | 
						|
        if ((cp = (char *) malloc(strlen(suff)+1)) == (char *)0)
 | 
						|
           fatal("No memory for name",(char *)0,0);
 | 
						|
        strcpy(cp, suff);
 | 
						|
        (*sp)->n_name = cp;
 | 
						|
     }
 | 
						|
  }
 | 
						|
  else
 | 
						|
     sp = suffparray;
 | 
						|
 | 
						|
  for ( rp = (*sp)->n_next, rrp = *sp; rp; rp = rp->n_next, rrp = rrp->n_next )
 | 
						|
     if (strcmp(name, rp->n_name) == 0)  return rp;
 | 
						|
 | 
						|
  if ( freerp ==  (struct name *)NULL) {
 | 
						|
     if ((rp = (struct name *)malloc(sizeof (struct name))) == (struct name *)0)
 | 
						|
        fatal("No memory for name",(char *)0,0);
 | 
						|
  }
 | 
						|
  else  {
 | 
						|
     rp = freerp;
 | 
						|
     freerp =  (struct name *)NULL;
 | 
						|
  }
 | 
						|
  rrp->n_next = rp;
 | 
						|
  rp->n_next = (struct name *)0;
 | 
						|
  if ((cp = (char *) malloc(strlen(name)+1)) == (char *)0)
 | 
						|
     fatal("No memory for name",(char *)0,0);
 | 
						|
  strcpy(cp, name);
 | 
						|
  rp->n_name = cp;
 | 
						|
  rp->n_line = (struct line *)0;
 | 
						|
  rp->n_time = (time_t)0;
 | 
						|
  rp->n_flag = 0;
 | 
						|
  lastrrp = rrp;
 | 
						|
 | 
						|
  return rp;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *     Test a name.
 | 
						|
 *     If the name already exists return the ptr. to its name structure.
 | 
						|
 *     Else if the file exists 'intern' the name and return the ptr.
 | 
						|
 *     Otherwise don't waste memory and return a NULL pointer
 | 
						|
 */
 | 
						|
struct name *testname(name)
 | 
						|
char *name;
 | 
						|
{
 | 
						|
  register struct name *rp;
 | 
						|
 | 
						|
  lastrrp = (struct name *)NULL;
 | 
						|
  rp = newname( name);
 | 
						|
  if (rp->n_line || rp->n_flag & N_EXISTS)
 | 
						|
     return(rp);
 | 
						|
  modtime(rp);
 | 
						|
  if (rp->n_flag & N_EXISTS)
 | 
						|
     return(rp);
 | 
						|
  if (lastrrp != (struct name *)NULL) {
 | 
						|
     free (rp->n_name);
 | 
						|
     lastrrp->n_next = (struct name *)NULL;
 | 
						|
     freerp = rp;
 | 
						|
  }
 | 
						|
  return((struct name *)NULL);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	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",(char *)0,0);
 | 
						|
  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 = strrchr(str, '\n'))  *rcp = '\0';	/*  Loose newline  */
 | 
						|
 | 
						|
  while (isspace(*str))  str++;
 | 
						|
 | 
						|
  if (*str == '\0')  return cp;		/*  If nothing left, the exit  */
 | 
						|
 | 
						|
  if ((rp = (struct cmd *)malloc(sizeof (struct cmd))) == (struct cmd *)0)
 | 
						|
	fatal("No memory for command",(char *)0,0);
 | 
						|
  rp->c_next = (struct cmd *)0;
 | 
						|
  if ((rcp = (char *) malloc(strlen(str)+1)) == (char *)0)
 | 
						|
	fatal("No memory for command",(char *)0,0);
 | 
						|
  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;
 | 
						|
int            flag;
 | 
						|
{
 | 
						|
  bool                  hascmds = FALSE;  /*  Target has commands  */
 | 
						|
  register struct line *rp;
 | 
						|
  register struct line *rrp;
 | 
						|
 | 
						|
 | 
						|
  /* Handle the .SUFFIXES case */
 | 
						|
  if (np->n_name[0] == '.' && !dp && !cp) {
 | 
						|
	for (rp = np->n_line; rp; rp = rrp) {
 | 
						|
		rrp = rp->l_next;
 | 
						|
		free(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",(char *)0,0);
 | 
						|
  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;
 | 
						|
  register char *a;
 | 
						|
  struct name   *np;
 | 
						|
  struct depend *dp;
 | 
						|
  struct cmd    *cp;
 | 
						|
  bool dbl;
 | 
						|
 | 
						|
 | 
						|
  if (getline(&str1s, fd))  return;	/*  Read the first line  */
 | 
						|
 | 
						|
  for(;;) {
 | 
						|
	if (*str1 == TABCHAR)	/*  Rules without targets  */
 | 
						|
		error("Rules not allowed here",(char *)0);
 | 
						|
 | 
						|
	p = str1;
 | 
						|
 | 
						|
	while (isspace(*p))  p++;	/*  Find first target  */
 | 
						|
 | 
						|
 | 
						|
	while (((q = strchr(p, '+')) != (char *)0) &&
 | 
						|
	    (q[1] == '=') && (p != q) && (q[-1] == '\\'))	/*  Find value */
 | 
						|
	{
 | 
						|
		a = q - 1;	/*  Del \ chr; move rest back  */
 | 
						|
		p = q;
 | 
						|
		while(*a++ = *q++)
 | 
						|
			;
 | 
						|
	}
 | 
						|
 | 
						|
	if (q != (char *)0 && q[1] == '=') {
 | 
						|
 | 
						|
		*q++ = '\0';		/*  Separate name and val  */
 | 
						|
		*q++ = '\0';		/*  Separate name and val  */
 | 
						|
		while (isspace(*q))
 | 
						|
			q++;
 | 
						|
		if (p = strrchr(q, '\n'))
 | 
						|
			*p = '\0';
 | 
						|
 | 
						|
		p = str1;
 | 
						|
		if ((a = gettok(&p)) == (char *)0)
 | 
						|
			error("No macro name",(char *)0);
 | 
						|
 | 
						|
		addmacro(a, q);
 | 
						|
 | 
						|
		if (getline(&str1s, fd))
 | 
						|
			return;
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	while (((q = strchr(p, '=')) != (char *)0) &&
 | 
						|
	    (p != q) && (q[-1] == '\\'))	/*  Find value */
 | 
						|
	{
 | 
						|
		a = q - 1;	/*  Del \ chr; move rest back  */
 | 
						|
		p = q;
 | 
						|
		while(*a++ = *q++)
 | 
						|
			;
 | 
						|
	}
 | 
						|
 | 
						|
	if (q != (char *)0) {
 | 
						|
 | 
						|
		*q++ = '\0';		/*  Separate name and val  */
 | 
						|
		while (isspace(*q))
 | 
						|
			q++;
 | 
						|
		if (p = strrchr(q, '\n'))
 | 
						|
			*p = '\0';
 | 
						|
 | 
						|
		p = str1;
 | 
						|
		if ((a = gettok(&p)) == (char *)0)
 | 
						|
			error("No macro name",(char *)0);
 | 
						|
 | 
						|
		setmacro(a, q);
 | 
						|
 | 
						|
		if (getline(&str1s, fd))
 | 
						|
			return;
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
 | 
						|
	/* include? */
 | 
						|
	p = str1;
 | 
						|
	while (isspace(*p)) p++;
 | 
						|
	if (strncmp(p, "include", 7) == 0 && isspace(p[7])) {
 | 
						|
		char *old_makefile = makefile;
 | 
						|
		int old_lineno = lineno;
 | 
						|
		FILE *ifd;
 | 
						|
 | 
						|
		p += 8;
 | 
						|
		memmove(str1, p, strlen(p)+1);
 | 
						|
		expand(&str1s);
 | 
						|
		p = str1;
 | 
						|
		while (isspace(*p)) p++;
 | 
						|
 | 
						|
		if ((q = malloc(strlen(p)+1)) == (char *)0)
 | 
						|
			fatal("No memory for include",(char *)0,0);
 | 
						|
 | 
						|
		strcpy(q, p);
 | 
						|
		p = q;
 | 
						|
		while ((makefile = gettok(&q)) != (char *)0) {
 | 
						|
			if ((ifd = fopen(makefile, "r")) == (FILE *)0)
 | 
						|
				fatal("Can't open %s: %s", makefile, errno);
 | 
						|
			lineno = 0;
 | 
						|
			input(ifd);
 | 
						|
			fclose(ifd);
 | 
						|
		}
 | 
						|
		free(p);
 | 
						|
		makefile = old_makefile;
 | 
						|
		lineno = old_lineno;
 | 
						|
 | 
						|
		if (getline(&str1s, fd))
 | 
						|
			return;
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Search for commands on target line --- do not expand them ! */
 | 
						|
	q = str1;
 | 
						|
	cp = (struct cmd *)0;
 | 
						|
	if ((a = strchr(q, ';')) != (char *)0) {
 | 
						|
		*a++ = '\0';	/*  Separate dependents and commands */
 | 
						|
		if ( a) cp = newcmd(a, cp);
 | 
						|
	}
 | 
						|
 | 
						|
	expand(&str1s);
 | 
						|
	p = str1;
 | 
						|
 | 
						|
	while (isspace(*p)) p++;
 | 
						|
 | 
						|
	while (((q = strchr(p, ':')) != (char *)0) &&
 | 
						|
	    (p != q) && (q[-1] == '\\'))	/*  Find dependents  */
 | 
						|
	{
 | 
						|
		a = q - 1;	/*  Del \ chr; move rest back  */
 | 
						|
		p = q;
 | 
						|
		while(*a++ = *q++) ;
 | 
						|
	}
 | 
						|
 | 
						|
	if (q == (char *)0)
 | 
						|
		error("No targets provided",(char *)0);
 | 
						|
 | 
						|
	*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)  */
 | 
						|
 | 
						|
	if (getline(&str2s, fd) == FALSE) {		/*  Get commands  */
 | 
						|
		while (*str2 == TABCHAR) {
 | 
						|
			cp = newcmd(&str2[0], cp);
 | 
						|
			if (getline(&str2s, 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;
 | 
						|
 | 
						|
	while (strlen(str2) >= str1s.len) strrealloc(&str1s);
 | 
						|
	strcpy(str1, str2);
 | 
						|
  }
 | 
						|
}
 |