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