Sync with 5.1.0
[deliverable/titan.core.git] / repgen / logformat.l
1 /******************************************************************************
2 * Copyright (c) 2000-2014 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 ******************************************************************************/
8 %option noyywrap
9 %option nounput
10 %{
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <errno.h>
17
18 #include "../common/memory.h"
19 #include "../common/version_internal.h"
20
21 #ifdef LICENSE
22 #include "../common/license.h"
23 #endif
24
25 static const char *program_name = NULL;
26 static size_t indent_depth = 4;
27 static FILE *output_file = NULL;
28 static int separate_files = 0;
29
30 static size_t indent_level = 0;
31 static enum { OPEN_BRACE, CLOSE_BRACE, COMMA, OTHER, OTHER_WS }
32 last_token = OTHER;
33
34 static char *line_buf = NULL;
35 static size_t buf_size = 0, buf_len = 0;
36 #define MIN_BUFSIZE 1024
37
38 static void init_line_buf(void)
39 {
40 line_buf = (char *)Malloc(MIN_BUFSIZE);
41 buf_size = MIN_BUFSIZE;
42 buf_len = 0;
43 }
44
45 static void enlarge_line_buf(size_t size_incr)
46 {
47 size_t new_buf_size = buf_size;
48 while (buf_len + size_incr > new_buf_size) new_buf_size *= 2;
49 if (new_buf_size > buf_size) {
50 line_buf = (char *)Realloc(line_buf, new_buf_size);
51 buf_size = new_buf_size;
52 }
53 }
54
55 static void free_line_buf(void)
56 {
57 Free(line_buf);
58 line_buf = NULL;
59 buf_size = 0;
60 buf_len = 0;
61 }
62
63 static void append_str(size_t chunk_size, const char *chunk_ptr)
64 {
65 enlarge_line_buf(chunk_size);
66 memcpy(line_buf + buf_len, chunk_ptr, chunk_size);
67 buf_len += chunk_size;
68 }
69
70 static void append_char(char c)
71 {
72 if (buf_size <= buf_len) {
73 buf_size *= 2;
74 line_buf = (char *)Realloc(line_buf, buf_size);
75 }
76 line_buf[buf_len++] = c;
77 }
78
79 static void append_indentation(void)
80 {
81 if (indent_depth > 0) {
82 append_char('\n');
83 if (indent_level > 0) {
84 size_t nof_spaces = indent_level * indent_depth;
85 enlarge_line_buf(nof_spaces);
86 memset(line_buf + buf_len, ' ', nof_spaces);
87 buf_len += nof_spaces;
88 }
89 } else {
90 /* no indentation is made */
91 append_char(' ');
92 }
93 }
94
95 static void indent_before_other_token(void)
96 {
97 switch (last_token) {
98 case OPEN_BRACE:
99 case COMMA:
100 /* start a new line after an opening brace or comma */
101 append_indentation();
102 break;
103 case CLOSE_BRACE:
104 case OTHER_WS:
105 /* add a single space as separator between the previous token or block */
106 append_char(' ');
107 default:
108 break;
109 }
110 last_token = OTHER;
111 }
112
113 static void write_failure(void)
114 {
115 fprintf(stderr, "%s: writing to output file failed: %s\n",
116 program_name, strerror(errno));
117 exit(EXIT_FAILURE);
118 }
119
120 static void write_line_buf(void)
121 {
122 if (buf_len > 0) {
123 if (fwrite(line_buf, buf_len, 1, yyout) != 1) write_failure();
124 /* append a newline character if it is missing from the end
125 * (e.g. because of EOF) */
126 if (line_buf[buf_len - 1] != '\n')
127 if (putc('\n', yyout) == EOF) write_failure();
128 }
129 if (buf_size > MIN_BUFSIZE && buf_size > 2 * buf_len) {
130 /* reset the buffer size if a shorter one is enough */
131 Free(line_buf);
132 line_buf = (char *)Malloc(MIN_BUFSIZE);
133 buf_size = MIN_BUFSIZE;
134 }
135 buf_len = 0;
136 indent_level = 0;
137 last_token = OTHER;
138 }
139
140 static FILE *open_file(const char *path, const char *mode)
141 {
142 FILE *fp = fopen(path, mode);
143 if (fp == NULL) {
144 fprintf(stderr, "%s: cannot open file %s for %s: %s\n",
145 program_name, path, mode[0] == 'r' ? "reading" : "writing",
146 strerror(errno));
147 exit(EXIT_FAILURE);
148 }
149 return fp;
150 }
151
152 static int in_testcase = 0;
153 static size_t n_testcases = 0;
154 static char **testcases = NULL;
155
156 static void begin_testcase(const char *testcase_name)
157 {
158 if (separate_files) {
159 size_t i;
160 if (in_testcase) fclose(yyout);
161 else in_testcase = 1;
162 for (i = 0; i < n_testcases; i++) {
163 if (!strcmp(testcase_name, testcases[i])) {
164 yyout = open_file(testcase_name, "a");
165 return;
166 }
167 }
168 n_testcases++;
169 testcases = (char **)Realloc(testcases, (n_testcases + 1) *
170 sizeof(*testcases));
171 testcases[n_testcases - 1] = mcopystr(testcase_name);
172 yyout = open_file(testcase_name, "w");
173 }
174 }
175
176 static void free_testcases(void)
177 {
178 size_t i;
179 for (i = 0; i < n_testcases; i++) Free(testcases[i]);
180 Free(testcases);
181 n_testcases = 0;
182 testcases = NULL;
183 }
184
185 static void end_testcase(void)
186 {
187 if (in_testcase) {
188 fclose(yyout);
189 yyout = output_file;
190 in_testcase = 0;
191 }
192 }
193
194 %}
195
196 WHITESPACE [ \t]
197 NEWLINE \r|\n|\r\n
198
199 NUMBER 0|([1-9][0-9]*)
200
201 IDENTIFIER [a-zA-Z][a-zA-Z0-9_]*
202
203 VERDICT none|pass|inconc|fail|error
204
205 YEAR [0-9]{4}
206 MONTH Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec
207 DATE [0-2][0-9]|3[01]
208 HOUR [01][0-9]|2[0-3]
209 MIN [0-5][0-9]
210 SEC [0-5][0-9]
211 MICROSEC [0-9]{6}
212
213 TIMESTAMP1 {NUMBER}\.{MICROSEC}
214 TIMESTAMP2 {HOUR}\:{MIN}\:{SEC}\.{MICROSEC}
215 TIMESTAMP3 {YEAR}\/{MONTH}\/{DATE}" "{TIMESTAMP2}
216
217 TIMESTAMP {TIMESTAMP1}|{TIMESTAMP2}|{TIMESTAMP3}
218
219 %x SC_cstring SC_binstring SC_quadruple
220
221 %%
222 /* start parsing of a new file from the initial state */
223 BEGIN(INITIAL);
224
225 <*>^{TIMESTAMP} {
226 /* recognize the start of a new entry in all states in order to recover from
227 * unterminated strings */
228 write_line_buf();
229 append_str(yyleng, yytext);
230 BEGIN(INITIAL);
231 }
232
233 "Test case "{IDENTIFIER}" started."{NEWLINE} {
234 size_t i;
235 /* cut the newline character(s) from the end */
236 while (yytext[yyleng - 1] == '\r' || yytext[yyleng - 1] == '\n') yyleng--;
237 append_str(yyleng, yytext);
238 /* append a UNIX-style newline character */
239 append_char('\n');
240 /* find the end of testcase identifier */
241 for (i = 10; yytext[i] != ' '; i++);
242 yytext[i] = '\0';
243 begin_testcase(yytext + 10);
244 write_line_buf();
245 }
246
247 "Test case "{IDENTIFIER}" finished. Verdict: "{VERDICT}{NEWLINE} {
248 /* cut the newline character(s) from the end */
249 while (yytext[yyleng - 1] == '\r' || yytext[yyleng - 1] == '\n') yyleng--;
250 append_str(yyleng, yytext);
251 /* append a UNIX-style newline character */
252 append_char('\n');
253 write_line_buf();
254 end_testcase();
255 }
256
257 {WHITESPACE}+ {
258 if (indent_level > 0) {
259 /* only record the presence of the whitespace in indented blocks */
260 if (last_token == OTHER) last_token = OTHER_WS;
261 } else {
262 /* copy to output transparently */
263 append_str(yyleng, yytext);
264 }
265 }
266
267 {NEWLINE} {
268 if (indent_level > 0) {
269 /* only record the presence of the newline in indented blocks */
270 if (last_token == OTHER) last_token = OTHER_WS;
271 } else {
272 /* canonize the newline character to UNIX style */
273 append_char('\n');
274 }
275 }
276
277 \{ {
278 if (indent_level > 0) {
279 switch (last_token) {
280 case OPEN_BRACE:
281 case COMMA:
282 /* start a new line for the nested block */
283 append_indentation();
284 break;
285 default:
286 /* separate the brace from the previous token */
287 append_char(' ');
288 }
289 }
290 append_char('{');
291 indent_level++;
292 last_token = OPEN_BRACE;
293 }
294
295 \} {
296 if (indent_level > 0) {
297 indent_level--;
298 if (last_token == OPEN_BRACE) {
299 /* add a space to an empty block */
300 append_char(' ');
301 } else {
302 /* start a newline for the closing brace */
303 append_indentation();
304 }
305 last_token = CLOSE_BRACE;
306 }
307 append_char('}');
308 }
309
310 , {
311 append_char(',');
312 if (indent_level > 0) last_token = COMMA;
313 }
314
315 \" {
316 if (indent_level > 0) indent_before_other_token();
317 append_char('"');
318 BEGIN(SC_cstring);
319 }
320
321 \' {
322 if (indent_level > 0) indent_before_other_token();
323 append_char('\'');
324 BEGIN(SC_binstring);
325 }
326
327 "char"{WHITESPACE}*\( {
328 if (indent_level > 0) indent_before_other_token();
329 /* convert whitespaces to canonical form */
330 append_str(5, "char(");
331 BEGIN(SC_quadruple);
332 }
333
334 . {
335 if (indent_level > 0) indent_before_other_token();
336 append_char(yytext[0]);
337 }
338
339 <SC_cstring>
340 {
341 \"\" append_str(2, "\"\""); /* escaped quotation mark */
342 \" {
343 /* end of the string */
344 append_char('"');
345 BEGIN(INITIAL);
346 }
347 }
348
349 <SC_binstring>\' {
350 /* end of the string */
351 append_char('\'');
352 BEGIN(INITIAL);
353 }
354
355 <SC_cstring,SC_binstring>
356 {
357 \\{NEWLINE} append_str(2, "\\\n"); /* canonize escaped newline characters */
358 {NEWLINE} append_char('\n'); /* canonize simple newline characters */
359 \\. append_str(yyleng, yytext); /* copy escaped characters */
360 . append_char(yytext[0]); /* copy simple characters */
361 }
362
363 <SC_quadruple>
364 {
365 \) {
366 append_char(')');
367 BEGIN(INITIAL);
368 }
369 ({WHITESPACE}|{NEWLINE})+ /* ignore all whitespaces and newlines */
370 , append_str(2, ", "); /* append a space after the comma */
371 . append_char(yytext[0]); /* copy simple characters */
372 }
373
374 %%
375
376 static void usage(void)
377 {
378 fprintf(stderr,
379 "usage: %s [-i n] [-o outfile] [-s] [file.log] ...\n"
380 " or %s -v\n"
381 "\n"
382 "OPTIONS:\n"
383 " -i n: set the depth of each indentation to n "
384 "characters\n"
385 " -o outfile: write the formatted log into file outfile\n"
386 " -s: place the logs of each test case into separate "
387 "files\n"
388 " -v: print version\n",
389 program_name, program_name);
390 }
391
392 int main(int argc, char *argv[])
393 {
394 int c;
395 int iflag = 0, oflag = 0, sflag = 0, vflag = 0, errflag = 0;
396 #ifdef LICENSE
397 license_struct lstr;
398 #endif
399 program_name = argv[0];
400 output_file = stdout;
401 while ((c = getopt(argc, argv, "i:o:sv")) != -1) {
402 switch (c) {
403 case 'i': {
404 unsigned int int_arg;
405 if (iflag || vflag) errflag = 1;
406 if (sscanf(optarg, "%u", &int_arg) != 1) {
407 fprintf(stderr, "%s: invalid indentation depth: %s\n",
408 program_name, optarg);
409 return EXIT_FAILURE;
410 }
411 indent_depth = int_arg;
412 iflag = 1;
413 break; }
414 case 'o':
415 if (oflag || vflag) errflag = 1;
416 else output_file = open_file(optarg, "w");
417 oflag = 1;
418 break;
419 case 's':
420 if (sflag || vflag) errflag = 1;
421 sflag = 1;
422 break;
423 case 'v':
424 if (iflag || oflag || sflag) errflag = 1;
425 vflag = 1;
426 break;
427 default:
428 errflag = 1;
429 }
430 }
431 if (errflag) {
432 usage();
433 return EXIT_FAILURE;
434 } else if (vflag) {
435 fputs("Log Formatter for the TTCN-3 Test Executor\n"
436 "Product number: " PRODUCT_NUMBER "\n"
437 "Build date: " __DATE__ " " __TIME__ "\n"
438 "Compiled with: " C_COMPILER_VERSION "\n\n"
439 COPYRIGHT_STRING "\n\n", stderr);
440 #ifdef LICENSE
441 print_license_info();
442 #endif
443 return EXIT_SUCCESS;
444 }
445 #ifdef LICENSE
446 init_openssl();
447 load_license(&lstr);
448 if (!verify_license(&lstr)) {
449 free_license(&lstr);
450 free_openssl();
451 exit(EXIT_FAILURE);
452 }
453 if (!check_feature(&lstr, FEATURE_LOGFORMAT)) {
454 fputs("The license key does not allow the formatting of log files.\n",
455 stderr);
456 return EXIT_FAILURE;
457 }
458 free_license(&lstr);
459 free_openssl();
460 #endif
461 separate_files = sflag;
462 yyout = output_file;
463 init_line_buf();
464 if (optind >= argc) {
465 yyin = stdin;
466 yylex();
467 write_line_buf();
468 end_testcase();
469 } else {
470 for ( ; optind < argc; optind++) {
471 yyin = open_file(argv[optind], "r");
472 yylex();
473 fclose(yyin);
474 write_line_buf();
475 end_testcase();
476 }
477 }
478 free_line_buf();
479 if (oflag) fclose(output_file);
480 free_testcases();
481 check_mem_leak(program_name);
482 return EXIT_SUCCESS;
483 }
This page took 0.042868 seconds and 5 git commands to generate.