home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <signal.h>
-
- #define ERROR NULL
- #define READ "r"
- #define WRITE "w"
-
- #define EOS 0
- int lpar = '(';
- #define LPAR lpar
- #define RPAR ')'
- #define COMMA ','
- #define GRAVE '`'
- #define ACUTE '\''
- #define LBRAK '['
- #define RBRAK ']'
- #ifdef M4
- char lquote LBRAK;
- char rquote RBRAK;
- #endif
- #ifndef M4
- char lquote = GRAVE;
- char rquote = ACUTE;
- #endif
- #define COMMENT '#'
- #define ALPH 1
- #define DIG 2
-
- #define HSHSIZ 199 /* prime */
- #define STACKS 50
- #define SAVS 4096
- #define TOKS 128
-
- #define putbak(c) *ip++ = c;
- #define getchr() (ip>cur_ip?*--ip: getc(infile[infptr]))
- #define putchr(c) if (cp==NULL) {if (curfile)putc(c,curfile);} 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;
- };
-
- 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 = NULL;
-
- 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 *tempname;
- struct nlist *lookup();
- char *install();
- char *malloc();
- char *mktemp();
- char *copy();
- long ctol();
- int hshval;
- FILE *olist[11] = { stdout };
- int okret;
- int curout = 0;
- FILE *curfile = { stdout };
- FILE *infile[10] = { stdin };
- int infptr = 0;
-
- main(argc, argv)
- char **argv;
- {
- char *argstk[STACKS+10];
- struct call callst[STACKS];
- register char *tp, **ap;
- int delexit(), catchsig();
- register t;
- int i;
-
- #ifdef gcos
- #ifdef M4
- install("GCOS", eoa);
- #endif
- #ifndef M4
- install("gcos", eoa);
- #endif
- #endif
- #ifdef unix
- #ifdef M4
- install("UNIX", eoa);
- #endif
- #ifndef M4
- install("unix", eoa);
- #endif
- #endif
-
- #ifdef M4
- 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);
- #endif
-
- #ifndef M4
- 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);
- #endif
- ap = argstk;
- #ifndef gcos
- if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
- signal(SIGHUP, catchsig);
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, catchsig);
- tempname = mktemp("/tmp/m4aXXXXX");
- close(creat(tempname, 0));
- #endif
- #ifdef gcos
- tempname = "m4.tempa";
- #endif
- if (argc>1)
- putbak(0);
- for (;;) {
- tp = token;
- *tp++ = t = getchr();
- *tp = EOS;
- if (t<=0) {
- if (infptr > 0) {
- fclose(infile[infptr]);
- infptr--;
- cur_ip = ip_stk[infptr];
- continue;
- }
- if (argc<=1)
- break;
- argc--;
- argv++;
- if (infile[infptr]!=stdin)
- fclose(infile[infptr]);
- if (**argv=='-')
- infile[infptr] = stdin;
- else if ((infile[infptr]=fopen(argv[0], READ))==ERROR) {
- fprintf(stderr, "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 = EOS;
- if (*ap = lookup(token)->def) {
- if (++ap >= &argstk[STACKS]) {
- fprintf(stderr, "m4: arg stack overflow\n");
- delexit();
- }
- if (cp==NULL)
- cp = callst;
- else if (++cp > &callst[STACKS]) {
- fprintf(stderr, "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) {
- fprintf(stderr, "m4: EOF in string\n");
- delexit();
- }
- putchr(t);
- }
- } else if (t==COMMENT) {
- putbak(t);
- while ((t = getchr())!='\n'&& t>=0)
- if (cp==NULL)
- putchr(t);
- putbak(t);
- } else if (cp==NULL) {
- 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 = NULL;
- } 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!=NULL) {
- fprintf(stderr, "m4: unexpected EOF\n");
- delexit();
- }
- okret = 1;
- delexit();
- }
-
- catchsig()
- {
- okret = 0;
- delexit();
- }
-
- delexit()
- {
- register FILE *fp;
- register i, c;
-
- if (!okret) {
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- }
- for (i=1; i<10; i++) {
- if (olist[i]==NULL)
- continue;
- fclose(olist[i]);
- tempname[7] = 'a'+i;
- if (okret) {
- fp = fopen(tempname, READ);
- while ((c = getc(fp)) > 0)
- putchar(c);
- fclose(fp);
- }
- unlink(tempname);
- }
- tempname[7] = 'a';
- unlink(tempname);
- exit(1-okret);
- }
-
- puttok()
- {
- register char *tp;
-
- tp = token;
- if (cp) {
- if (op >= &obuf[SAVS]) {
- fprintf(stderr, "m4: argument overflow\n");
- delexit();
- }
- while (*tp)
- *op++ = *tp++;
- } else if (curfile)
- while (*tp)
- putc(*tp++, curfile);
- }
-
- pbstr(str)
- register char *str;
- {
- register char *p;
-
- p = str;
- while (*p++);
- --p;
- if (ip >= &ibuf[SAVS]) {
- fprintf(stderr, "m4: pushback overflow\n");
- delexit();
- }
- while (p > str)
- putbak(*--p);
- }
-
- expand(a1, c)
- register char **a1;
- {
- register char *dp;
- register 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(str)
- char *str;
- {
- register char *s1, *s2;
- register struct nlist *np;
- static struct nlist nodef;
-
- s1 = str;
- for (hshval = 0; *s1; )
- hshval += *s1++;
- hshval %= HSHSIZ;
- for (np = hshtab[hshval]; np!=NULL; np = np->next) {
- s1 = str;
- s2 = np->name;
- while (*s1++ == *s2)
- if (*s2++ == EOS)
- return(np);
- }
- return(&nodef);
- }
-
- char *install(nam, val)
- char *nam, *val;
- {
- register struct nlist *np;
-
- if ((np = lookup(nam))->name == NULL) {
- np = (struct nlist *)malloc(sizeof(*np));
- if (np == NULL) {
- fprintf(stderr, "m4: no space for alloc\n");
- exit(1);
- }
- np->name = copy(nam);
- np->def = copy(val);
- np->next = hshtab[hshval];
- hshtab[hshval] = np;
- return(np->def);
- }
- free(np->def);
- np->def = copy(val);
- return(np->def);
- }
-
- doundef(ap, c)
- char **ap;
- {
- register struct nlist *np, *tnp;
-
- if (c < 1 || (np = lookup(ap[1]))->name == NULL)
- 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);
- }
-
- char *copy(s)
- register char *s;
- {
- register char *p, *s1;
-
- p = s1 = malloc((unsigned)strlen(s)+1);
- if (p == NULL) {
- fprintf(stderr, "m4: no space for alloc\n");
- exit(1);
- }
- while (*s1++ = *s++);
- return(p);
- }
-
- dodef(ap, c)
- char **ap;
- {
- if (c >= 2) {
- if (strcmp(ap[1], ap[2]) == 0) {
- fprintf(stderr, "m4: %s defined as itself\n", ap[1]);
- delexit();
- }
- install(ap[1], ap[2]);
- }
- else if (c == 1)
- install(ap[1], "");
- }
-
- doifdef(ap, c)
- char **ap;
- {
- register struct nlist *np;
-
- if (c < 2)
- return;
- if (lookup(ap[1])->name != NULL)
- pbstr(ap[2]);
- else if (c >= 3)
- pbstr(ap[3]);
- }
-
- dolen(ap, c)
- char **ap;
- {
- putnum((long) strlen(ap[1]));
- }
-
- docq(ap, c)
- char **ap;
- {
- if (c > 1) {
- lquote = *ap[1];
- rquote = *ap[2];
- } else if (c == 1) {
- lquote = rquote = *ap[1];
- } else {
- #ifndef M4
- lquote = GRAVE;
- rquote = ACUTE;
- #endif
- #ifdef M4
- lquote = LBRAK;
- rquote = RBRAK;
- #endif
- }
- }
-
- doshift(ap, c)
- char **ap;
- {
- fprintf(stderr, "m4: shift not yet implemented\n");
- }
-
- dodump(ap, c)
- char **ap;
- {
- int i;
- register struct nlist *np;
-
- if (c > 0)
- while (c--) {
- if ((np = lookup(*++ap))->name != NULL)
- fprintf(stderr, "`%s' `%s'\n", np->name, np->def);
- }
- else
- for (i=0; i<HSHSIZ; i++)
- for (np=hshtab[i]; np!=NULL; np=np->next)
- fprintf(stderr, "`%s' `%s'\n", np->name, np->def);
- }
-
- doerrp(ap, c)
- char **ap;
- {
- if (c > 0) {
- fprintf(stderr, ap[1], ap[2], ap[3], ap[4], ap[5], ap[6]);
- fprintf(stderr, "\n");
- }
- }
-
-
- long evalval; /* return value from yacc stuff */
- char *pe; /* used by grammar */
-
- doeval(ap, c)
- char **ap;
- {
-
- if (c > 0) {
- pe = ap[1];
- if (yyparse() == 0)
- putnum(evalval);
- else
- fprintf(stderr, "m4: invalid expression in eval: %s\n", ap[1]);
- }
- }
-
- doincl(ap, c, noisy)
- char **ap;
- {
- if (c > 0 && strlen(ap[1]) > 0) {
- infptr++;
- ip_stk[infptr] = cur_ip = ip;
- if ((infile[infptr] = fopen(ap[1], READ))==ERROR) {
- if (noisy) {
- fprintf(stderr, "m4: file not found: %s\n", ap[1]);
- delexit();
- }
- else
- infptr--;
- }
- }
- }
-
- dosyscmd(ap, c)
- char **ap;
- {
- if (c > 0)
- system(ap[1]);
- }
-
- domake(ap, c)
- char **ap;
- {
- if (c > 0)
- pbstr(mktemp(ap[1]));
- }
-
- doincr(ap, c)
- char **ap;
- {
- if (c >= 1)
- putnum(ctol(ap[1])+1);
- }
-
- putnum(num)
- long num;
- {
- register sign;
-
- sign = (num < 0) ? '-' : '\0';
- if (num < 0)
- num = -num;
- do {
- putbak(num%10+'0');
- num = num/10;
- } while (num!=0);
- if (sign == '-')
- putbak('-');
- }
-
- dosubstr(ap, c)
- char **ap;
- {
- int nc;
- register 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);
- }
-
- doindex(ap, c)
- char **ap;
- {
- if (c >= 2)
- putnum((long) strindex(ap[1], ap[2]));
- }
-
- strindex(p1, p2)
- char *p1, *p2;
- {
- register m;
- register 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);
- }
-
- dotransl(ap, c)
- char **ap;
- {
- register char *s, *fr, *to;
-
- if (c <= 1) return;
-
- if (c == 2) {
- register 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]);
- }
-
- doif(ap, c)
- register char **ap;
- {
- 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]);
- }
-
- dodiv(ap, c)
- register char **ap;
- {
- register int f;
-
- if (c<1)
- f = 0;
- else
- f = ctoi(ap[1]);
- if (f>=10 || f<0) {
- curfile = NULL;
- return;
- }
- tempname[7] = 'a' + f;
- if (olist[f] || (olist[f]=fopen(tempname, WRITE))) {
- curout = f;
- curfile = olist[f];
- }
- }
-
- doundiv(ap, c)
- char **ap;
- {
- register FILE *fp;
- register int i, ch;
- int j;
-
- if (c == 0) {
- for (i=1; i<10; i++) {
- if (i==curout || olist[i]==NULL)
- continue;
- fclose(olist[i]);
- tempname[7] = 'a'+i;
- fp = fopen(tempname, READ);
- if (curfile != NULL)
- while ((ch = getc(fp)) > 0)
- putc(ch, curfile);
- fclose(fp);
- unlink(tempname);
- olist[i] = NULL;
- }
-
- }
- else {
- for (j = 1; j <= c; j++) {
- i = ctoi(*++ap);
- if (i<1 || i>9 || i==curout || olist[i]==NULL)
- continue;
- fclose(olist[i]);
- tempname[7] = 'a'+i;
- fp = fopen(tempname, READ);
- if (curfile != NULL)
- while ((ch = getc(fp)) > 0)
- putc(ch, curfile);
- fclose(fp);
- unlink(tempname);
- olist[i] = NULL;
- }
- }
- }
-
- dodivnum(ap, c)
- char **ap;
- {
- putnum((long) curout);
- }
-
- dodnl(ap, c)
- char **ap;
- {
- register t;
-
- while ((t=getchr())!='\n' && t>=0)
- ;
- }
-
- long ctol(str)
- register char *str;
- {
- register 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);
- }
-
- ctoi(s)
- char *s;
- {
- return(ctol(s));
- }
-
- min(a, b)
- {
- if (a>b)
- return(b);
- return(a);
- }
-
- max(a, b)
- {
- if (a>b)
- return(a);
- return(b);
- }
-