TITLE 'ZLT (Z-system Library Typer), November 1, 1989' ; Program: ZLT (Z-system Library Typer) ; Author: Carson Wilson (this version) . ; Sysop, Antelope Freeway, Chicago, 312/764-5162. ; Assembly: Z80ASM, SLRNK, WILDEX, UNC, PARMLIB, SYSLIB, Z3LIB. ; Version: 1.3 ; VER equ 13 ; Current version number ; ; 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) ; ; Assembly time configurable areas. Each increases COM file size. ; LIMITL equ YES ; Yes allows output line limits ; (if wheel byte is not set) LIMITT equ YES ; Yes allows file type restriction DUSPEC equ YES ; Use DU/DIR-style drive/user specs? ; (otherwise forces current DU) WHLDU equ YES ; Make DU specs wheel-dependent? ACREDIT equ NO ; Want author names in sign-on? IF WHLDU AND NOT DUSPEC OOPS equ NOVALUE ; MUST HAVE DUSPEC YES IF YOU WANT WHLDU YES! ENDIF ; WHLDU AND NOT DUSPEC ; Defaults (no increase in COM size). NOCTRL equ YES ; Yes to prevent control char. output QUIET equ NO ; Display "raw" output PAGE equ YES ; Page (pause) output ; ; Configurable values. ; ;LNMAX equ 16H*3 ; 0 for no limit, else max file size (to 255) 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 ; CSEG ; EXTRN PARGET, PARCHR ; From PARMLIB1.LBR (see) EXTRN WILDEX ; Sigi Kluger wildcard expander EXTRN Z3INIT,GETWHL,GETCRT,GETEFCB ; From Z3LIB 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! IF DUSPEC EXTRN Z3LOG ; From Z3LIB EXTRN PUTUD,GETUD ; From SYSLIB ENDIF ; DUSPEC ; PUBLIC GETBYT,UNCOUT ; Referenced by UNC PUBLIC GLZHUN,PLZHUN ; Referenced by UNL ; ZLT: jp START db 'Z3ENV',1 Z3EADR: dw 00 ; ; Configuration values, even if unused via "limit" options ; 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. IF LIMITT ; 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 ENDIF ; LIMITT START: ld hl,0 ; Set up HL for add to stack ld (MEMCNT),hl ; Zero the memory count ld (STACK),sp ; Keep stack contents ld sp,STACK ; Set up local stack IF DUSPEC call PUTUD ; Stash entry DU for exit ENDIF ; DUSPEC 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 ld de,FCB1 ; Point target FCB ; IF DUSPEC ; "Parse" the command line IF WHLDU call GETWHL call nz,Z3LOG ; Non-wheels get current DU only ELSE ; IF NOT WHLDU call Z3LOG ; Log in as per Z3's parse ENDIF ; WHLDU ENDIF ; DUSPEC ; ; 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 a,(QDEF) ld (QFLAG),a ; Quiet ld a,(PDEF) ld (PFLAG),a ; Page ld a,3 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,(QDEF) 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,(PDEF) cpl ld (PFLAG),a ; Save flag nopopt: pop hl ld a,(hl) cp '/' ; Leading slash? jr nz,parse1 inc hl ; Skip it ld a,(hl) parse1: call ISDIGIT ; Delay? jr z,parse2 inc hl ld a,(hl) call ISDIGIT jr nz,parse3 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 name, version, credit 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: IF LIMITT ; Test the type of file call TSTTYP ENDIF ; LIMITT 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,0FFh cp h jr z,DUMPSQ ; Squeezed, dump it dec a ; To 0feh cp h jr z,DUMPCR ; Crunched, dump it dec a cp h 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 jp 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 jp 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 jp 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 jp 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 IF LIMITT inc de ex de,hl ld de,MEMFCB ld bc,11 ldir ; Name to memnam for checking ENDIF ; LIMITT call INITLP ; Other one pass initializers or 0FFh ; Set NZ flag jp 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 jp EXEUNT ;..... ; HELPER: ld de,SIGNON ; Give name, version, credit call TSTR ld de,USAGE ; Give help menu call TSTRC call COMNAM ; Show actual name of program IF WHLDU AND DUSPEC call GETWHL ld de,DUMSG push af push de call nz,TSTR ld de,USAGE1 call TSTR call COMNAM pop de pop af call nz,TSTR ENDIF ; WHLDU AND DUSPEC IF DUSPEC AND NOT WHLDU ld de,DUMSG push de call TSTR ld de,USAGE1 call TSTR call COMNAM pop de call TSTR ENDIF ; DUSPEC AND NOT WHLDU IF NOT DUSPEC ld de,USAGE1 call TSTR ENDIF ; NOT DUSPEC ld de,USAGE2 call TSTR xor a call INITLH jp EXIT ;..... ; PREEOF: ld de,EOFMSG ; ; Error exit, with message (DE)^ ; EXEUNT: call TSTRC ; Print message EXIT: IF DUSPEC call GETUD ; Restore entry conditions ENDIF ; DUSPEC 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 IF LIMITL ; Check for too many lines typed 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 ENDIF ; LIMITL 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 ;..... ; IF LIMITT ; 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 ENDIF ; LIMITT IF LIMITT 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 ENDIF ; LIMITT ;..... ; ; 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 jp 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 jp 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" jp 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 ;..... ; NFOUND: db 'Member ' ; NOFMSG: db 'Not found',CR,LF,0 SIGNON: db CR,LF,'ZLT Version ',VER/10+'0','.',VER MOD 10+'0' IF ACREDIT db ' by Falconer/Morgen/Wilson' ENDIF ; ACREDIT 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 IF DUSPEC DUMSG: db '[du: or dir:]',0 ENDIF ; DUSPEC USAGE1: db 'afn.typ [. opts]',CR,LF,0 USAGE2: db 'lbrname afn.typ [opts]',CR,LF db 'Options:',CR,LF db ' 0-9 - set speed',CR,LF db ' Q - quiet',CR,LF db ' P - page',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 IF LIMITT CANT: db BELL,CR,LF,'Can''t type a "',0 CANT2: db '" file',CR,LF,0 ENDIF ; LIMITT BADFILE:db BELL,CR,LF,'Corrupt or unknown format file',0 IF LIMITL EXCESS: db BELL,'Too long, download file',CR,LF,0 ENDIF ; LIMITL ;----------------------------------------------------------------------- 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