494 {
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
506
507
508 argc =
scanargs(&s_arg, argc, argv);
509 if (!s_arg || argc < 2) {
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
527 for (i_arg = 1; i_arg < argc; i_arg++) {
528 if (s_arg[i_arg].arg_type == OPTION) {
529
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))
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]))
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))
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:
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)
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}
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
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)