W8SDZ%MIT-MC@sri-unix.UUCP (02/05/84)
From: Keith Petersen <W8SDZ @ MIT-MC> /* * crck.c -- Unix version of the CP/M utility * * Usage: * crck [-t|c|u|i] [filename ... ] * * Calculates a 16-bit cyclic redundancy check on its input files and * prints the resulting number in hexadecimal. CRCK is manually invoked * on two versions of the same file to ensure that they are the same. * Prints the the filename, size in bytes or sectors depending on the * option flag, and the CRC. * * Options: * -t Perform CRCK on a CP/M text file that is stored as a Unix * file. CP/M record delimters are substituted for Unix * newlines and the file is padded to a 128-byte sector * boundary with ^Z's. * * -u Perform CRCK on a regular Unix file. Takes whatever is there. * * -c Perform CRCK on a CP/M ".COM" file. Handled the same as * the -u flag except sectors are reported rather than bytes. * * -i Perform CRCK on a CP/M ".COM" file stored in ITS binary * format. Ignores the first four bytes of the file. Implies * the -c option. * * If no option flag is chosen, the default option is -u. * * Wildcards may, of course, be used and the program may be used in * pipelines. * * *---------------------------------------------------------------------------- * Version 2.0 mods by Ben Goldfarb (decvax!ucf-cs!goldfarb or * Goldfarb.ucf-cs @ Rand-Relay) * * Added CP/M text and binary file modes and changed to * use standard stream I/O. */ #include <stdio.h> #define VERSION 20 /* Version 2.0 */ #define SECSIZ 128 /* CP/M sector size for fill */ #define CTLZ 'Z' - 0x40 /* Fill character for text files */ int cflag = 0; /* CP/M binary file */ int tflag = 0; /* CP/M text file */ int uflag = 0; /* Unix file */ int iflag = 0; /* ITS Binary file */ unsigned short crck(); /* CRC calculation function */ main(argc, argv) int argc; char **argv; { int err = 0; if ((++argv)[0][0] == '-') { switch (argv[0][1]) { case 't': ++tflag; break; case 'c': ++cflag; break; case 'u': ++uflag; break; case 'i': ++iflag; ++cflag; break; default: goto usage; } --argc; ++argv; } else /* for right now, "Unix mode" is the default */ ++uflag; if (isatty(2)) { /* print header if not in a pipe */ printf("CRCK program for Unix\n"); printf("Version %1d.%1d\n\n", VERSION/10, VERSION%10); if (iflag) printf("ITS mode selected\n"); if (tflag) printf("CP/M text mode selected\n"); if (cflag) printf("CP/M \".COM\" mode selected\n"); if (uflag) printf("Unix file mode selected\n"); putchar('\n'); } if (argc == 1 ) { /* we're just taking stdin from somewhere */ docrck("stdin"); exit(0); } else { /* we're doing a named file or a list of same */ for (; --argc; ++argv) { err = 0; if (freopen(*argv, "r", stdin) == NULL) { perror(*argv); ++err; } if (!err) docrck(*argv); } exit(0); } usage: fprintf(stderr, "Usage: crck [-t|c|u|i] [filename ... ]\n"); exit(-100); } docrck(name) /* Calculate and print a "CRCK" for stdin stream. */ char *name; { int icount; long nsec; unsigned short oldcrck; unsigned char crbuf[SECSIZ]; unsigned char *bufend = crbuf + SECSIZ; register c; register unsigned char *cp; oldcrck = 0; nsec = 0L; cp = crbuf; if (tflag) { /* * To calculate CRC for CP/M text files that are * presently stored in the form of Unix text files, * an ASCII CR must be inserted in the buffer before * each '\n'. Then the file must be padded out to * an even SECSIZ boundary with CTLZ's. */ while ((c = getchar()) != EOF) { if (((*cp++ = c) == '\n') && tflag) { /* need to add \r */ *(cp - 1) = '\r'; if (cp >= bufend) { /* sector boundary */ oldcrck = crck(crbuf, SECSIZ, oldcrck); ++nsec; cp = crbuf; } *cp++ = '\n'; } if (cp >= bufend) { /* sector boundary */ oldcrck = crck(crbuf, SECSIZ, oldcrck); ++nsec; cp = crbuf; } } if (cp != crbuf) { /* EOF during partial sector */ register fillcnt; /* Fill from current pointer pos to end of buffer */ if (tflag) for (fillcnt = bufend - cp; fillcnt--; *cp++ = CTLZ) ; /* Need to update CRC for final sector. */ oldcrck = crck(crbuf, cp-crbuf, oldcrck); ++nsec; } } else { /* uflag or cflag -- do a quick crck */ unsigned char tbuf[BUFSIZ]; int count = 0; if (iflag) /* skip first four bytes of ITS binary file */ for (icount = 0; (c = getchar()) != EOF && icount < 4; icount++) ; while ((count = fread(tbuf, 1, BUFSIZ, stdin)) > 0) { oldcrck = crck(tbuf, count, oldcrck); if (!cflag) nsec += count; /* here nsec is for BYTES */ else nsec += ((count + SECSIZ - 1) / SECSIZ); } } printf("%-18s", name); printf(" (%7ld %-7s) ==> %04x\n", nsec, uflag ? "bytes" : "sectors", oldcrck); } unsigned short crck(crbuf, count, ldcrc) /* uses algorithm of CRCK.COM prior to V5.0 */ register unsigned char *crbuf; register count; register unsigned short ldcrc; { /* * This routine copyright (c) 1983, Computer Development, Inc., * Beaverton, OR, USA. * All rights reserved. */ register unsigned short n; while (--count >= 0) { n = (ldcrc << 1); n = (n & 0xff00) | (( n + *crbuf++ ) & 0x00ff); if(ldcrc & 0x8000) n ^= 0xa097; ldcrc = n; } return(ldcrc); }