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