; BISHOW v34 - buffered bidirectional file scroll utility' ; ; Ver 34, 25 Sep 1987, Ernest F. Barnhart, N8DVE, Dayton, OH ; - Added cursor off/on for the Kaypro computers. ; - Changed back to using control key for real Wordstar ; compatibility. ; - Changed keys to allow the set function to work correctly. ; - Changed format of help screen. ; - Changed format of help lines. ; ; Ver 33, 29 Sep 86, Charlie Kestner, Hammond, Ind ; - clarified the LIBRARY AND SQUEEZE help message ; since this is probably version MOST folk would use. ; - eliminated having to use control key. Now just plain ; S, D, E, X, E, & C function for Wordstar users. ; - changed over some of the command keys for folk who ; like to use cursor/numeric pad. NO need to shift ; the numeric pad, plain numbers will do it. ; - long help key is now "/". ; ; Ver 32, 3 Nov 85, Rod Clark, Seattle WA ; - added Wordstar cursor pad (^C now = page down). ; - ESC exits, clears screen. Q exits, leaves screen. ; - Wrong keys are ignored. H = brief help. ? = help. ; - SHORT + SQUEEZE + LIBRARY = .COM file < 2k. ; - SHORT, no SQUEEZE, no LIBRARY = .COM file < 1k. ; - SHORT disables setting each margin interactively ; (the command line still sets the right margin and ; the page length), but it does let you scroll back ; and forth horizontally by tab stops within a file. ; The SHORT version gives two sets of cursor keys ; (Wordstar and CR/SP etc), but no help display. ; - BISHOW (no filename) tells whether it works on .LBR ; or squeezed files, or both, or just on plain files. ; - and fixed jumbled multiple-line .LBR directory. ; ; Ver 31, 15 Jan 84, Frans van Duinen, Toronto, Ont ; - made unsqueeze message optional ; - added library capability ; - fixed bug in conditional assembly of CLRSCR ; ; Ver 29, 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=TRUE ; (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 cond assembly option ; ; Ver 28, 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 Sigi Kluger of El ; Paso,Texas. The code was lifted, to allow ; continued use of ASM.COM ; ; ; Ver 17, 1 Aug 83, Ted H. Emigh ...!unc!tucc!emigh ; - added screen width specification ; - added screen definition commands (see notes below) ; ; Ver 16, 2 Jul 83, Chuck Forsberg ; - added commands for more, mince, vi familiarity. ; Bad command gives help. ; ; Ver 15.1, 26 June 83, Dick Mead ; - added "?" for help on commands. ; ; Ver 15, 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 14, 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 13, 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 12, 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 11, 30 Mar 83 - added BDOS function 6. W.F.Mcgee ; ; Ver 10, 23 Aug 82 Phil Cary, 748 Kenilworth Parkway, Baton ; Baton Rouge, LA 70808 ; ;----------------------------------------------------------------------- ; ; 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 a 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 since it is not a file that Wordstar can load and run. ; ; This bidirectional version uses random access reads. In addition, ; buffering was added so that 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 refill 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 subroutine "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, as written, requires a terminal with an erase ; screen and home cursor function. Some terminals do not allow the 80th ; column to be filled without 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 mini- ; mum column displayed (allowing you to "window" the output) and the ; number of lines ("SCROLN"). A zero for the maximum column displayed ; willgive an unlimited screen width. The maximum column displayed and ; the number of lines can be set when calling BISHOW, such as "BISHOW ; FILENAME.EXT 79 24" will give 79 columns and 24 lines with "BISHOW ; FILENAME.EXT 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 command 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. Direct I/O to the console is ; used to avoid echoing the commands to the console as the CP/M write ; console function does. ; ; Justa small contribution to the public domain software as partial pay- ; ment for the many fine and educational programs the system has given ; me. ; - Phil Cary. ;----------------------------------------------------------------------- ;Define version number for help message ; VERS EQU 3 REVS EQU 4 ; ; NO EQU 0 YES EQU NOT NO ; ; ASCII equates ; ENDMSG EQU 0 ; Null BS EQU 8 ; Backspace TAB EQU 9 ; Tab LF EQU 0AH ; Line feed FEED EQU 0CH ; Form feed CR EQU 0DH ; Carriage return EOF EQU 1AH ; End of file ESC EQU 1BH ; Escape SPACE EQU 20H ; Space ; ;----------------------------------------------------------------------- ; ; User settings ; KAYPRO EQU YES ; Use cursor on/off function HEATH EQU NO ; Assemble for H-19 terminal OSBORNE EQU NO ; Assemble for 52-column screen ; SHORT EQU NO ; No SQ or LBR = 1k / with SQ and LBR = 2k LONG EQU YES ; Duplicate keys, includes help, margin set SQUEEZE EQU YES ; Optional, to handle squeezed files LIBRARY EQU YES ; Optional, to handle .LBR files ; NOWAIT EQU YES ; True = no wait after screen clear SILENT EQU YES ; True = no superfluous "unsqueezing text" msg ; IF NOT OSBORNE SCROLN EQU 23 ; Number of lines per scroll MAXCHR EQU 80 ; Number of characters per line ENDIF ; NOT OSBORNE ; IF OSBORNE SCROLN EQU 24 ; Number of lines per scroll MAXCHR EQU 51 ; Number of characters per line ENDIF ; OSBORNE ; ; Change the help tables if you change keys ; ; Command keys - short version ; LINE EQU 'X'-40H LINE2 EQU SPACE PAGE EQU 'C'-40H PAGE2 EQU CR LINEUP EQU 'E'-40H LINEUP2 EQU 'E'-40H PAGEUP EQU 'R'-40H PAGEUP2 EQU 'R'-40H ARWLFT EQU 'S'-40H ARWLFT2 EQU 'S'-40H ARWRT EQU 'D'-40H ARWRT2 EQU 'D'-40H TOP EQU 'T' TOP2 EQU '7' QUIT EQU 'Q' QUITCL EQU ESC ; ; Additional command keys - long version ; IF LONG LINE3 EQU LF LINE4 EQU '+' LINE5 EQU '2' LINE6 EQU '2' PAGE3 EQU '3' PAGE4 EQU '3' PAGE5 EQU '3' LINEUP3 EQU '8' LINEUP4 EQU '-' LINEUP5 EQU '8' PAGEUP3 EQU '9' ARWLFT3 EQU '4' ARWRT3 EQU '6' SETKEY EQU 'S' HUH EQU 'H' HUH2 EQU '/' ENDIF ; LONG ; ;----------------------------------------------------------------------- ; ; Check help and CLRSCR routines ; ;----------------------------------------------------------------------- ; BASE EQU 0 ; Standard zero base CP/M ; ; BDOS functions ; CONOUT EQU 2 ; Console write 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 BASE ; Warm boot entry point BDOS EQU WBOOT+5 ; BDOS entry point FCB EQU WBOOT+5CH ; Default fcb drive number CMDTAIL EQU WBOOT+80H ; 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 WBOOT+100H ; Transient program area ; ; 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) ; ORG TPA ; JMP START ; Skip over next subroutines ; ;----------------------------------------------------------------------- ; ; Change help tables to reflect key changes ; IF LONG AND NOT OSBORNE HELP3: CALL CDISP DB CR,LF,LF DB ' ^E ^X ^R ^C T ^S ^D ' DB ' S H Q',CR,LF DB 'up line down line up page down page top left right' DB ' set help quit',CR,LF DB ' 8 2 9 3 7 4 6 ' DB ' S / ESC',CR,LF DB ENDMSG JMP GETCMD ENDIF ; LONG AND NOT OSBORNE ; IF LONG AND OSBORNE HELP3: JMP HELP2 ENDIF ; LONG AND OSBORNE ; IF LONG AND NOT OSBORNE HELP2: CALL CDISP DB CR,LF,LF DB ' ^E - line up ^R 9 page up ^S 4 left ' DB ' S set Q quit',CR,LF DB ' ^X line ^C page ^D 6 right' DB ' T 7 top ESC clear',CR,LF DB ENDMSG JMP GETCMD ENDIF ; LONG AND NOT OSBORNE ; IF LONG AND OSBORNE HELP2: CALL CDISP DB CR,LF,LF DB '^E line up ^R page up ^S left T top Q quit',CR,LF DB '^X line ^C page ^D right S set ESC clear',CR,LF DB ENDMSG JMP GETCMD ENDIF ; LONG AND OSBORNE ; ; Check your clear code ; CLRSCR: CALL CDISP ; Command to erase screen and home cursor ; IF NOT (HEATH OR OSBORNE) DB 1AH,ENDMSG ; Put your screen clear string here ENDIF ; NOT (HEATH OR OSBORNE) ; IF HEATH DB ESC,'E',ENDMSG ; For H/Z-19 terminal -- Change as required ENDIF ; HEATH ; IF OSBORNE DB 1AH,ENDMSG ; For Osborne (& Televideo?) ENDIF ; OSBORNE ; ; end of user settings ;----------------------------------------------------------------------- ; IF NOT NOWAIT WAIT: MVI B,0 ; Waste time (may or may not be necessary) WAIT1: XTHL ; Good time gobbeler! XTHL DCR B JNZ WAIT1 ENDIF ; NOT NOWAIT ; RET ; Return from clrscr ;----------------------------------------------------------------------- ; ; START OF PROGRAM ; ;----------------------------------------------------------------------- ; START: IF HEATH CALL CDISP DB ESC,'x5',ENDMSG ; Disable cursor ENDIF ; HEATH ; IF KAYPRO CALL CDISP DB ESC,'C4',ENDMSG ; Disable cursor ENDIF ; KAYPRO ; LXI H,0 ; Get CCP's stack DAD SP SHLD STACK ; Save old stack for reinstatement at exit 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 =0 or =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? ; IF LIBRARY JNC MEMB ; No - ENDIF ; LIBRARY ; CPI '0' JNC NUMBER ; Yes - must be width & height ; IF LIBRARY ; 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 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 =0 or =20H JZ OPENF ; End ENDIF ; LIBRARY ; ; Handle screen width and 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 ENDIF ; SQUEEZE ; IF LIBRARY CALL FILBF0 ; Fill the disk buffer with start of file CALL CHKLB ; Check for library file CALL CLRSCR JMP WRTFW0 ; Buffer contains top records ENDIF ; LIBRARY ; 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 FEED ; 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) JC WRTFW1 ; Continue with next character CALL FILBUF ; Fill the disk buffer with next records JMP WRTFW0 ; Start over ; HELP: CALL CLRSCR CALL CDISP DB CR,LF DB 'BISHOW v',(VERS MOD 10)+'0' DB REVS/10+'0',(REVS MOD 10)+'0' DB ', 25 Sep 1987' DB CR,LF,LF ; IF LIBRARY AND SQUEEZE DB ' BISHOW is a buffered, bi-directional' DB ' file pager that will display',CR,LF DB ' various forms of text files. Syntax is:',CR,LF,CR,LF DB ' bishow filename.typ [cols] [lines]',CR,LF,CR,LF DB ' Normal or squeezed ASCII or WordStar ' DB 'files may be viewed.',CR,LF,CR,LF DB ' A directory of a library file, or a ' DB 'member of a library file may',CR,LF DB ' be seen. Syntax is:',CR,LF,CR,LF DB ' bishow librname.lbr',CR,LF DB ' bishow librname membrnam.typ',CR,LF,CR,LF DB ' Note that the .LBR extension MUST be appended to ' DB 'the library name.',CR,LF DB ' in order to display the librarys directory. ',CR,LF,CR,LF DB ' (Type a "/" while viewing a file ' DB 'to see command summary.)',CR,LF DB ENDMSG ENDIF ; LIBRARY AND SQUEEZE ; IF LIBRARY AND NOT SQUEEZE DB 'bishow a:FILnotSQ.lbr ' ENDIF ; LIBRARY AND NOT SQUEEZE ; IF SQUEEZE AND NOT LIBRARY DB 'bishow a:SQZorNOT.fil ' ENDIF ; SQUEEZE AND NOT LIBRARY ; IF (NOT SQUEEZE) AND (NOT LIBRARY) DB 'bishow d:anyPLAIN.fil ' ENDIF ; (NOT SQUEEZE) AND (NOT LIBRARY) ; IF LIBRARY DB '[member] ' ENDIF ; LIBRARY ; DB '[cols [lines]]',CR,LF,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 STA LINCNT ; __line count ; GETCMD: PUSH H PUSH D PUSH B ; GETCM1: CALL GETIN ; Get input char if any ORA A ; Loop till char avail JZ GETCM1 POP B POP D POP H CPI 'a' ; Change command to JC GETCM2 ; __upper case CPI 'z'+1 JNC GETCM2 XRI 20H ; Is lower case, make upper case ; ; Commands for short version ; GETCM2: CPI LINE ; Scroll next line JZ WRTNXT CPI LINE2 JZ WRTNXT CPI PAGE ; Scroll next page JZ WRTFW1 CPI PAGE2 JZ WRTFW1 CPI LINEUP ; Scroll prev line JZ WRTPRV CPI LINEUP2 JZ WRTPRV CPI PAGEUP ; Scroll page backward JZ WRTBAK CPI PAGEUP2 JZ WRTBAK CPI ARWLFT ; Scroll left JZ ADJMM CPI ARWLFT2 JZ ADJMM CPI ARWRT ; Scroll right JZ ADJMM CPI ARWRT2 JZ ADJMM CPI TOP ; Go to 1st line of file JZ WRTTOP CPI TOP2 JZ WRTTOP CPI QUIT ; Does not clear screen JZ EXIT CPI QUITCL ; Clears screen JZ EXITCL ; ; Commands for long version ; IF LONG CPI LINE3 JZ WRTNXT CPI LINE4 JZ WRTNXT CPI LINE5 JZ WRTNXT CPI LINE6 JZ WRTNXT CPI PAGE3 JZ WRTFW1 CPI PAGE4 JZ WRTFW1 CPI PAGE5 JZ WRTFW1 CPI LINEUP3 JZ WRTPRV CPI LINEUP4 JZ WRTPRV CPI LINEUP5 JZ WRTPRV CPI PAGEUP3 JZ WRTBAK CPI ARWLFT3 JZ ADJMM CPI ARWRT3 JZ ADJMM CPI SETKEY JZ SETSCR CPI HUH JZ HELP2 ; Brief table of commands CPI HUH2 JZ HELP3 ; Full table of commands ENDIF ; LONG ; JMP GETCMD ; ; 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 FEED ; __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 RECCNT ; 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 ( ) does NOT ; agree with the wanted no ; .CBCRR Reset to record zero STA FCBCRR ; IF NOT LIBRARY STA FCBCRR+1 ; STA FCBCRR+2 ; __and clear the overflow ENDIF ; NOT LIBRARY ; IF LIBRARY LHLD SCZERO ; Set to record zero for file/member SHLD FCBCRR ENDIF ; LIBRARY ; ; Fill buffer from spec'd record ; FILBUF: MVI B,MAXREC ; Number of records to read ; FILB1S: IF LIBRARY LHLD SCZERO ; Get top record for member XCHG LHLD FCBCRR ; Is this top of file? CALL CMPHLDE ; This it? (=0 if equal) ENDIF ; LIBRARY ; IF NOT LIBRARY LHLD FCBCRR ; Is this top of file? MOV A,H ORA L ENDIF ; NOT LIBRARY ; STA TOPBUF ; Set top of file in buffer flag LXI D,DSKBUF ; Load start of disk buffer LXI H,0 ; Zero out the SHLD RECCNT ; __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 ; SQUEEZE ; FILBU1: PUSH H ; Save all PUSH D ; __registers from PUSH B ; __BDOS clobber MVI C,STDMA ; Set dma to CALL BDOS ; __disk buffer LXI D,FCB ; Set up to read MVI C,READR ; __a record CALL BDOS ; Do it ORA A ; Read OK? LHLD FCBCRR ; Get current record number INX H ; __bump it SHLD FCBCRR ; __and save it LHLD RECCNT ; Get records in buffer INX H ; Bump it SHLD RECCNT ; 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 ; LIBRARY ; 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 RTN handles mapping from UNSQ ; record # to record, byte and bit in squeeze stream. On input (no ; allowance made for records # over 65535) contains number 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 NXTREC ; & 1st record after buffered ones CALL CMPHLDE ; Consecutive? JZ USQNXT ; Yes - fine JNC USQBAK ; No - lower ; ; Next record after latest but not consec ; CALL CDISP DB CR,LF,'Disjoint records',CR,LF,0 JMP EXIT ; Should never happen ; USQBAK: DS 0 ; Going backward ENDIF ; SQUEEZE ; IF SQUEEZE AND LIBRARY LHLD SCZERO ; Get 1st record for member CALL CMPHLDE ; All the way back to start? ENDIF ; SQUEEZE AND LIBRARYX ; IF SQUEEZE AND NOT LIBRARY MOV A,D ; All the way? ORA E ENDIF ; SQUEEZE AND NOT LIBRARY ; 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 ; wanted 1st record, 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 ; (note is probab not record 0 ; because of header, eg decoding tree) MVI A,1 ; Set rewind with I/O STA SQREWD ; Set rewind flag XRA A STA SQEOF ; Reset end of file on SQ ; Leave current extent alone. This is ; how BDOS knows how to switch the ; extents. It checks if the current ; extent no agrees with the wanted ; record. STA FCBCRR+2 ; & count overflow, should not be needed MOV D,A JMP USQNX1 ; Go adjust buffer pointer ; (NOP since =0 ; ; SQ text still in buffer ; ; # of 1st record in SQ buf ; # of wanted SQ record ; (Max 100H SQ records in buffer) ; USQ1OK: MOV A,L SUB E RAR ; Convert to pages (100H) ; ; Know Cy=0 in ; Leaves carry set if odd number of records ; 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 ; ; Next record consecutive ; USQNXT: LHLD NXTSQS ; Get no of next SQ record SHLD FCBCRR ; ; Build mapping table entry ; LHLD INBUFS ; Calculate offer 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 sector relative DAD H ; Convert to record no ORA A ; Is next byte at start of record? JNZ RECTOK DCR H ; Yes - step back one record ; RECTOK: DCR A ANI 7FH ; And adjust byte index MOV E,H MVI D,0 LHLD SQBSC1 ; # of 1st record in buffer DAD D XCHG ; 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 sector relative byte offset INX H MOV M,B ; Save BITLFT INX H SHLD SQMAP ; Save new index ENDIF ; SQUEEZE ; IF SQUEEZE AND NOT SILENT CALL CDISP ; Show msg where is DB '>>> Unsqueezing Text <<<',ENDMSG ; Corrupts display if after CR but before LF ENDIF ; SQUEEZE AND NOT SILENT ; IF SQUEEZE CALL FILUSQ ; Fills unsq buffer ENDIF ; SQUEEZE ; IF SQUEEZE AND NOT SILENT CALL CDISP ; Remove msg just displayed, assumes ; BS works across start of line if reqd 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 ; SQUEEZE AND NOT SILENT ; 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 MOV L,H MVI H,0 SHLD RECCNT ; Save # of records in DSKBUF POP D ; Get FCBCRR as passed by calling rtn DAD D ; & calc new one SHLD FCBCRR SHLD NXTREC RET ENDIF ; SQUEEZE ; ; 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 to start of buffer RET ; __on 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 'No File',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 ; IF LONG 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 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 ; LONG ; 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 CALL CO ; No, print the character JMP CDIS1 ; __and loop ; CDIS2: XTHL ; Get return address on top of stack RET ; __and return ; CO: PUSH B ; Save the registers PUSH D ; __from BDOS PUSH H ; __clobber ; CO2: PUSH PSW MOV E,A ; Set up character MVI C,CONOUT ; __to send to console CALL BDOS ; Do it POP PSW ; CO5: POP H ; Restore POP D ; __the registers POP B RET ; 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 ; IF LONG 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 DB CR,LF,'Max Column: ' ; 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 DB LF,'Min Column: ' ; 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 per Page: ' ; 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 ENDIF ; LONG ; ; Adjust char min/max on cursor left/rt ; ADJMM: PUSH H CPI ARWLFT ; Move left (decrease)? JZ ADJM1 ; Set flag CPI ARWLFT2 JZ ADJM1 ; IF LONG CPI ARWLFT3 JZ ADJM1 ENDIF ; LONG ; ADJM1: LDA CHRMAX ; Rightmost char to display MOV H,A LDA CHRMIN ; Leftmost char to display MVI L,8 ; Scroll by 8 JZ ADJMMD ; OK - adjust to left ADD L ; No - increase min, no limit PUSH PSW MOV A,L ADD H ; Increase max JMP ADJMMS ; OK - adjust to right ; ADJMMD: SUB L ; Adjust to left PUSH PSW MOV A,H SUB L ; ; Adjust to right ; ADJMMS: MOV H,A ; max POP PSW ; min CMP H ; Wrap, (max< min) JNC ADJMMX ; OK - leave unchanged STA CHRMIN MOV A,H STA CHRMAX ; ADJMMX: POP H LDA LINMAX ; Write the same screen JMP WRTBK0 ; Same effect as WRTSAM above ; IF LONG 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 ENDIF ; LONG ; ; Clear screen only on exit ; EXITCL: CALL CLRSCR ; Clear the screen ; EXIT: LXI D,FCB ; Close file MVI C,CLOSE ; --in case this is MP/M CALL BDOS ; EXIT1: IF HEATH CALL CDISP ; Re-enable cursor DB ESC,'y5',ENDMSG ENDIF ; HEATH ; IF KAYPRO CALL CDISP DB ESC,'B4',ENDMSG ; Enable cursor ENDIF ; KAYPRO ; 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 ; ; Not library ; LDA MEMNAM ; Was member specified ORA A RZ ; No - ok CALL CDISP DB CR,LF,'Not LBR',CR,LF,0 JMP EXIT ; Get out to leave msg visible ; ; Is library ; 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 LXI H,DSKBUF+20H ; Set 1st member entry CALL CDISP ; Write a blank line before first dir line DB CR,LF,0 ; ; 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 member name routine ; ; See if this is the requested member ; MVI B,12 ; Length of names + 00H in front LXI D,MEMFCB CALL CPSTR ; Compare names JZ FOUND JMP NYET ; ; Display rather than look for the member ; 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 ; LIBRARY ; 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 ; LIBRARY AND NOT OSBORNE ; IF LIBRARY JMP DSPMLP ; Go for next char ; ; Have now displayed member 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 ; LIBRARY ; IF LIBRARY AND NOT OSBORNE DB ' ' ENDIF ; LIBRARY AND NOT OSBORNE ; 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 JNZ XLIB ; If not then display message CALL CDISP DB CR,LF,ENDMSG ; Leave blank line after directory JMP EXIT ; XLIB: CALL CDISP DB 'Not in LBR',CR,LF,0 JMP EXIT ; And show the poor schmuck the directory ; ; 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 ; LIBRARY ; 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 'unSQ LBR',CR,LF,0 JMP EXIT ; NOLBSQ: CALL CHKSQ ; Check if member squeezed ENDIF ; LIBRARY AND SQUEEZE ; IF LIBRARY CALL FILBF0 ; Refill buffer, now for member ; (FILBUF handles member offset in library) RET ; ; Member is empty ; NULLEN: CALL CDISP DB 'Empty',CR,LF,0 JMP EXIT ENDIF ; LIBRARY ; ; Get input if any ; GETIN: MVI C,6 ; Direct console I/O MVI E,0FFH ; __set up for input CALL BDOS ; Get character RET ; ; Compare strings HL> to DE> over ; ; and are changed, 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 to Z - equal; C - less than if equal ; returns =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 ; 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 * ;****************************************************** ; ; Check for SQ file, initialize tree if so ; IF SQUEEZE CHKSQ: XRA A MOV L,A MOV H,L ; Clear 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 ; SQUEEZE ; IF SQUEEZE AND LIBRARY LHLD SCZERO ; Get 1st record for member SHLD NXTREC ; & save as next record ENDIF ; SQUEEZE AND LIBRARY ; 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 buffer aft 1 sect ; ; Ccauses the SQ buffer to contain records 1+ only (not zero), normally ; fine since recort 0 contains only header info. Record 0 will be re- ; read if contains data and needed. Read and validate signature word. ; 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 ; Records (FILBUF uses 8 bit count ) 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,'Bad SQ tree',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 checksum, 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-0FFH) and is thus limited to 255 nodes and 255 characters represen- ; ted 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 - 0FFh) ; 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 ; ; In this version allow for only 256 different codes, every ASCII and ; non-ASCII character would have to be present, or run repeat counts ; 128-255 (every one) ; 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 , 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, ,, 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: 1) flag byte, 2) left ; child index/character and 3) right child index/character. Codes 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, child pointer or character POP D MOV A,H ORA A RZ ; Child index, =0,=index MOV A,L CMA MOV L,A ; Convert character to register 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 ; Calculate adjustment required ; 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 character ; ; No checksum taken ; 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? =1AH CPI DLE ; Run encoding flag? JNZ NORUN ; ; Handle DLE ; 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 encoding found ; RUN: DCR A ; Allow for char already retnd DCR A ; and this one STA RCNT ; Keep count yet to be retd LDA LAST ; Return second time CMP A RET ; ; Normal character, no run active ; NORUN: STA LAST ; This may be the start CMP A RET ; ; ; Read bits and decode to character. Nnote 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 character ; ; should always remain zero ; ANI 1010B ; Mask unwanted bits JZ BITLP ; Reg child pointer ; ; Got to character or EOF ; 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 register EOF ; GOTEOF: MVI A,EOF ORA A RET ; ; Get input word (low/high, 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: DS 0 ; BADR: CALL CDISP DB CR,LF,'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,'EOF',CR,LF,0 JMP EXIT ; GETOK: LHLD RECCNT ; 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 LHLD FCBCRR ; No of 1st record to read SHLD SQBSC1 CALL FILBU1 ; Read record into SQBUF ; ; no of sectors not read if EOF ; HL> 128 ; DE> last sector read, or after if EOF ; LHLD FCBCRR ; Get next SQ record number 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 ; and flag EOF ; ; Input buffer re-filled ; GETRF2: POP H SHLD RECCNT ; 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 ; Also used when loading tree 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 ; SQUEEZE ; ; Memory allocation ; RECCNT: DW 0 ; Number of records read into buffer LINMAX: DB SCROLN ; Number of 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 NXTREC: 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 ; buffer refill rtn (getrf) to set inbufs ; as per offset in SQBYT, and pre-load ; bit buffer. Bit buffer to be adj ; as per Bitlft 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 ; SQUEEZE ; IF LIBRARY NAMEXC: DB (MAXCHR/14)-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 ; Member name here ENDIF ; LIBRARY ; 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 squeeze record #, squeeze ; byte and bit offset for every time DSKBUF was filled. 1st entry con- ; tains index to latest mapping triplet to handle run compr straddling ; buffer end, should also store rcnt and last. ; SQBUF EQU SQMAP+100*4 ; (allows for 100 8k buffers) ENDIF ; SQUEEZE ; ; Input (squeezed) buffer, runs up to top of free memoryot ; END TPA