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