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

Defined functions

fmt defined in line 83; used 2 times
ispref defined in line 404; used 1 times
leadin defined in line 369; used 2 times
main defined in line 32; never used
oflush defined in line 313; used 9 times
pack defined in line 279; used 1 times
prefix defined in line 164; used 1 times
setout defined in line 266; used 1 times
  • in line 41
split defined in line 211; used 1 times
tabulate defined in line 327; used 1 times

Defined variables

SccsId defined in line 14; never used
headnames defined in line 24; used 1 times
lineno defined in line 19; used 5 times
mark defined in line 20; used 4 times
outbuf defined in line 259; used 3 times
outp defined in line 260; used 9 times
pfx defined in line 18; used 6 times
width defined in line 21; used 5 times

Defined macros

NOSTR defined in line 16; used 5 times
Last modified: 1982-12-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 986
Valid CSS Valid XHTML 1.0 Strict