TITLE 'ZLT (Z-system Library Typer), November 1, 1989' ; Program: ZLT (Z-system Library Typer) ; Author: Howard Goldstein ; Assembly: Z80ASM, SLRNK, WILDEX, UNC, ZSLIB, SYSLIB, Z3LIB. ; Version: 1.5 ; VER equ 15 ; Current version number ; ; Date: September 12, 1991 ; Changes: Fixed option parser again (I hope I did it right this ; time. Removed code that ignored directory specs when ; Wheel byte off. Removed all conditional assembly. ; Fixed built-in help message to reflect default settings ; of Q and P options. ; ; Author: Howard Goldstein ; Assembly: Z80ASM, SLRNK, WILDEX, UNC, ZSLIB, SYSLIB, Z3LIB. ; Version: 1.4 ; Date: September 6, 1991 ; Changes: Linked with new UNLZH module to support latest LZH ; compression. ; Added CFG file name to configuration block so CFG file ; can be found automatically even if program is renamed. ; Fixed a minor bug in the command line option parser. ; Replaced several JP's with JR's. ; Now linking with ZSLIB which contains the old PARMLIB ; modules. ; ; Author: Carson Wilson (this version) . ; Sysop, Antelope Freeway, Chicago, 312/764-5162. ; Assembly: Z80ASM, SLRNK, WILDEX, UNC, PARMLIB, SYSLIB, Z3LIB. ; Version: 1.3 ; Date: November 1, 1989 ; Changes: Added LZH file support. ; Added "P" option to print without paging. ; Made "P" and "Q" options installable defaults which are ; toggled at the command line. ; Default line limit for nonwheels is now 0 (no limit). ; Use ZCNFG to install a limit. ; ; Author: Carson Wilson (this version) ; Assembly: Z80ASM, SLRNK, WILDEX, UNC, PARMLIB, SYSLIB, Z3LIB. ; Version: 1.2 ; Date: July 22, 1989 ; ; Changes: Put history in separate ZLTHIST.DOC file. ; Translated to Z80 opcodes and expanded external labels to ; full 7 characters for use with SLR tools. ; It is desirable sometimes to output "raw" text, especially on ; remote systems where ZLT is the only available typer. ; This version allows a "Q" option which suppresses all ; non-error messages as well as extra linefeeds, sending to ; the screen the exact contents of a text file only. ; Allows help only for exactly two "/" characters, or no ; parameters. Now possible to type files named "/" if needed. ; Changed a few exclude types. Now excludes .NDR, .ENV, BIN, ; ZIP. ; Added patch points for Quiet and speed options. ; Cleaned up and shortened code with Z80 instructions. ; Improved help screen. ; ; ZLT types normal, crunched or squeezed files, either directly or from ; .LBR members. Wildcards access a series of library members OR files. ; For history see ZLTHIST.DOC. ;----------------------------------------------------------------------- ; CSEG ; NO equ 0 ; For conditional assembly YES equ NOT NO ; (Some assemblers don't like 0FFh) ; ; Defaults (no increase in COM size). LIMITT equ YES ; Yes to restrict filetypes NOCTRL equ YES ; Yes to prevent control char. output QUIET equ NO ; Display "raw" output PAGE equ YES ; Page (pause) output LNMAX equ 0 ; ;.... ; BELL equ 07h BS equ 08h TAB equ 09h LF equ 0Ah CR equ 0Dh ; ; CP/M-DOS+-ZRDOS system values ; BDOS equ 0005h FCB1 equ 05Ch FCB2 equ 06Ch TBUFF equ 80h ; ; BDOS calls ; CIO equ 6 ; Direct console I/O GETVER equ 12 OPEN equ 15 SRCHF equ 17 FREAD equ 20 SETDMA equ 26 FRDRAN equ 33 ; Read random record ; EXTRN PARGET, PARCHR ; From ZSLIB31 or higher EXTRN WILDEX ; Sigi Kluger wildcard expander EXTRN Z3INIT,GETWHL,GETCRT,GETEFCB ; From Z3LIB EXTRN Z3LOG EXTRN GETSPEED ; Added @v1.1 EXTRN INITFCB ; From SYSLIB EXTRN ISDIGIT ; Added @v1.1 EXTRN UNC ; Falconer-Greenberg UNCR module EXTRN UNL ; R. Warren UNLZH module ; NOTE: LINK WILDEX.REL FIRST & UNC.REL LAST! ; PUBLIC GETBYT,UNCOUT ; Referenced by UNC PUBLIC GLZHUN,PLZHUN ; Referenced by UNL ; ZLT: jp START db 'Z3ENV',1 Z3EADR: dw 00 ds 2 ; Configuration area begins at entry+1dh ; ; Configuration values ; db 'ZLT' ; Name of CFG file to search for db (VER/10)+'0',(VER mod 10)+'0' db ' ' ; MAXLIN: db LNMAX ; Max lines to type, 0 = unlimited TYPFLG: db LIMITT ; 0 for all file types, else selective CTLFLG: db NOCTRL ; 0 allows control char print QDEF: db QUIET ; Quiet default PDEF: db PAGE ; Page default DDEF: db 'X' ; Delay default ("X" for none) ; '?' matches any character. Alpha order for convenience only, ; a complete sequential scan is done. An existing name can be ; made to disappear by setting its high order bit somewhere. ; Table of invalid file types BADTBL: db 'ABS' ; Intended to disable db 'ARC' ; =================== db 'ARK' db 'BAD' db 'BIN' db 'C?M' ; COM, CQM, CZM db 'E?E' ; EXE, EQE, EZE (MSDOS executable) db 'ENV' db 'I?T' ; INT, IQT, IZT db 'LBR' db 'NDR' db 'O?J' ; OBJ, OQJ, OZR db 'P?D' ; PCD, PQD, PZD (executable by RUNPCD) db 'R?L' ; REL, RQL, RZL db 'S?R' ; SLR, SQR, SZR (SLR format rel files) db 'SYS' db 'TX#' db 'ZIP' db 'ZIP' ; Spares, for user configuration db 'ZIP' db 0 ; Table end marker START: ld (STACK),sp ; Keep stack contents ld sp,STACK ; Set up local stack ld hl,(Z3EADR) ld a,l or h ld de,NOTZ3 jp z,EXEUNT ; Assume 0000H ENV is non-Z3 call Z3INIT ld hl,FCB1+1 ld a,(hl) cp ' ' jp z,HELPER ld a,'/' cpi jr nz,nothlp cpi jr nz,nothlp cpi jp nz,HELPER ; Help only if exactly "//" or "// " nothlp: call GETCRT ; Point current CRT descriptor inc hl ; Bump to "usable lines" inc hl ld a,(hl) ld (PAGSIZ),a ; Store locally ld hl,ENDU ; Init. 3 words for re-entrance ld (NAMPTR),hl ld (NAMPT1),hl ld hl,65535 ld (RCNT),hl inc hl ld (MEMCNT),hl ; Zero the member count ld de,FCB1 ; Point target FCB call Z3LOG ; Log in as per Z3's parse ; ; Set defaults: ; xor a ld (de),a ; Force current drive ld (PAGLNS),a ; Init. line count to 0 ld a,(DDEF) ld (CDELAY),a ; Delay ld hl,(QDEF) ld (QFLAG),hl ; Quiet and paging ld a,3 ld hl,TBUFF+1 call PARGET jr z,parse3 ; No 3rd parm push hl ; Save ptr to 3rd parm. ld a,'Q' call PARCHR ; Search string for Quiet opt. jr z,noqopt ld a,(QFLAG) cpl ; Flip if option ld (QFLAG),a ; Save flag noqopt: pop hl push hl ; ld a,'P' call PARCHR ; Search string for Page opt. jr z,nopopt ld a,(PFLAG) cpl ld (PFLAG),a ; Save flag nopopt: pop hl ld a,(hl) cp '/' ; Leading slash? jr nz,parse1 inc hl ; Skip it parse1: ld a,(hl) or a ; End of command tail? jr z,parse3 ; Exit loop if so call ISDIGIT ; Delay? jr z,parse2 inc hl jr parse1 parse2: ld (CDELAY),a ; Save delay parse3: call LBROPN ; Set up the library name buffer ld (LBRFLG),a ; Save extract/type flag jr nz,START2 ; Type only ld hl,(MEMCNT) ; Get member count ld a,l ; Get member count lsb or h ; Any members? ld de,NFOUND jp z,EXEUNT ; No - exit ; fall thru START2: ld de,SIGN1 ; Give basic instructions ld a,(QFLAG) or a call z,TSTRC ld a,(LBRFLG) or a jr nz,DUMP ; Type only ; ; Per component loop ; NEXT: call INITLP ; Initialize the "next" loop call GETMEM ; Get next member FCB jp c,EXIT ; All done... call LBRSET ; Set up to read the library file ; ; Input setup, do the extraction and/or unsqueezing ; DUMP: call TSTTYP call UFNAME ; Display input filename if not LBR call GET2HL ; Get the first 2 bytes from the file jp nz,ZERPRT ; Special processing for 0-length file ld a,076h cp l jp nz,ASPRT ; Not compressed - print an ASCII file ld a,h inc a jr z,DUMPSQ ; Squeezed, dump it inc a jr z,DUMPCR ; Crunched, dump it inc a jp nz,ASPRT ; Not compressed - print an ASCII file ; ; Output from a CRLZH compressed file ; call NMSHOW ; Show actual name etc ld hl,(NAMPTR) ; Free memory area, above names call UNL ; Rel jr DUMPC1 ; ; Output from a crunched file ; DUMPCR: call NMSHOW ; Show actual name etc ld hl,(NAMPTR) ; Free memory area, above names call UNC ; Rel DUMPC1: ld de,BADFILE jp c,DONEM jp DONE ; ; Output from a squeezed component ; DUMPSQ: call GET2HL ; Get and discard the next 2 bytes call NMSHOW call SQSETU ; Setup the squeezed file ; ; List a squeezed component ; SQLOOP: call GETSQB ; Get a byte from the file jp c,DONE ; Eof - get next file name in queue call CRTYPE ; Else print the char jr SQLOOP ; And loop for more ;..... ; ; Show UNSQ/UNCR member name, etc. Optionally revise output name. ; NMSHOW: ld de,FFSEP ld a,(QFLAG) or a call z,TSTR ; Make the file-file seperator ld hl,OUTFCB+1 push hl ld b,11 NMSHW1: ld (hl),' ' ; Pre-blank the output name inc hl djnz NMSHW1 ld (hl),b pop de ; Point DE at OUTFCB+1 ld b,8 ; Size of name field ;....................................................................... ; ; This section types the filename to the console and puts it into ; "OUTFCB". A null character terminates all header processing. Other ; characters after filename are ignored, unless they follow a "[" ; character. These will be echoed to the console, until either a null ; character is detected (terminate processing) or a "]" character is ; detected (start scanning for null again). ; NMSHW2: push de ; Filename area of OUTFCB call LBRGET ; Get character from the file pop de ; Restore pointer or a ; Check for null jr z,NMSHW8 ; If found, terminate header processing cp '[' ; "[" ? jr z,NMSHWP ; If so, go display "stamp" text cp '.' ; Was the character a "."? jr nz,NMSHW3 ; If not update cnt, display character, ; Put in FCB call QCTYPE ; A "." gets displayed, but not put into ; FCB ld b,3 ; Also causes the filename char counter ; To "3" jr NMSHW2 ; Continue processing filename ext chars NMSHW3: inc b ; Check filename character limit dec b ; jr z,NMSHW5 ; If down to zero, exit this section call QCTYPE ; Else display the character inc de ; Bump filename dest pntr dec b ; Count it jr NMSHW2 ; Continue filename processing ; ;....................................................................... ; ; Filename has been fully processed. Continue header analysis. ; NMSHWA: call QCTYPE ; (entry here to display extra character) NMSHW4: call LBRGET or a ; Loop swallows characters until either jr z,NMSHW8 ; A null or a "[" char is detected ; NMSHW5: cp '[' jr nz,NMSHW4 NMSHWP: ld a,' ' ; "[" found. Insert extra blank for ; Aesthetics call QCTYPE ld a,'[' ; But display the "[" char as well NMSHW6: call QCTYPE call LBRGET cp ']' ; Loop to display characters to the con- jr z,NMSHWA ; sole until a null or a "]" is found or a jr nz,NMSHW6 ; ;....................................................................... ; ld a,(QFLAG) or a ret nz NMSHW8: jp CRLFLF ; Done with all header processing ;..... ; ; Output an unsqueezed file/component ; ZERPRT: ld (ZERLEN),a ; Save zero length file flag ASPRT: call QCRLF call QCRLF ld a,(ZERLEN) or a jr nz,DONE ; Don't type anything for 0-length file ld a,l ; Print push hl call CRTYPE ; First pop hl ; (file out clobbers hl) ld a,h ; Two ASPRT1: call CRTYPE ; Bytes call LBRGET ; Get a byte from the file jr z,ASPRT1 ; Not eof, print and get more jr DONE ;..... ; ; Done, send message ; DONEM: call TSTR ; ; Done, no message ; DONE: ld sp,STACK ; SP uncertain here - reset the stack ld a,(LBRFLG) or a jp z,NEXT call TLOOP jp DUMP ;..... ; ; Initialize the "next" loop ; INITLP: ld a,(PAGLNS) or a jr nz,INITL1 ; Paging was not stopped INITLH: ld (LINCN1),a ; Else clear for fresh start ld a,(PAGSIZ) ld (PAGLNS),a ; Restart any page pauses INITL1: ld hl,ZEROS ; Fill flag area with zeros ld b,LASTZ-ZEROS ; Count of zeroes to load ; ; Fill (HL) up for (B) with zeroes ; xor a INITL2: ld (hl),a ; Put a byte inc hl ; Next location djnz INITL2 ; Fill all 11 bytes ret ;..... ; ; Open the FILENAME.LBR file and the MEMBER.EXT files, returns Z-flag ; for library extraction, NZ for pure type ; LBROPN: ld bc,12 ; Field size for .LBR file ld hl,FCB1 ; Move first file FCB ld de,LBRFCB ; To LBRFCB ldir xor a ; Set ext & rec # to 0 for proper open ld (LBREXT),a ld (LBRSNO),a ld hl,FCB2+1 ; Source is member FCB name, no drive ld a,(hl) ; First member character cp ' ' ; Is it a space or control ? jp c,HELPER ; Control, exit with help jr z,TFILE ; Space, type one file only ld de,LBRBUF ld a,SETDMA ; Do all I/O thru this buffer call SYS ld de,MEMNAM ; Move FCB2 to MEMNAM ld bc,11 ; Bytes to move ldir ; Member name to local area ; ; Open the .LBR file ; ld hl,'BL' ld (LBRTYP),hl ; Force .LBR type ld a,'R' ld (LBRTYP+2),a call FOPNLB ; Open .LBR file inc a ; Open ok? jp z,NOFILE ; Failure, abort with help ; ; Read the first record of the library directory ; call LBREAD ; Read a sector ld hl,(LBRBUF+14) ; Get directory size ; ; Test for a valid library file ; ld a,(LBRBUF) or a ; Test first byte ld de,CORRPT jp nz,EXEUNT ; Non-zero, bad .LBR file ; ; Read the next library directory record ; LBROP5: push hl ; Save DIRSIZE call nz,LBREAD ; Read a sector, except 1st pass ; ; Search for the member name in the library directory ; ld hl,LBRBUF ; Process first entry call ADDMEM ; To memory buffer ld hl,LBRBUF+20H ; Process second entry call ADDMEM ; To memory buffer ld hl,LBRBUF+40H ; Process third entry call ADDMEM ; To memory buffer ld hl,LBRBUF+60H ; Process fourth entry call ADDMEM ; To memory buffer pop hl ; Count of dir entries dec hl ; -1 ld a,h ; Zero directory entries left ? or l jr nz,LBROP5 ; No read another directory sector ret ;..... ; ; The second parameter is missing, just type the main file, returns NZ ; flag to signal no library extraction ; TFILE: ld de,FCB1 ; Get afn FCB @ 005Ch call INITFCB ; Initialize ld hl,ENDU ; Point HL at free RAM ld (WBUFF),hl ; Stow the pointer for later call WILDEX ; Expand afn to buffer jp z,NOFILE ; Contrary to source, Z=failure ld (WCOUNT),hl ; Stow count ex de,hl ; Over to DE ld hl,(WBUFF) ; Get buffer start ld bc,16 ; 16 bytes/entry WBLOOP: add hl,bc ; Compute end of buffer dec de ld a,e or d jr nz,WBLOOP ld (NAMPTR),hl ; Store as start of UNC's buffer ld de,LBRBUF ; Now set up DMA to do all I/O ld a,SETDMA ; through this buffer call SYS TLOOP: ld hl,(WCOUNT) ; "per component loop" :-) ld a,l ; Test for no more files. or h jp z,EXIT ; If so, break out & quit dec hl ; Otherwise WCOUNT = WCOUNT-1 ld (WCOUNT),hl ; Stow new value ld de,LBRFCB ; Point working FCB push de ; Save on stack ld hl,(WBUFF) ; Point next nfilenametyp@@@@ ld bc,16 ; Length of move ldir ; Do it, get new pointer back ld (WBUFF),hl ; Stow it pop de ; Restore working FCB call INITFCB ; Initialize for open call call FOPEN ; Do the file open inc a jp z,NOFILE inc de ex de,hl ld de,MEMFCB ld bc,11 ldir ; Name to memnam for checking call INITLP ; Other one pass initializers or 0FFh ; Set NZ flag jr INITPT ; Set up pointers, leave NZ flag ;..... ; and return to caller... ; LBRSET: ld a,(QFLAG) or a jr nz,LBRST1 ; Quiet call CRLF ld de,MBRMSG call TSTR LBRST1: ld hl,MEMFCB ; Index member FCB call FNAME ld e,(hl) ; Get member starting record LSB inc hl ld d,(hl) ; And MSB push de ; Save inc hl ld e,(hl) ; Get member size LSB inc hl ld d,(hl) ; And MSB ex de,hl ; Into 'HL' inc hl ; +1 ld (RCNT),hl ; Save it in record count pop hl ; Restore starting record number ld (LBRRNO),hl xor a ld (LBRRNO+2),a ; Set random rcd no ld (LBREXT),a call FOPNLB ; Open the LBR file again inc a jp z,PREEOF ; Should not happen ld a,FRDRAN call SYS ; Do a random read to put in sequential or a jp nz,PREEOF ; No such record ; ; Initialize pointers to read from LBRFCB ; A, HL (but not flags) ; INITPT: ld a,080h ld (CHRCNT),a ; Set char count to force read ld hl,LBRBUF-1 ld (BUFPTR),hl ret ;..... ; ; Get a byte from the .LBR member. GETBYT for UNCREL use ; A,F,D,E,H,L ; GETBYT: GLZHUN: LBRGET: ld a,(CHRCNT) ; Get pointer inc a ; Point to next position ld (CHRCNT),a ; Put pointer back jp p,LBRGE1 ; Buffer not empty call ZBUFF ; Empty, reset pointers, read sector ld hl,(RCNT) ; Get record count dec hl ; -1 ld (RCNT),hl ; Set new record count ld a,l or h jr z,LBRGE2 ; If all records read call LBREAD ; Read a sector or a jr nz,LBRGE2 ; If read was unsuccessful LBRGE1: ld hl,(BUFPTR) inc hl ld (BUFPTR),hl ld a,(hl) ; No - get the next byte cp a ; Set zero - no error ret ;... ; LBRGE2: or 0FFh ret ; Return non-zero for error ;..... ; ; Zero the buffer pointers (for reaccess from start) ; ZBUFF: xor a ; Empty, read another record ld (CHRCNT),a ; Clear the character count ld hl,LBRBUF-1 ld (BUFPTR),hl ret ;..... ; ; Read a sector from library file ; LBREAD: ld a,FREAD ld de,LBRFCB ; LBR FCB jp SYS ; Read a block, and exit ;..... ; ; Get 2 bytes from input file into HL ; GET2HL: call LBRGET ; Get a byte from the input file ret nz ; May be an empty component push af call LBRGET ; Get a byte from the input file ld h,a pop af ld l,a ret ;..... ; NOFILE: ld de,NOFMSG jr EXEUNT ;..... ; HELPER: ld de,SIGNON ; Give name and version call TSTR ld de,USAGE ; Give help menu call TSTRC call COMNAM ; Show actual name of program ld de,USAGE1 call TSTR call COMNAM ld de,USAGE2 call TSTR ld a,(QDEF) call ONOFF ld de,USAGE3 call TSTR ld a,(PDEF) call ONOFF jr EXIT ;..... ; PREEOF: ld de,EOFMSG ; ; Error exit, with message (DE)^ ; EXEUNT: call TSTRC ; Print message EXIT: ld sp,(STACK) ; Restore original stack ret ; --exit-- to cp/m ;..... ; ; Output to CRT. Entry name "out" for UNC or UNCREL use ; UNCOUT: ; RMAC-compatible, unlike "OUT" PLZHUN: CRTYPE: cp 01Ah jp z,DONE ; EOF on 01Ah for ASCII output and 7Fh ; Make sure its ASCII push af ; Save the character call CRTYP4 ld a,(CDELAY) call ISDIGIT call z,DDELAY pop af push af call COUT pop af ; Restore character cp 0Ah ; Was it a line feed ret nz ; No - continue call GETWHL jr nz,CRTYP3 ; Jump around the line count tests ld a,(LINCNT) ; Advance line counter inc a ld (LINCNT),a ld b,a ; Line number in 'B' ld a,(MAXLIN) ; Max number of lines to type or a ; Test flag jr z,CRTYP3 ; If null function cp b ; Else compare to max lines ld de,EXCESS jp z,DONEM ; Announce too much CRTYP3: ld a,(PFLAG) ; Paging? or a jr z,CRTYP4 ; No. ld a,(LINCN1) ; Get line counter ld b,a ; Keep in 'B' ld a,(PAGLNS) ; Number of lines per page dec a ; Decrement and test flag jp m,CRTYP4 ; Function is null cp b ; Compare to lines per page jr nc,CRTYP4 ; If not at maximum count xor a ; Clear lines counter ld (LINCN1),a ld de,MORE call TSTR ; Announce the pause call PAUSE ; Get input from console cp ' '-1Ah ; Space for line at a time? jr nz,CRTP3A ld a,b ; Get original line count back dec a ; And set to "one line left" ld (LINCN1),a CRTP3A: ld de,CLEAN call TSTR ; Clear out the "[more]" CRTYP4: ld a,CIO ; BDOS function ld e,0FFh ; BDOS function call SYS ; Direct console in call cp 1Ah jr nz,NOTPAG ld a,(PAGLNS) or a ld a,(PAGSIZ) jr z,PAGDR xor a PAGDR: ld (PAGLNS),a ret NOTPAG: call ISDIGIT jr nz,NOTDIG ld (CDELAY),a ret NOTDIG: call PSCHK cp 'S'-40h ; CTL-S to pause? jr z,PAUSE and 5Fh cp 'S' ret nz ; Not CTL-S, return ; ; Returns input -01Ah. Aborts on c,C,^C or k,K,^K - next on CTL-X, etc. ; PAUSE: ld a,CIO ; BDOS function ld e,0FFh call SYS ; Direct console in call or a ; Was a key entered ? jr z,PAUSE ; Not yet call PSCHK sub 01Ah ret nz ; Not ^Z console entr ld (PAGLNS),a ; Disable pauses on ^Z ret ;..... ; ; Pause check for special characters ; PSCHK: cp 'C'-40h ; Want to abort? jr z,PSCHK2 ; If yes, quit cp 'K'-40h jr z,PSCHK2 cp 'X'-40h ; Jumping to next file? jr z,PSCHK1 cp ' ' ; Space for "line at a time"? ret z and 5Fh ; Insure in upper case cp 'C' jr z,PSCHK2 cp 'K' jr z,PSCHK2 call ISDIGIT jr z,DDELAY cp 'X' ret nz ; If not, keep going PSCHK1: call CRLF jp DONE ; Next file on CTL-X PSCHK2: ld de,ABRMSG call TSTRC jp EXIT DDELAY: sub '0' ret z ld b,a DDLP1: call GETSPEED ld hl,0 ld de,500/4 DDLP2: add hl,de dec a jr nz,DDLP2 DDLP3: ex (sp),hl ex (sp),hl dec hl ld a,l or h jr nz,DDLP3 dec b jr nz,DDLP1 ret ;..... ; COUT: ld e,a ; Save output character cp TAB jr z,COUT2 ; Expand a tab cp CR ; Carriage return jr nz,COUT0A xor a ; CR sets COLUMN to 0 jr COUT1A COUT0A: cp BS ; Is char a backspace? jr nz,COUT0B ld a,(COLUMN) ; Backspace sets COLUMN back one dec a jr COUT1A COUT0B: cp ' ' ; jr c,COUT1B ; Other controls don't affect COLUMN COUT1: ld a,(COLUMN) ; Advance column counter inc a COUT1A: ld (COLUMN),a COUT1B: call COUT3 ; Test control ld a,e ; Get character back jp z,CTYPE ; Else print the space ret ; Return to caller ;... ; COUT2: ld e,' ' call COUT1 ; Print a space ld a,(COLUMN) and 7 ; At next tab stop ? jr nz,COUT2 ; Yes, continue ret ;... ; COUT3: ld a,(CTLFLG) ; Get controls active or a ; Test flag ret z ; Return if not ld a,e ; Get output char cp ' ' jr nc,COUT4 ; Not control, clear flags cp CR ret z cp BS ret z cp BELL ret z cp LF ret ; Return with Z-flag set for linefeed ;... ; COUT4: cp a ; Set Z-flag ret ;..... ; ; Test for type-able file TSTTYP: ld a,(TYPFLG) ; Get test flag or a ; Test it ret z ; Return if ok to type all types ld b,3 ld hl,BADTBL-3 ; Index bad file type table TSTTY1: inc hl ; Next table address pointer djnz TSTTY1 ; Do until at next table entry ld a,(hl) ; Get a byte or a ; End of table ret z ; Yes - ok to type this one ld b,3 ; 3 char extension ld de,MEMFCB+8 ; Index file name extension TSTTY2: ld a,(de) ; Get a byte from extension and 7Fh ; Make sure its ascii cp (hl) ; Same as in table jr z,TSTTY3 ; Match, continue scan ld a,(hl) cp '?' ; '?' in table matches all jr nz,TSTTY1 ; No match, next entry TSTTY3: inc hl ; Bump table address pointer inc de ; Bump extent pointer djnz TSTTY2 ; Continue for 3 chars ld hl,MEMFCB+8 ; User name ld de,CANT call TSTR ; "can't type a '" ld b,3 ; 3 byte file type TSTTY5: ld a,(hl) ; Get byte call CTYPE ; Give a chance to abort here inc hl ; Next byte djnz TSTTY5 ; Type all 3 bytes ld de,CANT2 ; "' FILE ",CR,LF jp DONEM ; And do next file ;..... ; ; This part is adapted from TYPE109 by David Rand ; GETSQB: ld a,(RPTCNT) ; Get repeat flag or a ; Any chars to repeat ? jr nz,GETSQ1 ; Yes - get and count call NXTCH ; Get a character ret c ; Eof cp 90h ; Repeat byte flag jr nz,GETSQ3 ; No - call NXTCH ; Yes - get another character ret c ; EOF or a ; If null jr nz,GETSQ2 ld a,90h ; Dle is encoded as dle,0 ret ; Return with it, carry clear ;... ; GETSQ2: dec a ; Bump counter twice jr z,GETSQB ; 1 repeat is a null event GETSQ1: dec a ld (RPTCNT),a ; Set repeat count ld a,(RPTCHR) ; Return repeat character GETSQ3: ld (RPTCHR),a ; Set repeat char or a ; Clear any carry, not EOF ret ;..... ; ; Next decoded byte from file, ignoring repeat characters ; NXTCH: ld de,0 ; Pointer @ star of text ld a,(CHAR) ld c,a NXTCH1: ld a,(NUMFLT) or a jr nz,NXTCH2 push de ; Save 'DE' call LBRGET ; Get a byte from the input file jp nz,PREEOF ; Not expecting an eof here pop de ; Restore 'DE' ld c,a ld a,8 ; 'A' is counter NXTCH2: dec a ; Bump count ld (NUMFLT),a ; Save it ld a,c ; Get character rrca ; Shift right ld c,a ; Save character push af ; Save character ld hl,XLATBL ; Index ram area add hl,de ; HL=HL+(4*DE) add hl,de add hl,de add hl,de pop af ; Restore char jr nc,NXTCH3 ; If no carry inc hl inc hl NXTCH3: ld e,(hl) inc hl ld d,(hl) ld a,d and 80h jr z,NXTCH1 ld a,c ld (CHAR),a ld a,d cp 0FEh ; Special end of file ? ld a,1Ah ; Yes - return with EOF character scf ret z ; And carry for EOF ld a,e ccf cpl ret ; With carry clear, not EOF ;..... ; ; Set up the translation table for the squeezed file ; SQSETU: call GET2HL ; Get 2 bytes from input file into HL ld de,XLATBL ; Index ram area SQSET1: ld a,h ; Get MSB or l ; Test LSB ret z push hl ; Save table size counter push de ; Save ram area index call GET2HL ; Get 2 bytes from input file into HL pop de ; Restore ram area index ex de,hl ; Into 'HL' ld (hl),e ; Save the LSB byte inc hl ld (hl),d ; And MSB byte inc hl push hl ; Bump & save pointer call GET2HL ; Get 2 bytes from input file into HL ex de,hl ; Into DE pop hl ; Restore pointer ld (hl),e ; Save the LSB byte inc hl ld (hl),d ; And the MSB byte inc hl ; Bump pointer ex de,hl ; Restore pointer to 'DE' pop hl ; Restore table size counter dec hl ; Decrement it the byte count jr SQSET1 ; And loop for more ;..... ; ; Add a library member to the name queue buffer - only if a match to ; MEMNAM ; ADDMEM: ld a,(hl) ; Get first byte of member entry or a ret nz ; Non zero - must be deleted or null entry ; inc hl ; Go to the second byte push hl ; Save source address for coming 'LDIR' push hl ; Save it again ld b,11 ; 11 byte filename ADDME0: ld a,(hl) ; Get byte cp ' ' jr nz,ADDME1 ; Not space - continue inc hl ; Next char djnz ADDME0 ; Continue searching for spaces pop hl ; Must be the directory jr ADDME4 ; So abort this one ;... ; ADDME1: pop hl ld de,MEMNAM ; Index member FCB name ld b,11 ; 11 byte compare ADDME2: ld a,(de) ; Get byte from member name FCB cp '?' ; '?' matches all entries jr z,ADDME3 ; Match cp (hl) ; Same as member entry? jr nz,ADDME4 ; No - abort this process ADDME3: inc hl inc de djnz ADDME2 ; Compare all 11 bytes ld de,(NAMPTR) ; Get destination address pop hl ; Get source address back again ld bc,15 ; Move 15 byte block into memory ldir ld (NAMPTR),de ; Save name pointer ld hl,(MEMCNT) ; Get member number count inc hl ; Bump it up one ld (MEMCNT),hl ; Set next member memory address ret ADDME4: pop hl ; Balance stack ret ;..... ; ; Get the next member name from the memory name queue buffer, return ; carry set if no more members left ; GETMEM: ld hl,(MEMCNT) ; Get member count ld a,l or h scf ret z ; Zero count - set error condition dec hl ; Bump count down ld (MEMCNT),hl ; And reset member count ld hl,(NAMPT1) ; Get source address for move ld de,MEMFCB ; Get destination for move ld bc,15 ; 11 byte filename + 4 byte file info ldir ; The block ld (NAMPT1),hl ; Reset the next source address or a ; Clear any cy ret ;..... QCRLF: ld a,(QFLAG) or a jr z,CRLF ret ; ; Double CRLF to console ; CRLFLF: call CRLF ; ; CR and LF to console ; Uses A ; CRLF: ld a,CR call CTYPE ld a,LF ; Character to console, preserve all registers ; CTYPE: push af push de ld e,a cp LF jr nz,CTYPE1 ld a,(LINCN1) inc a ld (LINCN1),a CTYPE1: ld a,CIO ; Direct console output call SYS pop de pop af ret QCTYPE: ld c,a ; Quiet CTYPE ld a,(QFLAG) or a ret nz ld a,c jr CTYPE ;..... ; ; CRLF, then fall through to TSTR ; TSTRC: call CRLF ; ; Output string (DE)^ ; Uses A,F ; TSTR: push de TSTR1: ld a,(de) or a jr z,TSTRX call CTYPE inc de jr TSTR1 ; TSTRX: pop de ret ;..... ; ; Open LBRFCB file ; Uses A,F,D ; CP/M 3 apparently does not allow ambiguous file opens, so we ; screen them out for the benefit of Z3PLUS users FOPNLB: ld a,GETVER call SYS cp 30h ld de,LBRFCB ; Point LBR's FCB jr c,FOPEN ; If not CPM 3, ambiguous is OK push de ; Save it on the stack push bc ; Save incoming BC ld b,11 ; Counter in B AFNLP: inc de ; Advance to to char. ld a,(de) ; Get it sbc a,'?' ; A = 0 if ambiguous char.found cpl ; Now A = FFH if ambiguous jr z,AFNFND ; Break loop if ambiguous djnz AFNLP ; Otherwise loop around dec b ; Cheap NZ flag indication AFNFND: pop bc ; Restore registers pop de ret z ; Return with A = FFH if amb. ; ; Open file (DE)^, return BDOS response in (A) ; Uses A,F ; FOPEN: ld a,OPEN ; ; Execute BDOS function (A), preserve registers ; SYS: push hl push de push bc ld c,a call BDOS pop bc pop de pop hl ret ;..... ; UFNAME: ld a,(LBRFLG) ; Are we in LBRland? or a ret z ; Just return if so call QCRLF ; Otherwise turn up a line ld hl,LBRFCB+1 ; Point to "source" filename FCB ; and fall through to FNAME ; List filename from FCB (HL)^ ; Uses A,F,H,L ; FNAME: push bc ld b,8 ; Size ofyte ; FNAME1: ld a,(hl) and 07Fh cp ' ' call nz,QCTYPE ; Non space - print it inc hl ; Next character djnz FNAME1 ; Continue... ld a,'.' call QCTYPE ; Print seperator ld b,3 ; 3 character extent ; FNAME2: ld a,(hl) ; Get byte and 07Fh cp ' ' call nz,QCTYPE ; Non space - print it inc hl ; Next char djnz FNAME2 ; Continue... pop bc ret ;..... ; ; ; Print the actual name of this program if we can determine it, ; otherwise print "ZLT", with leading and trailing spaces. ; Uses all registers. ; COMNAM: ld a,' ' ; Print a space call CTYPE call GETEFCB ; Get ZCPR3's External FCB in HL ld de,ZLTNAM ; Point at "'ZLT ',0" jr z,TSTR ; Print it if no EFCB ld b,8 ; Otherwise load down-counter COMNLP: inc hl ; Bump pointer to character ld a,(hl) ; Character into A and 7Fh ; Strip to ASCII cp ' ' ; Is it a space? jp z,CTYPE ; Just type that and return call CTYPE ; Otherwise type the non-space djnz COMNLP ; and loop if not done ld a,' ' ; This does the trailing space jp CTYPE ; for 8-character names only ;..... ; ; Type "on" or "off" depending on A register ; ONOFF: ld de,ONMSG or a jp z,TSTR ld de,OFFMSG jp TSTR ;..... NFOUND: db 'Member ' ; NOFMSG: db 'Not found',CR,LF,0 SIGNON: db CR,LF,'ZLT Version ',VER/10+'0','.',VER MOD 10+'0' ; db ' by Falconer/Morgen/Wilson' db CR,LF SIGN1: db ' ^S pauses, ^C aborts, ^X goes to next file,' db ' ^Z disables/restores paging, ' db CR,LF db ' Space goes to next line, 0-9 sets inter-character' db ' delay, others page.',0 USAGE: db CR,LF,' Types normal, squeezed, crunched, LZH' db ' files and LBR members, wildcard (*,?)',CR,LF db ' filespecs permitted.',CR,LF,LF db 'Syntax:',CR,LF,0 USAGE1: db '[du: or dir:]', db 'afn.typ [. opts]',CR,LF,0 USAGE2: db '[du: or dir:]', db 'lbrname afn.typ [opts]',CR,LF db 'Options:',CR,LF db ' 0-9 - set speed',CR,LF db ' Q - quiet ',0 USAGE3: db ' P - paging ',0 ONMSG: db 'on',cr,lf,0 OFFMSG: db 'off',cr,lf,0 EOFMSG: db BELL,'Early EOF,' ; Fall through to next msg ABRMSG: db CR,LF,'<>',0 CLEAN: db CR,' ',CR,0 ; Erase the "more" FFSEP: db ' --> ',0 ; File-file seperator CORRPT: db 'LBR file corrupt',0 MBRMSG: db 'Member: ',0 MORE: db CR,'[more] ',0 NOTZ3: db BELL,'ZCPR3 required',0 ZLTNAM: db 'ZLT ',0 CANT: db BELL,CR,LF,'Can''t type a "',0 CANT2: db '" file',CR,LF,0 BADFILE:db BELL,CR,LF,'Corrupt or unknown format file',0 EXCESS: db BELL,'Too long, download file',CR,LF,0 ;----------------------------------------------------------------------- DSEG ; ; Temporary storage area ; BUFPTR: ds 2 CHRCNT: ds 1 ds 1 LINCN1: ds 1 ; Lines printed since [more] PAGLNS: ds 1 ; Ln/page before pause, 0 causes setup PAGSIZ: ds 1 ; Lines per page, 0 = no pauses CDELAY: ds 1 NAMPT1: ds 2 ; NAMBUF, init. to ENDU NAMPTR: ds 2 ; NAMBUF, init. to ENDU RCNT: ds 2 ; Maximum. record count for type, init. 65535 LBRFLG: ds 1 QFLAG: ds 1 PFLAG: ds 1 WCOUNT: ds 2 WBUFF: ds 2 MEMCNT: ds 2 LBRFCB: ds 9 LBRTYP: ds 3 LBREXT: ds 20 ; Lbrfcb+12; file extent LBRSNO: ds 1 ; Lbrfcb+32; sector # LBRRNO: ds 3 ; Lbrfcb+33; random rcd no. MEMFCB: ds 16 MEMNAM: ds 16 OUTFCB: ds 13 ; ; Mark start of zeroed area, per component loop ; ZEROS: NUMFLT: ds 1 CHAR: ds 1 RPTCHR: ds 1 ; Char to repeat RPTCNT: ds 1 ; Count of repeat characters LINCNT: ds 1 ; Number of lines printed total COLUMN: ds 1 ; Crt column position ZERLEN: ds 1 LASTZ: ds 64 ; Mark end of zeroed area, stack space STACK: ds 2 ; Store entry stack pointer LBRBUF: ds 128 ; Member read buffer XLATBL: ds 258*4 EXTRN ENDU end