Hashing cmdline strings added.
[skeinsum.git] / skein_cli.c
index 82b2ae3a59922be03c84ee35dba4548c272e2899..e95f4b60844f9e90db443def874a87c9e453d678 100644 (file)
@@ -31,23 +31,25 @@ along with skeinsum. If not, see <http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include "SHA3api_ref.h"
 
+#define WARN(msg, ...) fprintf(stderr, "skein%dsum: " msg, hashbitlen, ##__VA_ARGS__)
+
+#define TRYHELP_GOODBYE() do { printf("Try 'skein%dsum --help' for more information.\n", hashbitlen); exit(1); } while(0)
+
+typedef long long unsigned LLU;
+
 extern const int hashbitlen;
 
-#define MaxNmberFiles 10
 #define skeinVersion "1.3"
+
 const size_t input_minbufsize = 32 * 1024;
 const size_t input_maxbufsize = 32 * 1024 * 1024;
 
 
-char invalidOption = 0;
-
 enum
 {
   QUIET_OPTION = 11,
   STATUS_OPTION,
-  TAG_OPTION,
-  HELP_OPTION,
-  VERSION_OPTION
+  TAG_OPTION
 };
 
 static struct option const long_options[] =
@@ -59,57 +61,43 @@ static struct option const long_options[] =
   { "text",    no_argument, NULL, 't' },
   { "warn",    no_argument, NULL, 'w' },
   { "tag",     no_argument, NULL, TAG_OPTION },
-  { "help",    no_argument, NULL, HELP_OPTION },
-  { "version", no_argument, NULL, VERSION_OPTION },
+  { "help",    no_argument, NULL, 'h' },
+  { "version", no_argument, NULL, 'V' },
   { NULL, 0, NULL, 0 }
 };
 
