#include <u.h>
#include <libc.h>
#include <bio.h>
int lpar = '(';
#define LPAR lpar
#define RPAR ')'
#define COMMA ','
#define GRAVE '`'
#define ACUTE '\''
#define LBRAK '['
#define RBRAK ']'
char lquote = GRAVE;
char rquote = ACUTE;
#define COMMENT '#'
#define ALPH 1
#define DIG 2
#define HSHSIZ 2003 /* prime */
#define STACKS 500
#define SAVS 40960
#define TOKS 1280
#define putbak(c) *ip++ = c;
#define getchr() (ip>cur_ip?*--ip: Bgetc(infile[infptr]))
#define putchr(c) if (cp==nil) {if (curfile)Bputc(curfile, c);} else *op++ = c
char type[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG,
DIG, DIG, 0, 0, 0, 0, 0, 0,
0, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,
ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,
ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,
ALPH, ALPH, ALPH, 0, 0, 0, 0, ALPH,
0, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,
ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,
ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH, ALPH,
ALPH, ALPH, ALPH, 0, 0, 0, 0, 0,
};
char token[TOKS];
char eoa[] = "\0";
struct nlist {
char *name;
char *def;
struct nlist *next;
};
long evalval; /* return value from yacc stuff */
char *pe; /* used by grammar */
struct nlist *hshtab[HSHSIZ];
char ibuf[SAVS+TOKS];
char obuf[SAVS+TOKS];
char *op = obuf;
char *ip = ibuf;
char *ip_stk[10] = {ibuf};
char *cur_ip = ibuf;
struct call {
char **argp;
int plev;
};
struct call *cp = nil;
char *makeloc;
char *ifdefloc;
char *lenloc;
char *undefloc;
char *shiftloc;
char *cqloc;
char *defloc;
char *evaloc;
char *incrloc;
char *substrloc;
char *indexloc;
char *transloc;
char *ifloc;
char *divloc;
char *divnumloc;
char *undivloc;
char *dnlloc;
char *inclloc;
char *sinclloc;
char *syscmdloc;
char *dumploc;
char *errploc;
char *tmp_nam;
int hshval;
Biobuf *olist[11];
int okret;
int curout = 0;
Biobuf *curfile;
Biobuf *infile[10];
int infptr = 0;
extern int yyparse(void);
void notifyf(void *, char *);
void delexit(void);
void puttok(void);
void pbstr(char *);
void expand(char **, int);
struct nlist *lookup(char *);
char *install(char *, char *);
void doundef(char **, int);
void dodef(char **, int);
void doifdef(char **, int);
void dolen(char **, int);
void docq(char **, int);
void doshift(char **, int);
void dodump(char **, int);
void doerrp(char **, int);
void doeval(char **, int);
void doincl(void **, int, int);
void dosyscmd(char **, int);
void domake(char **, int);
void doincr(char **, int);
void putnum(long);
void dosubstr(char **, int);
void doindex(char **, int);
int strindex(char *, char *);
void dotransl(char **, int );
void doif(char **, int);
void dodiv(char **, int);
void doundiv(char **, int);
void dodivnum(char **, int);
void dodnl(char **, int);
long ctol(char *);
int ctoi(char *);
int min(int, int);
int max(int, int);
void
main(int argc, char *argv[])
{
Biobuf bin, bout;
char *argstk[STACKS+10];
struct call callst[STACKS];
char *tp, **ap;
int t, i;
Binit(&bin, 0, OREAD);
Binit(&bout, 1, OWRITE);
curfile = &bout;
*olist = &bout;
*infile = &bin;
install("plan9", eoa);
makeloc = install("maketemp", eoa);
ifdefloc = install("ifdef", eoa);
lenloc = install("len", eoa);
undefloc = install("undefine", eoa);
shiftloc = install("shift", eoa);
cqloc = install("changequote", eoa);
defloc = install("define", eoa);
evaloc = install("eval", eoa);
inclloc = install("include", eoa);
sinclloc = install("sinclude", eoa);
syscmdloc = install("syscmd", eoa);
dumploc = install("dumpdef", eoa);
errploc = install("errprint", eoa);
incrloc = install("incr", eoa);
substrloc = install("substr", eoa);
indexloc = install("index", eoa);
transloc = install("translit", eoa);
ifloc = install("ifelse", eoa);
divloc = install("divert", eoa);
divnumloc = install("divnum", eoa);
undivloc = install("undivert", eoa);
dnlloc = install("dnl", eoa);
ap = argstk;
notify(notifyf);
tmp_nam = mktemp("/tmp/m4aXXXXX");
close(create(tmp_nam, 0, 0644));
if (argc>1)
putbak(0);
for (;;) {
tp = token;
*tp++ = t = getchr();
*tp = 0;
if (t<=0) {
if (infptr > 0) {
Bterm(infile[infptr]);
infptr--;
cur_ip = ip_stk[infptr];
continue;
}
if (argc<=1)
break;
argc--;
argv++;
if (infile[infptr] != &bin)
Bterm(infile[infptr]);
if (**argv=='-')
infile[infptr] = &bin;
else if ((infile[infptr] = Bopen(argv[0], OREAD)) == nil) {
fprint(2, "m4: file not found: %s\n", argv[0]);
delexit();
}
continue;
}
if (type[t]==ALPH) {
while ((t=type[*tp++=getchr()])==ALPH||t==DIG);
putbak(*--tp);
*tp = 0;
if (*ap = lookup(token)->def) {
if (++ap >= &argstk[STACKS]) {
fprint(2, "m4: arg stack overflow\n");
delexit();
}
if (cp==nil)
cp = callst;
else if (++cp > &callst[STACKS]) {
fprint(2, "m4: call stack overflow\n");
delexit();
}
cp->argp = ap;
*ap++ = op;
puttok();
*op++ = '\0';
t = getchr();
putbak(t);
if (t!=LPAR) {
/* if (t!=' ' && t!='\t') */
putbak(')');
putbak('(');
}
else /* try to fix arg count */
*ap++ = op;
cp->plev = 0;
} else
puttok();
} else if (t==lquote) {
i = 1;
for (;;) {
t = getchr();
if (t==rquote) {
i--;
if (i==0)
break;
} else if (t==lquote)
i++;
else if (t<0) {
fprint(2, "m4: EOF in string\n");
delexit();
}
putchr(t);
}
} else if (t==COMMENT) {
putbak(t);
while ((t = getchr())!='\n'&& t>=0)
if (cp==nil)
putchr(t);
putbak(t);
} else if (cp==nil) {
puttok();
} else if (t==LPAR) {
if (cp->plev)
*op++ = t;
cp->plev++;
while ( (t=getchr())==' ' || t=='\t' || t=='\n')
; /* skip leading white space during arg collection */
putbak(t);
/*
} else if (t==' ' || t=='\t' || t=='\n') {
continue;
*/
} else if (t==RPAR) {
cp->plev--;
if (cp->plev==0) {
*op++ = '\0';
expand(cp->argp, ap-cp->argp-1);
op = *cp->argp;
ap = cp->argp-1;
cp--;
if (cp < callst)
cp = nil;
} else
*op++ = t;
} else if (t==COMMA && cp->plev<=1) {
*op++ = '\0';
*ap++ = op;
while ((t=getchr())==' ' || t=='\t' || t=='\n')
; /* skip leading white space during arg collection */
putbak(t);
} else
*op++ = t;
}
if (cp!=nil) {
fprint(2, "m4: unexpected EOF\n");
delexit();
}
okret = 1;
delexit();
}
void
notifyf(void *a, char *s)
{
USED(a, s);
delexit();
}
void
delexit(void)
{
Biobuf *bp;
int i, c;
for (i=1; i<10; i++) {
if (olist[i]==nil)
continue;
Bterm(olist[i]);
tmp_nam[7] = 'a'+i;
if (okret) {
bp = Bopen(tmp_nam, OREAD);
while ((c = Bgetc(bp)) > 0)
Bputc(curfile, c);
Bterm(bp);
}
remove(tmp_nam);
}
tmp_nam[7] = 'a';
remove(tmp_nam);
exits((1-okret)? "error": 0);
}
void
puttok(void)
{
char *tp;
tp = token;
if (cp) {
if (op >= &obuf[SAVS]) {
fprint(2, "m4: argument overflow\n");
delexit();
}
while (*tp)
*op++ = *tp++;
} else if (curfile)
while (*tp)
Bputc(curfile, *tp++);
}
void
pbstr(char *str)
{
char *p;
p = str;
while (*p++);
--p;
if (ip >= &ibuf[SAVS]) {
fprint(2, "m4: pushback overflow\n");
delexit();
}
while (p > str)
putbak(*--p);
}
void
expand(char **a1, int c)
{
char *dp;
int n;
dp = a1[-1];
if (dp==defloc)
dodef(a1, c);
else if (dp==evaloc)
doeval(a1, c);
else if (dp==inclloc)
doincl(a1, c, 1);
else if (dp==sinclloc)
doincl(a1, c, 0);
else if (dp==makeloc)
domake(a1, c);
else if (dp==syscmdloc)
dosyscmd(a1, c);
else if (dp==incrloc)
doincr(a1, c);
else if (dp==substrloc)
dosubstr(a1, c);
else if (dp==indexloc)
doindex(a1, c);
else if (dp==transloc)
dotransl(a1, c);
else if (dp==ifloc)
doif(a1, c);
else if (dp==divloc)
dodiv(a1, c);
else if (dp==divnumloc)
dodivnum(a1, c);
else if (dp==undivloc)
doundiv(a1, c);
else if (dp==dnlloc)
dodnl(a1, c);
else if (dp==dumploc)
dodump(a1, c);
else if (dp==errploc)
doerrp(a1, c);
else if (dp==lenloc)
dolen(a1, c);
else if (dp==ifdefloc)
doifdef(a1, c);
else if (dp==undefloc)
doundef(a1, c);
else if (dp==shiftloc)
doshift(a1, c);
else if (dp==cqloc)
docq(a1, c);
else {
while (*dp++);
for (dp--; dp>a1[-1]; ) {
if (--dp>a1[-1] && dp[-1]=='$') {
n = *dp-'0';
if (n>=0 && n<=9) {
if (n <= c)
pbstr(a1[n]);
dp--;
} else
putbak(*dp);
} else
putbak(*dp);
}
}
}
struct nlist *
lookup(char *str)
{
char *s1, *s2;
struct nlist *np;
static struct nlist nodef;
s1 = str;
for (hshval = 0; *s1; )
hshval += *s1++;
hshval %= HSHSIZ;
for (np = hshtab[hshval]; np!=nil; np = np->next) {
s1 = str;
s2 = np->name;
while (*s1++ == *s2)
if (*s2++ == 0)
return(np);
}
return(&nodef);
}
char *
install(char *nam, char *val)
{
struct nlist *np;
if ((np = lookup(nam))->name == nil) {
np = (struct nlist *)malloc(sizeof(*np));
if (np == nil) {
fprint(2, "m4: no space for alloc\n");
exits("no memory");
}
np->name = strdup(nam);
np->def = strdup(val);
np->next = hshtab[hshval];
hshtab[hshval] = np;
return(np->def);
}
free(np->def);
np->def = strdup(val);
return(np->def);
}
void
doundef(char **ap, int c)
{
struct nlist *np, *tnp;
if (c < 1 || (np = lookup(ap[1]))->name == nil)
return;
tnp = hshtab[hshval]; /* lookup sets hshval */
if (tnp == np) /* it's in first place */
hshtab[hshval] = np->next;
else {
for ( ; tnp->next != np; tnp = tnp->next)
;
tnp->next = np->next;
}
free(np->name);
free(np->def);
free((char *)np);
}
void
dodef(char **ap, int c)
{
if (c >= 2) {
if (strcmp(ap[1], ap[2]) == 0) {
fprint(2, "m4: %s defined as itself\n", ap[1]);
delexit();
}
install(ap[1], ap[2]);
}
else if (c == 1)
install(ap[1], "");
}
void
doifdef(char **ap, int c)
{
if (c < 2)
return;
if (lookup(ap[1])->name != nil)
pbstr(ap[2]);
else if (c >= 3)
pbstr(ap[3]);
}
void
dolen(char **ap, int c)
{
USED(c);
putnum((long) strlen(ap[1]));
}
void
docq(char **ap, int c)
{
if (c > 1) {
lquote = *ap[1];
rquote = *ap[2];
} else if (c == 1) {
lquote = rquote = *ap[1];
} else {
lquote = GRAVE;
rquote = ACUTE;
}
}
void
doshift(char **ap, int c)
{
USED(ap, c);
fprint(2, "m4: shift not yet implemented\n");
}
void
dodump(char **ap, int c)
{
int i;
struct nlist *np;
if (c > 0)
while (c--) {
if ((np = lookup(*++ap))->name != nil)
fprint(2, "`%s' `%s'\n", np->name, np->def);
}
else
for (i=0; i<HSHSIZ; i++)
for (np=hshtab[i]; np!=nil; np=np->next)
fprint(2, "`%s' `%s'\n", np->name, np->def);
}
void
doerrp(char **ap, int c)
{
if (c > 0) {
fprint(2, ap[1], ap[2], ap[3], ap[4], ap[5], ap[6]);
fprint(2, "\n");
}
}
void
doeval(char **ap, int c)
{
if (c > 0) {
pe = ap[1];
if (yyparse() == 0)
putnum(evalval);
else
fprint(2, "m4: invalid expression in eval: %s\n", ap[1]);
}
}
void
doincl(void **ap, int c, int noisy)
{
if (c > 0 && strlen(ap[1]) > 0) {
infptr++;
ip_stk[infptr] = cur_ip = ip;
if ((infile[infptr] = Bopen(ap[1], OREAD)) ==nil) {
if (noisy) {
fprint(2, "m4: file not found: %s\n", ap[1]);
delexit();
}
else
infptr--;
}
}
}
void
dosyscmd(char **ap, int c)
{
if (c <= 0)
return;
if(fork() == 0)
execl("/bin/rc", "rc", "-c", ap[1], 0);
waitpid();
}
void
domake(char **ap, int c)
{
if (c > 0)
pbstr(mktemp(ap[1]));
}
void
doincr(char **ap, int c)
{
if (c >= 1)
putnum(ctol(ap[1])+1);
}
void
putnum(long num)
{
int sign;
sign = (num < 0) ? '-' : '\0';
if (num < 0)
num = -num;
do {
putbak(num % 10 + '0');
num = num / 10;
} while (num != 0);
if (sign == '-')
putbak('-');
}
void
dosubstr(char **ap, int c)
{
int nc;
char *sp, *fc;
if (c < 2)
return;
if (c < 3)
nc = TOKS;
else
nc = ctoi(ap[3]);
fc = ap[1] + max(0, min(ctoi(ap[2]), strlen(ap[1])));
sp = fc + min(nc, strlen(fc));
while (sp > fc)
putbak(*--sp);
}
void
doindex(char **ap, int c)
{
if (c >= 2)
putnum((long) strindex(ap[1], ap[2]));
}
int
strindex(char *p1, char *p2)
{
int m;
char *s, *t, *p;
for (p = p1; *p; p++) {
s = p;
m = 1;
for (t = p2; *t; )
if (*t++ != *s++)
m = 0;
if (m == 1)
return(p-p1);
}
return(-1);
}
void
dotransl(char **ap, int c)
{
char *s, *fr, *to;
if (c <= 1) return;
if (c == 2) {
int i;
to = ap[1];
for (s = ap[1]; *s; s++) {
i = 0;
for (fr = ap[2]; *fr; fr++)
if (*s == *fr) {
i++;
break;
}
if (i == 0)
*to++ = *s;
}
*to = '\0';
}
if (c >= 3) {
for (s = ap[1]; *s; s++)
for (fr = ap[2], to = ap[3]; *fr && *to; fr++, to++)
if (*s == *fr)
*s = *to;
}
pbstr(ap[1]);
}
void
doif(char **ap, int c)
{
if (c < 3)
return;
while (c >= 3) {
if (strcmp(ap[1], ap[2]) == 0) {
pbstr(ap[3]);
return;
}
c -= 3;
ap += 3;
}
if (c > 0)
pbstr(ap[1]);
}
void
dodiv(char **ap, int c)
{
int f;
if (c<1)
f = 0;
else
f = ctoi(ap[1]);
if (f>=10 || f<0) {
curfile = nil;
return;
}
tmp_nam[7] = 'a' + f;
if (olist[f] || (olist[f]=Bopen(tmp_nam, OWRITE))) {
curout = f;
curfile = olist[f];
}
}
void
doundiv(char **ap, int c)
{
Biobuf *bp;
int i, ch;
int j;
if (c == 0) {
for (i=1; i<10; i++) {
if (i==curout || olist[i]==nil)
continue;
Bterm(olist[i]);
tmp_nam[7] = 'a'+i;
bp = Bopen(tmp_nam, OREAD);
if (curfile != nil)
while ((ch = Bgetc(bp)) > 0)
Bputc(curfile, ch);
Bterm(bp);
remove(tmp_nam);
olist[i] = nil;
}
}
else {
for (j = 1; j <= c; j++) {
i = ctoi(*++ap);
if (i<1 || i>9 || i==curout || olist[i]==nil)
continue;
Bterm(olist[i]);
tmp_nam[7] = 'a'+i;
bp = Bopen(tmp_nam, OREAD);
if (curfile != nil)
while ((ch = Bgetc(bp)) > 0)
Bputc(curfile, ch);
Bterm(bp);
remove(tmp_nam);
olist[i] = nil;
}
}
}
void
dodivnum(char **ap, int c)
{
USED(ap, c);
putnum((long) curout);
}
void
dodnl(char **ap, int c)
{
int t;
USED(ap, c);
while ((t=getchr())!='\n' && t>=0)
continue;
}
long
ctol(char *str)
{
int sign;
long num;
while (*str==' ' || *str=='\t' || *str=='\n')
str++;
num = 0;
if (*str == '-') {
sign = -1;
str++;
}
else
sign = 1;
while (*str>='0' && *str<='9')
num = num*10 + *str++ - '0';
return(sign * num);
}
int
ctoi(char *s)
{
return(ctol(s));
}
int
min(int a, int b)
{
if (a>b)
return(b);
return(a);
}
int
max(int a, int b)
{
if (a>b)
return(a);
return(b);
}
|