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