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

Annotation of src/usr.bin/deroff/deroff.c, Revision 1.13

1.13    ! deraadt     1: /*     $OpenBSD: deroff.c,v 1.12 2015/10/05 06:05:42 deraadt Exp $     */
1.1       millert     2:
                      3: /*-
                      4:  * Copyright (c) 1988, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
1.5       millert    15:  * 3. Neither the name of the University nor the names of its contributors
1.1       millert    16:  *    may be used to endorse or promote products derived from this software
                     17:  *    without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  */
                     31: /*
                     32:  * Copyright (C) Caldera International Inc.  2001-2002.
                     33:  * All rights reserved.
                     34:  *
                     35:  * Redistribution and use in source and binary forms, with or without
                     36:  * modification, are permitted provided that the following conditions
                     37:  * are met:
                     38:  * 1. Redistributions of source code and documentation must retain the above
                     39:  *    copyright notice, this list of conditions and the following disclaimer.
                     40:  * 2. Redistributions in binary form must reproduce the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer in the
                     42:  *    documentation and/or other materials provided with the distribution.
                     43:  * 3. All advertising materials mentioning features or use of this software
                     44:  *    must display the following acknowledgement:
                     45:  *     This product includes software developed or owned by Caldera
                     46:  *     International, Inc.
                     47:  * 4. Neither the name of Caldera International, Inc. nor the names of other
                     48:  *    contributors may be used to endorse or promote products derived from
                     49:  *    this software without specific prior written permission.
                     50:  *
                     51:  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
                     52:  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
                     53:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     54:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     55:  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
                     56:  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     57:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     58:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     59:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     60:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
                     61:  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     62:  * POSSIBILITY OF SUCH DAMAGE.
                     63:  */
                     64:
                     65: #include <err.h>
                     66: #include <limits.h>
                     67: #include <stdio.h>
                     68: #include <stdlib.h>
                     69: #include <string.h>
                     70: #include <unistd.h>
                     71:
                     72: /*
                     73:  *     Deroff command -- strip troff, eqn, and Tbl sequences from
                     74:  *     a file.  Has two flags argument, -w, to cause output one word per line
                     75:  *     rather than in the original format.
                     76:  *     -mm (or -ms) causes the corresponding macro's to be interpreted
                     77:  *     so that just sentences are output
                     78:  *     -ml  also gets rid of lists.
                     79:  *     Deroff follows .so and .nx commands, removes contents of macro
                     80:  *     definitions, equations (both .EQ ... .EN and $...$),
                     81:  *     Tbl command sequences, and Troff backslash constructions.
                     82:  *
                     83:  *     All input is through the Cget macro;
                     84:  *     the most recently read character is in c.
                     85:  *
                     86:  *     Modified by Robert Henry to process -me and -man macros.
                     87:  */
                     88:
                     89: #define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
                     90: #define C1get ( (c=getc(infile)) == EOF ? eof() :  c)
                     91:
                     92: #ifdef DEBUG
                     93: #  define C    _C()
                     94: #  define C1   _C1()
1.4       danh       95: #else /* not DEBUG */
1.1       millert    96: #  define C    Cget
                     97: #  define C1   C1get
1.4       danh       98: #endif /* not DEBUG */
1.1       millert    99:
                    100: #define SKIP while (C != '\n')
                    101: #define SKIP_TO_COM SKIP; SKIP; pc=c; while (C != '.' || pc != '\n' || C > 'Z')pc=c
                    102:
                    103: #define        YES 1
                    104: #define        NO 0
                    105: #define        MS 0    /* -ms */
                    106: #define        MM 1    /* -mm */
                    107: #define        ME 2    /* -me */
                    108: #define        MA 3    /* -man */
                    109:
                    110: #ifdef DEBUG
                    111: char *mactab[] = { "-ms", "-mm", "-me", "-ma" };
