From:	CSBVAX::CSBVAX::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 27-DEC-1988 23:17
To:	MRGATE::"ARISIA::EVERHART"
Subj:	MAKE.SHAR (part 2 of 5)


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Tue, 20 DEC 88 00:11:42 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Tue, 20 Dec 88 00:01:21 PST
Received: by ucbvax.Berkeley.EDU (5.61/1.33)
	id AA27558; Mon, 19 Dec 88 23:27:28 PST
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: 5 Dec 88 23:31:28 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)
Message-Id: <923@gvgpvd.GVG.TEK.COM>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com


$Part2:
$ File_is="MACRO.C"
$ Check_Sum_is=322197148
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/*
X *`009Macro control for make
X */
X
X#include "h.h"
X
XMACROP macrohead;
X
XMACROP
Xgetmp(name)
Xchar *name;
X{
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{
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    {
X`009`009rp_prev->m_next = rp->m_next;
X`009`009rp->m_next = macrohead;
X`009`009macrohead = rp;
X`009    }
X`009    return rp;
X`009}
X    return NULL_MACROP;
X}
X
X
Xchar *
Xgetmacro(name)
Xchar *name;
X{
X    MACROP mp;
X
X    if (mp = getmp(name))
X`009return mp->m_val;
X    else
X`009return "";
X}
X
X
XMACROP
Xsetmacro(name, val, permanent)
Xchar *name;
Xchar *val;
Xbool permanent;
X{
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    {
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    }
X    else`009`009`009/* If not defined, allocate space for new */
X    {
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    }
X
X    rp->m_val = newstring(NULL_CHARP, val);
X
X    return rp;
X}
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{
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    {
X`009if ((*rp == '\\') && (*(rp + 1) == 'n'))
X`009{`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}
X`009else
X`009if (*rp != '$')
X`009{
X`009    *p++ = *rp++;
X`009    (*len)--;
X`009}
X`009else
X`009{
X`009    q = buf;
X`009    if (*++rp == '{')
X`009`009while (*++rp && *rp != '}')
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    {
X`009`009*p++ = '$';
X`009`009break;
X`009    }
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    {
X`009`009sprintf(str1, "Infinitely recursive macro %s",
X`009`009`009mp->m_name);
X`009`009fatal(str1);
X`009    }
X`009    mp->m_flag |= M_SEEN;
X`009    *to = p;
X`009    doexp(to, mp->m_val, len, buf);
X`009    p = *to;
X`009    mp->m_flag &= ~M_SEEN;
X`009}
X`009if (*len <= 0)
X`009    error("Expanded line too line");
X    }
X    *p = '\0';
X    *to = p;
X}
X
X
X/*
X *`009Expand any macros in str.
X */
Xvoid
Xexpand(str)
Xchar *str;
X{
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}
$ GoSub Convert_File
$ File_is="MAIN.C"
$ Check_Sum_is=290248086
$ Copy SYS$Input VMS_SHAR_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{
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    {
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{
X
X#ifdef CASE_INSENSITIVE
X`009    *p = (isupper(*p) ? tolower(*p) : *p);
X#endif
X
X`009    switch (*p)
X`009    {
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{
X`009`009    if (argc-- <= 0)
X`009`009`009usage();
X`009`009    p = *argv++;
X`009`009}
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{
X`009`009    if (argc-- <= 0)
X`009`009`009usage();
X`009`009    p = *argv++;
X`009`009}
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    }
X`009}
Xend_of_args:;
X    }
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    {
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    }
X
X    if (rules)
X    {
X`009makerules();`009`009`009/* install built-in rules */
X`009makeinit();`009`009`009/* process local rule modifications */
X    }
X
X    if (mfhead == NULL_DEPENDP)`009/* supply list of defaults */
X    {
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{
X`009    mfnp = newname(p);
X`009    mfnp->n_flag |= N_DEFAULT;
X`009    mfhead = newdep(mfnp, mfhead);
X`009}
X    }
X    for (mfdp = mfhead; mfdp; mfdp = mfdp->d_next)
X    {
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{
X`009    ifd = fopen(makefile, "r");
X`009    if (ifd == NULL_FILEP)
X`009    {
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{
X`009`009    sprintf(str1, "Can't open makefile [%s]", makefile);
X`009`009    fatal(str1);
X`009`009}
X
X`009    }
X`009}
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    }
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    {`009if (!firstname)
X`009    fatal("No targets defined");
X
X`009estat = make(firstname, 0);
X    }
X    else
X`009while (argc--)
X`009{
X`009    if (!print && !silent && strcmp(*argv, "love") == 0)
X`009`009printf("Not war!\n");
X`009    estat |= make(newname(*argv++), 0);
X`009}
X
X    if (quest)
X`009EXIT(estat);
X    else
X`009EXIT(0);
X}
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{
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    {
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 strin
Xg.
X *`009`009At the end of the loop, p gets incremented and *p (p has a value of 1
V *`009`009now) creates an access violation (locations 0-512 are an access prote
Xction
V *`009`009band to prevent run-away programs from trashing everything).  This se
Xction
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{
X`009    sprintf(str1, "Cannot open makefile [%s]", filename);
X`009    fatal(str1);
X`009}
X/*
X`009if (!silent)
X`009    printf("[Defaults from %s]\n", filename);
X*/
X`009lineno = 0;
X`009input(fp);
X`009fclose(fp);
X    }
X    lineno = 0;`009`009`009/* Any calls to error now print no line
X`009`009`009`009   number */
X}
X
X
Xvoid
Xusage()
X{
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}
X
X
Xvoid
Xfatal(msg)
Xchar *msg;
X{
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    {
X`009NAMEP tnp;
X
X`009prt();
X`009for (tnp = namehead.n_next; tnp; tnp = tnp->n_next)
X`009    prtname(tnp, 0);
X    }
X    EXIT(1);
X}
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{
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}
X
X
X
X
X#ifdef CASE_INSENSITIVE
X/***********************************************************************
X Compare strings (ignoring case), and return:
X`009s1>s2:`009>0
X`009s1==s2:  0
X`009s1<s2:`009<0
X***********************************************************************/
X
X/* toupper() is  supposed to work  for all letters,  but PCC-20 does  it
Xincorrectly if the  argument is not  already lowercase; this  definition
Xfixes that.  PC histogramming of MAKE compiled with KCC-20 revealed that
X45% (!) of the  total execution time  is spent in  this function, and  a
Xfurther 15%  in  toupper().  With  KCC,  toupper() is  a  function,  and
Xislower() and  _toupper()  are in-line.   Putting  in a  conditional  is
Xtherefore  extremely   worthwhile   here,  and   saved   24%.    Further
Xeconomization by rewriting the inner loop to avoid the UC() calls unless
Xnecessary gave a further improvement of only 2%. */
X
Xint
Xstrcm2(s1, s2)
Xregister char *s1;
Xregister char *s2;
X{
X
X#ifdef KCC_20
X#define UC(c) (islower(c) ? _toupper(c) : c)
X    while (*s1)
X    {
X`009if (*s1 == *s2)
X`009    /* NO-OP */;
X`009else if (UC(*s1) == UC(*s2))
X`009    /* NO-OP */;
X`009else
X`009    break;
X`009s1++;
X`009s2++;
X    }
X#else
X#define UC(c) (islower(c) ? toupper(c) : c)
X    while ((*s1) && (UC(*s1) == UC(*s2)))
X    {
X`009s1++;
X`009s2++;
X    }
X#endif
X
X    return ((int) (UC(*s1) - UC(*s2)));
X}
X
X#endif
$ GoSub Convert_File
$ Goto Part3
-- 
/* 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  */

