langdon@lll-lcc.UUcp (Bruce Langdon) (02/02/86)
---------------------------------------------------------------------------
Utility CHECK provides a way to find the length of a file (in bytes,
and in lines for text files), and sorting out different versions of files
(by comparing their CRC's).
There are two files, CHECK.ACT and CRC.ACT. CRC shows a progression from
a straight Action version, updCRCa, to a machine language version updCRCx
of updCRCa, to a straight Action version that uses a table but is fastest.
If you compile and write and executable file to be run without recompiling,
consider removing the ; from SET $491... so it will not run on top of
something else. If you have the run-time libraries SYSLIB and SYSIO, remove
the ; from those INCLUDEs to make an executable file that doesn't need the
Action cartridge to run.
At least with DOS XL, CHECK can be re-run without re-reading it off disk
by just typing 'RUN'. This is the purpose of 'Entry'.
Other features useful in other programs include:
fast disk read
error handling
fixing up the DOS file name (force upper case, prefix D: if needed)
locating the buffer
run-time library does not set device=0; do it yourself in case.
----------------------------------------------------------------------
Bruce Langdon L-472 langdon%lll-lcc@lll-crg.ARPA
Physics Department "langdon#bruce%d"@lll-mfe.ARPA
Lawrence Livermore National Laboratory
Livermore, CA 94550 (415) 422-5444
UUCP: ..{gymble,ihnp4,seismo}!lll-crg!lll-lcc!langdon
---------------------------------------------------------------------------
; CHECK 8/17/85-12/21, A. B. Langdon
; Determine length, CRC and checksum of file.
; Also number of lines, for text file.
;SET $491=$4000 SET 14=$491^
BYTE JMP=[$4C]: CARD Entry
;INCLUDE "D:SYSLIB.ACT"
;INCLUDE "D:SYSIO.ACT"
; Using channel 1, Close caused "system error" with DOS 2.1 but not DOS XL.
; ACS bbs has a block read (BLKIO.ACT) in machine code segments that is
; smaller and has a general purpose call to CIO. Here, I'll leave mine
; as it illustrates use of the language and is just as fast.
; First global ARRAY, other than BYTE ARRAY of length less than 257,
; is placed AFTER rest of program (undocumented?).
BYTE ARRAY buffer(257) ; locate the buffer.
CARD FLen, ; File length up to 64K
i, CSum, NLines
BYTE OpOK, CSum0=CSum, CSum1=CSum+1, text
BYTE CIO_status ; global for CIO return value (per ACS convention)
INCLUDE "CRC.ACT"
CARD FUNC GetAD(BYTE chan CARD addr, len) ; Block read
TYPE IOCB=[BYTE hid,dno,com,sta
CARD badr,put,blen
BYTE aux1,aux2,aux3,aux4,aux5,aux6]
IOCB POINTER ic
BYTE chan16
BYTE POINTER b
chan16 = (chan&$07) LSH 4
ic = $340+chan16
ic.com = 7 ; read
ic.blen = len
ic.badr = addr
[$AE chan16 $20 $E456 $8C CIO_status] ; LDX chan, JSR CIO; STY CIO_status
FLen ==+ ic.blen ; this to RETURN is special to this application.
IF CIO_status = $88 THEN
EOF(chan)=1
IF (FLen&$FF) = 0 THEN ; likely last sector of
b = addr+ic.blen-1 ; a DOS 4 file.
WHILE b^ = 0 DO
b ==- 1
ic.blen ==- 1
FLen == -1
OD
FI
FI
b = addr
FOR i = 1 TO ic.blen DO
IF b^ = $9B THEN NLines ==+ 1 FI
CSum0 ==+ b^
CSum1 ==+ CSum0
updCRC(b^)
b ==+ 1
OD
RETURN (ic.blen)
CARD FUNC GetCD(BYTE chan) ; Read a word
CARD c
GetAD(chan,@c,2)
RETURN (c)
PROC FixFlSp(BYTE ARRAY FileSpec)
IF FileSpec(2)<>': AND FileSpec(3)<>': THEN ; prefix "D:" to file name
FileSpec^==+2
i=FileSpec^
WHILE i>2 DO
FileSpec(i)=FileSpec(i-2)
i==-1
OD
FileSpec(1)='D FileSpec(2)=':
FI
; Could also convert to upper case: if >$60 then subtract $20.
RETURN
PROC SysErr(BYTE errno)
PROC MyError(BYTE errno)
IF errno=$80 THEN Error=SysErr Error(errno) FI ; break quits
PrintF("error %I. Try again%E",errno)
OpOK=0
RETURN
PROC End=*() [$68$AA$68$CD$2E8$90$5$CD$2E6$90$F3 $48$8A$48$60]
; entry: PLA; TAX; PLA; CMP MEMLO+1; BCC lab; CMP MEMTOP+1; BCC entry;
; lab: PHA; TXA; PHA; RTS
; Trace back thru RTS's and return to cartridge or DOS.
; From ACS bulletin board.
PROC CHECK()
CHAR ARRAY FileSpec(20)
BYTE b, SHFLOK=$2BE
CARD fwa, lwa, BufLen, MEMTOP=$2E5, MEMLO=$2E7
BufLen=MEMTOP-$80-buffer
SysErr=Error
DO
Print("File Spec=")
SHFLOK=$40 ; upper case
InputS(FileSpec)
IF FileSpec^=0 THEN END() FI
FixFlSp(FileSpec)
Close(2)
OpOK=1 Error=MyError Open(2,FileSpec,4,0)
UNTIL OpOK OD
Error=SysErr
FLen=0 CSum=0 CRC=0 text=1 NLines=0
; With DOS 4, this artifice ensures
; that each GetAD reads one byte into
; next sector, to anticipate EOF.
BufLen ==& $FF00
GetAD(2,buffer,1)
IF buffer(0) = $FF THEN text=0 FI
WHILE EOF(2) = 0 DO
GetAD(2,buffer,BufLen)
OD
updCRC(0) updCRC(0)
PrintF("End of file. %H bytes%E",FLen)
PrintF(" checksum=%H, CRC=%H%E",CSum,CRC)
IF text THEN
PrintF("%I lines%E",NLines)
FI
Close(2)
RETURN
PROC Main()
device=0 ; in case MAC/65 has been here
SetupCRC()
DO
CHECK()
PrintE(" (RETURN to end)")
OD
RETURN
SET Entry=Main
---------------------------------------------------------------------------
MODULE; CRC.ACT 12/21/85 A. B. Langdon
; Before use, do SetupCRC().
; For each data set, first set global CRC=0.
; After calling updCRC(data) with all
; data bytes, do updCRC(0) twice.
; If CRCx is the CRC of a byte string,
; then the CRC of that string, followed by
; the hi and lo bytes of CRCx, is zero.
CARD CRC: BYTE CRCl=CRC, CRCh=CRC+1
CARD ARRAY CRCtable(256)
;PROC updCRCa(BYTE b) ; Action version
; From C code by D. Krantz,
; Dr. Dobb's Journal, June 1985.
; Takes 99 jiffies for 2000 bytes.
; BYTE i
; CARD flag
; FOR i=0 TO 7 DO
; flag = CRC&$8000
; CRC ==LSH 1
; IF b&$80 THEN CRC ==% 1 FI
; IF flag THEN CRC ==XOR $1021 FI
; b ==LSH 1
; OD
;RETURN
PROC updCRC(BYTE b)
; Adaptation to this CRC of the algorithm
; by W.D.Schwaderer, PC Tech Journal, 4/85.
; Takes 14 jiffies for 2000 bytes.
CARD tem
BYTE teml=tem, temh=tem+1
teml = b
temh = CRCl
CRC = tem XOR CRCtable(CRCh)
RETURN
PROC updCRCx=*(BYTE b)
; Machine language for Dr. Dobb's routine.
; Takes 35 jiffies for 2000 bytes.
[$85$A0] ; STA $A0
[$A2$8] ; loop over 8 bits
[$26$A0] ; 3 byte shift of data
[$2E CRC $2E CRC+1] ; and CRC
[$90$10 $AD CRC $49$21 $8D CRC] ; if carry, then XOR
[$AD CRC+1 $49$10 $8D CRC+1] ; poly bits
[$CA $D0$E3] ; loop
RETURN
PROC SetupCRC()
FOR i=0 TO $FF DO ; set up CRC table
CRCl=0 CRCh=i
updCRCx(0)
CRCtable(i)=CRC
OD ; <0.1 sec.
RETURN
MODULE; end CRC
---------------------------------------------------------------------------