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