[comp.sources.misc] v06i025: Yet Another Checksumming Program

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (01/30/89)

Posting-number: Volume 6, Issue 25
Submitted-by: naz@hslrswi.UUCP (Norman H. Azadian)
Archive-name: chksum

#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r--  1 naz          1991 Jan 25 15:14 readme
# -rw-r--r--  1 naz           536 Jan 25 15:05 makefile
# -rw-r--r--  1 naz           436 Jan 25 14:53 debug.h
# -rw-r--r--  1 naz          2837 Jan 25 14:41 gen.h
# -rw-r--r--  1 naz          8136 Jan 25 14:41 chksum.c
# -rw-r--r--  1 naz         11016 Jan 25 15:14 crc32.c
#
echo 'x - readme'
if test -f readme; then echo 'shar: not overwriting readme'; else
sed 's/^X//' << '________This_Is_The_END________' > readme
X
XChksum is a little program that I've developed and used a lot over the
Xyears. The prime difference between it and the ones that it copies, is
Xthat it can read a list of pathnames from stdin.  This turns out to be
Xvery handy indeed. Also, it uses a 32-bit CRC, which means that a false
Xmatch is 2**16 times less likely than with the 16-bit brands.  It
Xproduces identical results on both PCs and VAXen.
X
XThe 32-bit CRC routine was donated by kind souls on the net.  I have
Xtweaked it for my use, principally by adding inline optimized assembly
Xcode for my PC. I don't pretend to know what is going on inside, and I
Xregard it as a minor miracle that it actually produces the same numbers
Xon PCs as on VAXen.  Perhaps somebody will tell me if it produces the
X"right" numbers.
X
XI've developed it on an Aztec C compiler, currently version 4.10a.  You
Xshouldn't have much trouble porting it to your favorite compiler.  I
Xhave found that on the VAX I had to comment-out the #asm stuff in
Xcrc32.c, in spite of the fact that it is already conditionally compiled
Xout.  I have stubbed-out my debugging stuff, so the printd()'s and
Xinitdebug() won't produce any code.
X
XIf you don't have string.h, then you probably don't have the string
Xlibrary either.  No sweat, all you need do is delete the include for
Xstring.h, and add the following routine to chksum.c:
X
X	local void strcpy(dst, src)
X	char *dst, *src;
X		{
X		while ((*dst++ = *src++) != '\0')
X			continue;
X		}
X
XYou'll need to remove the reference to the library in the makefile too.
XIf all else fails, the DOS executable is now available at fine
Xcomp.binaries.pc  newsgroups everywhere.
X
XI hereby donate this program to the Public Domain for any and all
Xpurposes. Enjoy.
X
XHere is the output of "chksum -v *.h *.c makefile":
X
X26b5c1c7         436   debug.h
X02180ae4        2837   gen.h
X872b0f18        8136   chksum.c
X6d239b68       11016   crc32.c
X44bdd9f4         536   makefile
X====================
X86c94990       22961   Grand Totals for 5 files
________This_Is_The_END________
if test `wc -c < readme` -ne 1991; then
	echo 'shar: readme was damaged during transit (should have been 1991 bytes)'
fi
fi		; : end of overwriting check
echo 'x - makefile'
if test -f makefile; then echo 'shar: not overwriting makefile'; else
sed 's/^X//' << '________This_Is_The_END________' > makefile
X#	/usr/bin/src	870407	NHA
X
X#this is for 4.3bsd
XCOPT=		-O
XCFLAGS=		-I. -c
XLNFLAGS=	-o chksum
XCC=			/bin/cc
XLN=			/bin/cc
X
X#this is for the Aztec version 4.10a under DOS
X#AOPT=		-186
X#COPT=		+a +2
X#AFLAGS=		-DMODEL=3 $(AOPT)
X#CFLAGS=		-I. -ansi -c +l +b $(COPT)
X#LNFLAGS=	-t -g
X#LIBS=		-lstringl  -lcl
X#CC=			/manx/cc.exe
X#LN=			ln
X#RM=			del
X
X.c.o:
X	${CC} ${CFLAGS} $<
X
X.c.asm:
X	${CC} -at ${CFLAGS} $<
X
X
Xchksum.exe:		chksum.o  crc32.o
X	$(LN)  $(LNFLAGS)  chksum.o  crc32.o  $(LIBS)
X
Xclean:
X	-rm *.o
X	-rm *.sym
X	-rm *.dbg
X	-rm chksum.exe
________This_Is_The_END________
if test `wc -c < makefile` -ne 536; then
	echo 'shar: makefile was damaged during transit (should have been 536 bytes)'
