Commit | Line | Data |
---|---|---|
d44e3c4f | 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 | * Tatarka, Gabor | |
16 | * | |
17 | ******************************************************************************/ | |
970ed795 EL |
18 | /************************** |
19 | Log filter for TTCNv3 | |
20 | written by Gabor Tatarka | |
21 | **************************/ | |
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | #include <unistd.h> | |
25 | #include <string.h> | |
26 | #include <errno.h> | |
27 | #include "../common/version_internal.h" | |
28 | ||
29 | #ifdef LICENSE | |
30 | #include "../common/license.h" | |
31 | #endif | |
32 | ||
33 | #define Fail -1 | |
34 | #define False 0 | |
35 | #define True 1 | |
36 | ||
37 | #define ERR_NONE 0 | |
38 | #define ERR_WRITE 1 | |
39 | #define ERR_INVALID_LOG 2 | |
40 | ||
41 | /*filter flag values:*/ | |
42 | #define Write 1 | |
43 | #define DontWrite 2 | |
44 | /*0 is: act as Wothers*/ | |
45 | ||
46 | #define TimeLength 15 | |
47 | #define SecondLength 9 | |
48 | #define DateTimeLength 27 | |
49 | #define MaxTimeStampLength 27 | |
50 | #define BufferSize 512 | |
51 | #define YYYYMONDD 1 /*format of Date: year/month/day*/ | |
52 | ||
53 | static const char * const MON[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
54 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | |
55 | ||
56 | #define MaxType 15 | |
57 | typedef enum {/*If you add new types, add it to the end of the list, and | |
58 | also add it to EventTypeNames! ET_Unknown has no representation | |
59 | in text, and it must not be changed.Also change MaxType!*/ | |
60 | ET_Unknown=-1,ET_Error,ET_Warning,ET_Portevent,ET_Timerop, | |
61 | ET_Verdictop,ET_Defaultop,ET_Action,ET_Testcase,ET_Function, | |
62 | ET_User,ET_Statictics,ET_Parallel,ET_Matching,ET_Debug, | |
63 | ET_Executor | |
64 | } EventTypes; | |
65 | static const char * const EventTypeNames[] = { | |
66 | "ERROR","WARNING","PORTEVENT","TIMEROP","VERDICTOP","DEFAULTOP", | |
67 | "ACTION","TESTCASE","FUNCTION","USER","STATISTICS","PARALLEL", | |
68 | "MATCHING","DEBUG","EXECUTOR" | |
69 | }; | |
70 | static int Wothers=Write; | |
71 | static int Wflags[MaxType]; | |
72 | ||
73 | static int IsSecond(const char *str)/*Is timestamp format Seconds*/ | |
74 | { | |
75 | int a; | |
76 | if(*str<'0'||*str>'9')return False;/*first digit*/ | |
77 | while(*str>='0'&&*str<='9')str++;/*other digits*/ | |
78 | if(*str!='.')return False;/* '.' */ | |
79 | for(a=0;a<6;a++)if(*str<'0'||*str>'9')return False;/*microseconds(6 digits)*/ | |
80 | return True; | |
81 | } | |
82 | ||
83 | static int IsSecond2_6(const char *str)/*does string contain sec(2).usec(6)*/ | |
84 | { | |
85 | int a; | |
86 | for(a=0;a<SecondLength;a++) { | |
87 | if(a==2) { | |
88 | if(*str=='.') { | |
89 | str++;continue; | |
90 | } else return False; | |
91 | } | |
92 | if(*str<'0'||*str>'9')return False; | |
93 | str++; | |
94 | } | |
95 | return True; | |
96 | } | |
97 | ||
98 | static int IsTime(const char *str)/*Is timestamp format Time*/ | |
99 | { | |
100 | int a; | |
101 | if(False==IsSecond2_6(str+6))return False; | |
102 | for(a=0;a<6;a++){ | |
103 | if(a==2||a==5) { | |
104 | if(*str==':') { | |
105 | str++;continue; | |
106 | } else return False; | |
107 | } | |
108 | if(*str<'0'||*str>'9')return False; | |
109 | str++; | |
110 | } | |
111 | return True; | |
112 | } | |
113 | ||
114 | #ifdef YYYYMONDD /*Date format: year/month/day*/ | |
115 | # define FIRST_LEN 4 | |
116 | # define THIRD_LEN 2 | |
117 | #else /*Date format: day/month/year*/ | |
118 | # define FIRST_LEN 2 | |
119 | # define THIRD_LEN 4 | |
120 | #endif | |
121 | ||
122 | static int IsDateTime(const char *str)/*is timestamp format Date/Time*/ | |
123 | { | |
124 | int a,b; | |
125 | if(False==IsTime(str+12))return False; | |
126 | for(a=0;a<FIRST_LEN;a++) {/*YYYY or DD*/ | |
127 | if(*str<'0'||*str>'9')return False; | |
128 | str++; | |
129 | } | |
130 | if(*str!='/')return False;/* '/' */ | |
131 | str++; | |
132 | for(a=0,b=0;a<12;a++)if(0==strncmp(str,MON[a],3)){b=1;break;}/*MON*/ | |
133 | if(!b)return False; | |
134 | str+=3; | |
135 | if(*str!='/')return False;/* '/' */ | |
136 | str++; | |
137 | for(a=0;a<THIRD_LEN;a++) {/*DD or YYYY*/ | |
138 | if(*str<'0'||*str>'9')return False; | |
139 | str++; | |
140 | } | |
141 | return True; | |
142 | } | |
143 | ||
144 | static int ValidTS(const char *str)/*is timestamp of event valid*/ | |
145 | { | |
146 | if(True==IsSecond(str))return True; | |
147 | if(True==IsTime(str))return True; | |
148 | if(True==IsDateTime(str))return True; | |
149 | return False; | |
150 | } | |
151 | ||
152 | static EventTypes get_event_type(char *buf) | |
153 | { | |
154 | int a; | |
155 | char *ptr1,*ptr2; | |
156 | ptr1=buf+strlen(buf); | |
157 | for(a=0;a<MaxType;a++) { | |
158 | ptr2=strstr(buf,EventTypeNames[a]); | |
159 | if(ptr2<ptr1&&ptr2!=NULL) { | |
160 | ptr1=ptr2; | |
3abe9331 | 161 | if(*(ptr2+strlen(EventTypeNames[a]))==' '&& *(ptr2-1)==' ' |
162 | && *(ptr2+strlen(EventTypeNames[a])+1)!='|') | |
970ed795 EL |
163 | return a; |
164 | } | |
165 | } | |
166 | return ET_Unknown; | |
167 | } | |
168 | ||
169 | static int ProcessFile(FILE *out,FILE *in) /*filter infile to outfile*/ | |
170 | { | |
171 | int b=0; | |
172 | char line_buffer[BufferSize]; | |
173 | int last_event=0; | |
174 | EventTypes current_event_type=ET_Unknown; | |
175 | while(1) { | |
176 | line_buffer[0]='\0'; | |
177 | if(NULL==fgets(line_buffer,sizeof(line_buffer),in)) last_event=1; | |
178 | else if(ValidTS(line_buffer)) { | |
179 | current_event_type=get_event_type(line_buffer); | |
180 | b++; | |
181 | } | |
182 | if(current_event_type==ET_Unknown && Wothers==Write) { | |
183 | if(0>fprintf(out,"%s",line_buffer))return ERR_WRITE; | |
184 | } else if(Wflags[current_event_type]==Write || | |
185 | (Wflags[current_event_type]==0 && Wothers==Write)) { | |
186 | if(0>fprintf(out,"%s",line_buffer))return ERR_WRITE; | |
187 | } | |
188 | if(last_event)break; | |
189 | } | |
190 | if(!b)return ERR_INVALID_LOG; | |
191 | else return ERR_NONE; | |
192 | } | |
193 | ||
194 | static void Usage(const char *progname) | |
195 | { | |
196 | fprintf(stderr, | |
197 | "Usage: %s [-o outfile] [infile.log] [eventtype+|-] [...]\n" | |
198 | " or %s option\n" | |
199 | "options:\n" | |
200 | " -o outfile: write merged logs into file outfile\n" | |
201 | " -v: print version\n" | |
202 | " -h: print help (usage)\n" | |
203 | " -l: list event types\n" | |
204 | "If there is no outfile specified output is stdout.\n" | |
205 | "If infile is omitted input is stdin.\n" | |
206 | "Including and excluding event types at the same time is not allowed.\n" | |
207 | "\n",progname,progname); | |
208 | } | |
209 | ||
210 | static void ListTypes(void) | |
211 | { | |
212 | int a; | |
213 | fprintf(stderr,"Event types:\n"); | |
214 | for(a=0;a<MaxType;a++)fprintf(stderr,"\t%s\n",EventTypeNames[a]); | |
215 | } | |
216 | ||
217 | int main(int argc,char *argv[]) | |
218 | { | |
219 | int a,b,c; | |
220 | FILE *outfile = NULL, *infile = NULL; | |
221 | char *outfile_name=NULL,*infile_name=NULL; | |
222 | char tmp[20]; | |
223 | int vflag=0,oflag=0,hflag=0,lflag=0,plusflag=0,minusflag=0; | |
224 | #ifdef LICENSE | |
225 | license_struct lstr; | |
226 | #endif | |
227 | while ((c = getopt(argc, argv, "lhvo:")) != -1) { | |
228 | switch (c) { | |
229 | case 'o':/*set outfile*/ | |
230 | outfile_name=optarg; | |
231 | oflag = 1; | |
232 | break; | |
233 | case 'v':/*print version*/ | |
234 | vflag=1; | |
235 | break; | |
236 | case 'h':/*print help (usage)*/ | |
237 | hflag=1; | |
238 | break; | |
239 | case 'l':/*list event types*/ | |
240 | lflag=1; | |
241 | break; | |
242 | default: | |
243 | Usage(argv[0]); | |
244 | return EXIT_FAILURE; | |
245 | } | |
246 | } | |
247 | if (oflag + vflag + hflag + lflag > 1) { | |
248 | Usage(argv[0]); | |
249 | return EXIT_FAILURE; | |
250 | } else if (vflag) { | |
251 | fputs("Log Filter for the TTCN-3 Test Executor\n" | |
252 | "Product number: " PRODUCT_NUMBER "\n" | |
253 | "Build date: " __DATE__ " " __TIME__ "\n" | |
254 | "Compiled with: " C_COMPILER_VERSION "\n\n" | |
255 | COPYRIGHT_STRING "\n\n", stderr); | |
256 | #ifdef LICENSE | |
257 | print_license_info(); | |
258 | #endif | |
259 | return EXIT_SUCCESS; | |
260 | } else if (hflag) { | |
261 | Usage(argv[0]); | |
262 | return EXIT_SUCCESS; | |
263 | } else if(lflag) { | |
264 | ListTypes(); | |
265 | return EXIT_SUCCESS; | |
266 | } | |
267 | #ifdef LICENSE | |
268 | init_openssl(); | |
269 | load_license(&lstr); | |
270 | if (!verify_license(&lstr)) { | |
271 | free_license(&lstr); | |
272 | free_openssl(); | |
273 | exit(EXIT_FAILURE); | |
274 | } | |
275 | if (!check_feature(&lstr, FEATURE_LOGFORMAT)) { | |
276 | fputs("The license key does not allow the filtering of log files.\n", | |
277 | stderr); | |
278 | return 2; | |
279 | } | |
280 | free_license(&lstr); | |
281 | free_openssl(); | |
282 | #endif | |
283 | /* | |
284 | switches: -v -o -h -l | |
285 | filter parameters: parameter+ or parameter- | |
286 | */ | |
287 | for(a=0;a<MaxType;a++)Wflags[a]=0; | |
288 | for(a=1;a<argc;a++) { | |
289 | if(*argv[a]=='-'){if(*(argv[a]+1)=='o')a++;continue;}/*switch*/ | |
290 | if(*(argv[a]+strlen(argv[a])-1)=='-') {/*type to ignore*/ | |
291 | for(b=0,c=0;b<MaxType;b++) | |
292 | if(0==strncmp(EventTypeNames[b],argv[a], | |
293 | strlen(EventTypeNames[b]))&&strlen(EventTypeNames[b])== | |
294 | strlen(argv[a])-1) { | |
295 | Wflags[b]=DontWrite; | |
296 | c=1; | |
297 | } | |
298 | if(!c) {/*Undefined type*/ | |
299 | strncpy(tmp,argv[a],sizeof(tmp)-1); | |
300 | if(strlen(argv[a])>sizeof(tmp)-1) | |
301 | for(c=2;c<5;c++)tmp[sizeof(tmp)-c]='.'; | |
302 | else tmp[strlen(argv[a])-1]='\0'; | |
303 | tmp[sizeof(tmp)-1]='\0'; | |
304 | if(strlen(tmp))fprintf(stderr,"Warning: %s is not a valid " | |
305 | "event-type name.\n",tmp); | |
306 | else fprintf(stderr,"Warning: `-\' without an event-type " | |
307 | "name.\n"); | |
308 | } | |
309 | Wothers=Write; | |
310 | minusflag=1; | |
311 | continue; | |
312 | } | |
313 | if(*(argv[a]+strlen(argv[a])-1)=='+') {/*type to write out*/ | |
314 | for(b=0,c=0;b<MaxType;b++) | |
315 | if(0==strncmp(EventTypeNames[b],argv[a], | |
316 | strlen(EventTypeNames[b]))&&strlen(EventTypeNames[b])== | |
317 | strlen(argv[a])-1) { | |
318 | Wflags[b]=Write; | |
319 | c=1; | |
320 | } | |
321 | if(!c) {/*Undefined type*/ | |
322 | strncpy(tmp,argv[a],sizeof(tmp)-1); | |
323 | if(strlen(argv[a])>sizeof(tmp)-1) | |
324 | for(c=2;c<5;c++)tmp[sizeof(tmp)-c]='.'; | |
325 | else tmp[strlen(argv[a])-1]='\0'; | |
326 | tmp[sizeof(tmp)-1]='\0'; | |
327 | if(strlen(tmp))fprintf(stderr,"Warning: %s is not a valid " | |
328 | "event-type name.\n",tmp); | |
329 | else fprintf(stderr,"Warning: `+\' without an event-type " | |
330 | "name.\n"); | |
331 | } | |
332 | Wothers=DontWrite; | |
333 | plusflag=1; | |
334 | continue; | |
335 | } | |
336 | if(infile_name!=NULL) {/*only one input file at once*/ | |
337 | fprintf(stderr,"Error: more than one input file specified.\n"); | |
338 | return EXIT_FAILURE; | |
339 | } | |
340 | infile_name=argv[a]; | |
341 | } | |
342 | if(minusflag&&plusflag) {/*type1+ and type2- at the same time could cause | |
343 | types that are not defined what to do with, to act based on the | |
344 | last filter definition. Thus it is not allowed.*/ | |
345 | fprintf(stderr,"Error: include and exclude at the same time.\n"); | |
346 | return EXIT_FAILURE; | |
347 | } | |
348 | if(infile_name==NULL)infile=stdin;/*if no infile specified use stdin*/ | |
349 | else { | |
350 | infile=fopen(infile_name,"r"); | |
351 | if(infile==NULL) { | |
352 | fprintf(stderr,"Error opening %s : %s\n",infile_name, | |
353 | strerror(errno)); | |
354 | return EXIT_FAILURE; | |
355 | } | |
356 | } | |
357 | if(oflag) { | |
358 | outfile=fopen(outfile_name,"w"); | |
359 | if(outfile==NULL) { | |
360 | fprintf(stderr,"Error creating %s : %s\n",outfile_name, | |
361 | strerror(errno)); | |
362 | return EXIT_FAILURE; | |
363 | } | |
364 | } else outfile=stdout;/*if no outfile specified use stdout*/ | |
365 | a=ProcessFile(outfile,infile);/*filter infile to outfile*/ | |
366 | if(a==ERR_INVALID_LOG) { | |
367 | if(infile_name!=NULL)fprintf(stderr,"Error: the file %s is not a valid " | |
368 | "log file.\n",infile_name); | |
369 | else fprintf(stderr,"Error: invalid format received from standard " | |
370 | "input.\n"); | |
371 | return EXIT_FAILURE; | |
372 | } else if(a==ERR_WRITE) { | |
373 | if(errno)fprintf(stderr,"Error writing to output: %s\n", | |
374 | strerror(errno)); | |
375 | else fprintf(stderr,"Error writing to output\n"); | |
376 | return EXIT_FAILURE; | |
377 | } | |
378 | return EXIT_SUCCESS; | |
379 | } | |
380 |