Merge pull request #72 from eadrkir/master
[deliverable/titan.core.git] / repgen / logformat.l
CommitLineData
970ed795 1/******************************************************************************
d44e3c4f 2 * Copyright (c) 2000-2016 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
d44e3c4f 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 *
970ed795
EL
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
34static const char *program_name = NULL;
35static size_t indent_depth = 4;
36static FILE *output_file = NULL;
37static int separate_files = 0;
3abe9331 38static int format_tab_newline = 1;
39static int replaced_tab_newline = 0;
970ed795
EL
40
41static size_t indent_level = 0;
42static enum { OPEN_BRACE, CLOSE_BRACE, COMMA, OTHER, OTHER_WS }
43 last_token = OTHER;
44
45static char *line_buf = NULL;
46static size_t buf_size = 0, buf_len = 0;
47#define MIN_BUFSIZE 1024
48
49static void init_line_buf(void)
50{
51 line_buf = (char *)Malloc(MIN_BUFSIZE);
52 buf_size = MIN_BUFSIZE;
53 buf_len = 0;
54}
55
56static 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
66static void free_line_buf(void)
67{
68 Free(line_buf);
69 line_buf = NULL;
70 buf_size = 0;
71 buf_len = 0;
72}
73
74static 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
81static 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
90static 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
106static 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
124static 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
3f84031e 131//Solaris does not have strndup
132char * 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}
3abe9331 138
139char *
3f84031e 140str_replace ( const char *string, const int len, const char *substr, const char *replacement ){
3abe9331 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 */
3f84031e 148 if ( substr == NULL || replacement == NULL ) return my_strndup (string, len);
149 newstr = my_strndup (string, len);
3abe9331 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
970ed795
EL
174static void write_line_buf(void)
175{
176 if (buf_len > 0) {
3abe9331 177 if(format_tab_newline){
3f84031e 178 char * temp = str_replace(line_buf, buf_len, "\\n", "\n");
179 temp = str_replace(temp, buf_len-replaced_tab_newline, "\\t", "\t");
3abe9331 180 strcpy(line_buf, temp);
181 free(temp);
182 }
183 if (fwrite(line_buf, buf_len-replaced_tab_newline, 1, yyout) != 1) write_failure();
970ed795
EL
184 /* append a newline character if it is missing from the end
185 * (e.g. because of EOF) */
3abe9331 186 if (line_buf[buf_len - replaced_tab_newline - 1] != '\n'){
970ed795 187 if (putc('\n', yyout) == EOF) write_failure();
3abe9331 188 }
189 replaced_tab_newline = 0;
970ed795
EL
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
202static 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
214static int in_testcase = 0;
215static size_t n_testcases = 0;
216static char **testcases = NULL;
217
218static 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
238static 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
247static 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
258WHITESPACE [ \t]
259NEWLINE \r|\n|\r\n
260
261NUMBER 0|([1-9][0-9]*)
262
263IDENTIFIER [a-zA-Z][a-zA-Z0-9_]*
264
265VERDICT none|pass|inconc|fail|error
266
267YEAR [0-9]{4}
268MONTH Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec
269DATE [0-2][0-9]|3[01]
270HOUR [01][0-9]|2[0-3]
271MIN [0-5][0-9]
272SEC [0-5][0-9]
273MICROSEC [0-9]{6}
274
275TIMESTAMP1 {NUMBER}\.{MICROSEC}
276TIMESTAMP2 {HOUR}\:{MIN}\:{SEC}\.{MICROSEC}
277TIMESTAMP3 {YEAR}\/{MONTH}\/{DATE}" "{TIMESTAMP2}
278
279TIMESTAMP {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
438static void usage(void)
439{
440 fprintf(stderr,
3abe9331 441 "usage: %s [-i n] [-o outfile] [-s] [-n] [file.log] ...\n"
970ed795
EL
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"
3abe9331 450 " -n newline and tab control characters are not modified\n"
970ed795
EL
451 " -v: print version\n",
452 program_name, program_name);
453}
454
455int main(int argc, char *argv[])
456{
457 int c;
3abe9331 458 int iflag = 0, oflag = 0, sflag = 0, vflag = 0, errflag = 0, nflag = 0;
970ed795
EL
459#ifdef LICENSE
460 license_struct lstr;
461#endif
462 program_name = argv[0];
463 output_file = stdout;
3abe9331 464 if(argc == 1){
465 errflag = 1;
466 }
467 while ((c = getopt(argc, argv, "i:o:snv")) != -1 && !errflag) {
970ed795
EL
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;
3abe9331 489 case 'n':
490 if(vflag) errflag = 1;
491 format_tab_newline = 0;
492 nflag = 1;
493 break;
970ed795 494 case 'v':
3abe9331 495 if (iflag || oflag || sflag || nflag) errflag = 1;
970ed795
EL
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.044258 seconds and 5 git commands to generate.