summaryrefslogtreecommitdiff
path: root/src/md5sum.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1995-07-03 03:10:59 +0000
committerJim Meyering <jim@meyering.net>1995-07-03 03:10:59 +0000
commitc8e05ecd8d180473789049293031ea698d9e9394 (patch)
tree6a4e2e2ecfa9388a8577798ef783b3266eb50e00 /src/md5sum.c
parent9c8e5123bdbccfc51f22c96281fe13bc766ab773 (diff)
downloadcoreutils-c8e05ecd8d180473789049293031ea698d9e9394.tar.xz
(split_3): Rewrite to parse Plumb/Lankester format as well.
(main): Write (de facto) standard Plumb/Lankester format. New option: --quiet. Check option no longer takes an argument. When checking, exit status reflects success.
Diffstat (limited to 'src/md5sum.c')
-rw-r--r--src/md5sum.c182
1 files changed, 111 insertions, 71 deletions
diff --git a/src/md5sum.c b/src/md5sum.c
index 7ea957106..82a639c63 100644
--- a/src/md5sum.c
+++ b/src/md5sum.c
@@ -104,14 +104,14 @@
# define UINT_MAX UINT_MAX_32_BITS
#endif
-#if ULONG_MAX == UINT_MAX_32_BITS
- typedef unsigned long uint32;
+#if UINT_MAX == UINT_MAX_32_BITS
+ typedef unsigned int uint32;
#else
-# if UINT_MAX == UINT_MAX_32_BITS
- typedef unsigned int uint32;
+# if USHRT_MAX == UINT_MAX_32_BITS
+ typedef unsigned short uint32;
# else
-# if USHRT_MAX == UINT_MAX_32_BITS
- typedef unsigned short uint32;
+# if ULONG_MAX == UINT_MAX_32_BITS
+ typedef unsigned long uint32;
# else
/* The following line is intended to throw an error. Using #error is
not portable enough. */
@@ -144,8 +144,9 @@ static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
static const struct option long_options[] =
{
{ "binary", no_argument, 0, 'b' },
- { "check", required_argument, 0, 'c' },
+ { "check", no_argument, 0, 'c' },
{ "help", no_argument, 0, 'h' },
+ { "quiet", no_argument, 0, 'q' },
{ "string", required_argument, 0, 's' },
{ "text", no_argument, 0, 't' },
{ "verbose", no_argument, 0, 'v' },
@@ -170,54 +171,65 @@ static void process_buffer __P ((const void *buffer, size_t len,
/* FIXME: This is provisory. Use strtok. */
static int
-split_3 (s, u, v, w)
- char *s, **u, **v, **w;
+split_3 (s, u, binary, w)
+ char *s, **u, **w;
+ int *binary;
{
size_t i;
- char *p[3];
#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
i = 0;
- while (s[i] && ISWHITE (s[i]))
+ while (ISWHITE (s[i]))
++i;
- if (s[i])
+
+ /* The line has to be at least 35 characters long to contain correct
+ message digest information. */
+ if (strlen (&s[i]) >= 35)
{
- p[0] = &s[i];
- while (s[i] && !ISWHITE (s[i]))
- ++i;
- if (s[i])
- s[i++] = '\0';
- while (s[i] && ISWHITE (s[i]))
- ++i;
+ *u = &s[i];
+
+ /* The first field has to be the 32 character hexadecimal
+ representation of the message digest. If it not immediately
+ followed by a white space it's an error. */
+ if (!ISWHITE (s[i + 32]))
+ return 1;
+
+ i += 32;
+ s[i++] = '\0';
+
+ /* Now we have to look for two possibilities: the line is in the
+ new format in which case we have the character 'b' or 't' followed
+ by a white space or we have a ' ' or '*' immediately followed by
+ the file name. */
+ if (ISWHITE (s[i + 1]))
+ {
+ if (s[i] != 'b' && s[i] != 't')
+ return 1;
+ *binary = s[i] == 'b';
+ i += 2;
+ }
+ else
+ {
+ if (s[i] != ' ' && s[i] != '*')
+ return 1;
+ *binary = s[i] == '*';
+ ++i;
+ }
+
if (s[i])
{
- p[1] = &s[i];
+ *w = &s[i];
+ /* Skip past the third token. */
while (s[i] && !ISWHITE (s[i]))
++i;
if (s[i])
s[i++] = '\0';
- while (s[i] && ISWHITE (s[i]))
+ /* Allow trailing white space. */
+ while (ISWHITE (s[i]))
++i;
- if (s[i])
- {
- p[2] = &s[i];
- /* Skip past the third token. */
- while (s[i] && !ISWHITE (s[i]))
- ++i;
- if (s[i])
- s[i++] = '\0';
- /* Allow trailing white space. */
- while (s[i] && ISWHITE (s[i]))
- ++i;
- if (!s[i])
- {
- *u = p[0];
- *v = p[1];
- *w = p[2];
- return 0;
- }
- }
+ if (!s[i])
+ return 0;
}
}
return 1;
@@ -244,12 +256,14 @@ main (argc, argv)
char *argv[];
{
unsigned char md5buffer[16];
- const char *check_file = NULL;
- int binary = 1;
+ int old_format = 1; /* Use Plumb/Lankester format by default. */
+ int binary = 0; /* Text is default of the Plumb/Lankester format. */
+ int do_check = 0;
int do_help = 0;
int do_version = 0;
int verbose = 0;
int opt;
+ int quiet = 0;
char **string = NULL;
char n_strings = 0;
size_t i;
@@ -257,7 +271,7 @@ main (argc, argv)
/* Setting values of global variables. */
program_name = argv[0];
- while ((opt = getopt_long (argc, argv, "bc:hs:tvV", long_options, NULL))
+ while ((opt = getopt_long (argc, argv, "bchqs:tvV", long_options, NULL))
!= EOF)
switch (opt)
{
@@ -267,11 +281,15 @@ main (argc, argv)
binary = 1;
break;
case 'c':
- check_file = optarg;
+ do_check = 1;
break;
case 'h':
do_help = 1;
break;
+ case 'q':
+ quiet = 1;
+ verbose = 0;
+ break;
case 's':
{
if (string == NULL)
@@ -286,6 +304,7 @@ main (argc, argv)
binary = 0;
break;
case 'v':
+ quiet = 0;
verbose = 1;
break;
case 'V':
@@ -304,7 +323,7 @@ main (argc, argv)
if (do_help)
usage (0);
- if (n_strings > 0 && check_file != NULL)
+ if (n_strings > 0 && do_check != 0)
{
error (0, 0,
_("the --string and --check options are mutually exclusive"));
@@ -313,6 +332,7 @@ main (argc, argv)
if (n_strings > 0)
{
+ /* --quiet does not make much sense with --string. */
if (optind < argc)
{
error (0, 0, _("no files may be specified when using --string"));
@@ -329,8 +349,10 @@ main (argc, argv)
printf (" b \"%s\"\n", string[i]);
}
}
- else if (check_file == NULL)
+ else if (do_check == 0)
{
+ /* --quiet does no make much sense without --check. So print the
+ result even if --quiet is given. */
if (optind == argc)
argv[argc++] = "-";
@@ -343,7 +365,10 @@ main (argc, argv)
for (cnt = 0; cnt < 16; ++cnt)
printf ("%02x", md5buffer[cnt]);
- printf (" %c %s\n", binary ? 'b' : 't', argv[optind]);
+ if (old_format)
+ printf (" %c%s\n", binary ? '*' : ' ', argv[optind]);
+ else
+ printf (" %c %s\n", binary ? 'b' : 't', argv[optind]);
}
}
else
@@ -352,27 +377,30 @@ main (argc, argv)
int n_tests = 0;
int n_tests_failed = 0;
- if (optind < argc)
+ if (optind + 1 < argc)
{
error (0, 0,
- _("no additional files may be specified when using --check"));
+ _("only one argument may be specified when using --check"));
usage (1);
}
- if (strcmp (check_file, "-") == 0)
+ if (optind == argc || strcmp (argv[optind], "-") == 0)
cfp = stdin;
else
{
- cfp = fopen (check_file, "r");
+ cfp = fopen (argv[optind], "r");
if (cfp == NULL)
- error (1, errno, _("check file: %s"), check_file);
+ if (quiet)
+ exit (1);
+ else
+ error (1, errno, _("check file: %s"), argv[optind]);
}
do
{
char line[1024];
char *filename;
- char *type_flag;
+ int type_flag;
char *md5num;
int err;
@@ -380,6 +408,10 @@ main (argc, argv)
if (fgets (line, 1024, cfp) == NULL)
break;
+ /* Ignore comment lines, which begin with a '#' character. */
+ if (line[0] == '#')
+ continue;
+
/* Remove any trailing newline. */
if (line[strlen (line) - 1] == '\n')
line[strlen (line) - 1] = '\0';
@@ -387,11 +419,7 @@ main (argc, argv)
/* FIXME: maybe accept the output of --string=STRING. */
err = split_3 (line, &md5num, &type_flag, &filename);
- if (err
- || strlen (md5num) != 32
- || !hex_digits (md5num)
- || strlen (type_flag) != 1
- || (*type_flag != 'b' && *type_flag != 't'))
+ if (err || !hex_digits (md5num))
{
if (verbose)
error (0, 0, _("invalid line in check file: %s"), line);
@@ -404,12 +432,15 @@ main (argc, argv)
'c', 'd', 'e', 'f' };
size_t cnt;
- printf ("%s: ", filename);
- if (verbose)
- fflush (stdout);
+ if (!quiet)
+ {
+ printf ("%s: ", filename);
+ if (verbose)
+ fflush (stdout);
+ }
++n_tests;
- md5_file (filename, md5buffer, *type_flag == 'b');
+ md5_file (filename, md5buffer, type_flag);
/* Compare generated binary number with text representation
in check file. Ignore case of hex digits. */
@@ -419,12 +450,19 @@ main (argc, argv)
!= (bin2hex[md5buffer[cnt] & 0xf]))
break;
- puts (cnt < 16 ? (++n_tests_failed, _("FAILED")) : _("OK"));
+ if (cnt < 16)
+ ++n_tests_failed;
+ if (!quiet)
+ puts (cnt < 16 ? _("FAILED") : _("OK"));
}
}
while (!feof (cfp));
+ fclose (cfp);
+
+ if (!quiet)
+ printf (_("%d out of %d tests failed\n"), n_tests_failed, n_tests);
- printf (_("%d out of %d tests failed\n"), n_tests_failed, n_tests);
+ exit (n_tests_failed > 0);
}
exit (0);
@@ -440,23 +478,25 @@ usage (status)
else
printf (_("\
Usage: %s [OPTION] [FILE]...\n\
- or: %s --check=FILE\n\
- or: %s --string=STRING\n\
-Mandatory arguments to long options are mandatory for short options too.\n\
+ or: %s [OPTION] --string=STRING\n\
+ or: %s [OPTION] --check [FILE]\n\
+Print or check MD5 checksums.\n\
+With no FILE, or when FILE is -, read standard input.\n\
\n\
-h, --help display this help and exit\n\
+ -q, --quiet don't show anything, status code shows success\n\
-v, --verbose verbose output level\n\
-V, --version output version information and exit\n\
\n\
-b, --binary read files in binary mode (default)\n\
-t, --text read files in text mode\n\
\n\
- -c, --check=FILE check MD5 sums against list in FILE\n\
+ -c, --check check MD5 sums against given list\n\
-s, --string=STRING compute checksum for STRING\n\
\n\
-The sums are computed as described in RFC 1321. The file given at the -c\n\
-option should be a former output of this program. The default mode is to\n\
-produce a list with the checksum informations. A file name - denotes stdin.\n"),
+The sums are computed as described in RFC 1321. When checking, the input\n\
+should be a former output of this program. The default mode is to print\n\
+a line with checksum, type, and name for each FILE.\n"),
program_name, program_name, program_name);
exit (status);