TPCCLIB
Loading...
Searching...
No Matches
iftvalc.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 <math.h>
14/*****************************************************************************/
15#include "tpcextensions.h"
16#include "tpcift.h"
17/*****************************************************************************/
18
19/*****************************************************************************/
20static char *info[] = {
21 "Simple artithmetic calculations on values in Interfile-type (IFT) files.",
22 "Keys are case-insensitive. Only numerical values are accepted.",
23 " ",
24 "Usage: @P [options] file1 key1 operation file2 key2 [outputfile]",
25 " ",
26 "Options:",
27 " -stdoptions", // List standard options like --help, -v, etc
28 " ",
29 "The following characters are accepted as operators: +, -, x, and :.",
30 "Value(s) in file1 are modified using specified value in file2.",
31 "If IFT does not contain keys, or all values in file1 are to be processed,",
32 "then enter 'all' or 'none' as the key name.",
33 "Contents of file1, including changed and preserved ones, are saved in",
34 "outputfile, or if not given , then file1 is overwritten.",
35 " ",
36 "Example:",
37 " @P par.ift p1 x const.ift factor newpar.ift",
38 " ",
39 "See also: iftlist, iftisval, iftedit, iftadd, iftdel, parformat, taccalc",
40 " ",
41 "Keywords: header, IFT, tool",
42 0};
43/*****************************************************************************/
44
45/*****************************************************************************/
46/* Turn on the globbing of the command line, since it is disabled by default in
47 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
48 In Unix&Linux wildcard command line processing is enabled by default. */
49/*
50#undef _CRT_glob
51#define _CRT_glob -1
52*/
53int _dowildcard = -1;
54/*****************************************************************************/
55
56/*****************************************************************************/
60double doubleOperate(
62 double v1,
64 double v2,
66 int operation
67) {
68 if(operation==1) return(v1+v2);
69 if(operation==2) return(v1-v2);
70 if(operation==3) return(v1*v2);
71 if(operation==4) return(v1/v2);
72 return(nan(""));
73}
74/*****************************************************************************/
75
76/*****************************************************************************/
80int main(int argc, char **argv)
81{
82 int ai, help=0, version=0, verbose=1;
83 int ret;
84 //char *cptr;
85 char iftfile1[FILENAME_MAX], iftfile2[FILENAME_MAX], iftfile3[FILENAME_MAX];
86 char key1[128], key2[128];
87 int operation=0; // 1=+, 2=-, 3=*, 4=:
88
89
90 /*
91 * Get arguments
92 */
93 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
94 iftfile1[0]=iftfile2[0]=iftfile3[0]=(char)0;
95 key1[0]=key2[0]=(char)0;
96 /* Options */
97 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
98 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
99 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
100 return(1);
101 } else break; // later arguments may start with '-'
102
103 /* Print help or version? */
104 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
105 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
106 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
107
108 TPCSTATUS status; statusInit(&status);
109 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
110 status.verbose=verbose;
111
112 /* Process other arguments, starting from the first non-option */
113 if(ai<argc) strlcpy(iftfile1, argv[ai++], FILENAME_MAX);
114 if(ai<argc) strlcpy(key1, argv[ai++], 128);
115 if(ai<argc) {
116 if(strcasecmp(argv[ai], "DIV")==0) {
117 operation=4;
118 } else {
119 switch(*argv[ai]) {
120 case '+' : operation=1; break;
121 case '-' : operation=2; break;
122 case '*' : operation=3; break;
123 case '.' : operation=3; break;
124 case 'X' : operation=3; break;
125 case 'x' : operation=3; break;
126 case '/' : operation=4; break;
127 case ':' : operation=4; break;
128 }
129 }
130 if(operation==0) {
131 fprintf(stderr, "Error: invalid operator.\n");
132 return(1);
133 }
134 ai++;
135 }
136 if(ai<argc) strlcpy(iftfile2, argv[ai++], FILENAME_MAX);
137 if(ai<argc) strlcpy(key2, argv[ai++], 128);
138 if(ai<argc) strlcpy(iftfile3, argv[ai++], FILENAME_MAX);
139 if(ai<argc) {
140 fprintf(stderr, "Error: too many arguments.\n");
141 return(1);
142 }
143
144 /* Is something missing? */
145 if(!key2[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
146 /* If key is 'all' then set it to empty string */
147 if(strcasecmp(key1, "ALL")==0 || strcasecmp(key1, "NONE")==0) key1[0]=(char)0;
148 if(strcasecmp(key2, "ALL")==0 || strcasecmp(key2, "NONE")==0) key2[0]=(char)0;
149 /* If output filename not given, then use input file */
150 if(!iftfile3[0]) strcpy(iftfile3, iftfile1);
151
152 /* In verbose mode print arguments and options */
153 if(verbose>1) {
154 for(ai=0; ai<argc; ai++) printf("%s ", argv[ai]);
155 printf("\n"); fflush(stdout);
156 printf("iftfile1 := %s\n", iftfile1);
157 printf("key1 := %s\n", key1);
158 printf("operation := %d\n", operation);
159 printf("iftfile2 := %s\n", iftfile2);
160 printf("key2 := %s\n", key2);
161 printf("iftfile3 := %s\n", iftfile3);
162 }
163
164
165 /*
166 * Read IFT files
167 */
168 IFT ift1, ift2;
169 iftInit(&ift1); iftInit(&ift2);
170 int key_required; // If key was specified, then only values with keys are read
171
172 if(verbose>1) printf("reading %s\n", iftfile1);
173 FILE *fp=fopen(iftfile1, "r"); if(fp==NULL) {
174 fprintf(stderr, "Error: cannot open file %s\n", iftfile1);
175 return(2);
176 }
177 if(key1[0]) key_required=1; else key_required=0;
178 ret=iftRead(&ift1, fp, key_required, 1, &status); fclose(fp);
179 if(ret) {
180 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
181 iftFree(&ift1); return(2);
182 }
183 if(verbose>2) printf("list size: %d item(s)\n", ift1.keyNr);
184
185 if(verbose>1) printf("reading %s\n", iftfile2);
186 fp=fopen(iftfile2, "r"); if(fp==NULL) {
187 fprintf(stderr, "Error: cannot open file %s\n", iftfile2);
188 return(3);
189 }
190 if(key2[0]) key_required=1; else key_required=0;
191 ret=iftRead(&ift2, fp, key_required, 1, &status); fclose(fp);
192 if(ret) {
193 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
194 iftFree(&ift1); iftFree(&ift2); return(3);
195 }
196 if(verbose>2) printf("list size: %d item(s)\n", ift2.keyNr);
197
198
199 /*
200 * If both lists have the same number of items, and keys were not given,
201 * then try to operate matching items.
202 */
203 if(ift1.keyNr==ift2.keyNr && !key1[0] && !key2[0]) {
204 if(verbose>1) printf("operating items as pairs\n");
205 double v1, v2, v3;
206 int u1, u2;
207 char newstr[128];
208 int okNr=0;
209 if(iftFindNrOfKeys(&ift1, "")==ift1.keyNr &&
210 iftFindNrOfKeys(&ift2, "")==ift2.keyNr)
211 {
212 if(verbose>1) printf("files do not have key names\n");
213 for(int li=0; li<ift1.keyNr; li++) {
214 ret=iftGetDoubleWithUnit(&ift1, li, &v1, &u1);
215 if(!ret) ret=iftGetDoubleWithUnit(&ift2, li, &v2, &u2);
216 if(ret || isnan(v1) || isnan(v2)) {
217 if(verbose>1) printf("invalid values in item %d\n", 1+li);
218 continue;
219 }
220 v3=doubleOperate(v1, v2, operation);
221 if(u1==UNIT_UNKNOWN) snprintf(newstr, 128, "%g", v3);
222 else snprintf(newstr, 128, "%g %s", v3, unitName(u1));
223 if(verbose>3) printf("new_value := '%s'\n", newstr);
224 if(iftReplaceValue(&ift1, li, newstr, NULL)!=0) continue;
225 okNr++;
226 }
227 } else {
228 if(verbose>1) printf("files have key names, using matching keys\n");
229 int lj;
230 for(int li=0; li<ift1.keyNr; li++) {
231 lj=iftFindKey(&ift2, ift1.item[li].key, 0);
232 if(lj<0) continue;
233 ret=iftGetDoubleWithUnit(&ift1, li, &v1, &u1);
234 if(!ret) ret=iftGetDoubleWithUnit(&ift2, lj, &v2, &u2);
235 if(ret || isnan(v1) || isnan(v2)) {
236 if(verbose>1) printf("invalid values in item %d\n", 1+li);
237 continue;
238 }
239 v3=doubleOperate(v1, v2, operation);
240 if(u1==UNIT_UNKNOWN) snprintf(newstr, 128, "%g", v3);
241 else snprintf(newstr, 128, "%g %s", v3, unitName(u1));
242 if(verbose>3) printf("new_value := '%s'\n", newstr);
243 if(iftReplaceValue(&ift1, li, newstr, NULL)!=0) continue;
244 okNr++;
245 /* make sure that the same key from ift2 is not used again */
246 iftDelete(&ift2, lj);
247 }
248 }
249 if(okNr<1) {
250 fprintf(stderr, "Error: no valid calculations could be done.\n");
251 iftFree(&ift1); iftFree(&ift2);
252 return(4);
253 }
254 if(okNr<ift1.keyNr && verbose>0)
255 fprintf(stderr, "Notice: some lines omitted.\n");
256 /* We're done */
257 goto save_and_quit;
258 }
259
260 /*
261 * If keys were not given, check if ift2 has only one value to use for all.
262 */
263 if(!key1[0] && !key2[0]) {
264 /* Count how many valid values we can find in file2 */
265 int n=0, u, u2=0;
266 double v, v2=nan("");
267 for(int li=0; li<ift2.keyNr; li++) {
268 ret=iftGetDoubleWithUnit(&ift2, li, &v, &u);
269 if(ret==0 && !isnan(v)) {v2=v; u2=u; n++;}
270 }
271 if(verbose>2) printf("file2 contains %d valid values\n", n);
272 if(n==1) {
273 if(verbose>1) printf("using the single value in file2 for all file1 values\n");
274 double v1, v3;
275 int u1;
276 char newstr[128];
277 int okNr=0;
278 for(int li=0; li<ift1.keyNr; li++) {
279 ret=iftGetDoubleWithUnit(&ift1, li, &v1, &u1);
280 if(ret || isnan(v1)) {
281 if(verbose>1) printf("invalid values in item %d\n", 1+li);
282 continue;
283 }
284 if(verbose>2 && u1!=u2)
285 fprintf(stderr, "Warning: different units\n");
286 v3=doubleOperate(v1, v2, operation);
287 if(u1==UNIT_UNKNOWN) snprintf(newstr, 128, "%g", v3);
288 else snprintf(newstr, 128, "%g %s", v3, unitName(u1));
289 if(verbose>3) printf("new_value := '%s'\n", newstr);
290 if(iftReplaceValue(&ift1, li, newstr, NULL)!=0) continue;
291 okNr++;
292 }
293 if(okNr<1) {
294 fprintf(stderr, "Error: no valid calculations could be done.\n");
295 iftFree(&ift1); iftFree(&ift2);
296 return(4);
297 }
298 if(okNr<ift1.keyNr && verbose>0)
299 fprintf(stderr, "Notice: some lines omitted.\n");
300 /* We're done */
301 goto save_and_quit;
302 }
303 }
304
305 /*
306 * If key names are given, then check that there is one matching key
307 */
308 if(key1[0]) {
309 int n=iftFindNrOfKeys(&ift1, key1);
310 if(n<1) fprintf(stderr, "Error: key '%s' not found in file1.\n", key1);
311 if(n>1) fprintf(stderr, "Error: %d items matching key '%s' found in file1.\n", n, key1);
312 if(n!=1) {
313 iftFree(&ift1); iftFree(&ift2);
314 return(5);
315 }
316 }
317 if(key2[0]) {
318 int n=iftFindNrOfKeys(&ift2, key2);
319 if(n<1) fprintf(stderr, "Error: key '%s' not found in file2.\n", key2);
320 if(n>1) fprintf(stderr, "Error: %d items matching key '%s' found in file2.\n", n, key2);
321 if(n!=1) {
322 iftFree(&ift1); iftFree(&ift2);
323 return(6);
324 }
325 }
326
327 /*
328 * Key given for file2 but not for file1;
329 * use that one value in file2 for all items in file1.
330 */
331 if(key2[0] && !key1[0]) {
332 if(verbose>1) printf("using the specified item in file2 for all file1 values\n");
333 int li, u1, u2;
334 double v1, v2, v3;
335 li=iftFindKey(&ift2, key2, 0);
336 ret=iftGetDoubleWithUnit(&ift2, li, &v2, &u2);
337 if(ret || isnan(v2)) {
338 fprintf(stderr, "Error: invalid value in file2.\n");
339 iftFree(&ift1); iftFree(&ift2);
340 return(6);
341 }
342 char newstr[128];
343 int okNr=0;
344 for(li=0; li<ift1.keyNr; li++) {
345 ret=iftGetDoubleWithUnit(&ift1, li, &v1, &u1);
346 if(ret || isnan(v1)) {
347 if(verbose>1) printf("invalid values in item %d\n", 1+li);
348 continue;
349 }
350 if(verbose>2 && u1!=u2)
351 fprintf(stderr, "Warning: different units\n");
352 v3=doubleOperate(v1, v2, operation);
353 if(u1==UNIT_UNKNOWN) snprintf(newstr, 128, "%g", v3);
354 else snprintf(newstr, 128, "%g %s", v3, unitName(u1));
355 if(verbose>3) printf("new_value := '%s'\n", newstr);
356 if(iftReplaceValue(&ift1, li, newstr, NULL)!=0) continue;
357 okNr++;
358 }
359 if(okNr<1) {
360 fprintf(stderr, "Error: no valid calculations could be done.\n");
361 iftFree(&ift1); iftFree(&ift2);
362 return(4);
363 }
364 if(okNr<ift1.keyNr && verbose>0)
365 fprintf(stderr, "Notice: some lines omitted.\n");
366 /* We're done */
367 goto save_and_quit;
368 }
369
370
371 /*
372 * Key given for both files;
373 * use those items in the files.
374 */
375 if(key2[0] && key1[0]) {
376 if(verbose>1) printf("using the specified item in file1 and file2\n");
377 int li, u1, u2;
378 double v1, v2, v3;
379 li=iftFindKey(&ift2, key2, 0);
380 ret=iftGetDoubleWithUnit(&ift2, li, &v2, &u2);
381 if(ret || isnan(v2)) {
382 fprintf(stderr, "Error: invalid value in file2.\n");
383 iftFree(&ift1); iftFree(&ift2);
384 return(6);
385 }
386 li=iftFindKey(&ift1, key1, 0);
387 ret=iftGetDoubleWithUnit(&ift1, li, &v1, &u1);
388 if(ret || isnan(v1)) {
389 fprintf(stderr, "Error: invalid value in file1.\n");
390 iftFree(&ift1); iftFree(&ift2);
391 return(5);
392 }
393 char newstr[128];
394 if(verbose>2 && u1!=u2)
395 fprintf(stderr, "Warning: different units\n");
396 v3=doubleOperate(v1, v2, operation);
397 if(u1==UNIT_UNKNOWN) snprintf(newstr, 128, "%g", v3);
398 else snprintf(newstr, 128, "%g %s", v3, unitName(u1));
399 if(verbose>3) printf("new_value := '%s'\n", newstr);
400 if(iftReplaceValue(&ift1, li, newstr, NULL)!=0) {
401 fprintf(stderr, "Error: no valid calculations could be done.\n");
402 iftFree(&ift1); iftFree(&ift2);
403 return(4);
404 }
405 /* We're done */
406 goto save_and_quit;
407 }
408
409
410 /*
411 * Key given only for file1;
412 * operate that, if only one value is found in file2,
413 * or if same key is found in file2.
414 */
415 if(key1[0] && !key2[0]) {
416 if(verbose>1) printf("using the specified item in file1\n");
417 int li, u1;
418 double v1;
419 li=iftFindKey(&ift1, key1, 0);
420 ret=iftGetDoubleWithUnit(&ift1, li, &v1, &u1);
421 if(ret || isnan(v1)) {
422 fprintf(stderr, "Error: invalid value in file1.\n");
423 iftFree(&ift1); iftFree(&ift2);
424 return(5);
425 }
426 /* Count how many valid values we can find in file2 */
427 int n=0, u, u2=0, okNr=0;
428 double v, v2=nan("");
429 for(int lj=0; lj<ift2.keyNr; lj++) {
430 ret=iftGetDoubleWithUnit(&ift2, lj, &v, &u);
431 if(ret==0 && !isnan(v)) {v2=v; u2=u; n++;}
432 }
433 if(verbose>2) printf("file2 contains %d valid values\n", n);
434 if(n==0) {
435 fprintf(stderr, "Error: no valid values in file2.\n");
436 iftFree(&ift1); iftFree(&ift2);
437 return(6);
438 } else if(n==1) {
439 if(verbose>1) printf("using the single value in file2\n");
440 double v3;
441 char newstr[128];
442 if(verbose>2 && u1!=u2)
443 fprintf(stderr, "Warning: different units\n");
444 v3=doubleOperate(v1, v2, operation);
445 if(u1==UNIT_UNKNOWN) snprintf(newstr, 128, "%g", v3);
446 else snprintf(newstr, 128, "%g %s", v3, unitName(u1));
447 if(verbose>3) printf("new_value := '%s'\n", newstr);
448 if(iftReplaceValue(&ift1, li, newstr, NULL)==0)
449 okNr++;
450 } else {
451 if(verbose>1) printf("trying to search same key in file2\n");
452 int lj=iftFindKey(&ift2, key1, 0);
453 if(lj<0) {
454 fprintf(stderr, "Error: cannot find matching item in file2.\n");
455 iftFree(&ift1); iftFree(&ift2);
456 return(6);
457 }
458 ret=iftGetDoubleWithUnit(&ift2, lj, &v2, &u2);
459 if(ret || isnan(v2)) {
460 fprintf(stderr, "Error: invalid value in file2.\n");
461 iftFree(&ift1); iftFree(&ift2);
462 return(6);
463 }
464 double v3;
465 char newstr[128];
466 if(verbose>2 && u1!=u2)
467 fprintf(stderr, "Warning: different units\n");
468 v3=doubleOperate(v1, v2, operation);
469 if(u1==UNIT_UNKNOWN) snprintf(newstr, 128, "%g", v3);
470 else snprintf(newstr, 128, "%g %s", v3, unitName(u1));
471 if(verbose>3) printf("new_value := '%s'\n", newstr);
472 if(iftReplaceValue(&ift1, li, newstr, NULL)==0)
473 okNr++;
474 }
475 if(okNr<1) {
476 fprintf(stderr, "Error: no valid calculations could be done.\n");
477 iftFree(&ift1); iftFree(&ift2);
478 return(4);
479 }
480 /* We're done */
481 goto save_and_quit;
482 }
483
484 /*
485 * Other cases not yet working
486 */
487 fprintf(stderr, "Error: no valid calculations could be done.\n");
488 iftFree(&ift1); iftFree(&ift2);
489 return(9);
490
491
492 save_and_quit:
493 /*
494 * Write the modified IFT contents.
495 */
496 if(verbose>1) printf("writing modified IFT in %s\n", iftfile3);
497 fp=fopen(iftfile3, "w"); if(fp==NULL) {
498 fprintf(stderr, "Error: cannot open file %s\n", iftfile3);
499 iftFree(&ift1); iftFree(&ift2); return(11);
500 }
501 ret=iftWrite(&ift1, fp, &status); fclose(fp);
502 if(ret!=TPCERROR_OK) {
503 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
504 iftFree(&ift1); iftFree(&ift2); return(12);
505 }
506
507 iftFree(&ift1); iftFree(&ift2);
508 return(0);
509}
510/*****************************************************************************/
511
512/*****************************************************************************/
void iftFree(IFT *ift)
Definition ift.c:37
int iftReplaceValue(IFT *ift, int i, const char *value, TPCSTATUS *status)
Definition ift.c:268
void iftInit(IFT *ift)
Definition ift.c:21
int iftDelete(IFT *ift, int index)
Definition ift.c:206
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 iftGetDoubleWithUnit(IFT *ift, int index, double *v, int *unit)
Definition iftget.c:129
int iftWrite(IFT *ift, FILE *fp, TPCSTATUS *status)
Definition iftio.c:98
int iftRead(IFT *ift, FILE *fp, int is_key_required, int is_comment_accepted, TPCSTATUS *status)
Definition iftio.c:130
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
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
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.
@ UNIT_UNKNOWN
Unknown unit.
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.