add new | syntax.

syntax will change.
This commit is contained in:
rsc 2005-01-04 22:41:27 +00:00
parent 02f38ca68c
commit 9aa1c92f74
19 changed files with 281 additions and 83 deletions

View file

@ -11,10 +11,8 @@ void atouch(char*);
void bufcpy(Bufblock *, char *, int);
Envy *buildenv(Job*, int);
void catchnotes(void);
char *charin(char *, char *);
int chgtime(char*);
void clrmade(Node*);
char *copyq(char*, Rune, Bufblock*);
void delete(char*);
void delword(Word*);
int dorecipe(Node*);
@ -24,24 +22,23 @@ void dumpn(char*, Node*);
void dumpr(char*, Rule*);
void dumpv(char*);
void dumpw(char*, Word*);
int escapetoken(Biobuf*, Bufblock*, int, int);
void execinit(void);
int execsh(char*, char*, Bufblock*, Envy*);
int execsh(char*, char*, Bufblock*, Envy*, Shell*, Word*);
void Exit(void);
char *expandquote(char*, Rune, Bufblock*);
void expunge(int, char*);
void freebuf(Bufblock*);
void front(char*);
Node *graph(char*);
void growbuf(Bufblock *);
void initenv(void);
void initshell(void);
void insert(Bufblock *, int);
void ipop(void);
void ipush(void);
void killchildren(char*);
void *Malloc(int);
char *maketmp(int*);
int match(char*, char*, char*);
int match(char*, char*, char*, Shell*);
char *membername(char*, int, char*);
void mk(char*);
ulong mkmtime(char*);
@ -56,17 +53,21 @@ void nproc(void);
void nrep(void);
int outofdate(Node*, Arc*, int);
void parse(char*, int, int);
int pipecmd(char*, Envy*, int*);
int pipecmd(char*, Envy*, int*, Shell*, Word*);
void popshell(void);
void prusage(void);
void pushshell(void);
void rcopy(char**, Resub*, int);
void readenv(void);
void *Realloc(void*, int);
void rinsert(Bufblock *, Rune);
char *rulecnt(void);
void run(Job*);
char *setshell(Word*);
void setvar(char*, void*);
int shargv(Word*, int, char***);
char *shname(char*);
void shprint(char*, Envy*, Bufblock*);
void shprint(char*, Envy*, Bufblock*, Shell*);
Word *stow(char*);
void subst(char*, char*, char*);
void symdel(char*, int);

View file

@ -84,7 +84,7 @@ applyrules(char *target, char *cnt)
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, stem, r->shellt)) continue;
}
if(cnt[r->rule] >= nreps) continue;
cnt[r->rule]++;

View file

@ -28,7 +28,7 @@ assline(Biobuf *bp, Bufblock *buf)
case '\'':
case '"':
rinsert(buf, c);
if (escapetoken(bp, buf, 1, c) == 0)
if (shellt->escapetoken(bp, buf, 1, c) == 0)
Exit();
break;
case '`':
@ -87,14 +87,14 @@ bquote(Biobuf *bp, Bufblock *buf)
insert(buf,0);
buf->current = buf->start+start;
execinit();
execsh(0, buf->current, buf, envy);
execsh(0, buf->current, buf, envy, shellt, shellcmd);
return 1;
}
if(c == '\n')
break;
if(c == '\'' || c == '"' || c == '\\'){
insert(buf, c);
if(!escapetoken(bp, buf, 1, c))
if(!shellt->escapetoken(bp, buf, 1, c))
return 0;
continue;
}

View file

@ -39,6 +39,7 @@ main(int argc, char **argv)
* instead of sharing them
*/
initshell();
Binit(&bout, 1, OWRITE);
buf = newbuf();
whatif = 0;

View file

@ -1,7 +1,7 @@
#include "mk.h"
int
match(char *name, char *template, char *stem)
match(char *name, char *template, char *stem, Shell *sh)
{
Rune r;
int n;
@ -24,7 +24,7 @@ match(char *name, char *template, char *stem)
strncpy(stem, name, n);
stem[n] = 0;
if(*template == '&')
return !charin(stem, "./");
return !sh->charin(stem, "./");
return 1;
}

