[BACK]Return to main.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / m4

Annotation of src/usr.bin/m4/main.c, Revision 1.1.1.1

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