|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)fmt.c 2.2 (Berkeley) 8/11/83";
3: #endif
4:
5: #include <stdio.h>
6: #include <ctype.h>
7:
8: /*
9: * fmt -- format the concatenation of input files or standard input
10: * onto standard output. Designed for use with Mail ~|
11: *
12: * Syntax: fmt [ -width ] [ name ... ]
13: * Author: Kurt Shoens (UCB) 12/7/78
14: */
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.