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