|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.