;------------------------------------------------------------------------------ ; < History [recent] ==> See doc file for full history > ; ; Version 2.6 Bruce Morgen April 6, 1988 ; Introduced conditionals to create ZCPR3-compatible version which gets ; all its terminal data from the Z3 environment and accepts DU:/DIR: ; specs from the command line. This option requires assembly to a REL ; file and linkage with VLIB, Z3LIB and SYSLIB. Most linkers will ; leave a substantial vestigial DSEG at the end of the resulting COM ; file which can be safely deleted with a debugger and the SAVE command. ; The Z1 assembler (or Z80MR) cannot be used if ZCPR3 is equated TRUE. ; Use the "/6" option if using an SLR assembler, "/Z" with M80 (so you ; won't have to concern yourself at all with the ".Z80" directive, as a ; matter of fact, "M80 =QL25.AZM/Z" will work just fine, no renaming!). ; Linkage with L80 or the non-"virtual" SLR linker is tedious and will ; require a two passes, the first to determine the end of the CSEG, the ; second to create the COM file. DRI's LINK or Echelon's ZLINK are much ; more convenient because they automatically put the DSEG after the ; CSEG. If ZCPR3 is equated FALSE, the traditional QL assembly methods ; will work as before, resulting in a copy equivalent to version 2.5. ; ; IF RE-ASSEMBLING with "ZCPR3 EQU TRUE": ; Note that I use a beta release of the new Z80fied LIBs soon to be ; available from Echelon - although the old 8080-compatible versions ; SHOULD link in as-is, please don't count on that! For example, ; Z3LIB 1.3's rendition of the routine GETCRT trashes the BC register ; (it doesn't have to - just careless coding), so one or more GETCRT ; calls may have to be have to be bracketed by PUSH/POPs of BC for ; QL to work. That's the only bug that I KNOW to be a problem, but ; be careful, because there are so many versions of the LIBs extant ; in the various PD archives and on RCP/Ms. b/m April 6, 1988 ; ver 2.5 (sgg) 02-28-88 ; - Corrected a bug which prevented all previous versions from being able to ; uncrunch a file if the system's BDOS started at an address other than a ; page boundary or a page boundary plus six. This would cause an "unknown ; uncrunch error", which wasn't even the "correct" error message due to ; another bug in the error message reporting code (also fixed). ; - Eliminated the use of alternate registers and the associated EQUate. ; Use of the alternate registers conflicted with some systems. Removed ; redundant register saves and eliminated a subroutine level in the same ; same area (memory i/o routines). Also: ; - Added Wordstar-like ability to display control characters not otherwise ; handled (eg "02" in a file will display as "^B"). ; - Added ascii FF (formfeed) char to the "legitimate character" list, so ; documents with a leading formfeed won't come up in hex mode. ; - Changed most JP's to JR's in UNC.AZM, and removed the extra entrypoints ; and associated code not used by QL. ; ; ==> Many thanks to Ken Reid and Mike Greenhill. ; ; ver 2.4 (sgg) 01-25-88 ; To make QL a viable "online" utility: ; added BYE detect: adjusts memory limits and inhibits video attribute xmit ; checks wheel byte: inhibits system COM file and "core" dumps. ; continuously checks for ^S, etc while running remote. ; Stronger checking of user keyboard input; some synonyms added. ; Added M80 EQU to allow assembly under M80 / SLR Z80ASM. ; Used macros so terminal attribute sequences could be relocated to the beg- ; inning of the file (configuration section) where they logically should be. ; Other misc. changes. ; ; Note: Extensive documentation and history which used to be here and was ; completelety duplicated in the .DOC file has been removed and left ; in the DOC file only. All information relating to configurable equates ; has been left here, however. Also, all references to specific patch ; addresses have been eliminated, since the equates allow setting even ; more options and the file is being distributed with an assembler. ; Anyone who can't type "Z1 QL" probably can't patch the program either. ; (Assembly instructions have been added [see below]). ; ; ver 2.3 (njd) 12-27-87 ; ver 2.2 (njd) 12-12-87 ; Added TAB expansion capability. ; added core dumping option if no file or library name is given. ; added filename.ext to summary. ; added summary word count for text files. ; improved ws doc file handling ; better eof handling for files just larger than available memory. ; ;------------------------------------------------------------------------------ ; Quick look typer for reasonably sized libraried or unlibraried, ; crunched, squeezed & normal text and binary files, ; for z80 cpu's only under CP/M 2.0 or later. ; ; QL was written by: ; Nick Dobrinich ; 4337 West 48 ; Cleveland, OH 44144 ; Features: ; fast random access paging of libraried or stand-alone, crunched, squeezed ; or normal text files ; ddt-like display of binary files, crunched, squeezed or normal ; easy access to library members ; page numbering ; immediate jump to any page ; core dumping ; fast simple string searching for text and hex bytes within files and core ; for reasonably sized files or as much as can be entirely ram resident ; where 'reasonably sized' means: ; 50k for normal text files ; 50k for squeezed files after unsqueezing ; 28k for crunched files after uncrunching ; in a 62k system (BDOS at 0e200h). ; < Release > ; This code is placed in the public domain. ; Don't sell it. Don't send money. Don't sue me. Don't claim you wrote it. ; The code for uncrunching is copyright 1986 by Steve Greenberg and ; C.B. Falconer for private non-commercial use. They wrote it and I want ; to credit them for excellent work. Implementation time was less than two ; hours to add a working uncruncher to QL v1.6 without benefit of a linker. ; < Usage > ; ; ==> For full description of usage please refer to the QL25.DOC file. ; < Assembly > ; With "Z1" (supplied) - ; Leave file name "QL25.AZM" and make sure the assembler equate "M80" is set ; to FALSE. Type "Z1 QL25" to assemble. ; With "Z80ASM" (SLR) - ; Rename the file QL25.Z80 and set assembler equate "M80" to TRUE. ; Type "Z80ASM QL25" to assemble if ZCPR3 is FALSE. Otherwise ; type "Z80ASM QL25/6" - then (if you have DRI's LINK) type ; "LINK QL25,VLIB[S],Z3LIB[S],SYSLIB[S]" making note of the end ; address of the code (program) segment. You can then use a ; debugger (DDTZ and SID are the most convenient for this chore) ; to delete any part of the COM file above that address. Use of ; Use of L80 or the non-"virtual" SLR linkers is possible, but ; you'll have to do it in two passes, the first to determine ; where CSEG ends and the second with the "/D:nnnn" command set ; to the appropriate free address. This rather awkward ; methodology is detailed in the documentation for C.B. Falconer's ; "LT" program. ; With "M80" / "L80" or "LINK" ; Rename the file QL25.MAC and set assembler equate "M80" to TRUE, and delete ; the two semicolons near ".Z80" immediately below that. If ZCPR3 is FALSE, ; type "M80 =QL25/N" to assemble. Then type "L80 QL25/P:100,QL25/N/E" to link, ; or just "LINK QL25" (if you have DRI's LINK). If ZCPR3 is TRUE, type ; "M80 =QL25" and then (if you have DRI's LINK) type the line ; "LINK QL25,VLIB[S],Z3LIB[S],SYSLIB[S]" making note of the end address of ; the code (program) segment. You can then use a debugger (DDTZ and SID are ; the most convenient for this chore) to delete any part of the COM file ; above that address. Use of L80 or the non-"virtual" SLR linkers is ; possible, but you'll have to do it in two passes, the first to determine ; where CSEG ends and the second with the "/D:nnnn" command set to the ; approriate free address. This rather awkward methodology is detailed in ; the documentation for C.B. Falconer's "LT" program. ;============================================================================== QLVERSION EQU 26 ; <=== version #, keep up to date! FALSE EQU 0 ; TRUE EQU 0FFFFH ; Ok "true" val for Z1, Z80MR, M80, SLR Z80ASM ; (skirts the issue of NOT vs .NOT. for now) YES EQU 0FFH ; Byte value true (runtime flag only) ;................................ ; Choose your assembler! ; M80 EQU FALSE ; TRUE if using M80 or SLR Z80ASM ; FALSE to use Z1 assembler supplied ; ;; .Z80 ; <== Also remove the two ";"'s if using M80 ! ; ;...............................; ZCPR3 EQU FALSE ; For Z3-compatible version, ; linkage with VLIB/Z3LIB/SYSLIB required. ;============================================================================== ; ; < Customization > ; ; User customization equates ; Set to suit your terminal and preferences. DOSPLUS EQU FALSE ; TRUE if running C.B.Falconer's excellent dos+ ; ; FALSE for normal CP/M. ; ; This takes advantage of new bdos call 211 to print DE as a decimal number. ; QL is < 5k if running under DOS+, slightly > 5k under cp/m depending on ; which options are enabled. CLRSCR MACRO DB 1AH,0,0,0,0 ; Put byte sequence to clear the screen here ENDM ; ; Leave unused bytes zero. "1AH,0,0,0,0" or "ESC,'*',0,0,0" are common. LINES EQU 24 ; Terminal console lines. COLUMNS EQU 80 ; Terminal console columns. EXPANDTABS EQU TRUE ; TRUE to expand tab characters ; ; FALSE to send them right through ; ; If TRUE, tab characters encountered in the file being typed will be expan- ; ded into an appropriate number of spaces to bring the column count to a ; multiple of eight plus one (standard). You may set to "no" for miniscule ; time savings or for non-standard tab stops (if you know your hardware ; will support the tab expansion). ;.............................................................................. ; HALFINTENSITY EQU FALSE ; TRUE to display *.C?m members half bright. ; ; FALSE to display all at full intensity. ; ; If TRUE, you must fill in the correct codes to initiate & terminate half- ; intensity below. Unused bytes remain zero. If ZCPR3 is TRUE, don't ; bother, because QL will get this stuff from the Z3 TCAP buffer for you. ; DIMON MACRO DB ESC,'B1',0,0,0,0 ; <== dim (Kaypro) ENDM DIMOFF MACRO DB ESC,'C1',0,0,0,0 ; <== full brightness (Kaypro) ENDM ;.............................................................................. ; REVERSEVIDEO EQU FALSE ; TRUE if marking found strings with an escape ; sequence (reverse video recommended). ; FALSE if using displayable character(s) ; to mark. (See MRKCHR below). ; If TRUE, you must fill in the correct codes to initiate & terminate reverse ; video below. Unused bytes remain at zero. REVON MACRO DB ESC,'B0',0,0,0,0 ; <== reverse video "on" (Kaypro) ENDM REVOFF MACRO DB ESC,'C0',0,0,0,0 ; <== reverse video "off" (Kaypro) ENDM ; The following character or characters will be used to enclose a found string ; if REVERSEVIDEO above is FALSE, or whenever the program is being operated ; from a "remote" terminal. May be more than 1 character; unused bytes are 0. ; MRKCHR MACRO DB '\',0,0,0,0,0,0 ; Marks found strings like \this\ ENDM ; (prev version defaulted to $this$ instead) ;.............................................................................. ; LINEOVERLAP EQU 1 ; Number of lines to show from preceding page. ; This can help orient you on a new page. FINDFRTOP EQU FALSE ; TRUE means finds always start at top of file. ; ; FALSE means finds start on next page. ; ; (Repeat finds always start on the next page, regardless of this equate). UCHEX EQU TRUE ; TRUE for upper case a-f in hex dump. ; FALSE for lower case a-f if you can no longer ; distinguish B from 8. USEBIOSCONOUT EQU TRUE ; TRUE to use faster bios console output rtn. ; ; FALSE to go thru bdos, which is slower. ; ; Leave TRUE unless you have a very non-standard system: TRUE is about twice ; as fast as FALSE and makes paging very quick. If tabs don't show correctly, ; try expandtabs equ TRUE. DELAY EQU 3000 ; A number to enable page number entry delay. ; ; 0 to disable this feature and skip this code. ; ; For page number input, you can set the delay following the last number ; entered until the program jumps to that page without your having to hit ; the return key. This is highly hardware dependent, but easily adjusted. ; I'm a very bad and lazy typist, so I added this for my own use. If you ; hate it, simply set delay to 0. If set to some number > 0, the delay ; sets a loop timer that watches if you have typed a number, indicating that ; you're starting to enter a page number to jump to. If the timer reaches 0, ; it jumps to the page number entered so far, without your typing . ; For a 4MHz Kaypro, a delay of 2000 is about 1 second, which is ok for the ; way I type. A 2Mhz machine might need a count of 1000 for the same 1 second ; delay, but, again, this is machine dependent. I advise trial and error ; experimentation with different values of the delay to adjust this program ; to your machine and the way you type. ; The following EQU determines how embedded control characters (other than CR, ; LF,TAB & BS) will be displayed. If CTRLDISPLAY is TRUE, the two character ; combination: ^ will be used. If set to FALSE, all control characters ; will be displayed using the single character defined by CTRLMARKER below. If ; CTRLDISPLAY is FALSE and CTRLMARKER is set to NULL, control characters will ; not be displayed at all. ; CTRLDISPLAY EQU TRUE ; TRUE = display control chars as ^ ; FALSE = use the character defined below CTRLMARKER EQU NULL ; Char to use if CTRLDISPLAY above is FALSE ; NULL = do not display anything. HEXSIGNAL EQU '-' ; Character to signal entry of a hex find $. TRUNKCHAR EQU '>' ; Character to indicate truncation of line ; (Wordstar users may prefer "+") ; The following value adjusts the width of the display of library members, and ; should be left at 03H for terminals with approx 80 columns. Use 01H for 40 ; column terminals, or 00H for less. This value used to be set automatically ; based on COLUMNS, but the necessary conditional syntax which would work with ; all assemblers was getting out of hand. ; MASKVAL EQU 03H ; 03H for full width terminals, 01H for 40 col. ;----------------------------------------------------------------------------- ; ; < RCP/M equates > ; ; If you will not not going to be running QL on an RCP/M (remote) system, you ; may ignore the equates below and you are already done. ; ; RCP/M users, you MUST set your wheel byte below. It is defaulted to "5" ; below to guarantee a non-zero value for all "regular" users. WHEEL EQU 0005H ; <== SET to 003EH or your wheel byte address! ; Below is the character sequence which will be sent out whenever a "clear- ; screen" would have been generated if the program were in local use. 24 LF's ; have been put here in an experimental attempt to sort of give the same "feel" ; It will still leave the cursor at the bottom of the screen, so the screen ; will still have to scroll, but it should clear anyones screen pretty fast. ; It will mess up a "capture file" a bit, but QL already does that (a standard ; non-stop TYPE program should be available for "ascii downloads") ; ; Comment out or remove the second and third "DB" lines below if you wish to ; deactivate this concept. QL will then send a CR/LF and not attempt a clear- ; screen. (You may also put a "real" clearscreen sequence, if you want that ; sent out, but it will obviously be terminal specific). ; ; Remote "clearscreen". "Real" sequence at CLRSCR (near beginning) will always ; be used when the program is operated and BYE is not present. REMCLR MACRO DB CR,LF ; Leave this line DB LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF ; } Comment out these DB LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF ; } 2 lines if you want ENDM ; < end of user customization > ;============================================================================== IF M80 ; } Z1 EQU FALSE ; } skirt the issue of "NOT" vs ".NOT." syntax ELSE ; } now and forever! Z1 EQU TRUE ; } ENDIF ; } IF Z1 NLIST S ; No source listing LIST C ; Gen com file directly ENDIF IF ZCPR3 CSEG ELSE ASEG ORG 100H ENDIF ;.............................................................................. ; ; BDOS function equates ; CONOUT EQU 2 DIRIO EQU 6 RDBUFF EQU 10 OPEN EQU 15 READSEQ EQU 20 SETDMA EQU 26 SGUSER EQU 32 READRANDOM EQU 33 ; Page zero equates ; BDOS EQU 5 FCB1 EQU 5CH ; 1st fcb FCB1FN EQU FCB1+1 FCB1EXT EQU FCB1+9 FCB1R0 EQU FCB1+21H ; Rec number for sizing & lbr random access FCB1R2 EQU FCB1+23H ; 0'd before random read ; Ascii equates ; NULL EQU 0 CTRLC EQU 'C'-40H CTRLK EQU 'K'-40H CTRLX EQU 'X'-40H BELL EQU 7 BS EQU 8 TAB EQU 9 LF EQU 10 FORMFEED EQU 12 CR EQU 13 EOF EQU 1AH ESC EQU 1BH IF ZCPR3 PUBLIC $MEMRY EXTRN Z3VINIT,TINIT,DINIT EXTRN CLS,STNDOUT,STNDEND EXTRN Z3LOG,GETWHL,GETSPEED,GETCRT,GETVID EXTRN COUT,GETUD,PUTUD ELSE ; set the number of lines we can display (don't change) DISPLAY EQU LINES-LINEOVERLAP ; Display page size = 23 ENDIF ;============================================================================= QL: JP MAIN ; <=== entry IF ZCPR3 DB 'Z3ENV',1 Z3EADR: DW 00 ELSE WHL: DW WHEEL ; Make wheel patchable ENDIF ;______________________________________________________________________________ ; ; Screen management subroutines ; CLEARSCREEN: IF ZCPR3 PUSH HL CALL GETVID POP HL JR Z,USELFS ENDIF CALL BYECHK ; Remote user? JR NZ,USELFS ; Yes, use lf's to clear screen IF ZCPR3 CALL CLS ELSE CALL ESCMSG ; Output the bytes below CLRSCR ; Macro containing clearscreen byte sequence DB 0 ; End of msg marker (do not use) ENDIF CLRCOM: XOR A LD (COL),A ; Clr col ctr LD (LINEBYLINE),A ; Clr line by line flag RET ;................................ ; USELFS: IF ZCPR3 PUSH HL CALL CRLF CALL GETCRT INC HL LD H,(HL) LD A,LF LFLOOP: CALL COUT DEC H JR NZ,LFLOOP POP HL ELSE CALL MSG ; REMCLR ; Sleazy non-terminal specific "clearscrean" DB 0 ; End of message ENDIF JR CLRCOM ; Rest is same as above ;...............................; ;.............................................................................. ; ONHALF: ; (used only to display library *.C?m members at half-intensity) IF ZCPR3 PUSH HL CALL GETVID POP HL RET Z ENDIF CALL BYECHK ; Remote user? RET NZ ; No video specifics for the remote user IF ZCPR3 JP STNDOUT ELSE CALL ESCMSG ; Type out the below byte sequence DIMON ; Macro containing dim video char sequence DB 0 ; End of msg marker (do not use) RET ENDIF ;.............................................................................. ; OFFHALF: IF ZCPR3 PUSH HL CALL GETVID POP HL RET Z ENDIF CALL BYECHK ; Remote user? RET NZ ; No video specifics for the remote user IF ZCPR3 JP STNDEND ELSE CALL ESCMSG ; Type out the below byte sequence DIMOFF ; Char sequence to return to normal intensity DB 0 ; End of msg marker RET ENDIF ;.............................................................................. ; ONHILITE: PUSH HL IF REVERSEVIDEO ; Using some kind of escape seq CALL BYECHK ; Remote user? JR NZ,USECHAR ; Yes, do not send any escape sequences CALL ESCMSG ; Start reverse video REVON ; Macro containing reverse vid on char seq POP HL ; RET ; ENDIF ; Reverse video USECHAR: CALL MSG MRKCHR ; Character(s) to mark strings when found DB 0 ; End of msg marker POP HL RET ;.............................................................................. ; OFFHILITE: PUSH HL IF REVERSEVIDEO ; Using some kind of escape seq CALL BYECHK ; Remote user? JR NZ,OFFCH ; Yes, do not send any escape sequences CALL ESCMSG ; Output the byte sequence bekow REVOFF ; Macro containing rev video off char sequence POP HL ; RET ; ENDIF ; Reverse video OFFCH: CALL MSG ; Mark string w/o special video attributes MRKCHR ; Character(s) to enclose found string DB 0 ; End of msg marker (do not use) POP HL ; RET ; End of screen management stuff ;...............................; ; ; embedded copyright message simplified & moved near beginning (for dump) ; since it is no longer displayed at runtime DB 'by Nick Dobrinich. ' DB 'Sections Copyright (c) 1986 ' DB 'Steven Greenberg & C.B.Falconer ' DB '201-670-8724, 203-281-1438. ' DB 'Reproduce for non-profit only.' SIGNON: CALL MSG ; added tab chars to save a few bytes DB 'v',QLVERSION/10+'0','.' DB (QLVERSION-((QLVERSION/10)*10))+'0' IF ZCPR3 DB '/Z3' ENDIF DB ' usage: QL [d' IF ZCPR3 DB 'u: or dir' ENDIF DB ':]fn.ext | QL [d' IF ZCPR3 DB 'u: or dir' ENDIF DB ':]lib',CR,LF,LF DB ' A',TAB,'alternate display [text <==> hex]',CR,LF DB ' B',TAB,'back a page',CR,LF DB ' ',TAB,'forward a page',CR,LF DB ' ',TAB,'forward a line',CR,LF DB ' <##>',TAB,'jump to page #',CR,LF DB ' F',TAB,'find string | ' DB HEXSIGNAL,'hexbytes',CR,LF DB ' R',TAB,'repeat find',CR,LF DB ' T',TAB,'toggle truncation: now O' TRUNKSTATE: DB 'N ' ; On/off trunc state flag DB CR,LF DB ' ?',TAB,'help',CR,LF DB ' X',TAB,'exit',CR,LF,0 RET ;.............................................................................. ; WHLCHK: IF ZCPR3 JP GETWHL ELSE LD HL,(WHL) ; Pointer to wheel byte is at this loc LD A,(HL) ; Value of wheel byte OR A ; Return a status RET ; ENDIF ;.............................................................................. ; BYECHK: LD A,(BYE5FLAG+1) ; Actual existance of bye is chkd at prog init OR A ; That byte will be non-zero if bye was found RET ; This subr just returns that flag status ;.............................................................................. ;................................ ; ; Main entry MAIN: ; LD (OLDSP),SP ; Save old sp if no warm boot needed LD SP,STACK ; Set up local stack LD A,40 ; Misc initializations LD (STRMAX),A ; IF USEBIOSCONOUT ; Using faster bios rtn LD HL,(1) ; Bios + 3 warm start ep LD DE,9 ; Bias to bios conout jp ADD HL,DE LD (BIOSCONOUT),HL ; Save adr for fast putc ENDIF ; init all storage for go cmd restart LD HL,INITSTORAGE ; *stuff to 0 LD DE,INITSTORAGE+1 LD BC,ENDINITSTORAGE-INITSTORAGE-1 ; # bytes to init-1 LD (HL),0 ; Init src 0 LDIR ; Init the rest IF ZCPR3 LD HL,(Z3EADR) CALL Z3VINIT CALL TINIT CALL GETCRT INC HL INC HL LD A,(HL) DEC A LD (DISPLAY),A CALL PUTUD LD DE,FCB1 CALL Z3LOG ENDIF CALL SIGNON ; Say hello ; Check for existance of BYE5. Note that "remote operation" is assumed if ; BYE is detected. ;................................ ; Bye5xx existance test LD C,SGUSER ; Bdos set/get user call LD E,0FFH ; First get current value CALL BDOS ; PUSH AF ; Save current value ; LD C,SGUSER ; Bdos set/get user call LD E,241 ; Magic number to see if bye is resident CALL BDOS ; Look for special result from "set/get" user CP 77 ; Magic return# if it is there JR NZ,NOBYE ; Nope.. LD HL,-0800H ; Flag "BYE5" as resident by puttin -800h here LD (BYE5FLAG),HL ; (otherwise is zero from init above) ; NOBYE: POP AF ; Get orig user# back LD C,SGUSER ; Bdos set/get user call LD E,A ; Put user# in E CALL BDOS ; ;...............................; ; blank filename.ext $ ;; LD HL,FNEXT ; Moved FNEXT to initialized data area instead ;; LD DE,FNEXT+1 ; (v2.4) ;; LD BC,10 ;; LD (HL),0 ;; LDIR CALL CHKSUMCCP ; Do simple chksum of ccp for quit LD (CCPCHKSUM),A ;................................ ; Do all calculations relating to available ; Memory right here... LD HL,(BDOS+1) ; Get bdos base LD DE,(BYE5FLAG) ; (-2k) if ccp to be saved, else zero ADD HL,DE ; Add, ie subtract, that LD (BDOSBASE),HL ; Take future requests for (bdos+1) from here ;...............................; ; open the file if one given ; try open 1st with given name, then as .lbr OPENFILE: LD A,(FCB1FN) CP ' ' JR NZ,OPENSOMEFILE ; ; no fn given: see if core dump wanted CALL WHLCHK ; Must not let hackers crack system security! JP Z,QLEXIT ; So no "core dump" if wheel byte isn't set CALL MSG DB CR,LF,'Core dump (y/N)? ',0 LD C,1 CALL BDOS AND 1FH CP 19H ; Ctrl-y? ; could also be: cp 0eh ;for ctrl-n response, yes default JP NZ,QLEXIT ; set up for core dump LD A,YES ; 0ffh LD (CORE),A ; Set flag LD (HIPG),A LD (NONTEXT),A ; Allow hex/ascii disp only LD HL,0FFFFH ; Of all of memory LD (EOFADR),HL LD (FILELEN),HL XOR A LD (PAGE),A ; Set init pg 0 LD HL,PTRTBL+1 ; Set hi adrs only; lo are 0 LD B,0 ; 256 pgs SETMEMPP: LD (HL),A INC A INC HL INC HL DJNZ SETMEMPP JP PRPG ; Display hex/ascii of pg 0 OPENSOMEFILE: ; LD HL,FCB1FN ; Src LD DE,FNEXT ; Dst LD BC,11 ; Len LDIR ; Copy filename.ext LD C,OPEN CALL BDOSCALL ; Open file JP P,OPENOK ; Open ok >= 0 LD A,(LIBRARY) OR A ; JR NZ,NOTFOUND ; Error, couldn't find reg or lbr w/ that name ; see if there's a lbr by same name to get member listing LD A,YES LD (LIBRARY),A ; Library flag LD HL,FCB1EXT LD (HL),'L' ; Add 'lbr' extension INC HL LD (HL),'B' INC HL LD (HL),'R' ; now try to open the library JP OPENFILE CHKSUMCCP: ; compute simple 1 byte chksum of entire ccp ; ret in a LD HL,(6) LD DE,806H ; Size of ccp XOR A ; Clr cy SBC HL,DE ; *ccp LD BC,800H ; Chksum entire ccp CHK1SUM: ADD A,(HL) INC HL LD E,A ; Save chksum in E DEC BC LD A,B OR C LD A,E ; Get chksum back JR NZ,CHK1SUM RET ; Chksum in a ;.............................................................................. ; ILLEGAL: CALL MSG ; Display error and exit DB CR,LF,'++ Sorry, cannot display online .COM files ++',CR,LF,0 JR QLEXIT NOTFOUND: CALL MSG ; Display error and exit DB CR,LF,'++ File Not Found ++',CR,LF,0 QLEXIT: LD SP,STACK ; Stack may be questionable upon arrival here IF ZCPR3 CALL GETVID CALL NZ,DINIT CALL GETUD ENDIF CALL CHKSUMCCP LD B,A ; Ccp chksum now LD A,(CCPCHKSUM) ; Orig ccp chksum XOR B JP NZ,0 ; Warm boot if ccp was overlaid LD SP,(OLDSP) ; Else just ret to ccp RET QUIT: CALL SUMMARY ; Give filesize report QUITNOSUM: LD A,(LIBRARY) OR A ; Working with lbr? JR Z,QLEXIT ; No lbr, so exit ; working with lbr: list all members and let user choose next LD HL,0 LD (FCB1R0),HL ; Set lbr rec 0 CALL SEEK ; Position to lbr tof and fall thru ;................................ ; v2.4 OPENOK: ; System security related stuff CALL WHLCHK ; If wheel is set, skip all this JR NZ,LEGAL ; LD A,(FCB1+10) ; Else check if file has SYS attribute AND 80H ; JR NZ,NOTFOUND ; If it does, pretend file doesn't exist ; LD HL,FCB1+9 ; More system security: no examing online LD A,(HL) ; COM files. if they're in a lbr, ok, else AND 7FH ; they should be named OBJ or CZM. CP 'C' ; JR NZ,LEGAL ; INC HL ; LD A,(HL) ; AND 7FH ; CP 'O' ; JR NZ,LEGAL ; INC HL ; LD A,(HL) ; AND 7FH ; CP 'M' ; JP Z,ILLEGAL ; ;...............................; LEGAL: LD A,(LIBRARY) ; Access OK, continue OR A JP Z,CHKIFCOMPRESSED ; Not working with a library ; read 1st lbr directory sector to see how big lbr dir is IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; Set dma to buffer ENDIF LD HL,1 LD (NSECTS),HL CALL READFILE IF ZCPR3 PUSH DE LD HL,($MEMRY) LD DE,14 ADD HL,DE LD E,(HL) INC HL LD D,(HL) EX DE,HL POP DE ELSE LD HL,(BUFFER+14) ; # of lbr dir sects ENDIF DEC HL ; We already read the 1st LD A,H OR L JR Z,PRLBRDIR ; Lbr dir is only 1 sect long LD (NSECTS),HL CALL READFILE ; Read the rest of the lbr dir JP Z,LBRERROR ; print active member names of lbr ; *.C?m files in optional half intensity ; DE is next dma adr = last byte read + 1 PRLBRDIR: EX DE,HL LD (HL),0FFH ; Add lbr dir eof CALL CRLF IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ENDIF LD C,0 ; Count active lbr dir entries PRNXTMEMBER: LD DE,32 ; Lbr dir incr ADD HL,DE ; *next dir entry LD A,(HL) OR A ; 0 = active member? JR Z,ISACTIVE CP 0FEH ; Deleted member? JR Z,PRNXTMEMBER ; Skip it JR LBRDIREOF ISACTIVE: INC C ; Ctr++ PUSH BC ; Save count PUSH HL ; Save *dir[0] IF HALFINTENSITY ; chk for *.C?m PUSH HL ; *dir[0] LD DE,9 ADD HL,DE ; *ext LD A,(HL) CP 'C' JR NZ,NOTACOM INC HL INC HL ; *ext+2 LD A,(HL) CP 'M' JR NZ,NOTACOM ; else it's a com file, so do half intensity CALL ONHALF NOTACOM: POP HL ; *dir[0] ENDIF ; Halfintensity on ;................................ ; PUSH BC ; PUSH DE ; Save everything("b2dec" destroys) PUSH HL ; LD A,C ; CP 100 ; CALL C,SPACE ; LD A,C ; ("b2dec" left justifies) CP 10 ; CALL C,SPACE ; LD L,C ; Get member's #, still in C LD H,0 ; Put it in HL CALL B2DEC ; Display it LD A,':' ; Followed by a colon CALL PUTC ; POP HL ; POP DE ; Restore registers POP BC ; CALL PRNFN ; Type the LBR name pointed to by HL IF HALFINTENSITY CALL OFFHALF ENDIF ; Halfintensity off CALL MSG DB ' |',0 ; "fence" char and spaces btwn filenames IF ZCPR3 CALL GETCRT LD A,(HL) LD B,3 CP 78 JR NC,DOMSKV DEC B CP 38 JR NC,DOMSKV DEC B DOMSKV: ENDIF LD A,C ; Do a cr/lf after each 4 entries (or 2 or 1) IF ZCPR3 AND B ELSE AND MASKVAL ; (03h or 01h or 00h depending on "columns") ENDIF CALL Z,CRLF ; POP HL ; *dir[0] again POP BC ; Count again JR PRNXTMEMBER ; ;...............................; ;................................ ; PRNFN: ; Subr to type the filename pointed to by HL+1 LD A,(CORE) ; A core dump never has a filename OR A ; RET NZ ; So forget about it ; LD B,8 ; Display first 8 chars in fn ; PRNXT: INC HL ; *char++ LD A,(HL) ; Get char of member name CALL PUTC ; Print it DJNZ PRNXT ; Loop 8 times ; LD A,'.' ; Now display a "." CALL PUTC ; ; LD B,3 ; Same as above 3 more times for ext ; PRNXT2: INC HL ; LD A,(HL) ; CALL PUTC ; DJNZ PRNXT2 ; Loop 3 times ; RET ; ;...............................; LBRDIREOF: ; V2.4 CALL MSG DB CR,LF,'Member (1-',0 LD A,C LD (NMEMBERS),A ; # of active members LD L,A LD H,0 CALL B2DEC CALL MSG DB ') ',0 XOR A LD (JUMPTO),A ; Init jumpto for get LD A,(NMEMBERS) LD (HIPG),A ; Set hipg so get can deduce when enuf CALL GETCHNUM ; Get user member choice LD C,A ; LD A,(JUMPTO) ; Did he enter a number OR A ; JR NZ,CHKNUM ; Go check it LD A,C ; CALL UCASE ; Possibly upcase a character in a CP 'X' ; (getchnum lvs char in a for analysis) JP Z,QLEXIT ; "X" exits CP CTRLC ; So does ^C JP Z,QLEXIT ; CP CTRLK ; So does ^K JP Z,QLEXIT ; CP ESC ; So does ESC JP Z,QLEXIT ; CP CR ; So does CR JP Z,QLEXIT ; CP 'T' ; v2.4 We will allow this command here CALL Z,FLIPTRUNC ; will fall thru & redisplay new state CALL CLEARSCREEN ; All other resposes result in a help screen CALL SIGNON ; (which may or may not be there now) JP QUITNOSUM ; Back to lbr menu w/ no file summary ; chk for too big a member # ; CHKNUM: LD B,A ; B = jumpto LD A,(NMEMBERS) CP B ; Cy if nmembers < jumpto JP C,QUITNOSUM ; Display lbr dir again CALL CRLF XOR A LD (JUMPTO),A ; Rst jumpto ; go to member number & display it IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ENDIF LD DE,32 ; Dir incr MEMCNT: ADD HL,DE ; chk for deleted not at eof LD A,0FEH ; Deleted marker CP (HL) JR Z,MEMCNT ; Skip if deleted DJNZ MEMCNT INC HL ; *fn[1] ; copy full fn ext to member name string and to fnext string THISMEM: PUSH HL ; Save *fn[1] LD DE,MEMBER LD BC,11 LDIR ; Copy to member $ POP HL ; Rst *fn[1] LD DE,FNEXT LD BC,11 LDIR ; Copy to fnext $ LD E,(HL) ; HL = *member start INC HL LD D,(HL) ; DE = starting sect of member LD (FCB1R0),DE ; Fill in lbr r0,r1 fld for seek to member INC HL ; HL = *member len LD E,(HL) INC HL LD D,(HL) ; DE = len in sects to read after seek LD (NSECTS),DE ; chk for zero len, maybe a lbr date file LD A,D OR E JR NZ,SEEKMEMBER ; Seek within lbr CALL MSG DB 'Empty',CR,LF,0 JP QUITNOSUM SEEK: ; assumes fcb1r0 is set to rec to seek to ; set fcb1 r2 fld to 0 XOR A LD (FCB1R2),A ; 0 lbr r2 fld LD C,READRANDOM CALL BDOSCALL RET Z ; Seek ok POP HL ; Destroy ret adr LBRERROR: CALL MSG DB 'LBR read error',0 JP QLEXIT ; position to member within lbr at fcb1r0 SEEKMEMBER: CALL SEEK JP CHKIFCOMPRESSED ;................................ ; SHORTSUM: ; Print the filename at FNEXT: LD HL,FNEXT-1 ; No CR's, LF's or any other frills CALL PRNFN ; RET ; ;...............................; SUMMARY: ; display fn.ext CALL CRLF LD HL,FNEXT-1 CALL PRNFN CALL MSG DB ': ',0 LD A,(INCOMPLETE) ; Was read complete? OR A JR Z,DOSUMMARY ; If so, we know file size WARNING: CALL MSG DB CR,LF,'WARNING: file could NOT be read ' DB 'completely into RAM ',0 RET DOSUMMARY: ; report file size LD HL,(FILELEN) ; In bytes PUSH HL CALL B2DEC CALL MSG DB ' bytes (',0 POP HL ; HL = filelen SRL H SRL H ; Shift to kilobytes INC H ; For overflow lsb LD L,H LD H,0 CALL B2DEC CALL MSG DB 'k)',0 ; skip line count for non-text files LD A,(NONTEXT) OR A JP NZ,CRLF ; &ret, no line summary SUMLINES: CALL MSG DB ' in ',0 LD A,(HIPG) DEC A ; Don't count last pg lines yet LD B,A LD HL,0 JR Z,ONLY1PG ; Only 1 pg, nothing to add IF ZCPR3 LD A,(DISPLAY) LD E,A LD D,L ELSE LD DE,DISPLAY-1 ; Actual lines per pg ENDIF CNTLINES: ADD HL,DE DJNZ CNTLINES ONLY1PG: ; LD A,(LASTPGLINES) LD E,A LD D,0 ADD HL,DE ; Add in last pg lines CALL B2DEC CALL MSG DB ' lines, ',0 ; added word counting code ; words are any seq of chars >= '0' (30h) and < 80h ; handle ws doc by ascii mask ; count space between words IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ENDIF LD D,FALSE ; Inword = false ; reg E is temp storage for curr ch LD IX,0 ; Word count LD BC,(FILELEN) ; Get actual file len CNT: LD E,(HL) ; Save ch INC HL DEC BC LD A,B OR C JR Z,CNTALLDONE LD A,E ; Get ch AND 7FH ; Mask to ascii CP '0' ; Cy if < '0' JR C,ISWHITESP ; ch is valid in word XOR A ; False OR D ; Inword == false? JR NZ,CNT ; No LD D,YES ; In a word now INC IX ; Word count++ JR CNT ISWHITESP: LD D,FALSE ; Inword = false JR CNT CNTALLDONE: PUSH IX POP HL CALL B2DEC CALL MSG DB ' words',CR,LF,0 RET CHKIFCOMPRESSED: ; may be compressed by squeezing or crunching XOR A LD (INCOMPLETE),A ; Set read not incomplete yet LD A,(LIBRARY) OR A ; Working fr lbr? LD A,(FCB1EXT+1) ; Chk 2nd letter of file ext JR Z,ISITQZ ; If not lbr LD A,(MEMBER+9) ; Else, 2nd letter of member ext ISITQZ: CP 'Q' JR Z,SQUEEZED ; chk for crunched file CP 'Z' JP Z,CRUNCHED ; else it's a normal uncompressed file ; we also come back here for *.azm files after uncr fails NORMAL: IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; Read into buffer til eof or mem full ENDIF LD A,(LIBRARY) OR A JR NZ,NRMLBR ; Nsects already set for lbr member LD HL,512 ; Force read to eof or up to bdos LD (NSECTS),HL NRMLBR: CALL MSG DB 'Reading',0 CALL READFILE JP Z,TOOLARGE ; Set incomplete read flag JP FINDEOF ; Read was okydoky ; rewritten for clarity? ; DE should pt to 1st dma adr on entry ; DE pts to last dma adr used on exit ; seq read of uncompressed file or lbr member or lbr dir into buffer ; reads entire file (up to bdos) or nsects of a lbr dir or member ; nsects should be set for max sects to read ; NZ if read ok ; Z if too large for mem READFILE: LD C,SETDMA CALL BDOSCALL LD C,READSEQ CALL BDOSCALL RET NZ ; Read to eof ok ; pt to start of next dma LD HL,128 ADD HL,DE ; Dma += 128 EX DE,HL ; DE=next dma adr ; chk next dma adr < bdos LD A,(BDOSBASE+1) ; [possibly adjusted] bdos hi adr DEC A ; 256 byte bdos safety cushion CP D ; Curr hi dma adr RET Z ; File about to crash into bdos ; chk if spec # of sects read LD HL,(NSECTS) DEC HL ; Nsects-- LD (NSECTS),HL LD A,H OR L ; Spec # of sects read? JR NZ,READFILE ; No INC A ; Set nz for nsects read ok RET BDOSCALL: ; C must be set for correct bdos fn (open, readseq, readrandom) on fcb1 ; we stick setdma fn call in here as well to save code space ; saves & restores all regs except af which has ret code ; set z if a = 0 PUSH BC PUSH DE PUSH HL LD A,C IF DOSPLUS CP 211 ; Dos+ binary to decimal printer JR Z,DEISSET ENDIF CP SETDMA ; Fn call is setdma? JR Z,DEISSET ; If so, DE already set LD DE,FCB1 DEISSET: CALL BDOS OR A ; Set z for read ok POP HL POP DE POP BC RET ; unsqueezing code setup SQUEEZED: LD HL,(BDOSBASE) ; [possibly adjusted] bdos addr LD (WORKAREA),HL ; Workarea is all mem up to bdos for unsq LD HL,STACK LD (SPSAVE),HL ; Set default stk if too large ; set *sq and *unsq LD HL,100H ; Src ptr for getbyt, forcing read IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; Dst ptr for out ENDIF LD (UNCRSRC),HL LD (UNCRDST),DE CALL MSG DB 'Unsqueezing: ',0 CALL GETBYT CP 76H ; Compressed file marker (halt inst) JP NZ,NOTCOMPRESSED CALL GETBYT CP 0FFH ; Squeezed file marker JP NZ,NOTCOMPRESSED CALL GETBYT CALL GETBYT ; Skip 2 chksum bytes ; print the unsqueezed file name NXTSQFNCHAR: CALL GETBYT OR A ; '\0' $ term? JR Z,SQFNDONE CALL PUTC JR NXTSQFNCHAR SQFNDONE: CALL GETBYT ; Get # of 4 byte transl pairs LD L,A CALL GETBYT LD H,A ; times 4 for number of bytes in transl tbl ADD HL,HL ADD HL,HL LD B,H LD C,L ; copy unsq transl tbl over ptrtbl temporarily LD HL,PTRTBL ; Overlay ptrtbl temp with unsq tt COPYUNSQTT: CALL GETBYT LD (HL),A ; Store into tt INC HL DEC BC ; Ctr-- LD A,B OR C JR NZ,COPYUNSQTT LD B,0 ; Init bit ctr UNSQNEXT: ; drive the unsqueezer CALL UNSQ ; Unsq 1 char JR C,UNSQDONE ; Eof CP 90H ; Repeat count follows JR Z,REPCHAR ; Don't save 90h repeat ch LD (LASTUNSQCH),A ; Save in case of repeat count CALL OUT ; Put unsq char into buffer JR UNSQNEXT REPCHAR: CALL UNSQ ; Get repeat count JR C,UNSQDONE ; Eof OR A ; 0 cnt? JR Z,SEND90H ; Then send real 90h PUSH BC ; Save bit ctr B LD B,A ; Repeat ctr DEC B ; Actual cnt is 1 less JR Z,UNSQNEXT LD A,(LASTUNSQCH) REPLOOP: PUSH AF CALL OUT ; Out last ch B times POP AF DJNZ REPLOOP POP BC ; Rst bit ctr B JR UNSQNEXT SEND90H: LD A,90H CALL OUT JR UNSQNEXT UNSQDONE: CALL OUT ; Save eof marker LD HL,(UNCRSRC) LD DE,(UNCRDST) JP FINDEOF UNSQ: ; B = bitstogo mod 8 ctr ; C = curr sq ch, maybe partially shifted ; DE = curr transl tbl incr ; HL = *sq transl tbl LD DE,0 ; DE=curr tbl incr XOR A OR B ; Chk bits to go = 0 JR NZ,NEWINDEX ; Nz is sq char in progress ; else start with a new sq char NXTSQCHAR: CALL GETBYT ; Fetch a sq char LD C,A ; Save in C LD B,8 ; 8 bits per char shift ctr NEWINDEX: ; this code is from lt18 unsqueezer LD HL,PTRTBL ; Start of tt ; mult curr incr in DE by 4 by repeated adding ADD HL,DE ADD HL,DE ADD HL,DE ADD HL,DE ; shift out lsb of sq char & chk it LD A,C ; Get sq char back SRL A ; Shift bit 0 into cy LD C,A ; Save sq ch again JR NC,NOTSET ; Use odd pair INC HL ; To even pair if bit was set in sq char INC HL NOTSET: LD E,(HL) ; New incr for DE if not transl INC HL LD D,(HL) ; > 7fh if valid transl BIT 7,D ; Bit 7 set if valid JR Z,NOTTRANSL ; Hi bit not set: E is not a transl DEC B ; Bit ctr-- LD A,0FEH ; End of transl tbl CP D ; Set z flag if eof LD A,1AH ; Get eof marker SCF ; Mark this as the eof return RET Z ; Since 1ah could be repeat count LD A,E ; Else get char transl CCF ; No carry if not eof CPL ; Extract char by inversion RET ; Ret the unsq ch NOTTRANSL: DJNZ NEWINDEX JR NXTSQCHAR ; uncrunching i/o code CRUNCHED: CALL MSG DB 'Uncrunching: ',0 LD HL,100H ; Src ptr for getbyt, dummy end of sect IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; Dst ptr for out ENDIF LD (UNCRSRC),HL LD (UNCRDST),DE ; chk to see if header is correct for crunched file ; we do this here in order to abort gracefully if it's an uncrunched .azm file CALL GETBYT CP 76H JR NZ,NOTCOMPRESSED CALL GETBYT CP 0FEH JR NZ,NOTCOMPRESSED ; crunched header ok ; now output the file name ; ; Do not print data which may be after end of filename, but before the ; zero (system dependent data allowed here; cr23d uses this). We will ; print the chars if they are between "[" and "]", however. ; SAYCRNAME: LD B,12 ; Loop limit for 11 chars plus "." SAYLP: CALL GETBYT ; Next filename char CP '.' ; Dot? JR NZ,NOTDOT ; If not LD B,4 ; If we hit the dot, only 4 (dot+3) chars left NOTDOT: OR A ; A zero terminates, as always JR Z,CRHDRDONE ; Yes, done CALL PUTC ; Output the char DJNZ SAYLP ; Loop a limited number of times ;................................ ; CALL GETBYT ; This part's optional- print "[..]" text OR A ; End-of-header? JR Z,CRHDRDONE ; If so.. CP '[' ; Beg of comment? JR NZ,FNDEOH ; Forget it, skip junk and continue LD B,A ; Save that "[" LD A,' ' ; Space btwn filename and comment looks better CALL PUTC ; LD A,B ; Get that "[" bak again CMNTLP: CALL PUTC ; Ok, start typing comment CALL GETBYT ; Next char OR A ; In case of missing "]" JR Z,CRHDRDONE ; CP ']' ; End of comment? JR NZ,CMNTLP ; Loop for more chars if not CALL PUTC ; Print closing bracket ;...............................; ; now (finally!) make sure we are at the zero marked eoh FNDEOH: CALL GETBYT OR A JR NZ,FNDEOH CRHDRDONE: ; set workarea 24k below bdos. ; v2.5 revision. "UNC", in it's present configuration, checks that the address ; of free memory supplied to it in HL allows FULLY 24k (or more). It does this ; after rounding up the value supplied to the next even page boundary. So we ; have to add in an extra 256 bytes to allow for this rounding process. LD HL,(BDOSBASE) ; [possibly adjusted] bdos addr LD DE,24*1024+256 ; 24k plus one page for "rounding" v2.5 XOR A SBC HL,DE LD (WORKAREA),HL ; Save for debug only CALL UNC ; Join uncrel after filename scanned LD HL,(UNCRSRC) LD DE,(UNCRDST) JR C,CHKUNCRERRS ; file was successfully uncrunched PUSH DE ; DE pts to last out+1 EX DE,HL ; HL now pts to last out+1 IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; Start of uncr text ENDIF XOR A SBC HL,DE ; Len of uncr text LD (FILELEN),HL POP DE ; Last out+1 for findeof JP FINDEOF ; Treat like all others CHKUNCRERRS: CP 2 ; Error 2 is file not crunched JR NZ,CHK1ERROR ; we can handle this error: ; force top of file again, then treat as normal text NOTCOMPRESSED: CALL MSG ; Kill uncrunching: msg DB CR,' ',CR,0 LD HL,0 LD (FCB1R0),HL LD C,READRANDOM CALL BDOSCALL ; Read at tof JP NORMAL CHK1ERROR: PUSH AF ; } v2.5 Earlier versions did not include CALL CRLF ; } push/pop, and hence interpreted the POP AF ; } error message from "UNC" incorrectly CP 1 JR NZ,CHK3ERROR ; CALL MSG DB 'Later version uncruncher needed',0 JP QUITNOSUM CHK3ERROR: CP 3 JR NZ,CHK4ERROR CALL MSG DB 'File is corrupt',0 JP QUITNOSUM CHK4ERROR: CP 4 JR NZ,UNCRUNKERROR CALL MSG DB 'Not enough memory or stack overflow',0 JP QUITNOSUM UNCRUNKERROR: PUSH AF CALL MSG DB 'Unknown uncrunch error: ',0 POP AF ADD A,'0' ; Make an ascii # CALL PUTC JP QUITNOSUM ; i/o rtns for uncrel.azm ; these are also used by unsq code GETBYT: PUSH BC ; Save working regs PUSH HL LD HL,(UNCRSRC) LD A,H CP 1 ; At 100h? JR C,STILLINSECT ; read another sector of the file PUSH DE ; Save dst ptr fr bdos destruction LD C,SETDMA LD DE,80H ; Use default buffer CALL BDOSCALL LD C,READSEQ CALL BDOSCALL ; Read next sector into it POP DE ; Restore DE LD HL,80H ; Set ptr to start of this sector STILLINSECT: LD A,(HL) ; Get a char to uncr INC HL ; *ch++ LD (UNCRSRC),HL POP HL ; Restore working regs POP BC RET OUT: PUSH AF PUSH DE ; Save working regs LD DE,(UNCRDST) LD (DE),A INC DE ; chk for DE > workarea LD A,(WORKAREA+1) CP D ; Hi bytes only JR NZ,OUTOK ; else, uncr/unsq text is about to run into workarea LD SP,(SPSAVE) ; Restore our sp CALL CRLF DEC DE ; DE pts to last byte uncr JP TOOLARGE OUTOK: LD (UNCRDST),DE POP DE ; Rst working regs POP AF RET ;........................................ ; ; ; uncrunching module included here ; IF M80 ; INCLUDE UNC.AZM ; M80 type "include" syntax ELSE ; *INCLUDE UNC.AZM ; Z80MR type "include" syntax ENDIF ; ;.......................................; TOOLARGE: LD A,YES ; Flag incomplete read LD (INCOMPLETE),A ; we're no longer working with a compressed file ; normal, unsq & uncr all come here ; find eof marker: only look in last sector read ; if no eof found, put one in at end of last sector FINDEOF: EX DE,HL ; Last dma now in HL LD BC,128 XOR A ; Clr cy SBC HL,BC ; HL=start of last sector read LD A,EOF CPIR ; Look for eof thru 128 bytes JR Z,GOTEOF ; Eof found ; ld a,eof LD (HL),A ; Else put in our own eof marker ; Probably leaves some garbage at eof GOTEOF: LD (EOFADR),HL ; Save highest used adr XOR A ; Clr cy IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ENDIF SBC HL,DE LD (FILELEN),HL ; Save actual file len in bytes ; chk if we really have a text file ; assume it's text: ; IF the 1st byte is between 20h and 7fh or cr, lf or tab (or ff [v2.5]) ; AND 90% of 1st 100 chars are printable (for wordstar hi bits) ; if text, set ptrs to 1 char past every 22nd lf in buffer ; else, set up for hex/ascii dumping instead of chaos of earlier versions ; by setting ptrs to every 256 bytes of buffer SETPGPTRS: ; 1st see if we really have a text file IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ENDIF LD A,(HL) CALL CHKOKCTRLS ; Cr,lf,tab? JR Z,CHKTEXT ; Text so far CP ' ' JR C,ISNONTEXT ; Ctrl char 1st CP 7FH+1 ; This screens common init 0c3h JR NC,ISNONTEXT CHKTEXT: LD B,100 ; # to scan LD C,0 ; Count of non-text chars WASTEXT: LD A,(HL) INC HL AND 7FH ; Mask to ascii CALL CHKOKCTRLS JR Z,TEXTCH CP ' ' ; Some kind of ctrl char? JR NC,TEXTCH INC C ; Non-text++ TEXTCH: DJNZ WASTEXT LD A,C ; Non-text count CP 10 ; If < 10/100 are non-text, JR C,ISTEXT ; It really is a text file ; else it's a non-text file ISNONTEXT: LD A,YES LD (NONTEXT),A LD HL,(FILELEN) LD A,L OR A LD A,H ; # of 256 byte pgs JR Z,EVENPG ; Even page boundary INC A ; For overage EVENPG: LD (HIPG),A ; set pg ptrs to every 256 bytes of buffer LD B,A IF ZCPR3 LD DE,($MEMRY) DEC DE ELSE LD DE,BUFFER-1 ENDIF LD HL,PTRTBL SETPP: LD (HL),E INC HL LD (HL),D INC HL INC D ; += 256 bytes DJNZ SETPP ; stick in eof adr for last pg finds & print pg 1 JP STICKINEOF CHKOKCTRLS: ; chk for ctrl chars ok in a text file ; ret with Z set if tab,cr,lf (or ff [v2.5]) CP TAB RET Z CP CR RET Z CP FORMFEED RET Z CP LF RET ISTEXT: ; distinguish ws doc files by looking for 1st page break: 8ah ; if prev ch is 0dh or 8dh, assume it to be ws doc XOR A LD (NONTEXT),A ; Mark non-text flag false LD (WSDOC),A ; IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ENDIF LD BC,(FILELEN) LD A,8AH ; 1st possible ws doc pg break CPIR JP PO,NOPGBRK ; None found DEC HL STILLLF: DEC HL ; Back up to prev cr LD A,(HL) AND 7FH CP LF JR Z,STILLLF ; Skip if dbl sp CP CR JR NZ,NOPGBRK ; 8ah not preceded by 0dh or 8dh ; it's a real pg brk: go thru file and chg all 8ah to temp 0ah ; push adrs on stk so we can restore later LD A,YES LD (WSDOC),A LD HL,0 PUSH HL ; Flag top of stk IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ENDIF LD BC,(FILELEN) LD A,8AH FIND8AHNEXT: CPIR ; Look for 8ah to chg JP PO,NOPGBRK ; All 8ah chg to 0ah DEC HL ; HL now *8ah PUSH HL ; Save adr on stk for later ; No stk overflow chking done?? LD (HL),LF ; Chg to real lf INC HL JR FIND8AHNEXT NOPGBRK: ; set pg ptrs to ch following every 22nd lf IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ENDIF LD (PTRTBL),HL ; *1st pg LD DE,PTRTBL+2 ; *pg go here LD BC,(FILELEN) ; Get actual file len LD IX,0 ; Pg ctr SET1: IF ZCPR3 LD A,(DISPLAY) ELSE LD A,DISPLAY-1 ; Usually every 22 lines ENDIF SET2: PUSH AF ; Save line ctr LD A,LF CPIR ; Look for lf JP PO,SETDONE ; BC = 0 = last lf before eof POP AF ; Line ctr DEC A ; Is this the 22nd line? JR NZ,SET2 ; Not a pg break ; at pg break, store adr of start of next pg EX DE,HL ; DE=adr to store, HL=*ptrtbl LD (HL),E ; Store lo adr of pg ptr INC HL LD (HL),D ; Store hi adr INC HL EX DE,HL ; Rst ptrs INC IX ; Pg++ ; chk for > 255 pgs NOT implemented JR SET1 SETDONE: POP BC ; B = line ctr fr stk IF ZCPR3 LD A,(DISPLAY) ELSE LD A,DISPLAY-1 ENDIF SUB B ; 22-last line JR NZ,PARTIALPG ; LD A,B ; Display - 1 JR NOPARTIALPG ; This partial is really a full pg ; ld (lastpglines),a ; 0? JR Z,JPTOIS0 ; jr Z,get3 ;continue if it is 0 GOTO: LD (PAGE),A ; Else new pg is jumpto XOR A ; 0 out jumpto LD (JUMPTO),A JP PRPG ; Jumpto that page JPTOIS0: LD A,B OR A ; A was 0 on ret? JR NZ,GET3 ; No, see if letter cmd LD A,(CORE) INC A ; Pg 0 if core, pg 1 if other JR GOTO ; Else, force tof GET3: ; V2.4 ; chk letter cmds ; LD A,B ; Get cmd back CALL UCASE ; LD BC,ENDCMDS-CMDS ; # of cmds LD HL,CMDS CPIR ; Try to match cmd JP NZ,DEFAULT ; No matching cmd found LD H,B LD L,C ; Inverse cmd number ADD HL,HL ; *2 for word adrs LD DE,CMDADR ADD HL,DE ; *cmd adr we want LD E,(HL) ; Lo cmd adr INC HL LD D,(HL) ; Hi cmd adr EX DE,HL ; Cmd adr in HL JP (HL) ; Go exec it CMDS: DB ' ' ; DB '-' ; DB 'A' ; DB 'B' ; DB 'C' ; DB CTRLC ; DB 'F' ; DB CTRLK ; DB '/' ; DB 'Q' ; DB 'R' ; DB 'T' ; DB 'X' ; DB CTRLX ; DB ESC ; DB '/' ; DB '?' ; ENDCMDS: CMDADR: ; in reverse order DW HELP ; ? DW HELP ; / DW QUIT ; Esc DW QUIT ; ^X DW QUIT ; X DW TOGGLETRUNC ; T DW REPEAT ; R DW QUIT ; Q DW HELP ; / DW QUIT ; ^K DW FIND ; F DW QUIT ; ^C DW REPEAT ; C DW BACKAPAGE ; B DW ALTDISPLAY ; A DW BACKAPAGE ; - DW SINGLELINE ; GETCHNUM: ; accumulate numeric jumpto ; return if non-numeric or jumpto > hipg IF DELAY ; For pg # entry IF ZCPR3 CALL GETSPEED LD DE,DELAY/4 LD HL,00 DLYLP: ADD HL,DE DEC A JR NZ,DLYLP ELSE LD HL,DELAY ENDIF LD (TIMER),HL ; Reinit key delay timer ENDIF WAIT: LD C,DIRIO ; Direct cons io LD E,0FFH ; Read CALL BDOS OR A ; Anything typed? IF DELAY ; Key delay timer JR NZ,GOTKEY ; Something typed LD A,(JUMPTO) ; Building a jumpto number? OR A JR Z,WAIT ; No, just waiting for godot LD HL,(TIMER) DEC HL ; Timer-- LD (TIMER),HL LD A,H OR L ; Timer at 0? JR NZ,WAIT ; No, not timed out RET ; Exec jumpto now GOTKEY: ELSE ; Disabled delay timer JR Z,WAIT ; Not yet, so wait ENDIF ; Delay ; chk for pg number digits to jump to CP '0' RET C ; Non-numeric CP '9'+1 RET NC ; it's a digit: echo it PUSH AF ; Save digit CALL PUTC POP AF SUB '0' ; Remove ascii # bias LD B,A ; Save new digit ; times 10 + add new digit LD A,(JUMPTO) ; So far ADD A,A ; *2 LD C,A ADD A,A ; *4 ADD A,A ; *8 ADD A,C ; *10 ADD A,B ; Add in new digit LD (JUMPTO),A ; So far ; 0 here jumps to tof RET Z ; see if approx enuf digits to deduce jp pg: hipg / 8 < jpto LD B,A LD A,(HIPG) SRL A SRL A SRL A ; Hipg / 8 CP B ; Cy if < jpto? JR NC,GETCHNUM ; Might need 1 more digit RET DEFAULT: ; default cmd is page forward, cancel any found marking XOR A LD (FOUND),A LD HL,PAGE INC (HL) ; Page++ DEF1: JP PRPG BACKAPAGE: ; back 1 pg, cancel any found marking XOR A LD (FOUND),A BACKPAGE: CALL PGMINUS1 JR DEF1 PGMINUS1: LD A,(PAGE) DEC A ; Page-- ; chk for pg # 0 ; or a ;no IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; Repeat srch fr tof: circular ENDIF SET4MATCHSTART: JP STARTSRCHHERE ; print find prompt, get $ to find, srch for it FINDASTRING: XOR A LD (HEXSRCH),A ; Not hex srch yet CALL MSG DB 'Find: ',0 LD DE,STRMAX LD C,RDBUFF ; Read user $ CALL BDOS LD A,(STRLEN) OR A JP Z,FINDFAILS ; Null $ aborts find ; chk if finding a string of hex bytes ; B = user input ctr-- ; C = hi nbl flag if yes (0ffh), else C = hi nbl ; DE = *temp hex $ ; HL = *user input chars LD B,A ; Ch count LD A,(STRING) CP HEXSIGNAL ; Hex signal ch? JR NZ,FINDTEXT ; No DEC B ; Count-- for signal char JR Z,FINDTEXT ; Find - only LD A,1 CP B ; Find half nbl only? JR Z,FINDTEXT LD DE,HEXSTRING ; *temp hex out $ LD HL,STRING+1 ; Pt at 1st valid hex ch LD C,YES ; Set hi/lo flag = hi nbl NEXTHEX: LD A,(HL) ; Next user char INC HL CALL MKHEXDIGIT ; Strip ascii JR C,FINDTEXT ; Bad hex digit, do normal text srch PUSH AF LD A,C CP YES ; Doing hi nbl? JR NZ,LONBL ; No, doing lo nbl ; hi nbl goes in C POP AF SLA A SLA A SLA A SLA A ; After shift to 4 hi bits LD C,A ; Save hi nbl in C ; this also sets hi/lo nbl flag to lo (not hi) JR GOTHI LONBL: POP AF OR C ; Combine hi & lo nbls LD (DE),A ; Store into temp hex $ INC DE ; *temp++ LD C,YES ; Set hi nbl flag again GOTHI: DJNZ NEXTHEX ; ascii to hex transl done LD H,D LD L,E ; *last hex byte stored LD DE,HEXSTRING ; Base adr of hex$ XOR A SBC HL,DE ; # of bytes stored LD A,L LD (STRLEN),A ; Adj string len LD C,A ; # of bytes to copy LD B,0 LD HL,HEXSTRING ; Src LD DE,STRING ; Lst LDIR ; Copy hex$ to string buffer LD A,YES LD (HEXSRCH),A ; Call for a hex srch, no hi bit masking FINDTEXT: IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; Default srch start at tof ENDIF LD A,(CORE) OR A ; Find in core dump? JR Z,FFILE ; No, in a file LD DE,0 ; Default find in core starts at adr 0 FFILE: ; IF FINDFRTOP ; Start find on curr pg ELSE ; Avoid assembler specific .NOT. syntax LD A,(PAGE) ; Curr pg LD B,A ; Save curr pg LD A,(CORE) OR A JR NZ,FINCORE ; Pg 0 is 0'th ptr in core DEC B ; 0'th ptr is pg 1 if not core FINCORE: ; LD L,B ; LD H,0 ADD HL,HL ; *2 for word adr LD DE,PTRTBL ADD HL,DE ; Idx into ptrtbl LD E,(HL) ; Get pg adr INC HL LD D,(HL) ENDIF ; NOT FINDFRTOP STARTSRCHHERE: ; DE set for start of srch LD HL,(EOFADR) LD A,(NONTEXT) OR A ; In nontext display? JR NZ,OK2FINDEOF ; Yes DEC HL ; Dont allow srch for eof if in text display OK2FINDEOF: XOR A ; Clr cy LD (FRCMDMODE),A ; Set not fr cmd mode SBC HL,DE ; Len left to scan JR C,FINDFAILS ; Borrow = start srch beyond eof JR Z,FINDFAILS ; At eof: nothing to scan LD B,H ; Len goes in LD C,L ; BC for cpir EX DE,HL ; HL=start srch adr LD IX,MATCHES ; *matches so far MATCH1ST: ; find the 1st char of $ LD (IX),0 ; Count of chars matched so far LD DE,STRING ; *$ LD A,(DE) ; Get 1st char to find CPIR ; This does exact matching only ; Will not find 1st char with bit 7 set ; In text srch; ok in hex srch PUSH HL POP IY ; Iy = start adr of match + 1 JR Z,MATCHSEQ ; Matched 1st char FINDFAILS: XOR A ; Failure to find LD (FOUND),A LD (MATCHADR),A LD (MATCHADR+1),A IF ZCPR3 LD HL,($MEMRY) ELSE LD HL,BUFFER ; Repeat finds start at tof ENDIF LD A,(CORE) OR A JR Z,FILEFAIL ; Failed file srch LD HL,00FFH ; Failed core srch ; Can't repeat on pg 1 anyway FILEFAIL: LD (RESUMESRCH),HL RET ; now try to match rest of $ sequentially MATCHSEQ: INC (IX) ; Bump successes LD A,(STRLEN) ; # to match CP (IX) ; Matched whole $? JR Z,FOUNDSTRING ; Yes ; chk for eof LD A,B ; Hi char ctr OR C JR Z,FINDFAILS ; At eof DEC BC ; Len remaining to srch-- ; do this so we're semi-compatible with ws doc files ; 2nd & later matches ignore bit 7 if not srching for hex bytes EX DE,HL ; DE = *buffer, HL = *$ INC HL ; *$++ = next ch to match LD A,(HEXSRCH) ; Srch for hex bytes? OR A LD A,(DE) ; Fetch next char fr buffer JR NZ,NOMASK ; Don't mask if hex srch AND 7FH ; Mask hi bit for ws if not hex srch NOMASK: CP (HL) ; Matches char in $? EX DE,HL ; DE = *$; HL = *buffer again INC HL ; *next in buffer++ JR Z,MATCHSEQ ; This ch matched: chk next ch in $ ; 2nd ch or later failed to match: back to 1st ch matched + 1 PUSH IY POP HL ; Restore *file to 1st ch matched + 1 LD A,(IX) ; Count of successful matches BACK2CH1P1: INC BC ; Adj len remaining to srch DEC A ; Successes-- JR NZ,BACK2CH1P1 JR MATCH1ST ; Start srch again for 1st ch FOUNDSTRING: ; find out what pg match is in PUSH IY POP DE ; *1st matching char + 1 DEC DE ; *1st matching char LD (MATCHADR),DE ; Actual match adr of 1st found ch LD L,A ; Strlen LD H,0 ADD HL,DE LD (RESUMESRCH),HL ; Resume after this match LD IX,PTRTBL LD A,(CORE) ; Ff if in core LD B,A ; 0 if file NEXTPG: INC B ; Pg++ LD L,(IX) ; Lo pg adr INC IX LD H,(IX) ; Hi pg adr INC IX ; To next ptr XOR A ; Clr cy SBC HL,DE JR C,NEXTPG ; Not far enuf ; Nc = HL > DE is 1 pg too far JR Z,NEXTPG ; HL = DE = 1st byte on next pg ; B has page # + 1 so do backpage THISPAGE: LD A,YES LD (FOUND),A RET MKHEXDIGIT: ; called fr find for hex digit input ; strip ascii stuff fr possible hex digit in a ; cy set if invalid CP '0' RET C ; '0' CP '9'+1 ; Cy if '0' to '9' JR NC,CHKATHRUF AND 0FH ; Mask to hex nbl JR OKHEX CHKATHRUF: SET 5,A ; Tolower CP 'a' RET C ; Invalid CP 'f'+1 ; Cy if 'a' to 'f' CCF RET C ; No good ADD A,0A9H ; Make hex nbl OKHEX: SCF CCF ; Set no cy for ok RET MSG: ; print a null terminated string at ret adr of this sub ; ctrl chars are ok in ql msgs LD A,YES LD (FROMQLMSG),A ; Flag this as a ql msg: ctrl chars are ok MSG1: EX (SP),HL ; HL=*string LD A,(HL) ; Get char INC HL ; *ch++ EX (SP),HL ; Restore ret adr if done OR A ; Ch = 0 msg term? ; ret Z ;done JR Z,MSGDONE CALL PUTC ; Print ch JR MSG1 ; MSGDONE: LD (FROMQLMSG),A ; Mark false RET CRLF: LD A,CR CALL PUTC LD A,LF PUTC: ; character to go in a ; regs B thru L are saved and restored ; ix and iy are not for speed PUSH BC ; Save registers PUSH DE PUSH HL PUSH AF ; } CALL BYECHK ; } Process and handle on the fly aborts, etc. CALL NZ,CKABRT ; } (if running remote only). Only adds a few POP AF ; } cycles during local operation. AND 7FH ; Mask to ascii CP CR JR NZ,NOTCR ; cr zeroes col ctr XOR A LD (COL),A LD A,CR JR PUTCH NOTCR: LD B,A ; Save ch LD A,(TRUNKSTATE) CP 'N' ; Truncation on? JR NZ,NOTTOOLONG ; No, any line len ok LD A,(COL) ; IF ZCPR3 ;; PUSH BC ; Uncomment for Z3LIB 1.3 or older? CALL GETCRT ;; POP BC ; Uncomment for Z3LIB 1.3 or older? LD H,(HL) DEC H DEC H CP H ELSE CP COLUMNS-2 ; At max line len? ENDIF JR C,NOTTOOLONG ; No, line len still ok JR NZ,BIOSRET ; Already marked '>': skip this char ; at truncation pt: mark with '>' INC A ; To columns-1 LD (COL),A ; So next ch won't mark trunc again LD A,TRUNKCHAR ; Truncation marker JR PUTCH NOTTOOLONG: LD A,B ; Get ch back CP ' ' JR NC,PRINTABLE ; Count all printables ; chk ctrl chs we can handle CP LF ; Masked lf is ok JR Z,PUTCH CP TAB JR NZ,NOTTAB ; adjust col count assuming tabs 0,8,16... IF EXPANDTABS ; Expand tabs to equiv spaces LD A,(COL) CPL AND 7 ; Mod 8 INC A LD B,A ; Spaces to next tab stop XTAB: CALL SPACE ; Send spaces to tab stop DJNZ XTAB JR BIOSRET ; Restore regs & ret ELSE ; Term can handle actual tab ch LD A,(COL) AND 0F8H ; Mask off lo 3 bits ADD A,8 ; To next tab stop LD (COL),A ; Set new column LD A,TAB JR PUTCH ENDIF ; Expand tabs NOTTAB: CP BS JR NZ,NOTBS LD HL,COL DEC (HL) ; Col-- JR PUTCH ; we can't handle other ctrl chars UNLESS they're coming from ; a ql message, like clear screen or an escape seq ; this should filter all remaining ws doc chars NOTBS: LD B,A ; Save curr ch LD A,(FROMQLMSG) OR A LD A,B ; Get curr ch back JR NZ,PUTCH ; Ctrl ch from a ql msg, takes no line space IF CTRLDISPLAY ;................................ ; Display using the combination ^ PUSH BC ; Save a copy of the char, still in B LD A,'^' ; "control" CALL CONO ; Output that LD HL,COL ; Adjust for the "^" character INC (HL) ; Col++ POP BC ; Get the control char back LD A,B ; (char was in B) OR 40H ; Make it the corresponding non-cntrl char JR NOTCR ; Start this routine all over again ;...............................; ELSE ; CTRLDISPLAY LD A,CTRLMARKER ; Defined char to use ENDIF ; CTRLDISPLAY PRINTABLE: OR A ; Filter out NULL's, and don't incr COL JR Z,BIOSRET ; LD HL,COL ; INC (HL) ; Col++ PUTCH: CALL CONO ; Output the character BIOSRET: POP HL ; Restore regs POP DE POP BC RET ;................................ ; Generalized low-level single char output (A) CONO: ; Use BIOS or BDOS, as requested IF USEBIOSCONOUT ; LD C,A ; Goes in C for BIOS LD HL,(BIOSCONOUT) ; JP (HL) ; Do it; return directly from there ; ELSE ; LD E,A ; Goes in E for BDOS LD C,CONOUT ; Console output function JP BDOS ; Output the char and return from there ENDIF ; ;...............................; ;.............................................................................. ; PUTPGNUM: CALL MSG ; Start page title in lower left corner DB ': Page ',0 ; print current pg number LD A,(PAGE) LD L,A LD H,0 CALL B2DEC ; Convert to printable # & print CALL MSG DB ' of ',0 ; print max pg number LD A,(HIPG) LD L,A LD H,0 CALL B2DEC ; add marker if read was incomplete LD A,(INCOMPLETE) OR A JR Z,SPACE LD A,'+' CALL PUTC SPACE: LD A,' ' JP PUTC ; &ret SPACE2: CALL SPACE JR SPACE ; &ret IF DOSPLUS ; Under dos+ B2DEC: ; print binary # in HL as decimal, lead 0's suppressed LD D,H LD E,L LD C,211 ; New bdos call to print DE as decimal # JP BDOSCALL ; &ret ELSE ; The long way under cp/m 2.2 ; convert 16 bit binary # in HL to up to 5 ascii decimal digits & print ; suppress leading 0's ; rtn fr Alan Miller, 8080/z80 assembly language B2DEC: LD B,0 ; Leading 0 flag LD DE,-10000 ; 2's cpl of 10k CALL SUBP10 LD DE,-1000 CALL SUBP10 LD DE,-100 CALL SUBP10 LD DE,-10 CALL SUBP10 LD A,L ADD A,'0' ; Ascii bias JP PUTC ; &ret ; subtract power of 10 & count SUBP10: LD C,'0'-1 ; Ascii count SUB1: INC C ADD HL,DE ; Add neg # JR C,SUB1 ; one subt too many, add 1 back LD A,D ; Cpl DE CPL LD D,A LD A,E CPL LD E,A INC DE ; Add back ADD HL,DE LD A,C ; Get digit ; chk for '0' CP '1' ; '0'? JR NC,NONZERO ; No LD A,B ; Chk leading 0 flag OR A ; Set? LD A,C ; Get digit RET Z ; Skip leading 0 PRDIGIT: JP PUTC ; Print interior 0 NONZERO: LD B,YES ; Set leading 0 flag JR PRDIGIT ENDIF ; Not dosplus ; hex/ascii display code ; pg 0 is now really pg 0 if core dumping HEXASCII: ; display 256 bytes from pg# in a LD B,A ; Save pg to show LD A,(CORE) OR A JR NZ,HEXOFCORE ; Core dump 0'th pg ptr is pg 0 DEC B ; 0'th pg ptr is page 1 HEXOFCORE: LD H,B ; LD L,0 IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ; 1st pg of file dump is here ENDIF LD A,(CORE) OR A ; Displaying memory? JR Z,DUMPHERE ; No, showing file LD DE,0 ; 1st pg is beg of mem DUMPHERE: ADD HL,DE ; HL pts to pg start adr LD B,16 ; Show 16 lines NXTLINEHEXASC: PUSH BC ; Save ctr CALL DOHEXASCII POP BC ; Restore ctr DJNZ NXTLINEHEXASC RET DOHEXASCII: ; display 1 line (16 chs) of hex/ascii ; on entry: HL pts into buffer at start of line ; on exit: HL pts into buffer after last byte printed ; push BC ;save caller counter (safer if done in caller) LD B,16 ; # of bytes per line ; put the adr of this line PUSH HL ; Save ptr adr LD A,(CORE) OR A ; Displaying core? JR NZ,SHOWCOREADR ; Yes, show real adr IF ZCPR3 LD DE,($MEMRY) ELSE LD DE,BUFFER ENDIF XOR A ; Clr cy SBC HL,DE LD DE,100H ; Add 100h bias for cpm tpa ADD HL,DE SHOWCOREADR: LD A,H PUSH AF CALL PUTHINIBBLE POP AF CALL PUTLONIBBLE LD A,L PUSH AF CALL PUTHINIBBLE POP AF CALL PUTLONIBBLE CALL SPACE2 POP HL ; Get ptr adr back HEXLOOP: ; chk if marking a found string LD A,(FOUND) OR A JR Z,HEXNOMARK ; Not marking LD A,(HEXSRCH) OR A JR Z,HEXNOMARK ; Showing on ascii side only CALL ATMATCHADR JR NZ,HEXNOMARK CALL ONHILITE LD A,(HL) INC HL PUSH AF ; Save byte to display CALL PUTHINIBBLE POP AF CALL PUTLONIBBLE CALL OFFHILITE PUSH BC PUSH HL CALL FINDAGAIN ; Find next match POP HL POP BC JR HEXBYTEDONE HEXNOMARK: LD A,(HL) INC HL PUSH AF ; Save byte to display CALL PUTHINIBBLE POP AF CALL PUTLONIBBLE HEXBYTEDONE: CALL SPACE LD A,B ; Byte ctr CP 9 ; Half way thru hex display? CALL Z,SPACE ; If so, add an extra space DJNZ HEXLOOP ; now do ascii transl of these chs CALL SPACE LD DE,-16 ADD HL,DE ; Back ptr up 16 LD B,16 ASCIILOOP: ; chk if marking a found ascii string, just like for hex LD A,(FOUND) OR A JR Z,ASCNOMARK ; Not marking LD A,(HEXSRCH) OR A JR NZ,ASCNOMARK ; Showing on hex side only CALL ATMATCHADR JR NZ,ASCNOMARK CALL ONHILITE LD A,(HL) INC HL CALL PUTCIFASCII CALL OFFHILITE PUSH BC PUSH HL CALL FINDAGAIN POP HL POP BC JR ASCBYTEDONE ASCNOMARK: LD A,(HL) INC HL CALL PUTCIFASCII ASCBYTEDONE: DJNZ ASCIILOOP LD (CURRLINE),HL ; Save ptr to curr 'line' LD A,CR CALL PUTC LD A,(LINEBYLINE) OR A RET NZ ; jr NZ,dontlf LD A,LF ; call putc JP PUTC ; &ret ; dontlf: ; pop BC ; HL) PUSH HL ; Save *buffer LD DE,(MATCHADR) XOR A SBC HL,DE ; Z = at match adr; cy if matchadr > HL POP HL RET ;------------------------------------------------------------------------------ ; Routine to check for and handle ^S (pause) and ^C, ^K, etc, (abort). ; This routine is called continuously (from PUTC) when running remote. ; Local users can wait till the next screen ends. ; CKABRT: PUSH AF ; Save all regs PUSH BC PUSH DE LD C,DIRIO ; Normally, just check console status. LD E,0FFH ; CALL BDOS OR A JR NZ,GOT1 ; (if a character is available) RETABT: POP DE ; Always return from this subr from here POP BC POP AF RET ;.............................................................................. ; ; Analyze the character received ; GOT1: CP 'S'-40H ; ^S pauses JR Z,WA4CH ; Yes, go to pause loop GOT1B: AND 1FH ; ^C, ^K, ^X, C, K, X, etc all abort CP CTRLC JR Z,ABRT CP CTRLK JR Z,ABRT CP CTRLX JR NZ,RETABT ; Ignore other keys ABRT: JP QLEXIT ; Fix stack and exit direct WA4CH: LD C,DIRIO ; Loop till we get any character LD E,0FFH CALL BDOS OR A JR Z,WA4CH JR GOT1B ; Continue. Process the char also, but not ^S. IF ZCPR3 $MEMRY: DS 2 ENDIF ;============================================================================== IF ZCPR3 DSEG ENDIF ; v2.5 - Below is the data storage for the UNC.AZM code. In previous versions, ; this data was allocated in the middle of the code segment. ; ; effective DSEG starts here. Stuff below is initialized by the UNC.AZM code. ; other unitialized storage is initialized each run by code in QL. ; FULFLG: DEFS 1 ; "ff" when table is full LASTPR: DEFS 2 ; Last pred ENTFLG: DEFS 1 ; "already entered in table" flag CODES: DEFS 2 ; Current code? LFTOVR: DEFS 1 ; Previous input bits still unused WIDTH: DEFS 1 ; Current encoded cell width TRGMSK: DEFS 1 OUTFLG: DEFS 1 ; Last output char DEFS 1 ; Repeat flag for output (at outflg+1). 0 or 1 SPSAVE: DEFS 2 KIND: DEFS 1 ; Version to be decoded. 0..1 for 10/20 resp. CHAR: DEFS 1 ; Last char of the previously decoded string AVAIL: DEFS 2 ; Hi byte is reassigning code flag when 0ffh FFFLAG: DEFS 1 ; Force entries to be marked referenced NEXTX: DEFS 2 ; Next hashed index ?? @TABLE: DEFS 2 ; Base of decoding table XLATBL: DEFS 2 ; Translation table, hash to entry TBLTOP: DEFS 2 ; Negated address TROOM: DEFS 2 ; Space left in table STKLIM: DEFS 2 ; Stack usage limit ;============================================================================== ; ; Stuff below this point is for QL itself (as opposed to the UNC.AZM module) ; IF ZCPR3 DISPLAY: DS 1 ENDIF BIOSCONOUT: DS 2 ; Adr of jp to bios console out rtn OLDSP: DS 2 ; Calling program sp ; find string buffer for bdos 10 calls STRMAX: DS 1 ; v2.5 initialized to "40" at startup ;;;;;;;;; DB 40 ; Max chars in find string ; ; storage init by ldir at startup for zcpr go cmd ; next 2 storage alloc must follow strmax for bdos 10 to work ; INITSTORAGE: ; (beg of mem initialized to all zero) ; STRLEN: DS 1 ; # chars typed by user. } Must follow STRING: DS 40 ; Find string. } STRMAX abv! CCPCHKSUM: DS 1 ; Chksum of entire ccp CORE: DS 1 ; Flag for hex dumping memory COL: DS 1 ; Current display column CURRLINE: DS 2 ; *lf of curr line EOFADR: DS 2 ; Highest adr used FILELEN: DS 2 ; File length in bytes FOUND: DS 1 ; Flag for marking found string FRCMDMODE: DS 1 ; Flag for find or repeat cmd FROMQLMSG: DS 1 ; Flag for curr ch from a ql msg: ctrl chs ok HEXSRCH: DS 1 ; Flag for hex byte srching HEXSTRING: DS 20 ; Temp storage for hex byte find $ HIPG: DS 1 ; Highest pg number INCOMPLETE: DS 1 ; Incomplete read flag JUMPTO: DS 1 ; Pg # to jumpto LASTUNSQCH: DS 1 ; Saved for repeat count LASTPGLINES: DS 1 ; # of lines on last pg for summary LIBRARY: DS 1 ; Flag for working with library LINEBYLINE: DS 1 ; Flag for 1 line forward display MATCHADR: DS 2 ; Adr of 1st char find $ match MATCHES: DS 1 ; Chars matched so far in find MEMBER: DS 11 ; Member name as fn ext NSECTS: DS 2 ; # of member sects to read from lbr NMEMBERS: DS 1 ; # of active members in lbr NONTEXT: DS 1 ; Flag for hex/ascii dump PAGE: DS 1 ; Current page # RESUMESRCH: DS 2 ; Repeat find start adr SUPPRESSING: DS 1 ; Leading 0 suppression flag TIMER: DS 2 ; Key delay timer for jumpto page FNEXT: DS 11 ; Moved to initialized data area (v2.4) UNCRSRC: DS 2 ; Memory based ptrs for uncruncher UNCRDST: DS 2 ; And unsqueezer WORKAREA: DS 2 ; Debug ptr to 24k uncruncher work area WSDOC: DS 1 ; Flag for wordstar doc file BYE5FLAG: DS 2 ; 0800h if bye5 is resident, else 0000 BDOSBASE: DS 2 ; ;----- ; Mem allocation below this point done with EQU's to avoid generating lot's ; of zeroes in the COM file when using dumb assemblers/linkers. ; PTRTBL: ; (ds 1024) ; ; ds 512 bytes for 256 pg ptrs max ; alloc 512 bytes for extra large unsq translation table (> 80h groups of 4) IF ZCPR3 DS 1024 ENDINITSTORAGE: DS 40 STACK: DS 0 ELSE ENDINITSTORAGE EQU PTRTBL+1024 ; Last byte to be init at startup ; (ds 40) ; local stack area STACK EQU ENDINITSTORAGE+40 BUFFER EQU STACK ; File buffer area above the program ; Uses the rest of ram to bdos ENDIF END;QL