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: }

Defined functions

fmt defined in line 93; used 2 times
ispref defined in line 414; used 1 times
leadin defined in line 379; used 2 times
main defined in line 44; never used
oflush defined in line 323; used 9 times
pack defined in line 289; used 1 times
prefix defined in line 174; used 1 times
setout defined in line 276; used 1 times
  • in line 52
split defined in line 221; used 1 times
tabulate defined in line 337; used 1 times

Defined variables

copyright defined in line 8; never used
headnames defined in line 36; used 1 times
lineno defined in line 31; used 5 times
mark defined in line 32; used 4 times
outbuf defined in line 269; used 3 times
outp defined in line 270; used 9 times
pfx defined in line 30; used 6 times
sccsid defined in line 14; never used
width defined in line 33; used 5 times

Defined macros

NOSTR defined in line 28; used 5 times
Last modified: 1985-06-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1597
Valid CSS Valid XHTML 1.0 Strict