fi
fi		; : end of overwriting check
echo 'x - debug.h'
if test -f debug.h; then echo 'shar: not overwriting debug.h'; else
sed 's/^X//' << '________This_Is_The_END________' > debug.h
X/*   /usr/include/stub/debug.h    890123  NHA */
X/* This is the version for use with public sharing of my sources */
X/* The intent is to neutralize initdebug() and printd() so that */
X/* any compiler will swallow them without complaint */
X/* You may have to tweak this for yours */
X
X#ifndef	__DEBUG__
X#define	__DEBUG__
X
X/** #define printd	+ **/
X#define printd
X#define initdebug(acptr,avptr,confile,lstfile,initstring)
X
X#endif	__DEBUG__
________This_Is_The_END________
if test `wc -c < debug.h` -ne 436; then
	echo 'shar: debug.h was damaged during transit (should have been 436 bytes)'
fi
fi		; : end of overwriting check
echo 'x - gen.h'
if test -f gen.h; then echo 'shar: not overwriting gen.h'; else
sed 's/^X//' << '________This_Is_The_END________' > gen.h
X/*	/usr/include/stub/gen.h	890123	NHA	*/
X/* This is the version for use with public sharing of my sources */
X/* The intent is to neutralize initdebug() and printd() so that */
X/* any compiler will swallow them without complaint */
X
X#ifndef	__GEN__
X#define	__GEN__
X
X#include	<stdio.h>
X#include	<fcntl.h>
X#include	<ctype.h>
X/** #include    "config.h" **/
X#include    <debug.h>
X
X#define	import			extern
X#define	local			static
X#define	export
X/**	This will not work with prototypes in version 4.10a **/
X/** typedef	char			bool; **/
Xtypedef int				bool;
X#define	NULLFP			((int (*)())0)			/* NULL Function Pointer */
X
X#define	YES		1
X#define	NO		0
X#define	NOBREAK				/* used for a switch case which flows into next */
X#define	CRLF	037			/* Unit Separator sometimes replaces \n\r pair */
X
X/*** NOTE that this include must follow the definition of bool ***/
X/** #include	<window.h> **/					/* Norman's direct windows */
X/** import WINDOW	*wopen(char *dev); **/
X
X/* macros */
X#define	abs(x)		((x < 0) ? (-(x)) : (x))
X#define	max(x,y)	(((x) < (y)) ? (y) : (x))
X#define	min(x,y)	(((x) < (y)) ? (x) : (y))
X
X
X/* for use with Aztec farcall(), sysint(), and segreg() functions */
Xstruct regs		{ int	ax, bx, cx, dx, si, di, ds, es; };
Xstruct segregs	{ unsigned	cs, ss, ds, es; };
X
X/* use this to fiddle with longs and pointers and such */
Xunion u_long	{
X				unsigned long			lunsigned;
X				long					lsigned;
X				void					*ptr;
X				struct	{
X						unsigned		lo;
X						unsigned		hi;
X						}				half;
X				struct	{
X						unsigned char	b0;		/* Least Significant byte */
X						unsigned char	b1;
X						unsigned char	b2;
X						unsigned char	b3;		/* Most Significant byte */
X						}				byte;
X				};
X
X
X#define	BIT0	0x0001
X#define	BIT1	0x0002
X#define	BIT2	0x0004
X#define	BIT3	0x0008
X#define	BIT4	0x0010
X#define	BIT5	0x0020
X#define	BIT6	0x0040
X#define	BIT7	0x0080
X#define	BIT8	0x0100
X#define	BIT9	0x0200
X#define	BIT10	0x0400
X#define	BIT11	0x0800
X#define	BIT12	0x1000
X#define	BIT13	0x2000
X#define	BIT14	0x4000
X#define	BIT15	0x8000
X
X#define	BIT0L	0x00000001
X#define	BIT1L	0x00000002
X#define	BIT2L	0x00000004
X#define	BIT3L	0x00000008
X#define	BIT4L	0x00000010
X#define	BIT5L	0x00000020
X#define	BIT6L	0x00000040
X#define	BIT7L	0x00000080
X#define	BIT8L	0x00000100
X#define	BIT9L	0x00000200
X#define	BIT10L	0x00000400
X#define	BIT11L	0x00000800
X#define	BIT12L	0x00001000
X#define	BIT13L	0x00002000
X#define	BIT14L	0x00004000
X#define	BIT15L	0x00008000
X#define	BIT16L	0x00010000
X#define	BIT17L	0x00020000
X#define	BIT18L	0x00040000
X#define	BIT19L	0x00080000
X#define	BIT20L	0x00100000
X#define	BIT21L	0x00200000
X#define	BIT22L	0x00400000
X#define	BIT23L	0x00800000
X#define	BIT24L	0x01000000
X#define	BIT25L	0x02000000
X#define	BIT26L	0x04000000
X#define	BIT27L	0x08000000
X#define	BIT28L	0x10000000
X#define	BIT29L	0x20000000
X#define	BIT30L	0x40000000
X#define	BIT31L	0x80000000
X
X#endif	__GEN__
________This_Is_The_END________
if test `wc -c < gen.h` -ne 2837; then
	echo 'shar: gen.h was damaged during transit (should have been 2837 bytes)'
