|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 20397 (0x4fad)
Types: TextFile
Notes: UNIX file
Names: »make.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/make/make.c«
/*
* make -- maintain program groups
* td 80.09.17
* things to do:
* upon occasion things aren't freed up that should be
* figure out how .DEFAULT works
* write a routine to add a string to a token, and use it
* things done:
* 20-Oct-82 Made nextc properly translate "\\\n[ ]*" to ' '.
* 15-Jan-85 Made portable enough for z-8000, readable enough for
* human beings.
*/
#include "make.h"
/* read characters from backup (where macros have been expanded) or from
* whatever the open file of the moment is. keep track of line #s.
*/
readc()
{
if(nbackup!=0)
return(backup[--nbackup]);
if(lastc=='\n')
lineno++;
lastc=getc(fd);
return(lastc);
}
/* put c into backup[] */
putback(c)
{
if(c==EOF)
return;
if (nbackup == NBACKUP)
err("Macro definition too long");
backup[nbackup++]=c;
}
/* put s into backup */
unreads(s)
register char *s;
{
register char *t;
t = &s[strlen(s) - 1];
while (t >= s)
putback(*t--);
}
/* return a pointer to the macro definition assigned to macro name s.
* return NULL if the macro has not been defined.
*/
char *
getdef(s)
register char *s;
{
register struct macro *i;
for (i = macro; i != nmacro; ++i)
if (Streq(s, i->name))
return (i->value);
return (NULL);
}
/* install macro with name name and value value in macro[]. Overwrite an
* existing value if it is not protected.
*/
define(name, value, protected)
register char *name, *value;
{
register struct macro *i;
if(dflag)
printf("define %s = %s\n", name, value);
for (i = macro; i != nmacro; ++i)
if (Streq(name, i->name)) {
if (!i->protected) {
free(i->value);
i->value = value;
i->protected = protected;
} else if (dflag)
printf("... definition suppressed\n");
return;
}
if (nmacro == LMACRO)
err("Too many macro definitions");
i->name = name;
i->value = value;
i->protected = protected;
++nmacro;
}
/* return the next character from the input file. eat comments, return EOS
* for a newline not followed by an action, \n for newlines that are followed
* by actions, $ for $$, put macro expansions in backup[] (no complaint if
* macro is not defined).
*/
nextc()
{
register char *s;
register c;
Again:
if((c=readc())=='#'){
do
c=readc();
while(c!='\n' && c!=EOF);
}
if(c=='\n'){
if((c=readc())!=' ' && c!='\t'){
putback(c);
return(EOS);
}
do
c=readc();
while(c==' ' || c=='\t');
putback(c);
return('\n');
}
if(c=='\\'){
c=readc();
if(c=='\n') {
while ((c=readc())==' ' || c=='\t')
;
putback(c);
return(' ');
}
putback(c);
return('\\');
}
if(!defining && c=='$'){
c=readc();
if(c=='$')
return(c);
if(c=='@' || c=='?' || c=='<' || c=='*'){
putback(c);
return('$');
}
if (c <= ' ' || 0177 <= c)
err("Bad macro name");
if(c=='(') {
s=macroname;
while(' '<(c=readc()) && c<0177 && c!=')')
if(s!=¯oname[NMACRONAME])
*s++=c;
if (c != ')')
err("Bad macro name");
*s++ = '\0';
} else {
macroname[0]=c;
macroname[1]='\0';
}
if((s=getdef(macroname))!=NULL)
unreads(s);
goto Again;
}
return(c);
}
/* cry and die */
die(str)
char *str;
{
fprintf(stderr, "make: %r\n", &str);
exit(ERROR);
}
/* print lineno, cry and die */
err(s)
char *s;
{
fprintf(stderr, "make: %d: %r\n", lineno, &s);
exit(ERROR);
}
/* Get a block of l0+l1 bytes copy s0 and s1 into it, and return a pointer to
* the beginning of the block.
*/
char *
extend(s0, l0, s1, l1)
char *s0, *s1;
{
register char *t;
if (s0 == NULL)
t = malloc(l1);
else
t = realloc(s0, l0 + l1);
if (t == NULL)
err("Out of space");
strncpy(t+l0, s1, l1);
return(t);
}
/* Return 1 if c is EOS, EOF, or one of the characters in s */
delim(c, s)
register char c;
char *s;
{
char *index();
return (c == EOS || c == EOF || index(s, c) != NULL);
}
/* Prepare to copy a new token string into the token buffer; if the old value
* in token wasn't saved, tough matzohs.
*/
starttoken()
{
token=NULL;
tokp=tokbuf;
toklen=0;
}
/* Put c in the token buffer; if the buffer is full, copy its contents into
* token and start agin at the beginning of the buffer.
*/
addtoken(c)
{
if(tokp==&tokbuf[NTOKBUF]){
token=extend(token, toklen-NTOKBUF, tokbuf, NTOKBUF);
tokp=tokbuf;
}
*tokp++=c;
toklen++;
}
/* mark the end of the token in the buffer and save it in token. */
endtoken()
{
addtoken('\0');
token=extend(token, toklen-(tokp-tokbuf), tokbuf, tokp-tokbuf);
}
/* Install value at the end of the token list which begins with next; return
* a pointer to the beginning of the list, which is the one just installed if
* next was NULL.
*/
struct token *
listtoken(value, next)
char *value;
struct token *next;
{
register struct token *p;
register struct token *t;
t=(struct token *)malloc(sizeof *t); /*Necessaire ou le contraire?*/
if (t == NULL)
err("Out of space");
t->value=value;
t->nexttoken=NULL;
if(next==NULL)
return(t);
for(p=next;p->nexttoken!=NULL;p=p->nexttoken);
p->nexttoken=t;
return(next);
}
/* Read macros, dependencies, and actions from the file with name file, or
* from whatever file is already open. The first string of tokens is saved
* in a list pointed to by tp; if it was a macro, the definition goes in
* token, and we install it in macro[]; if tp points to a string of targets,
* its depedencies go in a list pointed to by dp, and the action to recreate
* it in token, and the whole shmear is installed.
*/
input(file)
char *file;
{
struct token *tp = NULL, *dp = NULL, *np;
register c;
char *action;
int twocolons;
if(file!=NULL && (fd=fopen(file, "r"))==NULL)
die("can't open %s", file);
lineno=1;
lastc=EOF;
for(;;){
c=nextc();
for(;;){
while(c==' ' || c=='\t')
c=nextc();
if(delim(c, "=:;\n"))
break;
starttoken();
while(!delim(c, " \t\n=:;")){
addtoken(c);
c=nextc();
}
endtoken();
tp=listtoken(token, tp);
}
switch(c){
case EOF:
if(tp!=NULL)
err("Incomplete line at end of file");
fclose(fd);
return;
case EOS:
if(tp==NULL)
break;
case '\n':
err("Newline after target or macroname");
case ';':
err("; after target or macroname");
/* SynErr:
* err("Syntax error");
*/
case '=':
if(tp==NULL || tp->nexttoken!=NULL)
err("= without macro name or in token list");
defining++;
starttoken();
while((c=nextc())!=EOS && c!=EOF)
addtoken(c);
endtoken();
define(tp->value, token, 0);
defining=0;
break;
case ':':
if(tp==NULL)
err(": without preceding target");
c=nextc();
if(c==':'){
twocolons=1;
c=nextc();
} else
twocolons=0;
for(;;){
while(c==' ' || c=='\t')
c=nextc();
if(delim(c, "=:;\n"))
break;
starttoken();
while(!delim(c, " \t\n=:;")){
addtoken(c);
c=nextc();
}
endtoken();
dp=listtoken(token, dp);
}
switch(c){
case ':':
err("::: or : in or after dependency list");
case '=':
err("= in or after dependency");
case EOF:
err("Incomplete line at end of file");
case ';':
case '\n':
starttoken();
while((c=nextc())!=EOS && c!=EOF)
addtoken(c);
endtoken();
action=token;
break;
case EOS:
action=NULL;
}
install(tp, dp, action, twocolons);
}
while(tp!=NULL){
np=tp->nexttoken;
free(tp);
tp=np;
}
while(dp!=NULL){
np=dp->nexttoken;
free(dp);
dp=np;
}
}
}
/* Return the last modified date of file with name name. If it's an archive,
* open it up and read the insertion date of the pertinent member.
*/
time_t
getmdate(name)
char *name;
{
char *subname,
*lwa;
int fd;
int magic;
time_t result;
struct ar_hdr hdrbuf;
char *index();
if (stat(name, &statbuf) ==0)
return (statbuf.st_mtime);
subname = index(name, '(');
if (subname == NULL)
return (0);
lwa = &name[strlen(name) - 1];
if (*lwa != ')')
return (0);
*subname = NUL;
fd = open(name, READ);
*subname++ = '(';
if (fd == EOF)
return (0);
if (read(fd, &magic, sizeof magic) != sizeof magic || magic != ARMAG) {
close(fd);
return (0);
}
*lwa = NUL;
result = 0;
while (read(fd, &hdrbuf, sizeof hdrbuf) == sizeof hdrbuf) {
if (strcmp(hdrbuf.ar_name, subname) == 0) {
result = hdrbuf.ar_date;
break;
}
lseek(fd, hdrbuf.ar_size, REL);
}
*lwa = ')';
return (result);
}
/* Does file name exist? */
exists(name)
char *name;
{
return(stat(name, &statbuf)>=0);
}
/* Return a pointer to the symbol table entry with name "name", NULL if it's
* not there.
*/
struct sym *
findsym(name)
char *name;
{
register struct sym *sp;
for(sp=sym;sp!=NULL;sp=sp->nextsym)
if(Streq(name, sp->name))
return(sp);
return(NULL);
}
/* Look for symbol with name "name" in the symbol table; install it if it's
* not there; initialize the action and dependency lists to NULL, the type to
* unknown, get the modification date, and return a pointer to the entry.
*/
struct sym *
lookup(name)
char *name;
{
register struct sym *sp;
if((sp=findsym(name))!=NULL)
return(sp);
if ((sp = (struct sym *)malloc(sizeof *sp)) == NULL) /*necessary?*/
err("Out of space (lookup)");
sp->name=name;
sp->action=NULL;
sp->deplist=NULL;
sp->type=T_UNKNOWN;
sp->moddate=getmdate(sp->name);
sp->nextsym=sym;
sym=sp;
return(sp);
}
/* Install a dependency with symbol having name "name", action "action" in
* the end of the dependency list pointed to by nextdep. If s has already
* been noted as a file in the dependency list, install action. Return a
* pointer to the beginning of the dependency list.
*/
struct dep *
adddep(name, action, nextdep)
char *name, *action;
struct dep *nextdep;
{
register struct dep *v;
register struct sym *s;
struct dep *dp;
s=lookup(name);
for(v=nextdep;v!=NULL;v=v->nextdep)
if(s==v->symbol){
if (action != NULL) {
if(v->action!=NULL)
err("Multiple detailed actions for %s",
s->name);
v->action=action;
}
return(nextdep);
}
if ((v = (struct dep *)malloc(sizeof *v)) == NULL) /*necessary?*/
err("Out of core (adddep)");
v->symbol=s;
v->action=action;
v->nextdep=NULL;
if(nextdep==NULL)
return(v);
for(dp=nextdep;dp->nextdep!=NULL;dp=dp->nextdep);
dp->nextdep=v;
return(nextdep);
}
/* Do everything for a dependency with left-hand side cons, r.h.s. ante,
* action "action", and one or two colons. If cons is the first target in the
* file, it becomes the default target. Mark each target in cons as detailed
* if twocolons, undetailed if not, and install action in the symbol table
* action slot for cons in the latter case. Call adddep() to actually create
* the dependency list.
*/
install(cons, ante, action, twocolons)
struct token *ante, *cons;
char *action;
{
struct sym *cp;
struct token *ap;
if(deftarget==NULL && cons->value[0]!='.')
deftarget=cons->value;
if(dflag){
printf("Ante:");
ap=ante;
while(ap!=NULL){
printf(" %s", ap->value);
ap=ap->nexttoken;
}
printf("\nCons:");
ap=cons;
while(ap!=NULL){
printf(" %s", ap->value);
ap=ap->nexttoken;
}
printf("\n");
if(action!=NULL)
printf("Action: `%s'\n", action);
if(twocolons)
printf("two colons\n");
}
for (; cons != NULL; cons = cons->nexttoken) {
cp=lookup(cons->value);
if(cp==suffixes && ante==NULL)
cp->deplist=NULL;
else{
if(twocolons){
if(cp->type==T_UNKNOWN)
cp->type=T_DETAIL;
else if(cp->type!=T_DETAIL)
err("`::' not allowed for %s",
cp->name);
} else {
if(cp->type==T_UNKNOWN)
cp->type=T_NODETAIL;
else if(cp->type!=T_NODETAIL)
err("Must use `::' for %s", cp->name);
if (action != NULL) {
if(cp->action != NULL)
err("Multiple actions for %s",
cp->name);
cp->action = action;
}
}
for(ap=ante;ap!=NULL;ap=ap->nexttoken)
cp->deplist=adddep(ap->value,
twocolons?action:NULL, cp->deplist);
}
}
}
/* If target exists, make it */
maketarget(target)
char *target;
{
register struct sym *s;
s=findsym(target);
if(s==NULL)
die("Target %s is not defined", target);
make(s);
}
/* Make s; first, make everything s depends on; if the target has detailed
* actions, execute any implicit actions associated with it, then execute
* the actions associated with the dependencies which are newer than s.
* Otherwise, put the dependencies that are newer than s in token ($?),
* make s if it doesn't exist, and call docmd.
*/
make(s)
register struct sym *s;
{
register struct dep *dep;
register char *t;
int update;
int type;
if(s->type==T_DONE)
return;
if(dflag)
printf("Making %s\n", s->name);
type=s->type;
s->type=T_DONE;
for(dep=s->deplist;dep!=NULL;dep=dep->nextdep)
make(dep->symbol);
if(type==T_DETAIL){
implicit(s, "", 0);
for(dep=s->deplist;dep!=NULL;dep=dep->nextdep)
if(dep->symbol->moddate>=s->moddate)
docmd(s, dep->action, s->name,
dep->symbol->name, "", "");
} else {
update=0;
starttoken();
for(dep=s->deplist;dep!=NULL;dep=dep->nextdep){
if(dflag)
printf("%s time=%ld %s time=%ld\n",
dep->symbol->name, dep->symbol->moddate,
s->name, s->moddate);
if(dep->symbol->moddate>=s->moddate){
update++;
addtoken(' ');
for(t=dep->symbol->name;*t;t++)
addtoken(*t);
}
}
endtoken();
if (!update && !exists(s->name)) {
update = TRUE;
if (dflag)
printf("`%s' made due to non-existence\n",
s->name);
}
if(s->action==NULL)
implicit(s, token, update);
else if(update)
docmd(s, s->action, s->name, token, "", "");
}
}
/*
* Explen returns the length of the string str after the
* macro-variables in it are expanded.
*/
int
explen(str)
register char *str;
{
int result;
register char *mp;
char *index();
result = strlen(str);
while ((str = index(str, '$')) != NULL)
if ((mp = index(macvars, *++str)) != NULL) {
++str;
result += mvarlen[mp - macvars] - 2;
}
return (result);
}
/*
* Expand returns a pointer to a copy of the string str with
* the macro-variables in it expanded.
*/
char *
expand(str)
register char *str;
{
register char *rptr;
register char ch;
char *mp;
char *result;
char *index();
rptr = (char *)malloc(explen(str) + 1);
if (rptr == NULL)
die("Out of space");
result = rptr;
while ((ch = *str++) != NUL)
if (ch == '$' && (mp = index(macvars, *str)) != NULL) {
strcpy(rptr, mvarval[mp - macvars]);
rptr += mvarlen[mp - macvars];
++str;
} else
*rptr++ = ch;
*rptr = NUL;
return (result);
}
/*
* Varexp epands the variable macros (@, ?, <, and *) in the
* string str. It first places the values and their lengths in
* the parallel arrays mvarval and mvarlen.
*/
char *
varexp(str, at, ques, less, star)
char *str, *at, *ques, *less, *star;
{
register char **valp = mvarval;
register int *lenp = mvarlen;
*lenp++ = strlen(at);
*valp++ = at;
*lenp++ = strlen(ques);
*valp++ = ques;
*lenp++ = strlen(less);
*valp++ = less;
*lenp = strlen(star);
*valp = star;
return (expand(str));
}
/* Mark s as modified; if tflag, touch s, otherwise execute the necessary
* commands.
*/
docmd(s, cmd, at, ques, less, star)
struct sym *s;
char *cmd, *at, *ques, *less, *star;
{
char *xcmd;
static char tcmd[] = "touch ";
if (dflag)
printf("ex `%s'\n\t$@=`%s'\n\t$?=`%s'\n\t$<=`%s'\n\t$*=`%s'\n",
cmd, at, ques, less, star);
if (qflag)
exit(NOTUTD);
s->moddate = now;
if (tflag) {
xcmd = (char *)malloc(strlen(tcmd) + strlen(s->name) + 1);
if (xcmd == NULL)
die("Out of Space");
strcpy(xcmd, tcmd);
strcat(xcmd, s->name);
} else if (cmd == NULL)
return;
else
xcmd = varexp(cmd, at, ques, less, star);
doit(xcmd);
free(xcmd);
}
/* look for '-' (ignore errors) and '@' (silent) in cmd, then execute it
* and note the return status.
*/
doit(cmd)
register char *cmd;
{
register char *mark;
int sflg, iflg;
int rstat;
char *index();
if (nflag) {
printf("%s\n", cmd);
return;
}
do {
mark = index(cmd, '\n');
if (mark != NULL)
*mark = NUL;
if (*cmd == '-') {
++cmd;
iflg = TRUE;
} else
iflg = iflag;
if (*cmd == '@') {
++cmd;
sflg = TRUE;
} else
sflg = sflag;
if (!sflg)
printf("%s\n", cmd);
fflush(stdout);
rstat = system(cmd);
if (rstat != 0 && !iflg)
if (sflg)
die("%s exited with status %d",
cmd, rstat);
else
die(" exited with status %d", rstat);
cmd = mark + 1;
} while (mark != NULL && *cmd != NUL);
}
/* Find the implicit rule to generate obj and execute it. Put the name of
* obj up to '.' in prefix, and look for the rest in the dependency list
* of .SUFFIXES. Find the file "prefix.foo" upon which obj depends, where
* foo appears in the dependency list of suffixes after the suffix of obj.
* Then make obj according to the rule from makeactions. If we can't find
* any rules, use .DEFAULT, provided we're definite.
*/
implicit(obj, ques, definite)
struct sym *obj;
char *ques;
{
register char *s;
register struct dep *d;
char *prefix, *file, *rulename;
struct sym *rule;
struct sym *subj;
if(dflag)
printf("Implicit %s (%s)\n", obj->name, ques);
starttoken();
for(s=obj->name;*s!='.' && *s!='\0';s++)
addtoken(*s);
endtoken();
if(*s=='\0'){
free(token);
if (definite)
defalt(obj, ques);
return;
}
prefix=token;
for(d=suffixes->deplist;d!=NULL;d=d->nextdep)
if(Streq(s, d->symbol->name))
break;
if(d==NULL){
free(prefix);
if (definite)
defalt(obj, ques);
return;
}
while((d=d->nextdep)!=NULL){
starttoken();
for(s=obj->name;*s!='.';s++)
addtoken(*s);
for(s=d->symbol->name;*s;s++)
addtoken(*s);
endtoken();
file=token;
if(exists(file)){
starttoken();
for(s=d->symbol->name;*s!='\0';s++)
addtoken(*s);
for(s=obj->name;*s!='.';s++);
for(;*s!='\0';s++)
addtoken(*s);
endtoken();
rulename=token;
if((rule=findsym(rulename))!=NULL){
make(subj=lookup(file));
if(definite || subj->moddate>=obj->moddate)
docmd(obj, rule->action,
obj->name, ques, file, prefix);
free(prefix);
free(rulename);
return;
}
free(rulename);
}
free(file);
}
free(prefix);
if (definite)
defalt(obj, ques);
}
/*
* Deflt uses the commands associated to `.DEFAULT' to make the object
* `obj'.
*/
defalt(obj, ques)
struct sym *obj;
char *ques;
{
if (deflt == NULL)
die("Don't know how to make %s", obj->name);
docmd(obj, deflt->action, obj->name, ques, "", "");
}
main(argc, argv)
char *argv[];
{
register char *s, *value;
struct token *fp = NULL;
struct sym *sp;
struct dep *d;
struct macro *mp;
char *index();
time(&now);
++argv;
--argc;
while (argc > 0 && argv[0][0] == '-')
for (--argc, s = *argv++; *++s != NUL;)
switch (*s) {
case 'i': iflag++; break;
case 's': sflag++; break;
case 'r': rflag++; break;
case 'n': nflag++; break;
case 't': tflag++; break;
case 'q': qflag++; break;
case 'p': pflag++; break;
case 'd': dflag++; break;
case 'f':
if (--argc < 0)
Usage();
fp=listtoken(*argv++, fp);
break;
default:
Usage();
}
while (argc > 0 && (value = index(*argv, '=')) != NULL) {
s = *argv;
while (*s != ' ' && *s != '\t' && *s != '=')
++s;
*s = '\0';
define(*argv++, value+1, 1);
--argc;
}
suffixes=lookup(".SUFFIXES");
if (!rflag)
input("/usr/lib/makemacros");
deftarget = NULL;
if (fp == NULL) {
if ((fd = fopen("makefile", "r")) != NULL)
input(NULL);
else
input("Makefile");
} else {
fd = stdin;
do {
input( strcmp(fp->value, "-") == 0 ? NULL : fp->value);
fp = fp->nexttoken;
} while (fp != NULL);
}
if (!rflag)
input("/usr/lib/makeactions");
if (findsym(".IGNORE") != NULL)
++iflag;
if (findsym(".SILENT") != NULL)
++sflag;
deflt = findsym(".DEFAULT");
if(pflag){
if(nmacro != macro) {
printf("Macros:\n");
for (mp = macro; mp != nmacro; ++mp)
printf("%s=%s\n", mp->name, mp->value);
}
printf("Rules:\n");
for(sp=sym;sp!=NULL;sp=sp->nextsym){
if(sp->type!=T_UNKNOWN){
printf("%s:", sp->name);
if(sp->type==T_DETAIL)
putchar(':');
for(d=sp->deplist;d!=NULL;d=d->nextdep)
printf(" %s", d->symbol->name);
printf("\n");
if(sp->action)
printf("\t%s\n", sp->action);
}
}
}
if(argc > 0){
do{
maketarget(*argv++);
} while (--argc > 0);
} else
maketarget(deftarget);
exit(ALLOK);
}
/* Whine about usage and then quit */
Usage()
{
fprintf(stderr, "%s\n", usage);
exit(1);
}