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

Defined functions

fmt defined in line 124; used 2 times
ispref defined in line 451; used 1 times
leadin defined in line 418; used 2 times
main defined in line 70; never used
oflush defined in line 366; used 9 times
pack defined in line 328; used 2 times
prefix defined in line 199; used 1 times
setout defined in line 303; used 1 times
  • in line 80
split defined in line 246; used 1 times
tabulate defined in line 379; used 1 times
value defined in line 58; never used

Defined variables

copyright defined in line 21; never used
goal_length defined in line 47; used 6 times
headnames defined in line 54; used 1 times
lineno defined in line 50; used 5 times
mark defined in line 51; used 4 times
max_length defined in line 48; used 4 times
outbuf defined in line 297; used 3 times
outp defined in line 298; used 9 times
pfx defined in line 49; used 6 times
sccsid defined in line 24; never used

Defined macros

GOAL_LENGTH defined in line 45; used 1 times
  • in line 78
MAX_LENGTH defined in line 46; used 1 times
  • in line 79
NOSTR defined in line 42; used 5 times
Last modified: 1992-10-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2767
Valid CSS Valid XHTML 1.0 Strict