home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
brik-2.0-src.tgz
/
tar.out
/
contrib
/
brik
/
brik.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
30KB
|
975 lines
/* ::[[ @(#) brik.c 1.55 89/07/12 03:31:06 ]]:: */
#ifndef LINT
static char sccsid[]="::[[ @(#) brik.c 1.55 89/07/12 03:31:06 ]]::";
#endif
#define DATESTAMP "1989/07/11"
#define VERSION "2.0"
/*
(c) Copyright 1989 Rahul Dhesi, All rights reserved. Permission is
granted to use, copy, and distribute this file under the terms of the
GNU General Public License version 1.0.
*/
/*
Checksum: 2990338384 (check or update this with "brik")
*/
static char copyright[] =
"\
Copyright 1989 Rahul Dhesi, All rights reserved. Use and distribution is\n\
permitted under the terms of the GNU General Public License version 1.0.\n\
";
/*
The following code assumes the ASCII character set and 8-bit bytes.
*/
#ifndef OK_STDIO
# include <stdio.h>
# define OK_STDIO
#endif
#include "brik.h" /* configuration options */
#include "assert.h"
typedef unsigned long tcrc; /* type of crc value -- same as in addbfcrc.c */
#ifdef GENTAB
void mkcrctab PARMS ((void));
#endif /* GENTAB */
#ifdef STDINCLUDE
# include <stdlib.h>
# include <string.h>
#else
FILE *fopen PARMS ((char *filename, char *mode));
char *nextfile PARMS ((int, char *, int));
char *strcat PARMS ((char *, char *));
char *strchr PARMS ((char *, char));
char *strcpy PARMS ((char *, char *));
char *strncat PARMS ((char *, char *, int));
int strcmp PARMS ((char *, char *));
int strlen PARMS ((char *));
void exit PARMS ((int status));
#endif /* STDINCLUDE */
/* twilight zone functions -- may or may not be standard */
int main PARMS ((int, char **));
int getopt PARMS ((int, char **, char *));
/* our own functions */
FILE *efopen PARMS ((char *filename, char *mode, int errlevel));
char suffix PARMS ((void));
char *nextfile PARMS ((int, char *, int));
void dofname PARMS ((char *));
void dofptr PARMS ((FILE *, char *));
int lowerit PARMS ((int));
void printhdr PARMS ((void));
void readnames PARMS ((FILE *));
void updatefile PARMS ((FILE *, long, tcrc, char *));
void whole_check PARMS ((FILE *, char *));
tcrc findcrc PARMS ((FILE *, char *, int *));
tcrc xatol PARMS ((char *));
void addbfcrc PARMS ((char *, int));
void brktst PARMS ((void));
void hdrcrc PARMS ((FILE *, char *));
void longhelp PARMS ((void));
void shorthelp PARMS ((void));
void showerr PARMS ((char *, int));
/* the following constants can be changed if you know what you are doing */
#define ERRLIMIT 127 /* exit(n) returns n not exceeding this */
#define LINESIZE 8192 /* handle lines of up to this length */
#define ERRBUFSIZ 1024 /* buffer size for perror() message */
#define BACKSIZE 1024 /* how much to seek back looking for header */
#define BINTABSIZ 256 /* size of binary char test table */
#ifdef CTRLZ_CHECK
# define Z_THRESHOLD 10 /* see how CTRLZ_CHECK is used later */
#endif /* CTRLZ_CHECK */
/* the following constants should not be changed */
#define MYNL 10 /* newline for CRC calculation */
#define PATTERN "Checksum:" /* look for this header */
#define CHARSINCRC 10 /* characters in CRC */
#define CMTCH '#' /* begins comment in CRC list */
/* error levels */
#define LVL_WARN 0
#define LVL_ERR 1
#define LVL_FATAL 2
#ifdef USEINDEX
# define strchr index
#endif /* USEINDEX */
#ifdef NOTRAIL_B /* avoid trailing "b" in mode string */
# define BRIK_RD "r"
# define BRIK_RW "r+"
# define BRIK_RDB "r"
#else
# define BRIK_RD "r"
# define BRIK_RW "r+"
# define BRIK_RDB "rb"
#endif /* NOTRAIL_B */
#define whitespace(x) (strchr(" \t\n",(x)) != NULL)
/* format strings for printing CRCs and filenames etc. */
static char ok[] = "ok ";
static char bad[] = "BAD";
static char blank[] = " ";
static char fmtstr[] = "%10lu%c %s %s\n";
static char hdrfmt[] = "Checksum: %10lu %s\n";
static char version[] = VERSION;
char bintab[BINTABSIZ]; /* binary char test table */
int patlen; /* length of PATTERN */
int errcount = 0; /* count of errors */
int gen1 = 0; /* generate CRCs for all files */
int gen2 = 0; /* generate CRCs for files with headers */
int silent = 0; /* be silent, just set error status */
int quiet = 0; /* talks less, but not completely silent */
int verbose = 0; /* be verbose, print message for good files too */
int updfile = 0; /* update file by inserting CRC */
int check1 = 0; /* whether to check header crcs */
int check2 = 0; /* whether to check whole file crcs */
int fromfile = 0; /* read filenames from a file */
int binary = 0; /* manipulate binary file */
int trailing = 0; /* include trailing empty lines */
int prthdr = 0; /* print Checksum: XXXXXXXXXX header */
int autocheck = 0; /* brik must decide if text or binary */
int is_stdin = 0; /* current file is stdin */
int doubtful = 0; /* text but doubtful */
#ifdef DEBUG
int debugging = 0;
#endif
/* opens file, prints error message if can't open */
FILE *efopen (fname, mode, level)
char *fname; /* filename to open */
char *mode; /* mode, e.g. "r" or "r+" */
int level; /* error level */
{
FILE *fptr;
fptr = fopen (fname, mode);
if (fptr == NULL)
showerr (fname, level);
return (fptr);
}
/* LOWERIT is a function or macro that returns lowercase of a character */
#ifndef LOWERIT
# ifdef AVOID_MACROS
# define LOWERIT lowerit
# else
# define LOWERIT(c) ((c)>='A' && (c)<='Z' ? ('a'-'A')+(c) : (c))
# endif
#endif
/* Function needed by SEEKFIX code even if a macro is available */
int lowerit (c) int c; /* returns lowercase of an ASCII character */
{
if (c >= 'A' && c <= 'Z') return (('a'-'A') + c);
else return (c);
}
/* STRNICMP is a case-insensitive strncmp */
#ifndef STRNICMP
int STRNICMP (s1, s2, n)
register char *s1, *s2;
int n;
{
assert (n >= 0);
assert (LOWERIT('X') == 'x');
assert (LOWERIT('*') == '*');
for ( ; LOWERIT(*s1) == LOWERIT(*s2); s1++, s2++) {
if (--n == 0 || *s1 == '\0')
return(0);
}
return(LOWERIT(*s1) - LOWERIT(*s2));
}
#endif /* STRNICMP */
#ifdef AVOID_MACROS
# define BRINCMP STRNICMP
#else
# define BRINCMP(s1,s2,n) (LOWERIT(*(s1))!=LOWERIT(*(s2))||STRNICMP(s1,s2,n))
#endif
#define xdigit(x) ((x) >= '0' && (x) <= '9')
/*
xatol is given a string that (supposedly) begins with a string
of digits. It returns a corresponding positive numeric value.
*/
tcrc xatol (str)
char *str;
{
tcrc retval;
retval = 0L;
while (xdigit(*str)) {
retval = retval * 10L + (*str-'0');
str++;
}
return (retval);
}
main (argc, argv)
int argc;
char **argv;
{
int i;
int c; /* next option letter */
int count = 0; /* count of required options seen */
char *infname; /* name of file to read filenames from */
FILE *infptr; /* open file ptr for infname */
extern int optind; /* from getopt: next arg to process */
extern int opterr; /* used by getopt */
opterr = 1; /* so getopt will print err msg */
argv[0] = "brik"; /* for getopt to use */
patlen = strlen (PATTERN);
#ifdef DEBUG
while ((c = getopt (argc, argv, "cCgGasqvWHfbThd")) != EOF)
#else
while ((c = getopt (argc, argv, "cCgGasqvWHfbTh")) != EOF)
#endif
{
switch (c) {
case 'a': autocheck++; binary = 0; trailing = 0; break;
case 'c': check1++; count++; break;
case 'C': check2++; count++; break;
case 'g': gen1++; count++; break;
case 'G': gen2++; count++; break;
case 's': silent++; verbose = 0; break;
case 'q': quiet++; verbose = 0; break;
case 'v': verbose++; silent = 0; break;
case 'W': updfile++; break;
case 'f': fromfile++; break;
case 'b': binary++; autocheck = 0; trailing = 0; break;
case 'T': trailing++; binary = 0; autocheck = 0; break;
case 'H': prthdr++; break;
#ifdef DEBUG
case 'd': debugging++; break;
#endif
case 'h': longhelp();
case '?': shorthelp();
}
}
if (count != 1)
shorthelp();
if (binary && (check1 || gen1)) {
fprintf (stderr, "brik: fatal: Can't read or update CRC header in binary mode\n");
exit (1);
}
if ((updfile || prthdr) && !gen1) {
fprintf (stderr, "brik: fatal: Use of -W and -H requires -g\n");
exit (1);
}
#if 0
if (gen1 || gen2 && !updfile)
silent = 0;
#endif
if (gen1)
autocheck = 0;
#ifdef GENTAB
/* generate CRC table */
mkcrctab();
#endif /* GENTAB */
/* initialize binary char test table */
for (i = 0; i < BINTABSIZ; i++) {
if ( (i < 7) || (i > 13 && i < 26) || (i > 126)) /*ASCII binary chars*/
bintab[i] = 1;
else
bintab[i] = 0;
}
i = optind;
if (fromfile) { /* read filenames from file */
if (i >= argc) { /* need filenames after -f */
fprintf (stderr, "brik: fatal: Filename(s) needed after -f\n");
exit (1);
}
for (; i < argc; i++) {
infname = argv[i];
if (strcmp(infname, "-") == 0) { /* "-" means stdin */
readnames (stdin);
} else {
#ifdef WILDCARD
extern char *nextfile();
nextfile (0, infname, 0); /* initialize fileset 0 */
while ((infname = nextfile(1, (char *) NULL, 0)) != NULL) {
infptr = efopen (infname, BRIK_RD, LVL_ERR);
readnames (infptr);
fclose (infptr);
}
#else
infptr = efopen (infname, BRIK_RD, LVL_ERR);
readnames (infptr);
fclose (infptr);
#endif /* WILDCARD */
}
}
} else { /* read filenames from command line */
if (i >= argc) {
#ifndef BIN_STDIN_OK
if (binary && !check2) {
fprintf (stderr, "brik: fatal: Can't handle stdin in binary mode\n");
exit (1);
}
#endif
is_stdin = 1;
dofptr (stdin, "stdin"); /* if no files, read stdin */
} else {
for (; i < argc; i ++) {
#ifdef WILDCARD
extern char *nextfile();
char *one_name; /* a matching filename */
nextfile (0, argv[i], 0); /* initialize fileset 0 */
while ((one_name = nextfile(1, (char *) NULL, 0)) != NULL)
dofname (one_name);
#else
dofname (argv[i]);
#endif /* WILDCARD */
}
}
}
errexit:
if (errcount > ERRLIMIT)
errcount = ERRLIMIT; /* don't overflow status code */
exit (errcount);
return (errcount); /* to keep turbo c and lint happy */
}
/*
** Reads names from supplied file pointer and handles them. Just
** returns if supplied NULL file pointer. Will also expand wildcards
** in names read from this file.
*/
void readnames (infptr)
FILE *infptr;
{
char buf[LINESIZE];
if (infptr == NULL)
return;
while (fgets (buf, LINESIZE, infptr) != NULL) {
#ifdef WILDCARD
char *fname; /* matching filename */
extern char *nextfile();
#endif /* WILDCARD */
buf[strlen(buf)-1] = '\0'; /* zap trailing newline */
#ifdef WILDCARD
nextfile (0, buf, 1); /* initialize fileset 1 */
while ((fname = nextfile(1, (char *) NULL, 1)) != NULL) {
dofname (fname);
}
#else
dofname (buf);
#endif /* WILDCARD */
}
}
/* do one filename */
void dofname (this_arg)
char *this_arg;
{
FILE *this_file;
char *mode; /* "r", "rb", "rw", etc. for fopen */
#ifdef BRKTST
extern void brktst();
brktst();
#endif
if (autocheck)
binary = 0; /* always begin by assuming text */
if (strcmp(this_arg,"-") == 0) {
#ifndef BIN_STDIN_OK
if (binary && !check2) {
fprintf (stderr, "brik: fatal: Can't handle stdin in binary mode\n");
exit (1);
}
#endif
is_stdin = 1;
this_file = stdin;
this_arg = "stdin";
} else {
if (updfile) {
assert (!binary);
this_file = efopen (this_arg, BRIK_RW, LVL_ERR);
} else {
if (binary && !check2) /* check2 reads filenames, not data */
mode = BRIK_RDB;
else
mode = BRIK_RD;
this_file = efopen (this_arg, mode, LVL_ERR);
}
}
if (this_file == NULL)
errcount++;
else {
#ifdef NOCASE
char *p;
for (p = this_arg; *p != '\0'; p++)
*p = LOWERIT(*p);
#endif
dofptr (this_file, this_arg);
if (this_file != NULL)
fclose (this_file);
}
}
/* returns appropriate suffix character for CRC, based on global flags */
char suffix()
{
return ((char) (doubtful ? '*' : (binary ? 'b' : (trailing ? 'T' : ' '))));
}
/*
** Do one file pointer. Decides if CRC header will be read or written,
** or whether just the whole file will be read.
*/
void dofptr (fptr, fname)
FILE *fptr;
char *fname;
{
int retval; /* return value from findcrc */
if (check2)
whole_check (fptr, fname); /* do whole file check from list */
else if (gen1 || check1) /* header-based CRC check or update */
hdrcrc (fptr, fname);
else { /* whole-file CRC calculation */
extern tcrc crccode;
assert (gen2);
printhdr();
(void) findcrc (fptr, fname, &retval);
if (!silent) {
if (!binary && retval == 1)
doubtful = 1; /* tell suffix() it's '*' */
printf (fmtstr, crccode, suffix(), blank, fname);
}
}
is_stdin = 0; /* set, but not reset, by our caller */
doubtful = 0; /* sphagetti code, need to fix later */
}
/* Does whole file check from a list of files and CRCs */
void whole_check (fptr, listname)
FILE *fptr; /* open file ptr of CRC list file */
char *listname; /* name of CRC list file */
{
tcrc fcrc; /* recorded crc */
char *fname; /* name of file whose CRC being checked */
char buf [LINESIZE]; /* line buffer */
char *p; /* temp ptr */
FILE *orgfile; /* file pointer for original file to check */
int lino = 0; /* line no. in list file for error msg */
char *mode; /* mode string for fopen */
while (fgets (buf, LINESIZE, fptr) != NULL) {
lino++;
p = buf;
if (*p == CMTCH) /* skip comment lines */
continue;
while (*p != '\0' && whitespace(*p)) /* skip whitespace */
p++;
if (*p == '\0')
continue; /* skip empty lines */
if (!xdigit(*p))
goto badline;
fcrc = xatol (p); /* recorded CRC */
while (xdigit(*p))
p++; /* skip past numeric chars */
doubtful = binary = trailing = 0;
if (*p == 'b') /* 'b' means binary */
binary = 1;
if (*p == 'T') /* 'T' means trailing mode */
trailing = 1;
if (*p == '*')
doubtful = 1; /* text but doubtful */
while (*p != '\0' && !whitespace(*p)) /* to whitespace */
p++;
while (whitespace(*p)) /* skip whitespace */
p++;
if (*p == '\n' || *p == '\0') { /* if at end of line */
goto badline;
}
fname = p;
#if 0
while (*p != '\0' && !whitespace(*p)) /* skip to whitespace */
#else
/* Names CAN contain whitespace, and even newlines, however there
* is no provision to store names with embedded newlines, so we
* are out of luck for that case...
*/
while (*p != '\0' && *p != '\n')
#endif
p++;
*p = '\0'; /* null-terminate filename */
if (binary)
mode = BRIK_RDB;
else
mode = BRIK_RD;
orgfile = efopen (fname, mode, LVL_ERR);
if (orgfile == NULL) {
errcount++;
} else {
int retval;
tcrc foundcrc;
assert (!(binary && trailing));
foundcrc = findcrc (orgfile, fname, &retval);
if (foundcrc == fcrc) {
if (verbose)
printf (fmtstr, foundcrc, suffix(), ok, fname);
} else {
if (!silent)
printf (fmtstr, foundcrc, suffix(), bad, fname);
errcount ++;
}
if (orgfile != NULL)
fclose (orgfile);
}
}
return;
badline:
fprintf (stderr,
"brik: error: Abandoning %s due to badly formatted line %d\n",
listname, lino);
return;
}
/*
Initializing the CRC to all one bits avoids failure of detection
should entire data stream get cyclically bit-shifted by one position.
The calculation of the probability of this happening is left as
an exercise for the reader.
*/
#define INITCRC 0xFFFFFFFFL;
/*
** hdrcrc processes one file given an open file pointer
** and the filename. The filename is used for messages etc.
** It does all manipulation of header-related CRCs, i.e.,
** checking generating header CRC. It deals only with text files.
*/
void hdrcrc (fptr, fname)
FILE *fptr;
char *fname;
{
char buf[LINESIZE];
int lino = 0;
char *ptr;
tcrc fcrc; /* crc recorded in file */
extern tcrc crccode;
int retval; /* return value from findcrc */
long hdrpos; /* where we found crc header in file */
crccode = INITCRC;
assert (!binary);
#ifndef NIXSEEK
hdrpos = ftell (fptr);
#endif
while (fgets (buf, LINESIZE, fptr) != NULL) {
#ifdef BRKTST
extern void brktst();
brktst();
#endif
lino++;
if (BRINCMP (buf, PATTERN, patlen) == 0) { /* found header */
#ifdef NIXSEEK
hdrpos = ftell (fptr); /* seek posn of line with header */
#endif
ptr = buf + patlen; /* point to beyond header */
while (*ptr != '\0' && whitespace(*ptr))
ptr++; /* skip white space */
fcrc = xatol (ptr); /* get stored crc */
while (xdigit(*ptr))
ptr++; /* skip past digits */
if (check1) {
if (*ptr == 'T') /* if 'T' suffix then */
trailing = 1; /* ..include trailing empty lines */
else
trailing = 0;
}
/* find CRC for rest of file */
(void) findcrc (fptr, fname, &retval);
if (gen1) { /* generating CRC */
if (updfile) { /* if updating file posn */
updatefile (fptr, hdrpos, crccode, fname); /* then do it */
if (prthdr && !silent) /* printing header */
printf (hdrfmt, crccode, fname);
} else {
if (prthdr && !silent) /* printing header */
printf (hdrfmt, crccode, fname);
else if (!silent)
printf (fmtstr, crccode, suffix(), blank, fname);
}
} else { /* checking CRC */
if (fcrc == crccode) {
if (verbose)
printf (fmtstr, crccode, suffix(), ok, fname);
} else {
if (!silent)
printf (fmtstr, crccode, suffix(), bad, fname);
errcount ++;
}
}
return;
} /* end if (BRINCMP (...) ) */
#ifndef NIXSEEK
hdrpos = ftell (fptr);
#endif
} /* end of while (fgets(...)) */
/* reach here if header not found -- this is an error */
if (!silent)
printf ("%10s %s\n", "????", fname);
errcount++;
return;
}
/* update file with CRC -- must be seekable */
void updatefile (fptr, hdrpos, crccode, fname)
FILE *fptr;
long hdrpos;
tcrc crccode;
char *fname;
{
char buf[LINESIZE];
int buflen; /* will hold count of chars in buf */
int chars_to_print; /* chars needed to fill in CRC */
/*
1 for blank, CHARSINCRC for actual CRC, and possibly
1 more for 'T' suffix if including trailing empty lines too
*/
chars_to_print = 1 + CHARSINCRC + (trailing ? 1 : 0);
#ifndef NIXSEEK
/* hdrpos is already seek position of header */
if (fseek (fptr, hdrpos, 0) != 0) { /* seek back */
fprintf(stderr,
"brik: error: No CRC written, seek failed on %s\n",fname);
return;
}
SEEKFIX
fgets (buf, LINESIZE, fptr);
if (BRINCMP (buf, PATTERN, patlen) == 0)
goto foundit;
fprintf(stderr,
"brik: error: No CRC written, header lost in %s\n",fname);
return;
#else
/* Following code does fseeks in a non-ANSI-conformant way */
/* hdrpos is seek position *after* header was read. Need to get back */
if (hdrpos >= BACKSIZE)
hdrpos -= BACKSIZE;
else
hdrpos = 0L;
if (fseek (fptr, hdrpos, 0) != 0) { /* seek back first */
fprintf(stderr,"brik: error: No CRC written, seek failed on %s\n",fname);
return;
}
/* now seek forward until we see CRC header again */
hdrpos = ftell (fptr);
while (fgets (buf, LINESIZE, fptr) != NULL) {
if (BRINCMP (buf, PATTERN, patlen) == 0)
goto foundit;
hdrpos = ftell (fptr);
}
fprintf(stderr,"brik: error: No CRC written, header lost in %s\n",fname);
return;
#endif /* NIXSEEK */
foundit: /* hdrpos points to line with header */
if (fseek (fptr, hdrpos, 0) != 0) { /* seek failed */
fprintf(stderr,"brik: error: No CRC written, seek failed on %s\n",fname);
return;
}
SEEKFIX
/* we are seeked back to the line with the CRC header */
#ifdef CHECKSEEK /* triple-check seeks */
{
char tmpbf1[LINESIZE];
char tmpbf2[LINESIZE];
fseek (fptr, hdrpos, 0);
assert (ftell (fptr) == hdrpos);
SEEKFIX
fgets (tmpbf1, LINESIZE, fptr);
fseek (fptr, 0L, 0); fseek (fptr, 0L, 2); /* exercise seeks */
fseek (fptr, hdrpos, 0);
assert (ftell (fptr) == hdrpos);
SEEKFIX
fgets (tmpbf2, LINESIZE, fptr);
if (strcmp(tmpbf1,tmpbf2) != 0 || BRINCMP(tmpbf1,PATTERN,patlen) != 0) {
fprintf (stderr,
"brik: error: Bad seek on %s, abandoning this file\n", fname);
return;
}
fseek (fptr, hdrpos, 0);
SEEKFIX
}
#endif /* CHECKSEEK */
#ifdef DEBUG
if (debugging) { /* zap newline, print buffer, restore newline */
int nlpos; char savech;
nlpos = strlen(buf) - 1; savech = buf[nlpos]; buf[nlpos] = '\0';
fprintf (stderr, "read header [%s]\n", buf);
buf[nlpos] = savech;
}
#endif
buflen = strlen (buf);
#ifdef DEBUG
if (debugging) /* need chars_to_print plus one trailing space or newline */
fprintf(stderr,"need %d chars, have %d\n",chars_to_print+1,buflen-patlen);
#endif
if (buflen - patlen > chars_to_print) { /* if enough space */
char sprbuf[1+CHARSINCRC+1+1+6]; /* blank+CRC+suffix+null+fudge */
char *ptr;
int i;
ptr = &buf[patlen]; /* point to beyond header */
sprintf (sprbuf, " %10lu%c", crccode, 'T');
for (i = 0; i < chars_to_print; i++) /* trailing 'T' possibly ignored */
ptr[i] = sprbuf[i];
if (ptr[i] != '\n')
ptr[i] = ' '; /* terminate with newline or blank */
fseek (fptr, 0L, 1); /* after read, must seek before write */
if (fwrite (buf, 1, buflen, fptr) != buflen) {
fprintf(stderr,
"brik: error: Write failed while writing CRC to %s\n",fname);
} else if (verbose)
printf (fmtstr, crccode, suffix(), blank, fname);
/* printf ("%10lu %s\n", crccode, fname); */
#ifdef DEBUG
buf[strlen(buf)-1] = '\0'; /* zap trailing newline */
if (debugging)
fprintf (stderr, "wrote header [%s]\n", buf);
#endif
} else {
fprintf(stderr,"brik: error: Not enough space for CRC in %s\n",fname);
return;
}
}
void longhelp()
{
printf ("%s\n", copyright);
printf (
"Usage: brik -cCgGsqvWHfbT [ file ] ... (must have one of -cCgG) \n\n");
printf ("Brik %s (%s) generates and verifies CRC-32 checksums. It can\n",
version, DATESTAMP);
printf ("\
also read or update a \"Checksum: xxxxxxxxxx\" header at the beginning\n\
of a line in which xxxxxxxxxx represents the CRC of all lines in the file\n\
*after* this header. A filename of \"-\" (or none) means standard input.\n\n\
");
printf ("\
-g look for Checksum: header, generate CRC for rest of file\n\
-c get CRC from header, verify CRC of rest of file\n\
-G generate CRC for entire file (add -b for binary files)\n\
-C verify all file CRCs from output of -G (-f is not needed)\n\
-b use binary mode -- read file byte by byte, not line by line\n\
-a automatically decide whether each file is text or binary\n\
");
#ifdef WILDCARD
printf (" -f read filenames (wildcards ok) from specified files\n");
#else
printf (" -f read filenames from specified files\n");
#endif
printf ("\
-v be verbose, report all results (else only errors are reported)\n\
-s be silent, say nothing, just return status code\n\
-q be quiet, don't print header for -G\n\
-W after generating CRC with -g, write it to original header\n\
-H after generating CRC with -g, print header to stdout\n\
-T include trailing empty lines, normally ignored (text mode only)\n\
");
exit (0);
}
/*
** Generates CRC of an open file, from current file position to end
** Except in -T mode, will ignore all trailing empty lines in text
** files. Algorithm for this is:
** 1. After each nonempty line, save crccode so far.
** 2. At end of file, if last line was empty, use saved crccode rather
** than current one.
** In whole-file mode, if was text mode but binary file, and if auto
** check is on, will re-open file in binary mode and do it again
** (except if stdin was being read)
** Returns 1 in retval if it detected that a text file contained binary
* characters.
*/
tcrc findcrc (fptr, fname, retval)
FILE *fptr;
char *fname;
int *retval;
{
int count;
char buf[LINESIZE];
extern tcrc crccode;
int warned = 0;
tcrc savedcrc; /* save crccode for trailing empty lines */
int buflen;
*retval = 0; /* will become 1 later if needed */
again: /* restart here if retrying in binary mode */
savedcrc = crccode = INITCRC;
if (binary) { /* binary */
while ((count = fread (buf, 1, LINESIZE, fptr)) > 0) {
#ifdef BRKTST
extern void brktst(); brktst();
#endif
addbfcrc (buf, count);
}
} else { /* text */
#ifdef CTRLZ_CHECK
int lines = 0; /* will count lines */
#endif /* CTRLZ_CHECK */
buflen = 1; /* assume empty lines so far */
while (fgets (buf, LINESIZE, fptr) != NULL) {
register char *p;
char *limit;
#ifdef BRKTST
extern void brktst(); brktst();
#endif
#ifdef CTRLZ_CHECK
lines++; /* count lines */
#endif /* CTRLZ_CHECK */
buflen = strlen (buf);
limit = buf + buflen;
for (p = buf; p != limit; p++) {
if (!warned && BINCHAR(*p)) {
*retval = 1;
if (autocheck && !is_stdin)/* restart, now known to be binary */
goto restart;
else { /* don't restart, just warn */
warned = 1;
}
}
if (*p == '\n')
*p = MYNL;
}
addbfcrc (buf, buflen);
if (buflen != 1)
savedcrc = crccode;
}
#ifdef CTRLZ_CHECK
if (gen2) {
int z_bin_check PARMS ((FILE *fptr, char *fname));
if (!warned && lines < Z_THRESHOLD && z_bin_check (fptr, fname)) {
*retval = 1;
if (autocheck && !is_stdin)
goto restart;
}
}
#endif
if (!trailing && buflen == 1)
crccode = savedcrc;
}
if (ferror (fptr))
fprintf (stderr, "brik: warning: error occurred while reading %s\n", fname);
return (crccode);
/*
reach here if we were trying to get a text crc but the file was binary, we
are in autocheck mode, and we are not reading stdin. Now we re-initialize
variables, reopen the file in binary mode, and begin again.
*/
restart:
binary = 1;
fclose (fptr); fptr = efopen (fname, BRIK_RDB, LVL_ERR);
if (fptr == NULL) {
errcount++;
return (crccode);
} else
goto again;
}
void printhdr ()
{
static int firsttime = 1;
if (firsttime && !quiet && !silent) {
printf ("%c Whole file CRCs generated by Brik v%s. Use \"brik -C\" to verify them.\n\n",
CMTCH, version);
printf ("%c CRC-32 filename\n", CMTCH);
printf ("%c ------ --------\n\n", CMTCH);
firsttime = 0;
}
}
/*
** Prints error message via perror(). The message is printed in the
** format "brik: %s: %s" where the first %s is the level text ("warning",
** "error", or "fatal") and the second %s is the string supplied by
** perror().
**
*/
void showerr (errmsg, level)
char *errmsg;
int level;
{
#define ERRSTRMAX 256 /* don't copy more than this many chars */
static char leveltext[][8] = {"warning", "error", "fatal"};
char errbuf[ERRBUFSIZ]; /* buffer for error message */
strcpy (errbuf, "brik: ");
assert (level >= LVL_WARN && level <= LVL_FATAL);
strncat (errbuf, leveltext[level], ERRSTRMAX);
strcat (errbuf, ": ");
strncat (errbuf, errmsg, ERRSTRMAX);
perror (errbuf);
}
void shorthelp()
{
fprintf (stderr, "%s\n\n%s", "Usage to get help: brik -h", copyright);
exit (1);
}