Annotation of coherent/d/bin/deroff.c, revision 1.1.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.