Annotation of coherent/d/bin/deroff.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Strip nroff/troff control lines and eqn
        !             3:  * and tbl sequences from input.
        !             4:  * Also, optionally, produce the
        !             5:  * output as a set of words.
        !             6:  */
        !             7: 
        !             8: #include <stdio.h>
        !             9: #include <ctype.h>
        !            10: 
        !            11: #define        NLINE   500             /* Input line length */
        !            12: #define        NFNEST  15              /* Depth of .so file nesting */
        !            13: 
        !            14: FILE   *ofiles[NFNEST];
        !            15: FILE   **ofpp = &ofiles[0];
        !            16: char   **flist;                /* list of files to open */
        !            17: 
        !            18: typedef        struct  FNAME {
        !            19:        struct  FNAME   *fn_next;
        !            20:        char    fn_name[];
        !            21: }      FNAME;
        !            22: 
        !            23: FNAME  *fnames;
        !            24: 
        !            25: char   line[NLINE];
        !            26: 
        !            27: int    delim1 = EOF;           /* Start embedded eqn */
        !            28: int    delim2 = EOF;           /* End embedd eqn */
        !            29: int    skipcnt;                /* Number of lines to skip */
        !            30: int    skiptitle;              /* Skip title text (until next nroff command) */
        !            31: int    sflag;                  /* Divide into sentences */
        !            32: int    wflag;                  /* Divide output into words */
        !            33: int    xflag;                  /* Extra knowledge of macros (style/diction) */
        !            34: 
        !            35: int    ineqn;                  /* Inside embedded eqn escape */
        !            36: FILE   *dopen();
        !            37: char   *dgets();
        !            38: 
        !            39: main(argc, argv)
        !            40: int argc;
        !            41: char *argv[];
        !            42: {
        !            43:        register char *ap;
        !            44: 
        !            45:        while (argc>1 && *argv[1]=='-') {
        !            46:                for (ap = &argv[1][1]; *ap!='\0'; ap++)
        !            47:                        switch (*ap) {
        !            48:                        case 's':
        !            49:                                sflag = 1;
        !            50:                                break;
        !            51: 
        !            52:                        case 'w':
        !            53:                                wflag = 1;
        !            54:                                break;
        !            55: 
        !            56:                        case 'x':
        !            57:                                xflag = 1;
        !            58:                                break;
        !            59: 
        !            60:                        default:
        !            61:                                usage();
        !            62:                        }
        !            63:                argv++;
        !            64:                argc--;
        !            65:        }
        !            66:        if (argc < 2)
        !            67:                ofiles[0] = stdin;
        !            68:        flist = &argv[1];
        !            69:        exit (deroff());
        !            70: }
        !            71: 
        !            72: /*
        !            73:  * Read until end-of-file
        !            74:  * and process the special nroff/troff/eqn/tbl
        !            75:  * lines in the file.
        !            76:  */
        !            77: deroff()
        !            78: {
        !            79: 
        !            80:        while (dgets(line) != NULL) {
        !            81:                if (!ineqn && line[0]=='.') {
        !            82:                        nroff(line);
        !            83:                        continue;
        !            84:                }
        !            85:                output(line);
        !            86:        }
        !            87: }
        !            88: 
        !            89: /*
        !            90:  * Output for that line which isn't an nroff
        !            91:  * control line.  This has to look for embedded
        !            92:  * eqn stuff and back-slash troff/nroff escapes.
        !            93:  * The embedded escapes are all handled to some degree
        !            94:  * but such things as nested quotes (e.g. \w or \h)
        !            95:  * do not quite work.  However, these occur almost never
        !            96:  * in text so it should be sufficient.
        !            97:  */
        !            98: output(l)
        !            99: register char *l;
        !           100: {
        !           101:        register int c;
        !           102:        register int inword = 0;
        !           103:        register int hyphen;
        !           104: 
        !           105:        if (skipcnt) {
        !           106:                skipcnt--;
        !           107:                return;
        !           108:        }
        !           109:        if (skiptitle)
        !           110:                return;
        !           111:        while ((c = *l++) != '\0') {
        !           112:                if (ineqn) {
        !           113:                        if (c == delim2)
        !           114:                                ineqn = 0;
        !           115:                        continue;
        !           116:                }
        !           117:                if (c == delim1) {
        !           118:                        ineqn = 1;
        !           119:                        continue;
        !           120:                }
        !           121:                if (c == '\\') {
        !           122:                        if ((c = *l++) == '\0')
        !           123:                                break;
        !           124:                        switch (c) {
        !           125:                        case '0':               /* digit width space */
        !           126:                        case '|':               /* Narrow space */
        !           127:                        case '&':               /* Non-printing, 0-width char */
        !           128:                        case '!':               /* Transparent line indicator */
        !           129:                        case '%':               /* Optional hyphenation char */
        !           130:                        case 't':               /* Non-interpreted tab */
        !           131:                        case 'u':               /* Up 1/2 */
        !           132:                        case 'd':               /* Down 1/2 */
        !           133:                        case 'a':               /* Non-interpeted leader */
        !           134:                        case 'c':               /* Interrupt text processing */
        !           135:                        case 'p':               /* Break and spread */
        !           136:                        case 'r':               /* Rerverse vertical motion */
        !           137:                        case '{':               /* Begin conditional */
        !           138:                        case '}':               /* End conditional */
        !           139:                                c = ' ';
        !           140:                                break;
        !           141: 
        !           142:                        case 'e':               /* Current escape */
        !           143:                                c = '\\';
        !           144:                                break;
        !           145:                        case '$':               /* argument */
        !           146:                                if (*l != '\0')
        !           147:                                        l++;
        !           148:                        case '^':               /* Half narrow space */
        !           149:                                continue;
        !           150: 
        !           151:                        case '(':               /* Char named `xx' */
        !           152:                                if (*l != '\0')
        !           153:                                        l++;
        !           154:                                if (*l != '\0')
        !           155:                                        l++;
        !           156:                                c = ' ';
        !           157:                                break;
        !           158: 
        !           159:                        case 'z':               /* Zero-width character */
        !           160:                                if (*l != '\0')
        !           161:                                        c = *l++;
        !           162:                                break;
        !           163: 
        !           164:                        case 'k':               /* Mark input place in `x' */
        !           165:                        case 'n':               /* Expand reggister x */
        !           166:                        case '*':               /* Interpolate string */
        !           167:                        case 'f':               /* Change font */
        !           168:                                if (*l != '\0')
        !           169:                                        if ((c = *l++) == '(') {
        !           170:                                                if (*l != '\0')
        !           171:                                                        l++;
        !           172:                                                if (*l != '\0')
        !           173:                                                        l++;
        !           174:                                        }
        !           175:                                continue;
        !           176: 
        !           177:                        case 's':               /* Change point size */
        !           178:                                if (*l == '\0')
        !           179:                                        continue;
        !           180:                                if ((c = *l++)=='-' || c=='+') {
        !           181:                                        if (*l == '\0')
        !           182:                                                continue;
        !           183:                                        c = *l++;
        !           184:                                }
        !           185:                                while (*l!='\0' && isdigit(c))
        !           186:                                        c = *l++;
        !           187:                                break;
        !           188: 
        !           189:                        case 'x':               /* Extra line space */
        !           190:                        case 'w':               /* Width function */
        !           191:                        case 'v':               /* Local vertical motion */
        !           192:                        case 'o':               /* Overstrike function */
        !           193:                        case 'L':               /* Vertical line */
        !           194:                        case 'l':               /* Horizontal line */
        !           195:                        case 'h':               /* Local horizontal motion */
        !           196:                        case 'b':               /* Bracket-builder */
        !           197:                                if ((c = *l) != '\0')
        !           198:                                        while (*l!='\0' && *l!=c)
        !           199:                                                l++;
        !           200:                                continue;
        !           201: 
        !           202:                        case '"':               /* Beginning of comment */
        !           203:                                while (*l != '\0')
        !           204:                                        l++;
        !           205:                                continue;
        !           206:                        }
        !           207:                }
        !           208:                if (wflag) {
        !           209:                        if (c == '\n')
        !           210:                                continue;
        !           211:                        if (!inword)
        !           212:                                if (isalpha(c))
        !           213:                                        inword = 1;
        !           214:                                else
        !           215:                                        continue;
        !           216:                        if (c=='-' && !hyphen) {
        !           217:                                hyphen = 1;
        !           218:                                continue;
        !           219:                        }
        !           220:                        hyphen = 0;
        !           221:                        if (c == '\'')
        !           222:                                continue;
        !           223:                        if (!isalpha(c) && !isdigit(c)) {
        !           224:                                inword = 0;
        !           225:                                putchar('\n');
        !           226:                                continue;
        !           227:                        }
        !           228:                }
        !           229:                putchar(c);
        !           230:        }
        !           231:        if (wflag && inword && !hyphen)
        !           232:                putchar('\n');
        !           233: }
        !           234: 
        !           235: /*
        !           236:  * Process nroff control lines.
        !           237:  * Remove EQN, TBL, macro defintions.
        !           238:  * Process .so and .nx here.
        !           239:  * Other lines have the rest of the line used.
        !           240:  */
        !           241: nroff(l)
        !           242: register char *l;
        !           243: {
        !           244:        skiptitle = 0;
        !           245:        if (l[1]=='E' && l[2]=='Q')
        !           246:                eqn();
        !           247:        else if (l[1]=='T' && l[2]=='S')
        !           248:                tbl();
        !           249:        else if (l[1]=='F' && l[2]=='S')
        !           250:                footnote();
        !           251:        else if (l[1]=='c' && l[2]=='e')
        !           252:                centre(l);
        !           253:        else if (l[1]=='n' && l[2]=='f')
        !           254:                nofill();
        !           255:        else if (l[1]=='D' && l[2]=='S')
        !           256:                display();
        !           257:        else if (l[1]=='K' && (l[2]=='F' || l[2]=='S'))
        !           258:                display();
        !           259:        else if (l[1]=='T' && l[2]=='L')
        !           260:                titles();
        !           261:        else if (l[1]=='A' && (l[2]=='I' || l[2]=='U'))
        !           262:                titles();
        !           263:        else if (l[2]=='H' && (l[1]=='S' || l[1]=='N'))
        !           264:                titles();
        !           265:        else if (l[1]=='n' && l[2]=='x')
        !           266:                include(line+3, 'n');
        !           267:        else if (l[1]=='s' && l[2]=='o')
        !           268:                include(line+3, 's');
        !           269:        else if (l[1]=='d' && l[2]=='e')
        !           270:                macdef();
        !           271:        else if (l[1]=='d' && l[2]=='s')
        !           272:                return;
        !           273:        else {
        !           274:                while (*l!=' ' && *l!='\t' && *l!='\0')
        !           275:                        l++;
        !           276:                while (*l==' ' || *l=='\t')
        !           277:                        l++;
        !           278:                if (*l != '\0')
        !           279:                        output(l);
        !           280:        }
        !           281: }
        !           282: 
        !           283: /*
        !           284:  * Process included files.
        !           285:  * The first argument is the pointer to where
        !           286:  * the filename is (it may have junk before and after it)
        !           287:  * The second is 's' for .so and 'n' for .nx.
        !           288:  */
        !           289: include(fn, type)
        !           290: register char *fn;
        !           291: char type;
        !           292: {
        !           293:        register int c;
        !           294:        register char *ep;
        !           295: 
        !           296:        while (*fn==' ' || *fn=='\t')
        !           297:                fn++;
        !           298:        for (ep = fn; (c = *ep)!='\0'; ep++)
        !           299:                if (c=='\n' || c==' ' || c=='\t' || c=='\\')
        !           300:                        break;
        !           301:        *ep = '\0';
        !           302:        if (type == 's')
        !           303:                dotso(fn);
        !           304:        else
        !           305:                *ofpp = dopen(fn);
        !           306: }
        !           307: 
        !           308: /*
        !           309:  * Process eqn directives.
        !           310:  * Currently, this simply looks for
        !           311:  * .EN lines as the terminator
        !           312:  * and delim lines to set the eqn delimiters.
        !           313:  */
        !           314: eqn()
        !           315: {
        !           316:        register char *cp;
        !           317: 
        !           318:        while (dgets(line) != NULL) {
        !           319:                if (strncmp(line, ".EN", 3) == 0)
        !           320:                        break;
        !           321:                if (strncmp(line, "delim", 5) == 0) {
        !           322:                        for (cp = line+5; *cp==' ' || *cp=='\t'; cp++)
        !           323:                                ;
        !           324:                        if (*cp=='\n' || *cp=='\0')
        !           325:                                continue;
        !           326:                        if (strncmp(cp, "off", 3) == 0) {
        !           327:                                delim1 = EOF;
        !           328:                                delim2 = EOF;
        !           329:                                continue;
        !           330:                        }
        !           331:                        delim1 = *cp++;
        !           332:                        delim2 = *cp;
        !           333:                }
        !           334:        }
        !           335: }
        !           336: 
        !           337: /*
        !           338:  * Process tbl directives.  At this time,
        !           339:  * all this does is look for the terminating
        !           340:  * .TE to end tables.
        !           341:  */
        !           342: tbl()
        !           343: {
        !           344:        while (dgets(line) != NULL)
        !           345:                if (strncmp(line, ".TE", 3) == 0)
        !           346:                        break;
        !           347: }
        !           348: 
        !           349: /*
        !           350:  * In extended knowledge mode (-ms macros),
        !           351:  * remove footnotes.  This mode is for
        !           352:  * style and diction.
        !           353:  */
        !           354: footnote()
        !           355: {
        !           356:        if (!xflag)
        !           357:                return;
        !           358:        while (dgets(line) != NULL)
        !           359:                if (strncmp(line, ".FE", 3) == 0)
        !           360:                        break;
        !           361: }
        !           362: 
        !           363: /*
        !           364:  * Throw away nofilled text as with footnotes above.
        !           365:  */
        !           366: nofill()
        !           367: {
        !           368:        if (!xflag)
        !           369:                return;
        !           370:        while (dgets(line) != NULL)
        !           371:                if (strncmp(line, ".fi", 3) == 0)
        !           372:                        break;
        !           373: }
        !           374: 
        !           375: /*
        !           376:  * Skip centred lines, in extended mode,
        !           377:  * by setting a skip counter on text.
        !           378:  */
        !           379: centre(l)
        !           380: char *l;
        !           381: {
        !           382:        if ((skipcnt = atoi(l)) == 0)
        !           383:                skipcnt = 1;
        !           384: }
        !           385: 
        !           386: /*
        !           387:  * Skip displays in extended mode.
        !           388:  */
        !           389: display()
        !           390: {
        !           391:        if (!xflag)
        !           392:                return;
        !           393:        while (dgets(line) != NULL) {
        !           394:                if (strncmp(line, ".KE", 3) == 0)
        !           395:                        break;
        !           396:                if (strncmp(line, ".DE", 3) == 0)
        !           397:                        break;
        !           398:        }
        !           399: }
        !           400: 
        !           401: /*
        !           402:  * If in extended mode, skip titles and author's
        !           403:  * names. Set a flag to skip until next nroff command.
        !           404:  */
        !           405: titles()
        !           406: {
        !           407:        if (xflag)
        !           408:                skiptitle = 1;
        !           409: }
        !           410: 
        !           411: /*
        !           412:  * Remove a macro defintion.
        !           413:  */
        !           414: macdef()
        !           415: {
        !           416:        while (dgets(line) != NULL)
        !           417:                if (strcmp(line, "..\n") == 0)
        !           418:                        break;
        !           419: }
        !           420: 
        !           421: /*
        !           422:  * Get a character from the next file stream.
        !           423:  */
        !           424: dgetc()
        !           425: {
        !           426:        register int c;
        !           427: 
        !           428: again:
        !           429:        if (*ofpp==NULL || (c = getc(*ofpp))==EOF) {
        !           430:                if (*ofpp!=stdin && *ofpp!=NULL)
        !           431:                        fclose(*ofpp);
        !           432:                if (ofpp > ofiles) {
        !           433:                        ofpp--;
        !           434:                        goto again;
        !           435:                }
        !           436:                while (*flist != NULL)
        !           437:                        if ((*ofpp = dopen(*flist++)) != NULL)
        !           438:                                goto again;
        !           439:                return (EOF);
        !           440:        }
        !           441:        return (c);
        !           442: }
        !           443: 
        !           444: /*
        !           445:  * Like fgets, only always reads using `dgetc'
        !           446:  * into a buffer of `NLINE' characters.
        !           447:  */
        !           448: char *
        !           449: dgets(as)
        !           450: char *as;
        !           451: {
        !           452:        register unsigned n = NLINE;
        !           453:        register char *s;
        !           454:        register int c;
        !           455: 
        !           456:        s = as;
        !           457:        while (--n>0 && (c = dgetc())!=EOF)
        !           458:                if ((*s++ = c) == '\n')
        !           459:                        break;
        !           460:        *s = '\0';
        !           461:        return (c==EOF && s==as ? NULL : as);
        !           462: }
        !           463: 
        !           464: /*
        !           465:  * Open input files (for .so, .nx, and from 
        !           466:  * command line).  Do not open any files twice.
        !           467:  */
        !           468: FILE *
        !           469: dopen(fname)
        !           470: register char *fname;
        !           471: {
        !           472:        register FNAME *fnp;
        !           473:        register FILE *fp;
        !           474: 
        !           475:        for (fnp = fnames; fnp != NULL; fnp = fnp->fn_next)
        !           476:                if (strcmp(fnp->fn_name, fname) == 0)
        !           477:                        return (NULL);
        !           478:        if ((fp = fopen(fname, "r")) == NULL)
        !           479:                fprintf(stderr, "deroff: cannot open `%s'\n", fname);
        !           480:        else if ((fnp=(FNAME *)malloc(sizeof(FNAME)+strlen(fname)+2)) != NULL) {
        !           481:                fnp->fn_next = fnames;
        !           482:                fnames = fnp;
        !           483:                strcpy(fnp->fn_name, fname);
        !           484:        }
        !           485:        return (fp);
        !           486: }
        !           487: 
        !           488: /*
        !           489:  * Include a file as per the `.so' request
        !           490:  * line.
        !           491:  */
        !           492: dotso(fname)
        !           493: char *fname;
        !           494: {
        !           495:        if (++ofpp >= &ofiles[NFNEST]) {
        !           496:                fprintf(stderr, "deroff: .so nested too deep--%s\n", fname);
        !           497:                ofpp--;
        !           498:                return;
        !           499:        }
        !           500:        if ((*ofpp = dopen(fname)) == NULL)
        !           501:                ofpp--;
        !           502: }
        !           503: 
        !           504: usage()
        !           505: {
        !           506:        fprintf(stderr, "Usage: deroff [ -w ] [ -x ] [file ...]\n");
        !           507:        exit(1);
        !           508: }

unix.superglobalmegacorp.com

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