fi
fi		; : end of overwriting check
echo 'x - chksum.c'
if test -f chksum.c; then echo 'shar: not overwriting chksum.c'; else
sed 's/^X//' << '________This_Is_The_END________' > chksum.c
X/*  /usr/bin/src/chksum.c 880118  NHA */
X
X#define	DEBUG	0
X#define	MAJOR	'P'
X#define	MINOR	'C'
X
X#include    <gen.h>
X#include	<string.h>
X
X#define	SUCCESS	0
X#define	FAILURE	(!SUCCESS)
X
X
X#ifdef __STDC__
Ximport char				*gets(void *buffer);
Ximport int				open(char *filename, int mode);
Ximport int				read(int fd, void *buf, int count);
Ximport int				close(int fd);
Ximport char				*getenv(char *name);
Ximport void				exit(int status);
Ximport unsigned long	crc32buf(unsigned long initialSum,
X										unsigned char *buf, unsigned count);
X#else
Ximport char				*gets();
Ximport int				open();
Ximport int				read();
Ximport int				close();
Ximport char				*getenv();
Ximport void				exit();
Ximport unsigned long	crc32buf();
X#endif __STDC__
X
Xlocal unsigned char	buffer[BUFSIZ];			/* reads go into this buffer */
Xlocal bool			showCount;				/* show the byte count [-c] */
Xlocal bool			showError;				/* show Errors in any case */
Xlocal bool			totalOnly;				/* don't show file sums [-t] */
Xlocal bool			verbose;				/* print filenames [-v] */
Xlocal bool			firstFile;				/* only true for 1st file */
Xlocal unsigned		fileCount;				/* # of files processed OK */
Xlocal unsigned		errorCount;				/* # of files with errors */
Xlocal unsigned long	sum;					/* checksum for a file */
Xlocal unsigned long	grandSum;				/* checksum over all files */
Xlocal unsigned long	byteCount;				/* byte count for a file */
Xlocal unsigned long	grandByteCount;			/* byte count over all files */
X
X
X
X
X/*+     c h k s u m
X * Calculate two chksums for the file.
X * One is simply the chksum of the bytes in the file.
X * The other is updating the grandSum with the bytes in the file.
X * The grandSum is only updated for files after the first file.
X * The byteCount and grandByteCount variables are also updated.
X * Return FAILURE for file errors, else SUCCESS.
X */
Xlocal bool chksum(fd)
Xint fd;										/* File Descriptor */
X    {
X    int    		status;						/* status returned from sys calls */
X
X	printd(4, "chksum(%d)\n", fd);
X
X	sum       = 0L;
X    while (1)
X        {
X		/* read next bufferload from the file */
X        status = read( fd, buffer, sizeof buffer );
X		printd(9, "read status=%d\n", status);
X        if (status < 0)
X			{
X			printd(4, "chksum(): returning FAILURE\n");
X            return FAILURE;
X			}
X        if (status == 0)
X            break;							/* End Of File */
X
X		/* update checksums */
X		sum = crc32buf(sum, buffer, (unsigned)status);
X		if ( ! firstFile )
X			grandSum = crc32buf(grandSum, buffer, (unsigned)status);
X
X		/* update byte counts */
X		byteCount += (unsigned long)status;
X		grandByteCount += (unsigned long)status;
X
X		printd(8, "sum=%08lx, grandSum=%08lx, byteCount=%ld, grandByteCount=%ld\n",
X		  sum, grandSum, byteCount, grandByteCount);
X		}
X
X	printd(4, "chksum(): returning SUCCESS with sum=%08lx,  grandSum=%08lx\n",
X	  sum, grandSum);
X	return SUCCESS;
X    }
X
X
X
X/*+		s u m F i l e
X * Given a filename, calculate the checksum, do any necessary displaying,
X * and update all the necessary global variables.
X * If the filename is a NULL pointer or a pointer to '\0', we use stdin.
X * In the event of file access errors, a sum of 0 is printed.
X */
Xlocal void sumFile(filename)
Xchar	*filename;
X	{
X	int fd;									/* File Descriptor */
X	char name[88];
X	bool isBad;								/* YES for file errors */
X
X	printd(4, "sumFile(%s)\n", filename);
X	byteCount = 0L;
X	
X	/* open input file.  NULL or ptr to '\0' is taken to mean standard input */
X	if (filename == NULL   ||   filename[0] == '\0')
X		{
X		strcpy(name, "--Stdin--");
X		fd = fileno(stdin);
X		}
X	else
X		{
X		strcpy(name, filename);
X	    fd = open(filename, O_RDONLY);
X	    if (fd < 0)
X	        {
X			isBad = YES;
X			++errorCount;
X			sum = 0L;
X	   		printd(2, "sumFile(%s): can't open file for read\n", filename);
X			if (showError)
X				fprintf(stderr, "chksum: can't open \"%s\" for reading\n",
X								filename);
X	        }
X		else
X			isBad = NO;
X		}
X
X	/* calculate the checksum */
X	if (0 <= fd)
X		{
X		if (chksum(fd) == SUCCESS)
X			{
X			isBad = NO;
X			++fileCount;
X			if (firstFile)
X				{
X				grandSum = sum;
X				firstFile = NO;
X				}
X			}
X		else
X			{
X			isBad = YES;
X			++errorCount;
X			sum = 0L;
X        	printd(2, "sumFile(%s): error reading file\n", name);
X			if (showError)
X				fprintf(stderr, "chksum: error reading file \"%s\"\n",
X								filename);
X			}
X		if (fd != fileno(stdin))
X			close(fd);
X		}
X
X	/* report the results */
X	if ( ! totalOnly)
X		{
X		printf("%08lx", sum);
X		if (showCount)
X			printf("  %10lu", byteCount);
X		if (verbose)
X			if (isBad)
X				printf("   %s     *** ERROR ***", name);
X			else
X				printf("   %s", name);
X		putchar('\n');
X		}
X	printd(4, "sumFile(): returning\n");
X	}
X
X
X
X/*+		u s a g e
X * Spew out the help message.
X */
Xlocal void usage()
X	{
X	fprintf(stderr, "chksum -- calculate 32-bit checksum for file(s), output to stdout\n");
X	fprintf(stderr, "Usage:	chksum   [-cehtv]    {file|--|-}...\n");
X	fprintf(stderr, "-c	Count bytes also\n");
X	fprintf(stderr, "-e	give extended Error reports on stderr\n");
X	fprintf(stderr, "-h	Help; give this help message and exit\n");
X	fprintf(stderr, "-t	Total only; don't list sum for each file\n");
X	fprintf(stderr, "-v	Verbose; list filenames along with checksums\n");
X	fprintf(stderr, "--	take filenames from stdin, 1 name per line\n");
X	fprintf(stderr, "-	take stdin as a file\n");
X	fprintf(stderr, "Filenames may be mixed with options.\n");
X	fprintf(stderr, "Exit status is the number of file errors encountered.\n");
X	exit(1);
X	}										/* usage */
X
X
X
X/*+     m a i n
X * See usage() for command line parameters.
X */
Xexport int main(ac, av)
Xint ac;
Xchar **av;
X    {
X	char	*p;
X	char	line[BUFSIZ];					/* for reading from stdin */
X	char	switchar;
X
X	/* initialize */
X	initdebug(&ac, &av, "/dev/con", "/dev/fifo", "**0");
X	showCount      = NO;					/* default is no byte counts */
X	showError      = NO;					/* default is no reports on stderr*/
X	totalOnly      = NO;					/* default is show all checksums */
X	verbose        = NO;					/* default is no filenames */
X	firstFile      = YES;					/* no files checksummed yet */
X	fileCount      = 0;
X	errorCount     = 0;
X	grandSum       = 0L;
X	grandByteCount = 0L;
X	p = getenv("SWITCHAR");
X	if (p == NULL)
X		switchar = '-';
X	else
X		switchar = *p;
X
X	/* process command line arguments */
X    for (--ac, ++av   ;   0 < ac   ;   --ac, ++av)
X		{
X		printd(7, "main():  ac = %d,  *av = '%s'\n", ac, *av); 
X		if (av[0][0] == switchar)
X			switch (av[0][1])
X				{
X			case 'C':
X			case 'c':
X				showCount = YES;
X				break;
X			case 'E':
X			case 'e':
X				showError = YES;
X				break;
X			case 'H':
X			case 'h':
X				usage();
X				break;
X			case 'T':
X			case 't':
X				totalOnly = YES;
X				break;
X			case 'V':
X			case 'v':
X				verbose = YES;
X				break;
X			case '-':						/* take filenames from stdin */
X				while (gets(line) != NULL)
X					sumFile(line);
X				if (showError  &&  ferror(stdin))
X					fprintf(stderr, "chksum: error reading standard input\n");
X				clearerr(stdin);
X				break;
X			case '\0':
X				sumFile(NULL);				/* use standard input for file */
X				break;
X			default:
X				fprintf(stderr, "chksum: unknown option  %s\n", av[0]);
X				}							/* switch */
X		else
X			sumFile(av[0]);					/* file */
X		}
X
X
X	/* put out the Grand Total */
X	if ((fileCount + errorCount)  ==  0)
X		usage();							/* no files specified */
X	else if ((fileCount + errorCount)  ==  1)
X		{									/* one file specified */
X		if (totalOnly)
X			{
X			printf("%08lx", grandSum);
X			if (showCount)
X				printf("  %10lu", grandByteCount);
X			putchar('\n');
X			}
X		}
X	else
X		{									/* multiple files specified */
X		if ( ! totalOnly)
X			{
X			printf("========");
X			if (showCount)
X				printf("============");
X			putchar('\n');
X			}
X		printf("%08lx", grandSum);
X		if (showCount)
X			printf("  %10lu", grandByteCount);
X		if (verbose)
X			{
X			if (showCount)
X				printf("   Grand Totals for %u files", fileCount);
X			else
X				printf("   Grand Total for %u files", fileCount);
X			if (errorCount == 1)
X				printf("   ***** plus 1 ERROR *****");
X			else if (1 < errorCount)
X				printf("   ***** plus %u ERRORS *****", errorCount);
X			}
X		putchar('\n');
X		}
X	printd(3, "chksum: returning %u", errorCount);
X	exit(errorCount);
X    }										/* main */
________This_Is_The_END________
if test `wc -c < chksum.c` -ne 8136; then
	echo 'shar: chksum.c was damaged during transit (should have been 8136 bytes)'
