ref: 94b1d3f0ad587b6e507ff872eb8562466e3af21a
parent: 6b0150764cc579c3764e6ed2a6db1237f11577de
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Dec 28 13:10:41 EST 2023
mk: Various improvements Variables are lists, just as in rc, so preserve emptry strings ('') in variables properly: FOO='' bar baz should result in FOO=('' bar baz) in the environment, while FOO= becomes a emptry list FOO=(). Get rid of the Evy struct, the environment can be represented as just an array of Symtab pointers, also meaning the value can never be out of sync. Embedd the name string in Symtab struct. It is immutable and dont require the caller to strdup() the name. Make Word's immutable, embedding the string value in the Word struct. This avoids alot of extra allocations. Provide a Strdup() function that handles allocation error. Handle variable overrides from the command line internally, avoiding the maketmp() file. When executing a recipe, pass the body using the -c flag to rc, avoiding a pipe() and fork(). This also has the advntage that rc can optimize the script as it sees it in its entirety and avoid fork() down the line. Make sure not to leak file-descriptors into sub-processes. Do an attempt at freeing memory (mostly for Arc's and environment values).
--- a/sys/src/cmd/mk/arc.c
+++ b/sys/src/cmd/mk/arc.c
@@ -8,7 +8,7 @@
a = (Arc *)Malloc(sizeof(Arc));
a->n = n;
a->r = r;
- a->stem = strdup(stem);
+ a->stem = Strdup(stem);
rcopy(a->match, match, NREGEXP);
a->next = 0;
a->flag = 0;
@@ -17,6 +17,13 @@
}
void
+freearc(Arc *a)
+{
+ free(a->stem);
+ free(a);
+}
+
+void
dumpa(char *s, Arc *a)
{
char buf[1024];
@@ -36,15 +43,10 @@
void
nrep(void)
{
- Symtab *sym;
Word *w;
- sym = symlook("NREP", S_VAR, 0);
- if(sym){
- w = sym->u.ptr;
- if (w && w->s && *w->s)
- nreps = atoi(w->s);
- }
+ if(!empty(w = getvar("NREP")))
+ nreps = atoi(w->s);
if(nreps < 1)
nreps = 1;
if(DEBUG(D_GRAPH))
--- a/sys/src/cmd/mk/archive.c
+++ b/sys/src/cmd/mk/archive.c
@@ -7,9 +7,9 @@
long
atimeof(int force, char *name)
{
+ char buf[512], *archive, *member;
Symtab *sym;
long t;
- char *archive, *member, buf[512];
archive = split(name, &member);
if(archive == 0)
@@ -26,7 +26,7 @@
else{
atimes(archive);
/* mark the aggegate as having been done */
- symlook(strdup(archive), S_AGG, "")->u.value = t;
+ symlook(archive, S_AGG, 1)->u.value = t;
}
/* truncate long member name to sizeof of name field in archive header */
snprint(buf, sizeof(buf), "%s(%.*s)", archive, utfnlen(member, SARNAME), member);
@@ -113,7 +113,7 @@
i--;
h.name[i+1]=0; /* can stomp on date field */
snprint(buf, sizeof buf, "%s(%s)", ar, h.name);
- symlook(strdup(buf), S_TIME, (void*)t)->u.value = t;
+ symlook(buf, S_TIME, 1)->u.value = t;
t = atol(h.size);
if(t&01) t++;
LSEEK(fd, t, 1);
@@ -131,7 +131,7 @@
if(fd < 0){
if(symlook(file, S_BITCH, 0) == 0){
Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file);
- symlook(file, S_BITCH, (void *)file);
+ symlook(file, S_BITCH, 1);
}
return 1;
}
@@ -148,7 +148,7 @@
{
char *p, *q;
- p = strdup(name);
+ p = Strdup(name);
q = utfrune(p, '(');
if(q){
*q++ = 0;
@@ -159,8 +159,8 @@
*q = 0;
if(type(p))
return p;
- free(p);
fprint(2, "mk: '%s' is not an archive\n", name);
}
+ free(p);
return 0;
}
--- a/sys/src/cmd/mk/bufblock.c
+++ b/sys/src/cmd/mk/bufblock.c
@@ -25,6 +25,8 @@
void
freebuf(Bufblock *p)
{
+ assert(p->current >= p->start);
+ p->current = 0;
p->next = freelist;
freelist = p;
}
@@ -39,6 +41,7 @@
n = p->end-p->start+QUANTA;
/* search the free list for a big buffer */
for (f = freelist; f; f = f->next) {
+ assert(f->current == 0);
if (f->end-f->start >= n) {
memcpy(f->start, p->start, p->end-p->start);
cp = f->start;
@@ -47,7 +50,6 @@
cp = f->end;
f->end = p->end;
p->end = cp;
- f->current = f->start;
break;
}
}
@@ -59,9 +61,17 @@
}
void
-bufcpy(Bufblock *buf, char *cp, int n)
+bufcpy(Bufblock *buf, char *cp)
{
+ int c;
+ while (c = *cp++)
+ insert(buf, c);
+}
+
+void
+bufncpy(Bufblock *buf, char *cp, int n)
+{
while (n--)
insert(buf, *cp++);
}
@@ -69,7 +79,6 @@
void
insert(Bufblock *buf, int c)
{
-
if (buf->current >= buf->end)
growbuf(buf);
*buf->current++ = c;
--- a/sys/src/cmd/mk/env.c
+++ b/sys/src/cmd/mk/env.c
@@ -1,10 +1,10 @@
#include "mk.h"
enum {
- ENVQUANTA=10
+ ENVQUANTA=64
};
-Envy *envy;
+static Symtab **envy;
static int nextv;
static char *myenv[] =
@@ -36,72 +36,66 @@
char **p;
for(p = myenv; *p; p++)
- symlook(*p, S_INTERNAL, (void *)"");
+ symlook(*p, S_INTERNAL, 1)->u.ptr = 0;
readenv(); /* o.s. dependent */
}
static void
-envinsert(char *name, Word *value)
+envupd(char *name, Word *value)
{
+ Symtab *sym = symlook(name, S_INTERNAL, 0);
+ assert(sym != 0);
+ delword(sym->u.ptr);
+ sym->u.ptr = value;
+}
+
+static void
+envinsert(Symtab *sym)
+{
static int envsize;
if (nextv >= envsize) {
envsize += ENVQUANTA;
- envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy));
+ envy = (Symtab **) Realloc(envy, envsize*sizeof(Symtab*));
}
- envy[nextv].name = name;
- envy[nextv++].values = value;
+ envy[nextv++] = sym;
}
static void
-envupd(char *name, Word *value)
+ereset(Symtab *s)
{
- Envy *e;
-
- for(e = envy; e->name; e++)
- if(strcmp(name, e->name) == 0){
- delword(e->values);
- e->values = value;
- return;
- }
- e->name = name;
- e->values = value;
- envinsert(0,0);
+ delword(s->u.ptr);
+ s->u.ptr = 0;
+ envinsert(s);
}
static void
ecopy(Symtab *s)
{
- char **p;
-
if(symlook(s->name, S_NOEXPORT, 0))
return;
- for(p = myenv; *p; p++)
- if(strcmp(*p, s->name) == 0)
- return;
- envinsert(s->name, s->u.ptr);
+ if(symlook(s->name, S_INTERNAL, 0))
+ return;
+ envinsert(s);
}
-void
+Symtab**
execinit(void)
{
- char **p;
-
nextv = 0;
- for(p = myenv; *p; p++)
- envinsert(*p, stow(""));
-
+ symtraverse(S_INTERNAL, ereset);
symtraverse(S_VAR, ecopy);
- envinsert(0, 0);
+ envinsert(0);
+ return envy;
}
-Envy*
+Symtab**
buildenv(Job *j, int slot)
{
char **p, *cp, *qp;
Word *w, *v, **l;
+ char num[16];
int i;
- char buf[256];
envupd("target", wdup(j->t));
if(j->r->attr®EXP)
@@ -109,10 +103,10 @@
else
envupd("stem", newword(j->stem));
envupd("prereq", wdup(j->p));
- snprint(buf, sizeof buf, "%d", getpid());
- envupd("pid", newword(buf));
- snprint(buf, sizeof buf, "%d", slot);
- envupd("nproc", newword(buf));
+ snprint(num, sizeof num, "%d", getpid());
+ envupd("pid", newword(num));
+ snprint(num, sizeof num, "%d", slot);
+ envupd("nproc", newword(num));
envupd("newprereq", wdup(j->np));
envupd("alltarget", wdup(j->at));
l = &v;
@@ -129,10 +123,7 @@
continue;
}
}
- *l = w->next;
- free(w->s);
- free(w);
- w = *l;
+ *l = w = popword(w);
}
envupd("newmember", v);
/* update stem0 -> stem9 */
--- a/sys/src/cmd/mk/file.c
+++ b/sys/src/cmd/mk/file.c
@@ -21,7 +21,7 @@
return mtime(name);
sym = symlook(name, S_TIME, 0);
- if (sym)
+ if(sym)
return sym->u.value; /* uggh */
t = mkmtime(name, 0);
@@ -28,7 +28,7 @@
if(t == 0)
return 0;
- symlook(name, S_TIME, (void*)t); /* install time in cache */
+ symlook(name, S_TIME, 1)->u.value = t; /* install time in cache */
return t;
}
@@ -76,7 +76,7 @@
} while(*s);
c = *s;
*s = 0;
- symlook(strdup(cp), S_TIME, (void *)t)->u.value = t;
+ symlook(cp, S_TIME, 1)->u.value = t;
if (c)
*s++ = c;
while(*s){
--- a/sys/src/cmd/mk/fns.h
+++ b/sys/src/cmd/mk/fns.h
@@ -1,11 +1,13 @@
void addrule(char*, Word*, char*, Word*, int, int, char*);
void addrules(Word*, Word*, char*, int, int, char*);
-void addw(Word*, char*);
int assline(Biobuf *, Bufblock *);
long atimeof(int,char*);
void atouch(char*);
-void bufcpy(Bufblock *, char *, int);
-Envy *buildenv(Job*, int);
+void bufcpy(Bufblock *, char *);
+void bufcpyq(Bufblock *, char *);
+void bufcpyw(Bufblock *, Word *);
+void bufncpy(Bufblock *, char *, int);
+Symtab **buildenv(Job*, int);
void catchnotes(void);
char *charin(char *, char *);
int chgtime(char*);
@@ -20,23 +22,24 @@
void dumpr(char*, Rule*);
void dumpv(char*);
void dumpw(char*, Word*);
+int empty(Word*);
int escapetoken(Biobuf*, Bufblock*, int, int);
-void execinit(void);
-int execsh(char*, char*, Bufblock*, Envy*);
+Symtab **execinit(void);
+int execsh(char*, char*, Symtab**, Bufblock*);
void Exit(void);
char *expandquote(char*, Rune, Bufblock*);
void expunge(int, char*);
+void freearc(Arc*);
void freebuf(Bufblock*);
+void freejob(Job*);
void front(char*);
+Word *getvar(char*);
Node *graph(char*);
void growbuf(Bufblock *);
void initenv(void);
void insert(Bufblock *, int);
-void ipop(void);
-void ipush(void);
void killchildren(char*);
void *Malloc(int);
-char *maketmp(void);
int match(char*, char*, char*);
void mk(char*);
ulong mkmtime(char*, int);
@@ -50,8 +53,9 @@
void nproc(void);
void nrep(void);
int outofdate(Node*, Arc*, int);
-void parse(char*, int, int);
-int pipecmd(char*, Envy*, int*);
+void parse(char*, int);
+int pipecmd(char*, char*, Symtab**, int*);
+Word *popword(Word*);
void prusage(void);
void rcopy(char**, Resub*, int);
void readenv(void);
@@ -59,12 +63,13 @@
void rinsert(Bufblock *, Rune);
char *rulecnt(void);
void run(Job*);
-void setvar(char*, void*);
+void setvar(char*, Word*);
char *shname(char*);
-void shprint(char*, Envy*, Bufblock*);
+void shprint(char*, Bufblock*);
Word *stow(char*);
+char *Strdup(char*);
void subst(char*, char*, char*, int);
-Symtab *symlook(char*, int, void*);
+Symtab *symlook(char*, int, int);
void symtraverse(int, void(*)(Symtab*));
void timeinit(char*);
long timeof(char*, int);
@@ -71,9 +76,12 @@
void touch(char*);
void update(int, Node*);
void usage(void);
+void varoverride(char*);
Word *varsub(char**);
+int wadd(Word**, char*);
int waitfor(char*);
int waitup(int, int*);
+int wcmp(Word*, Word*);
Word *wdup(Word*);
int work(Node*, Node*, Arc*);
-char *wtos(Word*, int);
+char *wtos(Word*);
--- a/sys/src/cmd/mk/graph.c
+++ b/sys/src/cmd/mk/graph.c
@@ -41,7 +41,6 @@
sym = symlook(target, S_NODE, 0);
if(sym)
return sym->u.ptr;
- target = strdup(target);
node = newnode(target);
head.n = 0;
head.next = 0;
@@ -49,8 +48,7 @@
memset((char*)rmatch, 0, sizeof(rmatch));
for(r = sym? sym->u.ptr:0; r; r = r->chain){
if(r->attr&META) continue;
- if(strcmp(target, r->target)) continue;
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
+ if((!r->recipe || !*r->recipe) && empty(r->tail)) continue; /* no effect; ignore */
if(cnt[r->rule] >= nreps) continue;
cnt[r->rule]++;
node->flags |= PROBABLE;
@@ -62,19 +60,20 @@
* if(r->attr&DEL)
* node->flags |= DELETE;
*/
- if(!r->tail || !r->tail->s || !*r->tail->s) {
+ if(empty(r->tail)) {
a->next = newarc((Node *)0, r, "", rmatch);
a = a->next;
- } else
+ } else {
for(w = r->tail; w; w = w->next){
a->next = newarc(applyrules(w->s, cnt), r, "", rmatch);
a = a->next;
+ }
}
cnt[r->rule]--;
head.n = node;
}
for(r = metarules; r; r = r->next){
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
+ if((!r->recipe || !*r->recipe) && empty(r->tail)) continue; /* no effect; ignore */
if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR))
continue;
if(r->attr®EXP){
@@ -84,7 +83,7 @@
if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0)
continue;
} else {
- if(!match(node->name, r->target, stem)) continue;
+ if(!match(node->name, r->target->name, stem)) continue;
}
if(cnt[r->rule] >= nreps) continue;
cnt[r->rule]++;
@@ -96,7 +95,7 @@
* if(r->attr&DEL)
* node->flags |= DELETE;
*/
- if(!r->tail || !r->tail->s || !*r->tail->s) {
+ if(empty(r->tail)){
a->next = newarc((Node *)0, r, stem, rmatch);
a = a->next;
} else
@@ -118,20 +117,20 @@
static void
togo(Node *node)
{
- Arc *la, *a;
+ Arc **l, *a;
/* delete them now */
- la = 0;
- for(a = node->prereqs; a; la = a, a = a->next)
+ l = &node->prereqs;
+ while(a = *l){
if(a->flag&TOGO){
- if(a == node->prereqs)
- node->prereqs = a->next;
- else
- la->next = a->next, a = la;
- }
+ *l = a->next;
+ freearc(a);
+ } else
+ l = &a->next;
+ }
}
-static
+static int
vacuous(Node *node)
{
Arc *la, *a;
@@ -149,9 +148,8 @@
for(a = node->prereqs; a; a = a->next)
if((a->flag&TOGO) == 0)
for(la = node->prereqs; la; la = la->next)
- if((la->flag&TOGO) && (la->r == a->r)){
+ if((la->flag&TOGO) && (la->r == a->r))
la->flag &= ~TOGO;
- }
togo(node);
if(vac)
node->flags |= VACUOUS;
@@ -161,15 +159,17 @@
static Node *
newnode(char *name)
{
- register Node *node;
+ Symtab *sym;
+ Node *node;
+ sym = symlook(name, S_NODE, 1);
node = (Node *)Malloc(sizeof(Node));
- symlook(name, S_NODE, (void *)node);
- node->name = name;
+ node->name = sym->name;
node->time = timeof(name, 0);
node->prereqs = 0;
node->flags = node->time? PROBABLE : 0;
node->next = 0;
+ sym->u.ptr = node;
return(node);
}
--- a/sys/src/cmd/mk/job.c
+++ b/sys/src/cmd/mk/job.c
@@ -3,7 +3,7 @@
Job *
newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, Word *tar, Word *atar)
{
- register Job *j;
+ Job *j;
j = (Job *)Malloc(sizeof(Job));
j->r = r;
@@ -20,14 +20,28 @@
}
void
+freejob(Job *j)
+{
+ delword(j->p);
+ delword(j->np);
+ delword(j->t);
+ delword(j->at);
+ free(j);
+}
+
+void
dumpj(char *s, Job *j, int all)
{
+ char *t;
+
Bprint(&bout, "%s\n", s);
while(j){
Bprint(&bout, "job@%p: r=%p n=%p stem='%s' nproc=%d\n",
j, j->r, j->n, j->stem, j->nproc);
- Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprereq='%s'\n",
- wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wtos(j->np, ' '));
+ Bprint(&bout, "\ttarget=%s", t = wtos(j->t)), free(t);
+ Bprint(&bout, " alltarget=%s", t = wtos(j->at)), free(t);
+ Bprint(&bout, " prereq=%s", t = wtos(j->p)), free(t);
+ Bprint(&bout, " nprereq=%s\n", t = wtos(j->np)), free(t);
j = all? j->next : 0;
}
}
--- a/sys/src/cmd/mk/lex.c
+++ b/sys/src/cmd/mk/lex.c
@@ -89,8 +89,7 @@
insert(buf, '\n');
insert(buf,0);
buf->current = buf->start+start;
- execinit();
- execsh(0, buf->current, buf, envy);
+ execsh(buf->current, 0, execinit(), buf);
return 1;
}
if(c == '\n')
--- a/sys/src/cmd/mk/main.c
+++ b/sys/src/cmd/mk/main.c
@@ -3,36 +3,29 @@
#define MKFILE "mkfile"
int debug;
-Rule *rules, *metarules;
int nflag = 0;
+int sflag = 0;
int tflag = 0;
int iflag = 0;
int kflag = 0;
int aflag = 0;
int uflag = 0;
+int nreps = 1;
char *explain = 0;
Word *target1;
-int nreps = 1;
Job *jobs;
+Rule *rules, *patrule, *metarules;
Biobuf bout;
-Rule *patrule;
+
void badusage(void);
-#ifdef PROF
-short buf[10000];
-#endif
void
main(int argc, char **argv)
{
- Word *w;
- char *s, *temp;
- char *files[256], **f = files, **ff;
- int sflag = 0;
- int i;
- int tfd = -1;
- Biobuf tb;
- Bufblock *buf;
+ Word **link, *flags, *files, *args;
Bufblock *whatif;
+ char *s;
+ int i;
/*
* start with a copy of the current environment variables
@@ -40,13 +33,14 @@
*/
Binit(&bout, 1, OWRITE);
- buf = newbuf();
whatif = 0;
USED(argc);
- for(argv++; *argv && (**argv == '-'); argv++)
+
+ flags = 0;
+ link = &flags;
+ for(argv++; *argv && (**argv == '-'); argv++, link = &(*link)->next)
{
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
+ *link = newword(*argv);
switch(argv[0][1])
{
case 'a':
@@ -67,11 +61,12 @@
explain = &argv[0][2];
break;
case 'f':
- if(*++argv == 0)
+ argv++;
+ if(*argv == 0 || **argv == 0)
badusage();
- *f++ = *argv;
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
+ link = &(*link)->next;
+ *link = newword(*argv);
+ wadd(&files, *argv);
break;
case 'i':
iflag = 1;
@@ -97,11 +92,13 @@
else
insert(whatif, ' ');
if(argv[0][2])
- bufcpy(whatif, &argv[0][2], strlen(&argv[0][2]));
+ bufcpy(whatif, &argv[0][2]);
else {
if(*++argv == 0)
badusage();
- bufcpy(whatif, &argv[0][0], strlen(&argv[0][0]));
+ bufcpy(whatif, &argv[0][0]);
+ link = &(*link)->next;
+ *link = newword(*argv);
}
break;
default:
@@ -108,12 +105,6 @@
badusage();
}
}
-#ifdef PROF
- {
- extern etext();
- monitor(main, etext, buf, sizeof buf, 300);
- }
-#endif
if(aflag)
iflag = 1;
@@ -124,54 +115,30 @@
/*
assignment args become null strings
*/
- temp = 0;
+ mkinfile = "command line args";
for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){
- bufcpy(buf, argv[i], strlen(argv[i]));
- insert(buf, ' ');
- if(tfd < 0){
- temp = maketmp();
- if(temp == 0) {
- perror("temp file");
- Exit();
- }
- if((tfd = create(temp, ORDWR, 0600)) < 0){
- perror(temp);
- Exit();
- }
- Binit(&tb, tfd, OWRITE);
- }
- Bprint(&tb, "%s\n", argv[i]);
+ if(!wadd(&flags, argv[i]))
+ varoverride(argv[i]);
*argv[i] = 0;
}
- if(tfd >= 0){
- Bflush(&tb);
- LSEEK(tfd, 0L, 0);
- parse("command line args", tfd, 1);
- remove(temp);
- }
+ setvar("MKFLAGS", flags);
- if (buf->current != buf->start) {
- buf->current--;
- insert(buf, 0);
- }
- symlook("MKFLAGS", S_VAR, (void *) stow(buf->start));
- buf->current = buf->start;
+ args = 0;
+ link = &args;
for(i = 0; argv[i]; i++){
if(*argv[i] == 0) continue;
- if(i)
- insert(buf, ' ');
- bufcpy(buf, argv[i], strlen(argv[i]));
+ *link = newword(argv[i]);
+ link = &(*link)->next;
}
- insert(buf, 0);
- symlook("MKARGS", S_VAR, (void *) stow(buf->start));
- freebuf(buf);
+ setvar("MKARGS", args);
- if(f == files){
- if(access(MKFILE, 4) == 0)
- parse(MKFILE, open(MKFILE, 0), 0);
- } else
- for(ff = files; ff < f; ff++)
- parse(*ff, open(*ff, 0), 0);
+ if(files == 0){
+ if(access(MKFILE, AEXIST) == 0)
+ parse(MKFILE, open(MKFILE, OREAD|OCEXEC));
+ } else {
+ for(; files; files = popword(files))
+ parse(files->s, open(files->s, OREAD|OCEXEC));
+ }
if(DEBUG(D_PARSE)){
dumpw("default targets", target1);
dumpr("rules", rules);
@@ -184,44 +151,26 @@
freebuf(whatif);
}
execinit();
- /* skip assignment args */
- while(*argv && (**argv == 0))
- argv++;
catchnotes();
- if(*argv == 0){
- if(target1)
- for(w = target1; w; w = w->next)
- mk(w->s);
- else {
+ if(args == 0){
+ if(target1 == 0){
fprint(2, "mk: nothing to mk\n");
Exit();
}
+ for(; target1; target1 = popword(target1))
+ mk(target1->s);
} else {
+ args = wdup(args);
if(sflag){
- for(; *argv; argv++)
- if(**argv)
- mk(*argv);
+ for(; args; args = popword(args))
+ mk(args->s);
} else {
- Word *head, *tail, *t;
-
- /* fake a new rule with all the args as prereqs */
- tail = 0;
- t = 0;
- for(; *argv; argv++)
- if(**argv){
- if(tail == 0)
- tail = t = newword(*argv);
- else {
- t->next = newword(*argv);
- t = t->next;
- }
- }
- if(tail->next == 0)
- mk(tail->s);
+ if(args->next == 0)
+ mk(args->s);
else {
- head = newword("command line arguments");
- addrules(head, tail, strdup(""), VIR, mkinline, 0);
+ Word *head = newword(mkinfile);
+ addrules(head, args, Strdup(""), VIR, 0, 0);
mk(head->s);
}
}
@@ -234,7 +183,6 @@
void
badusage(void)
{
-
fprint(2, "usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]] [targets ...]\n");
Exit();
}
@@ -242,7 +190,7 @@
void *
Malloc(int n)
{
- register void *s;
+ void *s;
s = malloc(n);
if(!s) {
@@ -249,6 +197,7 @@
fprint(2, "mk: cannot alloc %d bytes\n", n);
Exit();
}
+ setmalloctag(s, getcallerpc(&n));
return(s);
}
@@ -263,9 +212,20 @@
fprint(2, "mk: cannot alloc %d bytes\n", n);
Exit();
}
+ setrealloctag(s, getcallerpc(&s));
return(s);
}
+char *
+Strdup(char *s)
+{
+ int n = strlen(s)+1;
+ char *d = Malloc(n);
+ memcpy(d, s, n);
+ setmalloctag(d, getcallerpc(&s));
+ return d;
+}
+
void
regerror(char *s)
{
@@ -274,6 +234,6 @@
patrule->file, patrule->line, s);
else
fprint(2, "mk: %s:%d: regular expression error; %s\n",
- infile, mkinline, s);
+ mkinfile, mkinline, s);
Exit();
}
--- a/sys/src/cmd/mk/mk.c
+++ b/sys/src/cmd/mk/mk.c
@@ -172,7 +172,7 @@
Arc *a;
MADESET(node, fake? BEINGMADE : MADE);
- if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){
+ if(((node->flags&VIRTUAL) == 0) && (access(node->name, AEXIST) == 0)){
node->time = timeof(node->name, 1);
node->flags &= ~(CANPRETEND|PRETENDING);
for(a = node->prereqs; a; a = a->next)
@@ -188,14 +188,12 @@
}
static
-pcmp(char *prog, char *p, char *q)
+pcmp(char *cmd)
{
- char buf[3*NAMEBLOCK];
int pid;
Bflush(&bout);
- snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q);
- pid = pipecmd(buf, 0, 0);
+ pid = pipecmd(cmd, 0, 0, 0);
while(waitup(-3, &pid) >= 0)
;
return(pid? 2:1);
@@ -204,25 +202,28 @@
int
outofdate(Node *node, Arc *arc, int eval)
{
- char buf[3*NAMEBLOCK], *str;
- Symtab *sym;
- int ret;
-
- str = 0;
if(arc->prog){
- snprint(buf, sizeof buf, "%s%c%s", node->name, 0377,
- arc->n->name);
- sym = symlook(buf, S_OUTOFDATE, 0);
+ Bufblock *cmd;
+ Symtab *sym;
+ int ret;
+
+ cmd = newbuf();
+ bufcpy(cmd, arc->prog);
+ insert(cmd, ' ');
+ bufcpyq(cmd, node->name);
+ insert(cmd, ' ');
+ bufcpyq(cmd, arc->n->name);
+ insert(cmd, '\n');
+ insert(cmd, 0);
+ sym = symlook(cmd->start, S_OUTOFDATE, 0);
if(sym == 0 || eval){
+ ret = pcmp(cmd->start);
if(sym == 0)
- str = strdup(buf);
- ret = pcmp(arc->prog, node->name, arc->n->name);
- if(sym)
- sym->u.value = ret;
- else
- symlook(str, S_OUTOFDATE, (void *)ret);
+ sym = symlook(cmd->start, S_OUTOFDATE, 1);
+ sym->u.value = ret;
} else
ret = sym->u.value;
+ freebuf(cmd);
return(ret-1);
} else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing archive member */
return 1;
--- a/sys/src/cmd/mk/mk.h
+++ b/sys/src/cmd/mk/mk.h
@@ -15,21 +15,39 @@
typedef struct Word
{
- char *s;
struct Word *next;
+ char s[1];
} Word;
-typedef struct Envy
+typedef struct Symtab
{
- char *name;
- Word *values;
-} Envy;
+ union{
+ void *ptr;
+ uintptr value;
+ } u;
+ struct Symtab *next;
+ unsigned char space;
+ char name[1];
+} Symtab;
-extern Envy *envy;
+enum {
+ S_VAR, /* variable -> value */
+ S_TARGET, /* target -> rule */
+ S_TIME, /* file -> time */
+ S_NODE, /* target name -> node */
+ S_AGG, /* aggregate -> time */
+ S_BITCH, /* bitched about aggregate not there */
+ S_NOEXPORT, /* var -> noexport */
+ S_OVERRIDE, /* can't override */
+ S_OUTOFDATE, /* "cmp 'file1' 'file2'\n" -> 2(outofdate) or 1(not outofdate) */
+ S_BULKED, /* directory; we have bulked */
+ S_WESET, /* variable; we set in the mkfile */
+ S_INTERNAL, /* variable -> value; an internal mk variable (e.g., stem, target) */
+};
typedef struct Rule
{
- char *target; /* one target */
+ Symtab *target; /* one target */
Word *tail; /* constituents of targets */
char *recipe; /* do it ! */
short attr; /* attributes */
@@ -112,50 +130,17 @@
} Job;
extern Job *jobs;
-typedef struct Symtab
-{
- short space;
- char *name;
- union{
- void *ptr;
- uintptr value;
- } u;
- struct Symtab *next;
-} Symtab;
-
-enum {
- S_VAR, /* variable -> value */
- S_TARGET, /* target -> rule */
- S_TIME, /* file -> time */
- S_PID, /* pid -> products */
- S_NODE, /* target name -> node */
- S_AGG, /* aggregate -> time */
- S_BITCH, /* bitched about aggregate not there */
- S_NOEXPORT, /* var -> noexport */
- S_OVERRIDE, /* can't override */
- S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */
- S_MAKEFILE, /* target -> node */
- S_MAKEVAR, /* dumpable mk variable */
- S_EXPORTED, /* var -> current exported value */
- S_BULKED, /* we have bulked this dir */
- S_WESET, /* variable; we set in the mkfile */
- S_INTERNAL, /* an internal mk variable (e.g., stem, target) */
-};
-
extern int debug;
extern int nflag, tflag, iflag, kflag, aflag, mflag;
extern int mkinline;
-extern char *infile;
+extern char *mkinfile;
extern int nreps;
extern char *explain;
-extern char *termchars;
-extern char *shell;
-extern char *shellname;
-extern char *shflags;
-extern int IWS;
+extern char termchars[];
+extern char shell[];
+extern char shellname[];
-#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile, ((l)>=0)?(l):mkinline))
-#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r)->file, (r)->line))
+#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", mkinfile, ((l)>=0)?(l):mkinline))
#define NAMEBLOCK 1000
#define BIGBLOCK 20000
--- a/sys/src/cmd/mk/parse.c
+++ b/sys/src/cmd/mk/parse.c
@@ -1,31 +1,30 @@
#include "mk.h"
-char *infile;
+char *mkinfile;
int mkinline;
+
+static void ipush(char *file);
+static void ipop(void);
+static void doassign(Word *, Word *, int, int);
static int rhead(char *, Word **, Word **, int *, char **);
static char *rbody(Biobuf*);
extern Word *target1;
void
-parse(char *f, int fd, int varoverride)
+parse(char *f, int fd)
{
- int hline;
- char *body;
+ int hline, attr, pid, newfd;
Word *head, *tail;
- int attr, set, pid;
char *prog, *p;
- int newfd;
- Biobuf in;
Bufblock *buf;
+ Biobuf in;
if(fd < 0){
perror(f);
Exit();
}
- ipush();
- infile = strdup(f);
- mkinline = 1;
Binit(&in, fd, OREAD);
+ ipush(f);
buf = newbuf();
while(assline(&in, buf)){
hline = mkinline;
@@ -32,33 +31,33 @@
switch(rhead(buf->start, &head, &tail, &attr, &prog))
{
case '<':
- p = wtos(tail, ' ');
+ p = wtos(tail);
if(*p == 0){
SYNERR(-1);
fprint(2, "missing include file name\n");
Exit();
}
- newfd = open(p, OREAD);
+ newfd = open(p, OREAD|OCEXEC);
if(newfd < 0){
fprint(2, "warning: skipping missing include file: ");
perror(p);
} else
- parse(p, newfd, 0);
+ parse(p, newfd);
+ free(p);
break;
case '|':
- p = wtos(tail, ' ');
+ p = wtos(tail);
if(*p == 0){
SYNERR(-1);
fprint(2, "missing include program name\n");
Exit();
}
- execinit();
- pid=pipecmd(p, envy, &newfd);
+ pid=pipecmd(p, 0, execinit(), &newfd);
if(newfd < 0){
fprint(2, "warning: skipping missing program file: ");
perror(p);
} else
- parse(p, newfd, 0);
+ parse(p, newfd);
while(waitup(-3, &pid) >= 0)
;
if(pid != 0){
@@ -65,36 +64,14 @@
fprint(2, "bad include program status\n");
Exit();
}
+ free(p);
break;
case ':':
- body = rbody(&in);
- addrules(head, tail, body, attr, hline, prog);
- break;
+ addrules(head, tail, rbody(&in), attr, hline, prog);
+ continue; /* don't free head and tail */
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;
+ doassign(head, tail, attr, 0);
+ continue;
default:
SYNERR(hline);
fprint(2, "expected one of :<=\n");
@@ -101,13 +78,59 @@
Exit();
break;
}
+ delword(head);
+ delword(tail);
}
- close(fd);
freebuf(buf);
ipop();
+ close(fd);
}
+static void
+doassign(Word *head, Word *tail, int attr, int override)
+{
+ int set;
+
+ if(head->next){
+ SYNERR(-1);
+ fprint(2, "multiple vars on left side of assignment\n");
+ Exit();
+ }
+ if(symlook(head->s, S_OVERRIDE, 0)){
+ set = override;
+ } else {
+ set = 1;
+ if(override)
+ symlook(head->s, S_OVERRIDE, 1);
+ }
+ if(set){
+ setvar(head->s, tail);
+ symlook(head->s, S_WESET, 1);
+ tail = 0; /* don't free */
+ }
+ if(attr)
+ symlook(head->s, S_NOEXPORT, 1);
+ delword(head);
+ delword(tail);
+}
+
void
+varoverride(char *line)
+{
+ Word *head, *tail;
+ char *dummy;
+ int attr;
+
+ head = tail = 0;
+ if(rhead(line, &head, &tail, &attr, &dummy) == '='){
+ doassign(head, tail, attr, 1);
+ return;
+ }
+ delword(head);
+ delword(tail);
+}
+
+void
addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
{
Word *w;
@@ -135,6 +158,10 @@
int n;
Word *w;
+ *h = *t = 0;
+ *attr = 0;
+ *prog = 0;
+
p = charin(line,":=<");
if(p == 0)
return('?');
@@ -144,8 +171,6 @@
sep = '|';
p++;
}
- *attr = 0;
- *prog = 0;
if(sep == '='){
pp = charin(p, termchars); /* termchars is shell-dependent */
if (pp && *pp == '=') {
@@ -195,7 +220,7 @@
if (pp == 0 || *pp == 0)
goto eos;
*pp = 0;
- *prog = strdup(p);
+ *prog = Strdup(p);
*pp = ':';
p = pp;
break;
@@ -221,7 +246,7 @@
}
}
*h = w = stow(line);
- if(*w->s == 0 && sep != '<' && sep != '|') {
+ if(empty(w) && sep != '<' && sep != '|') {
SYNERR(mkinline-1);
fprint(2, "no var on left side of assignment/rule\n");
Exit();
@@ -257,7 +282,7 @@
mkinline++;
}
insert(buf, 0);
- p = strdup(buf->start);
+ p = Strdup(buf->start);
freebuf(buf);
return p;
}
@@ -270,40 +295,29 @@
};
static struct input *inputs = 0;
-void
-ipush(void)
+static void
+ipush(char *file)
{
- struct input *in, *me;
+ struct input *i;
- 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;
- }
+ i = (struct input *)Malloc(sizeof(*i));
+ i->file = mkinfile;
+ i->line = mkinline;
+ i->next = inputs;
+ inputs = i;
+
+ mkinfile = Strdup(file);
+ mkinline = 1;
}
-void
+static void
ipop(void)
{
- struct input *in, *me;
+ struct input *i;
- 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);
+ i = inputs;
+ inputs = i->next;
+ mkinfile = i->file;
+ mkinline = i->line;
+ free(i);
}
--- a/sys/src/cmd/mk/plan9.c
+++ b/sys/src/cmd/mk/plan9.c
@@ -1,7 +1,8 @@
#include "mk.h"
-char *shell = "/bin/rc";
-char *shellname = "rc";
+char shell[] = "/bin/rc";
+char shellname[] = "rc";
+char envdir[] = "/env/";
static Word *encodenulls(char*, int);
@@ -11,128 +12,119 @@
char *p;
int envf, f;
Dir *e;
- char nam[1024];
- int i, n, len;
+ Bufblock *path;
+ int i, n, len, npath;
Word *w;
rfork(RFENVG); /* use copy of the current environment variables */
- envf = open("/env", OREAD);
+ envf = open(envdir, OREAD);
if(envf < 0)
return;
+
+ path = newbuf();
+ bufcpy(path, envdir);
+ npath = path->current - path->start;
+
while((n = dirread(envf, &e)) > 0){
for(i = 0; i < n; i++){
- len = e[i].length;
/* don't import funny names, NULL values,
* or internal mk variables
*/
+ len = e[i].length;
if(len <= 0 || *shname(e[i].name) != '\0')
continue;
if (symlook(e[i].name, S_INTERNAL, 0))
continue;
- snprint(nam, sizeof nam, "/env/%s", e[i].name);
- f = open(nam, OREAD);
+
+ path->current = path->start + npath;
+ bufcpy(path, e[i].name);
+ insert(path, 0);
+ f = open(path->start, OREAD);
if(f < 0)
continue;
p = Malloc(len+1);
if(read(f, p, len) != len){
- perror(nam);
+ perror(path->start);
close(f);
continue;
}
+ p[len] = '\0';
close(f);
- if (p[len-1] == 0)
- len--;
- else
- p[len] = 0;
w = encodenulls(p, len);
free(p);
- p = strdup(e[i].name);
- setvar(p, (void *) w);
- symlook(p, S_EXPORTED, (void*)"")->u.ptr = "";
+ setvar(e[i].name, w);
}
free(e);
}
+ freebuf(path);
close(envf);
}
-/* break string of values into words at 01's or nulls*/
static Word *
encodenulls(char *s, int n)
{
- Word *w, *head;
- char *cp;
+ Word *head, **link;
+ int m;
- head = w = 0;
- while (n-- > 0) {
- for (cp = s; *cp && *cp != '\0'; cp++)
- n--;
- *cp = 0;
- if (w) {
- w->next = newword(s);
- w = w->next;
- } else
- head = w = newword(s);
- s = cp+1;
+ head = 0;
+ link = &head;
+ while(n > 0){
+ m = strlen(s)+1;
+ n -= m;
+ *link = newword(s);
+ s += m;
+ link = &(*link)->next;
}
- if (!head)
- head = newword("");
return head;
}
-/* as well as 01's, change blanks to nulls, so that rc will
- * treat the words as separate arguments
- */
void
-exportenv(Envy *e)
+exportenv(Symtab **e)
{
- int f, n, hasvalue, first;
+ int f, n, npath;
+ Bufblock *path;
Word *w;
- Symtab *sy;
- char nam[256];
- for(;e->name; e++){
- sy = symlook(e->name, S_VAR, 0);
- if (e->values == 0 || e->values->s == 0 || e->values->s[0] == 0)
- hasvalue = 0;
- else
- hasvalue = 1;
- if(sy == 0 && !hasvalue) /* non-existant null symbol */
+ path = newbuf();
+ bufcpy(path, envdir);
+ npath = path->current - path->start;
+
+ for(;*e; e++){
+ w = (*e)->u.ptr;
+ path->current = path->start + npath;
+ bufcpy(path, (*e)->name);
+ insert(path, 0);
+ if(w == 0){
+ remove(path->start);
continue;
- snprint(nam, sizeof nam, "/env/%s", e->name);
- if (sy != 0 && !hasvalue) { /* Remove from environment */
- /* we could remove it from the symbol table
- * too, but we're in the child copy, and it
- * would still remain in the parent's table.
- */
- remove(nam);
- delword(e->values);
- e->values = 0; /* memory leak */
- continue;
}
-
- f = create(nam, OWRITE, 0666L);
+ f = create(path->start, OWRITE, 0666L);
if(f < 0) {
- fprint(2, "can't create %s, f=%d\n", nam, f);
- perror(nam);
+ fprint(2, "can't create %s\n", path->start);
+ perror(path->start);
continue;
}
- first = 1;
- for (w = e->values; w; w = w->next) {
+ if(w->next == 0){
n = strlen(w->s);
- if (n) {
- if(first)
- first = 0;
- else{
- if (write (f, "\0", 1) != 1)
- perror(nam);
- }
- if (write(f, w->s, n) != n)
- perror(nam);
- }
+ if(n == 0) n = 1;
+ if(write(f, w->s, n) != n)
+ perror(path->start);
+ } else {
+ Bufblock *buf = newbuf();
+ do {
+ bufcpy(buf, w->s);
+ insert(buf, 0);
+ w = w->next;
+ } while(w);
+ n = buf->current - buf->start;
+ if(write(f, buf->start, n) != n)
+ perror(path->start);
+ freebuf(buf);
}
close(f);
}
+ freebuf(path);
}
int
@@ -156,83 +148,31 @@
}
int
-execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
+execsh(char *cmd, char *args, Symtab **env, Bufblock *buf)
{
- char *p;
- int tot, n, pid, in[2], out[2];
+ int fd, tot, n, pid;
- if(buf && pipe(out) < 0){
- perror("pipe");
- Exit();
- }
- pid = rfork(RFPROC|RFFDG|RFENVG);
- if(pid < 0){
- perror("mk rfork");
- Exit();
- }
- if(pid == 0){
- if(buf)
- close(out[0]);
- if(pipe(in) < 0){
- perror("pipe");
- Exit();
- }
- pid = fork();
- if(pid < 0){
- perror("mk fork");
- Exit();
- }
- if(pid != 0){
- dup(in[0], 0);
- if(buf){
- dup(out[1], 1);
- close(out[1]);
- }
- close(in[0]);
- close(in[1]);
- if (e)
- exportenv(e);
- if(shflags)
- execl(shell, shellname, shflags, args, nil);
- else
- execl(shell, shellname, args, nil);
- perror(shell);
- _exits("exec");
- }
- if(buf)
- close(out[1]);
- close(in[0]);
- p = cmd+strlen(cmd);
- while(cmd < p){
- n = write(in[1], cmd, p-cmd);
- if(n < 0)
- break;
- cmd += n;
- }
- close(in[1]);
- _exits(0);
- }
+ pid = pipecmd(cmd, args, env, buf? &fd: 0);
if(buf){
- close(out[1]);
tot = 0;
for(;;){
- if (buf->current >= buf->end)
+ if(buf->current >= buf->end)
growbuf(buf);
- n = read(out[0], buf->current, buf->end-buf->current);
+ n = read(fd, buf->current, buf->end-buf->current);
if(n <= 0)
break;
buf->current += n;
tot += n;
}
- if (tot && buf->current[-1] == '\n')
+ if(tot && buf->current[-1] == '\n')
buf->current--;
- close(out[0]);
+ close(fd);
}
return pid;
}
int
-pipecmd(char *cmd, Envy *e, int *fd)
+pipecmd(char *cmd, char *args, Symtab **env, int *fd)
{
int pid, pfd[2];
@@ -254,18 +194,22 @@
dup(pfd[1], 1);
close(pfd[1]);
}
- if(e)
- exportenv(e);
- if(shflags)
- execl(shell, shellname, shflags, "-c", cmd, nil);
+ if(env)
+ exportenv(env);
+ if(args)
+ execl(shell, shellname, args, "-Ic", cmd, nil);
else
- execl(shell, shellname, "-c", cmd, nil);
+ execl(shell, shellname, "-Ic", cmd, nil);
perror(shell);
_exits("exec");
}
if(fd){
+ char name[32];
+
close(pfd[1]);
- *fd = pfd[0];
+ snprint(name, sizeof(name), "/fd/%d", pfd[0]);
+ *fd = open(name, OREAD|OCEXEC);
+ close(pfd[0]);
}
return pid;
}
@@ -301,15 +245,6 @@
atnotify(notifyf, 1);
}
-char*
-maketmp(void)
-{
- static char temp[] = "/tmp/mkargXXXXXX";
-
- mktemp(temp);
- return temp;
-}
-
int
chgtime(char *name)
{
@@ -335,7 +270,7 @@
p = match->ep;
c = *p;
*p = 0;
- *to = strdup(match->sp);
+ *to = Strdup(match->sp);
*p = c;
}
else
@@ -344,95 +279,75 @@
}
void
-dirtime(char *dir, char *path)
+dirtime(char *dir)
{
- int i, fd, n;
- long mtime;
+ int i, fd, n, npath;
+ Bufblock *path;
+ ulong t;
Dir *d;
- char buf[4096];
- fd = open(dir, OREAD);
+ if(symlook(dir, S_BULKED, 0))
+ return;
+ symlook(dir, S_BULKED, 1);
+
+ path = newbuf();
+ bufcpy(path, dir);
+ if(strcmp(dir, ".") == 0)
+ npath = 0;
+ else {
+ insert(path, '/');
+ npath = path->current - path->start;
+ }
+ insert(path, 0);
+ fd = open(path->start, OREAD);
if(fd >= 0){
while((n = dirread(fd, &d)) > 0){
for(i=0; i<n; i++){
- mtime = d[i].mtime;
+ t = d[i].mtime;
/* defensive driving: this does happen */
- if(mtime == 0)
- mtime = 1;
- snprint(buf, sizeof buf, "%s%s", path,
- d[i].name);
- if(symlook(buf, S_TIME, 0) == nil)
- symlook(strdup(buf), S_TIME,
- (void*)mtime)->u.value = mtime;
+ if(t == 0) t = 1;
+ path->current = path->start + npath;
+ bufcpy(path, d[i].name);
+ insert(path, 0);
+ symlook(path->start, S_TIME, 1)->u.value = t;
}
free(d);
}
close(fd);
}
+ freebuf(path);
}
-void
-bulkmtime(char *dir)
-{
- char buf[4096];
- char *ss, *s, *sym;
-
- if(dir){
- sym = dir;
- s = dir;
- if(strcmp(dir, "/") == 0)
- strecpy(buf, buf + sizeof buf - 1, dir);
- else
- snprint(buf, sizeof buf, "%s/", dir);
- }else{
- s = ".";
- sym = "";
- buf[0] = 0;
- }
- if(symlook(sym, S_BULKED, 0))
- return;
- ss = strdup(sym);
- symlook(ss, S_BULKED, (void*)ss);
- dirtime(s, buf);
-}
-
ulong
mkmtime(char *name, int force)
{
- Dir *d;
- char *s, *ss, carry;
+ char *a, *s;
ulong t;
- Symtab *sym;
- char buf[4096];
- strecpy(buf, buf + sizeof buf - 1, name);
- cleanname(buf);
- name = buf;
-
- s = utfrrune(name, '/');
- if(s == name)
- s++;
+ t = 0;
+ /* cleanname() needs at least 2 characters */
+ a = Malloc(strlen(name)+2+1);
+ strcpy(a, name);
+ cleanname(a);
+ s = utfrrune(a, '/');
if(s){
- ss = name;
- carry = *s;
*s = 0;
+ dirtime(a);
+ *s = '/';
}else{
- ss = 0;
- carry = 0;
+ dirtime(".");
}
- bulkmtime(ss);
- if(carry)
- *s = carry;
if(!force){
- sym = symlook(name, S_TIME, 0);
+ Symtab *sym = symlook(a, S_TIME, 0);
if(sym)
- return sym->u.value;
- return 0;
+ t = sym->u.value;
+ } else {
+ Dir *d = dirstat(a);
+ if(d){
+ t = d->mtime;
+ free(d);
+ }
}
- if((d = dirstat(name)) == nil)
- return 0;
- t = d->mtime;
- free(d);
+ free(a);
return t;
}
-
--- a/sys/src/cmd/mk/rc.c
+++ b/sys/src/cmd/mk/rc.c
@@ -1,8 +1,6 @@
#include "mk.h"
-char *termchars = "'= \t"; /*used in parse.c to isolate assignment attribute*/
-char *shflags = "-I"; /* rc flag to force non-interactive mode */
-int IWS = '\1'; /* inter-word separator in env - not used in plan 9 */
+char termchars[] = "'= \t"; /*used in parse.c to isolate assignment attribute*/
/*
* This file contains functions that depend on rc's syntax. Most
@@ -172,4 +170,41 @@
s = copysingle(s, buf); /* copy quoted string */
}
return s;
+}
+
+static int
+needquotes(char *s)
+{
+ Rune r;
+
+ if(*s == 0)
+ return 1;
+ while(*s){
+ s += chartorune(&r, s);
+ if(needsrcquote(r))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * append string s into buffer buf with rc quoting as neccessary.
+ */
+void
+bufcpyq(Bufblock *buf, char *s)
+{
+ Rune r;
+
+ if(!needquotes(s)){
+ bufcpy(buf, s);
+ return;
+ }
+ insert(buf, '\'');
+ while(*s){
+ s += chartorune(&r, s);
+ if(r == '\'')
+ rinsert(buf, r);
+ rinsert(buf, r);
+ }
+ insert(buf, '\'');
}
--- a/sys/src/cmd/mk/recipe.c
+++ b/sys/src/cmd/mk/recipe.c
@@ -9,7 +9,7 @@
Node *n;
Rule *r = 0;
Symtab *s;
- Word head, ahead, lp, ln, *w, *ww, *aw;
+ Word *head, *ahead, *lp, *ln, *w, **ww, **aw;
aa = 0;
/*
@@ -45,13 +45,11 @@
build the node list
*/
node->next = 0;
- head.next = 0;
- ww = &head;
- ahead.next = 0;
- aw = &ahead;
+ head = 0, ww = &head;
+ ahead = 0, aw = &ahead;
if(r->attr®EXP){
- ww->next = newword(node->name);
- aw->next = newword(node->name);
+ *ww = newword(node->name);
+ *aw = newword(node->name);
} else {
for(w = r->alltargets; w; w = w->next){
if(r->attr&META)
@@ -58,11 +56,10 @@
subst(aa->stem, w->s, buf, sizeof(buf));
else
strecpy(buf, buf + sizeof buf - 1, w->s);
- aw->next = newword(buf);
- aw = aw->next;
+ *aw = newword(buf), aw = &(*aw)->next;
if((s = symlook(buf, S_NODE, 0)) == 0)
continue; /* not a node we are interested in */
- n = s->u.ptr;
+ n = (Node*)s->u.ptr;
if(aflag == 0 && n->time) {
for(a = n->prereqs; a; a = a->next)
if(a->n && outofdate(n, a, 0))
@@ -70,8 +67,7 @@
if(a == 0)
continue;
}
- ww->next = newword(buf);
- ww = ww->next;
+ *ww = newword(buf), ww = &(*ww)->next;
if(n == node) continue;
n->next = node->next;
node->next = n;
@@ -83,13 +79,13 @@
/*
gather the params for the job
*/
- lp.next = ln.next = 0;
+ lp = ln = 0;
for(n = node; n; n = n->next){
for(a = n->prereqs; a; a = a->next){
if(a->n){
- addw(&lp, a->n->name);
+ wadd(&lp, a->n->name);
if(outofdate(n, a, 0)){
- addw(&ln, a->n->name);
+ wadd(&ln, a->n->name);
if(explain)
fprint(1, "%s(%ld) < %s(%ld)\n",
n->name, n->time, a->n->name, a->n->time);
@@ -96,25 +92,11 @@
}
} else {
if(explain)
- fprint(1, "%s has no prerequisites\n",
- n->name);
+ fprint(1, "%s has no prerequisites\n", n->name);
}
}
MADESET(n, BEINGMADE);
}
-/* print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),wtos(lp.next, ' '));/**/
- run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, ahead.next));
+ run(newjob(r, node, aa->stem, aa->match, lp, ln, head, ahead));
return(1);
-}
-
-void
-addw(Word *w, char *s)
-{
- Word *lw;
-
- for(lw = w; w = w->next; lw = w){
- if(strcmp(s, w->s) == 0)
- return;
- }
- lw->next = newword(s);
}
--- a/sys/src/cmd/mk/rule.c
+++ b/sys/src/cmd/mk/rule.c
@@ -1,33 +1,33 @@
#include "mk.h"
static Rule *lr, *lmr;
-static rcmp(Rule *r, char *target, Word *tail);
static int nrules = 0;
void
-addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, char *prog)
+addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int line, char *prog)
{
- Rule *r;
- Rule *rr;
+ Rule *r, *rr;
Symtab *sym;
int reuse;
r = 0;
reuse = 0;
- if(sym = symlook(head, S_TARGET, 0)){
- for(r = sym->u.ptr; r; r = r->chain)
- if(rcmp(r, head, tail) == 0){
+ sym = symlook(head, S_TARGET, 0);
+ if(sym){
+ for(r = sym->u.ptr; r; r = r->chain){
+ if(wcmp(r->tail, tail) == 0){
reuse = 1;
break;
}
+ }
}
if(r == 0)
r = (Rule *)Malloc(sizeof(Rule));
- r->target = head;
+
r->tail = tail;
r->recipe = body;
- r->line = hline;
- r->file = infile;
+ r->line = line;
+ r->file = mkinfile;
r->attr = attr;
r->alltargets = ahead;
r->prog = prog;
@@ -34,15 +34,19 @@
r->rule = nrules++;
if(!reuse){
- rr = symlook(head, S_TARGET, r)->u.ptr;
- if(rr != r){
+ r->next = 0;
+ r->chain = 0;
+ if(sym == 0){
+ sym = symlook(head, S_TARGET, 1);
+ sym->u.ptr = r;
+ } else {
+ rr = sym->u.ptr;
r->chain = rr->chain;
rr->chain = r;
- } else
- r->chain = 0;
+ }
}
- if(!reuse)
- r->next = 0;
+ r->target = sym;
+
if((attr®EXP) || charin(head, "%&")){
r->attr |= META;
if(reuse)
@@ -73,28 +77,19 @@
void
dumpr(char *s, Rule *r)
{
+ char *t;
+
Bprint(&bout, "%s: start=%p\n", s, r);
for(; r; r = r->next){
Bprint(&bout, "\tRule %p: %s:%d attr=%x next=%p chain=%p alltarget='%s'",
- r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' '));
+ r, r->file, r->line, r->attr, r->next, r->chain,
+ t = wtos(r->alltargets)), free(t);
if(r->prog)
Bprint(&bout, " prog='%s'", r->prog);
- Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail,' '));
+ Bprint(&bout, "\n\ttarget=%s: %s\n", r->target->name,
+ t = wtos(r->tail)), free(t);
Bprint(&bout, "\trecipe@%p='%s'\n", r->recipe, r->recipe);
}
-}
-
-static int
-rcmp(Rule *r, char *target, Word *tail)
-{
- Word *w;
-
- if(strcmp(r->target, target))
- return 1;
- for(w = r->tail; w && tail; w = w->next, tail = tail->next)
- if(strcmp(w->s, tail->s))
- return 1;
- return(w || tail);
}
char *
--- a/sys/src/cmd/mk/run.c
+++ b/sys/src/cmd/mk/run.c
@@ -40,12 +40,12 @@
static void
sched(void)
{
- char *flags;
- Job *j;
+ char *t, *flags;
Bufblock *buf;
- int slot;
+ Symtab **env;
Node *n;
- Envy *e;
+ Job *j;
+ int slot;
if(jobs == 0){
usage();
@@ -54,14 +54,16 @@
j = jobs;
jobs = j->next;
if(DEBUG(D_EXEC))
- fprint(1, "firing up job for target %s\n", wtos(j->t, ' '));
+ fprint(1, "firing up job for target %s\n",
+ t = wtos(j->t)),
+ free(t);
slot = nextslot();
events[slot].job = j;
buf = newbuf();
- e = buildenv(j, slot);
- shprint(j->r->recipe, e, buf);
+ env = buildenv(j, slot);
+ shprint(j->r->recipe, buf);
if(!tflag && (nflag || !(j->r->attr&QUIET)))
- Bwrite(&bout, buf->start, (long)strlen(buf->start));
+ Bwrite(&bout, buf->start, strlen(buf->start));
freebuf(buf);
if(nflag||tflag){
for(n = j->n; n; n = n->next){
@@ -82,11 +84,13 @@
flags = 0;
else
flags = "-e";
- events[slot].pid = execsh(flags, j->r->recipe, 0, e);
+ events[slot].pid = execsh(j->r->recipe, flags, env, 0);
usage();
nrunning++;
if(DEBUG(D_EXEC))
- fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid);
+ fprint(1, "pid for target %s = %d\n",
+ t = wtos(j->t), events[slot].pid),
+ free(t);
}
}
@@ -93,7 +97,6 @@
int
waitup(int echildok, int *retstatus)
{
- Envy *e;
int pid;
int slot;
Symtab *s;
@@ -140,13 +143,14 @@
goto again;
}
j = events[slot].job;
+ events[slot].job = 0;
+ events[slot].pid = -1;
usage();
nrunning--;
- events[slot].pid = -1;
if(buf[0]){
- e = buildenv(j, slot);
+ buildenv(j, slot);
bp = newbuf();
- shprint(j->r->recipe, e, bp);
+ shprint(j->r->recipe, bp);
front(bp->start);
fprint(2, "mk: %s: exit status=%s", bp->start, buf);
freebuf(bp);
@@ -169,8 +173,9 @@
for(w = j->t; w; w = w->next){
if((s = symlook(w->s, S_NODE, 0)) == 0)
continue; /* not interested in this node */
- update(uarg, s->u.ptr);
+ update(uarg, (Node*)s->u.ptr);
}
+ freejob(j);
if(nrunning < nproclimit)
sched();
return(0);
@@ -179,14 +184,10 @@
void
nproc(void)
{
- Symtab *sym;
Word *w;
- if(sym = symlook("NPROC", S_VAR, 0)) {
- w = sym->u.ptr;
- if (w && w->s && w->s[0])
- nproclimit = atoi(w->s);
- }
+ if(!empty(w = getvar("NPROC")))
+ nproclimit = atoi(w->s);
if(nproclimit < 1)
nproclimit = 1;
if(DEBUG(D_EXEC))
@@ -193,7 +194,7 @@
fprint(1, "nprocs = %d\n", nproclimit);
if(nproclimit > nevents){
if(nevents)
- events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event));
+ events = (Event *)Realloc(events, nproclimit*sizeof(Event));
else
events = (Event *)Malloc(nproclimit*sizeof(Event));
while(nevents < nproclimit)
@@ -281,7 +282,7 @@
long t;
time(&t);
- if(tick)
+ if(tick && nrunning < nelem(tslot))
tslot[nrunning] += (t-tick);
tick = t;
}
@@ -292,6 +293,6 @@
int i;
usage();
- for(i = 0; i <= nevents; i++)
+ for(i = 0; i <= nevents && i < nelem(tslot); i++)
fprint(1, "%d: %ld\n", i, tslot[i]);
}
--- a/sys/src/cmd/mk/shprint.c
+++ b/sys/src/cmd/mk/shprint.c
@@ -1,9 +1,9 @@
#include "mk.h"
-static char *vexpand(char*, Envy*, Bufblock*);
+static char *vexpand(char*, Bufblock*);
void
-shprint(char *s, Envy *env, Bufblock *buf)
+shprint(char *s, Bufblock *buf)
{
int n;
Rune r;
@@ -11,7 +11,7 @@
while(*s) {
n = chartorune(&r, s);
if (r == '$')
- s = vexpand(s, env, buf);
+ s = vexpand(s, buf);
else {
rinsert(buf, r);
s += n;
@@ -21,25 +21,26 @@
insert(buf, 0);
}
-static char *
-mygetenv(char *name, Envy *env)
+static Symtab*
+mygetenv(char *name)
{
- if (!env)
- return 0;
- if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == 0)
- return 0;
- /* only resolve internal variables and variables we've set */
- for(; env->name; env++){
- if (strcmp(env->name, name) == 0)
- return wtos(env->values, ' ');
+ Symtab *s;
+
+ /* only resolve internal variables and variables we've set */
+ s = symlook(name, S_INTERNAL, 0);
+ if(s == 0){
+ s = symlook(name, S_VAR, 0);
+ if(s == 0 || !symlook(name, S_WESET, 0))
+ return 0;
}
- return 0;
+ return s;
}
static char *
-vexpand(char *w, Envy *env, Bufblock *buf)
+vexpand(char *w, Bufblock *buf)
{
- char *s, carry, *p, *q;
+ char carry, *p, *q;
+ Symtab *s;
assert(/*vexpand no $*/ *w == '$');
p = w+1; /* skip dollar sign */
@@ -52,15 +53,14 @@
q = shname(p);
carry = *q;
*q = 0;
- s = mygetenv(p, env);
+ s = mygetenv(p);
*q = carry;
if (carry == '}')
q++;
- if (s) {
- bufcpy(buf, s, strlen(s));
- free(s);
- } else /* copy name intact*/
- bufcpy(buf, w, q-w);
+ if(s)
+ bufcpyw(buf, s->u.ptr);
+ else /* copy $name intact */
+ bufncpy(buf, w, q-w);
return(q);
}
@@ -71,7 +71,7 @@
int i, j;
char *flds[512];
- q = strdup(s);
+ q = Strdup(s);
i = getfields(q, flds, nelem(flds), 0, " \t\n");
if(i > 5){
flds[4] = flds[i-1];
--- a/sys/src/cmd/mk/symtab.c
+++ b/sys/src/cmd/mk/symtab.c
@@ -5,7 +5,7 @@
static Symtab *hash[NHASH];
Symtab *
-symlook(char *sym, int space, void *install)
+symlook(char *sym, int space, int install)
{
long h;
char *p;
@@ -17,17 +17,17 @@
h = ~h;
h %= NHASH;
for(s = hash[h]; s; s = s->next)
- if((s->space == space) && (strcmp(s->name, sym) == 0))
- return(s);
+ if(s->space == space && strcmp(s->name, sym) == 0)
+ return s;
if(install == 0)
- return(0);
- s = (Symtab *)Malloc(sizeof(Symtab));
+ return 0;
+ s = (Symtab *)Malloc(sizeof(Symtab) + (++p - sym));
s->space = space;
- s->name = sym;
- s->u.ptr = install;
+ s->u.ptr = 0;
+ memcpy(s->name, sym, p - sym);
s->next = hash[h];
hash[h] = s;
- return(s);
+ return s;
}
void
--- a/sys/src/cmd/mk/var.c
+++ b/sys/src/cmd/mk/var.c
@@ -1,10 +1,20 @@
#include "mk.h"
+Word*
+getvar(char *name)
+{
+ Symtab *sym = symlook(name, S_VAR, 0);
+ if(sym)
+ return sym->u.ptr;
+ return 0;
+}
+
void
-setvar(char *name, void *value)
+setvar(char *name, Word *value)
{
- symlook(name, S_VAR, value)->u.ptr = value;
- symlook(name, S_MAKEVAR, (void*)"");
+ Symtab *sym = symlook(name, S_VAR, 1);
+ delword(sym->u.ptr);
+ sym->u.ptr = value;
}
static void
--- a/sys/src/cmd/mk/varsub.c
+++ b/sys/src/cmd/mk/varsub.c
@@ -5,7 +5,6 @@
static Bufblock *varname(char**);
static Word *extractpat(char*, char**, char*, char*);
static int submatch(char*, Word*, Word*, int*, char**);
-static Word *varmatch(char *);
Word *
varsub(char **s)
@@ -15,14 +14,12 @@
if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
return expandvar(s);
-
b = varname(s);
if(b == 0)
return 0;
-
- w = varmatch(b->start);
+ w = getvar(b->start);
freebuf(b);
- return w;
+ return wdup(w);
}
/*
@@ -45,7 +42,7 @@
rinsert(b, r);
cp += n;
}
- if (b->current == b->start){
+ if(b->current == b->start){
SYNERR(-1);
fprint(2, "missing variable name <%s>\n", *s);
freebuf(b);
@@ -57,42 +54,25 @@
}
static Word*
-varmatch(char *name)
-{
- Word *w;
- Symtab *sym;
-
- sym = symlook(name, S_VAR, 0);
- if(sym){
- /* check for at least one non-NULL value */
- for (w = sym->u.ptr; w; w = w->next)
- if(w->s && *w->s)
- return wdup(w);
- }
- return 0;
-}
-
-static Word*
expandvar(char **s)
{
Word *w;
Bufblock *buf;
- Symtab *sym;
char *cp, *begin, *end;
begin = *s;
(*s)++; /* skip the '{' */
buf = varname(s);
- if (buf == 0)
+ if(buf == 0)
return 0;
cp = *s;
- if (*cp == '}') { /* ${name} variant*/
+ if(*cp == '}') { /* ${name} variant*/
(*s)++; /* skip the '}' */
- w = varmatch(buf->start);
+ w = getvar(buf->start);
freebuf(buf);
- return w;
+ return wdup(w);
}
- if (*cp != ':') {
+ if(*cp != ':') {
SYNERR(-1);
fprint(2, "bad variable name <%s>\n", buf->start);
freebuf(buf);
@@ -99,7 +79,7 @@
return 0;
}
cp++;
- end = charin(cp , "}");
+ end = charin(cp, "}");
if(end == 0){
SYNERR(-1);
fprint(2, "missing '}': %s\n", begin);
@@ -107,13 +87,10 @@
}
*end = 0;
*s = end+1;
-
- sym = symlook(buf->start, S_VAR, 0);
- if(sym == 0 || sym->u.value == 0)
- w = newword(buf->start);
- else
- w = subsub(sym->u.ptr, cp, end);
+ w = getvar(buf->start);
freebuf(buf);
+ if(w)
+ w = subsub(w, cp, end);
return w;
}
@@ -120,8 +97,7 @@
static Word*
extractpat(char *s, char **r, char *term, char *end)
{
- int save;
- char *cp;
+ char save, *cp;
Word *w;
cp = charin(s, term);
@@ -144,7 +120,7 @@
subsub(Word *v, char *s, char *end)
{
int nmid;
- Word *head, *tail, *w, *h;
+ Word *head, *tail, *w, *h, **l;
Word *a, *b, *c, *d;
Bufblock *buf;
char *cp, *enda;
@@ -164,47 +140,52 @@
buf = newbuf();
for(; v; v = v->next){
h = w = 0;
+ l = &h;
if(submatch(v->s, a, b, &nmid, &enda)){
/* enda points to end of A match in source;
* nmid = number of chars between end of A and start of B
*/
if(c){
- h = w = wdup(c);
- while(w->next)
+ *l = w = wdup(c);
+ while(w->next){
+ l = &w->next;
w = w->next;
+ }
}
if(PERCENT(*cp) && nmid > 0){
if(w){
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, enda, nmid);
+ bufcpy(buf, w->s);
+ bufncpy(buf, enda, nmid);
insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
+ delword(w);
+ *l = w = newword(buf->start);
} else {
- bufcpy(buf, enda, nmid);
+ bufncpy(buf, enda, nmid);
insert(buf, 0);
- h = w = newword(buf->start);
+ *l = w = newword(buf->start);
}
buf->current = buf->start;
}
- if(d && *d->s){
+ if(!empty(d)){
if(w){
-
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, d->s, strlen(d->s));
+ bufcpy(buf, w->s);
+ bufcpy(buf, d->s);
insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
+ delword(w);
+ *l = w = newword(buf->start);
w->next = wdup(d->next);
- while(w->next)
- w = w->next;
buf->current = buf->start;
- } else
- h = w = wdup(d);
+ } else {
+ *l = w = wdup(d);
+ }
+ while(w->next){
+ l = &w->next;
+ w = w->next;
+ }
}
}
if(w == 0)
- h = w = newword(v->s);
+ *l = w = newword(v->s);
if(head == 0)
head = h;
@@ -223,9 +204,9 @@
static int
submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
{
+ char *end;
Word *w;
int n;
- char *end;
n = 0;
for(w = a; w; w = w->next){
--- a/sys/src/cmd/mk/word.c
+++ b/sys/src/cmd/mk/word.c
@@ -5,85 +5,109 @@
Word*
newword(char *s)
{
- Word *w;
-
- w = (Word *)Malloc(sizeof(Word));
- w->s = strdup(s);
+ int n = strlen(s)+1;
+ Word *w = (Word *)Malloc(sizeof(Word) + n);
+ memcpy(w->s, s, n);
w->next = 0;
- return(w);
+ return w;
}
+Word*
+popword(Word *w)
+{
+ Word *x = w->next;
+ free(w);
+ return x;
+}
+
Word *
stow(char *s)
{
- Word *head, *w, *new;
+ Word *w, *h, **l;
- w = head = 0;
- while(*s){
- new = nextword(&s);
- if(new == 0)
- break;
- if (w)
- w->next = new;
- else
- head = w = new;
+ h = 0;
+ l = &h;
+ while(*s && (*l = w = nextword(&s))){
while(w->next)
w = w->next;
-
+ l = &w->next;
}
- if (!head)
- head = newword("");
- return(head);
+ return h;
}
char *
-wtos(Word *w, int sep)
+wtos(Word *w)
{
Bufblock *buf;
- char *cp;
+ char *s;
buf = newbuf();
+ bufcpyw(buf, w);
+ insert(buf, 0);
+ s = Strdup(buf->start);
+ freebuf(buf);
+ return s;
+}
+
+void
+bufcpyw(Bufblock *buf, Word *w)
+{
for(; w; w = w->next){
- for(cp = w->s; *cp; cp++)
- insert(buf, *cp);
+ bufcpyq(buf, w->s);
if(w->next)
- insert(buf, sep);
+ insert(buf, ' ');
}
- insert(buf, 0);
- cp = strdup(buf->start);
- freebuf(buf);
- return(cp);
}
+int
+empty(Word *w)
+{
+ return w == 0 || w->s[0] == 0;
+}
+
+int
+wadd(Word **l, char *s)
+{
+ Word *w;
+
+ while(w = *l){
+ if(strcmp(w->s, s) == 0)
+ return 1;
+ l = &w->next;
+ }
+ *l = newword(s);
+ return 0;
+}
+
+int
+wcmp(Word *a, Word *b)
+{
+ for(; a && b; a = a->next, b = b->next)
+ if(strcmp(a->s, b->s))
+ return 1;
+ return(a || b);
+}
+
Word*
wdup(Word *w)
{
- Word *v, *new, *base;
+ Word *h, **l;
- v = base = 0;
+ h = 0;
+ l = &h;
while(w){
- new = newword(w->s);
- if(v)
- v->next = new;
- else
- base = new;
- v = new;
+ *l = newword(w->s);
+ l = &(*l)->next;
w = w->next;
}
- return base;
+ return h;
}
void
delword(Word *w)
{
- Word *v;
-
- while(v = w){
- w = w->next;
- if(v->s)
- free(v->s);
- free(v);
- }
+ while(w)
+ w = popword(w);
}
/*
@@ -93,19 +117,20 @@
static Word*
nextword(char **s)
{
+ Word *head, *tail, **link, *w, *t;
Bufblock *b;
- Word *head, *tail, *w;
- Rune r;
- char *cp;
int empty;
+ char *cp;
+ Rune r;
cp = *s;
b = newbuf();
-restart:
+ empty = 1;
head = tail = 0;
+ link = &head;
+restart:
while(*cp == ' ' || *cp == '\t') /* leading white space */
cp++;
- empty = 1;
while(*cp){
cp += chartorune(&r, cp);
switch(r)
@@ -117,12 +142,12 @@
case '\\':
case '\'':
case '"':
- empty = 0;
cp = expandquote(cp, r, b);
if(cp == 0){
fprint(2, "missing closing quote: %s\n", *s);
Exit();
}
+ empty = 0;
break;
case '$':
w = varsub(&cp);
@@ -133,29 +158,29 @@
}
empty = 0;
if(b->current != b->start){
- bufcpy(b, w->s, strlen(w->s));
+ bufcpy(b, w->s);
insert(b, 0);
- free(w->s);
- w->s = strdup(b->start);
+ t = popword(w);
+ w = newword(b->start);
+ w->next = t;
b->current = b->start;
}
- if(head){
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, w->s, strlen(w->s));
+ if(tail){
+ bufcpy(b, tail->s);
+ bufcpy(b, w->s);
insert(b, 0);
- free(tail->s);
- tail->s = strdup(b->start);
- tail->next = w->next;
- free(w->s);
- free(w);
+ delword(tail);
+ *link = tail = newword(b->start);
+ tail->next = popword(w);
b->current = b->start;
} else
- tail = head = w;
- while(tail->next)
+ *link = tail = w;
+ while(tail->next){
+ link = &tail->next;
tail = tail->next;
+ }
break;
default:
- empty = 0;
rinsert(b, r);
break;
}
@@ -162,18 +187,19 @@
}
out:
*s = cp;
- if(b->current != b->start){
- if(head){
- cp = b->current;
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, b->start, cp-b->start);
+ if(b->current != b->start || !empty){
+ insert(b, 0);
+ if(tail){
+ cp = Strdup(b->start);
+ b->current = b->start;
+ bufcpy(b, tail->s);
+ bufcpy(b, cp);
+ free(cp);
insert(b, 0);
- free(tail->s);
- tail->s = strdup(cp);
- } else {
- insert(b, 0);
- head = newword(b->start);
- }
+ delword(tail);
+ *link = newword(b->start);
+ } else
+ *link = newword(b->start);
}
freebuf(b);
return head;