source: trunk/minix/commands/elvis/fmt.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

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