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: }

Defined functions

initkwds defined in line 407; used 2 times
inspect defined in line 376; used 2 times
macro defined in line 239; used 4 times
main defined in line 143; never used

Defined variables

bbase defined in line 65; used 4 times
bp defined in line 66; used 6 times
buf defined in line 63; used 8 times
bufbase defined in line 64; used 6 times
copyright defined in line 38; never used
ecommt defined in line 86; used 2 times
endest defined in line 71; used 1 times
endpbb defined in line 67; used 3 times
ep defined in line 70; used 8 times
fp defined in line 73; used 18 times
hashtab defined in line 62; used 3 times
ilevel defined in line 78; used 10 times
keywrds defined in line 88; used 4 times
lquote defined in line 83; used 4 times
m4temp defined in line 77; used 14 times
m4wraps defined in line 81; used 4 times
null defined in line 80; used 3 times
oindex defined in line 79; never used
progname defined in line 82; used 3 times
rquote defined in line 84; used 2 times
sccsid defined in line 42; never used
scommt defined in line 85; used 2 times
sp defined in line 72; used 22 times
strspace defined in line 69; used 2 times

Defined macros

MAXKEYS defined in line 134; used 1 times
Last modified: 1994-04-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3995
Valid CSS Valid XHTML 1.0 Strict