1.4       danh      112: #endif /* DEBUG */
1.1       millert   113:
                    114: #define        ONE 1
                    115: #define        TWO 2
                    116:
                    117: #define NOCHAR -2
                    118: #define SPECIAL 0
                    119: #define APOS 1
                    120: #define PUNCT 2
                    121: #define DIGIT 3
                    122: #define LETTER 4
                    123:
                    124: #define MAXFILES 20
                    125:
                    126: int    iflag;
                    127: int    wordflag;
                    128: int    msflag;         /* processing a source written using a mac package */
                    129: int    mac;            /* which package */
                    130: int    disp;
                    131: int    parag;
                    132: int    inmacro;
                    133: int    intable;
                    134: int    keepblock;      /* keep blocks of text; normally false when msflag */
                    135:
                    136: char chars[128];  /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
                    137:
                    138: char line[LINE_MAX];
                    139: char *lp;
                    140:
                    141: int c;
                    142: int pc;
                    143: int ldelim;
                    144: int rdelim;
                    145:
                    146: char fname[PATH_MAX];
                    147: FILE *files[MAXFILES];
                    148: FILE **filesp;
                    149: FILE *infile;
                    150:
                    151: int argc;
                    152: char **argv;
                    153:
                    154: /*
                    155:  *     Macro processing
                    156:  *
                    157:  *     Macro table definitions
                    158:  */
                    159: typedef        int pacmac;             /* compressed macro name */
                    160: int    argconcat = 0;          /* concat arguments together (-me only) */
                    161:
                    162: #define        tomac(c1, c2)           ((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
                    163: #define        frommac(src, c1, c2)    (((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF))
                    164:
                    165: struct mactab{
                    166:        int     condition;
                    167:        pacmac  macname;
                    168:        int     (*func)();      /* XXX - args */
                    169: };
                    170:
                    171: struct mactab  troffmactab[];
                    172: struct mactab  ppmactab[];
                    173: struct mactab  msmactab[];
                    174: struct mactab  mmmactab[];
                    175: struct mactab  memactab[];
                    176: struct mactab  manmactab[];
                    177:
                    178: /*
                    179:  *     Macro table initialization
                    180:  */
                    181: #define        M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
                    182:
                    183: /*
                    184:  *     Flags for matching conditions other than
                    185:  *     the macro name
                    186:  */
                    187: #define        NONE            0
                    188: #define        FNEST           1               /* no nested files */
                    189: #define        NOMAC           2               /* no macro */
                    190: #define        MAC             3               /* macro */
                    191: #define        PARAG           4               /* in a paragraph */
                    192: #define        MSF             5               /* msflag is on */
                    193: #define        NBLK            6               /* set if no blocks to be kept */
                    194:
                    195: /*
                    196:  *     Return codes from macro minions, determine where to jump,
                    197:  *     how to repeat/reprocess text
                    198:  */
                    199: #define        COMX            1               /* goto comx */
                    200: #define        COM             2               /* goto com */
                    201:
                    202: int     skeqn(void);
                    203: int     eof(void);
                    204: int     _C1(void);
                    205: int     _C(void);
                    206: int     EQ(void);
                    207: int     domacro(void);
                    208: int     PS(void);
                    209: int     skip(void);
                    210: int     intbl(void);
                    211: int     outtbl(void);
                    212: int     so(void);
                    213: int     nx(void);
                    214: int     skiptocom(void);
                    215: int     PP(pacmac);
                    216: int     AU(void);
                    217: int     SH(pacmac);
                    218: int     UX(void);
                    219: int     MMHU(pacmac);
                    220: int     mesnblock(pacmac);
                    221: int     mssnblock(pacmac);
                    222: int     nf(void);
                    223: int     ce(void);
                    224: int     meip(pacmac);
                    225: int     mepp(pacmac);
                    226: int     mesh(pacmac);
                    227: int     mefont(pacmac);
                    228: int     manfont(pacmac);
                    229: int     manpp(pacmac);
                    230: int     macsort(const void *, const void *);
                    231: int     sizetab(struct mactab *);
                    232: void    getfname(void);
                    233: void    textline(char *, int);
                    234: void    work(void);
                    235: void    regline(void (*)(char *, int), int);
                    236: void    macro(void);
                    237: void    tbl(void);
                    238: void    stbl(void);
                    239: void    eqn(void);
                    240: void    backsl(void);
                    241: void    sce(void);
                    242: void    refer(int);
                    243: void    inpic(void);
                    244: void    msputmac(char *, int);
                    245: void    msputwords(int);
                    246: void    meputmac(char *, int);
                    247: void    meputwords(int);
                    248: void    noblock(char, char);
                    249: void    defcomline(pacmac);
                    250: void    comline(void);
                    251: void    buildtab(struct mactab **, int *);
                    252: FILE   *opn(char *);
                    253: struct mactab *macfill(struct mactab *, struct mactab *);
                    254: __dead void usage(void);
                    255:
                    256: int
                    257: main(int ac, char **av)
                    258: {
                    259:        int     i, ch;
                    260:        int     errflg = 0;
                    261:        int     kflag = NO;
1.12      deraadt   262:
1.13    ! deraadt   263:        if (pledge("stdio rpath", NULL) == -1)
        !           264:                err(1, "pledge");
1.1       millert   265:
                    266:        iflag = NO;
                    267:        wordflag = NO;
                    268:        msflag = NO;
                    269:        mac = ME;
                    270:        disp = NO;
                    271:        parag = NO;
                    272:        inmacro = NO;
                    273:        intable = NO;
                    274:        ldelim  = NOCHAR;
                    275:        rdelim  = NOCHAR;
                    276:        keepblock = YES;
                    277:
                    278:        while ((ch = getopt(ac, av, "ikpwm:")) != -1) {
                    279:                switch (ch) {
                    280:                case 'i':
                    281:                        iflag = YES;
                    282:                        break;
                    283:                case 'k':
                    284:                        kflag = YES;
                    285:                        break;
                    286:                case 'm':
                    287:                        msflag = YES;
                    288:                        keepblock = NO;
                    289:                        switch (optarg[0]) {
                    290:                        case 'm':
                    291:                                mac = MM;
                    292:                                break;
                    293:                        case 's':
                    294:                                mac = MS;
                    295:                                break;
                    296:                        case 'e':
                    297:                                mac = ME;
                    298:                                break;
                    299:                        case 'a':
                    300:                                mac = MA;
                    301:                                break;
                    302:                        case 'l':
                    303:                                disp = YES;
                    304:                                break;
                    305:                        default:
1.10      tedu      306:                                errflg = 1;
1.1       millert   307:                                break;
                    308:                        }
1.10      tedu      309:                        if (optarg[1] != '\0')
                    310:                                errflg = 1;
1.1       millert   311:                        break;
                    312:                case 'p':
                    313:                        parag = YES;
                    314:                        break;
                    315:                case 'w':
                    316:                        wordflag = YES;
                    317:                        kflag = YES;
                    318:                        break;
                    319:                default:
1.10      tedu      320:                        errflg = 1;
1.1       millert   321:                }
                    322:        }
                    323:        argc = ac - optind;
                    324:        argv = av + optind;
                    325:
                    326:        if (kflag)
                    327:                keepblock = YES;
                    328:        if (errflg)
                    329:                usage();
                    330:
                    331: #ifdef DEBUG
                    332:        printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
                    333:                msflag, mactab[mac], keepblock, disp);
