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