partial indent
[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;
b811a28a 65
b811a28a 66 while (!feof (fin)) {
b51fe422
LM
67 memset (bufin, 0, sizeof (bufin));
68 memset (bufout, 0, sizeof (bufout));
222cc715
LM
69
70 /* read file */
71 nb = fread (bufin, 1, BUFFERSIZE, fin);
943fa96e 72 VERBOSE (DEBUG, fprintf (stdout, "buffer in: %d\n", nb));
222cc715 73 if (errno != 0) {
943fa96e 74 VERBOSE (ERROR, fprintf (stderr, "can't read file (%d)\n", errno));
222cc715
LM
75 exit (1);
76 }
77
78 /* process line */
79 char *ptin = bufin;
80 char *ptout = bufout;
81 while (*ptin != '\0') {
b51fe422
LM
82 VERBOSE (DEBUG, fprintf (stdout, "caracter: %c\n", *ptin));
83
84 /* manage comment */
85 if (comment > 0) {
86 if (((comment == 1) && (*ptin == '\n')) ||
87 ((comment == 2) && ((*ptin == '*') && (ptin[1] == '/')))) {
88 comment = 0;
89 }
90 special = 0;
91 *ptout++ = *ptin++;
92 continue;
93 }
94
95 /* manage indent */
222cc715 96 switch (*ptin) {
b51fe422
LM
97 case '/':
98 comment = (ptin[1] == '/') ? 1 : (ptin[1] == '*') ? 2 : 0;
99 if (begin) {
100 for (i = 0; i < nbindent * TABSIZE; i++) {
101 *ptout++ = ' ';
102 }
103 begin = 0;
104 }
105 *ptout++ = *ptin;
106 break;
107 case ' ':
222cc715 108 case '\t':
b51fe422
LM
109 if (begin == 0) {
110 *ptout++ = *ptin;
222cc715
LM
111 }
112 break;
113 case '{':
b51fe422
LM
114 *ptout++ = '\n';
115 for (i = 0; i < nbindent * TABSIZE; i++) {
116 *ptout++ = ' ';
117 }
118 *ptout++ = *ptin;
119 *ptout++ = '\n';
120 nbindent++;
121 newline = 1;
122 begin = 1;
123 break;
222cc715 124 case '}':
b51fe422
LM
125 *ptout++ = '\n';
126 nbindent--;
127 for (i = 0; i < nbindent * TABSIZE; i++) {
128 *ptout++ = ' ';
129 }
130 *ptout++ = *ptin;
131 if (ptin[1] != ';') {
132 *ptout++ = '\n';
133 }
134 newline = 1;
135 begin = 1;
136 break;
222cc715
LM
137 case ';':
138 *ptout++ = *ptin;
b51fe422
LM
139 if (parent) {
140 break;
141 }
222cc715 142 *ptout++ = '\n';
b51fe422
LM
143 newline = 1;
144 begin = 1;
145 break;
146 case '\n':
147 if (newline == 1) {
148 newline = 0;
149 } else {
150 *ptout++ = '\n';
151 }
152 begin = 1;
153 break;
154 case '\r':
222cc715
LM
155 break;
156 default:
b51fe422
LM
157 if ((*ptin == '"') && (!character) && (!special)) {
158 string ^= 1;
159 }
160 if ((*ptin == '\'') && (!string) && (!special)) {
161 character ^= 1;
162 }
163 if (begin) {
164 for (i = 0; i < nbindent * TABSIZE; i++) {
165 *ptout++ = ' ';
166 }
167 begin = 0;
168 }
222cc715 169 *ptout++ = *ptin;
b811a28a 170 }
b51fe422
LM
171 special = (*ptin == '\\');
172 parent += (*ptin == '(') ? +1 : (*ptin == ')') ? -1 : 0;
222cc715 173 ptin++;
b811a28a 174 }
222cc715
LM
175 ptout = '\0';
176
177 /* write file */
943fa96e 178 VERBOSE (DEBUG, fprintf (stdout, "buffer out: %d\n", strlen (bufout)));
222cc715 179 ptout = bufout;
b51fe422
LM
180 while ((nb = fwrite (ptout, 1, strlen (ptout), fout)) != strlen (ptout)) {
181 VERBOSE (DEBUG, fprintf (stdout, "buffer out: %d/%d\n", nb, strlen (ptout)));
222cc715 182 if (errno != 0) {
943fa96e 183 VERBOSE (ERROR, fprintf (stderr, "can't write file (%d)\n", errno));
222cc715 184 exit (1);
b811a28a 185 }
222cc715
LM
186 ptout += nb;
187 }
b811a28a
LM
188 }
189
190 /* close all */
191 fclose (fin);
192 fclose (fout);
193
194 return 0;
195}
196
197/* main function */
198
199int main (int argc, char *argv[])
200{
222cc715 201 cmode_t cmode = e_unknown;
b811a28a
LM
202 char *input = NULL;
203 char *mode = "ansi";
204 char *output = NULL;
205
206 /* get basename */
207 char *pt = progname = argv[0];
208 while (*pt) {
209 if ((*pt == '/') || (*pt == '\\')) {
210 progname = pt + 1;
211 }
212 pt++;
213 }
214
215 int c;
216 while ((c = getopt(argc, argv, "i:hm:o:v:")) != EOF) {
217 switch (c) {
218 case 'i':
219 input = optarg;
220 break;
221 case 'm':
222 mode = optarg;
223 break;
224 case 'o':
225 output = optarg;
226 break;
227 case 'v':
228 verbose = atoi (optarg);
229 break;
230 case 'h':
231 default:
232 usage (c != 'h');
233 }
234 }
235 if (argc - optind != 0) {
236 fprintf (stderr, "%s: invalid option -- %s\n", progname, argv[optind]);
237 usage (1);
238 }
239
240 /* check input */
241 FILE *fin = NULL;
242 if (input) {
243 fin = fopen (input, "rb");
244 if (!fin) {
245 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", input));
246 }
247 } else {
248 fin = stdin;
249 }
250
251 /* check output */
252 FILE *fout = NULL;
253 if (output) {
b51fe422 254 fout = fopen (output, "wb");
b811a28a
LM
255 if (!fout) {
256 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", output));
257 fclose (fin);
258 }
259 } else {
260 fout = stdout;
261 }
262
222cc715
LM
263 /* check mode */
264 if (strcmp (mode, "ansi") == 0) {
265 cmode = e_ansi;
266 } else if (strcmp (mode, "k&r") == 0) {
267 cmode = e_kr;
268 } else {
269 VERBOSE (ERROR, fprintf (stderr, "error: mode '%s' unknown\n", mode));
270 }
271
272 return indent (fin, fout, cmode);
b811a28a
LM
273}
274
275// test: indent.exe -h
276// test: indent.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
277// test: indent.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
278// test: indent.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
279
280/* vim: set ts=4 sw=4 et: */