1.4       danh      334: #endif /* DEBUG */
1.1       millert   335:        if (argc == 0) {
                    336:                infile = stdin;
                    337:        } else {
                    338:                infile = opn(argv[0]);
                    339:                --argc;
                    340:                ++argv;
                    341:        }
                    342:        files[0] = infile;
                    343:        filesp = &files[0];
                    344:
                    345:        for (i = 'a'; i <= 'z' ; ++i)
                    346:                chars[i] = LETTER;
                    347:        for (i = 'A'; i <= 'Z'; ++i)
                    348:                chars[i] = LETTER;
                    349:        for (i = '0'; i <= '9'; ++i)
                    350:                chars[i] = DIGIT;
                    351:        chars['\''] = APOS;
                    352:        chars['&'] = APOS;
                    353:        chars['.'] = PUNCT;
                    354:        chars[','] = PUNCT;
                    355:        chars[';'] = PUNCT;
                    356:        chars['?'] = PUNCT;
                    357:        chars[':'] = PUNCT;
                    358:        work();
                    359:        exit(0);
                    360: }
                    361:
                    362: int
                    363: skeqn(void)
                    364: {
                    365:
                    366:        while ((c = getc(infile)) != rdelim) {
                    367:                if (c == EOF)
                    368:                        c = eof();
                    369:                else if (c == '"') {
                    370:                        while ((c = getc(infile)) != '"') {
                    371:                                if (c == EOF ||
                    372:                                    (c == '\\' && (c = getc(infile)) == EOF))
                    373:                                        c = eof();
                    374:                        }
                    375:                }
                    376:        }
                    377:        if (msflag)
                    378:                return((c = 'x'));
                    379:        return((c = ' '));
                    380: }
                    381:
                    382: FILE *
                    383: opn(char *p)
                    384: {
                    385:        FILE *fd;
                    386:
                    387:        if ((fd = fopen(p, "r")) == NULL)
                    388:                err(1, "fopen %s", p);
                    389:
                    390:        return(fd);
                    391: }
                    392:
                    393: int
                    394: eof(void)
                    395: {
                    396:
                    397:        if (infile != stdin)
                    398:                fclose(infile);
                    399:        if (filesp > files)
                    400:                infile = *--filesp;
                    401:        else if (argc > 0) {
                    402:                infile = opn(argv[0]);
                    403:                --argc;
                    404:                ++argv;
                    405:        } else
                    406:                exit(0);
                    407:        return(C);
                    408: }
                    409:
                    410: void
                    411: getfname(void)
                    412: {
                    413:        char *p;
                    414:        struct chain {
                    415:                struct chain *nextp;
                    416:                char *datap;
                    417:        } *q;
                    418:        static struct chain *namechain= NULL;
                    419:
                    420:        while (C == ' ')
                    421:                ;       /* nothing */
                    422:
                    423:        for (p = fname ; p - fname < sizeof(fname) && (*p = c) != '\n' &&
                    424:            c != ' ' && c != '\t' && c != '\\'; ++p)
                    425:                C;
                    426:        *p = '\0';
                    427:        while (c != '\n')
                    428:                C;
                    429:
                    430:        /* see if this name has already been used */
                    431:        for (q = namechain ; q; q = q->nextp)
                    432:                if (strcmp(fname, q->datap) == 0) {
                    433:                        fname[0] = '\0';
                    434:                        return;
                    435:                }
                    436:
1.11      tedu      437:        q = malloc(sizeof(struct chain));
1.1       millert   438:        if (q == NULL)
1.6       tom       439:                err(1, NULL);
1.1       millert   440:        q->nextp = namechain;
                    441:        q->datap = strdup(fname);
                    442:        if (q->datap == NULL)
1.6       tom       443:                err(1, NULL);
1.1       millert   444:        namechain = q;
                    445: }
                    446:
                    447: /*ARGSUSED*/
                    448: void
                    449: textline(char *str, int constant)
                    450: {
                    451:
                    452:        if (wordflag) {
                    453:                msputwords(0);
                    454:                return;
                    455:        }
                    456:        puts(str);
                    457: }
                    458:
                    459: void
                    460: work(void)
                    461: {
                    462:
                    463:        for (;;) {
                    464:                C;
                    465: #ifdef FULLDEBUG
                    466:                printf("Starting work with `%c'\n", c);
1.4       danh      467: #endif /* FULLDEBUG */
1.1       millert   468:                if (c == '.' || c == '\'')
                    469:                        comline();
                    470:                else
                    471:                        regline(textline, TWO);
                    472:        }
                    473: }
                    474:
                    475: void
                    476: regline(void (*pfunc)(char *, int), int constant)
                    477: {
                    478:
                    479:        line[0] = c;
                    480:        lp = line;
                    481:        while (lp - line < sizeof(line)) {
                    482:                if (c == '\\') {
                    483:                        *lp = ' ';
                    484:                        backsl();
                    485:                }
                    486:                if (c == '\n')
                    487:                        break;
                    488:                if (intable && c == 'T') {
                    489:                        *++lp = C;
                    490:                        if (c == '{' || c == '}') {
                    491:                                lp[-1] = ' ';
                    492:                                *lp = C;
                    493:                        }
                    494:                } else {
                    495:                        *++lp = C;
                    496:                }
                    497:        }
                    498:        *lp = '\0';
                    499:
                    500:        if (line[0] != '\0')
                    501:                (*pfunc)(line, constant);
                    502: }
                    503:
                    504: void
                    505: macro(void)
                    506: {
                    507:
                    508:        if (msflag) {
                    509:                do {
                    510:                        SKIP;
                    511:                } while (C!='.' || C!='.' || C=='.');   /* look for  .. */
                    512:                if (c != '\n')
                    513:                        SKIP;
                    514:                return;
                    515:        }
                    516:        SKIP;
                    517:        inmacro = YES;
                    518: }
                    519:
                    520: void
                    521: tbl(void)
                    522: {
                    523:
                    524:        while (C != '.')
                    525:                ;       /* nothing */
                    526:        SKIP;
                    527:        intable = YES;
                    528: }
                    529:
                    530: void
                    531: stbl(void)
                    532: {
                    533:
                    534:        while (C != '.')
                    535:                ;       /* nothing */
                    536:        SKIP_TO_COM;
                    537:        if (c != 'T' || C != 'E') {
                    538:                SKIP;
                    539:                pc = c;
                    540:                while (C != '.' || pc != '\n' || C != 'T' || C != 'E')
                    541:                        pc = c;
                    542:        }
                    543: }
                    544:
                    545: void
                    546: eqn(void)
                    547: {
                    548:        int c1, c2;
                    549:        int dflg;
                    550:        char last;
                    551:
                    552:        last=0;
                    553:        dflg = 1;
                    554:        SKIP;
                    555:
                    556:        for (;;) {
                    557:                if (C1 == '.'  || c == '\'') {
                    558:                        while (C1 == ' ' || c == '\t')
                    559:                                ;
                    560:                        if (c == 'E' && C1 == 'N') {
                    561:                                SKIP;
                    562:                                if (msflag && dflg) {
                    563:                                        putchar('x');
                    564:                                        putchar(' ');
                    565:                                        if (last) {
                    566:                                                putchar(last);
                    567:                                                putchar('\n');
                    568:                                        }
                    569:                                }
                    570:                                return;
                    571:                        }
                    572:                } else if (c == 'd') {
                    573:                        /* look for delim */
                    574:                        if (C1 == 'e' && C1 == 'l')
                    575:                                if (C1 == 'i' && C1 == 'm') {
                    576:                                        while (C1 == ' ')
                    577:                                                ;       /* nothing */
                    578:
                    579:                                        if ((c1 = c) == '\n' ||
                    580:                                            (c2 = C1) == '\n' ||
                    581:                                            (c1 == 'o' && c2 == 'f' && C1=='f')) {
                    582:                                                ldelim = NOCHAR;
                    583:                                                rdelim = NOCHAR;
                    584:                                        } else {
                    585:                                                ldelim = c1;
                    586:                                                rdelim = c2;
                    587:                                        }
                    588:                                }
                    589:                        dflg = 0;
                    590:                }
                    591:
                    592:                if (c != '\n')
                    593:                        while (C1 != '\n') {
                    594:                                if (chars[c] == PUNCT)
                    595:                                        last = c;
                    596:                                else if (c != ' ')
                    597:                                        last = 0;
                    598:                        }
                    599:        }
                    600: }
                    601:
                    602: /* skip over a complete backslash construction */
                    603: void
                    604: backsl(void)
                    605: {
                    606:        int bdelim;
                    607:
                    608: sw:
                    609:        switch (C) {
                    610:        case '"':
                    611:                SKIP;
                    612:                return;
                    613:
                    614:        case 's':
                    615:                if (C == '\\')
                    616:                        backsl();
                    617:                else {
                    618:                        while (C >= '0' && c <= '9')
                    619:                                ;       /* nothing */
                    620:                        ungetc(c, infile);
                    621:                        c = '0';
                    622:                }
                    623:                --lp;
                    624:                return;
                    625:
                    626:        case 'f':
                    627:        case 'n':
                    628:        case '*':
                    629:                if (C != '(')
                    630:                        return;
                    631:
                    632:        case '(':
                    633:                if (msflag) {
                    634:                        if (C == 'e') {
                    635:                                if (C == 'm') {
                    636:                                        *lp = '-';
                    637:                                        return;
                    638:                                }
                    639:                        }
                    640:                        else if (c != '\n')
                    641:                                C;
                    642:                        return;
                    643:                }
                    644:                if (C != '\n')
                    645:                        C;
                    646:                return;
                    647:
                    648:        case '$':
                    649:                C;      /* discard argument number */
                    650:                return;
                    651:
                    652:        case 'b':
                    653:        case 'x':
                    654:        case 'v':
                    655:        case 'h':
                    656:        case 'w':
                    657:        case 'o':
                    658:        case 'l':
                    659:        case 'L':
                    660:                if ((bdelim = C) == '\n')
                    661:                        return;
                    662:                while (C != '\n' && c != bdelim)
                    663:                        if (c == '\\')
                    664:                                backsl();
                    665:                return;
                    666:
                    667:        case '\\':
                    668:                if (inmacro)
                    669:                        goto sw;
                    670:
                    671:        default:
                    672:                return;
                    673:        }
                    674: }
                    675:
                    676: void
                    677: sce(void)
                    678: {
                    679:        char *ap;
                    680:        int n, i;
                    681:        char a[10];
                    682:
                    683:        for (ap = a; C != '\n'; ap++) {
                    684:                *ap = c;
                    685:                if (ap == &a[9]) {
                    686:                        SKIP;
                    687:                        ap = a;
                    688:                        break;
                    689:                }
                    690:        }
                    691:        if (ap != a)
                    692:                n = atoi(a);
                    693:        else
                    694:                n = 1;
                    695:        for (i = 0; i < n;) {
                    696:                if (C == '.') {
                    697:                        if (C == 'c') {
                    698:                                if (C == 'e') {
                    699:                                        while (C == ' ')
                    700:                                                ;       /* nothing */
                    701:                                        if (c == '0') {
                    702:                                                SKIP;
                    703:                                                break;
                    704:                                        } else
                    705:                                                SKIP;
                    706:                                }
                    707:                                else
                    708:                                        SKIP;
                    709:                        } else if (c == 'P' || C == 'P') {
                    710:                                if (c != '\n')
                    711:                                        SKIP;
                    712:                                break;
                    713:                        } else if (c != '\n')
                    714:                                SKIP;
                    715:                } else {
                    716:                        SKIP;
                    717:                        i++;
                    718:                }
                    719:        }
                    720: }
                    721:
                    722: void
                    723: refer(int c1)
                    724: {
                    725:        int c2;
                    726:
                    727:        if (c1 != '\n')
                    728:                SKIP;
                    729:
                    730:        for (c2 = -1;;) {
                    731:                if (C != '.')
                    732:                        SKIP;
                    733:                else {
                    734:                        if (C != ']')
                    735:                                SKIP;
                    736:                        else {
                    737:                                while (C != '\n')
                    738:                                        c2 = c;
                    739:                                if (c2 != -1 && chars[c2] == PUNCT)
                    740:                                        putchar(c2);
                    741:                                return;
                    742:                        }
                    743:                }
                    744:        }
                    745: }
                    746:
                    747: void
                    748: inpic(void)
                    749: {
                    750:        int c1;
1.9       millert   751:        char *p1, *ep;
1.1       millert   752:
                    753:        SKIP;
                    754:        p1 = line;
1.9       millert   755:        ep = line + sizeof(line) - 1;
1.1       millert   756:        c = '\n';
                    757:        for (;;) {
                    758:                c1 = c;
                    759:                if (C == '.' && c1 == '\n') {
                    760:                        if (C != 'P') {
                    761:                                if (c == '\n')
                    762:                                        continue;
                    763:                                else {
                    764:                                        SKIP;
                    765:                                        c = '\n';
                    766:                                        continue;
                    767:                                }
                    768:                        }
                    769:                        if (C != 'E') {
                    770:                                if (c == '\n')
                    771:                                        continue;
                    772:                                else {
                    773:                                        SKIP;
                    774:                                        c = '\n';
                    775:                                        continue;
                    776:                                }
                    777:                        }
                    778:                        SKIP;
                    779:                        return;
                    780:                }
                    781:                else if (c == '\"') {
                    782:                        while (C != '\"') {
                    783:                                if (c == '\\') {
                    784:                                        if (C == '\"')
                    785:                                                continue;
                    786:                                        ungetc(c, infile);
                    787:                                        backsl();
1.9       millert   788:                                } else if (p1 + 1 >= ep) {
                    789:                                        errx(1, ".PS length exceeds limit");
                    790:                                } else {
1.1       millert   791:                                        *p1++ = c;
1.9       millert   792:                                }
1.1       millert   793:                        }
                    794:                        *p1++ = ' ';
                    795:                }
                    796:                else if (c == '\n' && p1 != line) {
                    797:                        *p1 = '\0';
                    798:                        if (wordflag)
                    799:                                msputwords(NO);
                    800:                        else {
                    801:                                puts(line);
                    802:                                putchar('\n');
                    803:                        }
                    804:                        p1 = line;
                    805:                }
                    806:        }
                    807: }
                    808:
                    809: #ifdef DEBUG
                    810: int
                    811: _C1(void)
                    812: {
                    813:
                    814:        return(C1get);
                    815: }
                    816:
                    817: int
                    818: _C(void)
                    819: {
                    820:
                    821:        return(Cget);
                    822: }
