home *** CD-ROM | disk | FTP | other *** search
- /* ::[[ @(#) 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);
- }
-