-void printHexMsg(unsigned char *ptr, int size, char result[])
+void hash2hexstr(unsigned char hash[], char str[])
 {
-       int i = 0;
-       int j = 0;
-       char High, Low;
-       for (i = 0 ; i < size ; i ++)
-       {
-               High = ptr[i]>>4;
-               Low = ptr[i]&0x0F;
-
-               if (High >= 0xA && High <= 0xF)
-                       High += 0x37;
-               else if(High >= 0x0 && High <= 0x9)
-                       High += 0x30;
-
-               if (Low >= 0xA && Low <= 0xF)
-                       Low += 0x37;
-               else if(Low >= 0x0 && Low <= 0x9)
-                       Low += 0x30;
-
-               result[j++] = High;
-               result[j++] = Low;
+       int i;
+       for (i = 0; i < hashbitlen / 8; i++) {
+               sprintf(&str[i * 2], "%02X", hash[i]);
        }
-       result[i] = 0;
+       str[i * 2 + 1] = '\0';
 }
 
-int HashWithMode(char file_name[], char MsgDigest[], char mode)
+int HashFile(const char file_name[], char MsgDigest[], char mode)
 {
+       int is_stdin = (strcmp(file_name, "-") == 0);
+
        /* Try to get file info */
        struct stat st;
-       if (stat(file_name, &st) < 0) {
-               printf("skein%dsum: %s: STAT FAILED: %s\n", hashbitlen, file_name, strerror(errno));
+       st.st_size = 0;  /* ..needed when reading from stdio */
+       if (!is_stdin && stat(file_name, &st) < 0) {
+               WARN("%s: cannot stat: %s\n", file_name, strerror(errno));
                return -1;
        }
 
        /* Get filesize */
        size_t fsize = st.st_size;
        if (fsize != st.st_size) {
-               printf("skein%dsum: %s: SIZE WARNING: filesize %llu is too big for reading into memory!\n",
-                       hashbitlen, file_name, (long long unsigned)st.st_size);
+               WARN("%s: SIZE WARNING: filesize %llu is too big for reading into memory!\n",
+                       file_name, (long long unsigned)st.st_size);
        }
 
        /* Open file */
-       FILE *fp_in = fopen(file_name, (mode == 't' ? "r" : "rb") );
+       FILE *fp_in = is_stdin ? stdin : fopen(file_name, (mode == 't' ? "r" : "rb") );
        if (!fp_in) {
-               printf("skein%dsum: %s: OPEN FAILED: %s\n", hashbitlen, file_name, strerror(errno));
+               WARN("%s: cannot open: %s\n", file_name, strerror(errno));
                return -1;
        }
 
@@ -125,30 +113,37 @@ int HashWithMode(char file_name[], char MsgDigest[], char mode)
        }
 
        if (!readbuf) {
-               printf("skein%dsum: %s: MEM FAILED: %s\n", hashbitlen, file_name, strerror(errno));
-               fclose(fp_in);
+               WARN("%s: MEM FAILED: error %s\n", file_name, strerror(errno));
+               if (!is_stdin)
+                       fclose(fp_in);
                return -1;
        }
 
        /* Read contents */
-       size_t readpos = 0, readed, total_readed = 0;
+       size_t readpos = 0, total_readed = 0;
 
        while (1) {
                size_t maxread = bufsize - readpos;
-               readed = fread(readbuf, 1, maxread, fp_in);
+               size_t readed = fread(readbuf + readpos, 1, maxread, fp_in);
                if (readed > 0 && readed <= maxread)
                        total_readed += readed;
                if (readed != maxread)
                        break;
                if (getenv("SKEIN_DEBUG"))
-                       printf("DEBUG: bufsize=%u (0x%x), readpos=%u (0x%x), maxread=%u (0x%x), total=%u (0x%x)\n",
-                               bufsize, bufsize, readpos, readpos, maxread, maxread, total_readed, total_readed);
+                       printf("DEBUG: bufsize=%llu (0x%llx), readpos=%llu (0x%llx), maxread=%llu (0x%llx), total=%llu (0x%llx)\n",
+                               (LLU)bufsize, (LLU)bufsize, (LLU)readpos, (LLU)readpos,
+                               (LLU)maxread, (LLU)maxread, (LLU)total_readed, (LLU)total_readed);
                char *newbuf = NULL;
                if (bufsize * 2 > bufsize)  /* ..check overflow */
                        newbuf = realloc(readbuf, bufsize * 2);
                if (!newbuf) {
-                       printf("skein%dsum: %s: MEM WARNING: %u bytes only readed from %llu\n",
-                               hashbitlen, file_name, total_readed, (long long unsigned)st.st_size);
+                       if (total_readed < st.st_size) {
+                               WARN("%s: MEM WARNING: %llu bytes only readed from %llu\n",
+                                       file_name, (LLU)total_readed, (LLU)st.st_size);
+                       } else {
+                               WARN("%s: MEM WARNING: %llu bytes only readed.\n",
+                                       file_name, (LLU)total_readed);
+                       }
                        break;
                }
                readbuf = newbuf;
@@ -156,66 +151,78 @@ int HashWithMode(char file_name[], char MsgDigest[], char mode)
                bufsize *= 2;
        }
 
-       if (total_readed < st.st_size && total_readed < bufsize) {
-               printf("skein%dsum: %s: READ WARNING: filesize=%llu, readed=%u, %s\n",
-                       hashbitlen, file_name, (long long unsigned)st.st_size, total_readed, strerror(errno));
+       if (!is_stdin)
+               fclose(fp_in);
+
+       if (!is_stdin && total_readed < st.st_size && total_readed < bufsize) {
+               WARN("%s: READ WARNING: filesize=%llu, readed=%llu, error %d, %s\n",
+                       file_name, (LLU)st.st_size, (LLU)total_readed, errno, strerror(errno));
        }
 
-       fclose(fp_in);
+       if (getenv("SKEIN_DUMP")) {
+               printf("DEBUG: file=%s, bufsize=%llu (0x%llx), total_readed=%llu, buf:\n",
+                       file_name, (LLU)bufsize, (LLU)bufsize, (LLU)total_readed);
+               fwrite(readbuf, 1, total_readed, stdout);
+       }
 
        unsigned char output[hashbitlen/4];
        Hash(hashbitlen, (unsigned char*) readbuf, total_readed, output);
 
        free(readbuf);
 
-       printHexMsg(output,hashbitlen/4,MsgDigest);
+       hash2hexstr(output, MsgDigest);
 
        return 1;
 }
 
-int HashTextMode(char file_name[], char MsgDigest[])
+int PrintFileHash(const char filename[], int tag, char mode)
 {
-       return HashWithMode(file_name, MsgDigest, 't');
-}
-
-int HashBinaryMode(char file_name[], char MsgDigest[])
-{
-       return HashWithMode(file_name, MsgDigest, 'b');
+       char MsgDigest[hashbitlen/2];
+       if (HashFile(filename, MsgDigest, mode) < 0)
+               return -1;
+       if (tag == 1) {
+               printf("skein%d_v%s (%s) = %s\n", hashbitlen, skeinVersion, filename, MsgDigest);
+       } else {
+               printf("%s %s%s\n", MsgDigest, (mode == 'b' ? "*" : ""), filename);
+       }
+       return 1;
 }
 
-void HashStringMode(char Msg[],char MsgDigest[])
+/* Return: -1 = Error, 0 = Mismatch, 1 = Match */
+int HashMatch(const char StoredDigest[], const char *filename, int quiet)
 {
-       unsigned char output[hashbitlen/4];
-       Hash(hashbitlen,(unsigned char*) Msg,sizeof(Msg),output);
-       printHexMsg(output,hashbitlen/4,MsgDigest);
-}
+       char mode = 't';
+       if (filename[0] == '*') {
+               filename++;
+               mode = 'b';
+       }
+       
+       char MsgDigest[hashbitlen/2];
+       if (HashFile(filename, MsgDigest, mode) < 0)
+               return -1;
 
-void HashStdin(char MsgDigest[], int tag)
-{
-       char stri[100];
-       char longstring[1000];
-       longstring[0] = 0;
-       while(fgets(stri,100,stdin))
-               strcat(longstring, stri);
-       HashStringMode(longstring, MsgDigest);
-       if (tag) {
-               printf("skein%d_v%s (-) = %s\n", hashbitlen, skeinVersion, MsgDigest);
-       } else {
-               printf("%s *-\n", MsgDigest);
+       if (strcmp(MsgDigest, StoredDigest)) {
+               printf("%s: FAILED\n", filename);
+               return 0;
        }
+
+       if (quiet > 0)
+               printf("%s: OK\n", filename);
+       return 1;
 }
 
-int isProper(char MsgDigest[])
+int isProper(const char MsgDigest[])
 {
-       if ((strlen(MsgDigest) - hashbitlen/4) != 0)
+       int len = strlen(MsgDigest);
+       if (len != (hashbitlen / 4))
                return 0;
        int index = 0;
-       char c = 0;
-       for(index = 0; index < strlen(MsgDigest);index++)
+       for (index = 0; index < len; index++)
        {
-               c = MsgDigest[index];
-               if(!(( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'F')))
-                       return 0;
+               char c = MsgDigest[index];
+               if (c >= '0' && c <= '9') continue;
+               if (c >= 'A' && c <= 'F') continue;
+               return 0;
        }
 
        return 1;
@@ -307,6 +314,58 @@ int decomposeHashLine(char hash[], char MsgDigest_tmp[], char file_tmp[])
 
 }
 
+/* Return: -1 = some errors/mismatches, 1 = all ok */
+int VerifyHashesFromFile(FILE *fp, int status, int warn, int quiet)
+{
+       char hash[PATH_MAX + hashbitlen/4 + 4];
+       char MsgDigest_tmp[hashbitlen/2];
+       int NoMatch = 0, NotProper = 0, Computed = 0;
+       int line = 0;
+
+       while (fgets(hash, sizeof(hash)-1, fp))
+       {
+               char file_tmp[PATH_MAX];
+               line ++;
+               Computed++;
+               int hashVersion = decomposeHashLine(hash,MsgDigest_tmp,file_tmp);
+               if (hashVersion == -1)
+               {
+                       WARN("%s is using newer version of skein%d algorithm\n"
+                            "You should update your algorithm\n",
+                            file_tmp, hashbitlen);
+                       continue;
+               }
+               else if (hashVersion == 0)
+               {
+                       WARN("%s is using an older version of skein%d algorithm\n"
+                            "You should use the older algorithm\n",
+                            file_tmp, hashbitlen);
+                       continue;
+               }
+               else if (!isProper(MsgDigest_tmp))
+               {
+                       if(status != 1 && warn == 1)
+                               WARN("%s: %d: improperly formatted skein%d checksum line\n",file_tmp,line,hashbitlen);
+                       NotProper ++;
+                       NoMatch ++;
+               }
+               else if (HashMatch(MsgDigest_tmp, file_tmp, quiet) <= 0)
+               {
+                       NoMatch++;
+               }
+       }
+       if(NoMatch)
+       {
+               WARN("WARNING: %d of %d computed checksums did NOT match\n",
+                       NoMatch, Computed);
+       }
+       if(NotProper)
+       {
+               WARN("WARNING: %d line is improperly formatted\n", NotProper);
+       }
+       return (NotProper || NoMatch) ? -1 : 1;
+}
+
 void print_version(void)
 {
        printf("skein%dsum 1.0\n", hashbitlen);
@@ -321,37 +380,62 @@ void print_usage(void)
 {
        printf("Usage: skein%dsum [OPTION]... [FILE]...\n",hashbitlen);
        printf("Print or check skein (%d-bit) checksums.\n",hashbitlen);
-       printf("With no FILE, or when FILE is -, read standard input.\n");
-       printf("\n");
-       printf("-b, --binary         read in binary mode\n");
-       printf("-c, --check          read skein sums from the FILEs and check them\n");
-       printf("--tag            create a BSD-style checksum\n");
-       printf("-t, --text           read in text mode (default)\n");
-       printf("\n");
-       printf("The following three options are useful only when verifying checksums:\n");
-       printf("--quiet          don't print OK for each successfully verified file\n");
-       printf("--status         don't output anything, status code shows success\n");
-       printf("-w, --warn           warn about improperly formatted checksum lines\n");
-       printf("\n");
-       printf("--strict         with --check, exit non-zero for any invalid input\n");
-       printf("--help     display this help and exit\n");
-       printf("--version  output version information and exit\n");
-       printf("\n");
-       printf("The sums are computed as described in version 1.3 of the Skein\n");
-       printf("specification. When checking, the input should be a former output of\n");
-       printf("this program. The default mode is to print a line with checksum, a\n");
-       printf("character indicating input mode ('*' for binary, space for text), and\n");
-       printf("name for each FILE.\n");
+       printf("With no FILE, or when FILE is -, read standard input.\n"
+              "\n"
+              "-b, --binary     read in binary mode\n"
+              "-c, --check      read skein sums from the FILEs and check them\n"
+              "--tag            create a BSD-style checksum\n"
+              "-t, --text       read in text mode (default)\n"
+              "-0               hash strings from command line\n"
+              "\n"
+              "The following three options are useful only when verifying checksums:\n"
+              "--quiet          don't print OK for each successfully verified file\n"
+              "--status         don't output anything, status code shows success\n"
+              "-w, --warn       warn about improperly formatted checksum lines\n"
+              "\n"
+              "--strict         with --check, exit non-zero for any invalid input\n"
+              "-h, --help       display this help and exit\n"
+              "-V, --version    output version information and exit\n"
+              "\n"
+              "The sums are computed as described in version 1.3 of the Skein\n"
+              "specification. When checking, the input should be a former output of\n"
+              "this program. The default mode is to print a line with checksum, a\n"
+              "character indicating input mode ('*' for binary, space for text), and\n"
+              "name for each FILE.\n");
        exit(1);
 }
 
+int is_goodfile(const char filename[])
+{
+       if (!strcmp(filename, "-"))
+               return 1;
+
+       struct stat s;
+
+       if (stat(filename, &s) < 0) {
+               WARN("%s: no such file or directory\n", filename);
+               return 0;
+       }
+
+       if (S_ISREG (s.st_mode)) return 1;
+       if (S_ISCHR (s.st_mode)) return 1;
+       if (S_ISBLK (s.st_mode)) return 1;
+       if (S_ISLNK (s.st_mode)) return 1;
+       if (S_ISFIFO(s.st_mode)) return 1;
+
+       if (S_ISDIR (s.st_mode)) {
+               WARN("%s: is a directory\n", filename);
+               return 0;
+       }
+
+       WARN("%s: WARNING: unknown filetype 0x%Xu\n", filename, s.st_mode);
+       return 1;  /* try it as good */
+}
 
 
 int main(int argc, char** argv)
 {
-       char MsgDigest[hashbitlen/2];
-       char *list_files[MaxNmberFiles];
-       int number_files = 0;
+       int first_file = argc;
        int binary = -1,
                 check = -1,
                 quiet = -1,
@@ -365,10 +449,10 @@ int main(int argc, char** argv)
 /*****************************************************************************************
  ************************************* GETTING DATA ***********************************
  *****************************************************************************************/
-       while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
+       while ((opt = getopt_long (argc, argv, "hVbctw0", long_options, NULL)) != -1)
        {
                switch (opt) {
-                       case 0              : hashString = 1;  break;
+                       case '0'            : hashString = 1;  break;
                        case 'b'            : binary     = 1;  break;
                        case 't'            : binary     = 0;  break;
                        case 'c'            : check      = 1;  break;
@@ -377,326 +461,114 @@ int main(int argc, char** argv)
                        case STATUS_OPTION  : status     = 1;  break;
                        case TAG_OPTION     : tag        = 1;  break;
                        
-                       case HELP_OPTION    : print_usage();   /* ..never returns */
-                       case VERSION_OPTION : print_version(); /* ..never returns */
+                       case 'h'            : print_usage();   /* ..never returns */
+                       case 'V'            : print_version(); /* ..never returns */
 
-                       default:
-                               printf("Try `skein%dsum --help' for more information.\n",hashbitlen);
-                               exit(1);
+                       default: TRYHELP_GOODBYE();
                }
        }
 
-       for (; optind < argc; ++optind)
-       {
-               struct stat s;
-               if (stat(argv[optind], &s) < 0)
-               {
-                       printf("skein%dsum: %s: no such file or directory\n", hashbitlen, argv[optind]);
-                       errorFound = 1;
-               }
-               else if (s.st_mode & (S_IFREG|S_IFBLK))  /* ..regular file or block device? */
-               {
-                       if (number_files < MaxNmberFiles) {
-                               list_files[number_files++] = argv[optind];
-                       } else {
-                               printf("skein%dsum: %s: ignore because filelist is too long\n",
-                                       hashbitlen, argv[optind]);
-                       }
-               }
-               else if (s.st_mode & S_IFDIR)
-               {
-                       printf("skein%dsum: %s: is a directory\n",hashbitlen,argv[optind]);
-                       errorFound = 1;
-               }
-               else
-               {
-                       printf("skein%dsum: %s: wrong filetype 0x%Xu\n",
-                               hashbitlen, argv[optind], s.st_mode);
-                               errorFound = 1;
-               }
-       }
+       first_file = optind;
 
 /*****************************************************************************************
  ************************************* PROCESSING DATA ***********************************
  *****************************************************************************************/
-       if(argc > 1 && binary == 1)
+
+       if (hashString > 0)
        {
-               if (check == 1 || quiet == 1 || warn == 1 || status == 1)
-               {
-                       printf("skein%dsum: the --binary and --text options are meaningless when verifying checksums\n",hashbitlen);
-                       printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
-                       exit(0);
+               int n = first_file;
+               if (n >= argc) {
+                       WARN("command line should contain strings for hashing\n");
+                       TRYHELP_GOODBYE();
                }
-               if(number_files > 0)
-               {
-                       int index_files = 0;
-                       while(index_files < number_files)
-                       {
-                               if(hashString == 1)
-                               {
-                                       printf("skein%dsum: %s: No such file or directory\n",hashbitlen,list_files[index_files]);
-                                       index_files++;
-                                       continue;
-                               }
-                               if(HashBinaryMode(list_files[index_files],MsgDigest)!=-1)
-                               {
-                                       if(tag == 1)
-                                       {
-                                               printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
-                                       }
-                                       else
-                                       {
-                                               printf("%s ",MsgDigest);
-                                               printf("*%s\n",list_files[index_files]);
-                                       }
-                               }
-                               index_files++;
-                       }
-               }
-               else if(errorFound != 1)
-               {
-                       HashStdin(MsgDigest, tag);
+               for( ; n < argc; n++) {
+                       unsigned char output[hashbitlen/4];
+                       char digest[hashbitlen/4 + 1];
+                       Hash(hashbitlen, argv[n], strlen(argv[n]), output);
+                       hash2hexstr(output, digest);
+                       printf("%s -%s\n", digest, argv[n]);
                }
+               return 0;
        }
 
-       else if (argc > 1 && binary == 0) // Text Mode
+       if (check < 0)   /* READ FILES, GENERATE CHECKSUMS AND PRINT TO STDOUT.. */
        {
-               if (check == 1 || quiet == 1 || warn == 1 || status == 1)
+               if (quiet == 1 || warn == 1 || status == 1)
                {
-                       printf("skein%dsum: the --binary and --text options are meaningless when verifying checksums\n",hashbitlen);
-                       printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
-                       exit(0);
+                       if(quiet == 1)
+                               WARN("the --quiet option is meaningful only when verifying checksums\n");
+                       if(status ==1)
+                               WARN("the --status option is meaningful only when verifying checksums\n");
+                       if(warn == 1)
+                               WARN("the --warn option is meaningful only when verifying checksums\n");
+                       TRYHELP_GOODBYE();
                }
-               if(number_files > 0)
+
+               char mode = binary > 0 ? 'b' : 't';
+
+               int file_index;
+               for (file_index = first_file; file_index < argc; file_index++)
                {
-                       int index_files = 0;
-                       while(index_files < number_files)
-                       {
-                               if(HashTextMode(list_files[index_files],MsgDigest)!=-1)
-                               {
-                                       if(tag == 1)
-                                       {
-                                               printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
-                                       }
-                                       else
-                                       {
-                                               printf("%s ",MsgDigest);
-                                               printf("%s\n",list_files[index_files]);
-                                       }
-                               }
-                               index_files++;
+                       const char *filename = argv[file_index];
+                       if (!is_goodfile(filename)) {
+                               errorFound++;
+                               continue;
                        }
+
+                       if (binary > 0 && hashString == 1) {
+                               WARN("%s: No such file or directory\n", filename);
+                               continue;
+                       }
+
+                       if (PrintFileHash(filename, tag, mode) < 0)
+                               errorFound++;
                }
-               else if(errorFound != 1)
-               {
-                       HashStdin(MsgDigest, tag);
-               }
+
+               if (first_file >= argc)  /* no files in cmdline? hash stdin.. */
+                       if (PrintFileHash("-", tag, mode) < 0)
+                               errorFound++;
+
+               return (errorFound ? 1 : 0);
        }
 
-       else if (argc > 1 && binary == -1)
+       if (check == 1)   /* READ LISTFILES, GENERATE HASHES, COMPARE WITH STORED, PRINT RESULT */
        {
-               if(check == -1)
-               {// hashing stdin entries
-                       if(quiet == 1 || status == 1 || warn == 1)
-                       {
-                               if(quiet == 1)
-                                       printf("skein%dsum: the --quiet option is meaningful only when verifying checksums\n",hashbitlen);
-                               if(status ==1)
-                                       printf("skein%dsum: the --status option is meaningful only when verifying checksums\n",hashbitlen);
-                               if(warn == 1)
-                                       printf("skein%dsum: the --warn option is meaningful only when verifying checksums\n",hashbitlen);
-
-                               printf("Try 'skein%dsum --help' for more information.\n",hashbitlen);
-                               exit(1);
-                       }
-                       if(number_files > 0)
-                       {// hashing files
-                               int index_files = 0;
-                               while(index_files < number_files)
-                               {
-                                       if(HashTextMode(list_files[index_files],MsgDigest)!=-1)
-                                       {
-                                               if(tag == 1)
-                                               {
-                                                       printf("skein%d_v%s (%s) = %s\n",hashbitlen,skeinVersion,list_files[index_files],MsgDigest);
-                                               }
-                                               else
-                                               {
-                                                       printf("%s ",MsgDigest);
-                                                       printf("%s\n",list_files[index_files]);
-                                               }
-                                       }
-                                       index_files++;
-                               }
-                       }
-                       else if(errorFound != 1)
-                       {
-                               HashStdin(MsgDigest, tag);
-                       }
-               }
-               else if(check == 1)
+               if (tag == 1 || binary >= 0)
                {
-                       if(tag == 1)
-                       {
-                               printf("skein%dsum: the --tag option is meaningless when verifying checksums\n",hashbitlen);
-                               printf("Try 'skein%dsum --help' for more information\n",hashbitlen);
-                               exit(1);
-                       }
-                       int index_files = 0;
-                       while(index_files < number_files)
-                       {
-                               FILE *fp;
-                               char hash[500], file_name[100], file_tmp[100], MsgDigest_tmp[hashbitlen/2];
-                               int NoMatch = 0, NotProper = 0, Computed = 0;
-                               strcpy(file_name,list_files[index_files]);
-                               //show everything
-                               int line = 0;
-                               fp = fopen(file_name,"r");
-                               if(fp!=NULL)
-                               {
-                                       while(fgets(hash,500,fp)!=NULL)
-                                       {
-                                               line ++;
-                                               Computed++;
-                                               unsigned int hashVersion = decomposeHashLine(hash,MsgDigest_tmp,file_tmp);
-                                               if(hashVersion == -1)
-                                               {
-                                                       printf("skein%d: %s is using newer version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen);
-                                                       printf("You should update your algorithm\n");
-                                                       continue;
-                                               }
-                                               else if( hashVersion == 0)
-                                               {
-                                                       printf("skein%d: %s is using an older version of skein%d algorithm\n",hashbitlen,file_tmp,hashbitlen);
-                                                       printf("You should use the older algorithm\n");
-                                                       continue;
-                                               }
-                                               else
-                                               {
-                                                       if(!isProper(MsgDigest_tmp))
-                                                       {
-                                                               if(status != 1 && warn == 1)
-                                                               {
-                                                                       printf("skein%dsum: %s: %d: improperly formatted skein%d checksum line\n",hashbitlen,file_tmp,line,hashbitlen);
-                                                               }
-                                                               NotProper ++;
-                                                               NoMatch ++;
-                                                               continue;
-                                                       }
-                                                       if(file_tmp[0] == '*')
-                                                       {
-                                                               int index_file_tmp = 0;
-                                                               for( ; file_tmp[index_file_tmp+1]!=0 ; index_file_tmp++)
-                                                               {
-                                                                       file_tmp[index_file_tmp] = file_tmp[index_file_tmp + 1];
-                                                               }
-                                                               file_tmp[index_file_tmp] = 0;
-                                                               HashBinaryMode(file_tmp,MsgDigest);
-                                                       }
-                                                       else
-                                                       {
-                                                               HashTextMode(file_tmp,MsgDigest);
-                                                       }
-
-                                                       if(!strcmp(MsgDigest,MsgDigest_tmp))
-                                                       {
-                                                               if(quiet != 1)
-                                                               {
-                                                                       printf("%s: OK\n",file_tmp);
-                                                               }
-                                                       }
-                                                       else
-                                                       {
-                                                               printf("%s: FAILED\n",file_tmp);
-                                                               NoMatch ++;
-                                                       }
-                                               }
-                                       }
-                                       if(NoMatch)
-                                       {
-                                               printf("skein%dsum: WARNING: %d of %d computed checksums did NOT match\n",
-                                                               hashbitlen,NoMatch,Computed);
-                                       }
-                                       if(NotProper)
-                                       {
-                                               printf("skein%dsum: WARNING: %d line is improperly formatted\n",hashbitlen,NotProper);
-                                       }
-                               }
-                               else
-                               {
-                                       printf("skein%dsum: %s: No such file or directory\n",hashbitlen,file_name);
-                               }
-                               index_files++;
+                       if (tag == 1)
+                               WARN("the --tag option is meaningless when verifying checksums\n");
+                       if (binary >= 0)
+                               WARN("the --text and --binary options are meaningless when verifying checksums\n");
+                       TRYHELP_GOODBYE();
+               }
 
+               int file_index;
+               for (file_index = first_file; file_index < argc; file_index++)
+               {
+                       const char *filename = argv[file_index];
+                       if (!is_goodfile(filename)) {
+                               errorFound++;
+                               continue;
                        }
 
-                       if(number_files  == 0)
-                       {
-                               char longstring[1000];
-                               char file_name[30];
-                               char MsgDigest_tmp[hashbitlen/2];
-                               int Computed = 0, NotProper = 0, NoMatch = 0 , line = 0;
-                               while((fgets(longstring,1000,stdin))!=NULL)
-                               {
-                                       Computed++;
-                                       line ++;
-                                       decomposeHashLine(longstring,MsgDigest_tmp,file_name);
-                                       if(!isProper(MsgDigest_tmp))
-                                       {
-                                               if(status != 1 && warn == 1)
-                                               {
-                                                       printf("skein%dsum: %s: %d: improperly formatted skein%d checksum line\n",hashbitlen,file_name,line,hashbitlen);
-                                               }
-                                               NotProper ++;
-                                               NoMatch ++;
-                                               continue;
-                                       }
-                                       if(file_name[0] == '*')
-                                       {
-                                               int index_file_tmp = 0;
-                                               for( ; file_name[index_file_tmp+1]!=0 ; index_file_tmp++)
-                                               {
-                                                       file_name[index_file_tmp] = file_name[index_file_tmp + 1];
-                                               }
-                                               file_name[index_file_tmp] = 0;
-                                               HashBinaryMode(file_name,MsgDigest);
-                                       }
-                                       else
-                                       {
-                                               HashTextMode(file_name,MsgDigest);
-                                       }
-
-                                       if(!strcmp(MsgDigest,MsgDigest_tmp))
-                                       {
-                                               if(quiet != 1)
-                                               {
-                                                       printf("%s: OK\n",file_name);
-                                               }
-                                       }
-                                       else
-                                       {
-                                               printf("%s: FAILED\n",file_name);
-                                               NoMatch ++;
-                                       }
-                               }
-                               if(NoMatch)
-                               {
-                                       printf("skein%dsum: WARNING: %d of %d computed checksums did NOT match\n",
-                                                       hashbitlen,NoMatch,Computed);
-                               }
-                               if(NotProper)
-                               {
-                                       printf("skein%dsum: WARNING: %d line is improperly formatted\n",hashbitlen,NotProper);
-                               }
-
+                       FILE *fp = (strcmp(filename, "-") == 0) ? stdin : fopen(filename, "r");
+                       if (!fp) {
+                               errorFound++;
+                               WARN("%s: %s\n", filename, strerror(errno));
+                               continue;
                        }
+                       if (VerifyHashesFromFile(fp, status, warn, quiet) < 0)
+                               errorFound++;
+                       if (fp != stdin)
+                               fclose(fp);
+               }
 
+               if (first_file >= argc)  /* no files in cmdline? verify stdin.. */
+                       if (VerifyHashesFromFile(stdin, status, warn, quiet) < 0)
+                               errorFound++;
 
-               }
+               return (errorFound ? 1 : 0);
        }
 
-       if (!errorFound && (argc == 1 || (hashString == 1 && !number_files)))
-               HashStdin(MsgDigest, 0);
-
        return 1;
 }