1.4       danh      823: #endif /* DEBUG */
1.1       millert   824:
                    825: /*
                    826:  *     Put out a macro line, using ms and mm conventions.
                    827:  */
                    828: void
                    829: msputmac(char *s, int constant)
                    830: {
                    831:        char *t;
                    832:        int found;
                    833:        int last;
                    834:
                    835:        last = 0;
                    836:        found = 0;
                    837:        if (wordflag) {
                    838:                msputwords(YES);
                    839:                return;
                    840:        }
                    841:        while (*s) {
                    842:                while (*s == ' ' || *s == '\t')
                    843:                        putchar(*s++);
                    844:                for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t)
                    845:                        ;       /* nothing */
                    846:                if (*s == '\"')
                    847:                        s++;
                    848:                if (t > s + constant && chars[(unsigned char)s[0]] == LETTER &&
                    849:                    chars[(unsigned char)s[1]] == LETTER) {
                    850:                        while (s < t)
                    851:                                if (*s == '\"')
                    852:                                        s++;
                    853:                                else
                    854:                                        putchar(*s++);
                    855:                        last = *(t-1);
                    856:                        found++;
                    857:                } else if (found && chars[(unsigned char)s[0]] == PUNCT &&
                    858:                    s[1] == '\0') {
                    859:                        putchar(*s++);
                    860:                } else {
                    861:                        last = *(t - 1);
                    862:                        s = t;
                    863:                }
                    864:        }
                    865:        putchar('\n');
                    866:        if (msflag && chars[last] == PUNCT) {
                    867:                putchar(last);
                    868:                putchar('\n');
                    869:        }
                    870: }
                    871:
                    872: /*
                    873:  *     put out words (for the -w option) with ms and mm conventions
                    874:  */
                    875: void
                    876: msputwords(int macline)
                    877: {
                    878:        char *p, *p1;
                    879:        int i, nlet;
                    880:
                    881:        for (p1 = line;;) {
                    882:                /*
                    883:                 *      skip initial specials ampersands and apostrophes
                    884:                 */
                    885:                while (chars[(unsigned char)*p1] < DIGIT)
                    886:                        if (*p1++ == '\0')
                    887:                                return;
                    888:                nlet = 0;
                    889:                for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p)
                    890:                        if (i == LETTER)
                    891:                                ++nlet;
                    892:
                    893:                if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) {
                    894:                        /*
                    895:                         *      delete trailing ampersands and apostrophes
                    896:                         */
                    897:                        while ((i = chars[(unsigned char)p[-1]]) == PUNCT ||
                    898:                            i == APOS )
                    899:                                --p;
                    900:                        while (p1 < p)
                    901:                                putchar(*p1++);
                    902:                        putchar('\n');
                    903:                } else {
                    904:                        p1 = p;
                    905:                }
                    906:        }
                    907: }
                    908:
                    909: /*
                    910:  *     put out a macro using the me conventions
                    911:  */
                    912: #define SKIPBLANK(cp)  while (*cp == ' ' || *cp == '\t') { cp++; }
                    913: #define SKIPNONBLANK(cp) while (*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
                    914:
                    915: void
                    916: meputmac(char *cp, int constant)
                    917: {
                    918:        char    *np;
                    919:        int     found;
                    920:        int     argno;
                    921:        int     last;
                    922:        int     inquote;
                    923:
                    924:        last = 0;
                    925:        found = 0;
                    926:        if (wordflag) {
                    927:                meputwords(YES);
                    928:                return;
                    929:        }
                    930:        for (argno = 0; *cp; argno++) {
                    931:                SKIPBLANK(cp);
                    932:                inquote = (*cp == '"');
                    933:                if (inquote)
                    934:                        cp++;
                    935:                for (np = cp; *np; np++) {
                    936:                        switch (*np) {
                    937:                        case '\n':
                    938:                        case '\0':
                    939:                                break;
                    940:
                    941:                        case '\t':
                    942:                        case ' ':
                    943:                                if (inquote)
                    944:                                        continue;
                    945:                                else
                    946:                                        goto endarg;
                    947:
                    948:                        case '"':
                    949:                                if (inquote && np[1] == '"') {
1.3       millert   950:                                        memmove(np, np + 1, strlen(np));
1.1       millert   951:                                        np++;
                    952:                                        continue;
                    953:                                } else {
                    954:                                        *np = ' ';      /* bye bye " */
                    955:                                        goto endarg;
                    956:                                }
                    957:
                    958:                        default:
                    959:                                continue;
                    960:                        }
                    961:                }
                    962:                endarg: ;
                    963:                /*
                    964:                 *      cp points at the first char in the arg
                    965:                 *      np points one beyond the last char in the arg
                    966:                 */
                    967:                if ((argconcat == 0) || (argconcat != argno))
                    968:                        putchar(' ');
                    969: #ifdef FULLDEBUG
                    970:                {
                    971:                        char    *p;
                    972:                        printf("[%d,%d: ", argno, np - cp);
                    973:                        for (p = cp; p < np; p++) {
                    974:                                putchar(*p);
                    975:                        }
                    976:                        printf("]");
                    977:                }
1.4       danh      978: #endif /* FULLDEBUG */
1.1       millert   979:                /*
                    980:                 *      Determine if the argument merits being printed
                    981:                 *
                    982:                 *      constant is the cut off point below which something
                    983:                 *      is not a word.
                    984:                 */
                    985:                if (((np - cp) > constant) &&
                    986:                    (inquote || (chars[(unsigned char)cp[0]] == LETTER))) {
                    987:                        for (cp = cp; cp < np; cp++)
                    988:                                putchar(*cp);
                    989:                        last = np[-1];
                    990:                        found++;
                    991:                } else if (found && (np - cp == 1) &&
                    992:                    chars[(unsigned char)*cp] == PUNCT) {
                    993:                        putchar(*cp);
                    994:                } else {
                    995:                        last = np[-1];
                    996:                }
                    997:                cp = np;
                    998:        }
                    999:        if (msflag && chars[last] == PUNCT)
                   1000:                putchar(last);
                   1001:        putchar('\n');
                   1002: }
                   1003:
                   1004: /*
                   1005:  *     put out words (for the -w option) with ms and mm conventions
                   1006:  */
                   1007: void
                   1008: meputwords(int macline)
                   1009: {
                   1010:
                   1011:        msputwords(macline);
                   1012: }
                   1013:
                   1014: /*
                   1015:  *
                   1016:  *     Skip over a nested set of macros
                   1017:  *
                   1018:  *     Possible arguments to noblock are:
                   1019:  *
                   1020:  *     fi      end of unfilled text
                   1021:  *     PE      pic ending
                   1022:  *     DE      display ending
                   1023:  *
                   1024:  *     for ms and mm only:
                   1025:  *             KE      keep ending
                   1026:  *
                   1027:  *             NE      undocumented match to NS (for mm?)
                   1028:  *             LE      mm only: matches RL or *L (for lists)
                   1029:  *
                   1030:  *     for me:
                   1031:  *             ([lqbzcdf]
                   1032:  */
                   1033: void
                   1034: noblock(char a1, char a2)
                   1035: {
                   1036:        int c1,c2;
                   1037:        int eqnf;
                   1038:        int lct;
                   1039:
                   1040:        lct = 0;
                   1041:        eqnf = 1;
                   1042:        SKIP;
                   1043:        for (;;) {
                   1044:                while (C != '.')
                   1045:                        if (c == '\n')
                   1046:                                continue;
                   1047:                        else
                   1048:                                SKIP;
                   1049:                if ((c1 = C) == '\n')
                   1050:                        continue;
                   1051:                if ((c2 = C) == '\n')
                   1052:                        continue;
                   1053:                if (c1 == a1 && c2 == a2) {
                   1054:                        SKIP;
                   1055:                        if (lct != 0) {
                   1056:                                lct--;
                   1057:                                continue;
                   1058:                        }
                   1059:                        if (eqnf)
                   1060:                                putchar('.');
                   1061:                        putchar('\n');
                   1062:                        return;
                   1063:                } else if (a1 == 'L' && c2 == 'L') {
                   1064:                        lct++;
                   1065:                        SKIP;
                   1066:                }
                   1067:                /*
                   1068:                 *      equations (EQ) nested within a display
                   1069:                 */
                   1070:                else if (c1 == 'E' && c2 == 'Q') {
                   1071:                        if ((mac == ME && a1 == ')')
                   1072:                            || (mac != ME && a1 == 'D')) {
                   1073:                                eqn();
                   1074:                                eqnf=0;
                   1075:                        }
                   1076:                }
                   1077:                /*
                   1078:                 *      turning on filling is done by the paragraphing
                   1079:                 *      macros
                   1080:                 */
                   1081:                else if (a1 == 'f') {   /* .fi */
                   1082:                        if  ((mac == ME && (c2 == 'h' || c2 == 'p'))
                   1083:                            || (mac != ME && (c1 == 'P' || c2 == 'P'))) {
                   1084:                                SKIP;
                   1085:                                return;
                   1086:                        }
                   1087:                } else {
                   1088:                        SKIP;
                   1089:                }
                   1090:        }
                   1091: }
                   1092:
                   1093: int
                   1094: EQ(void)
                   1095: {
                   1096:
                   1097:        eqn();
                   1098:        return(0);
                   1099: }
                   1100:
                   1101: int
                   1102: domacro(void)
                   1103: {
                   1104:
                   1105:        macro();
                   1106:        return(0);
                   1107: }
                   1108:
                   1109: int
                   1110: PS(void)
                   1111: {
                   1112:
                   1113:        for (C; c == ' ' || c == '\t'; C)
                   1114:                ;       /* nothing */
                   1115:
                   1116:        if (c == '<') {         /* ".PS < file" -- don't expect a .PE */
                   1117:                SKIP;
                   1118:                return(0);
                   1119:        }
                   1120:        if (!msflag)
                   1121:                inpic();
                   1122:        else
                   1123:                noblock('P', 'E');
                   1124:        return(0);
                   1125: }
                   1126:
                   1127: int
                   1128: skip(void)
                   1129: {
                   1130:
                   1131:        SKIP;
                   1132:        return(0);
                   1133: }
                   1134:
                   1135: int
                   1136: intbl(void)
                   1137: {
                   1138:
                   1139:        if (msflag)
                   1140:                stbl();
                   1141:        else
                   1142:                tbl();
                   1143:        return(0);
                   1144: }
                   1145:
                   1146: int
                   1147: outtbl(void)
                   1148: {
                   1149:
                   1150:        intable = NO;
                   1151:        return(0);
                   1152: }
                   1153:
                   1154: int
                   1155: so(void)
                   1156: {
                   1157:
                   1158:        if (!iflag) {
                   1159:                getfname();
                   1160:                if (fname[0]) {
                   1161:                        if (++filesp - &files[0] > MAXFILES)
                   1162:                                err(1, "too many nested files (max %d)",
                   1163:                                    MAXFILES);
                   1164:                        infile = *filesp = opn(fname);
                   1165:                }
                   1166:        }
                   1167:        return(0);
                   1168: }
                   1169:
                   1170: int
                   1171: nx(void)
                   1172: {
                   1173:
                   1174:        if (!iflag) {
                   1175:                getfname();
                   1176:                if (fname[0] == '\0')
                   1177:                        exit(0);
                   1178:                if (infile != stdin)
                   1179:                        fclose(infile);
                   1180:                infile = *filesp = opn(fname);
                   1181:        }
                   1182:        return(0);
                   1183: }
                   1184:
                   1185: int
                   1186: skiptocom(void)
                   1187: {
                   1188:
                   1189:        SKIP_TO_COM;
                   1190:        return(COMX);
                   1191: }
                   1192:
                   1193: int
                   1194: PP(pacmac c12)
                   1195: {
                   1196:        int c1, c2;
                   1197:
                   1198:        frommac(c12, c1, c2);
                   1199:        printf(".%c%c", c1, c2);
                   1200:        while (C != '\n')
                   1201:                putchar(c);
                   1202:        putchar('\n');
                   1203:        return(0);
                   1204: }
                   1205:
                   1206: int
                   1207: AU(void)
                   1208: {
                   1209:
                   1210:        if (mac == MM)
                   1211:                return(0);
                   1212:        SKIP_TO_COM;
                   1213:        return(COMX);
                   1214: }
                   1215:
                   1216: int
                   1217: SH(pacmac c12)
                   1218: {
                   1219:        int c1, c2;
                   1220:
                   1221:        frommac(c12, c1, c2);
                   1222:
                   1223:        if (parag) {
                   1224:                printf(".%c%c", c1, c2);
                   1225:                while (C != '\n')
                   1226:                        putchar(c);
                   1227:                putchar(c);
                   1228:                putchar('!');
                   1229:                for (;;) {
                   1230:                        while (C != '\n')
                   1231:                                putchar(c);
                   1232:                        putchar('\n');
                   1233:                        if (C == '.')
                   1234:                                return(COM);
                   1235:                        putchar('!');
                   1236:                        putchar(c);
                   1237:                }
                   1238:                /*NOTREACHED*/
                   1239:        } else {
                   1240:                SKIP_TO_COM;
                   1241:                return(COMX);
                   1242:        }
                   1243: }
                   1244:
                   1245: int
                   1246: UX(void)
                   1247: {
                   1248:
                   1249:        if (wordflag)
                   1250:                printf("UNIX\n");
                   1251:        else
                   1252:                printf("UNIX ");
                   1253:        return(0);
                   1254: }
                   1255:
                   1256: int
                   1257: MMHU(pacmac c12)
                   1258: {
                   1259:        int c1, c2;
                   1260:
                   1261:        frommac(c12, c1, c2);
                   1262:        if (parag) {
                   1263:                printf(".%c%c", c1, c2);
                   1264:                while (C != '\n')
                   1265:                        putchar(c);
                   1266:                putchar('\n');
                   1267:        } else {
                   1268:                SKIP;
                   1269:        }
                   1270:        return(0);
                   1271: }
                   1272:
                   1273: int
                   1274: mesnblock(pacmac c12)
                   1275: {
                   1276:        int c1, c2;
                   1277:
                   1278:        frommac(c12, c1, c2);
                   1279:        noblock(')', c2);
                   1280:        return(0);
                   1281: }
                   1282:
                   1283: int
                   1284: mssnblock(pacmac c12)
                   1285: {
                   1286:        int c1, c2;
                   1287:
                   1288:        frommac(c12, c1, c2);
                   1289:        noblock(c1, 'E');
                   1290:        return(0);
                   1291: }
                   1292:
                   1293: int
                   1294: nf(void)
                   1295: {
                   1296:
                   1297:        noblock('f', 'i');
                   1298:        return(0);
                   1299: }
                   1300:
                   1301: int
                   1302: ce(void)
                   1303: {
                   1304:
                   1305:        sce();
                   1306:        return(0);
                   1307: }
                   1308:
                   1309: int
                   1310: meip(pacmac c12)
                   1311: {
                   1312:
                   1313:        if (parag)
                   1314:                mepp(c12);
                   1315:        else if (wordflag)      /* save the tag */
                   1316:                regline(meputmac, ONE);
                   1317:        else
                   1318:                SKIP;
                   1319:        return(0);
                   1320: }
                   1321:
                   1322: /*
                   1323:  *     only called for -me .pp or .sh, when parag is on
                   1324:  */
                   1325: int
                   1326: mepp(pacmac c12)
                   1327: {
                   1328:
                   1329:        PP(c12);                /* eats the line */
                   1330:        return(0);
                   1331: }
                   1332:
                   1333: /*
                   1334:  *     Start of a section heading; output the section name if doing words
                   1335:  */
                   1336: int
                   1337: mesh(pacmac c12)
                   1338: {
                   1339:
                   1340:        if (parag)
                   1341:                mepp(c12);
                   1342:        else if (wordflag)
                   1343:                defcomline(c12);
                   1344:        else
                   1345:                SKIP;
                   1346:        return(0);
                   1347: }
                   1348:
                   1349: /*
                   1350:  *     process a font setting
                   1351:  */
                   1352: int
                   1353: mefont(pacmac c12)
                   1354: {
                   1355:
                   1356:        argconcat = 1;
                   1357:        defcomline(c12);
                   1358:        argconcat = 0;
                   1359:        return(0);
                   1360: }
                   1361:
                   1362: int
                   1363: manfont(pacmac c12)
                   1364: {
                   1365:
                   1366:        return(mefont(c12));
                   1367: }
                   1368:
                   1369: int
                   1370: manpp(pacmac c12)
                   1371: {
                   1372:
                   1373:        return(mepp(c12));
                   1374: }
                   1375:
                   1376: void
                   1377: defcomline(pacmac c12)
                   1378: {
                   1379:        int c1, c2;
                   1380:
                   1381:        frommac(c12, c1, c2);
                   1382:        if (msflag && mac == MM && c2 == 'L') {
                   1383:                if (disp || c1 == 'R') {
                   1384:                        noblock('L', 'E');
                   1385:                } else {
                   1386:                        SKIP;
                   1387:                        putchar('.');
                   1388:                }
                   1389:        }
                   1390:        else if (c1 == '.' && c2 == '.') {
                   1391:                if (msflag) {
                   1392:                        SKIP;
                   1393:                        return;
                   1394:                }
                   1395:                while (C == '.')
                   1396:                        /*VOID*/;
                   1397:        }
                   1398:        ++inmacro;
                   1399:        /*
                   1400:         *      Process the arguments to the macro
                   1401:         */
                   1402:        switch (mac) {
                   1403:        default:
                   1404:        case MM:
                   1405:        case MS:
                   1406:                if (c1 <= 'Z' && msflag)
                   1407:                        regline(msputmac, ONE);
                   1408:                else
                   1409:                        regline(msputmac, TWO);
                   1410:                break;
                   1411:        case ME:
                   1412:                regline(meputmac, ONE);
                   1413:                break;
                   1414:        }
                   1415:        --inmacro;
                   1416: }
                   1417:
                   1418: void
                   1419: comline(void)
                   1420: {
                   1421:        int     c1;
                   1422:        int     c2;
                   1423:        pacmac  c12;
                   1424:        int     mid;
                   1425:        int     lb, ub;
                   1426:        int     hit;
                   1427:        static  int     tabsize = 0;
                   1428:        static  struct  mactab  *mactab = (struct mactab *)0;
                   1429:        struct  mactab  *mp;
                   1430:
                   1431:        if (mactab == 0)
                   1432:                 buildtab(&mactab, &tabsize);
                   1433: com:
                   1434:        while (C == ' ' || c == '\t')
                   1435:                ;
                   1436: comx:
                   1437:        if ((c1 = c) == '\n')
                   1438:                return;
                   1439:        c2 = C;
                   1440:        if (c1 == '.' && c2 != '.')
                   1441:                inmacro = NO;
                   1442:        if (msflag && c1 == '[') {
                   1443:                refer(c2);
                   1444:                return;
                   1445:        }
                   1446:        if (parag && mac==MM && c1 == 'P' && c2 == '\n') {
                   1447:                printf(".P\n");
                   1448:                return;
                   1449:        }
                   1450:        if (c2 == '\n')
                   1451:                return;
                   1452:        /*
                   1453:         *      Single letter macro
                   1454:         */
                   1455:        if (mac == ME && (c2 == ' ' || c2 == '\t') )
                   1456:                c2 = ' ';
                   1457:        c12 = tomac(c1, c2);
                   1458:        /*
                   1459:         *      binary search through the table of macros
                   1460:         */
                   1461:        lb = 0;
                   1462:        ub = tabsize - 1;
                   1463:        while (lb <= ub) {
                   1464:                mid = (ub + lb) / 2;
                   1465:                mp = &mactab[mid];
                   1466:                if (mp->macname < c12)
                   1467:                        lb = mid + 1;
                   1468:                else if (mp->macname > c12)
                   1469:                        ub = mid - 1;
                   1470:                else {
                   1471:                        hit = 1;
                   1472: #ifdef FULLDEBUG
                   1473:                        printf("preliminary hit macro %c%c ", c1, c2);
1.4       danh     1474: #endif /* FULLDEBUG */
1.1       millert  1475:                        switch (mp->condition) {
                   1476:                        case NONE:
                   1477:                                hit = YES;
                   1478:                                break;
                   1479:                        case FNEST:
                   1480:                                hit = (filesp == files);
                   1481:                                break;
                   1482:                        case NOMAC:
                   1483:                                hit = !inmacro;
                   1484:                                break;
                   1485:                        case MAC:
                   1486:                                hit = inmacro;
                   1487:                                break;
                   1488:                        case PARAG:
                   1489:                                hit = parag;
                   1490:                                break;
                   1491:                        case NBLK:
                   1492:                                hit = !keepblock;
                   1493:                                break;
                   1494:                        default:
                   1495:                                hit = 0;
                   1496:                        }
                   1497:
                   1498:                        if (hit) {
                   1499: #ifdef FULLDEBUG
                   1500:                                printf("MATCH\n");
1.4       danh     1501: #endif /* FULLDEBUG */
1.1       millert  1502:                                switch ((*(mp->func))(c12)) {
                   1503:                                default:
                   1504:                                        return;
                   1505:                                case COMX:
                   1506:                                        goto comx;
                   1507:                                case COM:
                   1508:                                        goto com;
                   1509:                                }
                   1510:                        }
                   1511: #ifdef FULLDEBUG
                   1512:                        printf("FAIL\n");
1.4       danh     1513: #endif /* FULLDEBUG */
1.1       millert  1514:                        break;
                   1515:                }
                   1516:        }
                   1517:        defcomline(c12);
                   1518: }
                   1519:
                   1520: int
                   1521: macsort(const void *p1, const void *p2)
                   1522: {
                   1523:        struct mactab *t1 = (struct mactab *)p1;
                   1524:        struct mactab *t2 = (struct mactab *)p2;
                   1525:
                   1526:        return(t1->macname - t2->macname);
                   1527: }
                   1528:
                   1529: int
                   1530: sizetab(struct mactab *mp)
                   1531: {
                   1532:        int i;
                   1533:
                   1534:        i = 0;
                   1535:        if (mp) {
                   1536:                for (; mp->macname; mp++, i++)
                   1537:                        /*VOID*/ ;
                   1538:        }
                   1539:        return(i);
                   1540: }
                   1541:
                   1542: struct mactab *
                   1543: macfill(struct mactab *dst, struct mactab *src)
                   1544: {
                   1545:
                   1546:        if (src) {
                   1547:                while (src->macname)
                   1548:                        *dst++ = *src++;
                   1549:        }
                   1550:        return(dst);
                   1551: }
                   1552:
                   1553: __dead void
                   1554: usage(void)
                   1555: {
                   1556:        extern char *__progname;
                   1557:
1.7       jmc      1558:        fprintf(stderr, "usage: %s [-ikpw] [-m a | e | l | m | s] [file ...]\n", __progname);
1.1       millert  1559:        exit(1);
                   1560: }
                   1561:
                   1562: void
                   1563: buildtab(struct mactab **r_back, int *r_size)
                   1564: {
                   1565:        int     size;
                   1566:        struct  mactab  *p, *p1, *p2;
                   1567:        struct  mactab  *back;
                   1568:
                   1569:        size = sizetab(troffmactab) + sizetab(ppmactab);
                   1570:        p1 = p2 = NULL;
                   1571:        if (msflag) {
                   1572:                switch (mac) {
                   1573:                case ME:
                   1574:                        p1 = memactab;
                   1575:                        break;
                   1576:                case MM:
                   1577:                        p1 = msmactab;
                   1578:                        p2 = mmmactab;
                   1579:                        break;
                   1580:                case MS:
                   1581:                        p1 = msmactab;
                   1582:                        break;
                   1583:                case MA:
                   1584:                        p1 = manmactab;
                   1585:                        break;
                   1586:                default:
                   1587:                        break;
                   1588:                }
                   1589:        }
                   1590:        size += sizetab(p1);
                   1591:        size += sizetab(p2);
1.11      tedu     1592:        back = calloc(size+2, sizeof(struct mactab));
1.1       millert  1593:        if (back == NULL)
1.6       tom      1594:                err(1, NULL);
1.1       millert  1595:
                   1596:        p = macfill(back, troffmactab);
                   1597:        p = macfill(p, ppmactab);
                   1598:        p = macfill(p, p1);
                   1599:        p = macfill(p, p2);
                   1600:
                   1601:        qsort(back, size, sizeof(struct mactab), macsort);
                   1602:        *r_size = size;
                   1603:        *r_back = back;
                   1604: }
                   1605:
                   1606: /*
                   1607:  *     troff commands
                   1608:  */
                   1609: struct mactab  troffmactab[] = {
                   1610:        M(NONE,         '\\','"',       skip),  /* comment */
                   1611:        M(NOMAC,        'd','e',        domacro),       /* define */
                   1612:        M(NOMAC,        'i','g',        domacro),       /* ignore till .. */
                   1613:        M(NOMAC,        'a','m',        domacro),       /* append macro */
                   1614:        M(NBLK,         'n','f',        nf),    /* filled */
                   1615:        M(NBLK,         'c','e',        ce),    /* centered */
                   1616:
                   1617:        M(NONE,         's','o',        so),    /* source a file */
                   1618:        M(NONE,         'n','x',        nx),    /* go to next file */
                   1619:
                   1620:        M(NONE,         't','m',        skip),  /* print string on tty */
                   1621:        M(NONE,         'h','w',        skip),  /* exception hyphen words */
                   1622:        M(NONE,         0,0,            0)
                   1623: };
                   1624:
                   1625: /*
                   1626:  *     Preprocessor output
                   1627:  */
                   1628: struct mactab  ppmactab[] = {
                   1629:        M(FNEST,        'E','Q',        EQ),    /* equation starting */
                   1630:        M(FNEST,        'T','S',        intbl), /* table starting */
                   1631:        M(FNEST,        'T','C',        intbl), /* alternative table? */
                   1632:        M(FNEST,        'T','&',        intbl), /* table reformatting */
                   1633:        M(NONE,         'T','E',        outtbl),/* table ending */
                   1634:        M(NONE,         'P','S',        PS),    /* picture starting */
                   1635:        M(NONE,         0,0,            0)
                   1636: };
                   1637:
                   1638: /*
                   1639:  *     Particular to ms and mm
                   1640:  */
                   1641: struct mactab  msmactab[] = {
                   1642:        M(NONE,         'T','L',        skiptocom),     /* title follows */
                   1643:        M(NONE,         'F','S',        skiptocom),     /* start footnote */
                   1644:        M(NONE,         'O','K',        skiptocom),     /* Other kws */
                   1645:
                   1646:        M(NONE,         'N','R',        skip),  /* undocumented */
                   1647:        M(NONE,         'N','D',        skip),  /* use supplied date */
                   1648:
                   1649:        M(PARAG,        'P','P',        PP),    /* begin parag */
                   1650:        M(PARAG,        'I','P',        PP),    /* begin indent parag, tag x */
                   1651:        M(PARAG,        'L','P',        PP),    /* left blocked parag */
                   1652:
                   1653:        M(NONE,         'A','U',        AU),    /* author */
                   1654:        M(NONE,         'A','I',        AU),    /* authors institution */
                   1655:
                   1656:        M(NONE,         'S','H',        SH),    /* section heading */
                   1657:        M(NONE,         'S','N',        SH),    /* undocumented */
                   1658:        M(NONE,         'U','X',        UX),    /* unix */
                   1659:
                   1660:        M(NBLK,         'D','S',        mssnblock),     /* start display text */
                   1661:        M(NBLK,         'K','S',        mssnblock),     /* start keep */
                   1662:        M(NBLK,         'K','F',        mssnblock),     /* start float keep */
                   1663:        M(NONE,         0,0,            0)
                   1664: };
                   1665:
                   1666: struct mactab  mmmactab[] = {
                   1667:        M(NONE,         'H',' ',        MMHU),  /* -mm ? */
                   1668:        M(NONE,         'H','U',        MMHU),  /* -mm ? */
                   1669:        M(PARAG,        'P',' ',        PP),    /* paragraph for -mm */
                   1670:        M(NBLK,         'N','S',        mssnblock),     /* undocumented */
                   1671:        M(NONE,         0,0,            0)
                   1672: };
                   1673:
                   1674: struct mactab  memactab[] = {
                   1675:        M(PARAG,        'p','p',        mepp),
                   1676:        M(PARAG,        'l','p',        mepp),
                   1677:        M(PARAG,        'n','p',        mepp),
                   1678:        M(NONE,         'i','p',        meip),
                   1679:
                   1680:        M(NONE,         's','h',        mesh),
                   1681:        M(NONE,         'u','h',        mesh),
                   1682:
                   1683:        M(NBLK,         '(','l',        mesnblock),
                   1684:        M(NBLK,         '(','q',        mesnblock),
                   1685:        M(NBLK,         '(','b',        mesnblock),
                   1686:        M(NBLK,         '(','z',        mesnblock),
                   1687:        M(NBLK,         '(','c',        mesnblock),
                   1688:
                   1689:        M(NBLK,         '(','d',        mesnblock),
                   1690:        M(NBLK,         '(','f',        mesnblock),
                   1691:        M(NBLK,         '(','x',        mesnblock),
                   1692:
                   1693:        M(NONE,         'r',' ',        mefont),
                   1694:        M(NONE,         'i',' ',        mefont),
                   1695:        M(NONE,         'b',' ',        mefont),
                   1696:        M(NONE,         'u',' ',        mefont),
                   1697:        M(NONE,         'q',' ',        mefont),
                   1698:        M(NONE,         'r','b',        mefont),
                   1699:        M(NONE,         'b','i',        mefont),
                   1700:        M(NONE,         'b','x',        mefont),
                   1701:        M(NONE,         0,0,            0)
                   1702: };
                   1703:
                   1704: struct mactab  manmactab[] = {
                   1705:        M(PARAG,        'B','I',        manfont),
                   1706:        M(PARAG,        'B','R',        manfont),
                   1707:        M(PARAG,        'I','B',        manfont),
                   1708:        M(PARAG,        'I','R',        manfont),
                   1709:        M(PARAG,        'R','B',        manfont),
                   1710:        M(PARAG,        'R','I',        manfont),
                   1711:
                   1712:        M(PARAG,        'P','P',        manpp),
                   1713:        M(PARAG,        'L','P',        manpp),
                   1714:        M(PARAG,        'H','P',        manpp),
                   1715:        M(NONE,         0,0,            0)
                   1716: };