1: /*- 2: * Copyright (c) 1989, 1993 3: * The Regents of the University of California. All rights reserved. 4: * 5: * This code is derived from software contributed to Berkeley by 6: * Ozan Yigit at York University. 7: * 8: * Redistribution and use in source and binary forms, with or without 9: * modification, are permitted provided that the following conditions 10: * are met: 11: * 1. Redistributions of source code must retain the above copyright 12: * notice, this list of conditions and the following disclaimer. 13: * 2. Redistributions in binary form must reproduce the above copyright 14: * notice, this list of conditions and the following disclaimer in the 15: * documentation and/or other materials provided with the distribution. 16: * 3. All advertising materials mentioning features or use of this software 17: * must display the following acknowledgement: 18: * This product includes software developed by the University of 19: * California, Berkeley and its contributors. 20: * 4. Neither the name of the University nor the names of its contributors 21: * may be used to endorse or promote products derived from this software 22: * without specific prior written permission. 23: * 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34: * SUCH DAMAGE. 35: */ 36: 37: #if !defined(lint) && defined(DOSCCS) 38: static char copyright[] = 39: "@(#) Copyright (c) 1989, 1993\n\ 40: The Regents of the University of California. All rights reserved.\n"; 41: 42: static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 43: #endif 44: 45: /* 46: * main.c 47: * Facility: m4 macro processor 48: * by: oz 49: */ 50: 51: #include <sys/types.h> 52: #include <signal.h> 53: #include <errno.h> 54: #include <stdio.h> 55: #include <ctype.h> 56: #include <string.h> 57: #include "mdef.h" 58: #include "stdd.h" 59: #include "extern.h" 60: #include "pathnames.h" 61: 62: ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 63: char buf[BUFSIZE]; /* push-back buffer */ 64: char *bufbase = buf; /* the base for current ilevel */ 65: char *bbase[MAXINP]; /* the base for each ilevel */ 66: char *bp = buf; /* first available character */ 67: char *endpbb = buf+BUFSIZE; /* end of push-back buffer */ 68: stae mstack[STACKMAX+1]; /* stack of m4 machine */ 69: char strspace[STRSPMAX+1]; /* string space for evaluation */ 70: char *ep = strspace; /* first free char in strspace */ 71: char *endest= strspace+STRSPMAX;/* end of string space */ 72: int sp; /* current m4 stack pointer */ 73: int fp; /* m4 call frame pointer */ 74: FILE *infile[MAXINP]; /* input file stack (0=stdin) */ 75: FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/ 76: FILE *active; /* active output file pointer */ 77: char *m4temp; /* filename for diversions */ 78: int ilevel = 0; /* input file stack pointer */ 79: int oindex = 0; /* diversion index.. */ 80: char *null = ""; /* as it says.. just a null.. */ 81: char *m4wraps = ""; /* m4wrap string default.. */ 82: char *progname; /* name of this program */ 83: char lquote = LQUOTE; /* left quote character (`) */ 84: char rquote = RQUOTE; /* right quote character (') */ 85: char scommt = SCOMMT; /* start character for comment */ 86: char ecommt = ECOMMT; /* end character for comment */ 87: 88: struct keyblk keywrds[] = { /* m4 keywords to be installed */ 89: "include", INCLTYPE, 90: "sinclude", SINCTYPE, 91: "define", DEFITYPE, 92: "defn", DEFNTYPE, 93: "divert", DIVRTYPE, 94: "expr", EXPRTYPE, 95: "eval", EXPRTYPE, 96: "substr", SUBSTYPE, 97: "ifelse", IFELTYPE, 98: "ifdef", IFDFTYPE, 99: "len", LENGTYPE, 100: "incr", INCRTYPE, 101: "decr", DECRTYPE, 102: "dnl", DNLNTYPE, 103: "changequote", CHNQTYPE, 104: "changecom", CHNCTYPE, 105: "index", INDXTYPE, 106: #ifdef EXTENDED 107: "paste", PASTTYPE, 108: "spaste", SPASTYPE, 109: #endif 110: "popdef", POPDTYPE, 111: "pushdef", PUSDTYPE, 112: "dumpdef", DUMPTYPE, 113: "shift", SHIFTYPE, 114: "translit", TRNLTYPE, 115: "undefine", UNDFTYPE, 116: "undivert", UNDVTYPE, 117: "divnum", DIVNTYPE, 118: "maketemp", MKTMTYPE, 119: "errprint", ERRPTYPE, 120: "m4wrap", M4WRTYPE, 121: "m4exit", EXITTYPE, 122: "syscmd", SYSCTYPE, 123: "sysval", SYSVTYPE, 124: 125: #ifdef unix 126: "unix", MACRTYPE, 127: #else 128: #ifdef vms 129: "vms", MACRTYPE, 130: #endif 131: #endif 132: }; 133: 134: #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 135: 136: extern int optind; 137: extern char *optarg; 138: 139: void macro(); 140: void initkwds(); 141: extern int getopt(); 142: 143: int 144: main(argc,argv) 145: int argc; 146: char *argv[]; 147: { 148: register int c; 149: register int n; 150: char *p; 151: register FILE *ifp; 152: 153: progname = basename(argv[0]); 154: 155: if (signal(SIGINT, SIG_IGN) != SIG_IGN) 156: signal(SIGINT, onintr); 157: 158: initkwds(); 159: 160: while ((c = getopt(argc, argv, "tD:U:o:")) != EOF) 161: switch(c) { 162: 163: case 'D': /* define something..*/ 164: for (p = optarg; *p; p++) 165: if (*p == '=') 166: break; 167: if (*p) 168: *p++ = EOS; 169: dodefine(optarg, p); 170: break; 171: case 'U': /* undefine... */ 172: remhash(optarg, TOP); 173: break; 174: case 'o': /* specific output */ 175: case '?': 176: usage(); 177: } 178: 179: argc -= optind; 180: argv += optind; 181: 182: active = stdout; /* default active output */ 183: /* filename for diversions */ 184: m4temp = mktemp(xstrdup(_PATH_DIVNAME)); 185: 186: bbase[0] = bufbase; 187: if (!argc) { 188: sp = -1; /* stack pointer initialized */ 189: fp = 0; /* frame pointer initialized */ 190: infile[0] = stdin; /* default input (naturally) */ 191: macro(); 192: } else 193: for (; argc--; ++argv) { 194: p = *argv; 195: if (p[0] == '-' && p[1] == '\0') 196: ifp = stdin; 197: else if ((ifp = fopen(p, "r")) == NULL) 198: oops("%s: %s", p, strerror(errno)); 199: sp = -1; 200: fp = 0; 201: infile[0] = ifp; 202: macro(); 203: if (ifp != stdin) 204: (void)fclose(ifp); 205: } 206: 207: if (*m4wraps) { /* anything for rundown ?? */ 208: ilevel = 0; /* in case m4wrap includes.. */ 209: bufbase = bp = buf; /* use the entire buffer */ 210: putback(EOF); /* eof is a must !! */ 211: pbstr(m4wraps); /* user-defined wrapup act */ 212: macro(); /* last will and testament */ 213: } 214: 215: if (active != stdout) 216: active = stdout; /* reset output just in case */ 217: for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */ 218: if (outfile[n] != NULL) 219: getdiv(n); 220: /* remove bitbucket if used */ 221: if (outfile[0] != NULL) { 222: (void) fclose(outfile[0]); 223: m4temp[UNIQUE] = '0'; 224: #ifdef vms 225: (void) remove(m4temp); 226: #else 227: (void) unlink(m4temp); 228: #endif 229: } 230: 231: return 0; 232: } 233: 234: ndptr inspect(); 235: 236: /* 237: * macro - the work horse.. 238: */ 239: void 240: macro() { 241: char token[MAXTOK]; 242: register char *s; 243: register int t, l; 244: register ndptr p; 245: register int nlpar; 246: 247: cycle { 248: if ((t = gpbc()) == '_' || isalpha(t)) { 249: putback(t); 250: if ((p = inspect(s = token)) == nil) { 251: if (sp < 0) 252: while (*s) 253: putc(*s++, active); 254: else 255: while (*s) 256: chrsave(*s++); 257: } 258: else { 259: /* 260: * real thing.. First build a call frame: 261: */ 262: pushf(fp); /* previous call frm */ 263: pushf(p->type); /* type of the call */ 264: pushf(0); /* parenthesis level */ 265: fp = sp; /* new frame pointer */ 266: /* 267: * now push the string arguments: 268: */ 269: pushs(p->defn); /* defn string */ 270: pushs(p->name); /* macro name */ 271: pushs(ep); /* start next..*/ 272: 273: putback(l = gpbc()); 274: if (l != LPAREN) { /* add bracks */ 275: putback(RPAREN); 276: putback(LPAREN); 277: } 278: } 279: } 280: else if (t == EOF) { 281: if (sp > -1) 282: oops("unexpected end of input", ""); 283: if (ilevel <= 0) 284: break; /* all done thanks.. */ 285: --ilevel; 286: (void) fclose(infile[ilevel+1]); 287: bufbase = bbase[ilevel]; 288: continue; 289: } 290: /* 291: * non-alpha single-char token seen.. 292: * [the order of else if .. stmts is important.] 293: */ 294: else if (t == lquote) { /* strip quotes */ 295: nlpar = 1; 296: do { 297: if ((l = gpbc()) == rquote) 298: nlpar--; 299: else if (l == lquote) 300: nlpar++; 301: else if (l == EOF) 302: oops("missing right quote", ""); 303: if (nlpar > 0) { 304: if (sp < 0) 305: putc(l, active); 306: else 307: chrsave(l); 308: } 309: } 310: while (nlpar != 0); 311: } 312: 313: else if (sp < 0) { /* not in a macro at all */ 314: if (t == scommt) { /* comment handling here */ 315: putc(t, active); 316: while ((t = gpbc()) != ecommt) 317: putc(t, active); 318: } 319: putc(t, active); /* output directly.. */ 320: } 321: 322: else switch(t) { 323: 324: case LPAREN: 325: if (PARLEV > 0) 326: chrsave(t); 327: while (isspace(l = gpbc())) 328: ; /* skip blank, tab, nl.. */ 329: putback(l); 330: PARLEV++; 331: break; 332: 333: case RPAREN: 334: if (--PARLEV > 0) 335: chrsave(t); 336: else { /* end of argument list */ 337: chrsave(EOS); 338: 339: if (sp == STACKMAX) 340: oops("internal stack overflow", ""); 341: 342: if (CALTYP == MACRTYPE) 343: expand((char **) mstack+fp+1, sp-fp); 344: else 345: eval((char **) mstack+fp+1, sp-fp, CALTYP); 346: 347: ep = PREVEP; /* flush strspace */ 348: sp = PREVSP; /* previous sp.. */ 349: fp = PREVFP; /* rewind stack...*/ 350: } 351: break; 352: 353: case COMMA: 354: if (PARLEV == 1) { 355: chrsave(EOS); /* new argument */ 356: while (isspace(l = gpbc())) 357: ; 358: putback(l); 359: pushs(ep); 360: } else 361: chrsave(t); 362: break; 363: 364: default: 365: chrsave(t); /* stack the char */ 366: break; 367: } 368: } 369: } 370: 371: /* 372: * build an input token.. 373: * consider only those starting with _ or A-Za-z. This is a 374: * combo with lookup to speed things up. 375: */ 376: ndptr 377: inspect(tp) 378: register char *tp; 379: { 380: register char c; 381: register char *name = tp; 382: register char *etp = tp+MAXTOK; 383: register ndptr p; 384: register unsigned long h = 0; 385: 386: while ((isalnum(c = gpbc()) || c == '_') && tp < etp) 387: h = (h << 5) + h + (*tp++ = c); 388: putback(c); 389: if (tp == etp) 390: oops("token too long", ""); 391: 392: *tp = EOS; 393: 394: for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr) 395: if (STREQ(name, p->name)) 396: break; 397: return p; 398: } 399: 400: /* 401: * initkwds - initialise m4 keywords as fast as possible. 402: * This very similar to install, but without certain overheads, 403: * such as calling lookup. Malloc is not used for storing the 404: * keyword strings, since we simply use the static pointers 405: * within keywrds block. 406: */ 407: void 408: initkwds() { 409: register int i; 410: register int h; 411: register ndptr p; 412: 413: for (i = 0; i < MAXKEYS; i++) { 414: h = hash(keywrds[i].knam); 415: p = (ndptr) xalloc(sizeof(struct ndblock)); 416: p->nxtptr = hashtab[h]; 417: hashtab[h] = p; 418: p->name = keywrds[i].knam; 419: p->defn = null; 420: p->type = keywrds[i].ktyp | STATIC; 421: } 422: }