|
|
1.1 root 1: /* fmt.c */
2:
3: /* usage: fmt [-width] [files]...
4: *
5: * Fmt rearrages text in order to make each line have roughly the
6: * same width. Indentation and word spacing is preserved.
7: *
8: * The default width is 72 characters, but you can override that via -width.
9: * If no files are given on the command line, then it reads stdin.
10: */
11:
12: #include <stdio.h>
13: #include <ctype.h>
14:
15: #ifndef TRUE
16: # define TRUE 1
17: # define FALSE 0
18: #endif
19:
20:
21:
22: int width = 72; /* the desired line width */
23: int isblank; /* is the current output line blank? */
24: int indent; /* width of the indentation */
25: char ind[512]; /* indentation text */
26: char word[1024]; /* word buffer */
27:
28: /* This function displays a usage message and quits */
29: void usage()
30: {
31: fprintf(stderr, "usage: fmt [-width] [files]...\n");
32: exit(2);
33: }
34:
35:
36:
37: /* This function outputs a single word. It takes care of spacing and the
38: * newlines within a paragraph.
39: */
40: void putword()
41: {
42: int i; /* index into word[], or whatever */
43: int ww; /* width of the word */
44: int sw; /* width of spacing after word */
45: static int psw; /* space width of previous word */
46: static int tab; /* the width of text already written */
47:
48:
49: /* separate the word and its spacing */
50: for (ww = 0; word[ww] && !isspace(word[ww]); ww++)
51: {
52: }
53: sw = strlen(word) - ww;
54: word[ww] = '\0';
55:
56: /* if no spacing (that is, the word was at the end of the line) then
57: * assume 1 space unless the last char of the word was punctuation
58: */
59: if (sw == 0)
60: {
61: sw = 1;
62: if (word[ww - 1] == '.' || word[ww - 1] == '?' || word[ww - 1] == '!')
63: sw = 2;
64: }
65:
66: /* if this is the first word on the line... */
67: if (isblank)
68: {
69: /* output the indentation first */
70: fputs(ind, stdout);
71: tab = indent;
72: }
73: else /* text has already been written to this output line */
74: {
75: /* will the word fit on this line? */
76: if (psw + ww + tab <= width)
77: {
78: /* yes - so write the previous word's spacing */
79: for (i = 0; i < psw; i++)
80: {
81: putchar(' ');
82: }
83: tab += psw;
84: }
85: else
86: {
87: /* no, so write a newline and the indentation */
88: putchar('\n');
89: fputs(ind, stdout);
90: tab = indent;
91: }
92: }
93:
94: /* write the word itself */
95: fputs(word, stdout);
96: tab += ww;
97:
98: /* remember this word's spacing */
99: psw = sw;
100:
101: /* this output line isn't blank anymore. */
102: isblank = FALSE;
103: }
104:
105:
106:
107: /* This function reformats text. */
108: void fmt(in)
109: FILE *in; /* the input stream */
110: {
111: int ch; /* character from input stream */
112: int prevch; /* the previous character in the loop */
113: int i; /* index into ind[] or word[] */
114: int inword; /* boolean: are we between indent & newline? */
115:
116:
117: /* for each character in the stream... */
118: for (indent = -1, isblank = TRUE, inword = FALSE, i = 0, prevch = '\n';
119: (ch = getc(in)) != EOF;
120: prevch = ch)
121: {
122: /* is this the end of a line? */
123: if (ch == '\n')
124: {
125: /* if end of last word in the input line */
126: if (inword)
127: {
128: /* if it really is a word */
129: if (i > 0)
130: {
131: /* output it */
132: word[i] = '\0';
133: putword();
134: }
135: }
136: else /* blank line in input */
137: {
138: /* finish the previous paragraph */
139: if (!isblank)
140: {
141: putchar('\n');
142: isblank = TRUE;
143: }
144:
145: /* output a blank line */
146: putchar('\n');
147: }
148:
149: /* continue with next input line... */
150: indent = -1;
151: i = 0;
152: inword = FALSE;
153: continue;
154: }
155:
156: /* if we're expecting indentation now... */
157: if (indent < 0)
158: {
159: /* if this is part of the indentation... */
160: if (isspace(ch))
161: {
162: /* remember it */
163: ind[i++] = ch;
164: }
165: else /* end of indentation */
166: {
167: /* mark the end of the indentation string */
168: ind[i] = '\0';
169:
170: /* calculate the width of the indentation */
171: for (i = indent = 0; ind[i]; i++)
172: {
173: if (ind[i] == '\t')
174: indent = (indent | 7) + 1;
175: else
176: indent++;
177: }
178:
179: /* reset the word index */
180: i = 0;
181:
182: /* reprocess that last character */
183: ungetc(ch, in);
184: }
185:
186: /* continue in the for-loop */
187: continue;
188: }
189:
190: /* if we get here, we're either in a word or in the space
191: * after a word.
192: */
193: inword = TRUE;
194:
195: /* is this the start of a new word? */
196: if (!isspace(ch) && isspace(prevch))
197: {
198: /* yes! output the previous word */
199: word[i] = '\0';
200: putword();
201:
202: /* reset `i' to the start of the word[] buffer */
203: i = 0;
204: }
205: word[i++] = ch;
206: }
207:
208: /* if necessary, write a final newline */
209: if (!isblank)
210: {
211: putchar('\n');
212: isblank = TRUE;
213: }
214: }
215:
216:
217:
218:
219:
220: int main(argc, argv)
221: int argc;
222: char **argv;
223: {
224: FILE *in; /* an input stream */
225: int error; /* if non-zero, then an error occurred */
226: int i;
227:
228:
229: /* handle the -width flag, if given */
230: if (argc > 1 && argv[1][0] == '-')
231: {
232: width = atoi(argv[1] + 1);
233: if (width <= 0)
234: {
235: usage();
236: }
237: argc--;
238: argv++;
239: }
240:
241: /* if no filenames given, then process stdin */
242: if (argc == 1)
243: {
244: fmt(stdin);
245: }
246: else /* one or more filenames given */
247: {
248: for (error = 0, i = 1; i < argc; i++)
249: {
250: in = fopen(argv[i], "r");
251: if (!in)
252: {
253: perror(argv[i]);
254: error = 3;
255: }
256: else
257: {
258: fmt(in);
259: fclose(in);
260: }
261: }
262: }
263:
264: /* exit, possibly indicating an error */
265: exit(error);
266: /*NOTREACHED*/
267: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.