147 {
148 SCANNED_ARG *s_arg;
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) {
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)
188 rowLabelColumn = s_arg[i_arg].list[1];
189 if (s_arg[i_arg].n_items > 2 &&
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)
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)
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)
216 s_arg[i_arg].n_items--;
217 if (!
scanItemList(&dummyFlags, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
223 s_arg[i_arg].n_items++;
225 fprintf(stderr, "Error: Given print format (\"%s\") for float data is invalid.\n", floatFormat);
226 exit(EXIT_FAILURE);
227 }
229 fprintf(stderr, "Error: Given print format (\"%s\") for double data is invalid.\n", doubleFormat);
230 exit(EXIT_FAILURE);
231 }
233 fprintf(stderr, "Error: Given print format (\"%s\") for long double data is invalid.\n", ldoubleFormat);
234 exit(EXIT_FAILURE);
235 }
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)
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)
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)
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
293 }
294 }
295 if (!floatFormat)
297 if (!doubleFormat)
299 if (!ldoubleFormat)
301 if (!stringFormat)
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 }
317 exit(EXIT_FAILURE);
318 }
321 exit(EXIT_FAILURE);
322 }
323 if (rowLabelColumn) {
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 {
334 notCompareRowLabel = 1;
335 }
336
337 if (rowLabelColumn) {
338 if (labelFromSecondFile)
340 else
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, ¶meters, SDDS_MATCH_PARAMETER);
356
357 if (CompareDefinitions(&table1, &table2, file1, file2, ¶meters, ¶meterName, &parDataType, SDDS_PARAMETER_TYPE, compareCommonFlags & COMPARE_COMMON_PARAMETER, NULL, 1, ignoreUnits))
358 different = 1;
359 }
360 if (array_provided) {
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, ¶meters, ¶meterName, &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
379 while (1) {
380 pagediff = 0;
383 if (pages1 > 0 && pages2 > 0) {
384
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) {
401 } else {
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) {
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 }
462 free(stringFormat);
463 free(floatFormat);
464 free(doubleFormat);
465 free(ldoubleFormat);
466
469 exit(EXIT_FAILURE);
470 }
471 return EXIT_SUCCESS;
472}
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
int32_t SDDS_VerifyPrintfFormat(const char *string, int32_t type)
Verifies that a printf format string is compatible with a specified data type.
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.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
int get_longdouble(long double *dptr, char *s)
Parses a long double value from the given string.
int get_long(long *iptr, char *s)
Parses a long integer value from the given string.
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
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)
void free_scanargs(SCANNED_ARG **scanned, int argc)
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.