1
0
Fork 0
sattools/qfits/saft/fitsmd5.c

856 lines
22 KiB
C

/*----------------------------------------------------------------------------*/
/**
@file fitsmd5.c
@author N. Devillard
@date May 2001
@version $Revision: 1.5 $
@brief Display/Add/Update the DATAMD5 keyword/value
This is a stand-alone utility. Compile it with any ANSI C compiler:
% cc -o fitsmd5 fitsmd5.c [optional optimization options]
*/
/*----------------------------------------------------------------------------*/
/*
$Id: fitsmd5.c,v 1.5 2003/07/04 15:08:04 yjung Exp $
$Author: yjung $
$Date: 2003/07/04 15:08:04 $
$Revision: 1.5 $
*/
/*-----------------------------------------------------------------------------
Includes
-----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
/*-----------------------------------------------------------------------------
Support for gzipped files if linked against zlib.
-----------------------------------------------------------------------------*/
#if HAVE_ZLIB
#include "zlib.h"
#define FILE gzFile
#define fopen gzopen
#define fclose gzclose
#define fread(b,s,n,f) gzread(f,b,n*s)
#define GZIP_MAGIC1 0x1f
#define GZIP_MAGIC2 0x8b
static
is_gzipped (char *filename)
{
FILE *in;
unsigned char b1, b2;
int r1, r2;
if ((in = fopen (filename, "r")) == NULL)
{
return -1;
}
r1 = fread (&b1, 1, 1, in);
r2 = fread (&b2, 1, 1, in);
fclose (in);
if (r1 != 1 || r2 != 1)
return 0;
if ((int) b1 != GZIP_MAGIC1 || (int) b2 != GZIP_MAGIC2)
{
return 0;
}
return 1;
}
#endif
/*-----------------------------------------------------------------------------
Define
-----------------------------------------------------------------------------*/
/* Definitions related to FITS */
#define FITSLINESZ 80 /* a FITS line is 80 chars */
#define FITSCARDS 36 /* 36 cards per block */
#define FITSBLOCKSZ (FITSLINESZ*FITSCARDS) /* FITS block size=2880 */
/* Definitions related to MD5 */
#define MD5HASHSZ 32 /* an MD5 key length is 32 bytes = 128 bits */
/* FITS keyword used to store MD5 key */
#define FITSMD5KEY "DATAMD5 "
/*-----------------------------------------------------------------------------
New types
-----------------------------------------------------------------------------*/
/* The following types defined for MD5 computation only */
typedef unsigned int word32;
struct MD5Context
{
word32 buf[4];
word32 bits[2];
unsigned char in[64];
};
/*-----------------------------------------------------------------------------
Private function prototypes
-----------------------------------------------------------------------------*/
static void MD5Init (struct MD5Context *);
static void MD5Update (struct MD5Context *, unsigned char *, unsigned);
static void MD5Final (unsigned char *, struct MD5Context *);
static void MD5Transform (word32 *, word32 *);
static void byteReverse (unsigned char *, unsigned);
static int fits_md5_check (char *, int);
static char *fits_pretty_string (char *);
static char *fits_getvalue (char *);
static void usage (void);
/*-----------------------------------------------------------------------------
Global variables
-----------------------------------------------------------------------------*/
static char *pname = NULL;
static char prog_desc[] = "Compute/Update the DATAMD5 keyword/value";
static int silent_process = 0;
/*-----------------------------------------------------------------------------
MD5 function code
-----------------------------------------------------------------------------*/
/* Reverse bytes in a 32-bit word. Harmless on little endian machines */
static void
byteReverse (unsigned char *buf, unsigned longs)
{
word32 t;
do
{
t = (word32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(word32 *) buf = t;
buf += 4;
}
while (--longs);
}
/* Start MD5 accumulation. Set bit count to 0 and buffer to MD5 init. const. */
static void
MD5Init (struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/* Update to reflect the concatenation of another buffer full of bytes. */
static void
MD5Update (struct MD5Context *ctx, unsigned char *buf, unsigned len)
{
register word32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((word32) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t)
{
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t)
{
memmove (p, buf, len);
return;
}
memmove (p, buf, t);
byteReverse (ctx->in, 16);
MD5Transform (ctx->buf, (word32 *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64)
{
memmove (ctx->in, buf, 64);
byteReverse (ctx->in, 16);
MD5Transform (ctx->buf, (word32 *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memmove (ctx->in, buf, len);
}
/* Final wrapup - pad to 64-byte boundary with the bit pattern 1 0* */
/* (64-bit count of bits processed, MSB-first) */
static void
MD5Final (unsigned char digest[16], struct MD5Context *ctx)
{
unsigned int count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8)
{
/* Two lots of padding: Pad the first block to 64 bytes */
memset (p, 0, count);
byteReverse (ctx->in, 16);
MD5Transform (ctx->buf, (word32 *) ctx->in);
/* Now fill the next block with 56 bytes */
memset (ctx->in, 0, 56);
}
else
{
/* Pad block to 56 bytes */
memset (p, 0, count - 8);
}
byteReverse (ctx->in, 14);
/* Append length in bits and transform */
((word32 *) ctx->in)[14] = ctx->bits[0];
((word32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform (ctx->buf, (word32 *) ctx->in);
byteReverse ((unsigned char *) ctx->buf, 4);
memmove (digest, ctx->buf, 16);
memset (ctx, 0, sizeof (ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void
MD5Transform (word32 buf[4], word32 in[16])
{
register word32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP (F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP (F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP (F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP (F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP (F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP (F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP (F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP (F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP (F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP (F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP (F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP (F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP (F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP (F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP (F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP (F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP (F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP (F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP (F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP (F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP (F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP (F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP (F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP (F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP (F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP (F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP (F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP (F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP (F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP (F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP (F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP (F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP (F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP (F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP (F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP (F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP (F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP (F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP (F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP (F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP (F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP (F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP (F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP (F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP (F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP (F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP (F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP (F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP (F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP (F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP (F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP (F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP (F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*-----------------------------------------------------------------------------
FITS-related functions
-----------------------------------------------------------------------------*/
/* Pretty-print a FITS string value */
static char *
fits_pretty_string (char *s)
{
static char pretty[FITSLINESZ + 1];
int i, j;
if (s == NULL)
return NULL;
pretty[0] = (char) 0;
if (s[0] != '\'')
return s;
/* skip first quote */
i = 1;
j = 0;
/* trim left-side blanks */
while (s[i] == ' ')
{
if (i == (int) strlen (s))
break;
i++;
}
if (i >= (int) (strlen (s) - 1))
return pretty;
/* copy string, changing double quotes to single ones */
while (i < (int) strlen (s))
{
if (s[i] == '\'')
i++;
pretty[j] = s[i];
i++;
j++;
}
/* NULL-terminate the pretty string */
pretty[j + 1] = (char) 0;
/* trim right-side blanks */
j = (int) strlen (pretty) - 1;
while (pretty[j] == ' ')
j--;
pretty[j + 1] = (char) 0;
return pretty;
}
/* Get the FITS value in a FITS card */
static char *
fits_getvalue (char *line)
{
static char value[FITSLINESZ + 1];
int from, to;
int inq;
int i;
if (line == NULL)
return NULL;
memset (value, 0, FITSLINESZ + 1);
/* Get past the keyword */
i = 0;
while (line[i] != '=' && i < FITSLINESZ)
i++;
if (i > FITSLINESZ)
return NULL;
i++;
while (line[i] == ' ' && i < FITSLINESZ)
i++;
if (i > FITSLINESZ)
return NULL;
from = i;
/* Now in the value section */
/* Look for the first slash '/' outside of a string */
inq = 0;
while (i < FITSLINESZ)
{
if (line[i] == '\'')
inq = !inq;
if (line[i] == '/')
if (!inq)
break;
i++;
}
i--;
/* Backtrack on blanks */
while (line[i] == ' ' && i >= 0)
i--;
if (i < 0)
return NULL;
to = i;
if (to < from)
return NULL;
/* Copy relevant characters into output buffer */
strncpy (value, line + from, to - from + 1);
/* Null-terminate the string */
value[to - from + 1] = (char) 0;
/*
* Make it pretty: remove head and tail quote, change double
* quotes to simple ones.
*/
strcpy (value, fits_pretty_string (value));
return value;
}
/* Replace the MD5 card in the input header */
static int
fits_replace_card (char *filename, int off_md5, char *datamd5)
{
char *buf;
int fd;
struct stat sta;
char card[FITSLINESZ];
int i;
int err;
/* Get file size */
if (stat (filename, &sta) == -1)
{
fprintf (stderr, "%s: cannot stat file [%s]: no update done\n",
pname, filename);
return 1;
}
/* Open file */
fd = open (filename, O_RDWR);
if (fd == -1)
{
fprintf (stderr,
"%s: cannot open file [%s] for modification: no update done\n",
pname, filename);
return 1;
}
/* Memory-map the file */
buf = (char *) mmap (0,
sta.st_size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == (char *) -1 || buf == NULL)
{
perror ("mmap");
close (fd);
return 1;
}
/* sprintf should be safe, the MD5 signature size is 32 chars */
sprintf (card, "%s= '%s' / data MD5 signature", FITSMD5KEY, datamd5);
i = FITSLINESZ - 1;
while (card[i] != 'e')
{
card[i] = ' ';
i--;
}
/* Copy card into file */
memcpy (buf + off_md5, card, FITSLINESZ);
/* flush output, unmap buffer, close file and quit */
err = 0;
sync ();
if (close (fd) == -1)
{
fprintf (stderr, "%s: error closing modified file [%s]",
pname, filename);
err++;
}
if (munmap (buf, sta.st_size) == -1)
{
perror ("munmap");
err++;
}
return err;
}
/* Display or modify the DATAMD5 value. Returns the number of errors. */
static int
fits_md5_check (char *filename, int update_header)
{
FILE *in;
char buf[FITSBLOCKSZ];
char *buf_c;
int i;
int in_header;
char *hdrmd5;
struct MD5Context ctx;
unsigned char digest[16];
static char datamd5[MD5HASHSZ + 1];
int off_md5;
int cur_off;
int md5keysz;
int err;
int check_fits;
struct stat sta;
if (filename == NULL)
return 1;
/* Try to stat file */
if (stat (filename, &sta) != 0)
{
fprintf (stderr, "%s: cannot stat file %s\n", pname, filename);
return 1;
}
/* See if this is a regular file */
if (!S_ISREG (sta.st_mode))
{
fprintf (stderr, "%s: not a regular file: %s\n", pname, filename);
return 1;
}
/* Open input file */
if ((in = fopen (filename, "r")) == NULL)
{
fprintf (stderr, "%s: cannot open file [%s]\n", pname, filename);
return 1;
}
/* Initialize all variables */
MD5Init (&ctx);
in_header = 1;
hdrmd5 = NULL;
off_md5 = 0;
cur_off = 0;
md5keysz = (int) strlen (FITSMD5KEY);
check_fits = 0;
/* Loop over input file */
while (fread (buf, 1, FITSBLOCKSZ, in) == FITSBLOCKSZ)
{
/* First time in the loop: check the file is FITS */
if (check_fits == 0)
{
/* Examine first characters in block */
if (buf[0] != 'S' ||
buf[1] != 'I' ||
buf[2] != 'M' ||
buf[3] != 'P' ||
buf[4] != 'L' ||
buf[5] != 'E' ||
buf[6] != ' ' || buf[7] != ' ' || buf[8] != '=')
{
fprintf (stderr, "%s: file [%s] is not FITS\n",
pname, filename);
fclose (in);
return 1;
}
else
{
check_fits = 1;
}
}
/* If current block is a header block */
if (in_header)
{
buf_c = buf;
for (i = 0; i < FITSCARDS; i++)
{
/* Try to locate MD5 keyword if not located already */
if (hdrmd5 == NULL)
{
if (!strncmp (buf_c, FITSMD5KEY, md5keysz))
{
hdrmd5 = fits_getvalue (buf_c);
off_md5 = cur_off;
}
}
/* Try to locate an END key */
if (buf_c[0] == 'E' &&
buf_c[1] == 'N' && buf_c[2] == 'D' && buf_c[3] == ' ')
{
in_header = 0;
break;
}
buf_c += FITSLINESZ;
cur_off += FITSLINESZ;
}
}
else
{
/* If current block is a data block */
/* Try to locate an extension header */
if (buf[0] == 'X' &&
buf[1] == 'T' &&
buf[2] == 'E' &&
buf[3] == 'N' &&
buf[4] == 'S' &&
buf[5] == 'I' &&
buf[6] == 'O' && buf[7] == 'N' && buf[8] == '=')
{
in_header = 1;
buf_c = buf;
for (i = 0; i < FITSCARDS; i++)
{
/* Try to find an END marker in this block */
if (buf_c[0] == 'E' &&
buf_c[1] == 'N' && buf_c[2] == 'D' && buf_c[3] == ' ')
{
/* Found END marker in same block as XTENSION */
in_header = 0;
break;
}
buf_c += FITSLINESZ;
}
}
else
{
/* Data block: accumulate for MD5 */
MD5Update (&ctx, (unsigned char *) buf, FITSBLOCKSZ);
}
}
}
fclose (in);
if (check_fits == 0)
{
/* Never went through the read loop: file is not FITS */
fprintf (stderr, "%s: file [%s] is not FITS\n", pname, filename);
return 1;
}
/* Got to the end of file: summarize */
MD5Final (digest, &ctx);
/* Write digest into a string */
sprintf (datamd5,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3], digest[4],
digest[5], digest[6], digest[7], digest[8], digest[9],
digest[10], digest[11], digest[12], digest[13], digest[14],
digest[15]);
if (!silent_process)
{
printf ("%s %s", datamd5, filename);
if (hdrmd5)
{
if (!strcmp (hdrmd5, datamd5))
{
printf (" (header Ok)");
}
else
{
printf (" (header is wrong)");
}
}
printf ("\n");
}
/* Update header if requested */
err = 0;
if (update_header)
{
if (hdrmd5 == NULL)
{
fprintf (stderr, "%s: cannot update header: missing %s\n",
pname, FITSMD5KEY);
return 1;
}
#if HAVE_ZLIB
if (is_gzipped (filename))
{
fprintf (stderr, "%s: cannot update header in gzipped file\n");
return 1;
}
#endif
err = fits_replace_card (filename, off_md5, datamd5);
}
return err;
}
/* Compute MD5 sum on the whole file and print out results on stdout */
static int
compute_md5 (char *filename)
{
struct MD5Context ctx;
unsigned char digest[16];
struct stat sta;
int fd;
unsigned char *buf;
/* Try to stat file */
if (stat (filename, &sta) != 0)
{
fprintf (stderr, "%s: cannot stat file %s\n", pname, filename);
return 1;
}
/* See if this is a regular file */
if (!S_ISREG (sta.st_mode))
{
fprintf (stderr, "%s: not a regular file: %s\n", pname, filename);
return 1;
}
/* Open file */
if ((fd = open (filename, O_RDONLY)) == -1)
{
fprintf (stderr, "%s: cannot open file %s\n", pname, filename);
return 1;
}
/* Memory-map the file */
buf =
(unsigned char *) mmap (0, sta.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (buf == (unsigned char *) -1 || buf == NULL)
{
perror ("mmap");
close (fd);
return 1;
}
/* Initialize MD5 context */
MD5Init (&ctx);
/* Compute MD5 on all bits in the file */
MD5Update (&ctx, buf, sta.st_size);
/* Finalize and print results */
close (fd);
munmap ((char *) buf, sta.st_size);
MD5Final (digest, &ctx);
printf
("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5],
digest[6], digest[7], digest[8], digest[9], digest[10], digest[11],
digest[12], digest[13], digest[14], digest[15], filename);
return 0;
}
static void
usage (void)
{
printf ("%s -- %s\n" "version: $Revision: 1.5 $\n", pname, prog_desc);
printf ("\n"
"use : %s [-u] [-s] [-a] <FITS files...>\n"
"options are:\n"
"\t-u update MD5 keyword in the file: %s\n"
"\t-s silent mode\n"
"\n"
"\t-a compute MD5 sum of the complete file (incl.header)\n"
"\n"
"This utility computes the MD5 checksum of all data sections\n"
"in a given FITS file, and compares it against the value\n"
"declared in DATAMD5 if present. It can also update the value\n"
"of this keyword (if present) with its own computed MD5 sum.\n"
"\n", pname, FITSMD5KEY);
printf ("You can also use it with the -a option to compute the MD5 sum\n"
"on the complete file (all bits). In this case, the file needs\n"
"not be FITS. This option is only provided to check this program\n"
"against other MD5 computation tools.\n"
"NB: Other options cannot be used together with -a.\n" "\n");
#if HAVE_ZLIB
printf ("\n"
"This program was compiled against zlib %s\n"
"which allows to process gzipped FITS files\n"
"as if they were normal FITS files.\n"
"Notice that you cannot use the -u option on\n"
"gzipped files, though.\n" "\n" "\n", ZLIB_VERSION);
#endif
exit (0);
}
/*-----------------------------------------------------------------------------
Main
-----------------------------------------------------------------------------*/
int
main (int argc, char *argv[])
{
int i;
int update_header;
int total_md5;
int err;
/* Initialize */
pname = argv[0];
update_header = 0;
total_md5 = 0;
if (argc < 2)
usage ();
/* Parse arguments for options */
for (i = 1; i < argc; i++)
{
if (!strcmp (argv[i], "-u"))
{
update_header = 1;
}
else if (!strcmp (argv[i], "-s"))
{
silent_process = 1;
}
else if (!strcmp (argv[i], "-a"))
{
total_md5 = 1;
}
}
/* Loop on input file names */
err = 0;
for (i = 1; i < argc; i++)
{
/* If not a command-line option */
if (strcmp (argv[i], "-u") &&
strcmp (argv[i], "-s") && strcmp (argv[i], "-a"))
{
/* Launch MD5 process on this file */
if (total_md5)
{
err += compute_md5 (argv[i]);
}
else
{
err += fits_md5_check (argv[i], update_header);
}
}
}
if (err > 0)
{
fprintf (stderr, "%s: %d error(s) during process\n", pname, err);
}
return err;
}