Public domain make source
caret at tictoc.UUCP
caret at tictoc.UUCP
Fri Jul 11 20:20:44 AEST 1986
Enough coaxing... Here it is. It will need work to work on most
other systems, but the work should be minor. I went though the
source just now, and here is a list of things which I noticed that
will need changing.
make.c:
* Fix dosh() for your system.
* Call to getstat() in modtime() is like a fstat() on unix,
so it needs fixing.
main.c:
* You can have fun in main(). That call to initalloc() is
really special to EON.
rules.c:
* Fix makerules() to suit you compilers for the auto suffix
stuff.
It supports most features of the UNIX make, the notable exceptions
being libraries, and some subtleties with quoting. I will support
problems with it to a degree. Good luck.
P.S. I never actually got around to writing a manual entry for
it, so the best course of action is to refer to the UNIX
manual entry, or the source.
Neil Russell
ACSnet: caret at tictoc.oz
UUCP: ...!seismo!munnari!tictoc.oz!caret
ARPA: caret%tictoc.oz at seismo.arpa
------------------------------ snip ------------------------------
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by caret on Fri Jul 11 20:15:58 EST 1986
# Contents: Makefile h.h check.c input.c macro.c main.c make.c reader.c
# rules.c
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
# Makefile for make!
@.SUFFIXES: .obj
@.c.obj:
c -c $(CFLAGS) $<
OBJS = check.obj input.obj macro.obj main.obj \
make.obj reader.obj rules.obj
m: $(OBJS)
c -a 4000h -o m $(OBJS)
$(OBJS): h.h
@//E*O*F Makefile//
chmod u=rw,g=r,o=r Makefile
echo x - h.h
sed 's/^@//' > "h.h" <<'@//E*O*F h.h//'
/*
* Include header for make
*/
#ifndef uchar
#define uchar unsigned char
#endif
#define bool uchar
#define time_t long
#define TRUE (1)
#define FALSE (0)
#define max(a,b) ((a)>(b)?(a):(b))
#define DEFN1 "makefile" /* Default names */
#define DEFN2 "Makefile"
#define LZ (1024) /* Line size */
/*
* A name. This represents a file, either to be made, or existant
*/
struct name
{
struct name * n_next; /* Next in the list of names */
char * n_name; /* Called */
struct line * n_line; /* Dependencies */
time_t n_time; /* Modify time of this name */
uchar n_flag; /* Info about the name */
};
#define N_MARK 0x01 /* For cycle check */
#define N_DONE 0x02 /* Name looked at */
#define N_TARG 0x04 /* Name is a target */
#define N_PREC 0x08 /* Target is precious */
/*
* Definition of a target line.
*/
struct line
{
struct line * l_next; /* Next line (for ::) */
struct depend * l_dep; /* Dependents for this line */
struct cmd * l_cmd; /* Commands for this line */
};
/*
* List of dependents for a line
*/
struct depend
{
struct depend * d_next; /* Next dependent */
struct name * d_name; /* Name of dependent */
};
/*
* Commands for a line
*/
struct cmd
{
struct cmd * c_next; /* Next command line */
char * c_cmd; /* Command line */
};
/*
* Macro storage
*/
struct macro
{
struct macro * m_next; /* Next variable */
char * m_name; /* Called ... */
char * m_val; /* Its value */
uchar m_flag; /* Infinite loop check */
};
extern char * myname;
extern struct name namehead;
extern struct macro * macrohead;
extern struct name * firstname;
extern bool silent;
extern bool ignore;
extern bool rules;
extern bool dotouch;
extern bool quest;
extern bool domake;
extern char str1[];
extern char str2[];
extern int lineno;
char * fgets();
char * index();
char * rindex();
char * malloc();
extern int errno;
char * getmacro();
struct macro * setmacro();
void input();
void error();
void fatal();
int make();
struct name * newname();
struct depend * newdep();
struct cmd * newcmd();
void newline();
char * suffix();
void touch();
void makerules();
char * gettok();
void precious();
@//E*O*F h.h//
chmod u=rw,g=r,o=r h.h
echo x - check.c
sed 's/^@//' > "check.c" <<'@//E*O*F check.c//'
/*
* Check structures for make.
*/
#include <stdio.h>
#include "h.h"
/*
* Prints out the structures as defined in memory. Good for check
* that you make file does what you want (and for debugging make).
*/
void
prt()
{
register struct name * np;
register struct depend * dp;
register struct line * lp;
register struct cmd * cp;
register struct macro * mp;
for (mp = macrohead; mp; mp = mp->m_next)
fprintf(stderr, "%s = %s\n", mp->m_name, mp->m_val);
fputc('\n', stderr);
for (np = namehead.n_next; np; np = np->n_next)
{
fprintf(stderr, "%s:\n", np->n_name);
for (lp = np->n_line; lp; lp = lp->l_next)
{
fputc(':', stderr);
for (dp = lp->l_dep; dp; dp = dp->d_next)
fprintf(stderr, " %s", dp->d_name->n_name);
fputc('\n', stderr);
for (cp = lp->l_cmd; cp; cp = cp->c_next)
fprintf(stderr, "-\t%s\n", cp->c_cmd);
fputc('\n', stderr);
}
fputc('\n', stderr);
}
}
/*
* Recursive routine that does the actual checking.
*/
void
check(np)
struct name * np;
{
register struct depend * dp;
register struct line * lp;
if (np->n_flag & N_MARK)
fatal("Circular dependency from %s", np->n_name);
np->n_flag |= N_MARK;
for (lp = np->n_line; lp; lp = lp->l_next)
for (dp = lp->l_dep; dp; dp = dp->d_next)
check(dp->d_name);
np->n_flag &= ~N_MARK;
}
/*
* Look for circular dependancies.
* ie.
* a: b
* b: a
* is a circular dep
*/
void
circh()
{
register struct name * np;
for (np = namehead.n_next; np; np = np->n_next)
check(np);
}
/*
* Check the target .PRECIOUS, and mark its dependentd as precious
*/
void
precious()
{
register struct depend * dp;
register struct line * lp;
register struct name * np;
if (!((np = newname(".PRECIOUS"))->n_flag & N_TARG))
return;
for (lp = np->n_line; lp; lp = lp->l_next)
for (dp = lp->l_dep; dp; dp = dp->d_next)
dp->d_name->n_flag |= N_PREC;
}
@//E*O*F check.c//
chmod u=rw,g=r,o=r check.c
echo x - input.c
sed 's/^@//' > "input.c" <<'@//E*O*F input.c//'
/*
* Parse a makefile
*/
#include <stdio.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(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;
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(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.
*/
void
newline(np, dp, cp)
struct name * np;
struct depend * dp;
struct cmd * cp;
{
bool hascmds = FALSE; /* Target has commands */
register struct line * rp;
register struct line * rrp;
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)
error("Commands defined twice 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;
}
/*
* 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;
if (getline(str1, fd)) /* Read the first line */
return;
for(;;)
{
if (*str1 == '\t') /* Rules without targets */
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);
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 */
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 */
{
while (*str2 == '\t')
{
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);
if (!firstname)
firstname = np;
}
if (feof(fd)) /* EOF? */
return;
strcpy(str1, str2);
}
}
@//E*O*F input.c//
chmod u=rw,g=r,o=r input.c
echo x - macro.c
sed 's/^@//' > "macro.c" <<'@//E*O*F macro.c//'
/*
* Macro control for make
*/
#include "h.h"
struct macro * macrohead;
struct macro *
getmp(name)
char * name;
{
register struct macro * rp;
for (rp = macrohead; rp; rp = rp->m_next)
if (strcmp(name, rp->m_name) == 0)
return rp;
return (struct macro *)0;
}
char *
getmacro(name)
char * name;
{
struct macro * mp;
if (mp = getmp(name))
return mp->m_val;
else
return "";
}
struct macro *
setmacro(name, val)
char * name;
char * val;
{
register struct macro * rp;
register char * cp;
/* Replace macro definition if it exists */
for (rp = macrohead; rp; rp = rp->m_next)
if (strcmp(name, rp->m_name) == 0)
{
free(rp->m_val); /* Free space from old */
break;
}
if (!rp) /* If not defined, allocate space for new */
{
if ((rp = (struct macro *)malloc(sizeof (struct macro)))
== (struct macro *)0)
fatal("No memory for macro");
rp->m_next = macrohead;
macrohead = rp;
rp->m_flag = FALSE;
if ((cp = malloc(strlen(name)+1)) == (char *)0)
fatal("No memory for macro");
strcpy(cp, name);
rp->m_name = cp;
}
if ((cp = malloc(strlen(val)+1)) == (char *)0)
fatal("No memory for macro");
strcpy(cp, val); /* Copy in new value */
rp->m_val = cp;
return rp;
}
/*
* Do the dirty work for expand
*/
void
doexp(to, from, len, buf)
char ** to;
char * from;
int * len;
char * buf;
{
register char * rp;
register char * p;
register char * q;
register struct macro * mp;
rp = from;
p = *to;
while (*rp)
{
if (*rp != '$')
{
*p++ = *rp++;
(*len)--;
}
else
{
q = buf;
if (*++rp == '(')
while (*++rp && *rp != ')')
*q++ = *rp;
else if (!*rp)
{
*p++ = '$';
break;
}
else
*q++ = *rp;
*q = '\0';
if (*rp)
rp++;
if (!(mp = getmp(buf)))
mp = setmacro(buf, "");
if (mp->m_flag)
fatal("Infinitely recursive macro %s", mp->m_name);
mp->m_flag = TRUE;
*to = p;
doexp(to, mp->m_val, len, buf);
p = *to;
mp->m_flag = FALSE;
}
if (*len <= 0)
error("Expanded line too line");
}
*p = '\0';
*to = p;
}
/*
* Expand any macros in str.
*/
void
expand(str)
char * str;
{
static char a[LZ];
static char b[LZ];
char * p = str;
int len = LZ-1;
strcpy(a, str);
doexp(&p, a, &len, b);
}
@//E*O*F macro.c//
chmod u=rw,g=r,o=r macro.c
echo x - main.c
sed 's/^@//' > "main.c" <<'@//E*O*F main.c//'
/*
* make [-f makefile] [-ins] [target(s) ...]
*
* (Better than EON mk but not quite as good as UNIX make)
*
* -f makefile name
* -i ignore exit status
* -n Pretend to make
* -p Print all macros & targets
* -q Question up-to-dateness of target. Return exit status 1 if not
* -r Don't not use inbuilt rules
* -s Make silently
* -t Touch files instead of making them
* -m Change memory requirements
*/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/err.h>
#include "h.h"
#define MEMSPACE (16384)
char * myname;
char * makefile; /* The make file */
unsigned memspace = MEMSPACE;
FILE * ifd; /* Input file desciptor */
bool domake = TRUE; /* Go through the motions option */
bool ignore = FALSE; /* Ignore exit status option */
bool silent = FALSE; /* Silent option */
bool print = FALSE; /* Print debuging information */
bool rules = TRUE; /* Use inbuilt rules */
bool dotouch = FALSE;/* Touch files instead of making */
bool quest = FALSE; /* Question up-to-dateness of file */
void
main(argc, argv)
char ** argv;
int argc;
{
register char * p; /* For argument processing */
int estat; /* For question */
register struct name * np;
myname = (argc-- < 1) ? "make" : *argv++;
while ((argc > 0) && (**argv == '-'))
{
argc--; /* One less to process */
p = *argv++; /* Now processing this one */
while (*++p != '\0')
{
switch(*p)
{
case 'f': /* Alternate file name */
if (*++p == '\0')
{
if (argc-- <= 0)
usage();
p = *argv++;
}
makefile = p;
goto end_of_args;
case 'm': /* Change space requirements */
if (*++p == '\0')
{
if (argc-- <= 0)
usage();
p = *argv++;
}
memspace = atoi(p);
goto end_of_args;
case 'n': /* Pretend mode */
domake = FALSE;
break;
case 'i': /* Ignore fault mode */
ignore = TRUE;
break;
case 's': /* Silent about commands */
silent = TRUE;
break;
case 'p':
print = TRUE;
break;
case 'r':
rules = FALSE;
break;
case 't':
dotouch = TRUE;
break;
case 'q':
quest = TRUE;
break;
default: /* Wrong option */
usage();
}
}
end_of_args:;
}
if (initalloc(memspace) == 0xffff) /* Must get memory for alloc */
fatal("Cannot initalloc memory");
if (strcmp(makefile, "-") == 0) /* Can use stdin as makefile */
ifd = stdin;
else
if (!makefile) /* If no file, then use default */
{
if ((ifd = fopen(DEFN1, "r")) == (FILE *)0)
if (errno != ER_NOTF)
fatal("Can't open %s; error %02x", DEFN1, errno);
if ((ifd == (FILE *)0)
&& ((ifd = fopen(DEFN2, "r")) == (FILE *)0))
fatal("Can't open %s", DEFN2);
}
else
if ((ifd = fopen(makefile, "r")) == (FILE *)0)
fatal("Can't open %s", makefile);
makerules();
setmacro("$", "$");
while (argc && (p = index(*argv, '=')))
{
char c;
c = *p;
*p = '\0';
setmacro(*argv, p+1);
*p = c;
argv++;
argc--;
}
input(ifd); /* Input all the gunga */
fclose(ifd); /* Finished with makefile */
lineno = 0; /* Any calls to error now print no line number */
if (print)
prt(); /* Print out structures */
np = newname(".SILENT");
if (np->n_flag & N_TARG)
silent = TRUE;
np = newname(".IGNORE");
if (np->n_flag & N_TARG)
ignore = TRUE;
precious();
if (!domake)
silent = FALSE;
if (!firstname)
fatal("No targets defined");
circh(); /* Check circles in target definitions */
if (!argc)
estat = make(firstname, 0);
else while (argc--)
{
if (!print && !silent && strcmp(*argv, "love") == 0)
printf("Not war!\n");
estat |= make(newname(*argv++), 0);
}
if (quest)
exit(estat);
else
exit(0);
}
usage()
{
fprintf(stderr, "Usage: %s [-f makefile] [-inpqrst] [macro=val ...] [target(s) ...]\n", myname);
exit(1);
}
void
fatal(msg, a1, a2, a3)
char *msg;
{
fprintf(stderr, "%s: ", myname);
fprintf(stderr, msg, a1, a2, a3);
fputc('\n', stderr);
exit(1);
}
@//E*O*F main.c//
chmod u=rw,g=r,o=r main.c
echo x - make.c
sed 's/^@//' > "make.c" <<'@//E*O*F make.c//'
/*
* Do the actual making for make
*/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/err.h>
#include "h.h"
/*
* Exec a shell that returns exit status correctly (/bin/esh).
* The standard EON shell returns the process number of the last
* async command, used by the debugger (ugg).
* [exec on eon is like a fork+exec on unix]
*/
int
dosh(string, shell)
char * string;
char * shell;
{
int number;
return ((number = execl(shell, shell,"-c", string, 0)) == -1) ?
-1: /* couldn't start the shell */
wait(number); /* return its exit status */
}
/*
* Do commands to make a target
*/
void
docmds(np)
struct name * np;
{
bool ssilent = silent;
bool signore = ignore;
int estat;
register char * q;
register char * p;
char * shell;
register struct line * lp;
register struct cmd * cp;
if (*(shell = getmacro("SHELL")) == '\0')
shell = ":bin/esh";
for (lp = np->n_line; lp; lp = lp->l_next)
for (cp = lp->l_cmd; cp; cp = cp->c_next)
{
strcpy(str1, cp->c_cmd);
expand(str1);
q = str1;
while ((*q == '@') || (*q == '-'))
{
if (*q == '@') /* Specific silent */
ssilent = TRUE;
else /* Specific ignore */
signore = TRUE;
q++; /* Not part of the command */
}
if (!ssilent)
fputs(" ", stdout);
for (p=q; *p; p++)
{
if (*p == '\n' && p[1] != '\0')
{
*p = ' ';
if (!ssilent)
fputs("\\\n", stdout);
}
else if (!ssilent)
putchar(*p);
}
if (!ssilent)
putchar('\n');
if (domake)
{ /* Get the shell to execute it */
if ((estat = dosh(q, shell)) != 0)
{
if (estat == -1)
fatal("Couldn't execute %s", shell);
else
{
printf("%s: Error code %d", myname, estat);
if (signore)
fputs(" (Ignored)\n", stdout);
else
{
putchar('\n');
if (!(np->n_flag & N_PREC))
if (unlink(np->n_name) == 0)
printf("%s: '%s' removed.\n", myname, np->n_name);
exit(estat);
}
}
}
}
}
}
/*
* Get the modification time of a file. If the first
* doesn't exist, it's modtime is set to 0.
*/
void
modtime(np)
struct name * np;
{
struct stat info;
int fd;
if ((fd = open(np->n_name, 0)) < 0)
{
if (errno != ER_NOTF)
fatal("Can't open %s; error %02x", np->n_name, errno);
np->n_time = 0L;
}
else if (getstat(fd, &info) < 0)
fatal("Can't getstat %s; error %02x", np->n_name, errno);
else
np->n_time = info.st_mod;
close(fd);
}
/*
* Update the mod time of a file to now.
*/
void
touch(np)
struct name * np;
{
char c;
int fd;
if (!domake || !silent)
printf(" touch %s\n", np->n_name);
if (domake)
{
if ((fd = open(np->n_name, 0)) < 0)
printf("%s: '%s' no touched - non-existant\n",
myname, np->n_name);
else
{
uread(fd, &c, 1, 0);
uwrite(fd, &c, 1);
}
close(fd);
}
}
/*
* Recursive routine to make a target.
*/
int
make(np, level)
struct name * np;
int level;
{
register struct depend * dp;
register struct line * lp;
time_t dtime = 1;
if (np->n_flag & N_DONE)
return 0;
if (!np->n_time)
modtime(np); /* Gets modtime of this file */
if (rules)
{
for (lp = np->n_line; lp; lp = lp->l_next)
if (lp->l_cmd)
break;
if (!lp)
dyndep(np);
}
if (!(np->n_flag & N_TARG) && np->n_time == 0L)
fatal("Don't know how to make %s", np->n_name);
for (lp = np->n_line; lp; lp = lp->l_next)
for (dp = lp->l_dep; dp; dp = dp->d_next)
{
make(dp->d_name, level+1);
dtime = max(dtime, dp->d_name->n_time);
}
np->n_flag |= N_DONE;
if (quest)
{
rtime(&np->n_time);
return np->n_time < dtime;
}
else if (np->n_time < dtime)
{
if (dotouch)
touch(np);
else
{
setmacro("@", np->n_name);
docmds(np);
}
rtime(&np->n_time);
}
else if (level == 0)
printf("%s: '%s' is up to date\n", myname, np->n_name);
return 0;
}
@//E*O*F make.c//
chmod u=rw,g=r,o=r make.c
echo x - reader.c
sed 's/^@//' > "reader.c" <<'@//E*O*F reader.c//'
/*
* Read in makefile
*/
#include <stdio.h>
#include "h.h"
int lineno;
/*
* Syntax error handler. Print message, with line number, and exits.
*/
void
error(msg, a1, a2, a3)
char * msg;
{
fprintf(stderr, "%s: ", myname);
fprintf(stderr, msg, a1, a2, a3);
if (lineno)
fprintf(stderr, " on line %d", lineno);
fputc('\n', stderr);
exit(1);
}
/*
* Read a line into the supplied string of length LZ. Remove
* comments, ignore blank lines. Deal with quoted (\) #, and
* quoted newlines. If EOF return TRUE.
*/
bool
getline(str, fd)
char * str;
FILE * fd;
{
register char * p;
char * q;
int pos = 0;
for (;;)
{
if (fgets(str+pos, LZ-pos, fd) == (char *)0)
return TRUE; /* EOF */
lineno++;
if ((p = index(str+pos, '\n')) == (char *)0)
error("Line too long");
if (p[-1] == '\\')
{
p[-1] = '\n';
pos = p - str;
continue;
}
p = str;
while (((q = index(p, '#')) != (char *)0) &&
(p != q) && (q[-1] == '\\'))
{
char *a;
a = q - 1; /* Del \ chr; move rest back */
p = q;
while (*a++ = *q++)
;
}
if (q != (char *)0)
{
q[0] = '\n';
q[1] = '\0';
}
p = str;
while (isspace(*p)) /* Checking for blank */
p++;
if (*p != '\0')
return FALSE;
pos = 0;
}
}
/*
* Get a word from the current line, surounded by white space.
* return a pointer to it. String returned has no white spaces
* in it.
*/
char *
gettok(ptr)
char **ptr;
{
register char * p;
while (isspace(**ptr)) /* Skip spaces */
(*ptr)++;
if (**ptr == '\0') /* Nothing after spaces */
return NULL;
p = *ptr; /* word starts here */
while ((**ptr != '\0') && (!isspace(**ptr)))
(*ptr)++; /* Find end of word */
*(*ptr)++ = '\0'; /* Terminate it */
return(p);
}
@//E*O*F reader.c//
chmod u=rw,g=r,o=r reader.c
echo x - rules.c
sed 's/^@//' > "rules.c" <<'@//E*O*F rules.c//'
/*
* Control of the implicit suffix rules
*/
#include "h.h"
/*
* Return a pointer to the suffix of a name
*/
char *
suffix(name)
char * name;
{
return rindex(name, '.');
}
/*
* Dynamic dependency. This routine applies the suffis rules
* to try and find a source and a set of rules for a missing
* target. If found, np is made into a target with the implicit
* source name, and rules. Returns TRUE if np was made into
* a target.
*/
bool
dyndep(np)
struct name * np;
{
register char * p;
register char * q;
register char * suff; /* Old suffix */
register char * basename; /* Name without suffix */
struct name * op; /* New dependent */
struct name * sp; /* Suffix */
struct line * lp;
struct depend * dp;
char * newsuff;
p = str1;
q = np->n_name;
suff = suffix(q);
while (q < suff)
*p++ = *q++;
*p = '\0';
basename = setmacro("*", str1)->m_val;
if (!((sp = newname(".SUFFIXES"))->n_flag & N_TARG))
return FALSE;
for (lp = sp->n_line; lp; lp = lp->l_next)
for (dp = lp->l_dep; dp; dp = dp->d_next)
{
newsuff = dp->d_name->n_name;
if (strlen(suff)+strlen(newsuff)+1 >= LZ)
fatal("Suffix rule too long");
p = str1;
q = newsuff;
while (*p++ = *q++)
;
p--;
q = suff;
while (*p++ = *q++)
;
sp = newname(str1);
if (sp->n_flag & N_TARG)
{
p = str1;
q = basename;
if (strlen(basename) + strlen(newsuff)+1 >= LZ)
fatal("Implicit name too long");
while (*p++ = *q++)
;
p--;
q = newsuff;
while (*p++ = *q++)
;
op = newname(str1);
if (!op->n_time)
modtime(op);
if (op->n_time)
{
dp = newdep(op, 0);
newline(np, dp, sp->n_line->l_cmd);
setmacro("<", op->n_name);
return TRUE;
}
}
}
return FALSE;
}
/*
* Make the default rules
*/
void
makerules()
{
struct cmd * cp;
struct name * np;
struct depend * dp;
setmacro("BDSCC", "asm");
/* setmacro("BDSCFLAGS", ""); */
cp = newcmd("$(BDSCC) $(BDSCFLAGS) -n $<", 0);
np = newname(".c.o");
newline(np, 0, cp);
setmacro("CC", "c");
setmacro("CFLAGS", "-O");
cp = newcmd("$(CC) $(CFLAGS) -c $<", 0);
np = newname(".c.obj");
newline(np, 0, cp);
setmacro("M80", "asm -n");
/* setmacro("M80FLAGS", ""); */
cp = newcmd("$(M80) $(M80FLAGS) $<", 0);
np = newname(".mac.o");
newline(np, 0, cp);
setmacro("AS", "zas");
/* setmacro("ASFLAGS", ""); */
cp = newcmd("$(ZAS) $(ASFLAGS) -o $@ $<", 0);
np = newname(".as.obj");
newline(np, 0, cp);
np = newname(".as");
dp = newdep(np, 0);
np = newname(".obj");
dp = newdep(np, dp);
np = newname(".c");
dp = newdep(np, dp);
np = newname(".o");
dp = newdep(np, dp);
np = newname(".mac");
dp = newdep(np, dp);
np = newname(".SUFFIXES");
newline(np, dp, 0);
}
@//E*O*F rules.c//
chmod u=rw,g=r,o=r rules.c
exit 0
More information about the Comp.sources.unix
mailing list