[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.1

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