TPCCLIB
Loading...
Searching...
No Matches
iftmatch.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <strings.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcift.h"
18/*****************************************************************************/
19
20/*****************************************************************************/
21/* Local functions */
23 IFT *ift1, IFT *ift2, char *key, int test_lt, int test_gt,
24 double test_abs, int verbose
25);
27 IFT *ift1, IFT *ift2, char *key1, char *key2, int test_lt, int test_gt,
28 double test_abs, int verbose
29);
30/*****************************************************************************/
31
32/*****************************************************************************/
33static char *info[] = {
34 "Verify that the contents in two IFT files is similar.",
35 "By default, all contents (keys and values) are tested, but by specifying",
36 "a key, only values of that that key are tested. If the second IFT file",
37 "has a different key name, then it can be specified as the second key name.",
38 " ",
39 "IFT files are text files with key and (optional) value at each line,",
40 "for example:",
41 " calibrated := yes",
42 " calibration_coefficient := 6.78901E-005",
43 " ",
44 "Key and value strings are case-insensitive. Lines may be in any order,",
45 "except that if more than one key instances are found, the order of the",
46 "values must be the same.",
47 " ",
48 "Program returns 0, if match is found, 1-9 in case of an error, or",
49 "10, if matching key or value is not found.",
50 " ",
51 "Usage: @P [options] filename1 filename2 [key [key2]]",
52 " ",
53 "Options:",
54 "-lt | -gt | -abs=<limit>",
55 " Values in file 1 and 2 are tested numerically (not as text), to be less",
56 " (-lt) or greater (-gt) in file 1 than in file 2, or the absolute",
57 " difference is not allowed to exceed the specified limit (-abs=<limit>)",
58 " -stdoptions", // List standard options like --help, -v, etc
59 " ",
60 "Example 1:",
61 " @P data1.ift data2.ift",
62 "Example 2:",
63 " @P iea345header.txt validheader.txt calibrated",
64 "Example 3:",
65 " @P -abs=0.02 iea345hdr.txt validhdr.txt halflife",
66 "Example 4:",
67 " @P -abs=0.02 iea345hdr.txt validhdr.txt half-life halflife",
68 " ",
69 "See also: iftisval, iftlist, csv2ift",
70 " ",
71 "Keywords: IFT, tool, software testing",
72 0};
73/*****************************************************************************/
74
75/*****************************************************************************/
76/* Turn on the globbing of the command line, since it is disabled by default in
77 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
78 In Unix&Linux wildcard command line processing is enabled by default. */
79/*
80#undef _CRT_glob
81#define _CRT_glob -1
82*/
83int _dowildcard = -1;
84/*****************************************************************************/
85
86/*****************************************************************************/
90int main(int argc, char **argv)
91{
92 int ai, help=0, version=0, verbose=1;
93 int ret, i;
94 char *cptr, iftfile1[FILENAME_MAX], iftfile2[FILENAME_MAX];
95 IFT ift1, ift2;
96 char *key, *key2;
97 double test_abs=-1.0;
98 int test_lt=0, test_gt=0;
99
100 /*
101 * Get arguments
102 */
103 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
104 iftInit(&ift1); iftInit(&ift2);
105 iftfile1[0]=iftfile2[0]=(char)0; key=NULL; key2=NULL;
106 /* Options */
107 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
108 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
109 cptr=argv[ai]+1;
110 if(strncasecmp(cptr, "ABS=", 4)==0) {
111 test_abs=atofVerified(cptr+4); if(!isnan(test_abs)) continue;
112 } else if(strcasecmp(cptr, "LT")==0) {
113 test_lt=1; continue;
114 } else if(strcasecmp(cptr, "GT")==0) {
115 test_gt=1; continue;
116 }
117 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
118 free(key); free(key2);
119 return(1);
120 } else break; // later arguments may start with '-'
121
122 /* Print help or version? */
123 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
124 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
125 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
126
127 TPCSTATUS status; statusInit(&status);
128 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
129 status.verbose=verbose;
130
131 /* Process other arguments, starting from the first non-option */
132 for(; ai<argc; ai++) {
133 if(!iftfile1[0]) {
134 strcpy(iftfile1, argv[ai]); continue;
135 } else if(!iftfile2[0]) {
136 strcpy(iftfile2, argv[ai]); continue;
137 } else if(key==NULL) {
138 key=strdup(argv[ai]); continue;
139 } else if(key2==NULL) {
140 key2=strdup(argv[ai]); continue;
141 }
142 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
143 free(key); free(key2);
144 return(1);
145 }
146
147 /* Is something missing? */
148 if(!iftfile2[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
149
150 /* In verbose mode print arguments and options */
151 if(verbose>1) {
152 for(ai=0; ai<argc; ai++)
153 printf("%s ", argv[ai]);
154 printf("\n");
155 printf("iftfile1 := %s\n", iftfile1);
156 printf("iftfile2 := %s\n", iftfile2);
157 if(key!=NULL) printf("key := %s\n", key);
158 if(key2!=NULL) printf("key2 := %s\n", key2);
159 if(test_abs>=0.0) printf("test_abs := %g\n", test_abs);
160 printf("test_lt := %d\n", test_lt);
161 printf("test_gt := %d\n", test_gt);
162 }
163
164
165 /*
166 * Read IFT files
167 */
168 FILE *fp;
169 if(verbose>1) printf("reading %s\n", iftfile1);
170 fp=fopen(iftfile1, "r"); if(fp==NULL) {
171 fprintf(stderr, "Error: cannot open file %s\n", iftfile1);
172 free(key); free(key2); return(2);
173 }
174 ret=iftRead(&ift1, fp, 1, 1, &status); fclose(fp);
175 if(ret) {
176 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
177 free(key); free(key2); iftFree(&ift1); return(2);
178 }
179 if(verbose>2) printf("list1 size: %d item(s)\n", ift1.keyNr);
180
181 if(verbose>1) printf("reading %s\n", iftfile2);
182 fp=fopen(iftfile2, "r"); if(fp==NULL) {
183 fprintf(stderr, "Error: cannot open file %s\n", iftfile2);
184 free(key); free(key2); iftFree(&ift1); return(2);
185 }
186 ret=iftRead(&ift2, fp, 1, 1, &status); fclose(fp);
187 if(ret) {
188 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
189 free(key); free(key2); iftFree(&ift1); iftFree(&ift2); return(2);
190 }
191 if(verbose>2) printf("list2 size: %d item(s)\n", ift2.keyNr);
192
193 /* If key was specified, then... */
194 if(key!=NULL) {
195 if(key2==NULL) {
196 if(verbose>1) printf("testing key '%s'\n", key);
197 ret=iftCheckKeyValue(&ift1, &ift2, key, test_lt, test_gt, test_abs,
198 verbose-1);
199 } else {
200 if(verbose>1) printf("testing keys '%s' and '%s'\n", key, key2);
201 ret=iftCheckKeyValues(&ift1, &ift2, key, key2, test_lt, test_gt, test_abs,
202 verbose-1);
203 }
204 if(ret==0) {
205 if(verbose>=0) fprintf(stdout, "Match was found.\n");
206 } else {
207 if(verbose>=0) fprintf(stderr, "No match: values are not the same.\n");
208 ret=10;
209 }
210 iftFree(&ift1); iftFree(&ift2); free(key); free(key2);
211 return(ret);
212 }
213
214 /* We are here to test all contents */
215 if(verbose>1) printf("full content testing\n");
216
217 /* First check that nr of keys is the same */
218 if(ift1.keyNr!=ift2.keyNr) {
219 if(verbose>=0) fprintf(stderr, "No match: key number is not the same.\n");
220 iftFree(&ift1); iftFree(&ift2); free(key); free(key2);
221 return(10);
222 }
223
224 /* Go through the list items */
225 ret=0;
226 for(i=0; i<ift1.keyNr; i++) {
227 // in case of multiple instances of the same key, it will be tested
228 // many times, but that does not matter so much
229
230 if(verbose>1) printf("testing key '%s'\n", ift1.item[i].key);
231 ret=iftCheckKeyValue(&ift1, &ift2, ift1.item[i].key, test_lt, test_gt,
232 test_abs, verbose-1);
233 if(ret==0) {
234 if(verbose>1) fprintf(stdout, "Match was found.\n");
235 } else {
236 if(verbose>=0)
237 fprintf(stderr, "No match: values are not the same for the key %s.\n",
238 ift1.item[i].key);
239 iftFree(&ift1); iftFree(&ift2); free(key); free(key2);
240 return(10);
241 }
242
243 } // next item
244
245
246 iftFree(&ift1); iftFree(&ift2); free(key); free(key2);
247 if(verbose>=0) fprintf(stdout, "Match was found.\n");
248 return(0);
249}
250/*****************************************************************************/
251
252/*****************************************************************************/
254
260 IFT *ift1,
262 IFT *ift2,
264 char *key,
267 int test_lt,
270 int test_gt,
273 double test_abs,
275 int verbose
276) {
277 if(verbose>2)
278 printf("iftCheckKeyValue(*ift1, *ift2, \"%s\", %d, %d, %g, ...)\n",
279 key, test_lt, test_gt, test_abs);
280 if(ift1==NULL || ift2==NULL) return(1);
281 if(key==NULL || strlen(key)<1) return(1);
282
283 /* Check first that key can be found in both files */
284 int n1, n2;
285 n1=iftFindNrOfKeys(ift1, key);
286 n2=iftFindNrOfKeys(ift2, key);
287 if(verbose>0) {
288 printf("%d instance(s) of key in file1.\n", n1);
289 printf("%d instance(s) of key in file2.\n", n2);
290 }
291 if(n1<1 || n2<1) {
292 if(verbose>0) fprintf(stderr, "No match: key not found.\n");
293 return(10);
294 }
295 /* Verify that the same key(s) and value(s) are found in both */
296 if(n1!=n2) {
297 if(verbose>0) fprintf(stderr, "No match: different nr of keys.\n");
298 return(10);
299 }
300 char *s1, *s2;
301 int i, li, lj;
302 double v1, v2;
303 s1=(char*)NULL; s2=(char*)NULL;
304 for(i=0, li=lj=-1; i<n1; i++) {
305 li=iftFindKey(ift1, key, li+1); if(verbose>5) printf("li=%d\n", li);
306 lj=iftFindKey(ift2, key, lj+1); if(verbose>5) printf("lj=%d\n", lj);
307 if(li<0 || lj<0) break;
308 /* Get pointers to value strings */
309 s1=(char*)ift1->item[li].value; s2=(char*)ift2->item[lj].value;
310 if(verbose>2) printf("testing strings '%s' == '%s'\n", s1, s2);
311 /* Check if both values are NULL or empty; considered as match */
312 if(s1==NULL && s2==NULL) continue;
313 if(strlen(s1)==0 && strlen(s2)==0) continue;
314 /* Check if values are the same as strings */
315 if(strcasecmp(s1, s2)==0) continue;
316 /* Try to convert them to doubles, ignoring unit */
317 if(doubleGetWithUnit(s1, &v1, NULL)!=0) break;
318 if(doubleGetWithUnit(s2, &v2, NULL)!=0) break;
319 /* Compare the doubles */
320 if(test_lt) {
321 if(verbose>2) printf("testing whether %g < %g\n", v1, v2);
322 if(v1<v2) continue;
323 } else if(test_gt) {
324 if(verbose>2) printf("testing whether %g > %g\n", v1, v2);
325 if(v1>v2) continue;
326 } else if(test_abs>=0) {
327 if(verbose>2) printf("testing whether |%g-%g| < %g\n", v1, v2, test_abs);
328 if(fabs(v1-v2)<test_abs) continue;
329 } else {
330 if(verbose>2) printf("testing whether %g == %g\n", v1, v2);
331 if(v1==v2) continue;
332 }
333 break;
334 }
335 if(i!=n1) {
336 if(verbose>0) fprintf(stderr, "No match: values are not the same.\n");
337 if(verbose>1) printf("value1 := '%s'\nvalue2 := '%s'\n", s1, s2);
338 return(10);
339 }
340 if(verbose>0) fprintf(stdout, "Match was found: values are the same.\n");
341 return(0);
342}
343/******************************************************************************/
344
345/******************************************************************************/
353 IFT *ift1,
355 IFT *ift2,
357 char *key1,
359 char *key2,
362 int test_lt,
365 int test_gt,
368 double test_abs,
370 int verbose
371) {
372 if(verbose>2)
373 printf("iftCheckKeyValues(*ift1, *ift2, \"%s\", \"%s\", %d, %d, %g, ...)\n",
374 key1, key2, test_lt, test_gt, test_abs);
375 if(ift1==NULL || ift2==NULL) return(1);
376 if(key1==NULL || strlen(key1)<1) return(1);
377 if(key2==NULL) key2=key1;
378
379 /* Check first that keys can be found in both files */
380 int n1, n2;
381 n1=iftFindNrOfKeys(ift1, key1);
382 n2=iftFindNrOfKeys(ift2, key2);
383 if(verbose>0) {
384 printf("%d instance(s) of key in file1.\n", n1);
385 printf("%d instance(s) of key in file2.\n", n2);
386 }
387 if(n1<1 || n2<1) {
388 if(verbose>0) fprintf(stderr, "No match: key not found.\n");
389 return(10);
390 }
391 /* Verify that the same key(s) and value(s) are found in both */
392 if(n1!=n2) {
393 if(verbose>0) fprintf(stderr, "No match: different nr of keys.\n");
394 return(10);
395 }
396 char *s1, *s2;
397 int i, li, lj;
398 double v1, v2;
399 s1=(char*)NULL; s2=(char*)NULL;
400 for(i=0, li=lj=-1; i<n1; i++) {
401 li=iftFindKey(ift1, key1, li+1); if(verbose>5) printf("li=%d\n", li);
402 lj=iftFindKey(ift2, key2, lj+1); if(verbose>5) printf("lj=%d\n", lj);
403 if(li<0 || lj<0) break;
404 /* Get pointers to value strings */
405 s1=(char*)ift1->item[li].value; s2=(char*)ift2->item[lj].value;
406 if(verbose>2) printf("testing strings '%s' == '%s'\n", s1, s2);
407 /* Check if both values are NULL or empty; considered as match */
408 if(s1==NULL && s2==NULL) continue;
409 if(strlen(s1)==0 && strlen(s2)==0) continue;
410 /* Check if values are the same as strings */
411 if(strcasecmp(s1, s2)==0) continue;
412 /* Try to convert them to doubles */
413 if(doubleGetWithUnit(s1, &v1, NULL)!=0) break;
414 if(doubleGetWithUnit(s2, &v2, NULL)!=0) break;
415 /* Compare the doubles */
416 if(test_lt) {
417 if(verbose>2) printf("testing whether %g < %g\n", v1, v2);
418 if(v1<v2) continue;
419 } else if(test_gt) {
420 if(verbose>2) printf("testing whether %g > %g\n", v1, v2);
421 if(v1>v2) continue;
422 } else if(test_abs>=0) {
423 if(verbose>2) printf("testing whether |%g-%g| < %g\n", v1, v2, test_abs);
424 if(fabs(v1-v2)<test_abs) continue;
425 } else {
426 if(verbose>2) printf("testing whether %g == %g\n", v1, v2);
427 if(v1==v2) continue;
428 }
429 break;
430 }
431 if(i!=n1) {
432 if(verbose>0) fprintf(stderr, "No match: values are not the same.\n");
433 if(verbose>1) printf("value1 := '%s'\nvalue2 := '%s'\n", s1, s2);
434 return(10);
435 }
436 if(verbose>0) fprintf(stdout, "Match was found: values are the same.\n");
437 return(0);
438}
439/*****************************************************************************/
440
441/*****************************************************************************/
double atofVerified(const char *s)
Definition decpoint.c:75
int doubleGetWithUnit(const char *s, double *v, int *u)
Definition doubleutil.c:272
void iftFree(IFT *ift)
Definition ift.c:37
void iftInit(IFT *ift)
Definition ift.c:21
int iftFindNrOfKeys(IFT *ift, const char *key)
Definition iftfind.c:142
int iftFindKey(IFT *ift, const char *key, int start_index)
Definition iftfind.c:30
int iftRead(IFT *ift, FILE *fp, int is_key_required, int is_comment_accepted, TPCSTATUS *status)
Definition iftio.c:130
int iftCheckKeyValues(IFT *ift1, IFT *ift2, char *key1, char *key2, int test_lt, int test_gt, double test_abs, int verbose)
Definition iftmatch.c:351
int iftCheckKeyValue(IFT *ift1, IFT *ift2, char *key, int test_lt, int test_gt, double test_abs, int verbose)
Definition iftmatch.c:258
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
char * strdup(const char *s)
Definition stringext.c:185
char * value
Definition tpcift.h:37
char * key
Definition tpcift.h:32
Definition tpcift.h:43
IFT_ITEM * item
Definition tpcift.h:57
int keyNr
Definition tpcift.h:47
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
Header file for library libtpcextensions.
@ TPCERROR_OK
No error.
Header file for library libtpcift.