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