From:	CSBVAX::CSBVAX::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 28-DEC-1988 05:53
To:	MRGATE::"ARISIA::EVERHART"
Subj:	MAKE.SHAR (part 1 of 5)


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Tue, 20 DEC 88 00:37:44 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Tue, 20 Dec 88 00:13:50 PST
Received: by ucbvax.Berkeley.EDU (5.61/1.33)
	id AA27545; Mon, 19 Dec 88 23:27:02 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:30:29 GMT
From: tektronix!gvgpsa!gvgpvd!tony@ucbvax.Berkeley.EDU  (Tony Ivanov)
Organization: Grass Valley Group, Inc., Grass Valley, CA
Subject: MAKE.SHAR (part 1 of 5)
Message-Id: <922@gvgpvd.GVG.TEK.COM>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com


	This a the VMS public domain MAKE source.  Included with the
source is a GLOBAL MAKEFILE that can be placed in a utility directory
with a logical name "MAKEINIT" pointing to it.  This makefile will
always be searched prior to executing the local makefile (good for
customizing site specific stuff).
	Also included is the source to TOUCH and ECHO (useful
commands that go into makefiles).  Following are installation steps:
    1)	Create a MAKE source directory.
    2)	$ COPY MAKE.SHAR* MAKE.SHAR
    3)	Move MAKE.SHAR to the source directory.
    4)	$ @MAKE.SHAR
    5)	$ @INITIAL.MAKE
From then on (after make is compiled), if you make changes, you can
use MAKE to re-make itself.

	Some notes on make:  I have changed the SYMBOL parsing
algorithm to accept commas and plusses as well as blanks.  This is
quite necessary for VMS command parsing.  Also, I have changed the
terminal I/O to do buffered I/O rather than character I/O since
buffered I/O is much faster.
$!..............................................................................
$! VAX/VMS archive file created by VMS_SHAR V-5.01 01-Oct-1987
$! which was written by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au)
$! To unpack, simply save and execute (@) this file.
$!
$! This archive was created by TONY
$! on Thursday 3-NOV-1988 12:34:12.73
$!
$! ATTENTION: To keep each article below 26112 bytes, this program
$! has been transmitted in 4 parts.
$! You should concatenate ALL parts to ONE file and execute (@) that file.
$!
$! It contains the following 16 files:
$! INITIAL.MAKE MAKEFILE. MAKEFILE.GLOBAL CHECK.C ECHO.C INPUT.C MACRO.C MAIN.C
$! MAKE.C READER.C RULES.C TOUCH.C VAXVMS.C H.H VAXC_SHARE.OPT VMS_RULES.DOC
$!==============================================================================
$ Set Symbol/Scope=(NoLocal,NoGlobal)
$ Version=F$GetSYI("VERSION") ! See what VMS version we have here:
$ If Version.ges."V4.4" then goto Version_OK
$ Write SYS$Output "Sorry, you are running VMS ",Version, -
                ", but this procedure requires V4.4 or higher."
$ Exit 44
$Version_OK: CR[0,8]=13
$ Pass_or_Failed="failed!,passed."
$ Goto Start
$Convert_File:
$ Read/Time_Out=0/Error=No_Error1/Prompt="creating ''File_is'" SYS$Command ddd
$No_Error1: Define/User_Mode SYS$Output NL:
$ Edit/TPU/NoSection/NoDisplay/Command=SYS$Input/Output='File_is' -
        VMS_SHAR_DUMMY.DUMMY
