add missing include
[indent.git] / indent.c
1 /* depend: */
2 /* cflags: */
3 /* linker: debug.o */
4
5 #include <assert.h>
6 #include <errno.h>
7 #include <getopt.h>
8 #include <malloc.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "debug.h"
14
15 /* macros */
16
17 #define CEIL(x, y) (((x) + (y) - 1) / (y))
18 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
19 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
20
21 //#define BUFFERSIZE 4096
22 #define BUFFERSIZE 256
23 #define TABSIZE 2
24
25 /* type definition */
26
27 typedef enum {
28 e_unknown = 0,
29 e_ansi,
30 e_kr
31 } cmode_t;
32
33 /* gobal variables */
34
35 char *progname = NULL;
36
37 /* help function */
38
39 void usage (int ret)
40 {
41 FILE *fd = ret ? stderr : stdout;
42 fprintf (fd, "usage: %s [-i file] [-h] [-m k&r|ansi|c99] [-o file] [-v]\n", progname);
43 fprintf (fd, " -i : input file\n");
44 fprintf (fd, " -h : help message\n");
45 fprintf (fd, " -m : indent mode\n");
46 fprintf (fd, " -o : output file\n");
47 fprintf (fd, " -v : verbose level (%d)\n", verbose);
48
49 exit (ret);
50 }
51
52 /* indent function */
53
54 int indent (FILE *fin, FILE *fout, cmode_t cmode) {
55 char bufin[BUFFERSIZE + 1] = {0};
56 char bufout[BUFFERSIZE * TABSIZE + 1] = {0};
57 size_t i, nb;
58 size_t nbindent = 0;
59 int begin = 1;
60 int parent = 0;
61 int comment = 0;
62 int newline = 0;
63 int string = 0;
64 int character = 0;
65 int special = 0;
66 int space = 0;
67
68 while (!feof (fin)) {
69 memset (bufin, 0, sizeof (bufin));
70 memset (bufout, 0, sizeof (bufout));
71
72 /* read file */
73 nb = fread (bufin, 1, BUFFERSIZE, fin);
74 VERBOSE (DEBUG, fprintf (stdout, "buffer in: %d\n", nb));
75 if (errno != 0) {
76 VERBOSE (ERROR, fprintf (stderr, "can't read file (%d)\n", errno));
77 exit (1);
78 }
79
80 /* process line */
81 char *ptin = bufin;
82 char *ptout = bufout;
83 while (*ptin != '\0') {
84 VERBOSE (DEBUG, fprintf (stdout, "caracter: %c\n", *ptin));
85
86 /* manage comment */
87 if (comment > 0) {
88 if (((comment == 1) && (*ptin == '\n')) ||
89 ((comment == 2) && ((*ptin == '*') && (ptin[1] == '/')))) {
90 comment = 0;
91 }
92 special = 0;
93 *ptout++ = *ptin++;
94 continue;
95 }
96
97 /* manage indent */
98 switch (*ptin) {
99 case '/':
100 comment = (ptin[1] == '/') ? 1 : (ptin[1] == '*') ? 2 : 0;
101 if (begin) {
102 for (i = 0; i < nbindent * TABSIZE; i++) {
103 *ptout++ = ' ';
104 }
105 begin = 0;
106 }
107 *ptout++ = *ptin;
108 break;
109 case ' ':
110 case '\t':
111 if (begin == 0) {
112 if ((string) || (!space)) {
113 *ptout++ = *ptin;
114 }
115 }
116 break;
117 case '{':
118 *ptout++ = '\n';
119 for (i = 0; i < nbindent * TABSIZE; i++) {
120 *ptout++ = ' ';
121 }
122 *ptout++ = *ptin;
123 *ptout++ = '\n';
124 nbindent++;
125 newline = 1;
126 begin = 1;
127 break;
128 case '}':
129 *ptout++ = '\n';
130 nbindent--;
131 for (i = 0; i < nbindent * TABSIZE; i++) {
132 *ptout++ = ' ';
133 }
134 *ptout++ = *ptin;
135 if (ptin[1] != ';') {
136 *ptout++ = '\n';
137 }
138 newline = 1;
139 begin = 1;
140 break;
141 case ';':
142 *ptout++ = *ptin;
143 if (parent) {
144 break;
145 }
146 *ptout++ = '\n';
147 newline = 1;
148 begin = 1;
149 break;
150 case '\n':
151 if (newline == 1) {
152 newline = 0;
153 } else {
154 *ptout++ = '\n';
155 }
156 begin = 1;
157 break;
158 case '\r':
159 break;
160 default:
161 if ((*ptin == '"') && (!character) && (!special)) {
162 string ^= 1;
163 }
164 if ((*ptin == '\'') && (!string) && (!special)) {
165 character ^= 1;
166 }
167 if (begin) {
168 for (i = 0; i < nbindent * TABSIZE; i++) {
169 *ptout++ = ' ';
170 }
171 begin = 0;
172 }
173 *ptout++ = *ptin;
174 }
175 space = ((*ptin == ' ') || (*ptin == '\t'));
176 special = (*ptin == '\\');
177 parent += (*ptin == '(') ? +1 : (*ptin == ')') ? -1 : 0;
178 ptin++;
179 }
180 ptout = '\0';
181
182 /* write file */
183 VERBOSE (DEBUG, fprintf (stdout, "buffer out: %d\n", strlen (bufout)));
184 ptout = bufout;
185 while ((nb = fwrite (ptout, 1, strlen (ptout), fout)) != strlen (ptout)) {
186 VERBOSE (DEBUG, fprintf (stdout, "buffer out: %d/%d\n", nb, strlen (ptout)));
187 if (errno != 0) {
188 VERBOSE (ERROR, fprintf (stderr, "can't write file (%d)\n", errno));
189 exit (1);
190 }
191 ptout += nb;
192 }
193 }
194
195 /* close all */
196 fclose (fin);
197 fclose (fout);
198
199 return 0;
200 }
201
202 /* main function */
203
204 int main (int argc, char *argv[])
205 {
206 cmode_t cmode = e_unknown;
207 char *input = NULL;
208 char *mode = "ansi";
209 char *output = NULL;
210
211 /* get basename */
212 char *pt = progname = argv[0];
213 while (*pt) {
214 if ((*pt == '/') || (*pt == '\\')) {
215 progname = pt + 1;
216 }
217 pt++;
218 }
219
220 int c;
221 while ((c = getopt(argc, argv, "i:hm:o:v:")) != EOF) {
222 switch (c) {
223 case 'i':
224 input = optarg;
225 break;
226 case 'm':
227 mode = optarg;
228 break;
229 case 'o':
230 output = optarg;
231 break;
232 case 'v':
233 verbose = atoi (optarg);
234 break;
235 case 'h':
236 default:
237 usage (c != 'h');
238 }
239 }
240 if (argc - optind != 0) {
241 fprintf (stderr, "%s: invalid option -- %s\n", progname, argv[optind]);
242 usage (1);
243 }
244
245 /* check input */
246 FILE *fin = NULL;
247 if (input) {
248 fin = fopen (input, "rb");
249 if (!fin) {
250 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", input));
251 }
252 } else {
253 fin = stdin;
254 }
255
256 /* check output */
257 FILE *fout = NULL;
258 if (output) {
259 fout = fopen (output, "wb");
260 if (!fout) {
261 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", output));
262 fclose (fin);
263 }
264 } else {
265 fout = stdout;
266 }
267
268 /* check mode */
269 if (strcmp (mode, "ansi") == 0) {
270 cmode = e_ansi;
271 } else if (strcmp (mode, "k&r") == 0) {
272 cmode = e_kr;
273 } else {
274 VERBOSE (ERROR, fprintf (stderr, "error: mode '%s' unknown\n", mode));
275 }
276
277 return indent (fin, fout, cmode);
278 }
279
280 // test: indent.exe -h
281 // test: indent.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
282 // test: indent.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
283 // test: indent.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
284
285 /* vim: set ts=4 sw=4 et: */