home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
beehive
/
compress
/
ql40.arc
/
QL.001
< prev
next >
Wrap
Text File
|
1991-08-11
|
54KB
|
2,463 lines
;.......................
;
; QL v4.0 14 August 1988
;
QLVERS EQU 40 ; <=== version #, keep up to date!
;==============================================================================
;
; Ascii equates
;
NULL EQU 0
CTRLC EQU 'C'-40H
CTRLK EQU 'K'-40H
CTRLX EQU 'X'-40H
BELL EQU 7
BS EQU 8
TAB EQU 9
LF EQU 10
FF EQU 12
CR EQU 13
EOF EQU 1AH
ESC EQU 1BH
;==============================================================================
;
; BDOS function equates
;
CONOUT EQU 2 ; Console Output
DIRIO EQU 6 ; Direct Console I/O
RDBUFF EQU 10 ; Console Read String
OPEN EQU 15 ; File Open
CLOSE EQU 16 ; File Close
SRCH1ST EQU 17 ; Search 1st
SRCHNXT EQU 18 ; Search Next
ERASE EQU 19 ; File Erase
READSEQ EQU 20 ; File Read [Sequential]
WRITSEQ EQU 21 ; File Write [Sequential]
CREAT EQU 22 ; File Create
GETDSK EQU 25 ; Get Current Disk
SETDMA EQU 26 ; Set Direct Memory Address
SGUSER EQU 32 ; Set/Get User
RANDOM EQU 33 ; File Read [Random]
;==============================================================================
;
; Page zero equates
;
BDOSEV EQU 0005 ; BDOS Entry Vector
FCB1 EQU 005CH ; File Control Block 1
FCB1FN EQU FCB1+01 ; FCB1 Filename
FCB1EXT EQU FCB1+09 ; FCB1 Extension
FCB1R0 EQU FCB1+21H ; Rec number for sizing & lbr random access
FCB1R2 EQU FCB1+23H ; 0'd before random read
;==============================================================================
;
; Derived Equates
;
IF M80 ; Non-syntax specific implementation of
Z1 EQU FALSE ; - mutual exclusion
ELSE
Z1 EQU TRUE
ENDIF
IF Z1
NLIST S ; No source listing
LIST C ; Gen com file directly
ENDIF
IF Z1
CTRLDUMMY EQU .NOT.(CTRLWORDSTAR.OR.CTRLDIMVID)
ELSE
CTRLDUMMY EQU NOT (CTRLWORDSTAR OR CTRLDIMVID)
ENDIF
;==============================================================================
;
; "assumed equates"
;
; Adjustable screen height and width is only partially implemented in the
; current version, so for now these should remain at 24 and 80 respectively.
;
LINES EQU 24 ; Terminal console lines.
COLUMNS EQU 80 ; Terminal console columns.
;==============================================================================
;
IF ZCPR3
CSEG
ELSE
ASEG
ORG 100H
ENDIF
;.....
;
IF ZCPR3
PUBLIC $MEMRY
EXTRN Z3VINIT,TINIT,DINIT
EXTRN CLS,STNDOUT,STNDEND
EXTRN Z3LOG,GETWHL,GETSPEED,GETCRT,GETVID
EXTRN COUT,GETUD,PUTUD
EXTRN RETUD,LOGUD
ENDIF
; set the number of lines we can display (don't change)
DISPLY EQU LINES-LINEOVERLAP-1 ; Display page size = 23
NL EQU LINES-6
;=====================================================================
; Entry Point
;=====================================================================
QL: JP MAIN ; <=== entry
IF ZCPR3
DB 'Z3ENV',1
Z3EADR: DW 0
ENDIF
;..............................................................................
;
; embedded copyright message simplified & moved near beginning (for dump)
; since it is no longer displayed at runtime
DB 'by Nick Dobrinich and Ross Presser '
DB 'Sections Copyright (c) 1986 '
DB 'Steven Greenberg and C.B. Falconer '
DB 'May be reproduced for non-profit use only.'
SIGNON: CALL MSG
DB 'QL v',QLVERS/10+'0','.'
DB (QLVERS-((QLVERS/10)*10))+'0'
IF ZCPR3 ;
DB ' /Z3' ;
ENDIF ;
DB ' 14 August 1988'
DB CR,LF,LF
DB ' --- While viewing --- --- Toggle Commands ---',CR,LF
DB CR,LF
DB '<cr> Forward one page A Display ASCII / HEX: '
ASTATE: DB 'ASCII',CR,LF
DB '<sp> Forward one line T Truncate long lines: '
TSTATE: DB 'YES',CR,LF
DB '<##> Go to any page ## C Case sensitive find: '
CSTATE: DB ' NO',CR,LF
DB ' B Backward one page',CR,LF
DB ' H Home (Top of file)',CR,LF
DB ' E End (Bot of file)',CR,LF,LF
;;
DB ' F Find text or hex byte',CR,LF
DB ' R Repeat find',CR,LF
DB ' X Exit viewing',CR,LF,LF,0
RET
REQCMD: CALL MSG
DB CR,LF,LF,'Command, or <ret> to resume Viewing: ',0
RET
;=====================================================================
; Main Program
;=====================================================================
MAIN:
LD (OLDSP),SP ; Save old sp if no warm boot needed
LD SP,STACK ; Set up local stack
;................................
;
IF ZCPR3 ; ZCPR3 initialization stuff
LD HL,(Z3EADR) ;
CALL Z3VINIT ;
CALL TINIT ;
CALL GETCRT ;
INC HL ;
INC HL ;
LD A,(HL) ; Get #of lines on CRT
LD (NLINES),A ; Keep that there
SUB LINEOVERLAP+1 ;
LD (DISPLAY),A ; # of lines per screen
CALL PUTUD ; Save orig DU for exit
CALL RETUD ; Get orig logged DU
LD (DEFDU),BC ; Save that here
LD DE,FCB1 ; Log to the file spec'd on the cmnd line
CALL Z3LOG ;
CALL RETUD ; Get the filenames DU
LD (LBRDU),BC ; And save that here..
LD HL,($MEMRY) ; Get addr of free memory
;...............................;
;................................
; French vanilla CP/M
ELSE ;
ld A,LINES ;
ld (NLINES),a ; Init screen size
LD A,DISPLY ;
LD (DISPLAY),A ; Init lines/pg-1
LD C,GETDSK ;
CALL BDOSEV ;
LD (DEFDU+1),A ; Keep default drive here ( 0 = "A")
LD (LBRDU+1),A ; Assume that the spec'd filename is same
LD A,(FCB1+0) ; Get the filename's drive spec
OR A ;
JR Z,ISSAME ; If zero, it is indeed the same
DEC A ; Else reduce the fcb+0 value so "A = 0"
LD (LBRDU+1),A ; And use that
;
ISSAME: LD C,SGUSER ; Now for user area stuff. For the regular
LD E,0FFH ; - CP / M version there is only one user#
CALL BDOSEV ;
LD (DEFDU+0),A ; So keep default user here (for display)
LD (LBRDU+0),A ; And a copy here as well
LD HL,ENDPROG ; Get addr of free memory
ENDIF ;
;...............................;
;................................
; New dynamic memory allocation.
LD (@PTRTBL),HL ; Assign beg of free memory to 1k "PTRTBL"
LD DE,1024 ;
ADD HL,DE ;
LD (@BUFFER),HL ; And everything above that to "BUFFER"
;...............................;
CALL INI1MEM ; Init all memory from "init1" - "end1init"
CALL INI2MEM ; Init all memory from "init2" - "end2init"
; (also initializes "ptrtbl")
LD A,40 ; Init Console String Buffer
LD (STRMAX),A ;
IF USEBIOSCONOUT ; Using faster BIOS rtn
LD HL,(1) ; BIOS + 3 warm start ep
LD DE,9 ; Bias to BIOS conout jp
ADD HL,DE
LD (BIOSCONOUT),HL ; Save adr for fast putc
ENDIF
LD HL,(@BUFFER) ; **
LD (BUFPTR),HL ; Set buffer ptr
XOR A ; Zero a
LD (FRSTFL),A ;
LD (FCB1R2),A ; For random reads
;..............................................................................
;
; Check for existence of BYE5.
; Note that "remote operation" is assumed if BYE is detected.
;
LD C,SGUSER ; BDOS set/get user call
LD E,0FFH ; First get current value
CALL BDOSEV ;
PUSH AF ; Save current value
;
LD C,SGUSER ; BDOS set/get user call
LD E,241 ; Magic number to see if bye is resident
CALL BDOSEV ; Look for special result from "set/get" user
CP 77 ; Magic return # if BYE is there
JR NZ,NOBYE ; Nope..
LD HL,-0800H ; Flag "BYE5" as resident by puttin -800h here
LD (BYE5FLAG),HL ; (otherwise is zero from init above)
;
NOBYE: POP AF ; Get orig user # back
LD C,SGUSER ; BDOS set/get user call
LD E,A ; Put user# in E
CALL BDOSEV ;
;..............................................................................
;
CALL CHKSUMCCP ; Do simple chksum of CCP for quit
LD (CCPCHKSUM),A
; Do all calculations relating to available Memory right here...
LD HL,(BDOSEV+1) ; Get BDOS base
LD DE,(BYE5FLAG) ; (-2k) if CCP to be saved, else zero
ADD HL,DE ; Add, ie subtract, that
LD (BDOSBASE),HL ; Take future requests for (BDOS+1) from here
; open the file if one given
; try open 1st with given name, then as .lbr
;................................
;
LD HL,FCB1FN ; See if command tail is blank
LD A,'/' ; Chk for help invocation
CP (HL) ;
JP Z,USAGE ;
LD A,' ' ;
CP (HL) ;
JR NZ,SOMETH ; Br if something was specified
LD B,11 ; Else convert to *.*
;
QUESLP: LD (HL),'?' ;
INC HL ;
DJNZ QUESLP ;
JR SWPAMBIG ; Go "sweep" all matching filenames
;...............................;
; check if ambig file specified
SOMETH: LD BC,11 ; Length (HL already set)
LD A,'?' ; Find a ?
CPIR ; Search
JR Z,SWPAMBIG ; If ambiguous, sweep 'em
;..............................................................................
;
OPENSOMEFILE: ;
LD HL,FCB1FN ; Src
LD DE,FNEXT ; Dst
LD BC,11 ; Len
LDIR ; Copy filename.ext
LD C,OPEN
CALL BDOSCALL ; Open file
JP P,OPENOK ; Open ok >= 0
LD A,(LIBRARY)
OR A ;
JR NZ,NONE ; Error, couldn't find reg or lbr w/ that name
; see if there's a lbr by same name to get member listing
OPENLIB:
LD A,0FFH
LD (LIBRARY),A ; Library flag
LD HL,FCB1EXT
LD (HL),'L' ; Add 'lbr' extension
INC HL
LD (HL),'B'
INC HL
LD (HL),'R'
; now try to open the library
JR OPENSOMEFILE
;..............................................................................
;
; The routines to handle ambigous file specifications follow (ie arrive
; here if at least one ? in filename).
;
; Note: In this case an LBR will always be opened as a library.
; In the less than likely event the user wants to examine the guts
; of an LBR file, he may still do so by typing the full command line, eg.
; "QL FILE.LBR" - but "QL FILE" or "QL *.LBR" or almost anything else
; will treat LBR files as libraries).
; We accumulate filenames at the start of the buffer, resetting BUFPTR
; and ask the user to choose one. After selection, we open the file as
; if it had been fully specified.
; After the user is finished with the file (or entire library if an LBR),
; QLEXIT returns to SWEEP, so he can examine another one. The filenames
; are protected by the resetting of BUFPTR.
; first preserve ambiguous filename
SWPAMBIG:
LD DE,(BUFPTR) ; Dest for fnames
LD (FILPTR),DE ; Save as start of fname table
LD HL,FCB1FN ; Src
LD BC,11 ; Len
LDIR
PUSH DE ; Save ptr
LD DE,80H ; Set default DMA
LD C,SETDMA
CALL BDOSCALL
LD C,SRCH1ST ; Search for first
CALL BDOSCALL
INC A ; A match found?
JR NZ,SWP1 ; Yep
NONE: CALL MSG ; Display error msg
DB CR,LF,'++ No matching files found ++',CR,LF,0
JR USAGE
;..............................................................................
;
SWP1: LD IX,0 ; Matches
POP DE ; Dest for fnames
SWPLP: DEC A ; Un-INC
ADD A,A ; A<<5
ADD A,A
ADD A,A
ADD A,A
ADD A,A
ADD A,81H ; +DMA points to fn
LD L,A ; Move to HL
LD H,0
;................................
; System security stuff
PUSH HL ; WHLCHK destroys (not any more!)
CALL WHLCHK ;
JR NZ,SWPOK ; If wheel is set, it's ok
LD A,L ; Else check SYS attr
ADD A,9 ;
LD L,A ;
BIT 7,(HL) ;
JR NZ,SWPNXT ; If set, pretend it wasn't found
DEC HL ; Next check if online COM file
LD A,(HL) ;
AND 7FH ;
CP 'C' ;
JR NZ,SWPOK ;
INC HL ;
LD A,(HL) ;
CP 'O' ; (we know SYS is not set)
JR NZ,SWPOK ;
INC HL ;
LD A,(HL) ;
AND 7FH ;
CP 'M' ;
JR Z,SWPNXT ; If so, pretend it wasn't found
;.....
; ; File is good, use it
SWPOK: POP HL ; Source
LD B,11 ; Chars in filename
LDIRLP: LD A,(HL) ; Move it - strip any hi-bits
AND 7FH ; (can't use LDIR, oh well...)
LD (DE),A ;
INC HL ;
INC DE ;
DJNZ LDIRLP ;
INC IX ; Count it
JR SWPNX2 ; (don't pop HL again)
;.....
; ; File is not authorized, go onto next
SWPNXT: POP HL ; Make sure HL gets popped anyway
SWPNX2: LD C,SRCHNXT ; Search for next
CALL BDOSCALL
INC A ; Match?
JR NZ,SWPLP ; Yes, go get it
PUSH IX ; Get count in HL
POP HL
LD A,H ; >255 files?
OR A ; Better be zero!
JR Z,SWP2 ;
CALL MSG ; Display error msg
DB CR,LF,'++ Error: Too many matching files ++',0
USAGE: CALL MSG
DB CR,LF,LF,' Usage: QL <afn>'
DB CR,LF
DB ' where <afn> should not match more than 255 files.'
DB CR,LF,LF,0
JP QLEXIT ; Exit
SWP2:
LD A,L ; Get file cnt
OR A ; Zero files?
JP Z,NONE ; Err msg & exit
LD (FILCNT),A ; Save it
LD (BUFPTR),DE ; Protect filenames
; If there was only one file, don't sweep
LD A,(FILCNT) ; Only 1 file?
DEC A
JR NZ,SORTEM ; If not, sort them alphabetically
LD B,1 ; If so...
JP LOOKUP ; Go get it
SORTEM: CALL SORT ; Sort the files into alphabetical order
;.....
;
; Arrive here when ready to choose next file to view.
;
SWEEP: XOR A
LD HL,FCB1FN ; Reset entire fcb except drive code
LD DE,FCB1FN+1
LD BC,34
LD (HL),A
LDIR
CALL INI2MEM ; Init all memory from "init2" to "end2init"
; (also initializes "ptrtbl")
CALL DFNS ; Display 'Files Matching: DU <afn>'
XOR A ;
LD (SCRNUM),A ; Init "screen#" to zero (goes, 0,72,144..)
NSCR: LD A,(FILCNT) ; Count of files
LD (HIPG),A ; Set hipg so can deduce when enuf
INC A ; Count +1
LD D,A ; Max #of files +1 goes into D
LD E,1 ; E is line#, (init to 1)
;................................
;
LINLP: LD B,4 ; Outer loop for NL lines
LD A,(SCRNUM) ;
ADD A,E ; 1st file# in each line = line# + scrn#
LD C,A ;
;................................
; Inner loop, 4/line
LP4: LD A,C ; File#
CP D ; Compare to max
JR NC,OUT4 ; If greater, done w/ this line
CALL C11HL ; Convert file # in c to pointer to name in HL
CALL PRNUMFN ; Print xxx:filename.ext
LD A,C ;
ADD A,NL ; Next file, if any, is prev# plus NL
LD C,A ;
DJNZ LP4 ;
;...............................;
OUT4: CALL CRLF ;
LD A,E ; Advance to next line
INC A ;
LD E,A ;
CP NL+1 ;
JR C,LINLP ;
;...............................;
LD A,(SCRNUM) ;
ADD A,72 ;
JR NC,NOVF72 ;
LD A,255 ;
NOVF72: LD (SCRNUM),A ;
LD C,A ;
CP D ;
JR NC,CHOOSE ;
CALL MSG ;
DB CR,LF,'File number or <ret> for more selections: ',0
XOR A ; "duplicate code starts here (subr?)
LD (JUMPTO),A ; Init jumpto for get
CALL GETCHNUM ; Get user member choice
LD C,A ;
LD A,(JUMPTO) ; Did he enter a number?
OR A ;
JP NZ,CHKFIL ; Go check it
LD A,C ;
CP CR ;
JR Z,NXTSCR ;
CALL CHEXIT ; ^C or ^K will exit direct to CP/M
JP Z,QLEXIT ; Other 'exit' type characters
NXTSCR: CALL DFNS ; Else continue with next screen
JP NSCR ;
;................................
;
C11HL: PUSH DE ; Save for caller
LD H,0 ;
LD L,C ;
PUSH HL ; Temp save '1x' value
ADD HL,HL ; 2x val
ADD HL,HL ; 4x val
PUSH HL ; Save temporarily
ADD HL,HL ; 8x value
POP DE ; Pop 4x val into de...
ADD HL,DE ; Now have 12x
POP DE ; Get back 1x
SBC HL,DE ; (carry certainly clear from prev addition)
LD DE,(FILPTR) ; Offset to beg of filenames (indirect)
ADD HL,DE ;
POP DE ; Restore caller's DE
RET ; Return pointer to filename
;...............................;
;.....
;
; Let user choose his selection
;
CHOOSE: CALL OFFHALF ;
CALL MSG
DB CR,LF,'Select file (1-',0
LD A,(FILCNT) ; Get count
LD (HIPG),A ; Set hipg so can deduce when enuf
LD L,A
LD H,0
CALL B2DEC
CALL MSG
DB '),',0
CALL WHLCHK
JR Z,SKPDMP
LD A,(FRSTFL)
OR A
JR NZ,SKPDMP
CALL MSG
DB ' <D>ump memory,',0
SKPDMP: CALL MSG
DB ' or <ret> to exit: ',0
BADCHAR:
XOR A
LD (JUMPTO),A ; Init jumpto for get
CALL GETCHNUM ; Get user member choice
LD C,A ;
LD A,(JUMPTO) ; Did he enter a number?
OR A ;
JR NZ,CHKFIL ; Go check it
LD A,C ;
CALL UCASE ; Possibly upcase his character response
LD C,A ;
CALL WHLCHK ; (kills A)
JR Z,SKPD2 ;
LD A,(FRSTFL) ;
OR A ;
JR NZ,SKPD2 ;
LD A,C ;
CP 'D' ;
JR Z,COREDM ; Go do a memory dump
SKPD2: LD A,C ;
CALL CHEXIT ; ^C or ^K will exit direct to CP/M
JP Z,QLEXIT ; Other 'exit' type characters
JR BADCHAR ;
;..............................................................................
;
; Chk for file # too big
;
CHKFIL: LD B,A ; B = jumpto
LD A,(FILCNT)
CP B ; Cy if filcnt < jumpto
JP C,SWEEP ; Display files again
CALL CRLF
XOR A
LD (JUMPTO),A ; Rst jumpto
DEC A
LD (SWEEPING),A ; Set sweeping flag
LD (FRSTFL),A ;
; Lookup member number
LOOKUP: LD L,B ; Move jumpto to HL
LD H,0
PUSH HL ; Save *1
ADD HL,HL
PUSH HL ; Save *2
ADD HL,HL
ADD HL,HL ; HL=*8
POP DE ; Rst *2
ADD HL,DE ; HL=*10
POP DE ; Rst *1
ADD HL,DE ; HL=*11
LD DE,(FILPTR) ; Start of file table
ADD HL,DE ; *hl = selected file
LD DE,FCB1FN ; Dest
LD BC,11 ; Length
LDIR
;
CALL ISLBR ; If LBR, open as one, else don't
JP NZ,OPENSOMEFILE ;
JP OPENLIB ;
; Subrtn to check if FCB1 extension matches "LBR"
; destroys A,HL -- Z set if match
ISLBR: LD HL,FCB1EXT ; See if FCB1EXT is 'LBR'
LD A,(HL)
AND 7FH
CP 'L'
RET NZ
INC HL
LD A,(HL)
AND 7FH
CP 'B'
RET NZ
INC HL
LD A,(HL)
AND 7FH
CP 'R'
RET
;=============================================================================
;
; Come here if a "core dump" was requested
;
COREDM: LD A,0FFH ; 0ffh
LD (CORE),A ; Set flag
LD (HIPG),A ;
LD HL,0FFFFH ; Of all of memory
LD (EOFADR),HL
LD (FILELEN),HL
XOR A
LD (PAGE),A ; Set init pg 0
LD (AFLAG),A ; Allow hex/ascii disp only
CALL TOGLA ; (flip from 0 [ascii] to ff [hex])
LD HL,(@PTRTBL) ;
INC HL ;
XOR A ;
LD B,A ; 256 pgs
SETMEMPP:
LD (HL),A
INC A
INC HL
INC HL
DJNZ SETMEMPP
JP PRPG ; Display hex/ascii of pg 0
;=============================================================================
;
; compute simple 1 byte chksum of entire CCP
; ret in a
;
CHKSUMCCP:
LD HL,(6)
LD DE,CCPSIZE+6 ; Size of CCP
XOR A ;
SBC HL,DE ; *CCP
LD BC,CCPSIZE ; Chksum entire CCP
CHK1SUM:
ADD A,(HL)
CPI ; HL++,BC--
RET PO ; Chksum in A
JR CHK1SUM
ILLEGAL:
CALL MSG ; Display error and exit
DB CR,LF,'++ Can''t display that ++',CR,LF,0
QLEXIT:
LD SP,STACK ; Stack may be questionable upon arrival here
IF ZCPR3
CALL GETVID
CALL NZ,DINIT
CALL GETUD
ENDIF
LD A,(PUTCABRT) ; Did we abort from PUTC?
OR A
JR NZ,QLOUT ; Yep, don't re-sweep
LD A,(SWEEPING) ; If in sweep mode, return to sweeper
OR A ;
JR Z,QLOUT ; If not
JP SWEEP ; And return to 'sweeper'
QLOUT: CALL CRLF
CALL CHKSUMCCP
LD B,A ; Ccp chksum now
LD A,(CCPCHKSUM) ; Orig CCP chksum
XOR B
JP NZ,0 ; Warm boot if CCP was overlaid
LD SP,(OLDSP) ; Else just ret to CCP
RET
;-----------------------------------------------------------------------------
;
QUIT:
QUITNOSUM:
LD SP,STACK ; Extracting may foul stack
LD A,(LIBRARY)
OR A ; Working with lbr?
JR Z,QLEXIT ; No lbr, so exit
; working with lbr: list all members and let user choose next
;
LD HL,0
LD (FCB1R0),HL ; Set lbr rec 0
CALL SEEK ; Position to lbr tof and fall thru
; System security related stuff
;
OPENOK: CALL WHLCHK ; If wheel is set, skip all this
JR NZ,LEGAL ;
LD HL,FCB1EXT+1 ; Else check if file has SYS attribute
BIT 7,(HL) ;
JP NZ,NONE ; If it does, pretend file doesn't exist
;
DEC HL ; More system security: no examing online
LD A,(HL) ; COM files. if they're in a lbr, ok, else
AND 7FH ; They should be named OBJ or CZM.
CP 'C' ;
JR NZ,LEGAL ;
INC HL ;
LD A,(HL) ;
CP 'O' ; We know that SYS is not set
JR NZ,LEGAL ;
INC HL ;
LD A,(HL) ;
AND 7FH ;
CP 'M' ;
JP Z,ILLEGAL ;
LEGAL: LD A,(LIBRARY) ; Access OK, continue
OR A
JP Z,CHKIFCOMPRESSED ; Not working with a library
; read 1st lbr directory sector to see how big lbr dir is
LD DE,(BUFPTR) ; Set dma to buffer
LD HL,1
LD (NSECTS),HL
CALL READFILE
LD A,(MTFLAG) ; Zero if readfile read nothing
OR A ;
JP Z,LBRERROR ; We'll call an empty LBR file a library error
LD IX,(BUFPTR) ; Point to buffer
LD L,(IX+14) ; Dir sects low
LD H,(IX+15) ; Dir sects high
DEC HL ; We already read the 1st
LD A,H
OR L
JR Z,PRLBRDIR ; Lbr dir is only 1 sect long
LD (NSECTS),HL
CALL READFILE ; Read the rest of the lbr dir
JP Z,LBRERROR
; print "du:lib.LBR" header for lbr directory
PRLBRDIR: ;
CALL CLEARSCREEN
CALL MSG
DB CR,LF,'Members in library ',0
PUSH DE
CALL PRNDFN ; Print DU:<filename>
POP DE
CALL CRLF ;
; print active member names of lbr
; *.C?m files in optional half intensity
; DE is next dma adr = last byte read + 1
EX DE,HL
LD (HL),0FFH ; Add lbr dir eof
CALL CRLF
LD HL,(BUFPTR)
LD C,0 ; Count active lbr dir entries
PRNXTMEMBER:
LD DE,32 ; Lbr dir incr
ADD HL,DE ; *next dir entry
LD A,(HL)
OR A ; 0 = active member?
JR Z,ISACTIVE
CP 0FEH ; Deleted member?
JR Z,PRNXTMEMBER ; Skip it
JP LBRDIREOF
ISACTIVE:
INC C ; Incr member# counter
INC HL ; (must point to name for prnumfn call)
CALL PRNUMFN ; Print xxx: filename.typ
LD A,C ; * add a crlf after each 4th name *
AND 03H ; *mskval ?? **
CALL Z,CRLF ;
DEC HL ;
JR PRNXTMEMBER ; Loop
;................................
; Display 'Files Matching: DU <afn>'
DFNS: PUSH BC ;
PUSH DE ;
PUSH HL ;
;
CALL CLEARSCREEN ;
CALL MSG ;
DB CR,LF,'Files matching ',0
CALL PRFDU ; Print appropriate DU:
LD HL,(FILPTR) ; Start of table
CALL PRNFN ; Print ambig filespec
CALL CRLF ;
CALL CRLF ;
POP HL ;
POP DE ;
POP BC ;
RET ;
;...............................;
;.....................................
;
; Print filename "C", pointed to by HL
;
PRNUMFN:
PUSH BC ;
PUSH DE ;
PUSH HL ;
CALL CKABRT ; Chk for abort 1/filename
; - (fixes stack and exits direct if requested)
PUSH BC ; Save everything ("chkext" destroys)
PUSH DE ;
PUSH HL ;
LD DE,8 ; Set de to point to the filename ext (hl+8)
ADD HL,DE ;
EX DE,HL ;
CALL CHKEXT ; Check if filename ext is COM, REL, etc.
JR C,DIMMIT ; If so, use half-intensity
CALL OFFHALF ; Else guarantee full intensity
JR POPPEM ;
DIMMIT: CALL ONHALF ; If so, do half intensity
POPPEM: POP HL ;
POP DE ;
POP BC ;
PUSH BC ;
PUSH DE ; Save everything("B2DEC" destroys)
PUSH HL ;
LD A,C ;
CP 100 ;
CALL C,SPACE ;
LD A,C ; ("b2dec" left justifies)
CP 10 ;
CALL C,SPACE ;
LD L,C ; Get member's #, still in C
LD H,0 ; Put it in HL
CALL B2DEC ; Display it
CALL MSG ;
DB '. ',0
POP HL ;
POP DE ; Restore registers
POP BC ;
CALL PRNFN ; Type the LBR name pointed to by HL
CALL OFFHALF
CALL MSG
DB ' |',0
POP HL ;
POP DE ;
POP BC ;
RET ; End of PRNUMFN: subr
;...............................;
;................................
; Subr to type filename pointed to by HL
;
PRNFN: LD A,(CORE) ; A core dump never has a filename
OR A ;
RET NZ ; So forget about it
;
LD B,8 ; Display first 8 chars in fn
;
PRNXT: LD A,(HL) ; Get char of member name
INC HL ; *char++
AND 7FH ; (make sure 'dcase' works right)
;
IF LOWERCASE ;
CALL DCASE ; "downcase" the character
ENDIF ; Lowercase
;
CALL PUTC ; Print it
DJNZ PRNXT ; Loop 8 times
;
LD A,'.' ; Now display a "."
CALL PUTC ;
;
LD B,3 ; Same as above 3 more times for ext
;
PRNXT2: LD A,(HL) ;
INC HL ;
AND 7FH ;
;
IF LOWERCASE ;
CALL DCASE ; "downcase" the character
ENDIF ; Lowercase
;
CALL PUTC ;
DJNZ PRNXT2 ; Loop 3 times
RET ;
;...............................;
;................................
;
PRFDU: LD HL,(LBRDU) ; Type the filename's (FCB1's) DU:
JR PDU ;
;
PRDDU: LD HL,(DEFDU) ; Type the originally logged (default) DU
;
PDU: LD A,'A' ;
ADD A,H ; Convert that to ascii
CALL PUTC ; And display it
LD H,0 ; User# already in "L", so just zero H
CALL B2DEC ; Print the user#
LD A,':' ;
CALL PUTC ; Print a colon
RET ;
;...............................;
;................................
; Print DU:<filename> for the FCB1 filename
PRNDFN: CALL PRFDU ; Print DU:
LD HL,FCB1+1 ; Point to filename
CALL PRNFN ; Print it and return
RET ;
;...............................;
LBRDIREOF:
LD A,C
LD (NMEMBERS),A ; Save # of active members, counted in C
CALL OFFHALF ;
CALL CRLF ;
CALL CRLF ;
CALL PRDDU ; Type the default DU to the screen
LD A,(EXTRACTING) ; Check flag
OR A ;
JR Z,VIEWPROMPT ; 0: viewing - no special prompt
CALL MSG ;
DB '> Extract',0 ;
JR PROMPT ;
VIEWPROMPT: ;
CALL MSG ;
DB '> View',0 ;
PROMPT: ;
CALL MSG ;
DB ' member (1-',0
LD A,(NMEMBERS) ; # of active members
LD L,A
LD H,0
CALL B2DEC
CALL WHLCHK
JR NZ,WHOK
CALL MSG
DB ') or <ret>: ',0 ; Rest of prompt if no wheel
JR GETRSP ; ** more effecient??
WHOK: LD A,(EXTRACTING)
OR A
JR NZ,EXTPR
CALL MSG ; Rest of prompt while in View mode
DB '), ''E'' for Extract',0
JR RESTPR ; Still more below
EXTPR: CALL MSG ; Rest of prompt while in Extract mode
DB '), ''V'' for View',0
RESTPR: CALL MSG
DB ' mode, or <ret>: ',0
GETRSP: XOR A
LD (JUMPTO),A ; Init jumpto for get
LD A,(NMEMBERS)
LD (HIPG),A ; Set hipg so get can deduce when enuf
CALL GETCHNUM ; Get user member choice
LD C,A ;
LD A,(JUMPTO) ; Did he enter a number
OR A ;
JP NZ,CHKNUM ; Go check it
LD A,C ;
CALL UCASE ; Possibly upcase a character in A
CALL CHEXIT ; ^C or ^K will exit direct to CP/M
JP Z,QLEXIT ; Other 'exit' type characters
LD B,A ;
CALL WHLCHK ; Nothing else legal if wheel isn't set
LD A,B ;
JR Z,GETRSP ;
CP 'E'
JR Z,EXTRMODE
CP 'V' ;
JR NZ,GETRSP ; Try again
XOR A ; Flag for view mode
JR MODESET
EXTRMODE: ;
LD A,1 ; Flag for extract mode
MODESET: ;
LD (EXTRACTING),A ; Set the mode
; Fall thru, redisplay w/ new prompt
CALL CLEARSCREEN ;
JP QUITNOSUM ;
;................................
;
CHEXIT: CP CTRLC ; ^C or ^K exit right to CP/M
JP Z,SYSTEM ; (stack gets fixed)
CP CTRLK ;
JP Z,SYSTEM ;
;
CP 'X' ; Other exit chars rtn w/ zero stat
RET Z ;
CP 'Q' ;
RET Z ;
CP ESC ;
RET Z ;
CP CTRLX ;
RET Z ;
CP CR ;
RET ;
;...............................;
;=============================================================================
; Hre we prepare to extract (and possibly decompress) to disk.
; Most of the work is done by the routines for ordinary reading, with
; the few differences being invoked by the setting of the EXTRACTING flag.
;
EXTCHK: LD A,(EXTRACTING) ; Return Z flag for EXTRACTING
OR A
RET
EXTRDONE:
; When we get here, all except last (partial) buffer has been written
; *(DE-1) is last addr used.
LD A,127 ; Include last sector
ADD A,E
LD E,A
LD A,D
ADC A,0
LD D,A
CALL OUTFLUSH ; Write the last buffer
LD C,CLOSE ; Close the file
LD DE,FCB3
CALL BDOSEV
IF ZCPR3
LD BC,(LBRDU) ;
CALL LOGUD ;
ENDIF ; ZCPR3
LD HL,(FLSECTS) ;
PUSH HL
CALL MSG
DB CR,LF,'Wrote ',0
CALL B2DEC ; Print # of sectors
CALL MSG
DB ' sectors (',0
POP HL ; = # sectors
XOR A ; Clear carry & byte
LD B,3
ROLP: RR H ; Divide by 8 & keep frac
RR L
RR A
DJNZ ROLP
OR A ; Any fraction?
JR Z,NOFRAC
INC HL ; Yep, count as 1K
NOFRAC: CALL B2DEC ; Print # of K
CALL MSG
DB 'K)',CR,LF,0
CALL DELAY8
JP QUITNOSUM ; Display lbr dir again
;...............................;
; This code segment takes the filename from FCB3+16
; and parses it into the destination file at FCB3.
; For uncompressed files, we simply move it.
; For squeezed/crunched files, we have to find the period etc.
;
EXTCRFILE: LD HL,FCB3+17 ; Point to member fn
LD DE,FCB3+1 ; Point to disk fcb
LD BC,8 ; 8 chars in first segment
EXTCR0: LD A,(HL) ; Get next char
AND 127 ; ASCII mask (no file attributes!)
JR Z,EXTCR1 ; If zero, was end of string char
CP '.' ; Dot yet?
JR Z,EXTCR1
LDI ; Transfer char
JP PE,EXTCR0 ; Loop if not done
; if we get here, the filename may be too long. We ignore bytes until we find
; a dot or null.
EXTSKIP:LD A,(HL)
OR A ; Null?
JR Z,EXTCR2
CP '.' ; Dot?
JR Z,EXTCR2
INC HL ; Test next char
JR EXTSKIP
EXTCR1: LD A,' ' ; Fill remaining part of first segment
LD (DE),A ; With spaces
INC DE
DEC C
JR NZ,EXTCR1
EXTCR2: INC HL ; Bump past dot
LD BC,3 ; Three more chars
EXTC2B: LD A,(HL) ; Get char
OR A ; Null means we fill with space
JR NZ,EXTCR4
LD A,' ' ; Fill with space
EXTCR3: LD (DE),A
INC DE
DEC C
JR NZ,EXTCR3
JR EXTFIL
EXTCR4: LDI ; Transfer char
JP PE,EXTC2B ; Loop
JR EXTFIL
EXTUCFILE: LD HL,MEMBER ; Point to member fn
LD DE,FCB3+1 ; Point to disk fcb
LD BC,11
LDIR
EXTFIL: LD HL,FCB3+12 ; Gotta zero rest of fcb3
INC DE ; Points to FCB3+13
LD (HL),0
LD BC,20
LDIR
LD (FLSECTS),BC ; Reset the sectors-written counter
IF ZCPR3
CALL GETUD ;
ENDIF ; ZCPR3
LD C,OPEN ; Attempt to open file
LD DE,FCB3
CALL BDOSEV
INC A ; Success means it already exists
JR Z,LEXT4
CALL MSG
DB CR,LF,LF,' ==> File exists; purge (y/N)? ',0
LD C,1
CALL BDOSEV
AND 1FH ; Y, y, or ^Y OK
CP 19H
PUSH AF ; ***
CALL CRLF
POP AF ; ***
JP NZ,QUITNOSUM ; Abort if he said no
LD C,ERASE ; Erase if he said yes
LD DE,FCB3
CALL BDOSEV
LEXT4: LD C,CREAT ; Create the file
LD DE,FCB3
CALL BDOSEV
INC A ; Failure means no dir space
RET NZ ; If it succeeded go back to reading-in code
CALL MSG
DB ' ++ Directory full ++ ',CR,LF,0
LWAIT0: CALL DELAY8
JP QUITNOSUM
;................................
;
DELAY8: CALL DELAY4 ;
DELAY4: CALL DELAY2 ;
DELAY2: CALL DELAY1 ;
DELAY1: LD BC,0 ;
;
LWAIT: NOP ;
DJNZ LWAIT ;
DEC C ;
JR NZ,LWAIT ;
RET ;
;...............................;
; Buffer flush failed; disk is full.
NOSPACE:
CALL MSG
DB ' ++ Disk Full ++',CR,LF,0
LD C,ERASE ; Erase the file
LD DE,FCB3
CALL BDOSEV
JR LWAIT0
; chk for too big a member #
CHKNUM: LD B,A ; B = jumpto
LD A,(NMEMBERS)
CP B ; Cy if nmembers < jumpto
JP C,QUITNOSUM ; Display lbr dir again
XOR A
LD (JUMPTO),A ; Rst jumpto
; go to member number & display it
LD HL,(BUFPTR)
LD DE,32 ; Dir incr
MEMCNT: ADD HL,DE
; chk for deleted not at eof
LD A,0FEH ; Deleted marker
CP (HL)
JR Z,MEMCNT ; Skip if deleted
DJNZ MEMCNT
INC HL ; *fn[1]
; copy full fn ext to member name string and to fnext string
;
PUSH HL ; Save *fn[1]
LD DE,MEMBER
LD BC,11
LDIR ; Copy to member $
POP HL ; Rst *fn[1]
LD DE,FNEXT
LD BC,11
LDIR ; Copy to fnext $
LD E,(HL) ; HL = *member start
INC HL
LD D,(HL) ; DE = starting sect of member
LD (FCB1R0),DE ; Fill in lbr r0,r1 fld for seek to member
INC HL ; HL = *member len
LD E,(HL)
INC HL
LD D,(HL) ; DE = len in sects to read after seek
LD (NSECTS),DE
; chk for zero len, maybe a lbr date file
LD A,D
OR E
JP Z,MT ; If member is empty (zero-length)
; position to member within lbr at fcb1r0
SEEKMEMBER:
CALL SEEK
JP CHKIFCOMPRESSED
; assumes fcb1r0 is set to rec to seek to
; set fcb1 r2 fld to 0
SEEK: XOR A
LD (FCB1R2),A ; 0 lbr r2 fld
LD C,RANDOM
CALL BDOSCALL
RET Z ; Seek ok
POP HL ; Destroy ret adr
LBRERROR:
CALL MSG
DB 'LBR read error',0
JP QLEXIT
;.....
;
SUMMARY:
CALL ONHALF ; Dim videp
CALL MSG ;
DB CR,LF,' File: ',0 ;
CALL PRNDFN ; Print DU:<filename>
CALL CRLF
LD A,(LIBRARY) ;
OR A ;
JR Z,NLBR2 ;
CALL MSG ;
DB 'Member: ',0 ;
LD HL,MEMBER ;
CALL PRNFN ;
CALL CRLF ;
NLBR2: LD A,(INCOMPLETE) ; Was read complete?
OR A
JR Z,DOSUMMARY ; If so, we know file size
WARNING:
CALL MSG
DB CR,LF,'( ** Entire file does NOT FIT in Memory ** )',0
CALL OFFHALF
RET
; report file size
DOSUMMARY:
CALL MSG ;
DB ' Size: ',0 ;
LD HL,(FILELEN) ; In bytes
PUSH HL
CALL B2DEC
CALL MSG
DB ' bytes (',0
POP HL ; HL = filelen
SRL H
SRL H ; Shift to kilobytes
INC H ; For overflow lsb
LD L,H
LD H,0
CALL B2DEC
CALL MSG
DB 'k)',CR,LF,0
; skip line count for non-text files
LD A,(AFLAG)
OR A
JR NZ,RETSUM ; &ret, no line summary
CALL MSG
DB 'Approx: ',0
LD A,(HIPG)
DEC A ; Don't count last pg lines yet
LD B,A
LD HL,0
JR Z,ONLY1PG ; Only 1 pg, nothing to add
LD A,(DISPLAY) ; Actual lines per pg
LD E,A
LD D,L
CNTLINES:
ADD HL,DE
DJNZ CNTLINES
ONLY1PG:
LD A,(LASTPGLINES)
LD E,A
LD D,0
ADD HL,DE ; Add in last pg lines
CALL B2DEC
CALL MSG
DB ' lines, ',0
; added word counting code
; words are any seq of chars >= '0' (30h) and < 80h
; handle ws doc by ascii mask
; count space between words
LD HL,(BUFPTR)
LD D,FALSE ; Inword = false
; reg E is temp storage for curr ch
LD IX,0 ; Word count
LD BC,(FILELEN) ; Get actual file len
CNT: LD E,(HL) ; Save ch
INC HL
DEC BC
LD A,B
OR C
JR Z,CNTALLDONE
LD A,E ; Get ch
AND 7FH ; Mask to ascii
CP '0' ; Cy if < '0'
JR C,ISWHITESP
; ch is valid in word
XOR A ; False
OR D ; Inword == false?
JR NZ,CNT ; No
LD D,0FFH ; In a word now
INC IX ; Word count++
JR CNT
ISWHITESP:
LD D,FALSE ; Inword = false
JR CNT
CNTALLDONE:
PUSH IX
POP HL
CALL B2DEC
CALL MSG
DB ' words.',CR,LF,0
RETSUM: CALL OFFHALF
RET ; End summary
;------------------------------------------------------------------------------
;
; may be compressed by squeezing or crunching
;
CHKIFCOMPRESSED:
XOR A
LD (INCOMPLETE),A ; Set read not incomplete yet
LD A,(EXTRACTING) ;
AND 02H ; Bit 1 set means do not decompress
JR NZ,NORMAL ;
LD A,(LIBRARY)
OR A ; Working fr lbr?
LD A,(FCB1EXT+1) ; Chk 2nd letter of file ext
JR Z,ISITQZ ; If not lbr
LD A,(MEMBER+9) ; Else, 2nd letter of member ext
ISITQZ: CP 'Q'
JP Z,SQUEEZED
; chk for crunched file
CP 'Z'
JP Z,CRUNCHED
; else it's a normal uncompressed file
; we also come back here for *.azm files after uncr fails
NORMAL:
CALL CRLF
NORML2: CALL EXTCHK ; If extracting, handle files here
CALL NZ,EXTUCFILE ; (the UnCompressed file routine)
LD DE,(BUFPTR) ; Read into buffer til eof or mem full
LD A,(LIBRARY)
OR A
JR NZ,NRMLBR ; Nsects already set for lbr member
LD HL,512 ; Force read to eof or up to BDOS
LD (NSECTS),HL
NRMLBR: CALL MSG
DB CR,' Reading',0 ; (extra CR in case of overwrite)
CALL READFILE
JP Z,TOOLARGE ; Set incomplete read flag
LD A,(MTFLAG) ; Else check if ANYTHING was read
OR A ;
JP NZ,FINDEOF ; If so, ok
MT: CALL MSG ; Else complain
DB CR,LF,'===> File Empty.',CR,LF,0
CALL DELAY8 ;
JP QUITNOSUM ;
; rewritten for clarity?
; DE should pt to 1st dma adr on entry
; DE pts to last dma adr used on exit
; seq read of uncompressed file or lbr member or lbr dir into buffer
; reads entire file (up to BDOS) or nsects of a lbr dir or member
; nsects should be set for max sects to read
; NZ if read ok
; Z if too large for mem
READFILE:
XOR A ; If subr returns w/ mtflag=0, nothing was read
LD (MTFLAG),A
REEDFILP:
LD C,SETDMA
CALL BDOSCALL
LD C,READSEQ
CALL BDOSCALL
RET NZ ; Read to eof ok
LD A,0FFH ; If at least 1 sec read, set this flag
LD (MTFLAG),A ;
; pt to start of next dma
LD HL,128
ADD HL,DE ; Dma += 128
EX DE,HL ; DE=next dma adr
; chk next dma adr < BDOS
LD A,(BDOSBASE+1) ; [possibly adjusted] BDOS hi adr
DEC A ; 256 byte BDOS safety cushion
CP D ; Curr hi dma adr
JR NZ,OKNEXT ; File about to crash into BDOS
CALL EXTCHK
RET Z ; Nope, give up
LD DE,BDOSBASE ; Pass end-of-buffer addr
CALL OUTFLUSH ; Flush the buffer
; On return, DE points to start of buffer again
; chk if spec # of sects read
OKNEXT: LD HL,(NSECTS)
DEC HL ; Nsects--
LD (NSECTS),HL
LD A,H
OR L ; Spec # of sects read?
JR NZ,REEDFILP ; No
INC A ; Set nz for nsects read ok
RET
; C must be set for correct BDOS fn (open, readseq, readrandom) on fcb1
; we stick setdma fn call in here as well to save code space
; saves & restores all regs except af which has ret code
; set z if a = 0
BDOSCALL:
PUSH BC
PUSH DE
PUSH HL
LD A,C
IF DOSPLUS
CP 211 ; DOS+ binary to decimal printer
JR Z,DEISSET
ENDIF
CP SETDMA ; Fn call is setdma?
JR Z,DEISSET ; If so, DE already set
LD DE,FCB1
DEISSET:
CALL BDOSEV
OR A ; Set z for read ok
POP HL
POP DE
POP BC
RET
; unsqueezing code setup
SQUEEZED:
LD HL,(BDOSBASE) ; [possibly adjusted] BDOS addr
LD (WORKAREA),HL ; Workarea is all mem up to BDOS for unsq
LD HL,STACK
LD (SPSAVE),HL ; Set default stk if too large
; set *sq and *unsq
LD HL,100H ; Src ptr for getbyt, forcing read
LD DE,(BUFPTR) ; Dst ptr for out
LD (UNCRSRC),HL
LD (UNCRDST),DE
CALL MSG
DB CR,LF,LF,'Unsqueezing: ',0
CALL GETBYT
CP 76H ; Compressed file marker (halt inst)
JP NZ,NOTCOMPRESSED
CALL GETBYT
CP 0FFH ; Squeezed file marker
JP NZ,NOTCOMPRESSED
CALL GETBYT
CALL GETBYT ; Skip 2 chksum bytes
LD DE,FCB3+17 ; Place to put unsqueezed fn
; print the unsqueezed file name
NXTSQFNCHAR:
CALL GETBYT
LD (DE),A ; Save in find string area
INC DE
OR A ; '\0' $ term?
JR Z,SQFNDONE
CALL PUTC
JR NXTSQFNCHAR
SQFNDONE:
CALL EXTCHK ; If we're extracting, time to open the file
CALL NZ,EXTCRFILE ; (the CompRessed file routine)
CALL GETBYT ; Get # of 4 byte transl pairs
LD L,A
CALL GETBYT
LD H,A
; times 4 for number of bytes in transl tbl
ADD HL,HL
ADD HL,HL
LD B,H
LD C,L
; copy unsq transl tbl over ptrtbl temporarily
LD HL,(@PTRTBL) ;
COPYUNSQTT:
CALL GETBYT
LD (HL),A ; Store into tt
INC HL
DEC BC ; Ctr--
LD A,B
OR C
JR NZ,COPYUNSQTT
LD B,0 ; Init bit ctr
; drive the unsqueezer
UNSQNEXT:
CALL UNSQ ; Unsq 1 char
JR C,UNSQDONE ; Eof
CP 90H ; Repeat count follows
JR Z,REPCHAR ; Don't save 90h repeat ch
LD (LASTUNSQCH),A ; Save in case of repeat count
CALL OUT ; Put unsq char into buffer
JR UNSQNEXT
REPCHAR:
CALL UNSQ ; Get repeat count
JR C,UNSQDONE ; Eof
OR A ; 0 cnt?
JR Z,SEND90H ; Then send real 90h
PUSH BC ; Save bit ctr B
LD B,A ; Repeat ctr
DEC B ; Actual cnt is 1 less
JR Z,UNSQNEXT
LD A,(LASTUNSQCH)
REPLOOP:
PUSH AF
CALL OUT ; Out last ch B times
POP AF
DJNZ REPLOOP
POP BC ; Rst bit ctr B
JR UNSQNEXT
SEND90H:
LD A,90H
CALL OUT
JR UNSQNEXT
UNSQDONE:
CALL OUT ; Save eof marker
LD HL,(UNCRSRC)
LD DE,(UNCRDST)
JP FINDEOF
; B = bitstogo mod 8 ctr
; C = curr sq ch, maybe partially shifted
; DE = curr transl tbl incr
; HL = *sq transl tbl
UNSQ: LD DE,0 ; DE=curr tbl incr
XOR A
OR B ; Chk bits to go = 0
JR NZ,NEWINDEX ; Nz is sq char in progress
; else start with a new sq char
NXTSQCHAR:
CALL GETBYT ; Fetch a sq char
LD C,A ; Save in C
LD B,8 ; 8 bits per char shift ctr
; this code is from lt18 unsqueezer
NEWINDEX:
LD HL,(@PTRTBL) ;
; mult curr incr in DE by 4 by repeated adding
ADD HL,DE
ADD HL,DE
ADD HL,DE
ADD HL,DE
; shift out lsb of sq char & chk it
LD A,C ; Get sq char back
SRL A ; Shift bit 0 into cy
LD C,A ; Save sq ch again
JR NC,NOTSET ; Use odd pair
INC HL ; To even pair if bit was set in sq char
INC HL
NOTSET: LD E,(HL) ; New incr for DE if not transl
INC HL
LD D,(HL) ; > 7fh if valid transl
BIT 7,D ; Bit 7 set if valid
JR Z,NOTTRANSL ; Hi bit not set: E is not a transl
DEC B ; Bit ctr--
LD A,0FEH ; End of transl tbl
CP D ; Set z flag if eof
LD A,1AH ; Get eof marker
SCF ; Mark this as the eof return
RET Z ; Since 1ah could be repeat count
LD A,E ; Else get char transl
CCF ; No carry if not eof
CPL ; Extract char by inversion
RET ; Ret the unsq ch
NOTTRANSL:
DJNZ NEWINDEX
JR NXTSQCHAR
; uncrunching i/o code
CRUNCHED:
CALL MSG
DB CR,LF,LF,'Uncrunching: ',0
LD HL,100H ; Src ptr for getbyt, dummy end of sect
LD DE,(BUFPTR) ; Dst ptr for out
LD (UNCRSRC),HL
LD (UNCRDST),DE
; chk to see if header is correct for crunched file
; we do this here in order to abort gracefully if it's an uncrunched .azm file
CALL GETBYT
CP 76H
JR NZ,NOTCOMPRESSED
CALL GETBYT
CP 0FEH
JR NZ,NOTCOMPRESSED
; crunched header ok
; now output the file name
;
; Do not print data which may be after end of filename, but before the
; zero (system dependent data allowed here; CR23d uses this). We will
; print the chars if they are between "[" and "]", however.
;
LD B,12 ; Loop limit for 11 chars plus "."
LD DE,FCB3+17 ; Place to put uncrunched filename
SAYLP: CALL GETBYT ; Next filename char
LD (DE),A ; Save fn for extracting
INC DE
CP '.' ; Dot?
JR NZ,NOTDOT ; If not
LD B,4 ; If we hit the dot, only 4 (dot+3) chars left
NOTDOT: OR A ; A zero terminates, as always
JR Z,CRHDRDONE ; Yes, done
CALL PUTC ; Output the char
DJNZ SAYLP ; Loop a limited number of times
CALL EXTCHK ; If we're extracting, time to open the file
CALL NZ,EXTCRFILE ; (the CompRessed file routine)
CALL GETBYT ; This part's optional- print "[..]" text
OR A ; End-of-header?
JR Z,CRHDRDONE ; If so..
CP '[' ; Beg of comment?
JR NZ,FNDEOH ; Forget it, skip junk and continue
LD B,A ; Save that "["
LD A,' ' ; Space btwn filename and comment looks better
CALL PUTC ;
LD A,B ; Get that "[" bak again
CMNTLP: CALL PUTC ; Ok, start typing comment
CALL GETBYT ; Next char
OR A ; In case of missing "]"
JR Z,CRHDRDONE ;
CP ']' ; End of comment?
JR NZ,CMNTLP ; Loop for more chars if not
CALL PUTC ; Print closing bracket
; now (finally!) make sure we are at the zero marked eoh
FNDEOH: CALL GETBYT
OR A
JR NZ,FNDEOH
; set workarea 24k below BDOS.
; "UNC", in it's present configuration, checks that the address of free
; memory supplied to it in HL allows FULLY 24k (or more). It does this
; after rounding up the value supplied to the next even page boundary. So
; we have to add in an extra 256 bytes to allow for this rounding process.
CRHDRDONE:
LD HL,(BDOSBASE) ; [possibly adjusted] BDOS addr
LD DE,24*1024+256 ; 24k + one page for "rounding"
XOR A
SBC HL,DE
LD (WORKAREA),HL ; Save for debug only
CALL UNC ; Join uncrel after filename scanned
LD HL,(UNCRSRC)
LD DE,(UNCRDST)
JR C,CHKUNCRERRS
; file was successfully uncrunched
PUSH DE ; DE pts to last out+1
EX DE,HL ; HL now pts to last out+1
LD DE,(BUFPTR) ; Start of uncr text
XOR A
SBC HL,DE ; Len of uncr text
LD (FILELEN),HL
POP DE ; Last out+1 for findeof
JP FINDEOF ; Treat like all others
CHKUNCRERRS:
CP 2 ; Error 2 is file not crunched
JR NZ,CHK1ERROR
; we can handle this error:
; force top of file again, then treat as normal text
NOTCOMPRESSED:
LD HL,0
LD (FCB1R0),HL
LD C,RANDOM
CALL BDOSCALL ; Read at tof
JP NORML2 ; (Will overwrite "Uncrunching" msg)
CHK1ERROR:
PUSH AF
CALL CRLF
POP AF
CP 1
JR Z,ERR1
CP 5
JR NZ,CHK3ERROR
ERR1: CALL MSG
DB 'Unknown crunched format',0
JP QUITNOSUM
CHK3ERROR:
CP 3
JR NZ,CHK4ERROR
CALL MSG
DB '++ File is corrupt ++',0
JP QUITNOSUM
CHK4ERROR:
CP 4
JR NZ,UNCRUNKERROR
CALL MSG
DB '++ Out of memory ++',0
JP QUITNOSUM
UNCRUNKERROR:
PUSH AF
CALL MSG
DB '++ Uncrunch error: ',0
POP AF
ADD A,'0' ; Make an ascii #
CALL PUTC
JP QUITNOSUM
; i/o rtns for uncrel.azm
; these are also used by unsq code
GETBYT: PUSH BC ; Save working regs
PUSH HL
LD HL,(UNCRSRC)
LD A,H
CP 1 ; At 100h?
JR C,STILLINSECT
; read another sector of the file
PUSH DE ; Save dst ptr fr BDOS destruction
LD C,SETDMA
LD DE,80H ; Use default buffer
CALL BDOSCALL
LD C,READSEQ
CALL BDOSCALL ; Read next sector into it
POP DE ; Restore DE
LD HL,80H ; Set ptr to start of this sector
STILLINSECT:
LD A,(HL) ; Get a char to uncr
INC HL ; *ch++
LD (UNCRSRC),HL
POP HL ; Restore working regs
POP BC
RET
OUT: PUSH AF
PUSH DE ; Save working regs
LD DE,(UNCRDST)
LD (DE),A
INC DE
; chk for DE > workarea
LD A,(WORKAREA+1)
CP D ; Hi bytes only
JR NZ,OUTOK
; else, uncr/unsq text is about to run into workarea
; so if we are extracting from a library, we flush the buffer now
CALL EXTCHK ; Are we indeed extracting?
JR NZ,OUT0
LD SP,(SPSAVE) ; Restore our sp
CALL CRLF
DEC DE ; DE pts to last byte uncr
JR TOOLARGE
OUTFLUSH:
PUSH HL ; Save last 2 working regs
PUSH BC ;
LD HL,(BUFPTR) ;
EX DE,HL ; Put last sector used addr in HL
OR A ; Clear carry for 16-bit subtract
SBC HL,DE ; HL is now length of full buffer
PUSH HL ; Save it
;;;; ADD HL,HL ; H has sector count ==> NO!! not if HL > 8000H
; V4.0 must use 2-byte sector count!!
LD B,0 ; BC will be sector counter
LD C,H ;
SLA L ;
RL C ;
RL B ; Now BC has correct sector count
OUTF0: PUSH DE
PUSH BC
LD C,SETDMA ; Set DMA to this sector
CALL BDOSEV
LD C,WRITSEQ ; Write sector
LD DE,FCB3 ; Extraction FCB
CALL BDOSEV
OR A ; Out of space?
JP NZ,NOSPACE
LD HL,(FLSECTS) ; Count one more sector flushed
INC HL
LD (FLSECTS),HL
POP BC
POP DE
LD HL,80H ; Point to next sector
ADD HL,DE
EX DE,HL ; Swap into DE
DEC BC ; V4.0 need 2-byte loop counter, as mentioned
LD A,B ;
OR C ;
JR NZ,OUTF0 ;
POP HL ; Get back orig buffer length
LD A,L ; Low byte
AND 127 ; This many bytes were not flushed
LD C,A ; Move to BC
LD B,0
EX DE,HL ; Point to unflushed bytes
LD DE,(BUFPTR) ; Point to start of buffer
JR Z,OUTF1 ; If there were no bytes, skip it
LDIR
OUTF1:
POP BC ; Restore regs
POP HL
RET ; And DE points to first free location
OUT0: LD DE,(WORKAREA) ; Pass ptr to buffer top in DE
LD E,0
CALL OUTFLUSH
OUTOK: LD (UNCRDST),DE ; Reset destination ptr
POP DE ; Rst working regs
POP AF
RET
;..............................................................................
;
TOOLARGE:
LD A,0FFH ; Flag incomplete read
LD (INCOMPLETE),A
;.....
;
; we're no longer working with a compressed file
; normal, unsq & uncr all come here
; if we were extracting, go finish up, else
; find eof marker: only look in last sector read
; if no eof found, put one in at end of last sector
;
FINDEOF:
LD A,(EXTRACTING) ; Were we extracting?
OR A
JP NZ,EXTRDONE ; ***
EX DE,HL ; Last dma now in HL
LD BC,128
XOR A ; Clr cy
SBC HL,BC ; HL=start of last sector read
LD A,EOF
CPIR ; Look for eof thru 128 bytes
JR Z,GOTEOF ; Eof found
LD (HL),A ; Else put in our own eof marker
; Probably leaves some garbage at eof
GOTEOF: LD (EOFADR),HL ; Save highest used adr
XOR A ; Clr cy
LD DE,(BUFPTR)
SBC HL,DE
LD (FILELEN),HL ; Save actual file len in bytes
; chk if we really have a text file
; assume it's text:
; IF the 1st byte is between 20h and 7fh or cr, lf or tab or formfeed
; AND 90% of 1st 100 chars are printable (for wordstar hi bits)
; if text, set ptrs to 1 char past every 22nd lf in buffer
; else, set up for hex/ascii dumping instead of chaos of earlier versions
; by setting ptrs to every 256 bytes of buffer
;
; 1st see if we really have a text file
;
LD HL,(BUFPTR)
LD A,(HL)
CALL CHKOKCTRLS ; Cr,lf,tab?
JR Z,CHKTEXT ; Text so far
CP ' '
JR C,ISNONTEXT ; Ctrl char 1st
CP 7FH+1 ; This screens common init 0c3h
JR NC,ISNONTEXT
CHKTEXT:
LD B,100 ; # to scan
LD C,0 ; Count of non-text chars
WASTEXT:
LD A,(HL)
INC HL
AND 7FH ; Mask to ascii
CALL CHKOKCTRLS
JR Z,TEXTCH
CP ' ' ; Some kind of ctrl char?
JR NC,TEXTCH
INC C ; Non-text++
TEXTCH: DJNZ WASTEXT
LD A,C ; Non-text count
CP 10 ; If < 10/100 are non-text,
JR C,ISTEXT ; It really is a text file
;.....
;
; setup for a non-text file
;
ISNONTEXT:
XOR A
LD (AFLAG),A
CALL TOGLA
LD HL,(FILELEN)
LD A,L
OR A
LD A,H ; # of 256 byte pgs
JR Z,EVENPG ; Even page boundary
INC A ; For overage
EVENPG: LD (HIPG),A
; set pg ptrs to every 256 bytes of buffer
LD B,A
LD DE,(BUFPTR)
DEC DE
LD HL,(@PTRTBL)
SETPP: LD (HL),E
INC HL
LD (HL),D
INC HL
INC D ; += 256 bytes
DJNZ SETPP
JP STICKINEOF ; Stick in eof adr for last pg finds
; - and print page 1
;................................
; ;
CHKOKCTRLS: ; Subr to chk for ctrl chars ok in a text file
CP TAB ; Ret with Z set if tab,cr,lf, or ff
RET Z ;
CP CR ;
RET Z ;
CP FF ;
RET Z ;
CP LF ;
RET Z ;
CP 1AH ;
RET ;
;...............................;
;.....
;
; Setup for a text file
;
; distinguish ws doc files by looking for 1st page break: 8ah
; if prev ch is 0dh or 8dh, assume it to be ws doc
;
ISTEXT: LD A,0FFH ;
LD (AFLAG),A ; Mark non-text flag false
CALL TOGLA ;
LD (WSDOC),A ;
LD HL,(BUFPTR)
LD BC,(FILELEN)
LD A,8AH ; 1st possible ws doc pg break
CPIR
JP PO,NOPGBRK ; None found
DEC HL
STILLLF:
DEC HL ; Back up to prev cr
LD A,(HL)
AND 7FH
CP LF
JR Z,STILLLF ; Skip if dbl sp
CP CR
JR NZ,NOPGBRK ; 8ah not preceded by 0dh or 8dh
; it's a real pg brk: go thru file and chg all 8ah to temp 0ah
; push adrs on stk so we can restore later
LD A,0FFH
LD (WSDOC),A
LD HL,0
PUSH HL ; Flag top of stk
LD HL,(BUFPTR)
LD BC,(FILELEN)
LD A,8AH
FIND8AHNEXT:
CPIR ; Look for 8ah to chg
JP PO,NOPGBRK ; All 8ah chg to 0ah
DEC HL ; HL now *8ah
PUSH HL ; Save adr on stk for later
; No stk overflow chking done??
LD (HL),LF ; Chg to real lf
INC HL
JR FIND8AHNEXT
; set pg ptrs to ch following every 22nd lf
NOPGBRK:
LD DE,(BUFPTR) ;
LD HL,(@PTRTBL) ;
LD (HL),E ;
INC HL ;
LD (HL),D ;
INC HL ;
EX DE,HL ;
LD HL,(BUFPTR) ;
LD BC,(FILELEN) ; Get actual file len
LD IX,0 ; Pg ctr
SET1: LD A,(DISPLAY) ; Usually every 22 lines
SET2: PUSH AF ; Save line ctr
LD A,LF
CPIR ; Look for lf
JP PO,SETDONE ; BC = 0 = last lf before eof
POP AF ; Line ctr
DEC A ; Is this the 22nd line?
JR NZ,SET2 ; Not a pg break
; at pg break, store adr of start of next pg
EX DE,HL ; DE=adr to store, HL=*ptrtbl
LD (HL),E ; Store lo adr of pg ptr
INC HL
LD (HL),D ; Store hi adr
INC HL
EX DE,HL ; Rst ptrs
INC IX ; Pg++
; chk for > 255 pgs NOT implemented
JR SET1
SETDONE:
POP BC ; B = line ctr fr stk
LD A,(DISPLAY)
SUB B ; 22-last line
JR NZ,PARTIALPG ;
LD A,B ; Display - 1
JR NOPARTIALPG ; This partial is really a full pg
PARTIALPG: ;
INC IX ; For last partial pg
NOPARTIALPG:
LD (LASTPGLINES),A ; Moved down to here
PUSH IX ; Pg ctr
POP HL
LD A,L ; Max 255 pgs allowed
LD (HIPG),A ; Save highest pg #
; stick in eof adr for last pg finds
LD HL,(EOFADR)
EX DE,HL
STICKINEOF:
LD (HL),E
INC HL
LD (HL),D
LD A,(AFLAG)
OR A
JR NZ,PRPG1 ; Skip this text stuff if in non-text
; if ws doc, restore 8ah removed before, adrs on stk
LD A,(WSDOC)
OR A
JR Z,PRPG1 ; Not ws doc
; do the restore until we pop 0000 flag
LD B,8AH
POP8AHNEXT:
POP HL ; Adr where 8ah was before
LD A,H
OR L ; At top of stk flag?
JR Z,PRPG1 ; Yes, done
LD (HL),B ; Replace 8ah
JR POP8AHNEXT
PRPG1: LD A,1
LD (PAGE),A ; Force pg 1 & print it
; print the current page
PRPG: CALL CLEARSCREEN
; chk for pg # beyond eof
LD A,(HIPG)
LD B,A ; B=hipg
LD A,(PAGE)
CP B ; Pg # too big?
JR C,PGNUMOK ; No
LD A,B
LD (PAGE),A ; Else, set highest pg num
; chk if doing hex/ascii dump
PGNUMOK:
LD A,(AFLAG)
OR A ; Non-text mode?
LD A,(PAGE)
JR Z,PRTEXT ; No, do text
CALL HEXASCII ; Else, dump 256 bytes like ddt
JP GETCMD
PRTEXT: LD L,A
LD H,0
DEC HL ; Pg 1 is ptd to by 0'th ptr
ADD HL,HL ; *2 for word adr
LD DE,(@PTRTBL) ;
ADD HL,DE ; *start adr of pg we want
LD E,(HL) ; Lo pg adr
INC HL
LD D,(HL) ; Hi pg adr
EX DE,HL ; HL = adr of pg we want
ld a,(NLINES) ;
LD B,A ; Lines/pg ctr, faster than cp adrs
DEC B
; B has # of lines to dump
PUTNEXT:
LD A,(FOUND)
OR A ; Are we marking found $?
JR Z,PUT1NEXT ; No
CALL ATMATCHADR ; Are we at the found $ yet?
JR NZ,PUT1NEXT ; No
; start hilite of found $
PUSH BC ; Save line ctr
CALL ONHILITE ;
CALL Z,USEALT ; (if that failed, use alternate method)
LD A,(STRLEN)
LD B,A
; dump ch of found $ in reverse video
INREVID:
LD A,(HL)
INC HL
CALL PUTC ; In rev vid
DJNZ INREVID
; stop hilite of found $
CALL OFFHILITE
CALL Z,USEALT
XOR A
LD (FOUND),A ; Took care of that match
PUSH HL ; Save buffer ptr
CALL FINDAGAIN ; Look for next occur of find$
POP HL ; Buffer ptr
POP BC ; Line ctr
JR PUTNEXT
; dump non-find $ chars
PUT1NEXT:
LD A,(HL) ; Get char
INC HL ; *char++
AND 7FH ; Mask in case ws doc
CP LF
JR Z,FOUNDLF
CP EOF ; Is it eof?
JR Z,HITEOF
; all truncation logic removed to putc:
SENDCH: CALL PUTC
JR PUTNEXT
FOUNDLF:
DJNZ SENDCH ; Line ctr--
LD (CURRLINE),HL ; *current line lf
LD A,(LINEBYLINE)
OR A ; Going line by line?
JR Z,GETCMD ; No
LD A,CR ; Else, don't put pg #
CALL PUTC
JR GET1
HITEOF: DEC HL ; Back up to prev lf
LD (CURRLINE),HL
SAYEOF: LD A,(INCOMPLETE)
OR A
JR Z,REALEOF
CALL WARNING ; Too big to fit
JR GETCMD
REALEOF:
CALL MSG
DB CR,LF,'*** End of File ***',0
; (Second half, QL.002 follows....)
;..............................................................................