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