SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddscheck.c
Go to the documentation of this file.
1/**
2 * @file sddscheck.c
3 * @brief Validates and checks an SDDS file for corruption or issues.
4 *
5 * @details
6 * This program reads one or more SDDS (Self Describing Data Set) files and determines their validity.
7 * It processes each file by verifying its structure, pages, and data, and outputs the status:
8 * - `"ok"` if the file is valid.
9 * - `"nonexistent"` if the file does not exist.
10 * - `"badHeader"` if the file has an invalid header.
11 * - `"corrupted"` if the file contains errors.
12 * For multiple files, each output line is prefixed with the corresponding file name.
13 *
14 * @section Usage
15 * ```
16 * sddscheck [options] <filename|directory> [<filename|directory>...]
17 * ```
18 *
19 * @section Options
20 * | Option | Description |
21 * |---------------------------------------|---------------------------------------------------------------------------------------|
22 * | `-printErrors` | Outputs detailed error messages to stderr. |
23 * | `-threads=<number>` | Number of input files to check concurrently. |
24 * | `-summary` | Prints aggregate counts after per-file output. |
25 * | `-failuresOnly` | Suppresses `ok` results. |
26 * | `-failOnError` | Exits nonzero if any checked file is not `ok`. |
27 * | `-recursive` | Recursively expands directory arguments. |
28 * | `-pattern=<glob>` | Filters directory expansion by file-name wildcard. |
29 * | `-maxErrors=<number>` | Stops after the specified number of failed files. |
30 * | `-showPages` | Adds the number of pages read to each result line. |
31 * | `-checkDefinitionsOnly` | Validates only the SDDS header and definitions. |
32 * | `-verbose` | Adds file size and SDDS layout metadata to each result line. |
33 * | `-stdin` | Reads file or directory names from standard input. |
34 *
35 * @copyright
36 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
37 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
38 *
39 * @license
40 * This file is distributed under the terms of the Software License Agreement
41 * found in the file LICENSE included with this distribution.
42 *
43 * @author
44 * M. Borland, C. Saunders, R. Soliday
45 */
46
47#include "mdb.h"
48#include "SDDS.h"
49#include "scan.h"
50
51#include <errno.h>
52#include <limits.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <sys/stat.h>
57
58#if defined(_WIN32) && !defined(_MINGW) && !defined(S_ISDIR)
59# define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR)
60#endif
61#if defined(_WIN32) && !defined(_MINGW) && !defined(S_ISREG)
62# define S_ISREG(mode) (((mode) & _S_IFMT) == _S_IFREG)
63#endif
64
65#if !defined(_WIN32) || defined(_MINGW)
66# include <dirent.h>
67# include <unistd.h>
68# define SDDSCHECK_USE_DIRENT 1
69#else
70# include <windows.h>
71# define SDDSCHECK_USE_DIRENT 0
72#endif
73
74#if defined(_OPENMP)
75# include <omp.h>
76# define SDDSCHECK_USE_OPENMP 1
77#else
78# define SDDSCHECK_USE_OPENMP 0
79#endif
80
81typedef enum {
82 CLO_PRINTERRORS = 0,
83 CLO_THREADS,
84 CLO_SUMMARY,
85 CLO_FAILURESONLY,
86 CLO_FAILONERROR,
87 CLO_RECURSIVE,
88 CLO_PATTERN,
89 CLO_MAXERRORS,
90 CLO_SHOWPAGES,
91 CLO_CHECKDEFINITIONSONLY,
92 CLO_VERBOSE,
93 CLO_STDIN
94} OptionType;
95
96#define N_OPTIONS 12
97
98static char *option[N_OPTIONS] = {
99 "printErrors",
100 "threads",
101 "summary",
102 "failuresOnly",
103 "failOnError",
104 "recursive",
105 "pattern",
106 "maxErrors",
107 "showPages",
108 "checkDefinitionsOnly",
109 "verbose",
110 "stdin"
111};
112
113typedef enum {
114 CHECK_OK = 0,
115 CHECK_NONEXISTENT,
116 CHECK_BADHEADER,
117 CHECK_CORRUPTED
118} CheckStatus;
119
120typedef struct {
121 char **item;
122 long items;
123 long allocated;
124} StringList;
125
126typedef struct {
127 long checkDefinitionsOnly;
129
130typedef struct {
131 int checked;
132 CheckStatus status;
133 long pagesRead;
134 long long sizeBytes;
135 int sizeKnown;
136 int dataMode;
137 int columns;
138 int parameters;
139 int arrays;
140 int associates;
141 int metadataKnown;
143
144char *usage =
145 "sddscheck [options] <filename|directory> [<filename|directory>...]\n\n"
146 "This program allows you to determine whether SDDS files have been\n"
147 "corrupted. It reads the entire file and prints a message to stdout.\n"
148 "\n"
149 "If the file is ok, \"ok\" is printed.\n"
150 "If the file has a problem, one of the following will be printed:\n"
151 " - \"nonexistent\": The file does not exist.\n"
152 " - \"badHeader\": The file header is invalid.\n"
153 " - \"corrupted\": The file contains errors.\n"
154 "If multiple files are provided, each output line is prefixed with the file name.\n"
155 "\n"
156 "Options:\n"
157 " -printErrors: Deliver error messages to stderr.\n"
158 " -threads=<number>: Number of input files to check concurrently (default: 1).\n"
159 " -summary: Print aggregate status counts after per-file output.\n"
160 " -failuresOnly: Suppress ok result lines.\n"
161 " -failOnError: Exit with status 1 if any checked file is not ok.\n"
162 " -recursive: Recursively expand directory arguments.\n"
163 " -pattern=<glob>: Include only matching base names during directory expansion.\n"
164 " May be repeated. If omitted with -recursive, all files are included.\n"
165 " -maxErrors=<number>: Stop starting new checks after this many failed files.\n"
166 " -showPages: Add pagesRead=<number> to each result line.\n"
167 " -checkDefinitionsOnly: Validate only SDDS header and definitions.\n"
168 " -verbose: Add file size, page count, and SDDS layout metadata.\n"
169 " -stdin: Read additional file or directory names from standard input.\n"
170 "\n"
171 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
172
173static void *checkedMalloc(size_t size) {
174 void *ptr;
175 if (size == 0)
176 size = 1;
177 ptr = malloc(size);
178 if (!ptr)
179 SDDS_Bomb("memory allocation failure");
180 return ptr;
181}
182
183static void *checkedRealloc(void *ptr, size_t size) {
184 if (size == 0)
185 size = 1;
186 ptr = realloc(ptr, size);
187 if (!ptr)
188 SDDS_Bomb("memory allocation failure");
189 return ptr;
190}
191
192static char *checkedStrdup(const char *text) {
193 char *copy;
194 size_t length;
195 if (!text)
196 text = "";
197 length = strlen(text) + 1;
198 copy = checkedMalloc(length);
199 memcpy(copy, text, length);
200 return copy;
201}
202
203static int parseLongOptionValue(const char *text, long minimum, long maximum, long *value) {
204 char *endptr;
205 long parsed;
206
207 if (!text || !*text)
208 return 0;
209 errno = 0;
210 parsed = strtol(text, &endptr, 10);
211 if (errno == ERANGE || endptr == text || *endptr || parsed < minimum || parsed > maximum)
212 return 0;
213 *value = parsed;
214 return 1;
215}
216
217static void stringListAppend(StringList *list, const char *text) {
218 if (list->items >= list->allocated) {
219 list->allocated = list->allocated ? 2 * list->allocated : 16;
220 list->item = checkedRealloc(list->item, sizeof(*list->item) * list->allocated);
221 }
222 list->item[list->items++] = checkedStrdup(text);
223}
224
225static void stringListFree(StringList *list) {
226 long i;
227 for (i = 0; i < list->items; i++)
228 free(list->item[i]);
229 free(list->item);
230 memset(list, 0, sizeof(*list));
231}
232
233static int compareStringPointers(const void *left, const void *right) {
234 const char *const *leftString = left;
235 const char *const *rightString = right;
236 return strcmp(*leftString, *rightString);
237}
238
239static const char *checkStatusString(CheckStatus status) {
240 switch (status) {
241 case CHECK_OK:
242 return "ok";
243 case CHECK_NONEXISTENT:
244 return "nonexistent";
245 case CHECK_BADHEADER:
246 return "badHeader";
247 case CHECK_CORRUPTED:
248 return "corrupted";
249 }
250 return "corrupted";
251}
252
253static const char *dataModeString(int mode) {
254 switch (mode) {
255 case SDDS_BINARY:
256 return "binary";
257 case SDDS_ASCII:
258 return "ascii";
259 case SDDS_PARALLEL:
260 return "parallel";
261 default:
262 return "unknown";
263 }
264}
265
266static const char *baseName(const char *path) {
267 const char *slash;
268 const char *backslash;
269
270 slash = strrchr(path, '/');
271 backslash = strrchr(path, '\\');
272 if (backslash && (!slash || backslash > slash))
273 slash = backslash;
274 return slash ? slash + 1 : path;
275}
276
277static int matchesPatterns(const char *path, const StringList *patterns) {
278 long i;
279 const char *name;
280
281 if (!patterns->items)
282 return 1;
283 name = baseName(path);
284 for (i = 0; i < patterns->items; i++) {
285 if (wild_match((char *)name, patterns->item[i]))
286 return 1;
287 }
288 return 0;
289}
290
291static int isDirectory(const char *path) {
292 struct stat statBuffer;
293 if (stat(path, &statBuffer) != 0)
294 return 0;
295 return S_ISDIR(statBuffer.st_mode);
296}
297
298static char *joinPath(const char *directory, const char *name) {
299 char *path;
300 size_t directoryLength, nameLength, length;
301 int needsSlash;
302
303 directoryLength = strlen(directory);
304 nameLength = strlen(name);
305 needsSlash = directoryLength && directory[directoryLength - 1] != '/' && directory[directoryLength - 1] != '\\';
306 length = directoryLength + needsSlash + nameLength + 1;
307 path = checkedMalloc(length);
308 snprintf(path, length, "%s%s%s", directory, needsSlash ? "/" : "", name);
309 return path;
310}
311
312static void collectDirectoryFiles(const char *directory, long recursive, const StringList *patterns, StringList *files) {
313 StringList entries = {NULL, 0, 0};
314 long i;
315
316#if SDDSCHECK_USE_DIRENT
317 DIR *dir;
318 struct dirent *entry;
319
320 dir = opendir(directory);
321 if (!dir) {
322 fprintf(stderr, "warning: unable to read directory %s: %s\n", directory, strerror(errno));
323 return;
324 }
325
326 while ((entry = readdir(dir))) {
327 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
328 continue;
329 stringListAppend(&entries, entry->d_name);
330 }
331 closedir(dir);
332#elif defined(_WIN32)
333 WIN32_FIND_DATAA entry;
334 HANDLE findHandle;
335 char *searchPattern;
336 DWORD error;
337
338 searchPattern = joinPath(directory, "*");
339 findHandle = FindFirstFileA(searchPattern, &entry);
340 if (findHandle == INVALID_HANDLE_VALUE) {
341 error = GetLastError();
342 if (error != ERROR_FILE_NOT_FOUND && error != ERROR_PATH_NOT_FOUND)
343 fprintf(stderr, "warning: unable to read directory %s: Windows error %lu\n",
344 directory, (unsigned long)error);
345 free(searchPattern);
346 return;
347 }
348
349 do {
350 if (strcmp(entry.cFileName, ".") == 0 || strcmp(entry.cFileName, "..") == 0 ||
351 (entry.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
352 continue;
353 stringListAppend(&entries, entry.cFileName);
354 } while (FindNextFileA(findHandle, &entry));
355 error = GetLastError();
356 if (error != ERROR_NO_MORE_FILES)
357 fprintf(stderr, "warning: unable to finish reading directory %s: Windows error %lu\n",
358 directory, (unsigned long)error);
359 FindClose(findHandle);
360 free(searchPattern);
361#else
362 (void)directory;
363 (void)recursive;
364 (void)patterns;
365 (void)files;
366 SDDS_Bomb("-recursive and directory -pattern expansion are not supported on this platform");
367#endif
368
369 if (entries.items > 1)
370 qsort(entries.item, entries.items, sizeof(*entries.item), compareStringPointers);
371
372 for (i = 0; i < entries.items; i++) {
373 char *path;
374 struct stat statBuffer;
375
376 path = joinPath(directory, entries.item[i]);
377#if SDDSCHECK_USE_DIRENT
378 if (lstat(path, &statBuffer) != 0) {
379#else
380 if (stat(path, &statBuffer) != 0) {
381#endif
382 free(path);
383 continue;
384 }
385 if (S_ISDIR(statBuffer.st_mode)) {
386 if (recursive)
387 collectDirectoryFiles(path, recursive, patterns, files);
388 } else if (S_ISREG(statBuffer.st_mode) && matchesPatterns(path, patterns)) {
389 stringListAppend(files, path);
390 }
391 free(path);
392 }
393 stringListFree(&entries);
394}
395
396static void readInputNamesFromStdin(StringList *input) {
397 char buffer[4096];
398
399 while (fgets(buffer, sizeof(buffer), stdin)) {
400 size_t length = strlen(buffer);
401 while (length && (buffer[length - 1] == '\n' || buffer[length - 1] == '\r'))
402 buffer[--length] = 0;
403 if (!length)
404 continue;
405 stringListAppend(input, buffer);
406 }
407}
408
409static CheckResult checkFile(char *input, const CheckOptions *options, long print_errors) {
410 SDDS_DATASET SDDS_input;
411 CheckResult result;
412 struct stat statBuffer;
413 long retval;
414
415 memset(&result, 0, sizeof(result));
416 result.checked = 1;
417 result.status = CHECK_CORRUPTED;
418 result.dataMode = 0;
419
420 if (stat(input, &statBuffer) != 0) {
421 result.status = CHECK_NONEXISTENT;
422 return result;
423 }
424 result.sizeKnown = 1;
425 result.sizeBytes = (long long)statBuffer.st_size;
426
427 if (!SDDS_InitializeInput(&SDDS_input, input)) {
428 if (print_errors)
429 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
430 else
432 result.status = CHECK_BADHEADER;
433 return result;
434 }
435
436 result.metadataKnown = 1;
437 result.dataMode = SDDS_input.layout.data_mode.mode;
438 result.columns = SDDS_input.layout.n_columns;
439 result.parameters = SDDS_input.layout.n_parameters;
440 result.arrays = SDDS_input.layout.n_arrays;
441 result.associates = SDDS_input.layout.n_associates;
442
443 if (options->checkDefinitionsOnly) {
444 result.status = CHECK_OK;
445 SDDS_Terminate(&SDDS_input);
446 return result;
447 }
448
449 while ((retval = SDDS_ReadPage(&SDDS_input)) > 0) {
450 /* Loop continues until EOF or an error occurs. */
451 result.pagesRead++;
452 }
453
454 if (retval == -1) {
455 SDDS_Terminate(&SDDS_input);
456 result.status = CHECK_OK;
457 return result;
458 }
459
460 if (print_errors)
461 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
462 else
464 SDDS_Terminate(&SDDS_input);
465 result.status = CHECK_CORRUPTED;
466 return result;
467}
468
469static void printCheckResult(const char *input, const CheckResult *result, long singleResult, long showPages, long verbose) {
470 if (singleResult && !showPages && !verbose) {
471 puts(checkStatusString(result->status));
472 return;
473 }
474
475 printf("%s: %s", input, checkStatusString(result->status));
476 if (showPages || verbose)
477 printf(" pagesRead=%ld", result->pagesRead);
478 if (verbose) {
479 if (result->sizeKnown)
480 printf(" sizeBytes=%lld", result->sizeBytes);
481 if (result->metadataKnown) {
482 printf(" dataMode=%s columns=%d parameters=%d arrays=%d associates=%d",
483 dataModeString(result->dataMode), result->columns, result->parameters, result->arrays, result->associates);
484 }
485 }
486 putchar('\n');
487}
488
489static void printSummary(long checked, long *statusCounts) {
490 printf("checked: %ld ok: %ld nonexistent: %ld badHeader: %ld corrupted: %ld\n",
491 checked, statusCounts[CHECK_OK], statusCounts[CHECK_NONEXISTENT], statusCounts[CHECK_BADHEADER], statusCounts[CHECK_CORRUPTED]);
492}
493
494int main(int argc, char **argv) {
495 StringList rawInput = {NULL, 0, 0};
496 StringList input = {NULL, 0, 0};
497 StringList patterns = {NULL, 0, 0};
498 CheckOptions checkOptions;
499 CheckResult *result;
500 long i_arg, print_errors, threads, summary, failuresOnly, failOnError, recursive, useStdin, maxErrors, showPages, verbose;
501 long checked, failures, statusCounts[4];
502 SCANNED_ARG *s_arg;
503
504 /* Register the program name for error reporting. */
506
507 /* Parse command-line arguments. */
508 argc = scanargs(&s_arg, argc, argv);
509 if (!s_arg || argc < 2) {
510 bomb(NULL, usage); /* Display usage and exit if arguments are insufficient. */
511 }
512
513 memset(&checkOptions, 0, sizeof(checkOptions));
514 memset(statusCounts, 0, sizeof(statusCounts));
515 print_errors = 0;
516 threads = 1;
517 summary = 0;
518 failuresOnly = 0;
519 failOnError = 0;
520 recursive = 0;
521 useStdin = 0;
522 maxErrors = 0;
523 showPages = 0;
524 verbose = 0;
525
526 /* Process each command-line argument. */
527 for (i_arg = 1; i_arg < argc; i_arg++) {
528 if (s_arg[i_arg].arg_type == OPTION) {
529 /* Match recognized options. */
530 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
531 case CLO_PRINTERRORS:
532 print_errors = 1;
533 break;
534 case CLO_THREADS:
535 if (s_arg[i_arg].n_items != 2 ||
536 !parseLongOptionValue(s_arg[i_arg].list[1], 1, INT_MAX, &threads))
537 SDDS_Bomb("invalid -threads syntax");
538 break;
539 case CLO_SUMMARY:
540 summary = 1;
541 break;
542 case CLO_FAILURESONLY:
543 failuresOnly = 1;
544 break;
545 case CLO_FAILONERROR:
546 failOnError = 1;
547 break;
548 case CLO_RECURSIVE:
549 recursive = 1;
550 break;
551 case CLO_PATTERN:
552 if (s_arg[i_arg].n_items != 2 || !strlen(s_arg[i_arg].list[1]))
553 SDDS_Bomb("invalid -pattern syntax");
554 stringListAppend(&patterns, s_arg[i_arg].list[1]);
555 break;
556 case CLO_MAXERRORS:
557 if (s_arg[i_arg].n_items != 2 ||
558 !parseLongOptionValue(s_arg[i_arg].list[1], 1, LONG_MAX, &maxErrors))
559 SDDS_Bomb("invalid -maxErrors syntax");
560 break;
561 case CLO_SHOWPAGES:
562 showPages = 1;
563 break;
564 case CLO_CHECKDEFINITIONSONLY:
565 checkOptions.checkDefinitionsOnly = 1;
566 break;
567 case CLO_VERBOSE:
568 verbose = 1;
569 break;
570 case CLO_STDIN:
571 useStdin = 1;
572 break;
573 default:
574 SDDS_Bomb("unknown option given"); /* Handle unrecognized options. */
575 break;
576 }
577 } else {
578 stringListAppend(&rawInput, s_arg[i_arg].list[0]);
579 }
580 }
581
582 if (useStdin)
583 readInputNamesFromStdin(&rawInput);
584
585 if (rawInput.items < 1)
586 bomb(NULL, usage);
587
588 for (i_arg = 0; i_arg < rawInput.items; i_arg++) {
589 if ((recursive || patterns.items) && isDirectory(rawInput.item[i_arg]))
590 collectDirectoryFiles(rawInput.item[i_arg], recursive, &patterns, &input);
591 else
592 stringListAppend(&input, rawInput.item[i_arg]);
593 }
594
595 result = checkedMalloc(sizeof(*result) * input.items);
596 memset(result, 0, sizeof(*result) * input.items);
597 checked = 0;
598 failures = 0;
599
600 if (input.items == 1 && !summary && !failuresOnly && !showPages && !verbose) {
601 result[0] = checkFile(input.item[0], &checkOptions, 0);
602 checked = 1;
603 statusCounts[result[0].status]++;
604 failures = result[0].status != CHECK_OK;
605 if (print_errors && result[0].status == CHECK_CORRUPTED)
606 checkFile(input.item[0], &checkOptions, 1);
607 printCheckResult(input.item[0], &result[0], 1, showPages, verbose);
608 if (print_errors && result[0].status == CHECK_BADHEADER)
609 checkFile(input.item[0], &checkOptions, 1);
610 free(result);
611 stringListFree(&patterns);
612 stringListFree(&rawInput);
613 stringListFree(&input);
614 return (failOnError && failures) ? 1 : 0;
615 }
616
617 if (threads <= 1 || input.items <= 1) {
618 for (i_arg = 0; i_arg < input.items; i_arg++) {
619 result[i_arg] = checkFile(input.item[i_arg], &checkOptions, print_errors);
620 checked++;
621 statusCounts[result[i_arg].status]++;
622 if (result[i_arg].status != CHECK_OK) {
623 failures++;
624 if (maxErrors && failures >= maxErrors)
625 break;
626 }
627 }
628 } else {
629 long sharedFailures = 0;
630 if (threads > input.items)
631 threads = input.items;
632#if SDDSCHECK_USE_OPENMP
633 omp_set_num_threads((int)threads);
634#pragma omp parallel for schedule(dynamic)
635 for (i_arg = 0; i_arg < input.items; i_arg++) {
636 long failuresSeen = 0;
637 if (maxErrors) {
638#pragma omp critical(sddscheck_failures)
639 {
640 failuresSeen = sharedFailures;
641 }
642 if (failuresSeen >= maxErrors)
643 continue;
644 }
645 result[i_arg] = checkFile(input.item[i_arg], &checkOptions, 0);
646 if (maxErrors && result[i_arg].status != CHECK_OK) {
647#pragma omp critical(sddscheck_failures)
648 {
649 sharedFailures++;
650 }
651 }
652 }
653#else
654 for (i_arg = 0; i_arg < input.items; i_arg++) {
655 if (maxErrors && sharedFailures >= maxErrors)
656 break;
657 result[i_arg] = checkFile(input.item[i_arg], &checkOptions, 0);
658 if (result[i_arg].status != CHECK_OK)
659 sharedFailures++;
660 }
661#endif
662 if (print_errors) {
663 for (i_arg = 0; i_arg < input.items; i_arg++) {
664 if (result[i_arg].checked && result[i_arg].status != CHECK_OK && result[i_arg].status != CHECK_NONEXISTENT)
665 checkFile(input.item[i_arg], &checkOptions, 1);
666 }
667 }
668 for (i_arg = 0; i_arg < input.items; i_arg++) {
669 if (!result[i_arg].checked)
670 continue;
671 checked++;
672 statusCounts[result[i_arg].status]++;
673 if (result[i_arg].status != CHECK_OK)
674 failures++;
675 }
676 }
677
678 for (i_arg = 0; i_arg < input.items; i_arg++) {
679 if (!result[i_arg].checked)
680 continue;
681 if (failuresOnly && result[i_arg].status == CHECK_OK)
682 continue;
683 printCheckResult(input.item[i_arg], &result[i_arg], input.items == 1, showPages, verbose);
684 }
685 if (summary)
686 printSummary(checked, statusCounts);
687
688 free(result);
689 stringListFree(&patterns);
690 stringListFree(&rawInput);
691 stringListFree(&input);
692 return (failOnError && failures) ? 1 : 0;
693}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
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_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:474
void SDDS_ClearErrors()
Clears all recorded error messages from the SDDS error stack.
Definition SDDS_utils.c:354
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:380
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
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 scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
int wild_match(char *string, char *template)
Determine whether one string is a wildcard match for another.
Definition wild_match.c:49