From:	CSBVAX::CSBVAX::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 24-JAN-1989 01:17
To:	MRGATE::"ARISIA::EVERHART"
Subj:	MAKE.SHAR (part 2 of 5; repackaged)


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Mon, 23 JAN 89 18:55:21 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Mon, 23 Jan 89 18:54:33 PST
Received: by ucbvax.Berkeley.EDU (5.61/1.33)
	id AA12890; Mon, 23 Jan 89 18:38:42 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 23 Jan 89 17:38:10 GMT
From: tektronix!gvgpsa!gvgpvd!tony@ucbvax.Berkeley.EDU  (Tony Ivanov)
Organization: Grass Valley Group, Inc., Grass Valley, CA
Subject: MAKE.SHAR (part 2 of 5; repackaged)
Message-Id: <1012@gvgpvd.GVG.TEK.COM>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com


+-+-+-+ Beginning of part 2 +-+-+-+
X
X#include "h.h"
X
XNAME namehead;
XNAMEP firstname;
X
Xchar str1[MAXSTRING];`009`009/* global store */
Xstatic char str2[MAXSTRING];`009/* str2 needed only here */
X
X
X/*
X *`009Intern a name.  Return a pointer to the name struct
X */
XNAMEP
Xnewname(name)
Xchar *name;
X`123
X    register NAMEP rp;
X    register NAMEP rrp;
X
X
X    for
X`009(
X`009 rp = namehead.n_next, rrp = &namehead;
X`009 rp;
X`009 rp = rp->n_next, rrp = rrp->n_next
X`009)
X`009if (strcmp(name, rp->n_name) == 0)
X`009    return rp;
X
X    if ((rp = (NAMEP) malloc(sizeof(NAME))) == NULL_NAMEP)
X`009fatal("No memory for name");
X    rrp->n_next = rp;
X    rp->n_next = NULL_NAMEP;
X
X    rp->n_name = newstring(NULL_CHARP, name);
X    rp->n_line = NULL_LINEP;
X    rp->n_time = NOTIME;
X    rp->n_flag = (uchar) 0;
X
X    return rp;
X`125
X
X
X/*
X *`009Add a dependant to the end of the supplied list of dependants.
X *`009Return the new head pointer for that list.
X */
XDEPENDP
Xnewdep(np, dp)
XNAMEP np;
XDEPENDP dp;
X`123
X    register DEPENDP rp;
X    register DEPENDP rrp;
X
X
X    if ((rp = (DEPENDP) malloc(sizeof(DEPEND))) == NULL_DEPENDP)
X`009fatal("No memory for dependant");
X    rp->d_next = NULL_DEPENDP;
X    rp->d_name = np;
X
X    if (dp == NULL_DEPENDP)
X`009return rp;
X
X    for (rrp = dp; rrp->d_next; rrp = rrp->d_next)
X`009;
X
X    rrp->d_next = rp;
X
X    return dp;
X`125
X
X
X/*
X *`009Add a command to the end of the supplied list of commands.
X *`009Return the new head pointer for that list.
X */
XCMDP
Xnewcmd(str, cp)
Xchar *str;
XCMDP cp;
X`123
X    register CMDP rp;
X    register CMDP rrp;
X    register char *rcp;
X
X
X    if (rcp = rindex(str, '\n'))
X`009*rcp = '\0';`009`009/* Loose newline  */
X
X    while (isspace(*str))
X`009str++;
X
X    if (*str == '\0')`009`009/* If nothing left, the exit  */
X`009return ((CMDP) NULL);
X
X    if ((rp = (CMDP) malloc(sizeof(CMD))) == NULL_CMDP)
X`009fatal("No memory for command");
X    rp->c_next = NULL_CMDP;
X    rp->c_cmd = newstring(NULL_CHARP, str);
X
X    if (cp == NULL_CMDP)
X`009return rp;
X
X    for (rrp = cp; rrp->c_next; rrp = rrp->c_next)
X`009;
X
X    rrp->c_next = rp;
X
X    return cp;
X`125
X
X
X/*
X *`009Add a new 'line' of stuff to a target.  This check to see
X *`009if commands already exist for the target.  If flag is set,
X *`009the line is a double colon target.
X *
X *`009Kludges:
X *`009i)  If the new name begins with a '.', and there are no dependents,
X *`009    then the target must cease to be a target.  This is for .SUFFIXES.
X *`009ii) If the new name begins with a '.', with no dependents and has
X *`009    commands, then replace the current commands.  This is for
X *`009    redefining commands for a default rule.
X *`009Neither of these free the space used by dependents or commands,
X *`009since they could be used by another target.
X */
Xvoid
Xnewline(np, dp, cp, flag)
XNAMEP np;
XDEPENDP dp;
XCMDP cp;
Xbool flag;
X`123
X    bool hascmds = FALSE;`009/* Target has commands  */
X    register LINEP rp;
X    register LINEP rrp;
X
X
X    /* Handle the .SUFFIXES case */
X    if (np->n_name[0] == '.' && !dp && !cp)
X    `123
X`009for (rp = np->n_line; rp; rp = rrp)
X`009`123
X`009    rrp = rp->l_next;
X`009    free((char *) rp);
X`009`125
X`009np->n_line = NULL_LINEP;
X`009np->n_flag &= `126N_TARG;
X`009return;
X    `125
X
X    /* This loop must happen since rrp is used later. */
X    for
X`009(
X`009 rp = np->n_line, rrp = NULL_LINEP;
X`009 rp;
X`009 rrp = rp, rp = rp->l_next
X`009)
X`009if (rp->l_cmd)
X`009    hascmds = TRUE;
X
X    if (hascmds && cp && !(np->n_flag & N_DOUBLE))
X`009/* Handle the implicit rules redefinition case */
X`009if (np->n_name[0] == '.' && dp == NULL_DEPENDP)
X`009`123
X`009    np->n_line->l_cmd = cp;
X`009    return;
X`009`125
X`009else
X`009`123
X`009    sprintf(str1, "Commands defined twice for target %s",
X`009`009    np->n_name);
X`009    error(str1);
X`009`125
X    if (np->n_flag & N_TARG)
X`009if (!(np->n_flag & N_DOUBLE) != !flag)`009/* like xor */
X`009`123
X`009    sprintf(str1, "Inconsistent rules for target %s", np->n_name);
X`009    error(str1);
X`009`125
X
X    if ((rp = (LINEP) malloc(sizeof(LINE))) == NULL_LINEP)
X`009fatal("No memory for line");
X    rp->l_next = NULL_LINEP;
X    rp->l_dep = dp;
X    rp->l_cmd = cp;
X
X    if (rrp)
X`009rrp->l_next = rp;
X    else
X`009np->n_line = rp;
X
X    np->n_flag `124= N_TARG;
X    if (flag)
X`009np->n_flag `124= N_DOUBLE;
X`125
X
X
X/*
X *`009Parse input from the makefile, and construct a tree structure
X *`009of it.
X */
Xvoid
Xinput(fd)
XFILE *fd;
X`123
X    char *p;
X    char *q;
X    NAMEP np;
X    DEPENDP dp;
X    CMDP cp;
X    bool dbl;
X
X
X    if (getline(str1, fd))`009/* Read the first line and */
X`009return;`009`009`009/* quit if file is empty */
X
X    for (;;)
X    `123
X`009if (*str1 == TAB)`009/* Rules without targets  */
X`009    error("Rules not allowed here");
X
X`009p = str1;
X
X`009while (isspace(*p))`009/* Find first target  */
X`009    p++;
X
X`009/* Collect macro name. */
X
X`009while (((q = index(p, '=')) != NULL_CHARP) &&
X`009       (p != q) && (q[-1] == '\\'))`009/* Find value */
X`009    p = q + 1;`009`009/* point past "\=" */
X
X`009if (q != NULL_CHARP)
X`009`123
X`009    register char *a;
X
X`009    *q++ = '\0';`009/* Separate name and val  */
X`009    while (isspace(*q))
X`009`009q++;
X`009    if (p = rindex(q, '\n'))
X`009`009*p = '\0';
X
X`009    p = str1;
X`009    squeeze(p);
X
X`009    /* Don't squeeze q (macro value)--it will get squeeze'd later
X`009       after macro substitution */
X
X`009    if ((a = gettok(&p)) == NULL_CHARP)
X`009`009error("No macro name");
X
X`009    (void) setmacro(a, q, TEMPORARY);
X
X`009    if (getline(str1, fd))
X`009`009return;
X`009    continue;
X`009`125
X
X`009/* Collect dependent names. */
X
X`009expand(str1);
X`009p = str1;
X
X`009while (((q = index(p, ':')) != NULL_CHARP) &&
X`009       (p != q) && (q[-1] == '\\'))`009/* Find dependents  */
X`009    p = q + 1;`009`009/* point past "\:" */
X
X`009if (q == NULL_CHARP)
X`009    error("No targets provided");
X
X`009*q++ = '\0';`009`009/* Separate targets and dependents  */
X
X`009if (*q == ':')`009`009/* Double colon */
X`009`123
X`009    dbl = TRUE;
X`009    q++;
X`009`125
X`009else
X`009    dbl = FALSE;
X
X`009while (isspace(*q))`009/* advance to first non-space in */
X`009    ++q;`009`009/* dependent list */
X
X`009squeeze(q);
X
X`009cp = NULL_CMDP;
X`009dp = NULL_DEPENDP;
X
X`009if (*q == ';')`009`009/* have TARGET:; RULE */
X`009    cp = newcmd(q + 1, cp);
X`009else`009`009`009/* have TARGET: dependent list */
X`009    for ( /* NO-OP */ ; ((p = gettok(&q)) != NULL_CHARP);)
X`009`009/* get list of dep's */
X`009    `123
X`009`009np = newname(p);/* Intern name  */
X`009`009dp = newdep(np, dp);`009/* Add to dep list */
X`009    `125
X
X`009/* Collect following rule lines. */
X
X`009if (getline(str2, fd) == FALSE)`009/* Get commands  */
X`009`123
X`009    while (*str2 == TAB)
X`009    `123
X`009`009cp = newcmd(&str2[0], cp);
X`009`009if (getline(str2, fd))
X`009`009    break;
X`009    `125
X`009`125
X
X`009/* Collect target names. */
X
X`009squeeze(str1);
X
X`009str1[strlen(str1) + 1] = '\0';`009/* Need two NULs for gettok() */
X`009q = str1;
X`009while ((p = gettok(&q)) != NULL_CHARP)`009/* Get target list */
X`009`123
X`009    np = newname(p);`009/* Intern name  */
X`009    newline(np, dp, cp, dbl);
X`009    if (!firstname && p[0] != '.')
X`009`009firstname = np;
X`009`125
X
X`009if (feof(fd))`009`009/* EOF?  */
X`009    return;
X
X`009strcpy(str1, str2);
X    `125
X`125
X
Xvoid
Xsqueeze(s)
Xregister char *s;
X/**
X ** Expand standard C escape sequences in-place in the argument
X ** string.  The valid escapes are:
X **
X ** `009\n`009LF, newline
X ** `009\t`009HT, horizontal tab
X ** `009\b`009BS, backspace
X ** `009\r`009CR, carriage return
X ** `009\f`009FF, formfeed
X ** `009\\`009\, backslash
X ** `009\'`009', single quote
X ** `009\ddd`009ddd, character corresponding to 1, 2, or 3 octal digit
X ** `009`009bit pattern.
X **
X ** Any other backslash-char pair is reduced to char.
X **/
X`123
X    register int c;
X    register int k;
X    register char *result;
X    char *original;
X
X    original = s;
X
X    if (debug)
X    `123`009`009`009`009/* use fputs() instead of printf()--VAX VMS
X`009`009`009`009   printf() fails with */
X`009/* long strings, sigh... */
X`009fputs("SQUEEZE[", stderr);
X`009fputs(s, stderr);
X`009fputs("] ->\n", stderr);
X    `125
X    for (result = s; *s; /* NO-OP */ )
X    `123
X`009if (*s != '\\')
X`009    *result++ = *s;
X`009else`009`009`009/* have backslashed character */
X`009`123
X`009    switch (*(++s))
X`009    `123
X`009    case '\0':`009`009/* end of string reached */
X`009`009break;
X
X`009    case '0':
X`009    case '1':
X`009    case '2':
X`009    case '3':
X`009    case '4':
X`009    case '5':
X`009    case '6':
X`009    case '7':
X`009`009c = (int) ((*s) - '0');
X`009`009for (k = 0; k < 2; ++k)
X`009`009`123`009`009/* collect octal digit string */
X`009`009    ++s;
X`009`009    if (('0' <= (*s)) && ((*s) <= '7'))
X`009`009`009c = 8 * c + (int) ((*s) - '0');
X`009`009    else`009/* advanced past octal digit */
X`009`009    `123
X`009`009`009--s;
X`009`009`009break;
X`009`009    `125
X`009`009`125
X`009`009*result++ = (char) c;
X`009`009break;
X
X`009    case 'n':
X`009`009*result++ = '\n';
X`009`009break;
X
X`009    case 't':
X`009`009*result++ = TAB;
X`009`009break;
X
X`009    case 'b':
X`009`009*result++ = '\b';
X`009`009break;
X
X`009    case 'r':
X`009`009*result++ = '\r';
X`009`009break;
X
X`009    case 'f':
X`009`009*result++ = '\f';
X`009`009break;
X
X`009    case '\\':
X`009`009*result++ = '\\';
X`009`009break;
X
X`009    case '\'':
X`009`009*result++ = '\'';
X`009`009break;
X
X`009    default:`009`009/* \x becomes x for all other x's */
X`009`009*result++ = *s;
X`009`009break;
X`009    `125
X`009`125
X`009if (*s)
X`009    ++s;
X    `125
X    *result = '\0';
X
X    if (debug)
X    `123`009`009`009`009/* use fputs() instead of printf()--VAX VMS
X`009`009`009`009   printf() fails with */
X`009/* long strings, sigh... */
X`009fputs("       [", stderr);`009/* line up with "SQUEEZE[" */
X`009fputs(original, stderr);
X`009fputs("]\n", stderr);
X    `125
X`125
$ GOSUB UNPACK_FILE
$ FILE_IS = "MACRO.C"
$ CHECKSUM_IS = 322197148
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009Macro control for make
X */
X
X#include "h.h"
X
XMACROP macrohead;
X
XMACROP
Xgetmp(name)
Xchar *name;
X`123
X    register MACROP rp;
X    register MACROP rp_prev;
X
X    for (rp = macrohead; rp; (rp_prev = rp, rp = rp->m_next))
X`009if (strcmp(name, rp->m_name) == 0)
X`009`123
X`009    /* In the interests of efficiency, we move each found entry
X`009       to the beginning of the list, on the justifiable
X`009       assumption that the macro reference is likely to recur. */
X`009    if (rp != macrohead)
X`009    `123
X`009`009rp_prev->m_next = rp->m_next;
X`009`009rp->m_next = macrohead;
X`009`009macrohead = rp;
X`009    `125
X`009    return rp;
X`009`125
X    return NULL_MACROP;
X`125
X
X
Xchar *
Xgetmacro(name)
Xchar *name;
X`123
X    MACROP mp;
X
X    if (mp = getmp(name))
X`009return mp->m_val;
X    else
X`009return "";
X`125
X
X
XMACROP
Xsetmacro(name, val, permanent)
Xchar *name;
Xchar *val;
Xbool permanent;
X`123
X    register MACROP rp;
X
X
X    /* Replace macro definition if a non-permanent one exists */
X    for (rp = macrohead; rp; rp = rp->m_next)
X`009if (strcmp(name, rp->m_name) == 0)
X`009    break;
X
X    if (rp)
X    `123
X`009if ((rp->m_flag & M_PERMANENT) && !permanent)
X`009    return rp;`009`009/* cannot replace permanent macro except */
X`009    `009`009`009/* by another permanent one */
X
X`009if (strcmp(val, rp->m_val) == 0)/* with libraries, it is common */
X`009    return rp;`009`009`009/* to have same value as before */
X
X`009free((char *) (rp->m_val));`009/* Replacing: free value space from
X`009`009`009`009`009   old */
X    `125
X    else`009`009`009/* If not defined, allocate space for new */
X    `123
X`009if ((rp = (MACROP) malloc(sizeof(MACRO))) == NULL_MACROP)
X`009    fatal("No memory for macro");
X
X`009rp->m_next = macrohead;
X`009macrohead = rp;
X`009rp->m_flag = (uchar) (permanent ? M_PERMANENT : 0);
X`009rp->m_name = newstring(NULL_CHARP, name);
X    `125
X
X    rp->m_val = newstring(NULL_CHARP, val);
X
X    return rp;
X`125
X
X
X/*
X *`009Do the dirty work for expand
X */
Xvoid
Xdoexp(to, from, len, buf)
Xchar **to;
Xchar *from;
Xint *len;
Xchar *buf;
X`123
X    register char *rp;
X    register char *p;
X    register char *q;
X    register MACROP mp;
X
X
X    rp = from;
X    p = *to;
X    while (*rp)
X    `123
X`009if ((*rp == '\\') && (*(rp + 1) == 'n'))
X`009`123`009`009`009/* translate \n literal pair to single
X`009`009`009`009   newline */
X`009    *p++ = '\n';
X`009    rp += 2;
X`009    (*len)--;
X`009    (*len)--;
X`009`125
X`009else
X`009if (*rp != '$')
X`009`123
X`009    *p++ = *rp++;
X`009    (*len)--;
X`009`125
X`009else
X`009`123
X`009    q = buf;
X`009    if (*++rp == '`123')
X`009`009while (*++rp && *rp != '`125')
X`009`009    *q++ = *rp;
X`009    else
X`009    if (*rp == '(')
X`009`009while (*++rp && *rp != ')')
X`009`009    *q++ = *rp;
X`009    else
X`009    if (!*rp)
X`009    `123
X`009`009*p++ = '$';
X`009`009break;
X`009    `125
X`009    else
X`009`009*q++ = *rp;
X`009    *q = '\0';
X`009    if (*rp)
X`009`009rp++;
X`009    if (!(mp = getmp(buf)))
X`009`009mp = setmacro(buf, "", TEMPORARY);
X`009    if (mp->m_flag & M_SEEN)
X`009    `123
X`009`009sprintf(str1, "Infinitely recursive macro %s",
X`009`009`009mp->m_name);
X`009`009fatal(str1);
X`009    `125
X`009    mp->m_flag `124= M_SEEN;
X`009    *to = p;
X`009    doexp(to, mp->m_val, len, buf);
X`009    p = *to;
X`009    mp->m_flag &= `126M_SEEN;
X`009`125
X`009if (*len <= 0)
X`009    error("Expanded line too line");
X    `125
X    *p = '\0';
X    *to = p;
X`125
X
X
X/*
X *`009Expand any macros in str.
X */
Xvoid
Xexpand(str)
Xchar *str;
X`123
X    static char a[MAXSTRING];
X    static char b[MAXSTRING];
X    char *p = str;
X    int len = MAXSTRING - 1;
X
X    strcpy(a, str);
X    doexp(&p, a, &len, b);
X`125
$ GOSUB UNPACK_FILE
$ FILE_IS = "MAIN.C"
$ CHECKSUM_IS = 290248086
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X *`009make [-f makefile] [-dimnpqrst] [target(s) ...]
X *
X *`009-d debug output on stderr
X *`009-f makefile name
X *`009-i ignore exit status
X *`009-m change memory requirements (EON only)
X *`009-n pretend to make
X *`009-p print all macros & targets
X *`009-q question up-to-dateness of target.  Return exit status 1 if not
X *`009-r do not use built-in rules
X *`009-s make silently
X *`009-t touch files instead of making them
X */
X
X#include "h.h"
X
X#ifdef EON
X#include <sys/err.h>
X#endif
X
X#ifdef KCC_20
X#include <errno.h>
X#endif
X
X#ifdef MSC
X#include <errno.h>
X#endif
X
X#ifdef OS9
X#include <errno.h>
X#endif
X
X#ifdef UNIX
X#include <sys/errno.h>
X#endif
X
X#ifdef VMS
X#include <errno.h>
X#endif
X
X#ifdef EON
X#define MEMSPACE`009(16384)
X#endif
X
X
Xchar *myname;
Xchar *makefile;`009`009`009/* The make file  */
X
X#ifdef EON
Xunsigned memspace = MEMSPACE;
X#endif
X
XFILE *ifd;`009`009`009/* Input file desciptor  */
Xint debug = 0;`009`009`009/* debug printout on stderr */
Xbool domake = TRUE;`009`009/* Go through the motions option  */
Xbool ignore = FALSE;`009`009/* Ignore exit status option  */
Xbool silent = FALSE;`009`009/* Silent option  */
Xbool print = FALSE;`009`009/* Print debugging information  */
Xbool rules = TRUE;`009`009/* Use inbuilt rules  */
Xbool dotouch = FALSE;`009`009/* Touch files instead of making  */
Xbool quest = FALSE;`009`009/* Question up-to-dateness of file  */
X
X
Xvoid
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X`123
X    register char *p;
X    char *q;
X    int estat = 0;`009`009/* exit status code */
X    register NAMEP np;
X    DEPENDP mfhead;`009`009/* makefile name list head pointer */
X    DEPENDP mfdp;
X    NAMEP mfnp;
X
X    myname = (argc-- < 1) ? "make" : *argv++;
X
X#ifdef VMS
X    myname = "make";`009`009/* otherwise get ugly dev:[dir]make.exe.## */
X#endif
X
X    mfhead = NULL_DEPENDP;`009/* no makefile names yet */
X
X    while ((argc > 0) && (**argv == '-'))
X    `123
X`009argc--;`009`009`009/* One less to process  */
X`009p = *argv++;`009`009/* Now processing this one  */
X
X`009while (*++p != '\0')
X`009`123
X
X#ifdef CASE_INSENSITIVE
X`009    *p = (isupper(*p) ? tolower(*p) : *p);
X#endif
X
X`009    switch (*p)
X`009    `123
X`009    case 'd':
X`009`009debug = isdigit(p[1]) ? atoi(&p[1]) : 1;
X`009`009while (isdigit(*++p))`009/* skip over digits */
X`009`009    ;
X`009`009--p;`009`009/* point to last digit or 'd' */
X`009`009break;
X
X`009    case 'f':`009`009/* Alternate file name  */
X`009`009if (*++p == '\0')
X`009`009`123
X`009`009    if (argc-- <= 0)
X`009`009`009usage();
X`009`009    p = *argv++;
X`009`009`125
X`009`009mfnp = newname(p);
X`009`009mfhead = newdep(mfnp, mfhead);
X`009`009p = index(p, '\0') - 1;`009/* point to just before NUL */
X`009`009break;
X
X#ifdef EON
X`009    case 'm':`009`009/* Change space requirements  */
X`009`009if (*++p == '\0')
X`009`009`123
X`009`009    if (argc-- <= 0)
X`009`009`009usage();
X`009`009    p = *argv++;
X`009`009`125
X`009`009memspace = atoi(p);
X`009`009goto end_of_args;
X#endif
X`009    case 'n':`009`009/* Pretend mode  */
X`009`009domake = FALSE;
X`009`009break;
X
X`009    case 'i':`009`009/* Ignore fault mode  */
X`009`009ignore = TRUE;
X`009`009break;
X
X`009    case 's':`009`009/* Silent about commands  */
X`009`009silent = TRUE;
X`009`009break;
X
X`009    case 'p':
X`009`009print = TRUE;
X`009`009break;
X
X`009    case 'r':
X`009`009rules = FALSE;
X`009`009break;
X
X`009    case 't':
X`009`009dotouch = TRUE;
X`009`009break;
X
X`009    case 'q':
X`009`009quest = TRUE;
X`009`009break;
X
X`009    default:`009`009/* Wrong option  */
X`009`009usage();
X`009    `125
X`009`125
Xend_of_args:;
X    `125
X
X#ifdef EON
X    if (initalloc(memspace) == 0xffff)`009/* Must get memory for alloc  */
X`009fatal("Cannot initalloc memory");
X#endif
X    (void) setmacro("$", "$", PERMANENT);
X
X    /* Now install any command-line macro definitions, overriding any */
X    /* values from the Makefile */
X    while (argc && (p = index(*argv, '=')))
X    `123
X`009char c;
X
X`009c = *p;
X`009*p = '\0';
X`009(void) setmacro(*argv, p + 1, PERMANENT);
X`009*p = c;
X
X`009argv++;
X`009argc--;
X    `125
X
X    if (rules)
X    `123
X`009makerules();`009`009`009/* install built-in rules */
X`009makeinit();`009`009`009/* process local rule modifications */
X    `125
X
X    if (mfhead == NULL_DEPENDP)`009/* supply list of defaults */
X    `123
X`009strcpy(str1, MAKEFILES);
X`009str1[strlen(str1) + 1] = '\0';`009/* extra NUL for gettok() */
X`009for (q = str1; (p = gettok(&q)) != NULL_CHARP; /* NO-OP */ )
X`009`123
X`009    mfnp = newname(p);
X`009    mfnp->n_flag `124= N_DEFAULT;
X`009    mfhead = newdep(mfnp, mfhead);
X`009`125
X    `125
X    for (mfdp = mfhead; mfdp; mfdp = mfdp->d_next)
X    `123
X`009makefile = mfdp->d_name->n_name;
X`009if (debug)
X`009    fprintf(stderr, "MAKEFILE[%s]\n", makefile);
X`009if (strcmp(makefile, "-") == 0)`009/* use stdin as makefile */
X`009    ifd = stdin;
X`009else
X`009`123
X`009    ifd = fopen(makefile, "r");
X`009    if (ifd == NULL_FILEP)
X`009    `123
X`009`009if (mfdp->d_name->n_flag & N_DEFAULT)
X`009`009    continue;`009/* ignore open failures on default names */
X`009`009else
X`009`009`123
X`009`009    sprintf(str1, "Can't open makefile [%s]", makefile);
X`009`009    fatal(str1);
X`009`009`125
X
X`009    `125
X`009`125
X`009lineno = 0;`009`009/* for error messages */
X`009input(ifd);`009`009/* process the makefile */
X`009if (ifd != stdin)
X`009    fclose(ifd);`009/* and close it */
X    `125
X    lineno = 0;`009`009`009/* Calls to error() now print no line number */
X
X    if (print)
X`009prt();`009`009`009/* Print out structures  */
X
X    np = newname(".SILENT");
X    if (np->n_flag & N_TARG)
X`009silent = TRUE;
X
X    np = newname(".IGNORE");
X    if (np->n_flag & N_TARG)
X`009ignore = TRUE;
X
X    precious();
X
X    circh();`009`009`009/* Check circles in target definitions  */
X
X    if (!argc)
X    `123`009if (!firstname)
X`009    fatal("No targets defined");
X
X`009estat = make(firstname, 0);
X    `125
X    else
X`009while (argc--)
X`009`123
X`009    if (!print && !silent && strcmp(*argv, "love") == 0)
X`009`009printf("Not war!\n");
X`009    estat `124= make(newname(*argv++), 0);
X`009`125
X
X    if (quest)
X`009EXIT(estat);
X    else
X`009EXIT(0);
X`125
X
X/***********************************************************************
XThe environment variable (DEC logical  name) MAKEINIT can be defined  to
Xbe a list of filenames separated by NAMESEP (normally a semicolon) which
Xare in normal Makefile format, and are automatically processed after the
Xbuilt-in rules are established, and before the user Makefile is read.
X
XThis makes it possible to tailor  default rules for particular sites  or
Xprojects, avoiding the necessity of massive modifications of  individual
Xuser makefiles.   For example,  a project  might wish  to have  compiler
Xdebug options  set during  development,  then replaced  by  optimization
Xrequests at the final release.  Similarly, a system administrator  could
Xchange a default compiler on a system-wide basis.
X***********************************************************************/
Xvoid
Xmakeinit()
X`123
X    register char *p;
X    char *filename;
X    FILE *fp;
X
X    if ((p = getenv("MAKEINIT")) == NULL_CHARP)
X`009return;
X    for (; *p; ++p)`009`009/* process each file in MAKEINIT list in turn */
X    `123
X`009filename = p;
X`009p = index(filename, NAMESEP);
X`009if (p != NULL_CHARP)
X`009    *p = '\0';`009`009/* change NAMESEP to string terminator */
X#ifdef VMS
X/*
V *`009`009For VMS systems, index returns 0 if NAMESEP is not found in the str
Xing.
V *`009`009At the end of the loop, p gets incremented and *p (p has a value of
X 1
V *`009`009now) creates an access violation (locations 0-512 are an access pro
Xtection
V *`009`009band to prevent run-away programs from trashing everything).  This
X section
X *`009`009of code relieves that problem.
X */
X`009else
X`009    p = filename + strlen(filename) - 1;
X#endif
X`009if ((fp = fopen(filename, "r")) == NULL_FILEP)
X`009`123
X`009    sprintf(str1, "Cannot open makefile [%s]", filename);
X`009    fatal(str1);
X`009`125
X/*
X`009if (!silent)
X`009    printf("[Defaults from %s]\n", filename);
X*/
X`009lineno = 0;
X`009input(fp);
X`009fclose(fp);
X    `125
X    lineno = 0;`009`009`009/* Any calls to error now print no line
X`009`009`009`009   number */
X`125
X
X
Xvoid
Xusage()
X`123
X    fprintf(stderr,
X#ifdef EON
X    "Usage: %s [-f makefile] [-dimnpqrst] [macro=val ...] [target(s) ...]\n",
X#else
X    "Usage: %s [-f makefile] [-dinpqrst] [macro=val ...] [target(s) ...]\n",
X#endif
X`009    myname);
X    EXIT(1);
X`125
X
X
Xvoid
Xfatal(msg)
Xchar *msg;
X`123
X    static bool entered = FALSE;
X
X    if (entered)`009`009/* unexpected recursive entry */
X`009EXIT(1);
X    entered = TRUE;
X
X#ifdef KCC_20
X    fprintf(stderr, "?");`009/* error flag for batch use */
X#endif
X
X    fprintf(stderr, "%s: ", myname);
X    fprintf(stderr, msg);
X    fputc('\n', stderr);
X    if (errno)
X`009perror("perror() says");
X    if (debug)
X    `123
X`009NAMEP tnp;
X
X`009prt();
X`009for (tnp = namehead.n_next; tnp; tnp = tnp->n_next)
X`009    prtname(tnp, 0);
X    `125
X    EXIT(1);
X`125
X
X
Xchar *
Xnewstring(p, value)
Xchar *p;
Xchar *value;
X/*
X** If 'p' is non-NULL, free the  storage it points to.  Then allocate  a
X** block of storage large enough for 'value' bytes, copy the contents of
X** 'value' into it, and return a pointer to the new block.  Execution is
X** terminated if there is insufficient storage for the new string.
X*/
X`123
X    int k;
X
X    if (p != NULL_CHARP)
X`009(void) free(p);
X
X    k = strlen(value);
X    if ((p = malloc(k + 1)) == NULL_CHARP)
X`009fatal("No memory for name");
X
X    strcpy(p, value);
X    return (p);
X`125
X
X
X
X
X#ifdef CASE_INSENSITIVE
X/***********************************************************************
X Compare strings (ignoring case), and return:
-+-+-+-+-+ End of part 2 +-+-+-+-+-
-- 
/* My opinions...             *  Tony Ivanov   MS-4B       *  ...ucbvax!   */
/* shared by my company?!...  *  Grass Valley Group, Inc.  *  tektronix!   */
/* you've got to be kidding!  *  P.O. Box 1114             *  gvgpsa!      */
/* "tony@gvgpvd.GVG.TEK.COM"  *  Grass Valley, CA  95945   *  gvgpvd!tony  */

