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