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