f:=Get_Info(Command_Line,"File_Name");b:=Create_Buffer("",f);
o:=Get_Info(Command_Line,"Output_File");Set(Output_File,b,o);
Position(Beginning_of(b));Loop x:=Erase_Character(1);Loop ExitIf x<>"V";
Move_Vertical(1);x:=Erase_Character(1);Append_Line;
Move_Horizontal(-Current_Offset);EndLoop;Move_Vertical(1);
ExitIf Mark(None)=End_of(b) EndLoop;Position(Beginning_of(b));Loop
x:=Search("`",Forward,Exact);ExitIf x=0;Position(x);Erase_Character(1);
If Current_Character='`' then Move_Horizontal(1);else
Copy_Text(ASCII(INT(Erase_Character(3))));EndIf;EndLoop;Exit;
$ Delete VMS_SHAR_DUMMY.DUMMY;*
$ Checksum 'File_is
$ Success=F$Element(Check_Sum_is.eq.CHECKSUM$CHECKSUM,",",Pass_or_Failed)+CR
$ Read/Time_Out=0/Error=No_Error2/Prompt=" CHECKSUM ''Success'" SYS$Command ddd
$No_Error2: Return
$Start:
$ File_is="INITIAL.MAKE"
$ Check_Sum_is=1696560800
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X$ on error then goto end
X$ on control_Y then goto end
X$ sv = f$verify ("YES")
X$`009CC/LIST CHECK.C,INPUT.C,MACRO.C,MAIN.C,MAKE.C,READER.C,RULES.C,VAXVMS.C
X$`009LINK/EXE=MAKE.EXE CHECK.OBJ,INPUT.OBJ,MACRO.OBJ,MAIN.OBJ,MAKE.OBJ, -
X`009READER.OBJ,RULES.OBJ,VAXVMS.OBJ,VAXC_SHARE.OPT/OPT
X$!`009LINK/EXE=MAKE.EXE CHECK.OBJ,INPUT.OBJ,MACRO.OBJ,MAIN.OBJ,MAKE.OBJ, -
X$!`009READER.OBJ,RULES.OBJ,VAXVMS.OBJ,SYS$LIBRARY:VAXCRTL.OLB/LIB
X$ end:`009sv=f$verify(sv)
$ GoSub Convert_File
$ File_is="MAKEFILE."
$ Check_Sum_is=695063573
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X#
X#`009This is the make file for "make"
X#
X
XPROGRAM =`009MAKE
X
X#`009These are system dependent variables
X#`009`009INSTALL_DIR -`009`009# Where the program will be installed.
X#`009`009PROG_NAME -`009`009# Actual name of the program.
X#`009`009CFLAGS - `009`009# How to get listings during compilation.
X#`009`009LD -`009`009`009# What the name of the image loader is.
V#`009`009IMAGE_NAMER -`009`009# What the flag is to create an image with a cert
Xain name.
X#`009`009LDFLAGS -`009`009# How to link in run-time libraries.
V#`009`009PURGE -`009`009`009# How to remove duplicate file names...meaningless 
Xfor UNIX.
X#`009`009RENAME -`009`009# How to change the name of a file..."mv" for UNIX.
X#`009`009COPY -`009`009`009# How to copy files..."cp" for UNIX.
X#`009`009SHAR -`009`009`009# How to make a "shar" file.
X#
XINSTALL_DIR`009=GLIB:
XTARGET_DIR`009=
XPROG_NAME`009=$(PROGRAM).EXE
XCFLAGS`009`009=/list
XLD`009`009=link
XIMAGE_NAMER`009=/exe=
XLDFLAGS`009`009=,vaxc_share/opt
XPURGE`009`009=purge
XRENAME`009`009=rename
XCOPY`009`009=copy/replace/nolog
XSHAR`009`009=vms_shar
X#
X#`009Source and object files.
X#
XSOURCE`009`009=CHECK.C,INPUT.C,MACRO.C,MAIN.C,MAKE.C,READER.C,\
X`009`009 RULES.C,VAXVMS.C
X
XOBJECTS`009`009=CHECK.OBJ,INPUT.OBJ,MACRO.OBJ,MAIN.OBJ,MAKE.OBJ,\
X`009`009 READER.OBJ,RULES.OBJ,VAXVMS.OBJ
X
XSHAR_FILES`009=INITIAL.MAKE,MAKEFILE.*,*.C,*.H,*.OPT,*.DOC
X#
X#`009Main target
X#
X$(PROGRAM):`009$(TARGET_DIR)$(PROG_NAME)
X`009`009@make install
X`009`009@make clean
X`009`009@touch $(PROGRAM)
X
X$(TARGET_DIR)$(PROG_NAME):`009$(OBJECTS)
X`009`009$(LD) $(IMAGE_NAMER) $(TARGET_DIR)$(PROG_NAME) $(OBJECTS) $(LDFLAGS)
X
Xinstall:`009$(TARGET_DIR)$(PROG_NAME)
X`009`009$(PURGE) $(TARGET_DIR)$(PROG_NAME)
X`009`009$(COPY) $(TARGET_DIR)$(PROG_NAME) $(INSTALL_DIR)
X`009`009$(PURGE) $(INSTALL_DIR)$(PROG_NAME)
X`009`009@touch install
X
Xclean:
X`009`009$(PURGE)
X
Xshar:
X`009`009$(SHAR) $(SHAR_FILES) make.shar
X#
X#`009Miscellaneous dependencies.
X#
XCHECK.obj:`009h.h
XINPUT.obj:`009h.h
XMACRO.obj:`009h.h
XMAIN.obj:`009h.h
XMAIN.obj:`009sys$$library:errno.h
XMAKE.obj:`009h.h
XMAKE.obj:`009sys$$library:stat.h
XMAKE.obj:`009sys$$library:errno.h
XREADER.obj:`009h.h
XRULES.obj:`009h.h
XVAXVMS.obj:`009sys$$library:descrip.h
XVAXVMS.obj:`009sys$$library:ssdef.h
$ GoSub Convert_File
$ File_is="MAKEFILE.GLOBAL"
$ Check_Sum_is=743154659
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X#
X#`009This is the default makefile to set up standard
X#`009rules for GVG.
X#
X#`009`009CFLAGS -`009Default C compilation flags.
X#`009`009FFLAGS -`009Default FORTRAN compilation flags.
X#`009`009AFLAGS -`009Default MACRO compilation flags.
X#`009`009LD -`009`009Loader name.
X#`009`009RM -`009`009File remover name.
X#`009`009RTL_SHARE -`009Command to link in shareable run-time libraries.
X#`009`009FORRTL_SHARE -`009Command to link in shareable run-time libraries.
X#`009`009LIBS -`009`009List of library names.
X#
XFFLAGS`009`009=/list
XCFLAGS`009`009=/list
XAFLAGS`009`009=/list
XLD`009`009=link
XRM`009`009=delete/nolog
XCRTL_SHARE`009=,vaxc_share/opt
XFORRTL_SHARE`009=
XLIBS`009`009=
X.c.exe:
X`009@make $*.obj
X`009$(LD) $(LDFLAGS) $*.obj $(LIBS) $(CRTL_SHARE)
X`009@$(RM) $*.obj;
X
X.for.exe:
X`009@make $*.obj
X`009$(LD) $(LDFLAGS) $*.obj $(LIBS) $(FORRTL_SHARE)
X`009@$(RM) $*.obj;
X
X.mar.exe:
X`009@make $*.obj
X`009$(LD) $(LDFLAGS) $*.obj $(LIBS)
X`009@$(RM) $*.obj;
X
X#
X#`009The following definitions are used for RUNOFF.
X#`009`009RC -`009`009Runoff command.
X#`009`009RFLAGS -`009Default RUNOFF flags.
X#`009`009MEMFLAGS -`009Runoff flags used to create .MEM files.
X#`009`009BRNFLAGS -`009Runoff flags used to create .BRN files.
X#`009`009RNTFLAGS -`009Runoff flags used to create .RNT files.
X#`009`009MECFLAGS -`009Runoff flags used to create .MEC files.
X#
X.SUFFIXES:`009.mem .rno .mec .rnt .brn
XRC =`009`009runoff
XRFLAGS =`009/right=6
X.rno.mem:
X`009$(RC) $(RFLAGS)$(MEMFLAGS) $*.rno
X
X.rno.brn:
X`009$(RC)/intermediate $(RFLAGS)$(BRNFLAGS) $*.rno
X
X.brn.rnt:
X`009$(RC)/contents $(RNTFLAGS) $*.brn
X
X.rnt.mec:
X`009$(RC) $(RFLAGS)$(MECFLAGS) $*.rnt
$ GoSub Convert_File
$ File_is="CHECK.C"
$ Check_Sum_is=2101212558
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/*
X *`009Check structures for make.
X */
X
X#include "h.h"
X
X
X/*
X *`009Prints out the structures as defined in memory.  Good for check
X *`009that you make file does what you want (and for debugging make).
X */
Xvoid
Xprt()
X{
X    register NAMEP np;
X    register DEPENDP dp;
X    register LINEP lp;
X    register CMDP cp;
X    register MACROP mp;
X
X
X    for (mp = macrohead; mp; mp = mp->m_next)
X`009fprintf(stderr, "%s = %s\n", mp->m_name, mp->m_val);
X
X    fputc('\n', stderr);
X
X    for (np = namehead.n_next; np; np = np->n_next)
X    {
X`009if (np->n_flag & N_DOUBLE)
X`009    fprintf(stderr, "%s::\n", np->n_name);
X`009else
X`009    fprintf(stderr, "%s:\n", np->n_name);
X`009if (np == firstname)
X`009    fprintf(stderr, "(MAIN NAME)\n");
X`009for (lp = np->n_line; lp; lp = lp->l_next)
X`009{
X`009    fputc(':', stderr);
X`009    for (dp = lp->l_dep; dp; dp = dp->d_next)
X`009`009fprintf(stderr, " %s", dp->d_name->n_name);
X`009    fputc('\n', stderr);
X
X`009    for (cp = lp->l_cmd; cp; cp = cp->c_next)
X`009`009fprintf(stderr, "-%c%s\n", TAB, cp->c_cmd);
X
X`009    fputc('\n', stderr);
X`009}
X`009fputc('\n', stderr);
X    }
X}
X
X
X/*
X *`009Recursive routine that does the actual checking.
X */
Xvoid
Xcheck(np)
XNAMEP np;
X{
X    register DEPENDP dp;
X    register LINEP lp;
X
X
X    if (np->n_flag & N_MARK)
X    {
X`009sprintf(str1, "Circular dependency from %s", np->n_name);
X`009fatal(str1);
X    }
X
X
X    np->n_flag |= N_MARK;
X
X    for (lp = np->n_line; lp; lp = lp->l_next)
X`009for (dp = lp->l_dep; dp; dp = dp->d_next)
X`009    check(dp->d_name);
X
X    np->n_flag &= ~N_MARK;
X}
X
X
X/*
X *`009Look for circular dependancies.
X *`009ie.
X *`009`009a: b
X *`009`009b: a
X *`009is a circular dep
X */
Xvoid
Xcirch()
X{
X    register NAMEP np;
X
X
X    for (np = namehead.n_next; np; np = np->n_next)
X`009check(np);
X}
X
X
X/*
X *`009Check the target .PRECIOUS, and mark its dependentd as precious
X */
Xvoid
Xprecious()
X{
X    register DEPENDP dp;
X    register LINEP lp;
X    register NAMEP np;
X
X
X    if (!((np = newname(".PRECIOUS"))->n_flag & N_TARG))
X`009return;
X
X    for (lp = np->n_line; lp; lp = lp->l_next)
X`009for (dp = lp->l_dep; dp; dp = dp->d_next)
X`009    dp->d_name->n_flag |= N_PREC;
X}
$ GoSub Convert_File
$ File_is="ECHO.C"
$ Check_Sum_is=709352348
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
Xmain (argc, argv)
X`009int`009argc;
X`009char`009*argv[];
X{
X`009for (--argc;  argc;  argc--)
V`009{`009squeeze (*(++argv));`009`009`009/* convert back-slash characters to as
Xcii. */
X`009`009if (strchr(*argv,'%'))`009`009`009/* can't handle formats yet */
X`009`009`009printf ("%s",*argv);
X`009`009else
X`009`009`009printf (*argv);
X`009`009putchar (' ');
X`009}
X`009putchar ('\n');
X}
X
X
X
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{
X    register int c;
X    register int k;
X    register char *result;
X    char *original;
X
X    original = s;
X
X    for (result = s; *s; /* NO-OP */ )
X    {
X`009if (*s != '\\')
X`009    *result++ = *s;
X`009else`009`009`009/* have backslashed character */
X`009{
X`009    switch (*(++s))
X`009    {
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{`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    {
X`009`009`009--s;
X`009`009`009break;
X`009`009    }
X`009`009}
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++ = '\t';
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    }
X`009}
X`009if (*s)
X`009    ++s;
X    }
X    *result = '\0';
X
X}
$ GoSub Convert_File
$ File_is="INPUT.C"
$ Check_Sum_is=57070876
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/*
X *`009Parse a makefile
X */
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{
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}
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{
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}
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{
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}
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{
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    {
X`009for (rp = np->n_line; rp; rp = rrp)
X`009{
X`009    rrp = rp->l_next;
X`009    free((char *) rp);
X`009}
X`009np->n_line = NULL_LINEP;
X`009np->n_flag &= ~N_TARG;
X`009return;
X    }
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{
X`009    np->n_line->l_cmd = cp;
X`009    return;
X`009}
X`009else
X`009{
X`009    sprintf(str1, "Commands defined twice for target %s",
X`009`009    np->n_name);
X`009    error(str1);
X`009}
X    if (np->n_flag & N_TARG)
X`009if (!(np->n_flag & N_DOUBLE) != !flag)`009/* like xor */
X`009{
X`009    sprintf(str1, "Inconsistent rules for target %s", np->n_name);
X`009    error(str1);
X`009}
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 |= N_TARG;
X    if (flag)
X`009np->n_flag |= N_DOUBLE;
X}
X
X
X/*
X *`009Parse input from the makefile, and construct a tree structure
X *`009of it.
X */
Xvoid
Xinput(fd)
XFILE *fd;
X{
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    {
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{
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}
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{
X`009    dbl = TRUE;
X`009    q++;
X`009}
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    {
X`009`009np = newname(p);/* Intern name  */
X`009`009dp = newdep(np, dp);`009/* Add to dep list */
X`009    }
X
X`009/* Collect following rule lines. */
X
X`009if (getline(str2, fd) == FALSE)`009/* Get commands  */
X`009{
X`009    while (*str2 == TAB)
X`009    {
X`009`009cp = newcmd(&str2[0], cp);
X`009`009if (getline(str2, fd))
X`009`009    break;
X`009    }
X`009}
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{
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}
X
X`009if (feof(fd))`009`009/* EOF?  */
X`009    return;
X
X`009strcpy(str1, str2);
X    }
X}
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{
X    register int c;
X    register int k;
X    register char *result;
X    char *original;
X
X    original = s;
X
X    if (debug)
X    {`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    }
X    for (result = s; *s; /* NO-OP */ )
X    {
X`009if (*s != '\\')
X`009    *result++ = *s;
X`009else`009`009`009/* have backslashed character */
X`009{
X`009    switch (*(++s))
X`009    {
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{`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    {
X`009`009`009--s;
X`009`009`009break;
X`009`009    }
X`009`009}
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    }
X`009}
X`009if (*s)
X`009    ++s;
X    }
X    *result = '\0';
X
X    if (debug)
X    {`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    }
X}
$ GoSub Convert_File
$ Goto Part2
-- 
/* 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  */

