Annotation of 43BSDReno/pgrm/m4/main.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1989 The Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * This code is derived from software contributed to Berkeley by
        !             6:  * Ozan Yigit.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms are permitted
        !             9:  * provided that: (1) source distributions retain this entire copyright
        !            10:  * notice and comment, and (2) distributions including binaries display
        !            11:  * the following acknowledgement:  ``This product includes software
        !            12:  * developed by the University of California, Berkeley and its contributors''
        !            13:  * in the documentation or other materials provided with the distribution
        !            14:  * and in all advertising materials mentioning features or use of this
        !            15:  * software. Neither the name of the University nor the names of its
        !            16:  * contributors may be used to endorse or promote products derived
        !            17:  * from this software without specific prior written permission.
        !            18:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            19:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            20:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            21:  */
        !            22: 
        !            23: #ifndef lint
        !            24: static char sccsid[] = "@(#)main.c     5.4 (Berkeley) 6/1/90";
        !            25: #endif /* not lint */
        !            26: 
        !            27: /*
        !            28:  * main.c
        !            29:  * Facility: m4 macro processor
        !            30:  * by: oz
        !            31:  */
        !            32: 
        !            33: #include "mdef.h"
        !            34: 
        !            35: /*
        !            36:  * m4 - macro processor
        !            37:  *
        !            38:  * PD m4 is based on the macro tool distributed with the software 
        !            39:  * tools (VOS) package, and described in the "SOFTWARE TOOLS" and 
        !            40:  * "SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include 
        !            41:  * most of the command set of SysV m4, the standard UN*X macro processor.
        !            42:  *
        !            43:  * Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro,
        !            44:  * there may be certain implementation similarities between
        !            45:  * the two. The PD m4 was produced without ANY references to m4
        !            46:  * sources.
        !            47:  *
        !            48:  * References:
        !            49:  *
        !            50:  *     Software Tools distribution: macro
        !            51:  *
        !            52:  *     Kernighan, Brian W. and P. J. Plauger, SOFTWARE
        !            53:  *     TOOLS IN PASCAL, Addison-Wesley, Mass. 1981
        !            54:  *
        !            55:  *     Kernighan, Brian W. and P. J. Plauger, SOFTWARE
        !            56:  *     TOOLS, Addison-Wesley, Mass. 1976
        !            57:  *
        !            58:  *     Kernighan, Brian W. and Dennis M. Ritchie,
        !            59:  *     THE M4 MACRO PROCESSOR, Unix Programmer's Manual,
        !            60:  *     Seventh Edition, Vol. 2, Bell Telephone Labs, 1979
        !            61:  *
        !            62:  *     System V man page for M4
        !            63:  *
        !            64:  * Modification History:
        !            65:  *
        !            66:  * Jan 28 1986 Oz      Break the whole thing into little
        !            67:  *                     pieces, for easier (?) maintenance.
        !            68:  *
        !            69:  * Dec 12 1985 Oz      Optimize the code, try to squeeze
        !            70:  *                     few microseconds out..
        !            71:  *
        !            72:  * Dec 05 1985 Oz      Add getopt interface, define (-D),
        !            73:  *                     undefine (-U) options.
        !            74:  *
        !            75:  * Oct 21 1985 Oz      Clean up various bugs, add comment handling.
        !            76:  *
        !            77:  * June 7 1985 Oz      Add some of SysV m4 stuff (m4wrap, pushdef,
        !            78:  *                     popdef, decr, shift etc.).
        !            79:  *
        !            80:  * June 5 1985 Oz      Initial cut.
        !            81:  *
        !            82:  * Implementation Notes:
        !            83:  *
        !            84:  * [1] PD m4 uses a different (and simpler) stack mechanism than the one 
        !            85:  *     described in Software Tools and Software Tools in Pascal books. 
        !            86:  *     The triple stack nonsense is replaced with a single stack containing 
        !            87:  *     the call frames and the arguments. Each frame is back-linked to a 
        !            88:  *     previous stack frame, which enables us to rewind the stack after 
        !            89:  *     each nested call is completed. Each argument is a character pointer 
        !            90:  *     to the beginning of the argument string within the string space.
        !            91:  *     The only exceptions to this are (*) arg 0 and arg 1, which are
        !            92:  *     the macro definition and macro name strings, stored dynamically
        !            93:  *     for the hash table.
        !            94:  *
        !            95:  *         .                                      .
        !            96:  *     |   .   |  <-- sp                       |  .  |
        !            97:  *     +-------+                               +-----+
        !            98:  *     | arg 3 ------------------------------->| str |
        !            99:  *     +-------+                               |  .  |
        !           100:  *     | arg 2 --------------+                    .
        !           101:  *     +-------+             |
        !           102:  *         *                 |                 |     |
        !           103:  *     +-------+             |                 +-----+
        !           104:  *     | plev  |  <-- fp     +---------------->| str |
        !           105:  *     +-------+                               |  .  |
        !           106:  *     | type  |                                  .
        !           107:  *     +-------+
        !           108:  *     | prcf  -----------+            plev: paren level
        !           109:  *     +-------+          |            type: call type
        !           110:  *     |   .   |          |            prcf: prev. call frame
        !           111:  *         .              |
        !           112:  *     +-------+          |
        !           113:  *     |       <----------+
        !           114:  *     +-------+
        !           115:  *
        !           116:  * [2] We have three types of null values:
        !           117:  *
        !           118:  *             nil  - nodeblock pointer type 0
        !           119:  *             null - null string ("")
        !           120:  *             NULL - Stdio-defined NULL
        !           121:  *
        !           122:  */
        !           123: 
        !           124: ndptr hashtab[HASHSIZE];       /* hash table for macros etc.  */
        !           125: char buf[BUFSIZE];             /* push-back buffer            */
        !           126: char *bp = buf;                /* first available character   */
        !           127: char *endpbb = buf+BUFSIZE;    /* end of push-back buffer     */
        !           128: stae mstack[STACKMAX+1];       /* stack of m4 machine         */
        !           129: char strspace[STRSPMAX+1];     /* string space for evaluation */
        !           130: char *ep = strspace;           /* first free char in strspace */
        !           131: char *endest= strspace+STRSPMAX;/* end of string space        */
        !           132: int sp;                        /* current m4  stack pointer   */
        !           133: int fp;                        /* m4 call frame pointer       */
        !           134: FILE *infile[MAXINP];          /* input file stack (0=stdin)  */
        !           135: FILE *outfile[MAXOUT];         /* diversion array(0=bitbucket)*/
        !           136: FILE *active;                  /* active output file pointer  */
        !           137: char *m4temp;                  /* filename for diversions     */
        !           138: int ilevel = 0;                /* input file stack pointer    */
        !           139: int oindex = 0;                /* diversion index..           */
        !           140: char *null = "";                /* as it says.. just a null..  */
        !           141: char *m4wraps = "";             /* m4wrap string default..     */
        !           142: char lquote = LQUOTE;          /* left quote character  (`)   */
        !           143: char rquote = RQUOTE;          /* right quote character (')   */
        !           144: char scommt = SCOMMT;          /* start character for comment */
        !           145: char ecommt = ECOMMT;          /* end character for comment   */
        !           146: struct keyblk keywrds[] = {    /* m4 keywords to be installed */
        !           147:        "include",      INCLTYPE,
        !           148:        "sinclude",     SINCTYPE,
        !           149:        "define",       DEFITYPE,
        !           150:        "defn",         DEFNTYPE,
        !           151:        "divert",       DIVRTYPE,
        !           152:        "expr",         EXPRTYPE,
        !           153:        "eval",         EXPRTYPE,
        !           154:        "substr",       SUBSTYPE,
        !           155:        "ifelse",       IFELTYPE,
        !           156:        "ifdef",        IFDFTYPE,
        !           157:        "len",          LENGTYPE,
        !           158:        "incr",         INCRTYPE,
        !           159:        "decr",         DECRTYPE,
        !           160:        "dnl",          DNLNTYPE,
        !           161:        "changequote",  CHNQTYPE,
        !           162:        "changecom",    CHNCTYPE,
        !           163:        "index",        INDXTYPE,
        !           164: #ifdef EXTENDED
        !           165:        "paste",        PASTTYPE,
        !           166:        "spaste",       SPASTYPE,
        !           167: #endif
        !           168:        "popdef",       POPDTYPE,
        !           169:        "pushdef",      PUSDTYPE,
        !           170:        "dumpdef",      DUMPTYPE,
        !           171:        "shift",        SHIFTYPE,
        !           172:        "translit",     TRNLTYPE,
        !           173:        "undefine",     UNDFTYPE,
        !           174:        "undivert",     UNDVTYPE,
        !           175:        "divnum",       DIVNTYPE,
        !           176:        "maketemp",     MKTMTYPE,
        !           177:        "errprint",     ERRPTYPE,
        !           178:        "m4wrap",       M4WRTYPE,
        !           179:        "m4exit",       EXITTYPE,
        !           180:        "syscmd",       SYSCTYPE,
        !           181:        "sysval",       SYSVTYPE,
        !           182:        "unix",         MACRTYPE,
        !           183: };
        !           184: 
        !           185: #define MAXKEYS        (sizeof(keywrds)/sizeof(struct keyblk))
        !           186: 
        !           187: extern ndptr lookup();
        !           188: extern ndptr addent();
        !           189: extern int onintr();
        !           190: 
        !           191: extern char *malloc();
        !           192: extern char *mktemp();
        !           193: 
        !           194: extern int optind;
        !           195: extern char *optarg;
        !           196: 
        !           197: main(argc,argv)
        !           198: char *argv[];
        !           199: {
        !           200:        register int c;
        !           201:        register int n;
        !           202:        char *p;
        !           203: 
        !           204:        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
        !           205:                signal(SIGINT, onintr);
        !           206: #ifdef NONZEROPAGES
        !           207:        initm4();
        !           208: #endif
        !           209:        initkwds();
        !           210: 
        !           211:        while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
        !           212:                switch(c) {
        !           213: 
        !           214:                case 'D':               /* define something..*/
        !           215:                        for (p = optarg; *p; p++)
        !           216:                                if (*p == '=')
        !           217:                                        break;
        !           218:                        if (*p)
        !           219:                                *p++ = EOS;
        !           220:                        dodefine(optarg, p);
        !           221:                        break;
        !           222:                case 'U':               /* undefine...       */
        !           223:                        remhash(optarg, TOP);
        !           224:                        break;
        !           225:                case 'o':               /* specific output   */
        !           226:                case '?':
        !           227:                default:
        !           228:                        usage();
        !           229:                }
        !           230: 
        !           231:        infile[0] = stdin;              /* default input (naturally) */
        !           232:        active = stdout;                /* default active output     */
        !           233:        m4temp = mktemp(DIVNAM);        /* filename for diversions   */
        !           234: 
        !           235:        sp = -1;                        /* stack pointer initialized */
        !           236:        fp = 0;                         /* frame pointer initialized */
        !           237: 
        !           238:        macro();                        /* get some work done here   */
        !           239: 
        !           240:        if (*m4wraps) {                 /* anything for rundown ??   */
        !           241:                ilevel = 0;             /* in case m4wrap includes.. */
        !           242:                putback(EOF);           /* eof is a must !!          */
        !           243:                pbstr(m4wraps);         /* user-defined wrapup act   */
        !           244:                macro();                /* last will and testament   */
        !           245:        }
        !           246: 
        !           247:        if (active != stdout)
        !           248:                active = stdout;        /* reset output just in case */
        !           249:        for (n = 1; n < MAXOUT; n++)    /* default wrap-up: undivert */
        !           250:                if (outfile[n] != NULL)
        !           251:                        getdiv(n);
        !           252:                                        /* remove bitbucket if used  */
        !           253:        if (outfile[0] != NULL) {
        !           254:                (void) fclose(outfile[0]);
        !           255:                m4temp[UNIQUE] = '0';
        !           256:                (void) unlink(m4temp);
        !           257:        }
        !           258: 
        !           259:        exit(0);
        !           260: }
        !           261: 
        !           262: ndptr inspect();       /* forward ... */
        !           263: 
        !           264: /*
        !           265:  * macro - the work horse..
        !           266:  *
        !           267:  */
        !           268: macro() {
        !           269:        char token[MAXTOK];
        !           270:        register char *s;
        !           271:        register int t, l;
        !           272:        register ndptr p;
        !           273:        register int  nlpar;
        !           274: 
        !           275:        cycle {
        !           276:                if ((t = gpbc()) == '_' || isalpha(t)) {
        !           277:                        putback(t);
        !           278:                        if ((p = inspect(s = token)) == nil) {
        !           279:                                if (sp < 0)
        !           280:                                        while (*s)
        !           281:                                                putc(*s++, active);
        !           282:                                else
        !           283:                                        while (*s)
        !           284:                                                chrsave(*s++);
        !           285:                        }
        !           286:                        else {
        !           287:                /*
        !           288:                 * real thing.. First build a call frame:
        !           289:                 *
        !           290:                 */
        !           291:                                pushf(fp);      /* previous call frm */
        !           292:                                pushf(p->type); /* type of the call  */
        !           293:                                pushf(0);       /* parenthesis level */
        !           294:                                fp = sp;        /* new frame pointer */
        !           295:                /*
        !           296:                 * now push the string arguments:
        !           297:                 *
        !           298:                 */
        !           299:                                pushs(p->defn);       /* defn string */
        !           300:                                pushs(p->name);       /* macro name  */
        !           301:                                pushs(ep);            /* start next..*/
        !           302: 
        !           303:                                putback(l = gpbc());
        !           304:                                if (l != LPAREN)  {   /* add bracks  */
        !           305:                                        putback(RPAREN);
        !           306:                                        putback(LPAREN);
        !           307:                                }
        !           308:                        }
        !           309:                }
        !           310:                else if (t == EOF) {
        !           311:                        if (sp > -1)
        !           312:                                error("m4: unexpected end of input");
        !           313:                        if (--ilevel < 0)
        !           314:                                break;                  /* all done thanks.. */
        !           315:                        (void) fclose(infile[ilevel+1]);
        !           316:                        continue;
        !           317:                }
        !           318:        /*
        !           319:         * non-alpha single-char token seen..
        !           320:         * [the order of else if .. stmts is
        !           321:         * important.]
        !           322:         *
        !           323:         */
        !           324:                else if (t == lquote) {                 /* strip quotes */
        !           325:                        nlpar = 1;
        !           326:                        do {
        !           327:                                if ((l = gpbc()) == rquote)
        !           328:                                        nlpar--;
        !           329:                                else if (l == lquote)
        !           330:                                        nlpar++;
        !           331:                                else if (l == EOF)
        !           332:                                        error("m4: missing right quote");
        !           333:                                if (nlpar > 0) {
        !           334:                                        if (sp < 0)
        !           335:                                                putc(l, active);
        !           336:                                        else
        !           337:                                                chrsave(l);
        !           338:                                }
        !           339:                        }
        !           340:                        while (nlpar != 0);
        !           341:                }
        !           342: 
        !           343:                else if (sp < 0) {              /* not in a macro at all */
        !           344:                        if (t == scommt) {      /* comment handling here */
        !           345:                                putc(t, active);
        !           346:                                while ((t = gpbc()) != ecommt)
        !           347:                                        putc(t, active);
        !           348:                        }
        !           349:                        putc(t, active);        /* output directly..     */
        !           350:                }
        !           351: 
        !           352:                else switch(t) {
        !           353: 
        !           354:                case LPAREN:
        !           355:                        if (PARLEV > 0)
        !           356:                                chrsave(t);
        !           357:                        while (isspace(l = gpbc()))
        !           358:                                ;               /* skip blank, tab, nl.. */
        !           359:                        putback(l);
        !           360:                        PARLEV++;
        !           361:                        break;
        !           362: 
        !           363:                case RPAREN:
        !           364:                        if (--PARLEV > 0)
        !           365:                                chrsave(t);
        !           366:                        else {                  /* end of argument list */
        !           367:                                chrsave(EOS);
        !           368: 
        !           369:                                if (sp == STACKMAX)
        !           370:                                        error("m4: internal stack overflow");
        !           371: 
        !           372:                                if (CALTYP == MACRTYPE)
        !           373:                                        expand(mstack+fp+1, sp-fp);
        !           374:                                else
        !           375:                                        eval(mstack+fp+1, sp-fp, CALTYP);
        !           376: 
        !           377:                                ep = PREVEP;    /* flush strspace */
        !           378:                                sp = PREVSP;    /* previous sp..  */
        !           379:                                fp = PREVFP;    /* rewind stack...*/
        !           380:                        }
        !           381:                        break;
        !           382: 
        !           383:                case COMMA:
        !           384:                        if (PARLEV == 1)        {
        !           385:                                chrsave(EOS);           /* new argument   */
        !           386:                                while (isspace(l = gpbc()))
        !           387:                                        ;
        !           388:                                putback(l);
        !           389:                                pushs(ep);
        !           390:                        }
        !           391:                        break;
        !           392:                default:
        !           393:                        chrsave(t);                     /* stack the char */
        !           394:                        break;
        !           395:                }
        !           396:        }
        !           397: }
        !           398: 
        !           399: 
        !           400: /*
        !           401:  * build an input token..
        !           402:  * consider only those starting with _ or A-Za-z. This is a
        !           403:  * combo with lookup to speed things up.
        !           404:  */
        !           405: ndptr
        !           406: inspect(tp) 
        !           407: register char *tp;
        !           408: {
        !           409:        register int h = 0;
        !           410:        register char c;
        !           411:        register char *name = tp;
        !           412:        register char *etp = tp+MAXTOK;
        !           413:        register ndptr p;
        !           414: 
        !           415:        while (tp < etp && (isalnum(c = gpbc()) || c == '_'))
        !           416:                h += (*tp++ = c);
        !           417:        putback(c);
        !           418:        if (tp == etp)
        !           419:                error("m4: token too long");
        !           420:        *tp = EOS;
        !           421:        for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
        !           422:                if (strcmp(name, p->name) == 0)
        !           423:                        break;
        !           424:        return(p);
        !           425: }
        !           426: 
        !           427: #ifdef NONZEROPAGES
        !           428: /*
        !           429:  * initm4 - initialize various tables. Useful only if your system 
        !           430:  * does not know anything about demand-zero pages.
        !           431:  *
        !           432:  */
        !           433: initm4()
        !           434: {
        !           435:        register int i;
        !           436: 
        !           437:        for (i = 0; i < HASHSIZE; i++)
        !           438:                hashtab[i] = nil;
        !           439:        for (i = 0; i < MAXOUT; i++)
        !           440:                outfile[i] = NULL;
        !           441: }
        !           442: #endif
        !           443: 
        !           444: /*
        !           445:  * initkwds - initialise m4 keywords as fast as possible. 
        !           446:  * This very similar to install, but without certain overheads,
        !           447:  * such as calling lookup. Malloc is not used for storing the 
        !           448:  * keyword strings, since we simply use the static  pointers
        !           449:  * within keywrds block. We also assume that there is enough memory 
        !           450:  * to at least install the keywords (i.e. malloc won't fail).
        !           451:  *
        !           452:  */
        !           453: initkwds() {
        !           454:        register int i;
        !           455:        register int h;
        !           456:        register ndptr p;
        !           457: 
        !           458:        for (i = 0; i < MAXKEYS; i++) {
        !           459:                h = hash(keywrds[i].knam);
        !           460:                p = (ndptr) malloc(sizeof(struct ndblock));
        !           461:                p->nxtptr = hashtab[h];
        !           462:                hashtab[h] = p;
        !           463:                p->name = keywrds[i].knam;
        !           464:                p->defn = null;
        !           465:                p->type = keywrds[i].ktyp | STATIC;
        !           466:        }
        !           467: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.