pdp11v/usr/src/cmd/m4/m4.c
/* @(#)m4.c 1.3 */
#include <stdio.h>
#include <signal.h>
#include "m4.h"
#define match(c,s) (c==*s && (!s[1] || inpmatch(s+1)))
main(argc,argv)
char **argv;
{
register t;
#ifdef gcos
tempfile = "m4*tempa";
#endif
#ifdef unix
{
static sigs[] = {SIGHUP, SIGINT, SIGPIPE, 0};
for (t=0; sigs[t]; ++t)
if (signal(sigs[t], SIG_IGN) != SIG_IGN)
signal(sigs[t],catchsig);
}
tempfile = mktemp("/tmp/m4aXXXXX");
close(creat(tempfile,0));
#endif
/* WARNING: the following depends on the implementation of the ctype macros! */
(_ctype+1)['_'] |= _L; /* makes '_' a real live letter */
/* end of warning */
procnam = argv[0];
getflags(&argc,&argv);
initalloc();
setfname("-");
if (argc>1) {
--argc;
++argv;
if (strcmp(argv[0],"-")) {
ifile[ifx] = xfopen(argv[0],"r");
setfname(argv[0]);
}
}
for (;;) {
token[0] = t = getchr();
token[1] = EOS;
if (t==EOF) {
if (ifx > 0) {
fclose(ifile[ifx]);
ipflr = ipstk[--ifx];
continue;
}
getflags(&argc,&argv);
if (argc<=1)
if (Wrapstr) {
pbstr(Wrapstr);
Wrapstr = NULL;
continue;
} else
break;
--argc;
++argv;
if (ifile[ifx]!=stdin)
fclose(ifile[ifx]);
if (*argv[0]=='-')
ifile[ifx] = stdin;
else
ifile[ifx] = xfopen(argv[0],"r");
setfname(argv[0]);
continue;
}
if (isalpha(t)) {
register char *tp = token+1;
register tlim = toksize;
struct nlist *macadd; /* temp variable */
while (isalnum(*tp++ = getchr()))
if (--tlim<=0)
error2("more than %d chars in word",
toksize);
putbak(*--tp);
*tp = EOS;
macadd = lookup(token);
*Ap = (char *) macadd;
if (macadd->def) {
if ((char *) (++Ap) >= astklm) {
--Ap;
error2(astkof,stksize);
}
if (Cp++==NULL)
Cp = callst;
Cp->argp = Ap;
*Ap++ = op;
puttok(token);
stkchr(EOS);
t = getchr();
putbak(t);
if (t!='(')
pbstr("()");
else /* try to fix arg count */
*Ap++ = op;
Cp->plev = 0;
} else {
puttok(token);
}
} else if (match(t,lquote)) {
register qlev = 1;
for (;;) {
token[0] = t = getchr();
token[1] = EOS;
if (match(t,rquote)) {
if (--qlev > 0)
puttok(token);
else
break;
} else if (match(t,lquote)) {
++qlev;
puttok(token);
} else {
if (t==EOF)
error("EOF in quote");
putchr(t);
}
}
} else if (match(t,lcom)) {
puttok(token);
for (;;) {
token[0] = t = getchr();
token[1] = EOS;
if (match(t,rcom)) {
puttok(token);
break;
} else {
if (t==EOF)
error("EOF in comment");
putchr(t);
}
}
} else if (Cp==NULL) {
putchr(t);
} else if (t=='(') {
if (Cp->plev)
stkchr(t);
else {
/* skip white before arg */
while (isspace(t=getchr()))
;
putbak(t);
}
++Cp->plev;
} else if (t==')') {
--Cp->plev;
if (Cp->plev==0) {
stkchr(EOS);
expand(Cp->argp,Ap-Cp->argp-1);
op = *Cp->argp;
Ap = Cp->argp-1;
if (--Cp < callst)
Cp = NULL;
} else
stkchr(t);
} else if (t==',' && Cp->plev<=1) {
stkchr(EOS);
*Ap = op;
if ((char *) (++Ap) >= astklm) {
--Ap;
error2(astkof,stksize);
}
while (isspace(t=getchr()))
;
putbak(t);
} else
stkchr(t);
}
if (Cp!=NULL)
error("EOF in argument list");
delexit(OK);
}
char *inpmatch(s)
register char *s;
{
register char *tp = token+1;
while (*s) {
*tp = getchr();
if (*tp++ != *s++) {
*tp = EOS;
pbstr(token+1);
return 0;
}
}
*tp = EOS;
return token;
}
getflags(xargc,xargv)
register int *xargc;
register char ***xargv;
{
while (*xargc > 1) {
register char *arg = (*xargv)[1];
if (arg[0]!='-' || arg[1]==EOS)
break;
switch (arg[1]) {
case 'B':
bufsize = atoi(&arg[2]);
break;
case 'D':
{
register char *t;
char *s[2];
initalloc();
for (t = s[0] = &arg[2]; *t; t++)
if (*t=='=') {
*t++ = EOS;
break;
}
s[1] = t;
dodef(&s[-1],2);
break;
}
case 'H':
hshsize = atoi(&arg[2]);
break;
case 'S':
stksize = atoi(&arg[2]);
break;
case 'T':
toksize = atoi(&arg[2]);
break;
case 'U':
{
char *s[1];
initalloc();
s[0] = &arg[2];
doundef(&s[-1],1);
break;
}
case 'e':
#ifdef unix
setbuf(stdout,(char *) NULL);
signal(SIGINT,SIG_IGN);
#endif
break;
case 's':
/* turn on line sync */
sflag = 1;
break;
default:
fprintf(stderr,"%s: bad option: %s\n",
procnam,arg);
delexit(NOT_OK);
}
(*xargv)++;
--(*xargc);
}
return;
}
initalloc()
{
static done = 0;
register t;
if (done++)
return;
hshtab = (struct nlist **) xcalloc(hshsize,sizeof(struct nlist *));
callst = (struct call *) xcalloc(stksize/3+1,sizeof(struct call));
Ap = argstk = (char **) xcalloc(stksize+3,sizeof(char *));
ipstk[0] = ipflr = ip = ibuf = xcalloc(bufsize+1,sizeof(char));
op = obuf = xcalloc(bufsize+1,sizeof(char));
token = xcalloc(toksize+1,sizeof(char));
astklm = (char *) (&argstk[stksize]);
ibuflm = &ibuf[bufsize];
obuflm = &obuf[bufsize];
toklm = &token[toksize];
for (t=0; barray[t].bname; ++t) {
static char p[2] = {0, EOS};
p[0] = t|~LOW7;
install(barray[t].bname,p,NOPUSH);
}
#ifdef unix
install("unix",nullstr,NOPUSH);
#endif
#ifdef gcos
install("gcos",nullstr,NOPUSH);
#endif
}
struct nlist *
install(nam,val,mode)
char *nam;
register char *val;
{
register struct nlist *np;
register char *cp;
int l;
if (mode==PUSH)
lookup(nam); /* lookup sets hshval */
else
while (undef(nam)) /* undef calls lookup */
;
np = (struct nlist *) xcalloc(1,sizeof(*np));
np->name = copy(nam);
np->next = hshtab[hshval];
hshtab[hshval] = np;
cp = xcalloc((l=strlen(val))+1,sizeof(*val));
np->def = cp;
cp = &cp[l];
while (*val)
*--cp = *val++;
}
struct nlist *
lookup(str)
char *str;
{
register char *s1;
register struct nlist *np;
static struct nlist nodef;
s1 = str;
for (hshval = 0; *s1; )
hshval += *s1++;
hshval %= hshsize;
for (np = hshtab[hshval]; np!=NULL; np = np->next) {
if (!strcmp(str, np->name))
return(np);
}
return(&nodef);
}
expand(a1,c)
char **a1;
{
register char *dp;
register struct nlist *sp;
sp = (struct nlist *) a1[-1];
if (sp->tflag || trace) {
int i;
fprintf(stderr,"Trace(%d): %s",Cp-callst,a1[0]);
if (c > 0) {
fprintf(stderr,"(%s",chkbltin(a1[1]));
for (i=2; i<=c; ++i)
fprintf(stderr,",%s",chkbltin(a1[i]));
fprintf(stderr,")");
}
fprintf(stderr,"\n");
}
dp = sp->def;
for (; *dp; ++dp) {
if (*dp&~LOW7) {
(*barray[*dp&LOW7].bfunc)(a1,c);
} else if (dp[1]=='$') {
if (isdigit(*dp)) {
register n;
if ((n = *dp-'0') <= c)
pbstr(a1[n]);
++dp;
} else if (*dp=='#') {
pbnum((long) c);
++dp;
} else if (*dp=='*' || *dp=='@') {
register i = c;
char **a = a1;
if (i > 0)
for (;;) {
if (*dp=='@')
pbstr(rquote);
pbstr(a[i--]);
if (*dp=='@')
pbstr(lquote);
if (i <= 0)
break;
pbstr(",");
}
++dp;
} else
putbak(*dp);
} else
putbak(*dp);
}
}
setfname(s)
register char *s;
{
strcpy(fname[ifx],s);
fname[ifx+1] = fname[ifx]+strlen(s)+1;
fline[ifx] = 1;
nflag = 1;
lnsync(stdout);
}
lnsync(iop)
register FILE *iop;
{
static int cline = 0;
static int cfile = 0;
if (!sflag || iop!=stdout)
return;
if (nflag || ifx!=cfile) {
nflag = 0;
cfile = ifx;
fprintf(iop,"#line %d \"",cline = fline[ifx]);
fpath(iop);
fprintf(iop,"\"\n");
} else if (++cline != fline[ifx])
fprintf(iop,"#line %d\n",cline = fline[ifx]);
}
fpath(iop)
register FILE *iop;
{
register i;
fprintf(iop,"%s",fname[0]);
for (i=1; i<=ifx; ++i)
fprintf(iop,":%s",fname[i]);
}
catchsig()
{
#ifdef unix
signal(SIGHUP,SIG_IGN);
signal(SIGINT,SIG_IGN);
#endif
delexit(NOT_OK);
}
delexit(code)
{
register i;
cf = stdout;
/* if (ofx != 0) { /* quitting in middle of diversion */
/* ofx = 0;
/* code = NOT_OK;
/* }
*/
ofx = 0; /* ensure that everything comes out */
for (i=1; i<10; i++)
undiv(i,code);
tempfile[7] = 'a';
unlink(tempfile);
if (code==OK)
exit(code);
_exit(code);
}
puttok(tp)
register char *tp;
{
if (Cp) {
while (*tp)
stkchr(*tp++);
} else if (cf)
while (*tp)
sputchr(*tp++,cf);
}
pbstr(str)
register char *str;
{
register char *p;
for (p = str + strlen(str); --p >= str; )
putbak(*p);
}
undiv(i,code)
register i;
{
register FILE *fp;
register c;
if (i<1 || i>9 || i==ofx || !ofile[i])
return;
fclose(ofile[i]);
tempfile[7] = 'a'+i;
if (code==OK && cf) {
fp = xfopen(tempfile,"r");
while ((c=getc(fp)) != EOF)
sputchr(c,cf);
fclose(fp);
}
unlink(tempfile);
ofile[i] = NULL;
}
char *copy(s)
register char *s;
{
register char *p;
p = xcalloc(strlen(s)+1,sizeof(char));
strcpy(p, s);
return(p);
}
pbnum(num)
long num;
{
pbnbr(num,10,1);
}
pbnbr(nbr,base,len)
long nbr;
register base, len;
{
register neg = 0;
if (base<=0)
return;
if (nbr<0)
neg = 1;
else
nbr = -nbr;
while (nbr<0) {
register int i;
if (base>1) {
i = nbr%base;
nbr /= base;
# if (-3 % 2) != -1
while (i > 0) {
i -= base;
++nbr;
}
# endif
i = -i;
} else {
i = 1;
++nbr;
}
putbak(itochr(i));
--len;
}
while (--len >= 0)
putbak('0');
if (neg)
putbak('-');
}
itochr(i)
register i;
{
if (i>9)
return i-10+'A';
else
return i+'0';
}
long ctol(str)
register char *str;
{
register sign;
long num;
while (isspace(*str))
++str;
num = 0;
if (*str=='-') {
sign = -1;
++str;
}
else
sign = 1;
while (isdigit(*str))
num = num*10 + *str++ - '0';
return(sign * num);
}
min(a,b)
{
if (a>b)
return(b);
return(a);
}
FILE *
xfopen(name,mode)
char *name,
*mode;
{
FILE *fp;
if ((fp=fopen(name,mode))==NULL)
error(badfile);
return fp;
}
char *xcalloc(nbr,size)
{
register char *ptr;
if ((ptr=calloc((unsigned) nbr,(unsigned) size)) == NULL)
error(nocore);
return ptr;
}
error2(str,num)
char *str;
int num;
{
char buf[500];
sprintf(buf,str,num);
error(buf);
}
error(str)
char *str;
{
fprintf(stderr,"\n%s:",procnam);
fpath(stderr);
fprintf(stderr,":%d %s\n",fline[ifx],str);
if (Cp) {
register struct call *mptr;
/* fix limit */
*op = EOS;
(Cp+1)->argp = Ap+1;
for (mptr=callst; mptr<=Cp; ++mptr) {
register char **aptr, **lim;
aptr = mptr->argp;
lim = (mptr+1)->argp-1;
if (mptr==callst)
fputs(*aptr,stderr);
++aptr;
fputs("(",stderr);
if (aptr < lim)
for (;;) {
fputs(*aptr++,stderr);
if (aptr >= lim)
break;
fputs(",",stderr);
}
}
while (--mptr >= callst)
fputs(")",stderr);
fputs("\n",stderr);
}
delexit(NOT_OK);
}
char *chkbltin(s)
char *s;
{
static char buf[24];
if (*s&~LOW7){
sprintf(buf,"<%s>",barray[*s&LOW7].bname);
return buf;
}
return s;
}
int getchr()
{
if (ip > ipflr)
return (*--ip);
C = feof(ifile[ifx]) ? EOF : getc(ifile[ifx]);
if (C =='\n')
fline[ifx]++;
return (C);
}