Typo corrected
[deliverable/titan.core.git] / repgen / logformat.l
1 /******************************************************************************
2 * Copyright (c) 2000-2015 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 static int format_tab_newline = 1;
30 static int replaced_tab_newline = 0;
31
32 static size_t indent_level = 0;
33 static enum { OPEN_BRACE, CLOSE_BRACE, COMMA, OTHER, OTHER_WS }
34 last_token = OTHER;
35
36 static char *line_buf = NULL;
37 static size_t buf_size = 0, buf_len = 0;
38 #define MIN_BUFSIZE 1024
39
40 static void init_line_buf(void)
41 {
42 line_buf = (char *)Malloc(MIN_BUFSIZE);
43 buf_size = MIN_BUFSIZE;
44 buf_len = 0;
45 }
46
47 static 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
57 static void free_line_buf(void)
58 {
59 Free(line_buf);
60 line_buf = NULL;
61 buf_size = 0;
62 buf_len = 0;
63 }
64
65 static 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
72 static 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
81 static 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
97 static 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
115 static 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
122 //Solaris does not have strndup
123 char * 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 }
129
130 char *
131 str_replace ( const char *string, const int len, const char *substr, const char *replacement ){
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 */
139 if ( substr == NULL || replacement == NULL ) return my_strndup (string, len);
140 newstr = my_strndup (string, len);
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
165 static void write_line_buf(void)
166 {
167 if (buf_len > 0) {
168 if(format_tab_newline){
169 char * temp = str_replace(line_buf, buf_len, "\\n", "\n");
170 temp = str_replace(temp, buf_len-replaced_tab_newline, "\\t", "\t");
171 strcpy(line_buf, temp);
172 free(temp);
173 }
174 if (fwrite(line_buf, buf_len-replaced_tab_newline, 1, yyout) != 1) write_failure();
175 /* append a newline character if it is missing from the end
176 * (e.g. because of EOF) */
177 if (line_buf[buf_len - replaced_tab_newline - 1] != '\n'){
178 if (putc('\n', yyout) == EOF) write_failure();
179 }
180 replaced_tab_newline = 0;
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
193 static 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
205 static int in_testcase = 0;
206 static size_t n_testcases = 0;
207 static char **testcases = NULL;
208
209 static 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
229 static 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
238 static 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
249 WHITESPACE [ \t]
250 NEWLINE \r|\n|\r\n
251
252 NUMBER 0|([1-9][0-9]*)
253
254 IDENTIFIER [a-zA-Z][a-zA-Z0-9_]*
255
256 VERDICT none|pass|inconc|fail|error
257
258 YEAR [0-9]{4}
259 MONTH Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec
260 DATE [0-2][0-9]|3[01]
261 HOUR [01][0-9]|2[0-3]
262 MIN [0-5][0-9]
263 SEC [0-5][0-9]
264 MICROSEC [0-9]{6}
265
266 TIMESTAMP1 {NUMBER}\.{MICROSEC}
267 TIMESTAMP2 {HOUR}\:{MIN}\:{SEC}\.{MICROSEC}
268 TIMESTAMP3 {YEAR}\/{MONTH}\/{DATE}" "{TIMESTAMP2}
269
270 TIMESTAMP {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
429 static void usage(void)
430 {
431 fprintf(stderr,
432 "usage: %s [-i n] [-o outfile] [-s] [-n] [file.log] ...\n"
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"
441 " -n newline and tab control characters are not modified\n"
442 " -v: print version\n",
443 program_name, program_name);
444 }
445
446 int main(int argc, char *argv[])
447 {
448 int c;
449 int iflag = 0, oflag = 0, sflag = 0, vflag = 0, errflag = 0, nflag = 0;
450 #ifdef LICENSE
451 license_struct lstr;
452 #endif
453 program_name = argv[0];
454 output_file = stdout;
455 if(argc == 1){
456 errflag = 1;
457 }
458 while ((c = getopt(argc, argv, "i:o:snv")) != -1 && !errflag) {
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;
480 case 'n':
481 if(vflag) errflag = 1;
482 format_tab_newline = 0;
483 nflag = 1;
484 break;
485 case 'v':
486 if (iflag || oflag || sflag || nflag) errflag = 1;
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.057449 seconds and 5 git commands to generate.