SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddsdiff.c
Go to the documentation of this file.
1/**
2 * @file sddsdiff.c
3 * @brief Compare two SDDS files for differences in definitions and data.
4 *
5 * @details
6 * The program `sddsdiff` compares two SDDS (Self Describing Data Sets) files by analyzing their
7 * definitions (columns, parameters, arrays) and data, supporting various comparison criteria such as
8 * exact matches, numerical tolerances, and absolute differences.
9 * It provides detailed reports on discrepancies in definitions or data values.
10 *
11 * @section Usage
12 * ```
13 * sddsdiff <file1> <file2>
14 * [-compareCommon[=column|parameter|array]]
15 * [-columns=<col1>[,<col2>...]]
16 * [-parameters=<par1>[,<par2>...]]
17 * [-arrays=<array1>[,<array2>...]]
18 * [-tolerance=<value>]
19 * [-relativeTolerance=<value>]
20 * [-precision=<integer>]
21
22 * [-format=float=<string>|double=<string>|longdouble=<string>|string=<string>]
23 * [-exact]
24 * [-absolute]
25 * [-rowlabel=<column-name>[,nocomparison]]
26 * [-ignoreUnits]
27 * ```
28 *
29 * @section Options
30 * | Option | Description |
31 * |----------------------------|-----------------------------------------------------------------------------|
32 * | `-compareCommon` | Compare only common columns, parameters, or arrays. |
33 * | `-columns` | Specify columns to compare. |
34 * | `-parameters` | Specify parameters to compare. |
35 * | `-arrays` | Specify arrays to compare. |
36 * | `-tolerance` | Set absolute numerical comparison tolerance. |
37 * | `-relativeTolerance` | Set relative tolerance using `min(abs(value1), abs(value2)) * value`. |
38 * | `-precision` | Set the precision for numerical comparison. |
39 * | `-format` | Specify the format for printing float, double, long double, or string data.|
40 * | `-exact` | Compare values exactly (mutually exclusive with tolerance and precision). |
41 * | `-absolute` | Compare absolute values. |
42 * | `-rowlabel` | Use a column to label rows for comparison. |
43 * | `-ignoreUnits` | Ignore units during the comparison. |
44 *
45 * @subsection Incompatibilities
46 * - `-exact` is incompatible with:
47 * - `-tolerance`
48 * - `-precision`
49 *
50 * @copyright
51 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
52 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
53 *
54 * @license
55 * This file is distributed under the terms of the Software License Agreement
56 * found in the file LICENSE included with this distribution.
57 *
58 * @author
59 * H. Shang, R. Soliday, L. Emery, M. Borland
60 */
61
62#include "mdb.h"
63#include "SDDS.h"
64#include "scan.h"
65#include "SDDSutils.h"
66#include <float.h>
67
68/* Enumeration for option types */
69enum option_type {
70 CLO_COMPARECOMMON,
71 CLO_COLUMNS,
72 CLO_PARAMETERS,
73 CLO_ARRAYS,
74 CLO_TOLERANCE,
75 CLO_RELATIVE_TOLERANCE,
76 CLO_PRECISION,
77 CLO_FORMAT,
78 CLO_EXACT,
79 CLO_ABSOLUTE,
80 CLO_ROWLABEL,
81 CLO_IGNORE_UNITS,
82 N_OPTIONS
83};
84
85char *option[N_OPTIONS] = {
86 "compareCommon",
87 "columns",
88 "parameters",
89 "arrays",
90 "tolerance",
91 "relativeTolerance",
92 "precision",
93 "format",
94 "exact",
95 "absolute",
96 "rowlabel",
97 "ignoreUnits"};
98
99char *USAGE1 = "Usage: sddsdiff <file1> <file2>\n\
100 [-compareCommon[=column|parameter|array]]\n\
101 [-columns=<col1>[,<col2>...]]\n\
102 [-parameters=<par1][,<par2>...]]\n\
103 [-arrays=<array1>[,<array2>...]]\n\
104 [-tolerance=<value>]\n\
105 [-relativeTolerance=<value>]\n\
106 [-precision=<integer>]\n\
107 [-format=float=<string>|double=<string>|longdouble=<string>|string=<string>]\n\
108 [-exact]\n\
109 [-absolute]\n\
110 [-rowlabel=<column-name>[,nocomparison]]\n\
111 [-ignoreUnits]\n\
112Options:\n\
113 -compareCommon[=column|parameter|array] Compare only the common items.\n\
114 -columns=<col1>[,<col2>...] Specify columns to compare.\n\
115 -parameters=<par1>[,<par2>...] Specify parameters to compare.\n\
116 -arrays=<array1>[,<array2>...] Specify arrays to compare.\n\
117 -tolerance=<value> Set absolute tolerance for numerical comparisons.\n\
118 -relativeTolerance=<value> Set relative tolerance using min(abs(value1), abs(value2))*value.\n\
119 -precision=<integer> Set precision for floating-point comparisons.\n\
120 -format=float=<string> Set print format for float data.\n\
121 -format=double=<string> Set print format for double data.\n\
122 -format=longdouble=<string> Set print format for long double data.\n\
123 -format=string=<string> Set print format for string data.\n\
124 -exact Compare values exactly.\n\
125 -absolute Compare absolute values, ignoring signs.\n\
126 -rowlabel=<column-name>[,nocomparison] Use a column to label rows.\n\
127 -ignoreUnits Do not compare units of items.\n";
128
129char *USAGE2 = "\n\
130Description:\n\
131 sddsdiff compares two SDDS files by checking their definitions and data. It reports differences in columns,\n\
132 parameters, and arrays based on the specified options.\n\
133\n\
134Example:\n\
135 sddsdiff data1.sdds data2.sdds -compareCommon=column -tolerance=1e-5 -absolute\n\
136\n\
137Program by Hairong Shang. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
138
139#define SDDS_COLUMN_TYPE 0
140#define SDDS_PARAMETER_TYPE 1
141#define SDDS_ARRAY_TYPE 2
142/* type=0,1,2 for Column, Parameter, Array */
143long CompareDefinitions(SDDS_DATASET *dataset1, SDDS_DATASET *dataset2, char *file1, char *file2, int32_t *names, char ***name, int32_t **dataType, long type, long compareCommon, char *rowLabelColumn, long notCompareRowLabel, short ignoreUnits);
144long CompareData(SDDS_DATASET *dataset1, SDDS_DATASET *dataset2, char *file1, char *file2, long names, char **name, int32_t *dataType, long type, long page, long double tolerance, long double relativeTolerance, long double precisionTolerance, char *floatFormat, char *doubleFormat, char *ldoubleFormat, char *stringFormat,
145 long absolute, void *rowLabel, long rowLabelType, char *labelName);
146long compare_two_data(void *data1, void *data2, long index, long datatype, long first, long flags, char *name, long page, long double tolerance, long double relativeTolerance, long double precisionTolerance, char *floatFormat, char *doubleFormat, char *ldoubleFormat, char *stringFormat, char *longFormat, char *ulongFormat,
147 char *shortFormat, char *ushortFormat, char *charFormat, long absolute, long parameter, char *labelName);
148void printTitle(long flags, char *name, long page, long absolute, char *labelName);
149
150#define COMPARE_COMMON_COLUMN 0x0001U
151#define COMPARE_COMMON_PARAMETER 0x0002U
152#define COMPARE_COMMON_ARRAY 0x0004U
153
154int main(int argc, char **argv) {
155 SCANNED_ARG *s_arg;
156 SDDS_DATASET table1, table2;
157 char *file1, *file2;
158 long different = 0, i, pages1, pages2, pagediff = 0, i_arg, absolute = 0;
159 int32_t *columnDataType, *parDataType, *arrayDataType;
160 int32_t columns, parameters, arrays, columnMatches, parameterMatches, arrayMatches;
161 int64_t rows1, rows2;
162 char **columnName, **parameterName, **arrayName, **columnMatch, **parameterMatch, **arrayMatch;
163 long column_provided, parameter_provided, array_provided, precision, labelFromSecondFile = 0, rowLabelType = 0, rowLabelIndex = -1, notCompareRowLabel = 0;
164 long double tolerance = 0.0L, relativeTolerance = 0.0L, precisionTolerance = 0.0L;
165 unsigned long compareCommonFlags = 0, dummyFlags = 0;
166 char *floatFormat, *doubleFormat, *ldoubleFormat, *stringFormat, *rowLabelColumn;
167 void *rowLabel;
168 short ignoreUnits = 0;
169
170 rowLabelColumn = NULL;
171 rowLabel = NULL;
172 floatFormat = doubleFormat = ldoubleFormat = stringFormat = NULL;
173 precision = 0;
174 columnDataType = parDataType = arrayDataType = NULL;
175 columnName = parameterName = arrayName = NULL;
176 columnMatch = parameterMatch = arrayMatch = NULL;
177 columnMatches = parameterMatches = arrayMatches = 0;
178 columns = parameters = arrays = 0;
179 file1 = file2 = NULL;
180 pages1 = pages2 = 0;
181 column_provided = parameter_provided = array_provided = 0;
183 argc = scanargs(&s_arg, argc, argv);
184 if (argc < 3) {
185 fprintf(stderr, "%s%s", USAGE1, USAGE2);
186 exit(EXIT_FAILURE);
187 }
188 for (i_arg = 1; i_arg < argc; i_arg++) {
189 if (s_arg[i_arg].arg_type == OPTION) {
190 delete_chars(s_arg[i_arg].list[0], "_");
191 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
192 case CLO_ROWLABEL:
193 if (s_arg[i_arg].n_items < 2)
194 SDDS_Bomb("Invalid -rowlabel syntax");
195 rowLabelColumn = s_arg[i_arg].list[1];
196 if (s_arg[i_arg].n_items > 2 &&
197 strncmp_case_insensitive("nocomparison", s_arg[i_arg].list[2], strlen(s_arg[i_arg].list[2])) == 0)
198 notCompareRowLabel = 1;
199 break;
200 case CLO_EXACT:
201 tolerance = -1.0L;
202 break;
203 case CLO_ABSOLUTE:
204 absolute = 1;
205 break;
206 case CLO_TOLERANCE:
207 if (s_arg[i_arg].n_items != 2)
208 SDDS_Bomb("Invalid -tolerance syntax");
209 if (!get_longdouble(&tolerance, s_arg[i_arg].list[1]))
210 SDDS_Bomb("Invalid -tolerance syntax (not a number given)");
211 break;
212 case CLO_RELATIVE_TOLERANCE:
213 if (s_arg[i_arg].n_items != 2)
214 SDDS_Bomb("Invalid -relativeTolerance syntax");
215 if (!get_longdouble(&relativeTolerance, s_arg[i_arg].list[1]))
216 SDDS_Bomb("Invalid -relativeTolerance syntax (not a number given)");
217 break;
218 case CLO_PRECISION:
219 if (s_arg[i_arg].n_items != 2)
220 SDDS_Bomb("Invalid -precision syntax");
221 if (!get_long(&precision, s_arg[i_arg].list[1]))
222 SDDS_Bomb("Invalid -precision syntax (not a number given)");
223 if (precision < 0)
224 precision = 0;
225 break;
226 case CLO_FORMAT:
227 if (s_arg[i_arg].n_items < 2)
228 SDDS_Bomb("Invalid -format syntax.");
229 s_arg[i_arg].n_items--;
230 if (!scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
231 "float", SDDS_STRING, &floatFormat, 1, 0,
232 "double", SDDS_STRING, &doubleFormat, 1, 0,
233 "longdouble", SDDS_STRING, &ldoubleFormat, 1, 0,
234 "string", SDDS_STRING, &stringFormat, 1, 0, NULL))
235 SDDS_Bomb("Invalid -format syntax");
236 s_arg[i_arg].n_items++;
237 if (floatFormat && !SDDS_VerifyPrintfFormat(floatFormat, SDDS_FLOAT)) {
238 fprintf(stderr, "Error: Given print format (\"%s\") for float data is invalid.\n", floatFormat);
239 exit(EXIT_FAILURE);
240 }
241 if (doubleFormat && !SDDS_VerifyPrintfFormat(doubleFormat, SDDS_DOUBLE)) {
242 fprintf(stderr, "Error: Given print format (\"%s\") for double data is invalid.\n", doubleFormat);
243 exit(EXIT_FAILURE);
244 }
245 if (ldoubleFormat && !SDDS_VerifyPrintfFormat(ldoubleFormat, SDDS_LONGDOUBLE)) {
246 fprintf(stderr, "Error: Given print format (\"%s\") for long double data is invalid.\n", ldoubleFormat);
247 exit(EXIT_FAILURE);
248 }
249 if (stringFormat && !SDDS_VerifyPrintfFormat(stringFormat, SDDS_STRING)) {
250 fprintf(stderr, "Error: Given print format (\"%s\") for string data is invalid.\n", stringFormat);
251 exit(EXIT_FAILURE);
252 }
253 break;
254 case CLO_COMPARECOMMON:
255 if (s_arg[i_arg].n_items == 1)
256 compareCommonFlags |= COMPARE_COMMON_COLUMN | COMPARE_COMMON_PARAMETER | COMPARE_COMMON_ARRAY;
257 else {
258 s_arg[i_arg].n_items--;
259 if (!scanItemList(&compareCommonFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
260 "column", -1, NULL, 0, COMPARE_COMMON_COLUMN,
261 "parameter", -1, NULL, 0, COMPARE_COMMON_PARAMETER,
262 "array", -1, NULL, 0, COMPARE_COMMON_ARRAY, NULL))
263 SDDS_Bomb("Invalid -compareCommon syntax");
264 s_arg[i_arg].n_items++;
265 }
266 break;
267 case CLO_COLUMNS:
268 if (s_arg[i_arg].n_items < 2)
269 SDDS_Bomb("Invalid -columns syntax");
270 columnMatch = tmalloc(sizeof(*columnMatch) * (columnMatches = s_arg[i_arg].n_items - 1));
271 for (i = 0; i < columnMatches; i++)
272 columnMatch[i] = s_arg[i_arg].list[i + 1];
273 column_provided = 1;
274 break;
275 case CLO_PARAMETERS:
276 if (s_arg[i_arg].n_items < 2)
277 SDDS_Bomb("Invalid -parameters syntax");
278 parameterMatch = tmalloc(sizeof(*parameterMatch) * (parameterMatches = s_arg[i_arg].n_items - 1));
279 for (i = 0; i < parameterMatches; i++)
280 parameterMatch[i] = s_arg[i_arg].list[i + 1];
281 parameter_provided = 1;
282 break;
283 case CLO_ARRAYS:
284 if (s_arg[i_arg].n_items < 2)
285 SDDS_Bomb("Invalid -arrays syntax");
286 arrayMatch = tmalloc(sizeof(*arrayMatch) * (arrayMatches = s_arg[i_arg].n_items - 1));
287 for (i = 0; i < arrayMatches; i++)
288 arrayMatch[i] = s_arg[i_arg].list[i + 1];
289 array_provided = 1;
290 break;
291 case CLO_IGNORE_UNITS:
292 ignoreUnits = 1;
293 break;
294 default:
295 fprintf(stderr, "Unknown option given (sddsdiff): %s\n", s_arg[i_arg].list[0]);
296 exit(EXIT_FAILURE);
297 break;
298 }
299 } else {
300 if (!file1)
301 file1 = s_arg[i_arg].list[0];
302 else if (!file2)
303 file2 = s_arg[i_arg].list[0];
304 else
305 SDDS_Bomb("Too many files given.");
306 }
307 }
308 if (!floatFormat)
309 SDDS_CopyString(&floatFormat, "%25.8e");
310 if (!doubleFormat)
311 SDDS_CopyString(&doubleFormat, "%25.16e");
312 if (!ldoubleFormat)
313 SDDS_CopyString(&ldoubleFormat, "%26.18Le");
314 if (!stringFormat)
315 SDDS_CopyString(&stringFormat, "%25s");
316
317 if ((tolerance || relativeTolerance) && precision > 0) {
318 SDDS_Bomb("Tolerance, relativeTolerance, and precision options are not compatible. Only one of tolerance, relativeTolerance, precision, or exact may be given.");
319 }
320 if (tolerance && relativeTolerance) {
321 SDDS_Bomb("Tolerance and relativeTolerance options are not compatible. Only one may be given.");
322 }
323 if (!file1 || !file2) {
324 fprintf(stderr, "Error: Two files must be provided for comparison.\n");
325 exit(EXIT_FAILURE);
326 }
327 if (strcmp(file1, file2) == 0) {
328 printf("\"%s\" and \"%s\" are identical.\n", file1, file2);
329 return EXIT_SUCCESS;
330 }
331 if (!SDDS_InitializeInput(&table1, file1)) {
332 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
333 exit(EXIT_FAILURE);
334 }
335 if (!SDDS_InitializeInput(&table2, file2)) {
336 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
337 exit(EXIT_FAILURE);
338 }
339 if (rowLabelColumn) {
340 if ((rowLabelIndex = SDDS_GetColumnIndex(&table1, rowLabelColumn)) < 0) {
341 if ((rowLabelIndex = SDDS_GetColumnIndex(&table2, rowLabelColumn)) < 0) {
342 fprintf(stdout, "Warning: Row label column \"%s\" does not exist in the input files. The number of rows will be labeled instead.\n", rowLabelColumn);
343 rowLabelColumn = NULL;
344 } else {
345 labelFromSecondFile = 1;
346 notCompareRowLabel = 1;
347 }
348 } else {
349 if (SDDS_GetColumnIndex(&table2, rowLabelColumn) < 0)
350 notCompareRowLabel = 1;
351 }
352
353 if (rowLabelColumn) {
354 if (labelFromSecondFile)
355 rowLabelType = SDDS_GetColumnType(&table2, rowLabelIndex);
356 else
357 rowLabelType = SDDS_GetColumnType(&table1, rowLabelIndex);
358 }
359 }
360 if (!precision) {
361 precisionTolerance = powl(10L, -1L * fabsl(log10l(LDBL_EPSILON)));
362 } else {
363 precisionTolerance = powl(10L, -1L * precision);
364 }
365 if (column_provided) {
366 columnName = getMatchingSDDSNames(&table1, columnMatch, columnMatches, &columns, SDDS_MATCH_COLUMN);
367 if (CompareDefinitions(&table1, &table2, file1, file2, &columns, &columnName, &columnDataType, SDDS_COLUMN_TYPE, compareCommonFlags & COMPARE_COMMON_COLUMN, rowLabelColumn, notCompareRowLabel, ignoreUnits))
368 different = 1;
369 }
370 if (parameter_provided) {
371 parameterName = getMatchingSDDSNames(&table1, parameterMatch, parameterMatches, &parameters, SDDS_MATCH_PARAMETER);
372
373 if (CompareDefinitions(&table1, &table2, file1, file2, &parameters, &parameterName, &parDataType, SDDS_PARAMETER_TYPE, compareCommonFlags & COMPARE_COMMON_PARAMETER, NULL, 1, ignoreUnits))
374 different = 1;
375 }
376 if (array_provided) {
377 arrayName = getMatchingSDDSNames(&table1, arrayMatch, arrayMatches, &arrays, SDDS_MATCH_ARRAY);
378 if (CompareDefinitions(&table1, &table2, file1, file2, &arrays, &arrayName, &arrayDataType, SDDS_ARRAY_TYPE, compareCommonFlags & COMPARE_COMMON_ARRAY, NULL, 1, ignoreUnits))
379 different = 1;
380 }
381 if (!columns && !parameters && !arrays) {
382 if (!compareCommonFlags || compareCommonFlags & COMPARE_COMMON_COLUMN)
383 different += CompareDefinitions(&table1, &table2, file1, file2, &columns, &columnName, &columnDataType, SDDS_COLUMN_TYPE, compareCommonFlags & COMPARE_COMMON_COLUMN, rowLabelColumn, notCompareRowLabel, ignoreUnits);
384 if (!compareCommonFlags || compareCommonFlags & COMPARE_COMMON_PARAMETER)
385 different += CompareDefinitions(&table1, &table2, file1, file2, &parameters, &parameterName, &parDataType, SDDS_PARAMETER_TYPE, compareCommonFlags & COMPARE_COMMON_PARAMETER, NULL, 1, ignoreUnits);
386 if (!compareCommonFlags || compareCommonFlags & COMPARE_COMMON_ARRAY)
387 different += CompareDefinitions(&table1, &table2, file1, file2, &arrays, &arrayName, &arrayDataType, SDDS_ARRAY_TYPE, compareCommonFlags & COMPARE_COMMON_ARRAY, NULL, 1, ignoreUnits);
388 }
389 if (!different) {
390 if (!columns && !parameters && !arrays) {
391 fprintf(stderr, "There are no common columns, parameters, or arrays in the two files.\n");
392 different = 1;
393 } else {
394 /* Definitions are the same, now compare the data */
395 while (1) {
396 pagediff = 0;
397 pages1 = SDDS_ReadPage(&table1);
398 pages2 = SDDS_ReadPage(&table2);
399 if (pages1 > 0 && pages2 > 0) {
400 /* Compare data */
401 rows1 = SDDS_CountRowsOfInterest(&table1);
402 rows2 = SDDS_CountRowsOfInterest(&table2);
403 if (rows1 != rows2) {
404 pagediff = 1;
405 different = 1;
406 fprintf(stderr, "The two files have different numbers of rows on page %ld: \"%s\" has %" PRId64 " rows, while \"%s\" has %" PRId64 " rows.\n",
407 pages1, file1, rows1, file2, rows2);
408 break;
409 } else {
410 if (parameters)
411 pagediff += CompareData(&table1, &table2, file1, file2, parameters, parameterName, parDataType, SDDS_PARAMETER_TYPE, pages1, tolerance, relativeTolerance, precisionTolerance, floatFormat, doubleFormat, ldoubleFormat, stringFormat, absolute, NULL, rowLabelType, NULL);
412
413 if (columns && rows1) {
414 if (rowLabelColumn) {
415 if (labelFromSecondFile) {
416 if (!(rowLabel = SDDS_GetColumn(&table2, rowLabelColumn)))
417 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
418 } else {
419 if (!(rowLabel = SDDS_GetColumn(&table1, rowLabelColumn)))
420 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
421 }
422 }
423 pagediff += CompareData(&table1, &table2, file1, file2, columns, columnName, columnDataType, SDDS_COLUMN_TYPE, pages1, tolerance, relativeTolerance, precisionTolerance, floatFormat, doubleFormat, ldoubleFormat, stringFormat, absolute, rowLabel, rowLabelType, rowLabelColumn);
424 if (rowLabelColumn) {
425 if (rowLabelType == SDDS_STRING)
426 SDDS_FreeStringArray((char **)rowLabel, rows1);
427 else
428 free(rowLabel);
429 rowLabel = NULL;
430 }
431 }
432 if (arrays)
433 pagediff += CompareData(&table1, &table2, file1, file2, arrays, arrayName, arrayDataType, SDDS_ARRAY_TYPE, pages1, tolerance, relativeTolerance, precisionTolerance, floatFormat, doubleFormat, ldoubleFormat, stringFormat, absolute, NULL, rowLabelType, NULL);
434 different += pagediff;
435 }
436 } else if (pages1 > 0 && pages2 <= 0) {
437 fprintf(stderr, "\"%s\" has fewer pages than \"%s\".\n", file2, file1);
438 different = 1;
439 break;
440 } else if (pages1 < 0 && pages2 > 0) {
441 different = 1;
442 fprintf(stderr, "\"%s\" has fewer pages than \"%s\".\n", file1, file2);
443 break;
444 } else {
445 break;
446 }
447 }
448 }
449 } else {
450 different = 1;
451 }
452 if (!different)
453 printf("\"%s\" and \"%s\" are identical.\n", file1, file2);
454 else
455 fprintf(stderr, "\"%s\" and \"%s\" are different.\n", file1, file2);
456
457 if (columns) {
458 for (i = 0; i < columns; i++)
459 free(columnName[i]);
460 free(columnName);
461 free(columnDataType);
462 free(columnMatch);
463 }
464 if (parameters) {
465 for (i = 0; i < parameters; i++)
466 free(parameterName[i]);
467 free(parameterName);
468 free(parDataType);
469 free(parameterMatch);
470 }
471 if (arrays) {
472 for (i = 0; i < arrays; i++)
473 free(arrayName[i]);
474 free(arrayName);
475 free(arrayDataType);
476 free(arrayMatch);
477 }
478 free_scanargs(&s_arg, argc);
479 free(stringFormat);
480 free(floatFormat);
481 free(doubleFormat);
482 free(ldoubleFormat);
483
484 if (!SDDS_Terminate(&table1) || !SDDS_Terminate(&table2)) {
485 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
486 exit(EXIT_FAILURE);
487 }
488 return EXIT_SUCCESS;
489}
490
491long CompareDefinitions(SDDS_DATASET *dataset1, SDDS_DATASET *dataset2, char *file1, char *file2, int32_t *names, char ***name, int32_t **dataType, long type, long compareCommon, char *rowLabelColumn, long notCompareRowLabel, short ignoreUnits) {
492 size_t same_items;
493 long sames, free_same_name = 0;
494 int32_t *same, *datatype;
495 int32_t names1, names2;
496 char **name1, **name2, *def, **same_name;
497 long type1, type2, i, returnValue = 0, first = 1;
498 int32_t index1, index2;
499 char *units1, *units2;
500 units1 = units2 = NULL;
501 name1 = name2 = same_name = NULL;
502 names1 = names2 = 0;
503 def = NULL;
504 same_items = 0;
505 same = datatype = NULL;
506
507 type1 = type2 = -1;
508
509 switch (type) {
510 case SDDS_COLUMN_TYPE:
511 name1 = SDDS_GetColumnNames(dataset1, &names1);
512 name2 = SDDS_GetColumnNames(dataset2, &names2);
513 SDDS_CopyString(&def, "column");
514 break;
515 case SDDS_PARAMETER_TYPE:
516 name1 = SDDS_GetParameterNames(dataset1, &names1);
517 name2 = SDDS_GetParameterNames(dataset2, &names2);
518 SDDS_CopyString(&def, "parameter");
519 break;
520 case SDDS_ARRAY_TYPE:
521 name1 = SDDS_GetArrayNames(dataset1, &names1);
522 name2 = SDDS_GetArrayNames(dataset2, &names2);
523 SDDS_CopyString(&def, "array");
524 break;
525 default:
526 fprintf(stderr, "Unknown type given for CompareDefinitions().\n");
527 return 1;
528 }
529 if (names1 == 0 && names2 == 0)
530 return 0;
531 if (*names) {
532 if (!names1 || !names2) {
533 fprintf(stderr, "Error: One of the files does not have any %s.\n", def);
534 returnValue = 1;
535 }
536 if (!returnValue) {
537 for (i = 0; i < *names; i++) {
538 if (rowLabelColumn && notCompareRowLabel && strcmp((*name)[i], rowLabelColumn) == 0)
539 continue;
540 if (-1 == match_string((*name)[i], name1, names1, EXACT_MATCH)) {
541 fprintf(stderr, "Error: File \"%s\" does not have %s \"%s\".\n", file1, def, (*name)[i]);
542 returnValue = 1;
543 break;
544 }
545 if (-1 == match_string((*name)[i], name2, names2, EXACT_MATCH)) {
546 fprintf(stderr, "Error: File \"%s\" does not have %s \"%s\".\n", file2, def, (*name)[i]);
547 returnValue = 1;
548 break;
549 }
550 }
551 }
552 if (returnValue) {
553 for (i = 0; i < names1; i++)
554 free(name1[i]);
555 free(name1);
556 for (i = 0; i < names2; i++)
557 free(name2[i]);
558 free(name2);
559 free(def);
560 return returnValue;
561 }
562 same_items = *names;
563 same_name = *name;
564 compareCommon = 0;
565 } else {
566 if (!names1 && !names2) {
567 free(def);
568 return 0;
569 }
570 if (compareCommon && (!names1 || !names2)) {
571 if (names1) {
572 for (i = 0; i < names1; i++)
573 free(name1[i]);
574 free(name1);
575 }
576 if (names2) {
577 for (i = 0; i < names2; i++)
578 free(name2[i]);
579 free(name2);
580 }
581 *names = 0;
582 return 0;
583 }
584 if (names1 != names2 && !compareCommon && !notCompareRowLabel)
585 returnValue = 1;
586 if (returnValue) {
587 fprintf(stderr, "Error: Two files have different numbers of %ss:\n \"%s\" has %" PRId32 " %ss while \"%s\" has %" PRId32 " %ss.\n", def, file1, names1, def, file2, names2, def);
588 for (i = 0; i < names2; i++)
589 free(name2[i]);
590 free(name2);
591 for (i = 0; i < names1; i++)
592 free(name1[i]);
593 free(name1);
594 free(def);
595 return returnValue;
596 }
597 same_items = 0;
598 for (i = 0; i < names1; i++) {
599 if (rowLabelColumn && notCompareRowLabel && strcmp(rowLabelColumn, name1[i]) == 0)
600 continue;
601 if (-1 == match_string(name1[i], name2, names2, EXACT_MATCH)) {
602 if (!compareCommon) {
603 if (first) {
604 fprintf(stderr, " Following %ss of \"%s\" are not in \"%s\":\n", def, file1, file2);
605 first = 0;
606 }
607 fprintf(stderr, " %s\n", name1[i]);
608 returnValue++;
609 }
610 } else {
611 same_name = (char **)SDDS_Realloc(same_name, sizeof(*same_name) * (same_items + 1));
612 same_name[same_items] = name1[i];
613 same_items++;
614 }
615 }
616 if (!compareCommon) {
617 if (!first)
618 fprintf(stderr, "\n");
619 first = 1;
620 for (i = 0; i < names2; i++) {
621 if (rowLabelColumn && notCompareRowLabel && strcmp(rowLabelColumn, name2[i]) == 0)
622 continue;
623 if (-1 == match_string(name2[i], name1, names1, EXACT_MATCH)) {
624 if (first) {
625 fprintf(stderr, " Following %ss of \"%s\" are not in \"%s\":\n", def, file2, file1);
626 first = 0;
627 }
628 fprintf(stderr, " %s\n", name2[i]);
629 returnValue++;
630 }
631 }
632 if (!first)
633 fprintf(stderr, "\n");
634 }
635 if (same_items)
636 free_same_name = 1;
637 }
638 sames = same_items;
639 if (same_items) {
640 datatype = (int32_t *)malloc(sizeof(*datatype) * same_items);
641 same = (int32_t *)malloc(sizeof(*same) * same_items);
642 /* Check the units and type */
643 for (i = 0; i < same_items; i++) {
644 same[i] = 1;
645 switch (type) {
646 case SDDS_COLUMN_TYPE:
647 index1 = SDDS_GetColumnIndex(dataset1, same_name[i]);
648 index2 = SDDS_GetColumnIndex(dataset2, same_name[i]);
649 type1 = SDDS_GetColumnType(dataset1, index1);
650 type2 = SDDS_GetColumnType(dataset2, index2);
651 if (!ignoreUnits) {
652 if (SDDS_GetColumnInformation(dataset1, "units", &units1, SDDS_GET_BY_INDEX, index1) != SDDS_STRING) {
653 SDDS_SetError("Units field of column has wrong data type!");
654 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
655 exit(EXIT_FAILURE);
656 }
657 if (SDDS_GetColumnInformation(dataset2, "units", &units2, SDDS_GET_BY_INDEX, index2) != SDDS_STRING) {
658 SDDS_SetError("Units field of column has wrong data type!");
659 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
660 exit(EXIT_FAILURE);
661 }
662 }
663 break;
664 case SDDS_PARAMETER_TYPE:
665 index1 = SDDS_GetParameterIndex(dataset1, same_name[i]);
666 index2 = SDDS_GetParameterIndex(dataset2, same_name[i]);
667 type1 = SDDS_GetParameterType(dataset1, index1);
668 type2 = SDDS_GetParameterType(dataset2, index2);
669 if (!ignoreUnits) {
670 if (SDDS_GetParameterInformation(dataset1, "units", &units1, SDDS_GET_BY_INDEX, index1) != SDDS_STRING) {
671 SDDS_SetError("Units field of parameter has wrong data type!");
672 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
673 exit(EXIT_FAILURE);
674 }
675 if (SDDS_GetParameterInformation(dataset2, "units", &units2, SDDS_GET_BY_INDEX, index2) != SDDS_STRING) {
676 SDDS_SetError("Units field of parameter has wrong data type!");
677 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
678 exit(EXIT_FAILURE);
679 }
680 }
681 break;
682 case SDDS_ARRAY_TYPE:
683 index1 = SDDS_GetArrayIndex(dataset1, same_name[i]);
684 index2 = SDDS_GetArrayIndex(dataset2, same_name[i]);
685 type1 = SDDS_GetArrayType(dataset1, index1);
686 type2 = SDDS_GetArrayType(dataset2, index2);
687 if (!ignoreUnits) {
688 if (SDDS_GetArrayInformation(dataset1, "units", &units1, SDDS_GET_BY_INDEX, index1) != SDDS_STRING) {
689 SDDS_SetError("Units field of array has wrong data type!");
690 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
691 exit(EXIT_FAILURE);
692 }
693 if (SDDS_GetArrayInformation(dataset2, "units", &units2, SDDS_GET_BY_INDEX, index2) != SDDS_STRING) {
694 SDDS_SetError("Units field of array has wrong data type!");
695 SDDS_PrintErrors(stderr, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
696 exit(EXIT_FAILURE);
697 }
698 }
699 break;
700 }
701 datatype[i] = type1;
702 if (type1 != type2) {
703 if (first && !compareCommon) {
704 fprintf(stderr, "The type of the following %ss do not match in the two files:\n", def);
705 fprintf(stderr, "%20s\t%20s\t%20s\n", "Name", file1, file2);
706 first = 0;
707 }
708 if (!compareCommon) {
709 fprintf(stderr, "%20s\t%20s\t%20s\n", same_name[i], SDDS_type_name[type1 - 1], SDDS_type_name[type2 - 1]);
710 returnValue++;
711 }
712 sames--;
713 same[i] = 0;
714 } else if ((units1 && units2 && strcasecmp(units1, units2) != 0) || (units1 && !units2) || (!units1 && units2)) {
715 if (first && !compareCommon) {
716 fprintf(stderr, "The units of the following %ss do not match in the two files:\n", def);
717 fprintf(stderr, "%20s\t%20s\t%20s\n", "Name", file1, file2);
718 first = 0;
719 }
720 if (!compareCommon) {
721 if (units1 && units2)
722 fprintf(stderr, "%20s\t%20s\t%20s\n", same_name[i], units1, units2);
723 else if (units1)
724 fprintf(stderr, "%20s\t%20s\t%20s\n", same_name[i], units1, " ");
725 else if (units2)
726 fprintf(stderr, "%20s\t%20s\t%20s\n", same_name[i], " ", units2);
727 returnValue++;
728 }
729 sames--;
730 same[i] = 0;
731 }
732 free(units1);
733 free(units2);
734 units1 = units2 = NULL;
735 if (returnValue && !compareCommon)
736 break;
737 }
738 if (!compareCommon && returnValue) {
739 sames = 0;
740 }
741 }
742 if (sames) {
743 if (!(*names)) {
744 for (i = 0; i < same_items; i++) {
745 if (same[i]) {
746 *name = (char **)SDDS_Realloc(*name, sizeof(**name) * (*names + 1));
747 *dataType = (int32_t *)SDDS_Realloc(*dataType, sizeof(**dataType) * (*names + 1));
748 SDDS_CopyString(*name + *names, same_name[i]);
749 (*dataType)[*names] = datatype[i];
750 (*names)++;
751 }
752 }
753 free(datatype);
754 } else
755 *dataType = datatype;
756 }
757
758 for (i = 0; i < names2; i++)
759 free(name2[i]);
760 free(name2);
761 for (i = 0; i < names1; i++)
762 free(name1[i]);
763 free(name1);
764 if (same)
765 free(same);
766 if (free_same_name)
767 free(same_name);
768 free(def);
769 return compareCommon ? 0 : returnValue;
770}
771
772long CompareData(SDDS_DATASET *dataset1, SDDS_DATASET *dataset2, char *file1, char *file2,
773 long names, char **name, int32_t *dataType, long type, long page, long double tolerance,
774 long double relativeTolerance, long double precisionTolerance, char *floatFormat, char *doubleFormat, char *ldoubleFormat,
775 char *stringFormat, long absolute, void *rowLabel, long rowLabelType, char *rowLabelColumn) {
776 long diff = 0, i, first = 1;
777 int64_t rows, j;
778 char fFormat[2048], dFormat[2048], ldFormat[2048], strFormat[2048], lFormat[2048], ulFormat[2048], ushortFormat[2048], shortFormat[2048], cFormat[2048], labelFormat[1024];
779 SDDS_ARRAY *array1, *array2;
780 void *data1, *data2;
781
782 array1 = array2 = NULL;
783 data1 = data2 = NULL;
784
785 if (!rowLabel) {
786 snprintf(fFormat, sizeof(fFormat), "%%20ld%s%s%s\n", floatFormat, floatFormat, floatFormat);
787 snprintf(dFormat, sizeof(dFormat), "%%20ld%s%s%s\n", doubleFormat, doubleFormat, doubleFormat);
788 snprintf(ldFormat, sizeof(ldFormat), "%%20ld%s%s%s\n", ldoubleFormat, ldoubleFormat, ldoubleFormat);
789 snprintf(strFormat, sizeof(strFormat), "%%20ld%s%s%%25ld\n", stringFormat, stringFormat);
790 snprintf(lFormat, sizeof(lFormat), "%s", "%20ld%25ld%25ld\n");
791 snprintf(ulFormat, sizeof(ulFormat), "%s", "%20ld%25lu%25lu%25ld\n");
792 snprintf(shortFormat, sizeof(shortFormat), "%s", "%20ld%25hd%25hd%25hd\n");
793 snprintf(ushortFormat, sizeof(ushortFormat), "%s", "%20ld%25hu%25hu%25hd\n");
794 snprintf(cFormat, sizeof(cFormat), "%s", "%20ld%25c%25c%25d\n");
795 }
796 switch (type) {
797 case SDDS_COLUMN_TYPE:
798 rows = SDDS_CountRowsOfInterest(dataset1);
799 if (!rows)
800 break;
801 for (i = 0; i < names; i++) {
802 first = 1;
803 if (!(data1 = SDDS_GetColumn(dataset1, name[i])) || !(data2 = SDDS_GetColumn(dataset2, name[i]))) {
804 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
805 exit(EXIT_FAILURE);
806 }
807 for (j = 0; j < rows; j++) {
808 if (rowLabel) {
809 switch (rowLabelType) {
810 case SDDS_STRING:
811 snprintf(labelFormat, sizeof(labelFormat), "%20s", ((char **)rowLabel)[j]);
812 break;
813 case SDDS_LONGDOUBLE:
814 snprintf(labelFormat, sizeof(labelFormat), "%20.15Le", ((long double *)rowLabel)[j]);
815 break;
816 case SDDS_DOUBLE:
817 snprintf(labelFormat, sizeof(labelFormat), "%20.10e", ((double *)rowLabel)[j]);
818 break;
819 case SDDS_FLOAT:
820 snprintf(labelFormat, sizeof(labelFormat), "%20.5e", ((float *)rowLabel)[j]);
821 break;
822 case SDDS_ULONG64:
823 snprintf(labelFormat, sizeof(labelFormat), "%20" PRIu64, ((uint64_t *)rowLabel)[j]);
824 break;
825 case SDDS_LONG64:
826 snprintf(labelFormat, sizeof(labelFormat), "%20" PRId64, ((int64_t *)rowLabel)[j]);
827 break;
828 case SDDS_ULONG:
829 snprintf(labelFormat, sizeof(labelFormat), "%20" PRIu32, ((uint32_t *)rowLabel)[j]);
830 break;
831 case SDDS_LONG:
832 snprintf(labelFormat, sizeof(labelFormat), "%20" PRId32, ((int32_t *)rowLabel)[j]);
833 break;
834 case SDDS_USHORT:
835 snprintf(labelFormat, sizeof(labelFormat), "%20hu", ((unsigned short *)rowLabel)[j]);
836 break;
837 case SDDS_SHORT:
838 snprintf(labelFormat, sizeof(labelFormat), "%20hd", ((short *)rowLabel)[j]);
839 break;
840 case SDDS_CHARACTER:
841 snprintf(labelFormat, sizeof(labelFormat), "%20c", ((char *)rowLabel)[j]);
842 break;
843 default:
844 fprintf(stderr, "Unknown data type for rowlabel.\n");
845 exit(EXIT_FAILURE);
846 }
847 snprintf(fFormat, sizeof(fFormat), "%s%s%s%s\n", labelFormat, floatFormat, floatFormat, floatFormat);
848 snprintf(dFormat, sizeof(dFormat), "%s%s%s%s\n", labelFormat, doubleFormat, doubleFormat, doubleFormat);
849 snprintf(ldFormat, sizeof(ldFormat), "%s%s%s%s\n", labelFormat, ldoubleFormat, ldoubleFormat, ldoubleFormat);
850 snprintf(strFormat, sizeof(strFormat), "%s%s%s%%25ld\n", labelFormat, stringFormat, stringFormat);
851 snprintf(lFormat, sizeof(lFormat), "%s%%25ld%%25ld%%25ld\n", labelFormat);
852 snprintf(ulFormat, sizeof(ulFormat), "%s%%25lu%%25lu%%25ld\n", labelFormat);
853 snprintf(shortFormat, sizeof(shortFormat), "%s%%25hd%%25hd%%25hd\n", labelFormat);
854 snprintf(ushortFormat, sizeof(ushortFormat), "%s%%25hu%%25hu%%25hd\n", labelFormat);
855 snprintf(cFormat, sizeof(cFormat), "%s%%25c%%25c%%25d\n", labelFormat);
856 }
857 if (compare_two_data(data1, data2, j, dataType[i], first, SDDS_COLUMN_TYPE, name[i], page, tolerance, relativeTolerance, precisionTolerance, fFormat, dFormat, ldFormat, strFormat, lFormat, ulFormat, shortFormat, ushortFormat, cFormat, absolute, 0, rowLabelColumn) != 0) {
858 diff++;
859 if (first)
860 first = 0;
861 }
862 if (dataType[i] == SDDS_STRING) {
863 free((char *)((char **)data1)[j]);
864 free((char *)((char **)data2)[j]);
865 }
866 }
867 free((char **)data1);
868 free((char **)data2);
869 data1 = data2 = NULL;
870 }
871 break;
872 case SDDS_PARAMETER_TYPE:
873 for (i = 0; i < names; i++) {
874 first = 1;
875 if (!(data1 = SDDS_GetParameter(dataset1, name[i], NULL)) || !(data2 = SDDS_GetParameter(dataset2, name[i], NULL))) {
876 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
877 exit(EXIT_FAILURE);
878 }
879 if (compare_two_data(data1, data2, 0, dataType[i], first, SDDS_PARAMETER_TYPE, name[i], page, tolerance, relativeTolerance, precisionTolerance, fFormat, dFormat, ldFormat, strFormat, lFormat, ulFormat, shortFormat, ushortFormat, cFormat, absolute, 1, NULL) != 0) {
880 diff++;
881 if (first)
882 first = 0;
883 }
884 if (dataType[i] == SDDS_STRING) {
885 free(*((char **)data1));
886 free(*((char **)data2));
887 }
888 free(data1);
889 free(data2);
890 data1 = data2 = NULL;
891 }
892 break;
893 case SDDS_ARRAY_TYPE:
894 for (i = 0; i < names; i++) {
895 first = 1;
896 if (!(array1 = SDDS_GetArray(dataset1, name[i], NULL)) || !(array2 = SDDS_GetArray(dataset2, name[i], NULL))) {
897 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
898 exit(EXIT_FAILURE);
899 }
900 if (array1->elements != array2->elements) {
901 fprintf(stderr, "Array \"%s\" has %" PRId32 " elements in \"%s\", but %" PRId32 " elements in \"%s\".\n", name[i], array1->elements, file1, array2->elements, file2);
902 diff++;
903 } else {
904 for (j = 0; j < array1->elements; j++) {
905 if (compare_two_data(array1->data, array2->data, j, dataType[i], first, SDDS_ARRAY_TYPE, name[i], page, tolerance, relativeTolerance, precisionTolerance, fFormat, dFormat, ldFormat, strFormat, lFormat, ulFormat, shortFormat, ushortFormat, cFormat, absolute, 0, NULL) != 0) {
906 diff++;
907 if (first)
908 first = 0;
909 }
910 }
911 }
912 SDDS_FreeArray(array1);
913 SDDS_FreeArray(array2);
914 array1 = array2 = NULL;
915 }
916 break;
917 }
918 return diff;
919}
920
921void printTitle(long flags, char *name, long page, long absolute, char *labelName) {
922 char *type = NULL;
923 char *element = NULL;
924
925 switch (flags) {
926 case SDDS_COLUMN_TYPE:
927 SDDS_CopyString(&type, "column");
928 if (labelName)
929 SDDS_CopyString(&element, labelName);
930 else
931 SDDS_CopyString(&element, "row");
932 break;
933 case SDDS_PARAMETER_TYPE:
934 SDDS_CopyString(&type, "parameter");
935 SDDS_CopyString(&element, "page number");
936 break;
937 case SDDS_ARRAY_TYPE:
938 SDDS_CopyString(&type, "array");
939 SDDS_CopyString(&element, "element number");
940 break;
941 }
942 if (type) {
943 fprintf(stdout, "\nDifferences found in %s \"%s\" on page %ld:\n", type, name, page);
944 if (absolute)
945 fprintf(stdout, "%20s%25s%25s%25s\n", element, "Value in file1", "Value in file2", "Difference (abs)");
946 else
947 fprintf(stdout, "%20s%25s%25s%25s\n", element, "Value in file1", "Value in file2", "Difference (file1 - file2)");
948 free(type);
949 free(element);
950 }
951}
952
953long compare_two_data(void *data1, void *data2, long index, long datatype,
954 long first, long flags, char *name, long page,
955 long double tolerance, long double relativeTolerance, long double precisionTolerance,
956 char *floatFormat, char *doubleFormat, char *ldoubleFormat,
957 char *stringFormat, char *longFormat, char *ulongFormat,
958 char *shortFormat, char *ushortFormat, char *charFormat,
959 long absolute, long parameter, char *labelName) {
960 char *str1, *str2;
961 long double ldval1, ldval2, ldenominator, ldabs1, ldabs2, lddiff;
962 double dval1, dval2, denominator, dabs1, dabs2, ddiff;
963 float fval1, fval2, fabs1, fabs2, fdenominator, fdiff;
964 int32_t lval1, lval2, labs1, labs2, ldiff, uldiff;
965 uint32_t ulval1, ulval2;
966 int64_t llval1, llval2, llabs1, llabs2, lldiff, ulldiff;
967 uint64_t ullval1, ullval2;
968 short sval1, sval2, sabs1, sabs2, sdiff, usdiff;
969 unsigned short usval1, usval2;
970 char cval1, cval2;
971 long returnValue = 0, printIndex;
972 long double tol, scale;
973
974 printIndex = index + 1;
975 if (parameter)
976 printIndex = page;
977
978 if (tolerance < 0)
979 tol = 0L;
980 else
981 tol = tolerance;
982
983 switch (datatype) {
984 case SDDS_STRING:
985 str1 = *((char **)data1 + index);
986 str2 = *((char **)data2 + index);
987 returnValue = strcmp(trim_spaces(str1), trim_spaces(str2));
988 if (returnValue != 0) {
989 if (first)
990 printTitle(flags, name, page, absolute, labelName);
991 if (labelName) {
992 fprintf(stdout, stringFormat, str1, str2, returnValue);
993 } else
994 fprintf(stdout, stringFormat, printIndex, str1, str2, returnValue);
995 }
996 break;
997 case SDDS_LONGDOUBLE:
998 ldval1 = *((long double *)data1 + index);
999 ldval2 = *((long double *)data2 + index);
1000 if (absolute) {
1001 ldabs1 = fabsl(ldval1);
1002 ldabs2 = fabsl(ldval2);
1003 } else {
1004 ldabs1 = ldval1;
1005 ldabs2 = ldval2;
1006 }
1007 lddiff = ldabs1 - ldabs2;
1008 if ((isnan(ldval1) && !isnan(ldval2)) || (isinf(ldval1) && !isinf(ldval2)))
1009 returnValue = 1;
1010 else if (ldabs1 != ldabs2) {
1011 if (relativeTolerance) {
1012 scale = MIN(fabsl(ldval1), fabsl(ldval2));
1013 if (fabsl(lddiff) > scale * relativeTolerance)
1014 returnValue = 1;
1015 } else if (tolerance) {
1016 if (fabsl(lddiff) > tol)
1017 returnValue = 1;
1018 } else {
1019 if (ldabs1 == 0L || ldabs2 == 0L) {
1020 if (fabsl(ldabs1 - ldabs2) > precisionTolerance)
1021 returnValue = 1;
1022 } else {
1023 ldabs1 = fabsl(ldval1);
1024 ldabs2 = fabsl(ldval2);
1025 ldenominator = (ldabs1 < ldabs2) ? ldabs1 : ldabs2;
1026 if (fabsl(ldval1 - ldval2) / ldenominator > precisionTolerance)
1027 returnValue = 1;
1028 }
1029 }
1030 }
1031 if (returnValue) {
1032 if (first)
1033 printTitle(flags, name, page, absolute, labelName);
1034 if (labelName)
1035 fprintf(stdout, ldoubleFormat, ldval1, ldval2, lddiff);
1036 else
1037 fprintf(stdout, ldoubleFormat, printIndex, ldval1, ldval2, lddiff);
1038 }
1039 break;
1040 case SDDS_DOUBLE:
1041 dval1 = *((double *)data1 + index);
1042 dval2 = *((double *)data2 + index);
1043 if (absolute) {
1044 dabs1 = fabs(dval1);
1045 dabs2 = fabs(dval2);
1046 } else {
1047 dabs1 = dval1;
1048 dabs2 = dval2;
1049 }
1050 ddiff = dabs1 - dabs2;
1051 if ((isnan(dval1) && !isnan(dval2)) || (isinf(dval1) && !isinf(dval2)))
1052 returnValue = 1;
1053 else if (dabs1 != dabs2) {
1054 if (relativeTolerance) {
1055 scale = MIN(fabs(dval1), fabs(dval2));
1056 if (fabs(ddiff) > scale * relativeTolerance)
1057 returnValue = 1;
1058 } else if (tolerance) {
1059 if (fabs(ddiff) > tol)
1060 returnValue = 1;
1061 } else {
1062 if (dabs1 == 0 || dabs2 == 0) {
1063 if (fabs(dabs1 - dabs2) > precisionTolerance)
1064 returnValue = 1;
1065 } else {
1066 dabs1 = fabs(dval1);
1067 dabs2 = fabs(dval2);
1068 denominator = (dabs1 < dabs2) ? dabs1 : dabs2;
1069 if (fabs(dval1 - dval2) / denominator > precisionTolerance)
1070 returnValue = 1;
1071 }
1072 }
1073 }
1074 if (returnValue) {
1075 if (first)
1076 printTitle(flags, name, page, absolute, labelName);
1077 if (labelName)
1078 fprintf(stdout, doubleFormat, dval1, dval2, ddiff);
1079 else
1080 fprintf(stdout, doubleFormat, printIndex, dval1, dval2, ddiff);
1081 }
1082 break;
1083 case SDDS_FLOAT:
1084 fval1 = *((float *)data1 + index);
1085 fval2 = *((float *)data2 + index);
1086 if (absolute) {
1087 fabs1 = fabs(fval1);
1088 fabs2 = fabs(fval2);
1089 } else {
1090 fabs1 = fval1;
1091 fabs2 = fval2;
1092 }
1093 fdiff = fabs1 - fabs2;
1094 if ((isnan(fval1) && !isnan(fval2)) || (isinf(fval1) && !isinf(fval2)))
1095 returnValue = 1;
1096 else if (fabs1 != fabs2) {
1097 if (relativeTolerance) {
1098 scale = MIN(fabs(fval1), fabs(fval2));
1099 if (fabs(fdiff) > scale * relativeTolerance)
1100 returnValue = 1;
1101 } else if (tolerance) {
1102 if (fabs(fdiff) > tol)
1103 returnValue = 1;
1104 } else {
1105 if (fabs1 == 0 || fabs2 == 0) {
1106 if (fabs(fabs1 - fabs2) > precisionTolerance)
1107 returnValue = 1;
1108 } else {
1109 fabs1 = fabs(fval1);
1110 fabs2 = fabs(fval2);
1111 fdenominator = (fabs1 < fabs2) ? fabs1 : fabs2;
1112 if (fabs(fval1 - fval2) / fdenominator > precisionTolerance)
1113 returnValue = 1;
1114 }
1115 }
1116 }
1117 if (returnValue) {
1118 if (first)
1119 printTitle(flags, name, page, absolute, labelName);
1120 if (labelName)
1121 fprintf(stdout, floatFormat, fval1, fval2, fdiff);
1122 else
1123 fprintf(stdout, floatFormat, printIndex, fval1, fval2, fdiff);
1124 }
1125 break;
1126 case SDDS_ULONG64:
1127 ullval1 = *((uint64_t *)data1 + index);
1128 ullval2 = *((uint64_t *)data2 + index);
1129 ulldiff = ullval1 - ullval2;
1130 if (labs(ulldiff) > tol)
1131 returnValue = 1;
1132 if (returnValue) {
1133 if (first)
1134 printTitle(flags, name, page, absolute, labelName);
1135 if (labelName)
1136 fprintf(stdout, ulongFormat, ullval1, ullval2, ulldiff);
1137 else
1138 fprintf(stdout, ulongFormat, printIndex, ullval1, ullval2, ulldiff);
1139 }
1140 break;
1141 case SDDS_LONG64:
1142 llval1 = *((int64_t *)data1 + index);
1143 llval2 = *((int64_t *)data2 + index);
1144 if (absolute) {
1145 llabs1 = labs(llval1);
1146 llabs2 = labs(llval2);
1147 } else {
1148 llabs1 = llval1;
1149 llabs2 = llval2;
1150 }
1151 lldiff = llabs1 - llabs2;
1152 if (llabs(lldiff) > tol)
1153 returnValue = 1;
1154 if (returnValue) {
1155 if (first)
1156 printTitle(flags, name, page, absolute, labelName);
1157 if (labelName)
1158 fprintf(stdout, longFormat, llval1, llval2, lldiff);
1159 else
1160 fprintf(stdout, longFormat, printIndex, llval1, llval2, lldiff);
1161 }
1162 break;
1163 case SDDS_ULONG:
1164 ulval1 = *((uint32_t *)data1 + index);
1165 ulval2 = *((uint32_t *)data2 + index);
1166 uldiff = ulval1 - ulval2;
1167 if (labs(uldiff) > tol)
1168 returnValue = 1;
1169 if (returnValue) {
1170 if (first)
1171 printTitle(flags, name, page, absolute, labelName);
1172 if (labelName)
1173 fprintf(stdout, ulongFormat, ulval1, ulval2, uldiff);
1174 else
1175 fprintf(stdout, ulongFormat, printIndex, ulval1, ulval2, uldiff);
1176 }
1177 break;
1178 case SDDS_LONG:
1179 lval1 = *((int32_t *)data1 + index);
1180 lval2 = *((int32_t *)data2 + index);
1181 if (absolute) {
1182 labs1 = abs(lval1);
1183 labs2 = abs(lval2);
1184 } else {
1185 labs1 = lval1;
1186 labs2 = lval2;
1187 }
1188 ldiff = labs1 - labs2;
1189 if (labs(ldiff) > tol)
1190 returnValue = 1;
1191 if (returnValue) {
1192 if (first)
1193 printTitle(flags, name, page, absolute, labelName);
1194 if (labelName)
1195 fprintf(stdout, longFormat, lval1, lval2, ldiff);
1196 else
1197 fprintf(stdout, longFormat, printIndex, lval1, lval2, ldiff);
1198 }
1199 break;
1200 case SDDS_SHORT:
1201 sval1 = *((short *)data1 + index);
1202 sval2 = *((short *)data2 + index);
1203 if (absolute) {
1204 sabs1 = abs(sval1);
1205 sabs2 = abs(sval2);
1206 } else {
1207 sabs1 = sval1;
1208 sabs2 = sval2;
1209 }
1210 sdiff = sabs1 - sabs2;
1211 if (abs(sdiff) > tol)
1212 returnValue = 1;
1213 if (returnValue) {
1214 if (first)
1215 printTitle(flags, name, page, absolute, labelName);
1216 if (labelName)
1217 fprintf(stdout, shortFormat, sval1, sval2, sdiff);
1218 else
1219 fprintf(stdout, shortFormat, printIndex, sval1, sval2, sdiff);
1220 }
1221 break;
1222 case SDDS_USHORT:
1223 usval1 = *((unsigned short *)data1 + index);
1224 usval2 = *((unsigned short *)data2 + index);
1225 usdiff = usval1 - usval2;
1226 if (abs(usdiff) > tol)
1227 returnValue = 1;
1228 if (returnValue) {
1229 if (first)
1230 printTitle(flags, name, page, absolute, labelName);
1231 if (labelName)
1232 fprintf(stdout, ushortFormat, usval1, usval2, usdiff);
1233 else
1234 fprintf(stdout, ushortFormat, printIndex, usval1, usval2, usdiff);
1235 }
1236 break;
1237 case SDDS_CHARACTER:
1238 cval1 = *((char *)data1 + index);
1239 cval2 = *((char *)data2 + index);
1240 if (cval1 != cval2) {
1241 returnValue = 1;
1242 if (first)
1243 printTitle(flags, name, page, absolute, labelName);
1244 if (labelName)
1245 fprintf(stdout, charFormat, cval1, cval2, cval1 - cval2);
1246 else
1247 fprintf(stdout, charFormat, printIndex, cval1, cval2, cval1 - cval2);
1248 }
1249 break;
1250 default:
1251 fprintf(stderr, "Unknown data type %ld.\n", datatype);
1252 exit(EXIT_FAILURE);
1253 }
1254 return returnValue;
1255}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
char * SDDS_type_name[SDDS_NUM_TYPES]
Array of supported data type names.
Definition SDDS_data.c:43
void * SDDS_GetColumn(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves a copy of the data for a specified column, including only rows marked as "of interest".
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
SDDS_ARRAY * SDDS_GetArray(SDDS_DATASET *SDDS_dataset, char *array_name, SDDS_ARRAY *memory)
Retrieves an array from the current data table of an SDDS dataset.
void * SDDS_GetParameter(SDDS_DATASET *SDDS_dataset, char *parameter_name, void *memory)
Retrieves the value of a specified parameter from the current data table of a data set.
int32_t SDDS_GetArrayInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified array in the SDDS dataset.
Definition SDDS_info.c:192
int32_t SDDS_GetParameterInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified parameter in the SDDS dataset.
Definition SDDS_info.c:117
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
Definition SDDS_info.c:41
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:50
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
void SDDS_FreeArray(SDDS_ARRAY *array)
Frees memory allocated for an SDDS array structure.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:421
int32_t SDDS_GetParameterType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a parameter in the SDDS dataset by its index.
int32_t SDDS_VerifyPrintfFormat(const char *string, int32_t type)
Verifies that a printf format string is compatible with a specified data type.
Definition SDDS_utils.c:816
int32_t SDDS_GetArrayIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named array in the SDDS dataset.
char ** getMatchingSDDSNames(SDDS_DATASET *dataset, char **matchName, int32_t matches, int32_t *names, short type)
Retrieves an array of matching SDDS entity names based on specified criteria.
char ** SDDS_GetParameterNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all parameters in the SDDS dataset.
int32_t SDDS_GetParameterIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named parameter in the SDDS dataset.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
char ** SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all columns in the SDDS dataset.
int32_t SDDS_GetArrayType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of an array in the SDDS dataset by its index.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:474
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a column in the SDDS dataset by its index.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
char ** SDDS_GetArrayNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all arrays in the SDDS dataset.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
Definition SDDS_utils.c:922
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:743
#define SDDS_ULONG
Identifier for the unsigned 32-bit integer data type.
Definition SDDStypes.h:67
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_ULONG64
Identifier for the unsigned 64-bit integer data type.
Definition SDDStypes.h:55
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_CHARACTER
Identifier for the character data type.
Definition SDDStypes.h:91
#define SDDS_USHORT
Identifier for the unsigned short integer data type.
Definition SDDStypes.h:79
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_LONGDOUBLE
Identifier for the long double data type.
Definition SDDStypes.h:31
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49
Utility functions for SDDS dataset manipulation and string array operations.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:65
int get_longdouble(long double *dptr, char *s)
Parses a long double value from the given string.
Definition data_scan.c:88
int get_long(long *iptr, char *s)
Parses a long integer value from the given string.
Definition data_scan.c:255
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int strncmp_case_insensitive(char *s1, char *s2, long n)
Compares up to a specified number of characters of two strings in a case-insensitive manner.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:588
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
char * trim_spaces(char *s)
Trims leading and trailing spaces from a string.
Definition trim_spaces.c:28