Annotation of 41BSD/cmd/ucbmail/fmt.c, revision 1.1.1.1

1.1       root        1: #
                      2: 
                      3: #include <stdio.h>
                      4: #include <ctype.h>
                      5: 
                      6: /*
                      7:  * fmt -- format the concatenation of input files or standard input
                      8:  * onto standard output.  Designed for use with Mail ~|
                      9:  *
                     10:  * Syntax: fmt [ name ... ]
                     11:  * Author: Kurt Shoens (UCB) 12/7/78
                     12:  */
                     13: 
                     14: #define        LENGTH  72              /* Max line length in output */
                     15: #define        NOSTR   ((char *) 0)    /* Null string pointer for lint */
                     16: 
                     17: int    pfx;                    /* Current leading blank count */
                     18: int    lineno;                 /* Current input line */
                     19: int    mark;                   /* Last place we saw a head line */
                     20: 
                     21: char   *calloc();              /* for lint . . . */
                     22: char   *headnames[] = {"To", "Subject", "Cc", 0};
                     23: 
                     24: /*
                     25:  * Drive the whole formatter by managing input files.  Also,
                     26:  * cause initialization of the output stuff and flush it out
                     27:  * at the end.
                     28:  */
                     29: 
                     30: main(argc, argv)
                     31:        char **argv;
                     32: {
                     33:        register FILE *fi;
                     34:        register int errs = 0;
                     35: 
                     36:        setout();
                     37:        lineno = 1;
                     38:        mark = -10;
                     39:        setbuf(stdout, calloc(1, BUFSIZ));
                     40:        if (argc < 2) {
                     41:                setbuf(stdin, calloc(1, BUFSIZ));
                     42:                fmt(stdin);
                     43:                oflush();
                     44:                exit(0);
                     45:        }
                     46:        while (--argc) {
                     47:                if ((fi = fopen(*++argv, "r")) == NULL) {
                     48:                        perror(*argv);
                     49:                        errs++;
                     50:                        continue;
                     51:                }
                     52:                fmt(fi);
                     53:                fclose(fi);
                     54:        }
                     55:        oflush();
                     56:        exit(errs);
                     57: }
                     58: 
                     59: /*
                     60:  * Read up characters from the passed input file, forming lines,
                     61:  * doing ^H processing, expanding tabs, stripping trailing blanks,
                     62:  * and sending each line down for analysis.
                     63:  */
                     64: 
                     65: fmt(fi)
                     66:        FILE *fi;
                     67: {
                     68:        char linebuf[BUFSIZ], canonb[BUFSIZ];
                     69:        register char *cp, *cp2;
                     70:        register int c, col;
                     71: 
                     72:        c = getc(fi);
                     73:        while (c != EOF) {
                     74:                
                     75:                /*
                     76:                 * Collect a line, doing ^H processing.
                     77:                 * Leave tabs for now.
                     78:                 */
                     79: 
                     80:                cp = linebuf;
                     81:                while (c != '\n' && c != EOF && cp-linebuf < BUFSIZ-1) {
                     82:                        if (c == '\b') {
                     83:                                if (cp > linebuf)
                     84:                                        cp--;
                     85:                                c = getc(fi);
                     86:                                continue;
                     87:                        }
                     88:                        if ((c < ' ' || c >= 0177) && c != '\t') {
                     89:                                c = getc(fi);
                     90:                                continue;
                     91:                        }
                     92:                        *cp++ = c;
                     93:                        c = getc(fi);
                     94:                }
                     95:                *cp = '\0';
                     96: 
                     97:                /*
                     98:                 * Toss anything remaining on the input line.
                     99:                 */
                    100: 
                    101:                while (c != '\n' && c != EOF)
                    102:                        c = getc(fi);
                    103:                
                    104:                /*
                    105:                 * Expand tabs on the way to canonb.
                    106:                 */
                    107: 
                    108:                col = 0;
                    109:                cp = linebuf;
                    110:                cp2 = canonb;
                    111:                while (c = *cp++) {
                    112:                        if (c != '\t') {
                    113:                                col++;
                    114:                                if (cp2-canonb < BUFSIZ-1)
                    115:                                        *cp2++ = c;
                    116:                                continue;
                    117:                        }
                    118:                        do {
                    119:                                if (cp2-canonb < BUFSIZ-1)
                    120:                                        *cp2++ = ' ';
                    121:                                col++;
                    122:                        } while ((col & 07) != 0);
                    123:                }
                    124: 
                    125:                /*
                    126:                 * Swipe trailing blanks from the line.
                    127:                 */
                    128: 
                    129:                for (cp2--; cp2 >= canonb && *cp2 == ' '; cp2--)
                    130:                        ;
                    131:                *++cp2 = '\0';
                    132:                prefix(canonb);
                    133:                if (c != EOF)
                    134:                        c = getc(fi);
                    135:        }
                    136: }
                    137: 
                    138: /*
                    139:  * Take a line devoid of tabs and other garbage and determine its
                    140:  * blank prefix.  If the indent changes, call for a linebreak.
                    141:  * If the input line is blank, echo the blank line on the output.
                    142:  * Finally, if the line minus the prefix is a mail header, try to keep
                    143:  * it on a line by itself.
                    144:  */
                    145: 
                    146: prefix(line)
                    147:        char line[];
                    148: {
                    149:        register char *cp, **hp;
                    150:        register int np, h;
                    151: 
                    152:        if (strlen(line) == 0) {
                    153:                oflush();
                    154:                putchar('\n');
                    155:                return;
                    156:        }
                    157:        for (cp = line; *cp == ' '; cp++)
                    158:                ;
                    159:        np = cp - line;
                    160: 
                    161:        /*
                    162:         * The following horrible expression attempts to avoid linebreaks
                    163:         * when the indent changes due to a paragraph.
                    164:         */
                    165: 
                    166:        if (np != pfx && (np > pfx || abs(pfx-np) > 8))
                    167:                oflush();
                    168:        if (h = ishead(cp))
                    169:                oflush(), mark = lineno;
                    170:        if (lineno - mark < 3 && lineno - mark > 0)
                    171:                for (hp = &headnames[0]; *hp != (char *) 0; hp++)
                    172:                        if (ispref(*hp, cp)) {
                    173:                                h = 1;
                    174:                                oflush();
                    175:                                break;
                    176:                        }
                    177:        if (!h && (h = (*cp == '.')))
                    178:                oflush();
                    179:        pfx = np;
                    180:        split(cp);
                    181:        if (h)
                    182:                oflush();
                    183:        lineno++;
                    184: }
                    185: 
                    186: /*
                    187:  * Split up the passed line into output "words" which are
                    188:  * maximal strings of non-blanks with the blank separation
                    189:  * attached at the end.  Pass these words along to the output
                    190:  * line packer.
                    191:  */
                    192: 
                    193: split(line)
                    194:        char line[];
                    195: {
                    196:        register char *cp, *cp2;
                    197:        char word[BUFSIZ];
                    198: 
                    199:        cp = line;
                    200:        while (*cp) {
                    201:                cp2 = word;
                    202: 
                    203:                /*
                    204:                 * Collect a 'word,' allowing it to contain escaped
                    205:                 * white space.
                    206:                 */
                    207: 
                    208:                while (*cp && *cp != ' ') {
                    209:                        if (*cp == '\\' && isspace(cp[1]))
                    210:                                *cp2++ = *cp++;
                    211:                        *cp2++ = *cp++;
                    212:                }
                    213: 
                    214:                /*
                    215:                 * Guarantee a space at end of line.
                    216:                 * Two spaces after end of sentence punctuation.
                    217:                 */
                    218: 
                    219:                if (*cp == '\0') {
                    220:                        *cp2++ = ' ';
                    221:                        if (any(cp[-1], ".:!"))
                    222:                                *cp2++ = ' ';
                    223:                }
                    224:                while (*cp == ' ')
                    225:                        *cp2++ = *cp++;
                    226:                *cp2 = '\0';
                    227:                pack(word);
                    228:        }
                    229: }
                    230: 
                    231: /*
                    232:  * Output section.
                    233:  * Build up line images from the words passed in.  Prefix
                    234:  * each line with correct number of blanks.  The buffer "outbuf"
                    235:  * contains the current partial line image, including prefixed blanks.
                    236:  * "outp" points to the next available space therein.  When outp is NOSTR,
                    237:  * there ain't nothing in there yet.  At the bottom of this whole mess,
                    238:  * leading tabs are reinserted.
                    239:  */
                    240: 
                    241: char   outbuf[BUFSIZ];                 /* Sandbagged output line image */
                    242: char   *outp;                          /* Pointer in above */
                    243: 
                    244: /*
                    245:  * Initialize the output section.
                    246:  */
                    247: 
                    248: setout()
                    249: {
                    250:        outp = NOSTR;
                    251: }
                    252: 
                    253: /*
                    254:  * Pack a word onto the output line.  If this is the beginning of
                    255:  * the line, push on the appropriately-sized string of blanks first.
                    256:  * If the word won't fit on the current line, flush and begin a new
                    257:  * line.  If the word is too long to fit all by itself on a line,
                    258:  * just give it its own and hope for the best.
                    259:  */
                    260: 
                    261: pack(word)
                    262:        char word[];
                    263: {
                    264:        register char *cp;
                    265:        register int s, t;
                    266: 
                    267:        if (outp == NOSTR)
                    268:                leadin();
                    269:        t = strlen(word);
                    270:        s = outp-outbuf;
                    271:        if (t+s <= LENGTH) {
                    272:                
                    273:                /*
                    274:                 * In like flint!
                    275:                 */
                    276: 
                    277:                for (cp = word; *cp; *outp++ = *cp++)
                    278:                        ;
                    279:                return;
                    280:        }
                    281:        if (s > pfx) {
                    282:                oflush();
                    283:                leadin();
                    284:        }
                    285:        for (cp = word; *cp; *outp++ = *cp++)
                    286:                ;
                    287: }
                    288: 
                    289: /*
                    290:  * If there is anything on the current output line, send it on
                    291:  * its way.  Set outp to NOSTR to indicate the absence of the current
                    292:  * line prefix.
                    293:  */
                    294: 
                    295: oflush()
                    296: {
                    297:        if (outp == NOSTR)
                    298:                return;
                    299:        *outp = '\0';
                    300:        tabulate(outbuf);
                    301:        outp = NOSTR;
                    302: }
                    303: 
                    304: /*
                    305:  * Take the passed line buffer, insert leading tabs where possible, and
                    306:  * output on standard output (finally).
                    307:  */
                    308: 
                    309: tabulate(line)
                    310:        char line[];
                    311: {
                    312:        register char *cp, *cp2;
                    313:        register int b, t;
                    314: 
                    315:        /*
                    316:         * Toss trailing blanks in the output line.
                    317:         */
                    318: 
                    319:        cp = line + strlen(line) - 1;
                    320:        while (cp >= line && *cp == ' ')
                    321:                cp--;
                    322:        *++cp = '\0';
                    323:        
                    324:        /*
                    325:         * Count the leading blank space and tabulate.
                    326:         */
                    327: 
                    328:        for (cp = line; *cp == ' '; cp++)
                    329:                ;
                    330:        b = cp-line;
                    331:        t = b >> 3;
                    332:        b &= 07;
                    333:        if (t > 0)
                    334:                do
                    335:                        putc('\t', stdout);
                    336:                while (--t);
                    337:        if (b > 0)
                    338:                do
                    339:                        putc(' ', stdout);
                    340:                while (--b);
                    341:        while (*cp)
                    342:                putc(*cp++, stdout);
                    343:        putc('\n', stdout);
                    344: }
                    345: 
                    346: /*
                    347:  * Initialize the output line with the appropriate number of
                    348:  * leading blanks.
                    349:  */
                    350: 
                    351: leadin()
                    352: {
                    353:        register int b;
                    354:        register char *cp;
                    355: 
                    356:        for (b = 0, cp = outbuf; b < pfx; b++)
                    357:                *cp++ = ' ';
                    358:        outp = cp;
                    359: }
                    360: 
                    361: /*
                    362:  * Save a string in dynamic space.
                    363:  * This little goodie is needed for
                    364:  * a headline detector in head.c
                    365:  */
                    366: 
                    367: char *
                    368: savestr(str)
                    369:        char str[];
                    370: {
                    371:        register char *top;
                    372: 
                    373:        top = calloc(strlen(str) + 1, 1);
                    374:        if (top == NOSTR) {
                    375:                fprintf(stderr, "fmt:  Ran out of memory\n");
                    376:                exit(1);
                    377:        }
                    378:        copy(str, top);
                    379:        return(top);
                    380: }
                    381: 
                    382: /*
                    383:  * Is s1 a prefix of s2??
                    384:  */
                    385: 
                    386: ispref(s1, s2)
                    387:        register char *s1, *s2;
                    388: {
                    389: 
                    390:        while (*s1++ == *s2)
                    391:                ;
                    392:        return(*s1 == '\0');
                    393: }

unix.superglobalmegacorp.com

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