home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
beehive
/
zcat
/
bishow32.lbr
/
BISHOW32.AZM
/
BISHOW32.ASM
Wrap
Assembly Source File
|
1991-01-30
|
50KB
|
2,059 lines
; BISHOW v3.20 - buffered bidirectional file scroll utility
;
; Ver 3.20, 4 Aug 86, Kenji Nakadegawa, FOG #33 415-655-1206 300/1200
; - added printer toggle plus ability to send LF and FF to printer
; - removed ^H and ^L for moving text sideways (needed ^L for LF)
; - took out some of the many commands for next page (^F now is FF)
; - new commands: "^P" toggles printer, "A" show same screen again,
; "^L" sends LF to printer, "^F" sends FF to printer. The A,
; ^L, and ^F commands only work when printer is toggled on.
;
;-----------------------------------------------------------------------
;
; BISHOW is a buffered, bidirectional version of SHOW.ASM which first
; appeared in Interface Age, November, 1981. That program could only
; scroll forward in a file, and read records from disk one at a time as
; they were sent to the console. I used SHOW frequently to take a quick
; look at a file without loading a big text editor and to examine another
; file with the RUN command while in Wordstar. TYPE does not work as
; it is not a file that Wordstar can load and run.
;
; It was annoying when I went past the point I was looking for in a file
; with SHOW, and could not go backwards. Thus, this bidirectional ver-
; sion which uses random access reads. In addition, buffering was added
; so the number of disk reads would be reduced and moving back and forth
; in a moderate-sized file would be speeded up. There is a trade-off
; between the size of the buffer and the length of time it takes to re-
; fill the buffer which should be set to the user's preference.
;
; There are several customizing items in this program. One is the equate
; "MAXREC" which sets the buffer size. Another is the string in the sub-
; routine "CLRSCR" just after the ORG statement. This should be changed
; to erase the screen and home the cursor for the user's terminal. The
; program requires a terminal with an erase screen and home cursor func-
; tion. Some terminals do not allow the 80th column to be filled with-
; out going to the next line. For this reason, the screen width
; ("MAXCHR") initially is set to 79. The screen sizes can be changed
; using the "S" (screen) command. The parameters that can be changed
; are the maximum column displayed ("MAXCHR"), the minimum column dis-
; played (allowing you to "window" the output) and the number of lines
; ("SCROLN"). A zero for the maximum column displayed will give an un-
; limited screen width. The maximum column displayed and the number of
; lines can be set when calling BISHOW i.e., "BISHOW FILENAME.DOC 79 24"
; will give 79 columns and 24 lines, and "BISHOW FILENAME.DOC 79" will
; give 79 columns with the default number of lines. The last customizing
; item is the "short" equate. If this is chosen the multiplicity of com-
; mand forms is not allowed (see the beginning to change the commands
; used), and certain messages are shortened. This will allow BISHOW to
; fit into a 1K area. If "short" is NO the program is slightly over 1K.
; Finally, direct I/O to the console is used to avoid echoing the com-
; mands to the console as the CP/M write console function does.
;
; Just a small contribution to the public domain software as partial pay-
; ment for the many fine and educational programs the system has given
;
; - Phil Cary
;
;-----------------------------------------------------------------------
; previous changes
;
; Ver 3.01, 15 Jan 84, Frans van Duinen, Toronto, Ont
; - made unsqueeze message optional
; - added library capability
; - fixed bug in conditional assembly of CLRSCR
;
; Ver 2.09, 7 Jan 84, Frans van Duinen, Toronto, Ont
; - modified USQ routines for higher speed (+10%) and less memory
; usage.
; - made USQ code optional through conditional assembly
; - fixed a bug introduced with 2.08 and SHORT=YES (resulted from
; ASM's inability to nest IF/ENDIF)
; - fixed a bug that reset FCBEX after open, whenever record 0
; was read, (this resulted in BDOS assuming that the current
; extent, whose allocation group nos were still in the FCB,
; was the correct one.
; - changed exit to clear screen only on Q or ^C exit, to leave
; any messages visible
; - made wait after clear screen a conditional assembly option
;
; Ver 2.08, 2 Jan 84, Frans van Duinen, Toronto, Ont
; - added squeezed file capability
; - added sidewise scrolling on ^I, ^L, steps of 8
; - Osborne support for cursor keys, clr scr & scr size
; - Changed FILBAK rtn to recognize top of file
; - Set up flag to avoid unnecessary re-reading of
; top of file
;
; The unsqueeze code was lifted from the USQ base code by Dave
; Rand (Edmonton, Alberta) as adapted for LTYPE1 by S.Kluger. The
; code was lifted to allow continued use of ASM.COM.
;
; Ver 1.07, 1 Aug 83, Ted H. Emigh
; - added screen width specification
; - added screen definition commands (see notes below)
;
; Ver 1.06, 2 Jul 83, Chuck Forsberg
; - added commands for more, mince, vi familiarity. Bad cmd
; gives help
;
; Ver 1.051, 26 June 83, Dick Mead
; - added "?" for help on commands.
;
; Ver 1.05, 31 May 83, Bruce Ratoff
; - added 'N' (next line) and 'P' (previous line) cmds
; - decreased buffer from 8k to 4k (8k takes too long)
;
; Ver 1.04, 15 May 83, Keith Petersen, W8SDZ
; - fixed bug which caused display past end-of-file and added
; bogus EOF in case none at file end
; - added strip of high-order bit in line count routine
; - added exit clear of any left-over keyboard character
;
; Ver 1.03, 11 May 83, Keith Petersen, W8SDZ
; - fixed to allow assembly with ASM.COM
; - fixed screen clear bug when crossing read boundries
; - added strip for high-order bit in character before printing
; (needed for WordStar files)
; - improved stack routines
; - fixed bug in console input routine
; - removed Z80 dependant code (now works on 8080 too)
;
; Ver 1.02, 06 May 83, Lucien Pan, Toronto, Canada
; - fixed some minor bugs
; - returns to ccp w/o warm boot
; - filters form-feeds (useful in .PRN files)
; - scrolls foward/backwards by same number of lines
; - disable/enable cursor during scroll for H-19
;
; Ver 1.01, 30 Mar 83 - added BDOS function 6. W.F.Mcgee
;
; Ver 1.00, 23 Aug 82 Phil Cary, 748 Kenilworth Parkway, Baton Rouge, LA
;
;-----------------------------------------------------------------------
; Equates
;
VERS EQU 3 ; Note current use in DB constrains VERS &
REVS EQU 20 ; REVS to be one and two digits respectively
;
NO EQU 0
YES EQU NOT NO
;
HEATH EQU NO ; Assemble for H-19 terminal
OSBORNE EQU NO ; Assemble for Osborne I
SHORT EQU NO ; Set to YES if you want the short
; Version which is less than 1K
; Requires also that SQUEEZE is set false
SQUEEZE EQU YES ; Generate code to handle squeezed files
NOWAIT EQU YES ; Do not wait after clear screen
SILENT EQU YES ; No "unsqueezing text" msg
LIBRARY EQU YES ; Optional handling of library type files
;
;
;Operational equates
;
MAXREC EQU 32 ; Number of records in buffer
SQSIGN EQU 0FF76H ; Signature for SQ files
LBSIGN EQU 2000H ; Signature for library files
DLE EQU 090H ; Char flag for run compression (SQ)
;
IF NOT OSBORNE
SCROLN EQU 24 ; Number of lines per scroll
PSCRLN EQU 12 ; Opt. short scroll for print mode
MAXCHR EQU 79 ; Number of characters per line
ARWLFT EQU 08H ; Cursor left key (backspace)
ARWRT EQU 09H ; Cursor right key (tab)
ENDIF
;
IF OSBORNE
SCROLN EQU 24 ; Number of lines per scroll
MAXCHR EQU 51 ; Number of characters per line
PSCRLN EQU 12 ; Opt. short scroll for print mode
ARWLFT EQU 08H ; Cursor left key (backspace)
ARWUP EQU 0BH ; Cursor up key (vert tab)
ARWRT EQU 0CH ; Cursor right key (formfeed)
ENDIF
;
;
; BDOS functions
;
CONOUT EQU 2 ; Console write
LSTOUT EQU 5 ; List output
OPEN EQU 15 ; Open file
CLOSE EQU 16 ; Close file
READR EQU 33 ; Read file random access
STDMA EQU 26 ; Set dma address
;
;
; Page zero equates
;
WBOOT EQU 0000H ; Warm boot entry point
BDOS EQU 0005H ; BDOS entry point
FCB EQU 005CH ; Default fcb drive number
CMDTAIL EQU 0080H ; Location of command tail
FCBFN EQU FCB+1 ; Start of filename
FCBFT EQU FCB+9 ; Start of filetype
FCBEX EQU FCB+12 ; Current extent number
FCBCRR EQU FCB+33 ; Current record number, random access
TPA EQU 0100H ; Transient program area
;
;
; ASCII equates
;
ENDMSG EQU 0 ; Null
BELL EQU 7 ; Bell
BS EQU 8 ; Backspace
TAB EQU 9 ; Tab
LF EQU 0AH ; Line feed
FF EQU 0CH ; Form feed
CR EQU 0DH ; Carriage return
EOF EQU 1AH ; End of file
ESC EQU 1BH ; Escape
SPACE EQU 20H ; Space
;
;
; Equates for the short version
;
; Any invalid command gives help in addition to quit, ^C ends the pro-
; gram. Be sure to change the HELP2 printout.
;
NXTPAG EQU SPACE ; Next page
BACK EQU 'B' ; Scroll backward
NEXT EQU CR ; Next line
PREV EQU '-' ; Previous line
SCREEN EQU 'S' ; Set screen parameters
QUIT EQU 'Q' ; Exit bishow
FIRST EQU '1' ; First page
;
;
ORG TPA
;
JP START ; Skip over next subroutine
;
;
CLRSCR: CALL CDISP ; Erase screen and home cursor
;
IF NOT (HEATH OR OSBORNE)
DB ESC,'*',ENDMSG ; Put your screen clear string here
ENDIF
;
IF HEATH
DB ESC,'E',ENDMSG ; For H/Z-19 terminal
ENDIF
;
IF OSBORNE
DB 1AH,ENDMSG ; For Osborne and Televideo
ENDIF
;
IF NOT NOWAIT
WAIT: MVI B,0 ; Waste time
;
WAIT1: XTHL ; Good time gobbler!
XTHL
DCR B
JNZ WAIT1
ENDIF
;
RET ; Return from clrscr
;.....
;
;
HELP2: CALL CDISP
DB CR,LF,'Commands:',CR,LF
;
IF NOT SHORT
DB 'sp,F,^V=next page, ^B,B=back page, '
; DB '^H=left, ^L=rite' ;needed the ^L for LF to printer
DB 'CR,+,N=next line '
DB CR,LF
DB '-,P=back line, 1=1st line, ^C,Q=exit, S=set screen size'
DB CR,LF
DB '^P toggles printer (^L=LF ^F=FF A=same page again)'
DB CR,LF,ENDMSG
ENDIF
;
IF SHORT
DB 'sp=next page, B=back page',CR,LF
DB 'CR=next line, '
DB '-=back line, 1=1st line, ^C,Q=exit',CR,LF,ENDMSG
ENDIF
;
JMP GETCMD
;.....
;
;
START: LXI H,0 ; Get CCP's stack return
DAD SP
SHLD STACK ; Save old stack for later
LXI SP,STACK ; Set new stack
LXI H,CMDTAIL ; Point to command tail
MOV B,M ; Get number of char in tail
INX H ; Point to first character
INR B
CALL EATSP ; Step to next non-bl in input
JZ OPENF ; No more characters
CALL FILNAM ; Skip file name, returns <B>=0 or <A>=20H
JZ OPENF ; Only file name in tail
;
;
; Check if there is a member name
;
CALL EATSP ; Step to next non-bl in input
JZ OPENF ; No more characters
CPI '9'+1 ; Numeric?
JNC MEMB ; No -
CPI '0'
JNC NUMBER ; Yes - must be width & heigth
;
;
; Have member name (at FCB+11H)
;
MEMB:
STA MEMNAM ; No - have member name
PUSH H ; Posn in command line
PUSH B ; # of chars remaining
LXI H,FCB+11H ; Source
LXI D,MEMFCB+1 ; Destination
MVI B,11 ; Move name + type
CALL MOVE
;
;
; Add .LBR suffix if required
;
LXI H,FCB+9 ; Is there a suffix
MOV A,M
CPI SPACE
JNZ NUMBR2 ; Yes - leave
MVI M,'L'
INX H
MVI M,'B'
INX H
MVI M,'R'
;
NUMBR2: POP B
POP H
CALL FILNAM ; Skip member name, returns <B>=0 or <A>=20H
JZ OPENF ; End
;
;
; Handle screen width & height
;
NUMBER:
LXI D,CHRMAX ; Point to chr/line
CALL GETNBR ; Get number of characters/line
JC HELP ; Invalid number
LXI D,LINMAX ; Point to number of lines
CNZ GETNBR ; Call only if characters still in
; command tail
JC HELP ; Invalid number
;
OPENF: CALL OPNFIL ; Open file in default fcb
;
IF SQUEEZE
CALL CHKSQ ; Check for squeezed, init if
; returns first word in file in <HL>
ENDIF
;
IF LIBRARY
CALL CLRSCR ; Erase the screen
CALL FILBF0 ; Fill the disk buffer with start of file
CALL CHKLB ; Check for library file
JMP WRTFW0 ; Buffer contains top records
ENDIF
;
WRTFWD: CALL CLRSCR ; Erase the screen
CALL FILBF0 ; Fill the disk buffer with start of file
;
WRTFW0: LXI H,DSKBUF ; Point to beginning of buffer
;
WRTFW1: MOV A,M ; Get a character
CPI EOF ; See if eof
JZ GETCMD ; Yes, wait for command
INX H ; Bump pointer
ANI 7FH ; Strip high bit
CPI 'L'-40H ; Filter form-feeds
JZ FILTER ; __commonly found in .PRN files
CALL CO1 ; Put it on console
CPI CR ; See if end of line
JZ FWDCNT ; Yes, adjust line count
;
WRTFW2: LXI D,ENDBUF ; Get end of buffer address
CALL CMPHLDE ; Is HL> gt DE> (end of buff)
;
;
; Note test is LT now, not NE
;
JC WRTFW1 ; Continue with next character
CALL FILBUF ; Fill the disk buffer with next records
JMP WRTFW0 ; Start over
;
HELP: CALL CDISP
DB 'BISHOW version '
DB (VERS MOD 10)+'0','.'
DB REVS/10+'0',(REVS MOD 10)+'0',CR,LF
DB 'Usage: d:bishow d:fn.ft '
;
IF LIBRARY
DB '[member] '
ENDIF
;
DB '[cols [lines]]',CR,LF
DB ENDMSG
JMP EXIT1
;
FILTER: PUSH PSW ; Save status
MVI A,'^' ; Print '^' in front
CALL CO1 ; __of control character
POP PSW ; Restore status
ADI 40H ; Mask into displayable char
CALL CO1 ; Display filtered control char
;
FWDCNT: LDA LINCNT ; Get number of lines displayed
INR A ; Bump it
STA LINCNT ; __and store it
MOV D,A ; Save lincnt
LDA LINMAX ; Get max number of line
CMP D ; Compare with line count
JNZ WRTFW2 ; If not there, continue, else get command
XRA A ; Zero the line count
STA LINCNT
;
GETCMD: PUSH H
PUSH D
PUSH B
;
IF HEATH
CALL CDISP
DB ESC,'x5',ENDMSG ; Disable cursor
ENDIF
;
GETCM1: CALL GETIN ; Get input char if any
ORA A ; Loop till char avail
JZ GETCM1
POP B
POP D
POP H
;
UPRET: CPI 'a' ; Added return from UNPRNT: (vers 3.2)
JC GETCM2 ; Change command to
CPI 'z'+1 ; Upper case
JNC GETCM2
XRI 20H ; Is lower case, make upper case
;
GETCM2: IF NOT SHORT
CPI '1' ; 1 means goto 1st line
JZ WRTTOP ; Test if top in buffer
CPI '?' ; Help request
JZ HELP2
CPI ' ' ; More use space
JZ WRTFW1
CPI 'F' ; Scroll forward?
JZ WRTFW1 ; Br if yes
;;see CPI 'F'-40H ;[vi uses ^F] STOLE ^F for the
;;below JZ WRTFW1 ;form feed routine below
CPI 'V'-40H ; Mince uses ^V
JZ WRTFW1
CPI 'B' ; Scroll backward?
JZ WRTBAK
CPI 'B'-40H ; Vi uses ^B
JZ WRTBAK
CPI 'N' ; Scroll next line?
JZ WRTNXT
CPI '+'
JZ WRTNXT
CPI CR ; Scroll next line?
JZ WRTNXT
CPI LF
JZ WRTNXT
CPI 'P' ; Scroll prev line?
JZ WRTPRV
;
;
; Added command codes to check
;
; 'A' to print the same screen again (only in print mode)
;
CPI 'A' ; Rewrite screen
JZ WRTAGN ; Exists to rewrite screen after adjust.
;
;
; '^L' to send LF to printer (only in print mode)
;
CPI 'L'-40H ; ^L for linefeed
JZ PLF
;
;
; '^F' to send form feed to printer (only in print mode)
; Stole '^F' from scroll forward
;
CPI 'F'-40H ; ^F for formfeed
JZ PFF
;
;
; ^P to toggle print on or off
;
CPI 'P'-40H ; Print toggle
JZ PTOGL
ENDIF
;
IF OSBORNE AND NOT SHORT
CPI ARWUP ; Cursor up?
JZ WRTPRV
ENDIF
;
IF NOT SHORT
CPI '-'
JZ WRTPRV
CPI 'C'-40H ; Must be exit
JZ EXITCL ; Return control to CCP if yes or
CPI 'Q' ; More use q for quit
JZ EXITCL
CPI 'S' ; Set screen parameters
JZ SETSCR
;
;
; Removed response to ^H and ^L for screen control
;
;; CPI ARWLFT ;Cursor left?
;; JZ ADJMM
;; CPI ARWRT ;Cursor right?
;; JZ ADJMM
;
; End of cut
;
JMP HELP2 ; Else give a hint
ENDIF
;
IF SHORT
CPI FIRST ; 1 means goto 1st line
JZ WRTTOP
CPI NXTPAG ; Scroll forward?
JZ WRTFW1 ; Br if yes
CPI BACK ; Scroll backward?
JZ WRTBAK
CPI NEXT ; Scroll next line?
JZ WRTNXT
CPI PREV ; Scroll prev line?
JZ WRTPRV
CPI 'C'-40H ; Must be exit
JZ EXITCL ; Return control to CCP if yes or
CPI QUIT ; Alternative quit
JZ EXITCL
CPI SCREEN ; Set screen parameters
JZ SETSCR
JMP HELP2 ; Else give a hint
ENDIF
;
;
;
; Added routine to toggle printer
;
; New routine added for printing version
;
IF NOT SHORT
PTOGL: LDA PFLG ; Get print flag
ORA A ; Test 00=off
JZ PTOGL1
MVI A,0 ; Make 00 if it wasn't
STA PFLG ; Store new PFLG
CALL CDISP
DB '>>>> print toggle OFF <<<<'
DB ENDMSG
JMP UNPRNT
;
PTOGL1: MVI A,0FFH ; Move FFh to A
STA PFLG ; Store new PFLG
CALL CDISP
DB '>>>> print toggle _ON_ <<<'
DB ENDMSG
JMP UNPRNT
;
;
; Routine to send CR or LF to LST:
;
PFF: LDA PFLG
ORA A
JZ PCC1
CALL CDISP
DB '>> sending FF to printer <'
DB ENDMSG
MVI E,0FFH ; Routine to send FF
JMP PCC
;
PLF: LDA PFLG
ORA A
JZ PCC1
CALL CDISP
DB '>> sending LF to printer <'
DB ENDMSG
MVI E,LF ; LF to LST: device
;
PCC: PUSH B ; Save all registers
PUSH D
PUSH H
PUSH PSW
MVI C,LSTOUT
CALL BDOS
POP PSW ; Restore all registers afte BDOS call
POP H
POP D
POP B
JMP UNPRNT
;
PCC1: JMP GETCMD
;
UNPRNT: PUSH H ; Clear printer msg. from console
PUSH D ; Save regs. for BDOS call in GETIN
PUSH B
;
UNPRT1: CALL GETIN
ORA A
JZ UNPRT1 ; Wait for CMD input
POP B ; Restore regs.
POP D
POP H
PUSH PSW ; Save char on stack
CALL CDISP ; Backspace over msg on console
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB ENDMSG
POP PSW ; Return char to A
JMP UPRET ; Re-enter GETCMD routine
;.....
;
;
; New routine to reprint screen in printer mode
;
WRTAGN: LDA PFLG
ORA A
JZ GETCMD ; Toggle off-get next CMD
JMP WRTSAM ; Toggle on-show same screen again
ENDIF
;.....
;
;
; Go to top of file
;
WRTTOP: LDA TOPBUF ; Get top in buffer flag
ORA A
JNZ WRTFWD ; No - the hard way
CALL CLRSCR ; Erase the screen
;
WRTTO1: XRA A
STA LINCNT ; Clear lines put so far
JMP WRTFW0 ; Buffer contains top records
;.....
;
;
; Write one more line
;
WRTNXT: LDA LINMAX
DCR A ; Fool WRTFW1 to only write one line
STA LINCNT
JMP WRTFW1
;.....
;
;
; Back up one line
;
WRTPRV: LDA LINMAX ; Back up one screen + 1 line
INR A
JMP WRTBK0
;.....
;
;
; Back up full screen
;
WRTBAK: LDA LINMAX ; Get screen line count
ADD A ; multiply by 2
;
WRTBK0: INR A ; and add 1
STA LINCNT ; to backup to previous page
CALL CLRSCR ; Clear the screen
;
WRTBK1: LXI D,DSKBUF ; Get address of start of buffer start
CALL CMPHLDE ; Is HL> LT DE> (start of buff)
JC FILBAK ; Go refill buffer
;
WRTBK2: MOV A,M ; Get a character
ANI 7FH ; Strip high bit
DCX H ; Decrement buffer
CPI CR ; See if end of line
JZ BAKCNT ; or form-feed
CPI 'L'-40H ; and adjust line count if so
JNZ WRTBK1 ; Else, loop if not
;
BAKCNT: LDA LINCNT ; Else, get number of lines to move back
DCR A ; and decrement it
STA LINCNT ; store it
JNZ WRTBK1 ; and loop if not there
INX H ; Else bump pointer
INX H ; to account for DCX
JMP WRTFW1 ; And go write a screen
;.....
;
;
; Test for top of file
;
FILBAK: LDA TOPBUF ; Get top in buffer flag
ORA A
JZ WRTTO1 ; Yes - start of file in buffer
;
;
; Start of file not in buffer, step back
;
LHLD SECCNT ; Get no of records last read
LXI D,MAXREC ; Get the buffer size
DAD D ; Add them
XCHG ; and put them in DE
LDA FCBCRR ; Subtract low order byte
SUB E ; from current record count
STA FCBCRR ; and store in current record count
LDA FCBCRR+1 ; Same with high order byte
SBB D ; but with borrow
JM WRTFWD ; If beyond beginning of file, start over
STA FCBCRR+1 ; Else, store high order byte
CALL FILBUF ; Fill the buffer
LXI H,ENDBUF ; and point to end of buffer
CALL CLRSCR ; Clear the screen
JMP WRTBK2 ; Continue moving back in file
;.....
;
;
; Fill buffer with top of file
;
FILBF0: XRA A ; Get a 0
STA LINCNT ; Store in line count
STA CHRCNT ; Store in character count
; Do not reset the current extent - BDOS
; will switch extents only if the no
; specified ( <FCBEX> ) does NOT agree
; with the wanted no <FCBCRR>.
STA FCBCRR ; Reset to record zero
;
IF NOT LIBRARY
STA FCBCRR+1 ;
STA FCBCRR+2 ; __and clear the overflow
ENDIF
;
IF LIBRARY
LHLD SCZERO ; Set to record zero for file/member
SHLD FCBCRR
ENDIF
;
;
; Fill buffer from spec'd record FILBUF:
;
FILBUF: MVI B,MAXREC ; Number of records to resd
;
FILB1S: IF LIBRARY
LHLD SCZERO ; Get top record for member
XCHG
LHLD FCBCRR ; Is this top of file?
CALL CMPHLDE ; This it? (<A>=0 if equal)
ENDIF
;
IF NOT LIBRARY
LHLD FCBCRR ; Is this top of file?
MOV A,H
ORA L
ENDIF
;
STA TOPBUF ; Set top of file in buffer flag
LXI D,DSKBUF ; Load start of disk buffer
LXI H,0 ; Zero out the
SHLD SECCNT ; number of records in buffer
; ; Z - top, NZ - not top
IF SQUEEZE
LDA SQFLG ; Is this a squeezed file
ORA A
JNZ FILSQ ; Yes -
ENDIF
;
FILBU1: PUSH H ; Save all registers
PUSH D
PUSH B
MVI C,STDMA ; Set DMA to disk buffer
CALL BDOS
LXI D,FCB ; Set up to read a record
MVI C,READR
CALL BDOS ; Do it
ORA A ; Read OK?
LHLD FCBCRR ; Get current record number
INX H ; Bump it
SHLD FCBCRR ; Save it
LHLD SECCNT ; Get records in buffer
INX H ; Bump it
SHLD SECCNT ; Store it
POP B
POP D
POP H
JNZ RDERR ; No, last record read
;
IF LIBRARY
PUSH D ; Save record buffer pointer
LHLD FCBCRR ; Get current record number
XCHG
LHLD SCLAST ; & get last record for member (or FFFF)
CALL CMPHLDE ; Are we within member
POP D
JC RDERR ; No, last record read
ENDIF
;
DCR B ; Decrement it
RZ ; If done return
LXI H,128 ; Else, add 128 to
DAD D ; __dma address
XCHG ; Put it in de
JMP FILBU1 ; Read another record
;.....
;
;
; Fill buffer from squeezed file - this routine handles mapping from
; UNSQ record # to record, byte & bit in SQ stream on input FCBCRR con-
; tains wanted record no, ( no allowance made for records # over 65535)
; <B> contains no of records wanted, DE> buffer where records wanted,
; ignored in this version, always full DSKBUF
;
IF SQUEEZE
FILSQ: LHLD FCBCRR ; Get # for 1st record wanted
XCHG
PUSH D ; Save to restore after unsq
LHLD NXTSEC ; & 1st record after buffered ones
CALL CMPHLDE ; Consecutive?
JZ USQNXT ; Yes - fine
JNC USQBAK ; No - lower
;
;
; Next record after latest but not consececutive
;
CALL CDISP
DB CR,LF,'Program failure, non-contiguous records requested'
DB CR,LF,'from unsqueeze rtn',CR,LF,0
JMP EXIT ; Should never happen
;
USQBAK: ENDIF
;
IF SQUEEZE AND LIBRARY
LHLD SCZERO ; Get 1st record for member
CALL CMPHLDE ; All the way back to start?
ENDIF
;
IF SQUEEZE AND NOT LIBRARY
MOV A,D ; All the way?
ORA E
ENDIF
;
IF SQUEEZE
JNZ USQNO1 ; No - MUST be prev!!!
LXI H,SQMAP+2+8 ; Yes - reset SQMAP index to #3
SHLD SQMAP
;
USQNO1: LHLD SQMAP ; Get index into mapping table
LXI D,-8 ; Step back from next, past current to prev
DAD D
SHLD SQMAP ; & save updated index for next
MOV E,M ; Get SQ record no
INX H
MOV D,M
INX H
MOV C,M ; Get byte offset
INX H
MOV A,M ; & bit offset
STA BITLFT
XRA A
STA RCNT ; No runs in progress
STA SQBYT+1 ; Set offset 1st data byte
MOV A,C
STA SQBYT ; For now offset within record only
LHLD SQBSC1 ; Get no of first SQ record now in buffer
XCHG ; <HL> wanted 1st record, <DE> actual 1st
CALL CMPHLDE ; Is 1st buffer record low/equal 1st data sect?
JNC USQ1OK ; Yes - first wanted record SQ in buffer
; Max header 1035 bytes + file name)
;
; Force reload of SQ buffer
;
SHLD NXTSQS ; No - 1st data record b/4 1st buffer sect
MVI A,1 ; Set rewind with I/O
STA SQREWD ; Set rewind flag
; SQBYT contains offset of 1st data byte
XRA A
STA SQEOF ; Reset end of file on SQ
; Leave current extent alone. This is
; how BDOS knows how to switch extents.
STA FCBCRR+2 ; & count overflow, should not be necessary
MOV D,A
JMP USQNX1 ; Go adj buffer pointer
;...
;
;
; <DE> # of 1st record in SQ buf
; <HL> # of wanted SQ record
; (Max 100H SQ records in buffer)
;
USQ1OK: MOV A,L
SUB E
RAR ; Convert to pages (100H)
MOV D,A
MVI A,0 ; Do not disturb Cy
RAR ; Pu carry (now 80H or 00H)
;
USQNX1: MOV E,A
LHLD SQBYT ; Get offset of 1st data byte in wanted sect
DAD D ; --> offset in buffer
LXI D,SQBUF
DAD D ; Convert to absolute addr
SHLD INBUFS ; & set as next byte to unsqueeze
;
USQNXT: LHLD NXTSQS ; Get no of next SQ record
SHLD FCBCRR
LHLD INBUFS ; Calc offset in buffer
LXI D,-SQBUF
DAD D
MOV C,L ; Keep offset within record
LDA BITLFT ; Get bit offset
MOV B,A
ORA A ; On byte boundary?
MOV A,C
JNZ NOTBBY ; No -
INR A ; Yes - no adj reqd
;
NOTBBY: ANI 7FH ; Ensure record relative
DAD H ; Convert to record no
ORA A ; Is next byte at start of sect?
JNZ SECTOK
DCR H ; Yes - step back one record
;
SECTOK: DCR A
ANI 7FH ; & adj byte index
MOV E,H
MVI D,0
LHLD SQBSC1 ; # of 1st record in buffer
DAD D
XCHG ; <D> absolute SQ record no
LHLD SQMAP ; Get index
MOV M,E ; Save abs SQ record no
INX H
MOV M,D
INX H
MOV M,A ; Save record relative byte offset
INX H
MOV M,B ; Save bitlft
INX H
SHLD SQMAP ; Save new index
ENDIF
;
IF SQUEEZE AND NOT SILENT
CALL CDISP ; Show msg where is
DB '>>> Unsqueezing text <<<',ENDMSG
ENDIF
;
CALL FILUSQ ; Fill unsq buffer
;
IF SQUEEZE AND NOT SILENT
CALL CDISP ; Remove msg just displayed, assumes
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB ' '
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS
DB BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,BS,0
ENDIF
;
IF SQUEEZE
LHLD FCBCRR ; Get no of next SQ record
SHLD NXTSQS
LHLD NXTADR ; Calc # of unsq records in buf
LXI D,-DSKBUF ; (as neg no)
DAD D ; Calc length
DAD H ; & convert to records in <H>
MOV L,H
MVI H,0
SHLD SECCNT ; Save # of records in DSKBUF
POP D ; Get FCBCRR as passed by calling rtn
DAD D ; & calc new one
SHLD FCBCRR
SHLD NXTSEC
RET
ENDIF
;.....
;
;
; We only get here if end of file
;
RDERR: MVI A,EOF ; Get bogus eof
STAX D ; Save at buffer end in case no eof in file
XRA A ; Get a zero to direct start of buffer
RET
;
OPNFIL: LDA FCBFN ; Point to first letter of filename
CPI ' ' ; Anything there?
JZ HELP ; No, give help message
XRA A ; Get a 0
STA FCBEX ; Zero current extent
LXI D,FCB ; File name in default fcb
MVI C,OPEN ; Set up to open
CALL BDOS ; Do it
INR A ; Open OK?
RNZ ; Yes
CALL CDISP ; Else, give error msg and quit
DB 'file not found ',ENDMSG
JMP EXIT1 ; Leave msg on screen on exit
;
GETNBR: MOV A,M ; Get first digit
INX H
DCR B ; B=number of characters left in buffer
RZ ; No digit
CPI SPACE
JZ GETNBR ; Wait until next non-space
PUSH D ; Save location to save number
MVI D,0 ; Initialize number
;
GNUM1: SUI 30H ; Change ASCII to number
JC INVNUM ; Not a number
CPI 10
CMC
JC INVNUM ; Not a number
PUSH PSW ; Save number
MOV A,D ; Multiply old number by 10
ADD A ; *2
ADD A ; *4
ADD A ; *8
ADD D ; *9
ADD D ; *10
MOV D,A
POP PSW ; Restore new digit
ADD D
MOV D,A
MOV A,M ; Get next digit
INX H
DCR B
JZ ENDNUM ; End of number
CPI SPACE
JNZ GNUM1
;
ENDNUM: MOV A,D ; Save number
DCR A ; Correct number for co routines
XCHG ; Set to restore save location
POP H ; Restore save location
MOV M,A ; Save digit
XCHG ; Put buffer location where it belongs
MOV A,B ; See if any characters left in buffer
ORA A ; Zero if no characters in buffer
RET
;.....
;
;
INVNUM: POP D ; Correct stack
RET
;.....
;
;
ASCIIN: MVI B,100 ; Divide by 100, then change
CALL DIVIDE ; __digit to ASCII and store at hl
MVI B,10 ; Divide by 10, then change
CALL DIVIDE ; __digit to ASCII and store at hl+1
MVI B,30H ; Change ones place number
ADD B ; __to ASCII and store at hl+2
MOV M,A
;
IF NOT (SHORT AND HEATH)
DCX H ; Delete leading zeroes
DCX H ; __in the number
MVI C,SPACE ; __and replace with spaces
MOV A,B
CMP M ; Check first digit for '0'
JNZ CDISP ; Not zero
MOV M,C ; Replace with space
INX H
CMP M ; Check second digit for '0'
JNZ CDISP ; Not zero
MOV M,C ; Replace with space
ENDIF
IF NOT SHORT
;
;
; This is the modified CHAR and STRING out routine
;
CDISP: XTHL ; Exchange top of stack and HL
;
CDIS1: MOV A,M ; HL now pointing to db message
ORA A ; See if 0 at end of message
INX H
JZ CDIS2 ; Yes, restore stack and return
;
;
; Moved routine here to avoid printing strings on the printer
;
PUSH B ; Save the registers
PUSH D
PUSH H
PUSH PSW
MOV E,A ; Set up character
MVI C,CONOUT
CALL BDOS ; Do it
POP PSW ; Restore the registers
POP H
POP D
POP B
JMP CDIS1
;
CDIS2: XTHL ; Get return address on top of stack
RET
;.....
;
;
; Regular character output routine
;
CO: PUSH B ; Save the registers
PUSH D
PUSH H
;
CO2: PUSH PSW
MOV E,A ; Set up character
MVI C,CONOUT
CALL BDOS
;
;
; Added print routine version
;
PFTRY: LDA PFLG ; Get PFLG
ORA A ; Test 00=off 0FFh=on
JZ PCONT ; If 00 continue without LST:
POP PSW ; Recover char in A
PUSH PSW ; Save it again
MOV E,A ; Set up for LSTOUT
MVI C,LSTOUT ; BDOS function 5
CALL BDOS
;
;
; Return to original
;
PCONT: POP PSW ; Restore the registers
CO5: POP H
POP D
POP B
RET
ENDIF
;.....
;
;
IF SHORT
;; insert original DDISP-CO here
ENDIF
;
;
CO1: PUSH B ; Save the registers
PUSH D
PUSH H
MOV E,A
LXI H,CHRCNT ; Get address of character count
CPI CR ; See if end of line
JZ ENDLIN ; Update line information
CPI LF ; Ignore linefeed
JZ CO2
LDA CHRMAX ; Get maximum characters per line
CMP M ; See if too many char
JC CO5 ; Don't print character
MOV A,E ; Restore and print character
CPI TAB ; Fix chrcnt for tabs
JZ TABFIX
INR M ; Increment character count
LDA CHRMIN ; See if up to minimum display yet
CMP M
MOV A,E ; Restore character
JNC CO5 ; Do not display character
JMP CO2 ; Finally, display character
;
ENDLIN: MVI M,0 ; Reset character count
JMP CO2 ; Print cr
;
TABFIX: MVI A,08H ; Fix chrcnt for tabs
ADD M ; Increment to next 8-count
ANI 0F8H ; Make into multiple of 8
;
TAB2: SUB M ; Get number of space to go
MOV B,A
;
TAB1: MVI A,SPACE ; Expand tab
CALL CO1
DCR B
JNZ TAB1 ; Still more spaces
JMP CO5 ; Exit routine
;
SETSCR: PUSH H
PUSH D
PUSH B
;
GETMAX: LDA CHRMAX ; Get maximum number of characters
INR A
LXI H,HUNS
CALL ASCIIN ; Put ASCII number in message
;
IF NOT SHORT
DB CR,LF,'Maximum Column: '
ENDIF
;
IF SHORT
DB CR,LF,'Max Column: '
ENDIF
;
HUNS: DB 30H
DB 30H
DB 30H
DB ' New? ',ENDMSG
CALL GETINP ; Read input from console
LXI D,CHRMAX ; Set new chrmax in memory
CALL GETNBR
JC GETMAX ; If error, repeat last message
;
GETMIN: LDA CHRMIN ; Get minimum character display
INR A
LXI H,HUN
CALL ASCIIN ; Put ASCII number in message
;
IF NOT SHORT
DB LF,'Minimum Column: '
ENDIF
;
IF SHORT
DB LF,'Min Column: '
ENDIF
;
HUN: DB 30H
DB 30H
DB 30H
DB ' New? ',ENDMSG
CALL GETINP ; Read input from console
LXI D,CHRMIN ; Set new chrmax in memory
CALL GETNBR
JC GETMIN ; If error, repeat last message
;
GETLIN: LDA LINMAX ; Get number of lines per display
LXI H,HUND
CALL ASCIIN ; Put ASCII number in message
DB LF,'Lines Displayed: '
;
HUND: DB 30H
DB 30H
DB 30H
DB ' New? ',ENDMSG
CALL GETINP ; Read input from console
LXI D,LINMAX ; Set new chrmax in memory
CALL GETNBR
JC GETLIN ; If error, repeat last message
POP B
POP D
POP H
;
WRTSAM: LDA LINMAX ; Write the same screen
JMP WRTBK0
;
;
GETINP: MVI A,5 ; Get set to read new maximum column
STA CMDTAIL
MVI C,0AH
LXI D,CMDTAIL
CALL BDOS ; Get maximum column
LXI H,CMDTAIL+1 ; Now, change to ASCII
MOV B,M
INX H
INR B
RET ; Return with input in buffer
;
;
; Adjust character minimum/maximum on cursor left/right
;
IF NOT SHORT
ADJMM: PUSH H
CPI ARWLFT ; Move left (decrease)?
LDA CHRMAX ; What is last char on line t/b displ
MOV H,A
LDA CHRMIN ; & 1st char to display
MVI L,8 ; Scroll by 8
JZ ADJMMD ; Yes - adjust down
ADD L ; No - increase min, no limit
PUSH PSW
MOV A,L
ADD H ; & max
JMP ADJMMS
;
ADJMMD: SUB L ; Display more to the left
PUSH PSW
MOV A,H
SUB L
;
ADJMMS: MOV H,A ; <H> max
POP PSW ; <A> min
CMP H ; Wrap, (max< min)
JNC ADJMMX ; Yes - leave unchanged
STA CHRMIN
MOV A,H
STA CHRMAX
;
ADJMMX: POP H
JMP WRTSAM ; Go write same screen
ENDIF
;
DIVIDE: MVI C,'0'-1 ; Extract dividend of a div c
;
DIV1: INR C ; __and store in location pointed
SUB B ; __to by hl
JNC DIV1
ADD B
MOV M,C ; Save ASCII digit
INX H ; Bump pointer to next location
RET
;.....
;
;
; Clear screen only on register exit
;
EXITCL: CALL CLRSCR ; Clear the screen
;
EXIT: CALL GETIN ; Get any waiting characters
CALL GETIN ; And any possible second char
;
IF HEATH
CALL CDISP ; Re-enable cursor
DB ESC,'y5',ENDMSG
ENDIF
;
LXI D,FCB ; Close file
MVI C,CLOSE
CALL BDOS
;
EXIT1: LHLD STACK ; Get old stack
SPHL
RET ; Return to CCP
;.....
;
;
; Check for Library file
;
IF LIBRARY
CHKLB: XRA A
STA MEMFCB
STA LBFLG ; Clear library flag
LHLD DSKBUF ; Get 1st word in file
LXI D,LBSIGN ; Get expected value
CALL CMPHLDE
JZ ISLB
LDA MEMNAM ; Was member specified
ORA A
RZ ; No - ok
CALL CDISP
DB CR,LF,'File is not a library',CR,LF,0
JMP EXIT ; Get out to leave msg visible
;
ISLB: MVI A,1
STA LBFLG ; Yes - set library flag
LXI H,DSKBUF+14 ; Set to dir size (in records)
MOV A,M ; Assume <255 entries
RAL
RAL ; Convert # records to # entries
DCR A ; Less 1 for file descriptor
STA DIRSIZ ; Directory size in entries
MOV B,A ; Save no of entries for loop
LDA MEMNAM ; Do we have member name on command line?
ORA A
JNZ NODISP ; Yes
CALL CDISP ; Note protects <B>
DB CR,LF,'Library file, containing:',CR,LF,LF,0
;
NODISP: LXI H,DSKBUF+20H ; Set 1st member entry
;
;
; Loop through directory entries
;
DIRLP: PUSH B ; Save no of entries remaining
MOV A,M ; Get entry status
ORA A ; Deleted?
JNZ NYET ; Yes - skp to next
LDA MEMNAM ; Do we have member name on command line?
ORA A
JZ DISPM ; No - display all member names
MVI B,12 ; Length of names + 00H in front
LXI D,MEMFCB
CALL CPSTR ; Compare names
JZ FOUND
JMP NYET
;
DISPM: MVI B,11 ; Length of names
PUSH H
INX H ; Step to actual name
;
DSPMLP: MOV A,M
CALL CO ; Display one char
INX H
DCR B ; Reduce count remaining
JZ NMEND ; End of name
ENDIF
;
IF LIBRARY AND NOT OSBORNE
MOV A,B
CPI 3 ; Only 3 more?
JNZ DSPMLP ; No -
MVI A,'.' ; Yes - put out dot
CALL CO
ENDIF
;
IF LIBRARY
JMP DSPMLP ; Go for next char
;
;
;
; Displayed full name
;
NMEND: LXI H,NAMEXC ; Max no of names across sofar
MOV A,M
INX H ; Step to names across sofar
INR M ; Count current
CMP M ; Over max?
JNC NOTMAX ; Not yet
MVI M,0 ; Yes - reset
CALL CDISP
DB CR,LF,0
JMP NYET1
;
NOTMAX: CALL CDISP
ENDIF
;
IF LIBRARY AND NOT OSBORNE
DB ' '
ENDIF
;
IF LIBRARY
DB '| ',0
NYET1: POP H ; Reset to start of this entry
;
NYET: LXI B,20H ; Length of each entry
DAD B ; Step to next
POP B ; Get entry count (remaining)
DCR B
JNZ DIRLP ; More members
LDA MEMNAM ; Do we have member name on command line?
ORA A
JZ EXIT ; No - just get out after dsp directory
; in future may ask what member to display
CALL CDISP
DB CR,LF
DB 'Member file not found in LBR directory',CR,LF,0
JMP EXIT
;.....
;
;
; Found the member name
;
FOUND: POP B ; Clear stack
LXI D,12
DAD D
PUSH H ; Save pointer for now,
INX H ; Point to size
INX H
MOV A,M ; Get low byte
INX H
MOV H,M
MOV L,A
ORA H ; If a=0 then file is 0k
JZ NULLEN ; Go complain
XTHL ; Get pointer back, save size
MOV A,M ; Get file address
INX H
MOV H,M
MOV L,A
SHLD SCZERO ; Save as first file record
POP D ; & get size back
DAD D ; Convert to last record no (inclusive)
SHLD SCLAST
ENDIF
;
IF LIBRARY AND SQUEEZE
LDA SQFLG ; Get SQ flag in case of double squeeze
ORA A
JZ NOLBSQ ; Ok, library itself not squeezed
CALL CDISP
DB CR,LF,'Cannot display member in squeezed library',CR,LF,0
JMP EXIT
;
NOLBSQ: CALL CHKSQ ; Check if member squeezed
ENDIF
;
IF LIBRARY
CALL FILBF0 ; Refill buffer, now for member
RET
;.....
;
;
NULLEN: CALL CDISP
DB CR,LF,'Member is empty',CR,LF,0
JMP EXIT
ENDIF
;.....
;
;
; Get input if any
;
GETIN: MVI C,6 ; Direct console I/O
MVI E,0FFH
JMP BDOS ; Get char, exit via BDOS
;.....
;
;
; Compare strings HL> to DE> over <B>
; <DE> and <B> are changed, <HL> kept
;
CPSTR: PUSH H
;
CP$LP: LDAX D
CMP M
JNZ CP$EX ; No match
INX D
INX H
DCR B
JNZ CP$LP
;
CP$EX: POP H
RET
;.....
;
;
;Compare <HL> to <DE> Z - equal; C - <HL> less than <DE> if equal
; returns <A>=0
;
CMPHLDE:MOV A,H
SUB D
RNZ
MOV A,L
SUB E
RET
;....
;
;
; Skip blanks in input
;
EATSP: MOV A,M ; Get character if there is one
INX H
DCR B ; B=number of characters left
RZ ; No more characters
CPI SPACE ; Ignore spaces
JZ EATSP
DCX H ; Step back to 1st non-blank
INR B
ORA A ; Force NZ
RET
;.....
;
;
; Skip name in input
;
FILNAM: MOV A,M ; Get characters in file name
INX H
DCR B ; B=number of characters left
RZ ; Only file name in tail
CPI SPACE ; Wait for next space
JNZ FILNAM
ORA A ; Force NZ
RET ; Blank
;.....
;
;
; Move from HL> to DE> over <B>
;
MOVE: MOV A,M
STAX D
INX H ; Step to next source
INX D ; & destination
DCR B ; Reduce count (00=256)
JNZ MOVE
RET
;.....
;
;
;******************************************************
; USQ support code *
; 10/12/83 by Dave Rand *
;******************************************************
;
IF SQUEEZE
CHKSQ: XRA A
MOV L,A
MOV H,L ; Clear <hl>
STA SQFLG ; Make sure not set as squeezed yet
STA SQEOF ; End of file on SQ
STA SQREWD ; Clear "rewinding" SQ file
STA BITLFT ; Force init char read
STA RCNT ; And zero repeats
STA FCBCRR+2 ; And overflow
SHLD NUMVALS ; Clear # nodes
ENDIF
;
IF SQUEEZE AND LIBRARY
LHLD SCZERO ; Get 1st record for member
SHLD NXTSEC ; & save as next record
ENDIF
;
IF SQUEEZE
SHLD FCBCRR ; Clear next record
LXI H,SQBUF ; Set to input (squeezed) buffer
SHLD INBUFS
SHLD INBUFU
LXI D,128
DAD D
SHLD SQBUFE ; Force exit on full buff aft 1 sect
CALL GETW ; Read 1st word in file
LXI D,SQSIGN ; Get expected value
CALL CMPHLDE
RNZ
MVI A,1
STA SQFLG ; Yes - set flag
LHLD 0006 ; Get top of memory
LXI D,SQBUF+100H*128 ; Limit buffer to max 100H
CALL CMPHLDE ; Sectors (FILBUF uses 8 bit count <B>)
JC TOPLOW ; Use top
XCHG ; Use limit
;
TOPLOW: SHLD SQBUFE ; & store as full address
CALL NAMLP ; Skip past name
CALL USQTBL ; Validate & load decoding tree
JZ OAK ; Tree ok
CALL CDISP
DB CR,LF,'Invalid decode tree size',CR,LF,0
JMP EXIT
;....
;
;
OAK: LXI H,SQMAP+2 ; Point to 1st entry
SHLD SQMAP ; Set to 1at entry in SQ mapper
RET
;.....
;
;
; Read and save checksum
;
RDCHKS: CALL GETW ; Get cksum, and store
SHLD FILCHKS
RET
;.....
;
;
; Read and skip name
;
NAMLP: CALL GETC ; Loop to skip name
JNZ EREXT ; I/O error or unexpected EOF
ORA A
JNZ NAMLP ; Not yet end of name
RET
;.....
;
;
; Load decoding tree
;
; This version uses 1 byte abslute node indices (1-ffH) and is thus
; limited to 255 nodes and 255 characters represented in the squeezed
; file. (All different characters present in the original file as well
; as any added through run encoding. Runs of 3 or more consecutive
; identical characters are encoded as char, DLE, count, where count is
; a one byte field 00 - FFH)
;
USQTBL: CALL GETW ; Get no of nodes
MOV A,H
ORA L
JZ NZEXIT ; Null tree
SHLD NUMVALS
MOV A,H ; Max 257, 256 char & spec eof
ORA A ; H/O byte should be zero
JNZ NZEXIT
LXI D,SQTREE ; Set to decoding tree
;
NODELP: SHLD NXTADR ; Save no of nodes
MOV A,H
ORA L
RZ ; Done all nodes
CALL CVNODE ; Get node, falg byte in <H>,
PUSH H
CALL CVNODE ; Get second child/char
POP B
MOV A,B
RAL ; Shift flags to 8, 4 posns
ORA H ; Combine in 1st child flags
XCHG ; HL> SQTREE, <A>,<C>,<E> node
MOV M,A ; Store flags in table
INX H
MOV M,C
INX H
MOV M,E
INX H
XCHG ; DE> SQTREE
LHLD NXTADR ; Nodes remaining
DCX H
JMP NODELP
;.....
;
;
; Get encoded node
;
; Our nodes contain 3 bytes:
; - flag byte,
; - left child index/char
; - right child index/char
;
; Nodes on input are 4 bytes, with each half containing an index
; (1-100h) or character, where characters are encoded as negative values
; -(char+1) EOF is encoded as -(100h+1)
;
CVNODE: PUSH D
CALL GETW ; Get word, chld ptr or char
POP D
MOV A,H
ORA A
RZ ; Child index, <H>=0,<L>=index
MOV A,L
CMA
MOV L,A ; Convert char to reg form
MOV A,H ; Get h/o byte again
CMA
INR A ; Conv to 1 if char, 2 if EOF
MOV H,A
CPI 1 ; Was that reg char?
RZ ; Yes - complete
ADI 3 ; No convert EOF flag to 0100
MOV H,A
RET
;.....
;
; Exit with NZ flag
;
NZEXIT: MVI A,2 ; Tree error
ORA A ; Set NZ flag
RET
;.....
;
;
; Fill output buffer (unsqueezed char)
;
FILUSQ: LDA SQREWD ; Rewinding SQ input?
ORA A
JZ NOREWD ; No
;
;
; Reload SQ buffer
;
LHLD INBUFS
PUSH H ; Getrf resets
CALL GETRF ; Yes - reload buffer & get 1st 8 bits
POP H
SHLD INBUFS ; Set to first data byte to use
;
BADJ: MOV C,A
LDA BITLFT ; Get preset 1st wanted bit no
MOV C,A
MVI A,8
SUB B ; Calc adjmt reqd
;
BADJLP: DCR A
JZ BADJFN ; Bit adjust finished
MOV B,A
MOV A,C
RRC
MOV C,A
MOV A,B
JMP BADJLP
;
BADJFN: STA BITBUF
XRA A
STA SQREWD ; And clear rewind flag
;
NOREWD: LXI H,DSKBUF ; Reset buffer pointer
XRA A
;
BUFLP: SHLD NXTADR ; Save as next byte in buffer
RNZ ; End of file (NZ flag)
LXI D,SQTREE ; Get end of input
CALL CMPHLDE ; Buffer full (de < hl - not full)
JNC FULL ; Buffer is full
CALL GETNXT ; Get next decoded char
LHLD NXTADR ; Next out buffer posn
MOV M,A ; Store char returned, may be EOF char
INX H
JMP BUFLP
;
FULL: XRA A ; Ensure Z
RET ; Return on full buffer
;.....
;
;
; Get next decoded character
;
GETNXT: LDA RCNT ; See if in the middle of
ORA A ; Repeat sequence...
JZ NORPT
DCR A ; Yes - reduce repeat remaining
STA RCNT
LDA LAST ; Get latest char again
CMP A
RET ; Return with Z for ok
;...
;
;
NORPT: CALL DECODE
RNZ ; EOF? <A>=1AH
CPI DLE ; Run encoding flag?
JNZ NORUN
CALL DECODE ; Get count
RNZ ; EOF? (is really error after DLE)
ORA A
JNZ RUN ; Non-zero, real run
MVI A,DLE ; Dle is encoded as dle,0
CMP A
RET
;...
;
;
RUN: DCR A ; Allow for char already retnd
DCR A ; & this one
STA RCNT ; Keep count yet to be retd
LDA LAST ; Return second time
CMP A
RET
;...
;
;
NORUN: STA LAST ; This may be the start
CMP A
RET
;.....
;
;
; Read bits and decode to char, note this version uses 3 bytes per node
; not 4. The first byte in each node is a flag byte
;
; .... x... - left node contains EOF marker
; .... .x.. - right node contains EOF marker
; .... ..x. - left node contains char
; .... ...x - right node contains char
;
DECODE: LXI D,0 ; Set to node zero in table
LDA BITBUF ; Get bits from bit buffer
MOV C,A
;
BITLP: LDA BITLFT ; Any bits remaining?
ORA A
JNZ NXTBIT ; Yes - go use
PUSH D
CALL GETC ; No - replenish bit buffer
JNZ BADR ; Unexpected eof
POP D
MOV C,A
MVI A,8 ; Set as 8 bits inbuffer
;
NXTBIT: DCR A
STA BITLFT ; Save no of bit remaining
LXI H,SQTREE ; Set to node 0, left child ptr
DAD D
DAD D
DAD D ; Add in node no (4 bytes/node)
MOV B,M ; Get flag byte
INX H ; Step to left child pointer
MOV A,C ; Get input bits
RRC ; Shuffle LOW-ORDER bit to Carry
MOV C,A
MOV A,B ; Get flag byte
JNC GETN3 ; Zero input bit,leave at left
INX H ; Add 1 to point to right child pointer
ADD B ; Normalize wanted flags to .... x.x.
;
GETN3: MOV E,M ; Pick up child or char
ANI 1010B ; Mask unwanted bits
JZ BITLP ; Reg child pointer
ANI 1000B ; End of file marker?
JNZ GOTEOF ; Yes - get out with eof
MOV A,C
STA BITBUF ; Save bit buffer
MOV A,E ; Get decoded char (neg)
RET
;...
;
;
; Exit on regular EOF
;
GOTEOF: MVI A,EOF
ORA A
RET
;.....
;
; Get input word (lo/hi, unencoded)
;
GETW: CALL GETC
JNZ BADR ; Unexpected EOF
PUSH PSW
CALL GETC
JNZ BADR ; Unexpected EOF
MOV H,A
POP PSW
MOV L,A
RET
;.....
;
;
EREXT:
BADR: CALL CDISP
DB CR,LF,'Unexpected EOF',CR,LF,0
JMP EXIT
;.....
;
;
; Get single (unencoded) character
;
GETC: LHLD INBUFU
XCHG
LHLD INBUFS
CALL CMPHLDE ; End of input buffer?
JZ GETRF ; Yes
;
GETC1: MOV A,M ; No get next byte
INX H
SHLD INBUFS ; Save addr of next byte
CMP A
RET
;.....
;
;
; Refill input buffer
;
GETRF: LDA SQEOF ; Is there anything else?
ORA A
JZ GETOK
CALL CDISP
DB CR,LF,'Read past EOF on SQ file',CR,LF,0
JMP EXIT
;.....
;
;
GETOK: LHLD SECCNT ; Save record count (decoded buffer only)
PUSH H
LXI H,SQBUF ; Set input buffer as empty,
SHLD INBUFS ; _and start of buffer
XCHG ; DE> buffer, next record locn
LHLD SQBUFE ; End of input buffer
SHLD INBUFU ; Assume no end of file for now
MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D ; Calc buffer size
MOV H,A
DAD H ; Convert to no of records
MOV B,H ; No of records to read
; # records limited to 100 max (<B>=0)
LHLD FCBCRR ; No of 1st record to read
SHLD SQBSC1
CALL FILBU1 ; Read record into SQBUF
;
;
; <B> no of records not read if EOF
; HL> 128
; DE> last record read, or after if EOF
;
LHLD FCBCRR ; Get next SQ record no
SHLD NXTSQS
MOV A,B ; Did we fill buffer?
ORA A
JZ GETRF2 ; Yes - no eof
XCHG ; Eof, adjust buffer end marker
SHLD INBUFU ; Mark end of buffer used
STA SQEOF ; & flag eof
;
;
; Input buffer re-filled
;
GETRF2: POP H
SHLD SECCNT ; Restore record count (decoded buffer only)
LHLD INBUFU ; Get end of buffer
XCHG
LHLD INBUFS ; Get start of buffer
CALL CMPHLDE ; Something there?
JC GETC1 ; Yes - go for char
JMP EREXT ; No - read past eof or empty file
;.....
;
;
; End of baseline USQ code
;
OTBUFE: DW 0 ; End of decoded char buffer
INBUFS: DW 0 ; Start of input buffer
INBUFU: DW 0 ; End of used part input buffer
SQBUFE: DW 0 ; End of input buffer
NXTADR: DW DSKBUF ; Next byte in output buffer
BITLFT: DS 1 ; No of bits left in bit buffer
RCNT: DS 1 ; Run count remaining (DLE)
FILCHKS:DS 2 ; Checksum read from file
LAST: DS 1 ; Last reg char decoded
BITBUF: DS 1 ; Latest 8 bits (encoded) from input file
NUMVALS:DS 2 ; No of nodes in encodng tree
ENDIF
;.....
;
;
; Memory allocation
;
IF NOT SHORT
PFLG: DB 0 ; Printer toggle 0=off
ENDIF
;
SECCNT: DW 0 ; Number of records read into buffer
LINMAX: DB SCROLN ; Number of to write lines on console
CHRMAX: DB MAXCHR-1 ; Number of characters to display per line
CHRMIN: DB 0 ; Character to start displaying on line
CHRCNT: DS 1 ; Character number in line
LINCNT: DS 1 ; Line number on write or move back in buffer
TOPBUF: DB 0 ; Top of file is now in buffer
; Z - yes, NZ - no
;
IF SQUEEZE
NXTSEC: DW 0 ; Next (unsqueezed) record not yet in BSKBUF
; set (and used) only by FILSQ
SQFLG: DB 0 ; File is squeezed
SQEOF: DB 0 ; End of file on squeezed file
SQREWD: DB 0 ; Flag the SQ input file is being re-read
;
SQBYT: DW 0 ; Offset of first data byte in SQ buffer
SQBSC1: DW 0 ; No of 1st record in SQ buffer
NXTSQS: DW 0 ; No of last record in SQ buffer
ENDIF
;
IF LIBRARY
NAMEXC: DB (MAXCHR/11)-1 ; No of directory names across display
DB 0 ; No of names so far
DIRSIZ: DB 0 ; # of members possible in directory
MEMNAM: DB 0 ; Member name specified on command line
SCZERO: DW 0 ; First record for member
SCLAST: DW 0FFFFH ; Last record for member (included in member)
; SCZERO and SCLAST are relative in file
LBFLG: DB 0 ; File is a library file
MEMFCB: DS 12 ; Name of member file
ENDIF
;
DS 60 ; Stack area
STACK: DS 2 ; Old stack saved here
DSKBUF EQU $ ; Disk buffer area above the program
;
ENDBUF EQU DSKBUF+MAXREC*128
;
IF SQUEEZE
SQTREE EQU ENDBUF ; Space for SQ decoding tree
SQMAP EQU SQTREE+256*3
;
;
; Space for SQ buffer mapping table contains SQ sect #, SQ byte and bit
; offset for every time DSKBUF was filled 1st entry contains index to
; latest mapping triplet to handle run compr straddling buffer end,
; should also store recent and last.
;
SQBUF EQU SQMAP+100*4 ; (allows for 100 8k buffers)
ENDIF
;
;
END