fi
fi		; : end of overwriting check
echo 'x - crc32.c'
if test -f crc32.c; then echo 'shar: not overwriting crc32.c'; else
sed 's/^X//' << '________This_Is_The_END________' > crc32.c
X/* /usr/lib/src/pd/crc32.c	881102	NHA	*/
X/*
X *  Crc - 32 BIT ANSI X3.66 CRC checksum files
X */
X
X#define	TEST	0
X#define	DEBUG	0
X#define	FAST	0
X
X#define	MAJOR	'L'
X#define	MINOR	'C'
X
X#include <gen.h>
X
X#define OK		0
X#define ERROR	(-1)
X#define LINT_ARGS
X
X/**********************************************************************\
X|*                                                                    *|
X|* Demonstration program to compute the 32-bit CRC used as the frame  *|
X|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71     *|
X|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level     *|
X|* protocol).  The 32-bit FCS was added via the Federal Register,     *|
X|* 1 June 1982, p.23798.  I presume but don't know for certain that   *|
X|* this polynomial is or will be included in CCITT V.41, which        *|
X|* defines the 16-bit CRC (often called CRC-CCITT) polynomial.  FIPS  *|
X|* PUB 78 says that the 32-bit FCS reduces otherwise undetected       *|
X|* errors by a factor of 10^-5 over 16-bit FCS.                       *|
X|*                                                                    *|
X\**********************************************************************/
X
X/* Need an unsigned type capable of holding 32 bits; */
Xtypedef unsigned long int UNS_32_BITS;
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/* 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/*  1. 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/*  2. The CRC accumulation logic is the same for all CRC polynomials, */
X/*     be they sixteen or thirty-two bits wide.  You simply choose the */
X/*     appropriate table.  Alternatively, because the table can be     */
X/*     generated at runtime, you can start by generating the table for */
X/*     the polynomial in question and use exactly the same "updcrc",   */
X/*     if your application needn't simultaneously handle two CRC       */
X/*     polynomials.  (Note, however, that XMODEM is strange.)          */
X/*                                                                     */
X/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */
X/*     of course, 32-bit entries work OK if the high 16 bits are zero. */
X/*                                                                     */
X/*  4. 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
Xstatic UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
X0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
X0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
X0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
X0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
X0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
X0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
X0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
X0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
X0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
X0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
X0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
X0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
X0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
X0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
X0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
X0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
X0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
X0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
X0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
X0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
X0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
X0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
X0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
X0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
X0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
X0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
X0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
X0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
X0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
X0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
X0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
X0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
X0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
X0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
X0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
X0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
X0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
X0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
X0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
X0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
X0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
X0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
X0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
X0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
X0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
X0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
X0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
X0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
X0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
X0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
X0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
X0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
X0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
X0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
X0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
X0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
X0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
X0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
X0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
X0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
X0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
X0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
X0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
X0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
X};
X
X
X
X/*+	c r c 3 2 b u f
X * Given an initial 32-bit CRC and a buffer, calculate the new CRC.
X * Returns the new CRC.
X */
Xexport UNS_32_BITS crc32buf( crc, cp, cnt )
XUNS_32_BITS	crc;				/* initial CRC */
Xunsigned char	*cp;				/* pointer to buffer */
Xunsigned	cnt;				/* # chars in buffer */
X	{
X	printd(3, "crc32buf(%lu, %p, %u)\n", crc, cp, cnt);
X
X#if	FAST
X#asm
X;es:si	holds pointer to buffer (cp)
X;cx		holds count (cnt)
X;dx,ax	holds crc hi,lo
X	mov	cx, word ptr 14[bp]		;cnt
X	jcxz	done
X	mov	ax, word ptr 6[bp]		;crc lo
X	mov	dx, word ptr 8[bp]		;crc hi
X	les	bx, dword ptr 10[bp]		;cp
X	mov	si, bx
Xagain:
X	mov	bl, es:byte ptr [si]		;octet
X	xor	bl, al				;crc ^ octet & 0377
X	xor	bh, bh
X	shl	bx, 1
X	shl	bx, 1				;bx is index into crc_32_tab
X	mov	al, ah				;crc >>= 8
X	mov	ah, dl
X	mov	dl, dh
X	xor	dh, dh
X	xor	ax, word ptr crc_32_tab_[bx]	;low word
X	xor	dx, word ptr crc_32_tab_[bx+2]	;high word
X	inc	si
X	loop	again
X	mov	word ptr 6[bp], ax		;crc lo
X	mov	word ptr 8[bp], dx		;crc hi
Xdone:
X#endasm
X#else FAST
X#define	W	16
X#define	B	8
X	while( cnt-- ) {
X#  if SWAPPED
X		crc = (crc<<B) ^ crc_32_tab[(crc>>(W-B)) ^ *cp++];
X#  else SWAPPED
X		crc = (crc>>B) ^ crc_32_tab[(crc & ((1<<B)-1)) ^ *cp++]; 
X#  endif SWAPPED
X		printd(8, "crc32buf(): cnt=%u, crc=%08lx\n", cnt, crc);
X    	}
X#endif FAST
X
X    printd(3, "crc32buf(): returning %lu\n", crc);
X    return( crc );
X}					/* crc32buf() */
X
X
X
X/*+		c r c 3 2 1
X * Given a 32-bit CRC and a byte, return the new CRC which includes the byte.
X */
Xexport UNS_32_BITS crc321( crc, octet )
XUNS_32_BITS	crc;
Xunsigned char	octet;
X	{
X    UNS_32_BITS		newcrc;
X	printd(3, "crc321(%lu, %#02x)\n", crc, octet);
X#if FAST
X#asm
X	mov	bl, byte ptr 10[bp]		;octet
X	xor	bl, byte ptr 6[bp]		;(crc ^ octet) & 0377
X	xor	bh, bh
X	shl	bx, 1
X	shl	bx, 1				;bx is index into crc_32_tab
X	mov	ax, word ptr crc_32_tab_[bx]	;low word
X	mov	dx, word ptr crc_32_tab_[bx+2]	;high word
X	xor	ax, word ptr 7[bp]		;xor with (crc >> 8), low word
X	xor	dl, byte ptr 9[bp]		;xor with (crc >> 8), high byte
X	mov	word ptr -4[bp], ax		;store in newcrc
X	mov	word ptr -2[bp], dx		; for printf() and return value
X#endasm
X#else FAST
X	newcrc =  (crc_32_tab[((crc) ^ (octet)) & 0377]   ^   ((crc) >> 8));
X#endif FAST
X	printd(3, "crc321(): returning %lu\n", newcrc);
X	return newcrc;
X}						/* crc321() */
X
X
X#if TEST
X
X#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
X
X
Xlocal crc32file(name)
Xchar *name;
X{
X	register FILE *fin;
X	register unsigned long oldcrc32;
X	register unsigned long crc32;
X	register unsigned long oldcrc;
X	register c;
X	register long charcnt;
X
X	oldcrc32 = 0xFFFFFFFF; charcnt = 0;
X#ifdef M_I86SM
X	if ((fin=fopen(name, "rb"))==NULL)
X#else
X	if ((fin=fopen(name, "r"))==NULL)
X#endif
X	{
X		perror(name);
X		return ERROR;
X	}
X	while ((c=getc(fin))!=EOF) {
X		++charcnt;
X/**		oldcrc32 = UPDC32(c, oldcrc32); **/
X		oldcrc32 = crc321(oldcrc32, c);
X	}
X
X	if (ferror(fin)) {
X		perror(name);
X		charcnt = -1;
X	}
X	fclose(fin);
X
X	crc32 = oldcrc32;  oldcrc = oldcrc32 = ~oldcrc32;
X
X/*
X	crc32 = UPDC32((oldcrc32 & 0377), crc32);  oldcrc32 >>=8;
X	crc32 = UPDC32((oldcrc32 & 0377), crc32);  oldcrc32 >>=8;
X	crc32 = UPDC32((oldcrc32 & 0377), crc32);  oldcrc32 >>=8;
X	crc32 = UPDC32((oldcrc32 & 0377), crc32);  oldcrc32 >>=8;
X	printf("%08lX ", crc32);
X*/
X
X	printf("%08lX %7ld %s\n", oldcrc, charcnt, name);
X
X	return OK;
X}
X
X
Xexport main(argc, argp)
Xchar **argp;
X{
X	register errors = 0;
X
X	while( --argc > 0)
X		errors |= crc32file( *++argp);
X	exit(errors != 0);
X}
X#endif TEST
________This_Is_The_END________
if test `wc -c < crc32.c` -ne 11016; then
	echo 'shar: crc32.c was damaged during transit (should have been 11016 bytes)'
fi
fi		; : end of overwriting check
exit 0