[comp.binaries.ibm.pc] v10inf03: brik shar

ibmbin-request@crdgw1.crd.ge.com (03/15/91)

Checksum: 1359967623  (Verify with "brik -cv")
Posting-number: Volume 10, Issue inf03
Originally-from: dhesi@bsu-cs.bsu.edu
Archive-name: admin/briksrc1

[ Date of last change Dec-08-1990 ]

#!/bin/sh
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   4104 -rw-r--r-- Install
#   3563 -rw-r--r-- Usenet
#   6391 -rw-r--r-- addbfcrc.c
#    754 -rw-r--r-- assert.h
#  26440 -rw-r--r-- brik.c
#  18671 -rw-r--r-- brik.doc
#   7035 -rw-r--r-- brik.h
#     66 -rw-r--r-- brik.prj
#    675 -rw-r--r-- descrip.mms
#   2808 -rw-r--r-- getopt.c
#    403 -rw-r--r-- makebrik.com
#    829 -rw-r--r-- makefile
#     86 -rw-r--r-- mkbsd
#    137 -rw-r--r-- mksysv
#    127 -rw-r--r-- mkuport
#     28 -rw-r--r-- options.opt
#   8118 -rw-r--r-- turboc.c
#   2419 -rw-r--r-- vms.c
#
# ============= Install ==============
echo "x - extracting Install (Text)"
sed 's/^X//' << 'SHAR_EOF' > Install &&
X                          
X                          INSTALLING BRIK 1.0
X
XThe following files should be in this package.  The files brik.exe and
Xtcconfig.tc are binary files.  All other files are text files with
Xlines terminated by linefeeds.
X
X   bytes      name             description
X   -----      ----             -----------
X    4104      Install          installation instructions
X    6391      addbfcrc.c       source
X     754      assert.h         source
X   26440      brik.c           source
X   18671      brik.doc         documentation
X   16710      brik.exe         executable for MS-DOS
X    7035      brik.h           source
X      66      brik.prj         project file for MS-DOS Turbo C 1.0
X     675      descrip.mms      makefile for VAX/VMS 4.7
X    2808      getopt.c         source for Turbo C 1.0 and VAX/VMS 4.7
X     403      makebrik.com     makefile for VAX/VMS 4.7
X     829      makefile         makefile for **IX
X      86      mkbsd            make script for 4.xBSD
X     137      mksysv           make script for System V
X     127      mkuport          make script for Microport System V/AT 2.2
X      28      options.opt      linker options for VAX/VMS 4.7
X    1380      tcconfig.tc      configuration file for MS-DOS Turbo C 1.0
X    8118      turboc.c         source for MS-DOS Turbo C 1.0
X    2419      vms.c            source file for VAX/VMS 4.7
X
XBrik is believed to compile and execute in the following environments:
X
X1.   MS-DOS 3.x, Turbo C 1.0
X2.   VAX/VMS 4.7 with VAX/VMS C 2.4
X3.   4.3BSD from Berkeley on a VAX-11/785
X4.   Microport System V/AT version 2.2
X
XMake sure all the needed files are in the current directory.  Then follow
Xinstructions below for your specific type of system.  If doing so doesn't
Xgive you a running copy of brik, read brik.h and experiment with the various
Xcompilation options.
X
X1.   MS-DOS, Turbo C 1.0
X
XUse the supplied tcconfig.tc configuration file.  Load the interactive
Xtc.exe compiler, revise those options that are different for your
Xsystem, and compile.  I don't know if this will work with Turbo C 2.0.
X
X2.   VAX/VMS
X
X2.1.   If you have DEC's make utility called "mms", proceed as follows:
X
X     a.   Delete "makefile" so mms won't get confused
X     b.   Type "mms" at the VMS prompt
X     c.   If all goes well, mms will compile and link the necessary files,
X          ending by creating "brik.exe" in the current directory.
X     d.   Move "brik.exe" wherever you want it and define a symbol with
X          a command line of the following type:
X
X               $ brik :== $my$disk:[bindir]brik.exe
X
X         where my$disk is the name of your device and bindir is the name
X         of the directory in which "brik.exe" is kept.
X
X2.2.  If you don't have "mms", use the command file supplied.  Invoke it as:
X
X     $ @makebrik
X
XWhen it exits, brik.exe should have been created in your current
Xdirectory, and the symbol "brik" should also have been defined for
Xyou.  If you move brik.exe to another directory be sure to redefine the
Xsymbol "brik" correctly as described above in part I.
X
XBe sure to read the section in the manul on VAX/VMS bugs.
X
X3.   4.xBSD
X
XInvoke the script "mkbsd" with the command "sh mkbsd".  Finally move
Xthe program "brik" into an appropriate directory and make sure that
Xthat directory is in your execution search path.
X
X4.   System V
X
XInvoke the script "mksysv" (for generic System V) or "mkuport" (for
XMicroport System V/AT) with the command "sh mksysv" or "sh mkuport".
XThe "mkuport" script will try to move the compiled "brik" into
X/usr/local/bin/brik so revise it if you don't want this done.  The
X"mksysv" script will create "brik" in the current directory ready to be
Xmoved to an appropriate directory in your search path.
X
XThe "mkuport" script compiles brik using the large memory model,
Xbecause an unexpected bug in Microport System V/AT made all my small-
Xmodel libraries vanish and I haven't had a chance to restore them from
Xbackups.  I suspect compiling in the small memory model will work.
X
X                                       -- Rahul Dhesi
X                                          1989/03/13
SHAR_EOF
# ============= Usenet ==============
echo "x - extracting Usenet (Text)"
sed 's/^X//' << 'SHAR_EOF' > Usenet &&
XFrom ibmbin Sun Mar 19 19:58:56 EST 1989
XArticle 1793 of comp.binaries.ibm.pc:
XPath: bsu-cs!ibmbin
X>From: dhesi@bsu-cs.bsu.edu (Rahul Dhesi)
XNewsgroups: comp.binaries.ibm.pc
XSubject: v01i217: brik, a general-purpose CRC-32 program v1.0 (part 01/02)
XSummary: brik.arc, a general-purpose CRC-32 program v1.0
XMessage-ID: <6105@bsu-cs.UUCP>
XDate: 14 Mar 89 09:01:09 GMT
XSender: news@bsu-cs.UUCP
XFollowup-To: comp.binaries.ibm.pc.d
XLines: 694
XApproved: dhesi@bsu-cs.bsu.edu
XX-Submissions-to: ibmpc-binaries@bsu-cs.bsu.edu
XX-Questions-to: ibmpc-binaries-request@bsu-cs.bsu.edu
X
XChecksum: 2208628413  (verify or update with "brik")
XPosting-number: Volume 01, Issue 217
XOriginally-from: Rahul Dhesi <dhesi@bsu-cs.bsu.edu>
XSubmitted-by: Rahul Dhesi <dhesi@bsu-cs.bsu.edu>
XArchive-name: brik10/part01
X
XI intend this program to be the standard comp.binaries.ibm.pc mechanism
Xfor automatic verification of incoming articles.  Once it is working,
Xyou will be able to tell tell at a glance whether an incoming posting
Xin comp.binaries.ibm.pc was received in corrupted form.
X
XThe executable for MS-DOS, and C source suitable for System V, 4.3BSD,
XVAX/VMS, and MS-DOS/Turbo C, are all in the archive.  However, the
Xfollowing description is not inside the archive.  Save it separately if
Xyou want to keep it.
X
XThis is brik version 1.0, a general-purpose program to generate and
Xverify 32-bit CRCs in both text and binary files.  The Checksum:
Xheaders in recent comp.binaries.ibm.pc postings contain CRCs that can
Xbe verified or updated with this program.
X
XAdvantages of brik over "sum" and most CRC programs I have seen are:
X
X(a) It is freely redistributable and its algorithm is not proprietary
X    or licensed by *T&T or anybody else.
X
X(b) It treats text files in a special way.  If you use brik to find
X    the CRCs of text files on an MS-DOS system, transfer the files to
X    a **IX system with Kermit and use brik on the **IX system, the
X    CRC calculated there will match the CRC calculated on the MS-DOS
X    system.  However, you can override this feature if you wish, 
X    and simply get a binary CRC for every byte in a file.
X
X(c) Brik will also look for a Checksum: header in any text file (or
X    C source file) and verify it based on the contents of the file
X    that occur *after* the header.  This allows Usenet software to
X    change the initial header portion of an article without affecting
X    your ability to check the integrity of all lines that occur
X    after the Checksum: header.  Brik itself also updates the Checksum:
X    header if needed.
X
X(d) Brik can create either text-mode or binary-mode CRCs for a bunch
X    of files that can be later checked by brik on the same or a
X    different system in one batch.  Although brik isn't designed for this
X    purpose, it can be used to keep track of files that change
X    unexpectedly (e.g. corrupted filesystems, viruses).  Since brik
X    will happily accept filenames on the command line, or from standard
X    input, or from a list inside one or more files, it is flexible and
X    will work well with other programs such as "find" (**IX) and
X    "stuff" (MS-DOS).
X
XTo verify the CRC of any comp.binaries.ibm.pc posting from the "rn"
Xnewsreader, type the command:
X
X	 | brik -c
X
XThis will feed the current article to "brik -c" as standard input.
XBrik will search for the Checksum: header, compare the CRC in that
Xheader with the calculated CRC of the rest of the file, and report any
Xmismatch.
X
XRahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee}!bsu-cs!dhesi
X                    ARPA:  dhesi@bsu-cs.bsu.edu
SHAR_EOF
# ============= addbfcrc.c ==============
echo "x - extracting addbfcrc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > addbfcrc.c &&
X/* @(#) addbfcrc.c 1.5 89/03/08 14:58:35 */
X/* Most of following CRC-32 stuff is from zmodem source code */
X
X#ifndef LINT
Xstatic char sccsid[]="::[[ @(#) addbfcrc.c 1.6 89/03/10 19:08:47 ]]::";
X#endif
X
X/* I claim no copyright over the contents of this file.  -- Rahul Dhesi */
X
X/*
XChecksum:  951252172      (check or update this with "brik")
X*/
X
X
Xlong crccode;
X
X/*
X * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
X * code or tables extracted from it, as desired without restriction.
X */
X
X/* First, the polynomial itself and its table of feedback terms.  The  */
X/* polynomial is                                                       */
X/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
X/* Note that we take it "backwards" and put the highest-order term in  */
X/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
X/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
X/* the MSB being 1.                                                    */
X
X/* Note that the usual hardware shift register implementation, which   */
X/* is what we're using (we're merely optimizing it by doing eight-bit  */
X/* chunks at a time) shifts bits into the lowest-order term.  In our   */
X/* implementation, that means shifting towards the right.  Why do we   */
X/* do it this way?  Because the calculated CRC must be transmitted in  */
X/* order from highest-order term to lowest-order term.  UARTs transmit */
X/* characters in order from LSB to MSB.  By storing the CRC this way,  */
X/* we hand it to the UART in the order low-byte to high-byte; the UART */
X/* sends each low-bit to hight-bit; and the result is transmission bit */
X/* by bit from highest- to lowest-order term without requiring any bit */
X/* shuffling on our part.  Reception works similarly.                  */
X
X/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
X/*                                                                     */
X/*     The table can be generated at runtime if desired; code to do so */
X/*     is shown later.  It might not be obvious, but the feedback      */
X/*     terms simply represent the results of eight shift/xor opera-    */
X/*     tions for all combinations of data and CRC register values.     */
X/*                                                                     */
X/*     The values must be right-shifted by eight bits by the "updcrc"  */
X/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
X/*     hardware you could probably optimize the shift in assembler by  */
X/*     using byte-swap instructions.                                   */
X
Xlong crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
X      0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
X      0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
X      0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
X      0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
X      0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
X      0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
X      0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
X      0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
X      0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
X      0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
X      0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
X      0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
X      0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
X      0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
X      0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
X      0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
X      0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
X      0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
X      0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
X      0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
X      0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
X      0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
X      0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
X      0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
X      0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
X      0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
X      0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
X      0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
X      0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
X      0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
X      0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
X      0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
X      0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
X      0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
X      0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
X      0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
X      0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
X      0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
X      0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
X      0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
X      0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
X      0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
X      0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
X      0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
X      0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
X      0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
X      0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
X      0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
X      0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
X      0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
X      0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
X      0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
X      0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
X      0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
X      0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
X      0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
X      0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
X      0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
X      0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
X      0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
X      0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
X      0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
X      0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
X      0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
X};
X
Xaddbfcrc (buf, size)
Xregister char *buf;
Xregister int size;
X{
X   int i;
X   for (i = 0;  i < size;  i ++) {
X      crccode = crc_32_tab[(int) ((crccode) ^ (buf[i])) & 0xff] ^
X         (((crccode) >> 8) & 0x00FFFFFFL);
X   }
X}
SHAR_EOF
# ============= assert.h ==============
echo "x - extracting assert.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > assert.h &&
X/* @(#) assert.h 1.5 89/03/08 14:59:02 */
X
X/* I claim no copyright over the contents of this file.  -- Rahul Dhesi */
X
X/*
XChecksum: 3376323427      (check or update this with "brik")
X*/
X
X/*
X**   Assertions are enabled only if NDEBUG is not defined.
X**   Not all compilers define __FILE__ and __LINE__.  If yours
X**   doesn't, you can just let NDEBUG remain #defined in brik.h and no
X**   assertions will be compiled in.  Or, if you want to enable
X**   assertions, redefine the assert() macro so it works with your
X**   compiler.
X*/
X
X#ifndef OK_STDIO
X# include <stdio.h>
X# define OK_STDIO
X#endif
X
X#ifndef NDEBUG
X#define assert(E) \
X{if(!(E))fprintf(stderr,"Assertion error in %s line %d\n",__FILE__,__LINE__);}
X#else
X#define assert(E)
X#endif /* NDEBUG */
SHAR_EOF
# ============= brik.c ==============
echo "x - extracting brik.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > brik.c &&
X/* ::[[ @(#) brik.c 1.44 89/03/12 14:34:35 ]]:: */
X#ifndef LINT
X static char sccsid[]="::[[ @(#) brik.c 1.44 89/03/12 14:34:35 ]]::";
X#endif
X
X#define DATESTAMP "1989/03/12 14:34:35"
X
X/*
X(c) Copyright 1989 Rahul Dhesi, All rights reserved.  Permission is
Xgranted to copy and distribute this file in modified or unmodified
Xform, for any purpose whether commercial or noncommercial, provided
Xthat (a) this paragraph, and the author identification printed by
Xthe program, are preserved unchanged, and (b) no attempt is made to
Xrestrict redistribution of this file.  Inclusion of this file in a
Xcollection whose distribution is restricted by a compilation copyright
Xshall be considered an attempt to restrict redistribution of this file.
XNotwithstanding the above, there are no restrictions on the copying or
Xdistribution of not-human-readable executable machine code created by
Xprocessing this file with a language translator.
X*/
X
X/*
XChecksum: 1280097858      (check or update this with "brik")
X*/
X
X/*
XThe following code assumes the ASCII character set and 8-bit bytes.
X*/
X
X#ifndef OK_STDIO
X# include <stdio.h>
X# define OK_STDIO
X#endif
X
X#include "brik.h"          /* configuration options */
X#include "assert.h"
X
XFILE *fopen();
XFILE *efopen();
Xchar *fgets();
Xint fclose();
Xchar *strchr();
Xint strlen();
Xint strcmp();
Xchar *strcat();
Xint fseek();
Xlong ftell();
Xint fwrite();
Xvoid hdrcrc();
Xvoid showerr();
Xvoid longhelp();
Xvoid shorthelp();
Xlong findcrc();
X
X#ifdef ANSIPROTO
Xvoid addbfcrc (char *, int);
Xint printhdr (void);
XFILE *efopen (char *, char *, int);
Xlong xatol (char *);
Xint main (int, char **);
Xint dofname (char *);
Xint dofptr (FILE *, char *);
Xint whole_check (FILE *, char *);
Xvoid hdrcrc (FILE *, char *);
Xlong findcrc (FILE *, char *);
Xint updatefile (FILE *, long, long, char *);
Xvoid longhelp(void);
Xvoid shorthelp(void);
Xvoid showerr (char *, int);
Xchar suffix(void);
Xint lowerit (int);
X
Xint strlen (char *);
Xchar *strchr (char *, char);
Xchar *strcpy (char *, char *);
Xchar *strcat (char *, char *);
Xchar *strncat (char *, char *, int);
Xint getopt (int, char **, char *);
Xvoid exit (int);
Xint strcmp (char *, char *);
Xint readnames (FILE *);
Xchar *nextfile (int, char *, int);
Xvoid brktst(void);
X#endif
X
X#define MYNL      10       /* newline for CRC calculation */
X#define ERRLIMIT 127       /* exit(n) returns n not exceeding this */
X#define LINESIZE  8192     /* handle lines of up to this length */
X#define ERRBUFSIZ 1024     /* buffer size for perror() message */
X#define PATTERN   "Checksum:"    /* look for this header */
X#define CHARSINCRC 10      /* characters in CRC */
X#define BACKSIZE  1024     /* how much to seek back looking for header */
X#define CMTCH     '#'      /* begins comment in CRC list */
X
X/* define macro for testing if chars within range */
X#ifndef BINCHAR
X# define LOW_PRINT '\007'   /* smallest printable char */
X# define HIGH_PRINT '\176'  /* biggest printable char */
X# define BINCHAR(c)     ((c) < LOW_PRINT || (c) > HIGH_PRINT)
X#endif /* BINCHAR */
X
X/* error levels */
X#define LVL_WARN  0
X#define LVL_ERR   1
X#define LVL_FATAL 2
X
X#ifdef  USEINDEX
X# define strchr   index
X#endif  /* USEINDEX */
X
X#ifdef TRAIL_T             /* need trailing "t" in fopen string */
X# define BRIK_RD  "rt"
X# define BRIK_RW  "r+t"
X# define BRIK_RDB "rb"
X#else
X# define BRIK_RD  "r"
X# define BRIK_RW  "r+"
X# define BRIK_RDB "r"
X#endif   /* TRAIL_T */
X
X#define  whitespace(x)     (strchr(" \t\n",(x)) != NULL)
X/* format strings for printing CRCs and filenames etc. */
Xstatic char ok[] =      "ok ";
Xstatic char bad[] =     "BAD";
Xstatic char blank[] =   "   ";
Xstatic char fmtstr[] = "%10lu%c %s %s\n";
X
X
Xint patlen;                /* length of PATTERN */
Xint errcount = 0;          /* count of errors */
Xint gen1 = 0;              /* generate CRCs for all files */
Xint gen2 = 0;              /* generate CRCs for files with headers */
Xint silent = 0;            /* be quiet, just set error status */
Xint verbose = 0;           /* be verbose, print message for good files too */
Xint updfile = 0;           /* update file by inserting CRC */
Xint check1 = 0;            /* whether to check header crcs */
Xint check2 = 0;            /* whether to check whole file crcs */
Xint fromfile = 0;          /* read filenames from a file */
Xint binary = 0;            /* manipulate binary file */
Xint trailing = 0;          /* include trailing empty lines */
X
X#ifdef DEBUG
Xint debugging = 0;
X#endif
X
X/* opens file, prints error message if can't open */
XFILE *efopen (fname, mode, level)
Xchar *fname;               /* filename to open */
Xchar *mode;                /* mode, e.g. "r" or "r+" */
Xint level;                 /* error level */
X{
X   FILE *fptr;
X   fptr = fopen (fname, mode);
X   if (fptr == NULL)
X      showerr (fname, level);
X   return (fptr);
X}
X
X/* LOWERIT is a function or macro that returns lowercase of a character */
X#ifndef LOWERIT
X# ifdef AVOID_MACROS
X#  define LOWERIT    lowerit
X# else
X#  define LOWERIT(c)        ((c)>='A' && (c)<='Z' ? ('a'-'A')+(c) : (c))
X# endif
X#endif
X
X/* Function needed by SEEKFIX code even if a macro is available */
Xint lowerit (c) int c;  /* returns lowercase of an ASCII character */
X{
X  if (c >= 'A' && c <= 'Z') return (('a'-'A') + c);
X  else return (c);
X}
X
X/* STRNICMP is a case-insensitive strncmp */
X#ifndef STRNICMP
Xint STRNICMP (s1, s2, n)
Xregister char *s1, *s2;
Xint n;
X{
X   assert (n >= 0);
X   assert (LOWERIT('X') == 'x');
X   assert (LOWERIT('*') == '*');
X
X   for ( ; LOWERIT(*s1) == LOWERIT(*s2);  s1++, s2++) {
X      if (--n == 0 || *s1 == '\0')
X         return(0);
X   }
X   return(LOWERIT(*s1) - LOWERIT(*s2));
X}
X#endif /* STRNICMP */
X
X#ifdef AVOID_MACROS
X# define BRINCMP     STRNICMP
X#else
X# define BRINCMP(s1,s2,n) (LOWERIT(*(s1))!=LOWERIT(*(s2))||STRNICMP(s1,s2,n))
X#endif
X
X
X#define xdigit(x)    ((x) >= '0' && (x) <= '9')
X
X/*
Xxatol is given a string that (supposedly) begins with a string
Xof digits.  It returns a corresponding positive numeric value.
X*/
Xlong xatol (str)
Xchar *str;
X{
X   long retval;
X   retval = 0L;
X   while (xdigit(*str)) {
X      retval = retval * 10L + (*str-'0');
X      str++;
X   }
X   return (retval);
X}
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X   int i;
X   int c;                        /* next option letter */
X   int count = 0;                /* count of required options seen */
X   char *infname;                /* name of file to read filenames from */
X   FILE *infptr;                 /* open file ptr for infname */
X
X   extern int optind;            /* from getopt: next arg to process */
X   extern int opterr;            /* used by getopt */
X
X   opterr = 0;                   /* so getopt won't print err msg */
X
X   patlen = strlen (PATTERN);
X
X#ifdef DEBUG
X   while ((c = getopt (argc, argv, "cCgGsvWfbThd")) != EOF)
X#else
X   while ((c = getopt (argc, argv, "cCgGsvWfbTh")) != EOF)
X#endif
X   {
X      switch (c) {
X         case 'c':   check1++; count++; break;
X         case 'C':   check2++; count++; break;
X         case 'g':   gen1++; count++; break;
X         case 'G':   gen2++; count++; break;
X         case 's':   silent++; verbose = 0; break;
X         case 'v':   verbose++; silent = 0; break;
X         case 'W':   updfile++; break;
X         case 'f':   fromfile++; break;
X         case 'b':   binary++; trailing = 0; break;
X         case 'T':   trailing++; binary = 0; break;
X#ifdef DEBUG
X         case 'd':   debugging++; break;
X#endif
X         case 'h':   longhelp();
X         case '?':   shorthelp();
X      }
X   }
X
X   if (count != 1)
X      shorthelp();
X
X   if (binary && (check1 || gen1)) {
X      fprintf (stderr, "brik: fatal: Can't read or update CRC header in binary mode\n");
X      exit (1);
X   }
X
X   if (updfile && !gen1) {
X      fprintf (stderr, "brik: fatal: Use of -W requires -g\n");
X      exit (1);
X   }
X
X   if ((gen1 || gen2) && !updfile)
X      silent = 0;
X
X   i = optind;
X
X   if (fromfile) {                  /* read filenames from file */
X      if (i >= argc) {              /* need filenames after -f */
X         fprintf (stderr, "brik: fatal: Filename(s) needed after -f\n");
X         exit (1);
X      }
X      for (; i < argc;  i++) {
X         infname = argv[i];
X         if (strcmp(infname, "-") == 0) { /* "-" means stdin */
X            readnames (stdin);
X         } else {
X#ifdef WILDCARD
X            extern char *nextfile();
X            nextfile (0, infname, 0);     /* initialize fileset 0 */
X            while ((infname = nextfile(1, (char *) NULL, 0)) != NULL) {
X               infptr = efopen (infname, BRIK_RD, LVL_ERR);
X               readnames (infptr);
X               fclose (infptr);
X            }
X#else
X            infptr = efopen (infname, BRIK_RD, LVL_ERR);
X            readnames (infptr);
X            fclose (infptr);
X#endif /* WILDCARD */
X         }
X      }
X   } else {                         /* read filenames from command line */
X      if (i >= argc) {
X#ifdef TRAIL_T
X         if (binary) {
X            fprintf (stderr, "brik: fatal: Can't handle stdin in binary mode\n");
X            exit (1);
X         }
X#endif
X         dofptr (stdin, "stdin");      /* if no files, read stdin */
X      } else {
X         for (;  i < argc;  i ++) {
X#ifdef WILDCARD
X            extern char *nextfile();
X            char *one_name;               /* a matching filename */
X            nextfile (0, argv[i], 0);     /* initialize fileset 0 */
X            while ((one_name = nextfile(1, (char *) NULL, 0)) != NULL)
X               dofname (one_name);
X#else
X            dofname (argv[i]);
X#endif /* WILDCARD */
X         }
X      }
X   }
Xerrexit:
X   if (errcount > ERRLIMIT)
X      errcount = ERRLIMIT;       /* don't overflow status code */
X   exit (errcount);
X   /*NOTREACHED*/
X}
X
X/*
X**   Reads names from supplied file pointer and handles them.  Just
X**   returns if supplied NULL file pointer.  Will also expand wildcards
X**   in names read from this file.
X*/
Xreadnames (infptr)
XFILE *infptr;
X{
X   char buf[LINESIZE];
X   if (infptr == NULL)
X      return;
X   while (fgets (buf, LINESIZE, infptr) != NULL) {
X#ifdef WILDCARD
X      char *fname;                  /* matching filename */
X      extern char *nextfile();
X#endif /* WILDCARD */
X      buf[strlen(buf)-1] = '\0'; /* zap trailing newline */
X#ifdef WILDCARD
X      nextfile (0, buf, 1);     /* initialize fileset 1 */
X      while ((fname = nextfile(1, (char *) NULL, 1)) != NULL) {
X         dofname (fname);
X      }
X#else
X      dofname (buf);
X#endif /* WILDCARD */
X   }
X}
X
X/* do one filename */
Xdofname (this_arg)
Xchar *this_arg;
X{
X   FILE *this_file;
X   char *mode;                         /* "r", "rb", "rw", etc. for fopen */
X#ifdef BRKTST
X   extern void brktst();
X   brktst();
X#endif
X
X   if (strcmp(this_arg,"-") == 0) {
X#ifdef TRAIL_T
X      if (binary) {
X         fprintf (stderr, "brik: fatal: Can't handle stdin in binary mode\n");
X         exit (1);
X      }
X#endif
X      this_file = stdin;
X      this_arg = "stdin";
X   } else {
X      if (updfile) {
X         assert (!binary);
X         this_file = efopen (this_arg, BRIK_RW, LVL_ERR);
X      } else {
X         if (binary && !check2) /* check2 reads filenames, not data */
X            mode = BRIK_RDB;
X         else
X            mode = BRIK_RD;
X         this_file = efopen (this_arg, mode, LVL_ERR);
X      }
X   }
X   if (this_file == NULL)
X      errcount++;
X   else {
X#ifdef NOCASE
X      char *p;
X      for (p = this_arg;  *p != '\0';  p++)
X         *p = LOWERIT(*p);
X#endif
X      dofptr (this_file, this_arg);
X      fclose (this_file);
X   }
X}
X
Xchar suffix()
X{
X   return (binary ? 'b' : (trailing ? 'T' : ' '));
X}
X
X
X/*
X**   Do one file pointer.  Decides if CRC header will be read or written,
X**   or whether just the whole file will be read.
X*/
Xdofptr (fptr, fname)
XFILE *fptr;
Xchar *fname;
X{
X   if (check2)
X      whole_check (fptr, fname);    /* do whole file check from list */
X   else if (gen1 || check1)         /* header-based CRC check or update */
X      hdrcrc (fptr, fname);
X   else {                           /* whole-file CRC calculation */
X      extern long crccode;
X      assert (gen2);
X      printhdr();
X      findcrc (fptr, fname);
X      printf (fmtstr, crccode, suffix(), blank, fname);
X   }
X}
X
X
X/* Does whole file check from a list of files and CRCs */
Xwhole_check (fptr, listname)
XFILE *fptr;                   /* open file ptr of CRC list file */
Xchar *listname;               /* name of CRC list file */
X{
X   long fcrc;                 /* recorded crc */
X   char *fname;               /* name of file whose CRC being checked */
X   char buf [LINESIZE];       /* line buffer */
X   char *p;                   /* temp ptr */
X   FILE *orgfile;             /* file pointer for original file to check */
X   int lino = 0;              /* line no. in list file for error msg */
X   char *mode;                /* mode string for fopen */
X
X   while (fgets (buf, LINESIZE, fptr) != NULL) {
X      lino++;
X      p = buf;
X      if (*p == CMTCH)              /* skip comment lines */
X         continue;
X      while (*p != '\0' && whitespace(*p))      /* skip whitespace */
X         p++;
X      if (*p == '\0')
X         continue;                              /* skip empty lines */
X      if (!xdigit(*p))
X         goto badline;
X      fcrc = xatol (p); /* recorded CRC */
X
X      while (xdigit(*p))
X         p++;                                   /* skip past numeric chars */
X
X      binary = trailing = 0;
X      if (*p == 'b')                            /* 'b' means binary */
X         binary = 1;
X
X      if (*p == 'T')                            /* 'T' means trailing mode */
X         trailing = 1;
X
X      while (*p != '\0' && !whitespace(*p)) /* to whitespace */
X         p++;
X      while (whitespace(*p))   /* skip whitespace */
X         p++;
X
X      if (*p == '\n' || *p == '\0') {     /* if at end of line */
X         goto badline;
X      }
X      fname = p;
X      while (*p != '\0' && !whitespace(*p))  /* skip to whitespace */
X         p++;
X      *p = '\0';                    /* null-terminate filename */
X
X      if (binary)
X         mode = BRIK_RDB;
X      else
X         mode = BRIK_RD;
X
X      orgfile = efopen (fname, mode, LVL_ERR);
X      if (orgfile == NULL) {
X         errcount++;
X      } else {
X         long foundcrc;
X         assert (!(binary && trailing));
X         foundcrc = findcrc (orgfile, fname);
X         if (foundcrc == fcrc) {
X            if (verbose)
X               printf (fmtstr, foundcrc, suffix(), ok, fname);
X         } else {
X            if (!silent)
X               printf (fmtstr, foundcrc, suffix(), bad, fname);
X            errcount ++;
X         }
X         fclose (orgfile);
X      }
X   }
X   return;
Xbadline:
X   fprintf (stderr,
X      "brik: error: Abandoning %s due to badly formatted line %d\n",
X      listname, lino);
X   return;
X}
X
X
X/*
XInitializing the CRC to all one bits avoids failure of detection
Xshould entire data stream get cyclically bit-shifted by one position.
XThe calculation of the probability of this happening is left as
Xan exercise for the reader.
X*/
X#define INITCRC   0xFFFFFFFFL;
X
X/*
X**   hdrcrc processes one file given an open file pointer
X**   and the filename.  The filename is used for messages etc.
X**   It does all manipulation of header-related CRCs, i.e.,
X**   checking generating header CRC.  It deals only with text files.
X*/
Xvoid hdrcrc (fptr, fname)
XFILE *fptr;
Xchar *fname;
X{
X   char buf[LINESIZE];
X   int lino = 0;
X   char *ptr;
X   long fcrc;   /* crc recorded in file */
X   extern long crccode;
X   long hdrpos;                     /* where we found crc header in file */
X
X   crccode = INITCRC;
X
X   assert (!binary);
X
X#ifndef NIXSEEK
X   hdrpos = ftell (fptr);
X#endif
X   while (fgets (buf, LINESIZE, fptr) != NULL) {
X#ifdef BRKTST
X      extern void brktst();
X      brktst();
X#endif
X      lino++;
X      if (BRINCMP (buf, PATTERN, patlen) == 0) {      /* found header */
X#ifdef NIXSEEK
X         hdrpos = ftell (fptr);        /* seek posn of line with header */
X#endif
X         ptr = buf + patlen;           /* point to beyond header */
X         while (*ptr != '\0' && whitespace(*ptr))
X            ptr++;                     /* skip white space */
X         fcrc = xatol (ptr);           /* get stored crc */
X         while (xdigit(*ptr))
X            ptr++;                     /* skip past digits */
X         if (check1) {
X            if (*ptr == 'T')           /* if 'T' suffix then */
X               trailing = 1;          /* ..include trailing empty lines */
X            else
X               trailing = 0;
X         }
X
X         findcrc (fptr, fname);        /* find CRC for rest of file */
X
X         if (gen1) {                   /* generating CRC */
X            if (updfile) {             /* if updating file posn */
X               updatefile (fptr, hdrpos, crccode, fname); /* then do it */
X            } else if (!silent)
X               printf (fmtstr, crccode, suffix(), blank, fname);
X         } else {                      /* checking CRC */
X            if (fcrc == crccode) {
X               if (verbose)
X                  printf (fmtstr, crccode, suffix(), ok, fname);
X            } else {
X               if (!silent)
X                  printf (fmtstr, crccode, suffix(), bad, fname);
X               errcount ++;
X            }
X         }
X         return;
X      } /* end if (BRINCMP (...) ) */
X#ifndef NIXSEEK
X      hdrpos = ftell (fptr);
X#endif
X   } /* end of while (fgets(...)) */
X
X   /* reach here if header not found -- this is an error */
X   if (!silent)
X      printf ("%10s      %s\n", "????", fname);
X   errcount++;
X   return;
X}
X
X/* update file with CRC -- must be seekable */
Xupdatefile (fptr, hdrpos, crccode, fname)
XFILE *fptr;
Xlong hdrpos;
Xlong crccode;
Xchar *fname;
X{
X   char buf[LINESIZE];
X   int buflen;             /* will hold count of chars in buf */
X   int chars_to_print;     /* chars needed to fill in CRC */
X
X   /*
X   1 for blank, CHARSINCRC for actual CRC, and possibly
X   1 more for 'T' suffix if including trailing empty lines too
X   */
X   chars_to_print = 1 + CHARSINCRC + (trailing ? 1 : 0);
X
X#ifndef NIXSEEK
X   /* hdrpos is already seek position of header */
X   if (fseek (fptr, hdrpos, 0) != 0) { /* seek back */
X      fprintf(stderr,
X         "brik: error: No CRC written, seek failed on %s\n",fname);
X      return;
X   }
X
XSEEKFIX
X
X   fgets (buf, LINESIZE, fptr);
X   if (BRINCMP (buf, PATTERN, patlen) == 0)
X      goto foundit;
X   fprintf(stderr,
X      "brik: error: No CRC written, header lost in %s\n",fname);
X   return;
X#else
X   /* Following code does fseeks in a non-ANSI-conformant way */
X   /* hdrpos is seek position *after* header was read.  Need to get back */
X   if (hdrpos >= BACKSIZE)
X      hdrpos -= BACKSIZE;
X   else
X      hdrpos = 0L;
X   if (fseek (fptr, hdrpos, 0) != 0) {       /* seek back first */
X      fprintf(stderr,"brik: error: No CRC written, seek failed on %s\n",fname);
X      return;
X   }
X   /* now seek forward until we see CRC header again */
X   hdrpos = ftell (fptr);
X   while (fgets (buf, LINESIZE, fptr) != NULL) {
X      if (BRINCMP (buf, PATTERN, patlen) == 0)
X         goto foundit;
X      hdrpos = ftell (fptr);
X   }
X   fprintf(stderr,"brik: error: No CRC written, header lost in %s\n",fname);
X   return;
X#endif /* NIXSEEK */
X
Xfoundit:    /* hdrpos points to line with header */
X   if (fseek (fptr, hdrpos, 0) != 0) { /* seek failed */
X      fprintf(stderr,"brik: error: No CRC written, seek failed on %s\n",fname);
X      return;
X   }
XSEEKFIX
X   /* we are seeked back to the line with the CRC header */
X
X#ifdef CHECKSEEK  /* triple-check seeks */
X   {
X      char tmpbf1[LINESIZE];
X      char tmpbf2[LINESIZE];
X      fseek (fptr, hdrpos, 0);
X      assert (ftell (fptr) == hdrpos);
XSEEKFIX
X      fgets (tmpbf1, LINESIZE, fptr);
X      fseek (fptr, 0L, 0); fseek (fptr, 0L, 2);    /* exercise seeks */
X      fseek (fptr, hdrpos, 0);
X      assert (ftell (fptr) == hdrpos);
XSEEKFIX
X      fgets (tmpbf2, LINESIZE, fptr);
X      if (strcmp(tmpbf1,tmpbf2) != 0 || BRINCMP(tmpbf1,PATTERN,patlen) != 0) {
X         fprintf (stderr,
X            "brik: error: Bad seek on %s, abandoning this file\n", fname);
X         return;
X      }
X      fseek (fptr, hdrpos, 0);
XSEEKFIX
X   }
X#endif /* CHECKSEEK */
X
X#ifdef DEBUG
X   if (debugging) {  /* zap newline, print buffer, restore newline */
X      int nlpos; char savech;
X      nlpos = strlen(buf) - 1;  savech = buf[nlpos];  buf[nlpos] = '\0';
X      fprintf (stderr, "read header  [%s]\n", buf);
X      buf[nlpos] = savech;
X   }
X#endif
X
X   buflen = strlen (buf);
X#ifdef DEBUG
X   if (debugging)  /* need chars_to_print plus one trailing space or newline */
X      fprintf(stderr,"need %d chars, have %d\n",chars_to_print+1,buflen-patlen);
X#endif
X   if (buflen - patlen > chars_to_print) {      /* if enough space */
X      char sprbuf[1+CHARSINCRC+1+1+6];  /* blank+CRC+suffix+null+fudge */
X      char *ptr;
X      int i;
X      ptr = &buf[patlen];                 /* point to beyond header */
X      sprintf (sprbuf, " %10lu%c", crccode, 'T');
X      for (i = 0;  i < chars_to_print;  i++) /* trailing 'T' possibly ignored */
X         ptr[i] = sprbuf[i];
X      if (ptr[i] != '\n')
X         ptr[i] = ' ';           /* terminate with newline or blank */
X      fseek (fptr, 0L, 1);       /* after read, must seek before write */
X      if (fwrite (buf, 1, buflen, fptr) != buflen) {
X         fprintf(stderr,
X            "brik: error: Write failed while writing CRC to %s\n",fname);
X      } else if (verbose)
X         printf (fmtstr, crccode, suffix(), blank, fname);
X         /* printf ("%10lu      %s\n", crccode, fname); */
X#ifdef DEBUG
X      buf[strlen(buf)-1] = '\0'; /* zap trailing newline */
X      if (debugging)
X         fprintf (stderr, "wrote header [%s]\n", buf);
X#endif
X   } else {
X      fprintf(stderr,"brik: error: Not enough space for CRC in %s\n",fname);
X      return;
X   }
X}
X
Xvoid longhelp()
X{
Xprintf ("     Brik 1.0 (%s), a free CRC-32 program by Rahul Dhesi\n\n",
X                        DATESTAMP);
X
Xprintf ("Usage:  brik -cCgGsvWfbT [ file ] ...\n\n");
X
Xprintf ("Brik 1.0 generates and verifies 32-bit CRC values (checksums).  Optionally\n");
Xprintf ("it will read or update a \"Checksum: xxxxxxxxxx\" header at the beginning of\n");
Xprintf ("a line in which xxxxxxxxxx represents the CRC of all lines in the file\n");
Xprintf ("*after* this header.  One of -c, -C, -g, or -G is required.  If no\n");
X#ifdef WILDCARD
Xprintf ("filename is given, or if a filename is -, standard input is read.\n");
Xprintf ("Wildcards are allowed on the command line and in files read with -f.\n\n");
X#else
X/* extra newline */
Xprintf ("filename is given, or if a filename is -, standard input is read.\n\n");
X#endif
X
Xprintf ("   -g     look for Checksum: header, generate CRC for rest of file\n");
Xprintf ("   -c     get CRC from header, verify CRC of rest of file\n");
Xprintf ("   -G     generate CRC for entire file (add -b for binary files)\n");
Xprintf ("   -C     verify all file CRCs from output of -G (-f is not needed)\n");
Xprintf ("   -b     use binary mode--read file byte by byte, not line by line\n");
X
X#ifdef WILDCARD
Xprintf ("   -f     read filenames (wildcards ok) from specified files\n");
X#else
Xprintf ("   -f     read filenames from specified files\n");
X#endif
X
Xprintf ("   -v     be verbose, report all results (else only errors are reported)\n");
Xprintf ("   -s     be silent, say nothing, just return status code\n");
Xprintf ("   -W     after generating CRC with -g, write it to original header\n");
Xprintf ("   -T     include trailing empty lines, normally ignored (text mode only)\n\n");
X
X#ifndef EXITBUG
Xprintf ("The exit code is the number of files with bad or missing CRCs.\n");
X#endif
X
Xexit (1);
X}
X
X/*
X**   Generates CRC of an open file, from current file position to end
X**   Except in -T mode, will ignore all trailing empty lines in text
X**   files.  Algorithm for this is:
X**      1.   After each nonempty line, save crccode so far.
X**      2.   At end of file, if last line was empty, use saved crccode rather
X**           than current one.
X*/
X
Xlong findcrc (fptr, fname)
XFILE *fptr;
Xchar *fname;
X{
X   int count;
X   char buf[LINESIZE];
X   extern long crccode;
X   int warned = 0;
X   long savedcrc;       /* save crccode here to handle trailing empty lines */
X   int buflen;
X
X   savedcrc = crccode = INITCRC;
X
X   if (binary) {                                   /* binary */
X      while ((count = fread (buf, 1, LINESIZE, fptr)) > 0) {
X#ifdef BRKTST
X         extern void brktst(); brktst();
X#endif
X         addbfcrc (buf, count);
X      }
X      return (crccode);
X   } else {                                           /* text */
X      buflen = 1;                   /* assume empty lines so far */
X      while (fgets (buf, LINESIZE, fptr) != NULL) {
X         char *p;
X         char *limit;
X#ifdef BRKTST
X         extern void brktst(); brktst();
X#endif
X         buflen = strlen (buf);
X         limit = buf + buflen;
X         for (p = buf;  p != limit;  p++) {
X            if (!warned && BINCHAR(*p)) {
X               fprintf (stderr,
X                  "brik: warning: File %s is probably binary, don't trust text mode CRC\n",
X                  fname);
X               warned = 1;
X            }
X            if (*p == '\n')
X               *p = MYNL;
X         }
X         addbfcrc (buf, buflen);
X         if (buflen != 1)
X            savedcrc = crccode;
X      }
X      if (!trailing && buflen == 1)
X         crccode = savedcrc;
X      return (crccode);
X   }
X}
X
Xprinthdr ()
X{
X   static int firsttime = 1;
X   if (firsttime) {
X      printf ("%c Whole file CRCs generated by Brik v1.0.  Use \"brik -C\" to verify them.\n\n",
X         CMTCH);
X        printf ("%c CRC-32        filename\n", CMTCH);
X        printf ("%c ------        --------\n\n", CMTCH);
X      firsttime = 0;
X   }
X}
X
X/*
X**   Prints error message via perror().  The message is printed in the
X**   format "brik: %s: %s" where the first %s is the level text ("warning",
X**   "error", or "fatal") and the second %s is the string supplied by
X**   perror().
X**
X**   superfluous right now because it is only called from efopen()
X**   and only with level = LVL_ERR.
X*/
X
Xvoid showerr (errmsg, level)
Xchar *errmsg;
Xint level;
X{
X#define ERRSTRMAX  40         /* don't copy more than this many chars */
X   static char leveltext[][7] =   {"warning", "error", "fatal"};
X   char errbuf[ERRBUFSIZ];       /* buffer for error message */
X   strcpy (errbuf, "brik: ");
X   assert (level >= LVL_WARN && level <= LVL_FATAL);
X   strncat (errbuf, leveltext[level], ERRSTRMAX);
X   strcat (errbuf, ": ");
X   strncat (errbuf, errmsg, ERRSTRMAX);
X   perror (errbuf);
X}
X
Xvoid shorthelp()
X{
X   fprintf (stderr,
X   "brik: fatal: One of -cCgG required, -svWfbT are optional (-h for help)\n");
X   exit (1);
X}
SHAR_EOF
echo "End of part 1, continue with part 2"
exit 0