View file

@ -192,14 +192,14 @@ update(int fake, Node *node)
}
static int
pcmp(char *prog, char *p, char *q)
pcmp(char *prog, char *p, char *q, Shell *sh, Word *shcmd)
{
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(buf, 0, 0, sh, shcmd);
while(waitup(-3, &pid) >= 0)
;
return(pid? 2:1);
@ -219,7 +219,7 @@ outofdate(Node *node, Arc *arc, int eval)
if(sym == 0 || eval){
if(sym == 0)
str = strdup(buf);
ret = pcmp(arc->prog, node->name, arc->n->name);
ret = pcmp(arc->prog, node->name, arc->n->name, arc->r->shellt, arc->r->shellcmd);
if(sym)
sym->value = (void *)ret;
else

View file

@ -26,6 +26,18 @@ typedef struct Envy
extern Envy *envy;
typedef struct Shell
{
char *name;
char *termchars; /* used in parse.c to isolate assignment attribute */
int iws; /* inter-word separator in environment */
char *(*charin)(char*, char*); /* search for unescaped characters */
char *(*expandquote)(char*, Rune, Bufblock*); /* extract escaped token */
int (*escapetoken)(Biobuf*, Bufblock*, int, int); /* input escaped token */
char *(*copyq)(char*, Rune, Bufblock*); /* check for quoted strings */
int (*matchname)(char*); /* does name match */
} Shell;
typedef struct Rule
{
char *target; /* one target */
@ -40,6 +52,8 @@ typedef struct Rule
char *prog; /* to use in out of date */
struct Rule *chain; /* hashed per target */
struct Rule *next;
Shell *shellt; /* shell to use with this rule */
Word *shellcmd;
} Rule;
extern Rule *rules, *metarules, *patrule;
@ -143,11 +157,10 @@ extern int mkinline;
extern char *infile;
extern int nreps;
extern char *explain;
extern char *termchars;
extern int IWS;
extern char *shell;
extern char *shellname;
extern char *shflags;
extern Shell *shellt;
extern Word *shellcmd;
extern Shell shshell, rcshell;
#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))

View file

@ -1,5 +1,12 @@
a: b
cp b a
|$PLAN9/bin/rc
use-rc:V:
for(i in a b c)
echo $i
|/bin/sh
use-sh:V:
for i in a b c
do
echo $i
done
c:V:
echo hello world

View file

@ -17,11 +17,13 @@ parse(char *f, int fd, int varoverride)
int newfd;
Biobuf in;
Bufblock *buf;
char *err;
if(fd < 0){
fprint(2, "open %s: %r\n", f);
Exit();
}
pushshell();
ipush();
infile = strdup(f);
mkinline = 1;
@ -52,7 +54,7 @@ parse(char *f, int fd, int varoverride)
Exit();
}
execinit();
pid=pipecmd(p, envy, &newfd);
pid=pipecmd(p, envy, &newfd, shellt, shellcmd);
if(newfd < 0){
fprint(2, "warning: skipping missing program file %s: %r\n", p);
} else
@ -93,6 +95,14 @@ cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
if(attr)
symlook(head->s, S_NOEXPORT, (void *)"");
break;
case 'S':
if((err = setshell(tail)) != nil){
SYNERR(hline);
fprint(2, "%s\n", err);
Exit();
break;
}
break;
default:
SYNERR(hline);
fprint(2, "expected one of :<=\n");
@ -103,6 +113,7 @@ cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
close(fd);
freebuf(buf);
ipop();
popshell();
}
void
@ -114,7 +125,7 @@ addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
/* tuck away first non-meta rule as default target*/
if(target1 == 0 && !(attr&REGEXP)){
for(w = head; w; w = w->next)
if(charin(w->s, "%&"))
if(shellt->charin(w->s, "%&"))
break;
if(w == 0)
target1 = wdup(head);
@ -133,19 +144,24 @@ rhead(char *line, Word **h, Word **t, int *attr, char **prog)
int n;
Word *w;
p = charin(line,":=<");
if(p == 0)
return('?');
sep = *p;
*p++ = 0;
if(sep == '<' && *p == '|'){
sep = '|';
p++;
if(*line == '|'){
sep = 'S'; /* shell */
p = line+1;
}else{
p = shellt->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 */
pp = shellt->charin(p, shellt->termchars); /* termchars is shell-dependent */
if (pp && *pp == '=') {
while (p != pp) {
n = chartorune(&r, p);
@ -219,7 +235,7 @@ rhead(char *line, Word **h, Word **t, int *attr, char **prog)
}
}
*h = w = stow(line);
if(*w->s == 0 && sep != '<' && sep != '|') {
if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') {
SYNERR(mkinline-1);
fprint(2, "no var on left side of assignment/rule\n");
Exit();

View file

@ -1,9 +1,5 @@
#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 */
/*
* This file contains functions that depend on rc's syntax. Most
* of the routines extract strings observing rc's escape conventions
@ -38,7 +34,7 @@ squote(char *cp)
* characters in quotes and variable generators are escaped
*/
char *
charin(char *cp, char *pat)
rccharin(char *cp, char *pat)
{
Rune r;
int n, vargen;
@ -82,7 +78,7 @@ charin(char *cp, char *pat)
* others are just inserted into the receiving buffer.
*/
char*
expandquote(char *s, Rune r, Bufblock *b)
rcexpandquote(char *s, Rune r, Bufblock *b)
{
if (r != '\'') {
rinsert(b, r);
@ -108,7 +104,7 @@ expandquote(char *s, Rune r, Bufblock *b)
* rc; the others are just inserted into the receiving buffer.
*/
int
escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
{
int c, line;
@ -155,7 +151,7 @@ copysingle(char *s, Bufblock *buf)
* s points to char after opening quote, q.
*/
char *
copyq(char *s, Rune q, Bufblock *buf)
rccopyq(char *s, Rune q, Bufblock *buf)
{
if(q == '\'') /* copy quoted string */
return copysingle(s, buf);
@ -173,3 +169,26 @@ copyq(char *s, Rune q, Bufblock *buf)
}
return s;
}
static int
rcmatchname(char *name)
{
char *p;
if((p = strchr(name, '/')) != nil)
name = p+1;
if(name[0] == 'r' && name[1] == 'c')
return 1;
return 0;
}
Shell rcshell = {
"rc",
"'= \t",
'\1',
rccharin,
rcexpandquote,
rcescapetoken,
rccopyq,
rcmatchname,
};

View file

@ -23,6 +23,8 @@ addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, ch
}
if(r == 0)
r = (Rule *)Malloc(sizeof(Rule));
r->shellt = shellt;
r->shellcmd = shellcmd;
r->target = head;
r->tail = tail;
r->recipe = body;
@ -42,7 +44,7 @@ addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, ch
}
if(!reuse)
r->next = 0;
if((attr&REGEXP) || charin(head, "%&")){
if((attr&REGEXP) || shellt->charin(head, "%&")){
r->attr |= META;
if(reuse)
return;
@ -72,7 +74,8 @@ addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, ch
void
dumpr(char *s, Rule *r)
{
Bprint(&bout, "%s: start=%ld\n", s, r);
Bprint(&bout, "%s: start=%ld shelltype=%s shellcmd=%s\n",
s, r, r->shellt->name, wtos(r->shellcmd, ' '));
for(; r; r = r->next){
Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld alltarget='%s'",
r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' '));

View file

@ -59,7 +59,7 @@ sched(void)
events[slot].job = j;
buf = newbuf();
e = buildenv(j, slot);
shprint(j->r->recipe, e, buf);
shprint(j->r->recipe, e, buf, j->r->shellt);
if(!tflag && (nflag || !(j->r->attr&QUIET)))
Bwrite(&bout, buf->start, (long)strlen(buf->start));
freebuf(buf);
@ -82,7 +82,7 @@ sched(void)
flags = 0;
else
flags = "-e";
events[slot].pid = execsh(flags, j->r->recipe, 0, e);
events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->shellt, j->r->shellcmd);
usage();
nrunning++;
if(DEBUG(D_EXEC))
@ -145,7 +145,7 @@ again: /* rogue processes */
if(buf[0]){
e = buildenv(j, slot);
bp = newbuf();
shprint(j->r->recipe, e, bp);
shprint(j->r->recipe, e, bp, j->r->shellt);
front(bp->start);
fprint(2, "mk: %s: exit status=%s", bp->start, buf);
freebuf(bp);

View file

@ -1,9 +1,5 @@
#include "mk.h"
char *termchars = "\"'= \t"; /*used in parse.c to isolate assignment attribute*/
char *shflags = 0;
int IWS = ' '; /* inter-word separator in env */
/*
* This file contains functions that depend on the shell's syntax. Most
* of the routines extract strings observing the shell's escape conventions.
@ -34,8 +30,8 @@ squote(char *cp, int c)
/*
* search a string for unescaped characters in a pattern set
*/
char *
charin(char *cp, char *pat)
static char *
shcharin(char *cp, char *pat)
{
Rune r;
int n, vargen;
@ -82,8 +78,8 @@ charin(char *cp, char *pat)
* extract an escaped token. Possible escape chars are single-quote,
* double-quote,and backslash.
*/
char*
expandquote(char *s, Rune esc, Bufblock *b)
static char*
shexpandquote(char *s, Rune esc, Bufblock *b)
{
Rune r;
@ -110,8 +106,8 @@ expandquote(char *s, Rune esc, Bufblock *b)
* Input an escaped token. Possible escape chars are single-quote,
* double-quote and backslash.
*/
int
escapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
static int
shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
{
int c, line;
@ -168,8 +164,8 @@ copysingle(char *s, Rune q, Bufblock *buf)
* check for quoted strings. backquotes are handled here; single quotes above.
* s points to char after opening quote, q.
*/
char *
copyq(char *s, Rune q, Bufblock *buf)
static char *
shcopyq(char *s, Rune q, Bufblock *buf)
{
if(q == '\'' || q == '"') /* copy quoted string */
return copysingle(s, q, buf);
@ -187,3 +183,24 @@ copyq(char *s, Rune q, Bufblock *buf)
}
return s;
}
static int
shmatchname(char *name)
{
USED(name);
return 1;
}
Shell shshell = {
"sh",
"\"'= \t", /*used in parse.c to isolate assignment attribute*/
' ', /* inter-word separator in env */
shcharin,
shexpandquote,
shescapetoken,
shcopyq,
shmatchname,
};

76
src/cmd/mk/shell.c Normal file
View file

@ -0,0 +1,76 @@
#include "mk.h"
static Shell *shells[] = {
&shshell,
&rcshell
};
Shell *shellt;
Word *shellcmd;
typedef struct Shellstack Shellstack;
struct Shellstack
{
Shell *t;
Word *w;
Shellstack *next;
};
Shellstack *shellstack;
char*
setshell(Word *w)
{
int i;
if(w->s == nil)
return "shell name not found on line";
for(i=0; i<nelem(shells); i++)
if(shells[i]->matchname(w->s))
break;
if(i == nelem(shells))
return "cannot determine shell type";
shellt = shells[i];
shellcmd = w;
return nil;
}
void
initshell(void)
{
shellcmd = stow(shells[0]->name);
shellt = shells[0];
}
void
pushshell(void)
{
Shellstack *s;
/* save */
s = Malloc(sizeof *s);
s->t = shellt;
s->w = shellcmd;
s->next = shellstack;
shellstack = s;
initshell(); /* reset to defaults */
}
void
popshell(void)
{
Shellstack *s;
if(shellstack == nil){
fprint(2, "internal shellstack error\n");
Exit();
}
s = shellstack;
shellstack = s->next;
shellt = s->t;
shellcmd = s->w;
free(s);
}

View file

@ -40,7 +40,7 @@ getfields(char *str, char **args, int max, int mflag, char *set)
}
void
shprint(char *s, Envy *env, Bufblock *buf)
shprint(char *s, Envy *env, Bufblock *buf, Shell *sh)
{
int n;
Rune r;
@ -52,7 +52,7 @@ shprint(char *s, Envy *env, Bufblock *buf)
else {
rinsert(buf, r);
s += n;
s = copyq(s, r, buf); /*handle quoted strings*/
s = sh->copyq(s, r, buf); /*handle quoted strings*/
}
}
insert(buf, 0);

22
src/cmd/mk/sys.std.h Normal file
View file

@ -0,0 +1,22 @@
#include <utf.h>
#include <fmt.h>
#include <bio.h>
#include <regexp9.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#define OREAD O_RDONLY
#define OWRITE O_WRONLY
#define ORDWR O_RDWR
#define nil 0
#define nelem(x) sizeof((x)/sizeof((x)[0]))
#define seek lseek
#define remove unlink
#define exits(x) exit(x && *(char*)x ? 1 : 0)
#define USED(x) if(x){}else
#define create(name, mode, perm) open(name, mode|O_CREAT, perm)
#define ERRMAX 256

View file

@ -51,7 +51,7 @@ readenv(void)
* to exec immediately after this.
*/
void
exportenv(Envy *e)
exportenv(Envy *e, Shell *sh)
{
int i;
char **p;
@ -61,7 +61,7 @@ exportenv(Envy *e)
for(i = 0; e->name; e++, i++) {
p = (char**) Realloc(p, (i+2)*sizeof(char*));
if(e->values)
snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->values, IWS));
snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->values, sh->iws));
else
snprint(buf, sizeof buf, "%s=", e->name);
p[i] = strdup(buf);
@ -102,9 +102,29 @@ expunge(int pid, char *msg)
int mypid;
int
execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
shargv(Word *cmd, int extra, char ***pargv)
{
char *p;
char **argv;
int i, n;
Word *w;
n = 0;
for(w=cmd; w; w=w->next)
n++;
argv = Malloc((n+extra+1)*sizeof(argv[0]));
i = 0;
for(w=cmd; w; w=w->next)
argv[i++] = w->s;
argv[n] = 0;
*pargv = argv;
return n;
}
int
execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcmd)
{
char *p, **argv;
int tot, n, pid, in[2], out[2];
if(buf && pipe(out) < 0){
@ -138,11 +158,11 @@ execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
close(in[0]);
close(in[1]);
if (e)
exportenv(e);
if(shflags)
execl(shell, shellname, shflags, args, 0);
else
execl(shell, shellname, args, 0);
exportenv(e, sh);
n = shargv(shellcmd, 1, &argv);
argv[n++] = args;
argv[n] = 0;
execvp(argv[0], argv);
mkperror(shell);
_exit(1);
}
@ -180,9 +200,11 @@ execsh(char *args, char *cmd, Bufblock *buf, Envy *e)
}
int
pipecmd(char *cmd, Envy *e, int *fd)
pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd)
{
int pid, pfd[2];
int n;
char **argv;
if(DEBUG(D_EXEC))
fprint(1, "pipecmd='%s'\n", cmd);/**/
@ -203,11 +225,12 @@ pipecmd(char *cmd, Envy *e, int *fd)
close(pfd[1]);
}
if(e)
exportenv(e);
if(shflags)
execl(shell, shellname, shflags, "-c", cmd, 0);
else
execl(shell, shellname, "-c", cmd, 0);
exportenv(e, sh);
n = shargv(shellcmd, 2, &argv);
argv[n++] = "-c";
argv[n++] = cmd;
argv[n] = 0;
execvp(argv[0], argv);
mkperror(shell);
_exit(1);
}

View file

@ -103,7 +103,7 @@ expandvar(char **s)
return 0;
}
cp++;
end = charin(cp , "}");
end = shellt->charin(cp , "}");
if(end == 0){
SYNERR(-1);
fprint(2, "missing '}': %s\n", begin);
@ -128,7 +128,7 @@ extractpat(char *s, char **r, char *term, char *end)
char *cp;
Word *w;
cp = charin(s, term);
cp = shellt->charin(s, term);
if(cp){
*r = cp;
if(cp == s)

View file

@ -114,7 +114,7 @@ nextword(char **s)
case '\\':
case '\'':
case '"':
cp = expandquote(cp, r, b);
cp = shellt->expandquote(cp, r, b);
if(cp == 0){
fprint(2, "missing closing quote: %s\n", *s);
Exit();