310 lines
5.2 KiB
C
310 lines
5.2 KiB
C
#include "mk.h"
|
|
|
|
char *infile;
|
|
int mkinline;
|
|
static int rhead(char *, Word **, Word **, int *, char **);
|
|
static char *rbody(Biobuf*);
|
|
extern Word *target1;
|
|
|
|
void
|
|
parse(char *f, int fd, int varoverride)
|
|
{
|
|
int hline;
|
|
char *body;
|
|
Word *head, *tail;
|
|
int attr, set, pid;
|
|
char *prog, *p;
|
|
int newfd;
|
|
Biobuf in;
|
|
Bufblock *buf;
|
|
|
|
if(fd < 0){
|
|
perror(f);
|
|
Exit();
|
|
}
|
|
ipush();
|
|
infile = strdup(f);
|
|
mkinline = 1;
|
|
Binit(&in, fd, OREAD);
|
|
buf = newbuf();
|
|
while(assline(&in, buf)){
|
|
hline = mkinline;
|
|
switch(rhead(buf->start, &head, &tail, &attr, &prog))
|
|
{
|
|
case '<':
|
|
p = wtos(tail, ' ');
|
|
if(*p == 0){
|
|
SYNERR(-1);
|
|
fprint(2, "missing include file name\n");
|
|
Exit();
|
|
}
|
|
newfd = open(p, OREAD);
|
|
if(newfd < 0){
|
|
fprint(2, "warning: skipping missing include file: ");
|
|
perror(p);
|
|
} else
|
|
parse(p, newfd, 0);
|
|
break;
|
|
case '|':
|
|
p = wtos(tail, ' ');
|
|
if(*p == 0){
|
|
SYNERR(-1);
|
|
fprint(2, "missing include program name\n");
|
|
Exit();
|
|
}
|
|
execinit();
|
|
pid=pipecmd(p, envy, &newfd);
|
|
if(newfd < 0){
|
|
fprint(2, "warning: skipping missing program file: ");
|
|
perror(p);
|
|
} else
|
|
parse(p, newfd, 0);
|
|
while(waitup(-3, &pid) >= 0)
|
|
;
|
|
if(pid != 0){
|
|
fprint(2, "bad include program status\n");
|
|
Exit();
|
|
}
|
|
break;
|
|
case ':':
|
|
body = rbody(&in);
|
|
addrules(head, tail, body, attr, hline, prog);
|
|
break;
|
|
case '=':
|
|
if(head->next){
|
|
SYNERR(-1);
|
|
fprint(2, "multiple vars on left side of assignment\n");
|
|
Exit();
|
|
}
|
|
if(symlook(head->s, S_OVERRIDE, 0)){
|
|
set = varoverride;
|
|
} else {
|
|
set = 1;
|
|
if(varoverride)
|
|
symlook(head->s, S_OVERRIDE, (void *)"");
|
|
}
|
|
if(set){
|
|
/*
|
|
char *cp;
|
|
dumpw("tail", tail);
|
|
cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
|
|
*/
|
|
setvar(head->s, (void *) tail);
|
|
symlook(head->s, S_WESET, (void *)"");
|
|
}
|
|
if(attr)
|
|
symlook(head->s, S_NOEXPORT, (void *)"");
|
|
break;
|
|
default:
|
|
SYNERR(hline);
|
|
fprint(2, "expected one of :<=\n");
|
|
Exit();
|
|
break;
|
|
}
|
|
}
|
|
close(fd);
|
|
freebuf(buf);
|
|
ipop();
|
|
}
|
|
|
|
void
|
|
addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
|
|
{
|
|
Word *w;
|
|
|
|
assert(/*addrules args*/ head && body);
|
|
/* tuck away first non-meta rule as default target*/
|
|
if(target1 == 0 && !(attr®EXP)){
|
|
for(w = head; w; w = w->next)
|
|
if(charin(w->s, "%&"))
|
|
break;
|
|
if(w == 0)
|
|
target1 = wdup(head);
|
|
}
|
|
for(w = head; w; w = w->next)
|
|
addrule(w->s, tail, body, head, attr, hline, prog);
|
|
}
|
|
|
|
static int
|
|
rhead(char *line, Word **h, Word **t, int *attr, char **prog)
|
|
{
|
|
char *p;
|
|
char *pp;
|
|
int sep;
|
|
Rune r;
|
|
int n;
|
|
Word *w;
|
|
|
|
p = charin(line,":=<");
|
|
if(p == 0)
|
|
return('?');
|
|
sep = *p;
|
|
*p++ = 0;
|
|
if(sep == '<' && *p == '|'){
|
|
sep = '|';
|
|
p++;
|
|
}
|
|
*attr = 0;
|
|
*prog = 0;
|
|
if(sep == '='){
|
|
pp = charin(p, termchars); /* termchars is shell-dependent */
|
|
if (pp && *pp == '=') {
|
|
while (p != pp) {
|
|
n = chartorune(&r, p);
|
|
switch(r)
|
|
{
|
|
default:
|
|
SYNERR(-1);
|
|
fprint(2, "unknown attribute '%c'\n",*p);
|
|
Exit();
|
|
case 'U':
|
|
*attr = 1;
|
|
break;
|
|
}
|
|
p += n;
|
|
}
|
|
p++; /* skip trailing '=' */
|
|
}
|
|
}
|
|
if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
|
|
while (*p) {
|
|
n = chartorune(&r, p);
|
|
if (r == ':')
|
|
break;
|
|
p += n;
|
|
switch(r)
|
|
{
|
|
default:
|
|
SYNERR(-1);
|
|
fprint(2, "unknown attribute '%c'\n", p[-1]);
|
|
Exit();
|
|
case 'D':
|
|
*attr |= DEL;
|
|
break;
|
|
case 'E':
|
|
*attr |= NOMINUSE;
|
|
break;
|
|
case 'n':
|
|
*attr |= NOVIRT;
|
|
break;
|
|
case 'N':
|
|
*attr |= NOREC;
|
|
break;
|
|
case 'P':
|
|
pp = utfrune(p, ':');
|
|
if (pp == 0 || *pp == 0)
|
|
goto eos;
|
|
*pp = 0;
|
|
*prog = strdup(p);
|
|
*pp = ':';
|
|
p = pp;
|
|
break;
|
|
case 'Q':
|
|
*attr |= QUIET;
|
|
break;
|
|
case 'R':
|
|
*attr |= REGEXP;
|
|
break;
|
|
case 'U':
|
|
*attr |= UPD;
|
|
break;
|
|
case 'V':
|
|
*attr |= VIR;
|
|
break;
|
|
}
|
|
}
|
|
if (*p++ != ':') {
|
|
eos:
|
|
SYNERR(-1);
|
|
fprint(2, "missing trailing :\n");
|
|
Exit();
|
|
}
|
|
}
|
|
*h = w = stow(line);
|
|
if(*w->s == 0 && sep != '<' && sep != '|') {
|
|
SYNERR(mkinline-1);
|
|
fprint(2, "no var on left side of assignment/rule\n");
|
|
Exit();
|
|
}
|
|
*t = stow(p);
|
|
return(sep);
|
|
}
|
|
|
|
static char *
|
|
rbody(Biobuf *in)
|
|
{
|
|
Bufblock *buf;
|
|
int r, lastr;
|
|
char *p;
|
|
|
|
lastr = '\n';
|
|
buf = newbuf();
|
|
for(;;){
|
|
r = Bgetrune(in);
|
|
if (r < 0)
|
|
break;
|
|
if (lastr == '\n') {
|
|
if (r == '#')
|
|
rinsert(buf, r);
|
|
else if (r != ' ' && r != '\t') {
|
|
Bungetrune(in);
|
|
break;
|
|
}
|
|
} else
|
|
rinsert(buf, r);
|
|
lastr = r;
|
|
if (r == '\n')
|
|
mkinline++;
|
|
}
|
|
insert(buf, 0);
|
|
p = strdup(buf->start);
|
|
freebuf(buf);
|
|
return p;
|
|
}
|
|
|
|
struct input
|
|
{
|
|
char *file;
|
|
int line;
|
|
struct input *next;
|
|
};
|
|
static struct input *inputs = 0;
|
|
|
|
void
|
|
ipush(void)
|
|
{
|
|
struct input *in, *me;
|
|
|
|
me = (struct input *)Malloc(sizeof(*me));
|
|
me->file = infile;
|
|
me->line = mkinline;
|
|
me->next = 0;
|
|
if(inputs == 0)
|
|
inputs = me;
|
|
else {
|
|
for(in = inputs; in->next; )
|
|
in = in->next;
|
|
in->next = me;
|
|
}
|
|
}
|
|
|
|
void
|
|
ipop(void)
|
|
{
|
|
struct input *in, *me;
|
|
|
|
assert(/*pop input list*/ inputs != 0);
|
|
if(inputs->next == 0){
|
|
me = inputs;
|
|
inputs = 0;
|
|
} else {
|
|
for(in = inputs; in->next->next; )
|
|
in = in->next;
|
|
me = in->next;
|
|
in->next = 0;
|
|
}
|
|
infile = me->file;
|
|
mkinline = me->line;
|
|
free((char *)me);
|
|
}
|