; SUBTITLE Main source-code file for SuperZap ;---------------- I/O EQUATES --------------- CMD EQU 0080H FBUFF EQU 0080H ; Note: The CP/M 2.2-specific version of this program used the default ; file I/O buffer at 80H for all disk operations, i.e., for file- ; oriented AND physical I/O. Under CP/M 3, this is not tenable ; because the BIOS deals with physical sectors rather than 128- ; byte "logical" sectors and physical sectors can be much larger ; than 128 bytes. ; ; Physical disk I/O for CP/M 3 now uses an area set aside at ; the end of this program, before the clipboard. 2048 bytes has ; been reserved. That should be enough; I don't know of any ; system that supports physical sectors larger than 1024 bytes, ; but the notes on the WD1797 floppy-disk controller (FDC) ; indicate that 2048 is also a possible sector size. ; ; JHB January 1986 ; ;---------------- CP/M SYSTEM-CALL CODES ---------------- CPM EQU 0005H ;CP/M call address GETVSN EQU 12 ;Get CP/M Version Number RESET EQU 13 ;Reset Disk System OPEN EQU 15 ;Open File CLOSE EQU 16 ;Close File FNDFST EQU 17 ;Find First Directory Match FNDNXT EQU 18 ;Find Next Directory Match GETDEF EQU 25 ;Get Current Drive ID SDMA EQU 26 ;Set DMA Address (required for CP/M 3) USERNO EQU 32 ;Get/Set User Number READRN EQU 33 ;Read Random Record WRITRN EQU 34 ;Write Random Record FILESZ EQU 35 ;Compute File Size ;---------------- DEFAULT FCB IMAGE ---------------- WRKFCB EQU 005CH ;default FCB address WRKDR EQU WRKFCB+0 ;drive WRKFN EQU WRKDR+1 ;filename body WRKFT EQU WRKFN+8 ;filename extension WRKEX EQU WRKFT+3 ;extent number WRKS1 EQU WRKEX+1 ;CP/M reserved WRKS2 EQU WRKS1+1 ;CP/M reserved WRKRC EQU WRKS2+1 ;record count this extent WRKMP EQU WRKRC+1 ;allocation map for extent WRKNR EQU WRKMP+16 ;next sequential record WRKRR EQU WRKNR+1 ;two-byte random record number WRKOV EQU WRKRR+2 ;random overflow flag FREESP: DW ENDCDE ;allow user code insertion ;---------------- MESSAGE AREAS ---------------- HLAREA EQU 0109H ;help lines 01-10 (01 for 09) DRAREA EQU 0E08H ;directory lines 14-21 (14 for 08) HDRMSG: DB 0,33,'SuperZap ',$VER,'.',$MOD,0 ;---------------- GLOBAL WORK AREAS ---------------- MEMRY: DS 2 ;free memory space CPM3: DS 1 ;CP/M 3 flag READST: DB 0FFH ;return code from read operations INCH: DB 0 ;input character TYCURC: DB 0 ;current character for type RELREC: DW 0 ;current record number BUFPOS: DS 1 ;current position in buffer LINESC: DS 2 ;line count for type display BASEAD: DS 3 ;page/record number for type SAVREC: DW 0 ;save record during set SAVFSC: DW 0 ;record to be read RO: DB 0 ;read-only flag NEWDE@: DS 2 ;address of entry just found NXTDE@: DS 2 ;next position in table TOPDE@: DW 0 ;top of directory table FSTDE@: DW 0 ;bottom of directory table DECNT: DB 0 ;number of entries read PRTCNT: DB 0 ;number of entries displayed SELDE: DS 1 ;selected directory entry DIROFF: DB 0 ;directory display offset DEFDRV: DS 1 ;current drive ID CURAN: DS 1 ;current absolute drive number ERRFLD: DW 0 ;error field on screen DB 0 ;end-of-field mark ERRTXT: DW 0 ;address of error text PRVERR: DW 0 ;address of previous text WTG: DB 0 ;next process mode AFNSTR: DB '???????????' ;ambiguous file name/type DSKCMD: DB 'DSK:' ;selects sector mode from command line PGEPTR: DS 2 ;address of page pointer list CURPG@: DS 2 ;address of current page entry MAXPG@: DS 2 ;address of last page entry RPANEL: DS 1 ;display panel request ;------------------ CLIPBOARD DATA ----------------- CBADDR: DS 2 ;clipboard-buffer address CBTYPE: DS 1 ;none/physical/relative CBSECT: DS 2 ;sector number CBDRIV: DS 1 ;absolute drive number CBNAME: DS 12 ;ufn or track number DB 0 ;end-of-field mark CBDMSG: DB 'Drive ',0 CBTMSG: DB ' Track ',0 CBSMSG: DB ' Sector ',0 CBEMTY: DB 'Empty',0 ;---------------- DIRECTORY-MODE FCB ---------------- LMDFCB EQU $ LMDDR: DB 0 ;drive LMDFN: DS 8 ;file name LMDFT: DS 3 ;file type LMDEX: DB 0 ;extent number LMDS1: DB 0 ;reserved for system (1) LMDS2: DB 0 ; (2) LMDRC: DB 0 ;record count LMDD0: DS 16 ;cluster-allocation map LMDCR: DB 0 ;current record ; LOCAL BIOS COPY ; Used to simplify direct BIOS calls LBIOS EQU $ WBOOT: CALL BIOS3 ;For CP/M 3, we make all of these CONST: CALL BIOS3 ; branch to the same place. From CONIN: CALL BIOS3 ; there, we will do a "come from" CONOUT: CALL BIOS3 ; statement to figure out which LIST: CALL BIOS3 ; routine was called. PUNCH: CALL BIOS3 READER: CALL BIOS3 ;For CP/M 2.2, these CALLs will HOME: CALL BIOS3 ; be overlaid with a copy of the SELDSK: CALL BIOS3 ; jump table at the beginning of SETTRK: CALL BIOS3 ; the BIOS. SETSEC: CALL BIOS3 SETDMA: CALL BIOS3 ;Jan 86 - jhb READ: CALL BIOS3 WRITE: CALL BIOS3 LISTST: CALL BIOS3 SECTRN: CALL BIOS3 ; Note that the entire CP/M 3 BIOS table is not represented here. ELBIOS EQU $ ;end of local BIOS ; INIT - SUPERZAP INITIALIZATION INIT: LD HL,(0006H) LD L,0 ;don't interfere with any RSXs LD SP,HL ;set stack to base of BDOS LD C,GETVSN ;test CP/M version CALL CPM ; set 'CPM3' to 0 if CP/M 2.2 LD A,2FH ; or to 1 if CP/M 3 SUB L LD A,H ;pull in MP/M flag, too JR NC,NOTPLUS INC A NOTPLUS:LD (CPM3),A ;zero if CP/M 2.2, non-zero if MP/M or CP/M 3 OR A ;only copy BIOS vector if CP/M 2.x JR NZ,NOLOCAL LD HL,(0001H) ;load BIOS vector address LD DE,LBIOS LD BC,ELBIOS-LBIOS LDIR ;set up local BIOS vector NOLOCAL:LD HL,AFNSTR CALL LSEL ;set list selection to all LD HL,(FREESP) ;find top of program LD (CBADDR),HL ;set clipboard address LD DE,80H ADD HL,DE LD (MEMRY),HL ;put work area above clipboard XOR A LD (CBTYPE),A ;set clipboard empty LD HL,0 LD (ERRTXT),HL ;clear error-message field LD (PRVERR),HL ; and previous error LD C,GETDEF CALL CPM ;get default drive number LD (DEFDRV),A ; and save it LD (CURAN),A ;set current absolute disk number LD A,(WRKDR) OR A JR Z,INIT01 ;IF drive ID not in command DEC A ;ELSE LD (CURAN),A ; use that as current INIT01 EQU $ ;ENDIF LD HL,CMD ;point to command area INIT02: INC HL ;LOOP LD A,(HL) OR A JR Z,INIT05 ;CASE end of command CP ' ' JR Z,INIT02 ;ignore spaces INC HL LD A,(HL) CP ':' JR Z,INIT03 ;if command is drive ID, skip past it DEC HL ;else point to first character JR INIT04 INIT03: INC HL ;skip past drive ID INIT04: LD DE,DSKCMD LD BC,4 CALL CPST CALL Z,SETP ;if disk option JR Z,INIT07 ; set physical-sector mode INIT05: CALL SETD ;else assume directory mode LD HL,WRKFN LD A,(HL) CP ' ' JR Z,INIT07 ;IF not null option LD B,11 ;ELSE check for afn INIT06: LD A,(HL) CP '?' JR Z,INIT08 ;CASE afn indicated INC HL ;else DJNZ INIT06 ; loop till fn and ft scanned CALL SETF ;must be ufn, so set file mode INIT07: LD A,(CURAN) ;ENDIF CALL CHDR ;initialize disk-control blocks JR Z,INIT09 ;if illegal disk, set error msg JR MAIN ;else head for mainline INIT08: LD HL,WRKFN ;on '?' found CALL LSEL ;set list selection to afn given JR INIT07 INIT09: LD A,(DEFDRV) ;use default disk CALL CHDR LD HL,ILDMSG LD (ERRTXT),HL ;set error message ; and fall through to mainline ; MAIN - SUPERZAP MAINLINE ; Deleted useless attempt to restore default drive by a disk-system reset ; (BDOS function 13) before program exit, since the final warm boot will ; accomplish this anyway. - gah MAIN: LD A,(WTG) ;LOOP $MTCH MAINLS ;test code JR NZ,MAIN01 ;exit if no command waiting $EXVA MAINVC ;else execute action JR MAIN ;ENDLOOP MAIN01: call clrs ;gimme a fresh screen ; LD A,(DEFDRV) ;useless code! - gah ; LD E,A ; LD C,SETDEF ; CALL CPM ;restore original default drive ; LD C,RESET ; reset disk system ; CALL CPM rst 0 ; and exit to system ILDMSG: DB '** Invalid drive specified **',0 ; MAINLINE ACTION VECTOR MAINLS: DB 4,'XFDP' MAINVC EQU $ DW ENDR ;end run DW FDMD ;file-display mode DW DRMD ;directory mode DW PSMD ;physical-sector mode ; ENDR - END SUPERZAP RUN ENDR: XOR A LD (WTG),A RET ; FDMD - FILE-DISPLAY MODE FDMD: LD HL,(FDMDER) LD (ERRFLD),HL ;set error-field pointer LD A,TRUE LD (RPANEL),A ;request panel display LD (FDMDSI),A ;request si display CALL TFLE LD A,(FLERR) OR A JP NZ,SETD ;if file error, go set directory mode FDMD01: LD A,(RPANEL) OR A JR Z,FDMD03 ;IF panel not required XOR A ;ELSE LD (RPANEL),A ; reset request $NPANEL FDMDPN ; and display file-mode panel LD HL,FILEMS ;point to file message LD A,(COMFLG) OR A JR Z,FDMD02 ;IF not a .COM file LD HL,LOADMS ;ELSE point to load message FDMD02: CALL DFLD ;ENDIF $FLD FCBMSG CALL DCBI ;display clipboard info ld hl,sbohdr call dpnll ;display sector-buffer-offset header LD A,8 CALL CLRL ;clear error-msg line FDMD03 EQU $ ;ENDIF CALL ERRP ;process errors LD A,(FDMDSI) OR A JR Z,FDMD04 ;IF si display not required CALL DFSI ;ELSE display file-sector info LD HL,FBUFF CALL WRBF ;display buffer contents XOR A LD (FDMDSI),A ;reset request FDMD04 EQU $ ;ENDIF $IFLD SELMSG ;prompt selmsg and get command $MTCH FDMDLS CALL NZ,ALRM ;if invalid key, sound the alarm JR NZ,FDMD04 ; and loop $EXVA FDMDVC ;else execute command LD A,(WTG) CP 'F' JR Z,FDMD01 ;loop if still in file mode LD DE,WRKFCB LD C,CLOSE ;else close file JP CPM ; and exit COMFLG: DS 1 ;flag for .COM file ; FILE-SECTOR-DISPLAY MESSAGES, PANEL, AND ACTION VECTORS ; Under v3.4, new options added - July 86 pgm ; Added highlighted sector-buffer-offset header - Sept 90 gah SELMSG: DB 09,31,'Select option ==>',0 SETMSG: DB 11,34,'Enter Hex Sector:',0 ;overlaid by curmsg FDMDER: DB 07,00 ;error position FILEMS: DB 11,55,'File Offset ',0 LOADMS: DB 11,54,'Load Address',0 FDMDPN: DB 16 ;field count DB 02,03,'Next sector',0 DB 02,33,'Top of file',0 DB 02,60,'Return to file List',0 DB 03,03,'Previous sector',0 DB 03,33,'Bottom of file',0 DB 03,60,'Exit from SuperZap',0 DB 04,03,'Select Sector',0 DB 04,33,'Find ASCII string',0 DB 05,03,'Clipboard operations',0 DB 05,33,'Find Hex sequence',0 DB 05,60,'Edit sector',0 DB 11,03,'File Name',0 DB 11,16,'Access',0 CURMSG: DB 11,34,' Current Sector ',0 ;overlaid by setmsg DB 12,00 DRIVNM: DB 'd:' FILENM: DB 'filename.typ',0 DB 12,17,'R/' FDMDRS: DB 's ',0 ;access indicator DB 11 DB 02,00,'N',0 DB 02,30,'T',0 DB 02,57,'L',0 DB 03,00,'P',0 DB 03,30,'B',0 DB 03,57,'Z',0 DB 04,00,'S',0 DB 04,30,'A',0 DB 05,00,'C',0 DB 05,30,'H',0 DB 05,57,'E',0 FCBMSG: DB 06,03,'Clipboard :- ',0 SBOHDR: DB 1,14,00 ;sector-buffer-offset header DB 'Offset 0 1 2 3 4 5 6 7' DB ' 8 9 A B C D E F -----ASCII------' DB 0 ; The next few bytes used in file and physical-sector modes, for searches ; Variations to v3.5 - 2 Sept 86 pgm FNDPMT: DB 08,00,'Find:',0 STRPOS: DB 08,06,0 ;input position for find string NOTFND: DB 08,00,'NOT FOUND ',0 INTMSG: DB 08,00,'INTERRUPTED ',0 HITKEY: DB '- HIT ANY KEY',BEL,0 ;added - gah HITT: DB '- HIT FOR TOP',0 FNDCON: DB 13,65,'NEXT? (Y/N)',0 ; FILE STATISTICS FIELDS WRSNFL: DB 12,41,0 ;location of sector number WRFOFL: DB 12,57,0 ; offset SFSNIP: DB 12,41,0 ; hex input FDMDLS: DB 11,'NPTBZLESCAH';new extra options added - pgm FDMDVC EQU $ DW NXFS ;next file sector DW PRFS ;previous file sector DW FRFS ;position to first file sector DW LSFS ;position to last file sector DW SETX ;set exit mode DW SETD ;set directory mode DW FSCH ;edit file sector DW SFSN ;select file sector number DW FCBM ;file clipboard manager DW FASC ;find ascii string DW FHEX ;find hex sequence FDMDSI: DS 1 ;si request flag ; NXFS - READ NEXT FILE SECTOR ; Maybe it's just my caution or lack of complete comprehension ; of all of the code, but I DO think we could do with a good deal ; more register preservation in many routines....pgm NXFS: PUSH DE ;save some registers LD HL,(RELREC) INC HL LD (RELREC),HL ;increment record number CALL RDFS ;attempt to read record PUSH AF ;save file status CALL NZ,ALRM ;if bad read, sound alarm JR NZ,NXFS01 ; and exit LD A,TRUE LD (FDMDSI),A ;else request si display NXFS01: POP AF ;return file status in accumulator POP DE RET ; PRFS - READ PREVIOUS FILE SECTOR PRFS: LD HL,(RELREC) LD A,H OR L JP Z,ALRM ;if record zero, go sound alarm DEC HL LD (RELREC),HL ;decr record pointer CALL RDFS ;attempt to read it JP NZ,ALRM ;if bad read, go sound alarm JR RQSID ;go request si display ; FSCH - EDIT FILE SECTOR FSCH: LD A,(RO) OR A JP NZ,ALRM ;if r/o file, go sound alarm CALL SCCH ;go into sector-change mode LD A,(SCCHWR) OR A PUSH AF ;save flags CALL NZ,WRFS ;write out sector if required POP AF CALL Z,RDFS ;else read sector JP RQFSID ;redisplay file-mode panel ; and request si display ; FRFS - POSITION TO FIRST FILE SECTOR FRFS: LD HL,0 LD (RELREC),HL CALL RDFS ;read the sector JR RQSID ;go request si display ; LSFS - POSITION TO LAST FILE SECTOR LSFS: LD DE,WRKFCB LD C,FILESZ ;compute file size CALL CPM LD HL,(WRKRR) DEC HL LD (RELREC),HL ;set up record to read CALL RDFS ;read the record JR RQSID ;go request si display ; SFSN - SELECT FILE-SECTOR NUMBER ; Modified to use new GTHEX routine - 20 Sept 86 pgm SFSN: $CFLD SELMSG ;clear function prompt LD HL,(RELREC) LD (SAVREC),HL ;save record number LD (OLDHEX),HL ; - twice $FLD SETMSG ;display set message LD HL,0 LD (HEXFIG),HL ;zero our variable LD A,1 ;load code for display variables LD (HXDIS),A LD HL,SFSNIP ;store display point LD (HXHED),HL SFSN01 EQU $ ;LOOP CALL GTHEX ;go get hex data LD HL,(HEXFIG) LD (RELREC),HL ;put it away as found CALL RDFS CALL NZ,ALRM ;if read error, sound alarm JR NZ,SFSN01 ; and loop (alrm saves af) ;ENDLOOP $FLD CURMSG ;redisplay current sector message RQSID: LD A,TRUE LD (FDMDSI),A ;request si display RET ; FCBM - FILE CLIPBOARD MANAGER FCBM: $NPANEL PCBMPN ;display panel $FLD PCBCUR ;position for current info LD A,(CURAN) ADD A,'A' CALL CHRO ;display drive LD A,':' CALL CHRO $STRO FILENM $STRO CBSMSG $HEXW RELREC ;sector $FLD PCBCBD ;position for clipboard data CALL DCBD ;display clipboard data CALL CBCI ;get command $EXVA FCBMV ;process command RQFSID: LD A,TRUE LD (RPANEL),A ;request panel JR RQSID ;go request si display FCBMV EQU $ DW FCBX ;exit clipboard manager DW FLCB ;load clipboard (logical) DW FXCB ;exchange with clipboard with file sector FCBX: RET ; CBCI - GET CLIPBOARD COMMAND CBCI EQU $ ;LOOP $IFLD SELMSG ;get command $MTCH PCBML RET Z ;exit if valid CALL ALRM ;sound alarm JR CBCI ;ENDLOOP ; DCBI - DISPLAY CLIPBOARD INFO DCBI: LD A,(CBTYPE) OR A JR Z,DCBI02 ;CASE clipboard empty - display msg DEC A JR Z,DCBI03 ;CASE physical-sector mode LD A,(CBDRIV) ;get drive ADD A,'A' ;convert to ascii letter CALL CHRO ;display it LD A,':' CALL CHRO ;add a colon $STRO CBNAME ;display filename DCBI01: $STRO CBSMSG LD HL,(CBSECT) ; and sector JP HEXW DCBI02: LD HL,CBEMTY JP STRO DCBI03: $STRO CBDMSG LD A,(CBDRIV) ADD A,'A' CALL CHRO ;display drive ld a,':' call chro ;add a colon - gah $STRO CBTMSG $HEXW CBNAME ;track JR DCBI01 ; FXCB - EXCHANGE CLIPBOARD WITH FILE SECTOR FXCB: LD A,(CBTYPE) OR A JP Z,ALRM ;if clipboard empty, go ring bell LD A,(RO) OR A JP NZ,ALRM ;if file r/o, go signal error LD BC,(CBADDR) CALL DMASET ;set CP/M buffer CALL WRFS ;write buffer LD BC,FBUFF CALL DMASET ;restore dma CALL FLCB ;copy old buffer JP RDFS ;go reread sector ; FLCB - LOAD CLIPBOARD (LOGICAL) FLCB: LD HL,FBUFF LD DE,(CBADDR) LD BC,128 LDIR ;copy the buffer LD A,(CURAN) LD (CBDRIV),A ;set drive LD HL,FILENM LD DE,CBNAME LD BC,12 LDIR ;copy filename LD HL,(RELREC) LD (CBSECT),HL ;set sector number LD A,2 LD (CBTYPE),A ;set the type RET ; DFSI - DISPLAY FILE-SECTOR INFORMATION DFSI: $FLD WRSNFL ;position for sector number $HEXW RELREC ;display record number $FLD WRFOFL ;position for file offset LD HL,(RELREC) ;get record number XOR A SRL H RR L RRA LD (BASEAD+2),A LD A,(COMFLG) OR A JR Z,DFSI01 ;IF not .COM file INC HL ;ELSE bump pointer DFSI01 EQU $ ;ENDIF LD (BASEAD),HL ;save rec/2 JP PRTADR ;go print 3-byte address ; New section - remodified 17 Sept 86 pgm PATTRN: DS 20 ;maximum number of bytes to search for LASTHL: DS 2 ;pointers for last "lead" byte found LASTBC: DS 2 ; PREVHL: DS 2 ;pointers to find in earlier sector PREVBC: DS 2 ; OERLAP: DB 0 ;flag for pattrn overlapping sector buffers CURCH: DS 1 ;byte storage LSFLG: DS 1 ;flag for last sector byte CURCT: DS 1 ;current count of pattrn bytes CUHX: DS 1 ;temporary input-byte storage FNDMK: DB 2,'->' ;pointer for found string/sequence ; For find in physical-sector mode, ; FNDTR variable (track) with TARGET near TYPE ; FHEX - INPUT HEX SEQUENCE AND SEARCH FOR IT FHEX: XOR A LD (ASCII),A CALL HXIN JR FIND ; FASC - GET ASCII PATTERN FOR SEARCH, FIND AND DISPLAY IT FASC: LD A,TRUE LD (ASCII),A CALL ASIN ;prompt, get and check ASCII pattrn, ; and leave it in pattrn, null terminated ; FIND ; Searches for and displays with pointers all instances of ASCII or ; hexadecimal patterns in object file. Prompts for continuation, and ; continues if requested to end of file or end of disk, depending ; on current mode. In file mode, ends on display of end of file, ; top of file, or last sector accessed. In physical-sector mode, ; ends on track 0, sector 0, but then goes to 1st directory block. FIND: LD A,(AFNCNT) OR A JP Z,RQFSID FIND01: XOR A ;clear indicator of sector overlap LD (OERLAP),A LD HL,FBUFF ;buffer location LD BC,80H ;buffer (sector) size LD (LASTBC),BC LD (LASTHL),HL LD (PREVBC),BC ;storage for when we cross LD (PREVHL),HL ; sector boundaries FIND02: PUSH DE ;play safe - de value preserved CALL CONST POP DE OR A JR Z,FIND04 ;CASE key not hit call clrfnd ;else clear pattrn input line call vminv $FLD INTMSG ;display interrupted msg $stro hitkey call vmnorm call chri ;dump out keystroke FIND03: call chri ; and wait for input - gah CALL SHSEC PUSH AF ld a,8 call clrl ;clear message line - gah POP AF LD (FDMDSI),A RET FIND04: LD A,TRUE ;signal last byte LD (LSFLG),A LD HL,(LASTHL) LD BC,(LASTBC) FIND05: LD A,(AFNCNT) LD (CURCT),A LD DE,PATTRN ;get and look for 1st byte LD A,(DE) CPIR JP PE,FIND07 ;CASE not overrun JR Z,FIND09 ;CASE not found on last byte, CALL GTNXT ; get another sector, JR Z,FIND01 ; aborting if none available ; or looping if one is FIND06: call clrfnd ;else clear pattrn input line call vminv ;use inverse video - gah $FLD NOTFND ;say target not found (eof or eodisk) LD A,(WTG) CP 'F' JP Z,FIND18 ;CASE file mode $stro hitkey ;prompt for a key call vmnorm JR FIND03 FIND07: LD (LASTBC),BC ;save pointers LD (LASTHL),HL FIND08 EQU $ ;LOOP - check tail CALL DCCT ;next byte - end of search pattern? JR Z,FIND14 ;yes - go display find DEC C ;else are we at buffer end JP M,FIND10 ;yes CP (HL) ;no - continue checking pattrn JP NZ,FIND02 ;failed - restart search INC HL ;otherwise - next buffer byte JR FIND08 ;ENDLOOP FIND09: LD (LASTBC),BC ;save these for screen LD (LASTHL),HL CALL DCCT JR Z,FIND13 ;if not reached end of sector FIND10 EQU $ ;else we found a bit but reached end of sector LD (CURCH),A ;save current byte LD A,C ;use BC value as flag to show LD (LSFLG),A ; whether found pattrn at very end LD HL,(LASTHL) LD (PREVHL),HL LD BC,(LASTBC) LD (PREVBC),BC ;save pointers for progress point LD A,TRUE LD (OERLAP),A ;flagging that we have overlapped CALL GTNXT ;get/check next sector JR NZ,FIND06 ;reached eof - exit LD HL,FBUFF ;point to start of next sector LD BC,80H LD A,(CURCH) ;restore byte FIND11: CP (HL) ;LOOP JR NZ,FIND12 ;CASE we found a match CALL DCCT ;else keep checking JR Z,FIND14 INC HL JR FIND11 ;ENDLOOP FIND12 EQU $ ;tried the overlap, but no match LD A,(LSFLG) ;was it on last byte anyway? OR A JP Z,FIND01 ;if so, loop CALL GOBAK ;if not, go back a sector XOR A ;establish we're back LD (OERLAP),A LD HL,(PREVHL) ;restore the sector's pointers LD BC,(PREVBC) JP FIND05 ; and continue search on 1st sector FIND13: LD A,C ;if only byte is at end of buffer, LD (LSFLG),A ; signal with c = 0 = lsflg and show it FIND14: LD BC,(LASTBC) ;well, get a pointer anyway LD A,(LSFLG) OR A JR NZ,FIND15 ;IF last character LD HL,FBUFF ;ELSE reinitialize pointers for new buffer LD (LASTHL),HL LD BC,80H LD (LASTBC),BC FIND15 EQU $ ;ENDIF LD A,(OERLAP) ;was find in overlap? OR A JR Z,FIND16 ;IF no overlap LD BC,(PREVBC) ;ELSE replace pointer with earlier one CALL GOBAK ; and go back to start of find, XOR A ; remembering to flag that it's done LD (OERLAP),A FIND16 EQU $ ;ENDIF PUSH BC ;are registers saved? - save bc anyway CALL SHSEC ;show things POP BC ;get back byte pointer LD HL,80H ;calculate equivalent OR A ; of bufpos for display SBC HL,BC LD A,L OR A JR NZ,FIND17 ;IF not zero, it's not last byte LD A,80H ; so set up to character in front FIND17: DEC A ;ENDIF LD (BUFPOS),A ;use that CALL SLCP ; to update cursor and LD HL,(LPOS) ; then fiddle DEC H ; to go back a bit more DEC H ; to allow room for visual pointer LD (LPOS),HL CALL UDCP ;point to that position call vmblnk ;use blinking video - gah $strl fndmk ;point to the find call vmunbl ;blinking off call vminv $FLD FNDCON ;ask if we want next call vmnorm CALL CHRF ;get answer to next query CP 'Y' PUSH AF ;save response $cfld fndcon ;erase prompt - gah CALL SLCP ;reposition on display LD HL,(LPOS) DEC H ;back again DEC H LD (LPOS),HL CALL UDCP ;for cursor update and CALL SPCO ; clear fndmk CALL SPCO POP AF ;now check query answer JR NZ,FIND19 ;if next wanted, do it LD A,(LSFLG) ; but check first OR A ; if on last byte in buffer JP NZ,FIND02 ;if not, then loop CALL GTNXT ;last byte? get new sector JP Z,FIND02 ;if it's there, loop JP FIND06 FIND18: $STRO HITT ;offer option to go to top of file call vmnorm CALL CHRF ;wait for input CP 'T' JR NZ,FIND19 ;IF top of file requested CALL FRFS ;ELSE go to first file sector FIND19: JP RQFSID ;ENDIF CLRFND: $CFLD FNDCON ;clear msg field LD A,8 JP CLRL ; GTNXT - GET NEXT SECTOR IN 'FIND' SEQUENCE ; Has to return Z set if new sector IS available, reset if NOT. This ; allows for use of 'FIND' in both file and physical-sector modes. ; In physical-sector mode, disk overrun results in positioning over ; disk directory. ; ; --- ADDED REGISTER PRESERVATION AND MADE DATA UPDATE LESS FREQUENT ; (uses new variable 'fndtr' set up in 'typp' data area) ; 15-17 Sept 86 pgm GTNXT: PUSH DE ;save LD A,(WTG) CP 'F' JR Z,GTNX03 ;CASE file mode LD HL,(PSMDTR) ;else LD (FNDTR),HL ; save current track value CALL NXPS ; and try for next physical sector LD HL,(PSMDTR) ;now, check if disk overflow reached LD DE,(PSMDSC) ADD HL,DE LD A,L ;test hl value for disk overflow OR H JR Z,GTNX04 ;CASE we've reached end of disk XOR A GTNX01: PUSH AF CALL PSRD ;read in selected sector LD HL,(PSMDTR) LD DE,(FNDTR) OR A SBC HL,DE JR Z,GTNX02 ;IF new track CALL UBLK ;ELSE show our position CALL DPSI GTNX02: POP AF ;ENDIF POP DE RET GTNX03: CALL NXFS ;read next file sector PUSH AF ;save status LD A,(RELREC) ;in file mode, if on 8-sector boundary AND 07H ; update display of data CALL Z,DFSI JR GTNX02 ;exit GTNX04: OR 0FFH ;return sector found - non-zero LD HL,(DPBOFF) ; and set up to display directory LD (PSMDTR),HL JR GTNX01 ;loop ; GOBAK - RETURN TO EARLIER SECTOR IN 'FIND' ROUTINE ; More register-saving added - 15 Sept 86 pgm GOBAK: PUSH BC PUSH DE LD A,(WTG) CP 'F' ;check if in file mode PUSH AF CALL Z,PRFS ;if so, then read previous file sector POP AF JR Z,GOBAK1 ; and exit CALL PRPS ;else read previous physical sector CALL PSRD GOBAK1: POP DE POP BC RET ; SHSEC - DISPLAY BUFFER DATA IN 'FIND' UNDER F AND P OPTIONS ; BC is preserved elsewhere - preserve DE just in case SHSEC: PUSH DE LD A,(WTG) CP 'F' ;check if in file mode PUSH AF CALL Z,DFSI ;if so, display file-sector info POP AF JR Z,SHSEC1 ; and then display file data CALL UBLK ;else update block pointer CALL DPSI ; and display physical-sector info SHSEC1: LD HL,FBUFF CALL WRBF ;display data in sector buffer POP DE RET ; DDCT - GET NEXT PATTERN BYTE AND CHECK BYTE COUNT DCCT: INC DE LD A,(DE) ;get next byte PUSH HL ; and decr count LD HL,CURCT DEC (HL) ;did we get to end? POP HL RET ; ASIN - GET ASCII STRING INPUT FOR SEARCH ; Added check to prevent backspacing past 1st input character ; - 14 July 90 gah ASIN: CALL SSTR ;initialize ASIN01 EQU $ ;LOOP CALL AFNC ;position cursor CALL CHRI ;get a character (unfolded) CP CR RET Z ;CASE cr - we're done, so exit CP $ESC JR Z,ASIN03 ;CASE escape - cancel search $MTCH ASINCD JR Z,ASIN04 ;CASE screen character ctrl key CP $TAB JR Z,ASIN02 ;CASE tab (insert without tabbing!) CP ' ' CALL C,ALRM ;CASE other ctrl key - ring bell JR C,ASIN01 ; and loop ASIN02: CALL PASTR ;output progress LD HL,AFNCNT LD A,(AFNMAX) INC (HL) CP (HL) RET Z ;exit if max character input reached JR ASIN01 ;ENDLOOP ASIN03: XOR A LD (AFNCNT),A ;cancel search RET ASIN04: $EXVA ASINVC ;do action required JR ASIN01 ; and loop ASINCD: DB 3,$LEFT,$RIGHT,$DELETE ASINVC EQU $ DW APNL ;cursor left in field DW APNR ;cursor right in field DW AFND ;delete character in afn ; PASTR - STORE BYTES OF PATTERN FOR SEARCH PASTR: PUSH AF LD HL,(AFNCHP) LD A,(AFNCNT) CALL AAHL POP AF LD (HL),A PUSH AF LD A,(ASCII) OR A JR Z,PASTR1 POP AF JP CHRO PASTR1: POP AF JP HEXO ; HXIN - GET HEX-SEQUENCE INPUT FOR SEARCH HXIN: CALL SSTR ;initialize HXIN01 EQU $ ;LOOP XOR A ;clear temporary byte hold LD (CUHX),A CALL HXSC ;position on screen $STRL CLLSTR ;clear line beyond that CALL HXSC ;reposition CALL CHRF ;get a nibble in $MTCH HEXCHR JR Z,HXIN02 ;CASE hex characters on 1st nibble LD A,(INCH) ;else switch case CP CR RET Z ;CASE cr - we're done, so exit CP $ESC JR Z,HXIN04 ;CASE escape - cancel search CP $LEFT JR Z,HXIN05 ;CASE backspace (for correction) CALL ALRM ;default - ring bell JR HXIN01 ;ENDLOOP HXIN02: LD A,(CUHX) CALL HXAD LD (CUHX),A CALL PASTR ;now save byte and display, LD HL,AFNCNT ; incrementing byte count INC (HL) HXIN03: CALL CHRF ;LOOP $MTCH HEXCHR JR Z,HXIN06 LD A,(INCH) ;non-hex input 2nd nibble CP CR JR Z,HXIN07 ;CASE cr - start search CP $ESC JR Z,HXIN04 ;CASE escape - cancel find CP $LEFT JR Z,HXIN08 ;CASE backspace (for correction) CALL ALRM ;wrong input - ring bell and loop JR HXIN03 ;ENDLOOP HXIN04: XOR A ;cancel find LD (AFNCNT),A RET ;just exit HXIN05: LD A,(AFNCNT) ;if still the 1st byte of input, OR A ; just restart JR Z,HXIN01 DEC A ;if not 1st byte, decrement count LD (AFNCNT),A ; and restart JR HXIN01 HXIN06: LD A,(CUHX) CALL HXAD LD (CUHX),A LD HL,AFNCNT ;going back in byte count DEC (HL) CALL HXSC ;to ensure save and screen right CALL PASTR LD HL,AFNCNT ;if after two nibbles in LD A,(AFNMAX) ; we're at maximum byte count... INC (HL) CP (HL) RET Z ; then exit JR HXIN09 ;else loop for another byte HXIN07: LD HL,AFNCNT ;decrement count DEC (HL) ; before exit, but... RET NZ ;if it's single 1st nibble INC (HL) ; don't signal no input RET HXIN08: XOR A LD HL,CUHX ;rotate byte back RRD LD A,(HL) OR A ;if still known relevant data JR NZ,HXIN03 ; then loop for 2nd nibble LD HL,AFNCNT ;else reposition DEC (HL) HXIN09: JP HXIN01 ; and loop for whole new byte ; HXSC - POSITION CURSOR FOR HEX SCREEN INPUT, EACH BYTE SEPARATED WITH SPACES HXSC: PUSH AF PUSH BC LD HL,(AFNCUR) LD A,(AFNCNT) LD B,A ADD A,A ADD A,B ADD A,H LD H,A CALL CURS POP BC POP AF RET ; HXAD - A = A * 16 HXAD: EX DE,HL ;move value into de LD L,A ; and current byte into L LD H,0 CALL H16D ; rotating and adding LD A,L ; and getting result in accumulator RET ; SSTR - INITIALIZE PATTERN FOR SEARCH AND PROMPTING SSTR: XOR A ;initialize variables LD (AFNCNT),A ; and prompt for find input ; LD (PATTRN),A ;useless! - gah LD A,8 CALL CLRL $FLD FNDPMT LD HL,(STRPOS) LD (AFNCUR),HL LD HL,PATTRN LD (AFNCHP),HL LD A,20 ;set maximum length of input LD (AFNMAX),A RET ; End of v3.4 stuff ; Re-revised - 15 Sept 1986 pgm ; DRMD - DIRECTORY MODE ; Added display of current user number - gah DRMD: LD HL,(DRMDEF) LD (ERRFLD),HL ;set panel error field LD A,TRUE LD (DRMDLD),A ;request list DRMD01: LD A,(DRMDLD) ;LOOP OR A JR Z,DRMD03 ;IF list not required $NPANEL DRMDPN ;ELSE display directory-list panel ld hl,(drmusr) call curs ld e,0ffh ld c,userno call cpm ;get current user number ld c,a ; in c sub 10 ;more than 9? jr c,drmd02 ;nope ld c,a ld a,'1' ;yup, so prefix with '1' call chro drmd02: ld a,c call hexc ld a,')' call chro CALL DLST ;do directory list XOR A LD (DRMDLD),A ;reset list request DRMD03 EQU $ ;ENDIF CALL ERRP ;process errors LD A,(SELDE) CALL DIRPOS ;position over current entry CALL CHRF $MTCH DRMDLS ;get command CALL NZ,ALRM ;if invalid, sound alarm JR NZ,DRMD03 ; and loop $EXVA DRMDVC ;else perform action LD A,(WTG) CP 'D' RET NZ ;exit if no longer in directory mode JR DRMD01 ;ENDLOOP ; DIRECTORY-MODE PANEL AND ACTION VECTORS ; Updated to include user-number selection - Jan 86 jhb ; Now displays current user number - gah DRMDPN: DB 15 DB 02,04,'Cursor left',0 DB 02,25,'Next directory page',0 DB 02,57,'Change Drive',0 DB 03,04,'Cursor right',0 DB 03,25,'Previous directory page',0 DB 03,57,'Select track/Sector',0 DB 04,04,'Cursor up',0 DB 04,25,'Set directory Mask',0 DB 04,57,'Edit file',0 DB 05,04,'Cursor down',0 DB 05,25,'Change User number',0 DB 05,57,'Type file',0 DB 06,04,'Next file',0 DB 06,25,'(current:',0 DB 06,57,'Exit from SuperZap',0 DB 14 DB 02,00,'^',$LEFT+40H,0 DB 02,22,'N',0 DB 02,54,'D',0 DB 03,00,'^',$RIGHT+40H,0 DB 03,22,'P',0 DB 03,54,'S',0 DB 04,00,'^',$UP+40H,0 DB 04,22,'M',0 DB 04,54,'E',0 DB 05,00,'^',$DOWN+40H,0 DB 05,22,'U',0 DB 05,54,'T',0 DB 06,00,'TAB',0 DB 06,54,'Z',0 DRMDLS: DB 15,$LEFT,$RIGHT,$UP,$DOWN,CR,'EZDSMPNTU',$TAB DRMDVC EQU $ DW FBS ;backspace in directory DW FFS ;cursor forward in directory DW FUP ;cursor up in directory DW FDN ;cursor down in directory DW FNL ;carriage return in directory DW STFL ;select file DW SETX ;set exit mode DW CHDD ;change directory drive DW SETP ;set physical sector mode DW SAFN ;set directory mask DW DIRP ;page up in directory DW DIRN ;page down in directory DW TYPE ;type selected file DW CHUN ;change user number DW FFS ;next directory file DRMUSR: DB 06,36 ;location of current-user display DRMDEF: DB 10,00 NRFMSG: DB '** No records in file **',0 FNFMSG: DB '** File not found **',0 DRMDLD: DS 1 ;list directory request flag ; DIRP - PAGE UP IN DIRECTORY DIRP: LD A,(DIROFF) OR A JP Z,ALRM ;if not page 0, go sound alarm SUB 32 JR DIRPN ; DIRN - PAGE DOWN IN DIRECTORY DIRN: LD A,(DIROFF) ADD A,32 ;point to next page LD HL,DECNT CP (HL) JP NC,ALRM ;if not available, go sound alarm DIRPN: LD (DIROFF),A ;save new pointer XOR A LD (SELDE),A ;set first entry on page CALL ERRP LD HL,DRAREA CALL CLRA ;clear directory area JP DLST ;go display page ; FFS - CURSOR FORWARD IN DIRECTORY FFS: CALL GTDOFF FFS01: LD A,(SELDE) ;LOOP INC A AND 1FH LD (SELDE),A ;next entry RET Z ADD A,B CP (HL) RET C ;until new <= max JR FFS01 ;ENDLOOP ; FBS - BACKSPACE IN DIRECTORY FBS: CALL GTDOFF FBS01: LD A,(SELDE) ;LOOP DEC A AND 1FH LD (SELDE),A ;select previous RET Z ;exit if first position ADD A,B CP (HL) RET C ;until new <= max JR FBS01 ;ENDLOOP ; FUP - CURSOR UP IN DIRECTORY FUP: CALL GTDOFF FUP01: LD A,(SELDE) ;LOOP SUB 4 AND 1FH LD (SELDE),A ;1 line up RET Z ;exit if first position ADD A,B CP (HL) RET C ;until new <= max JR FUP01 ;ENDLOOP ; FDN - CURSOR DOWN IN DIRECTORY FDN: CALL GTDOFF FDN01: LD A,(SELDE) ;LOOP ADD A,4 AND 1FH LD (SELDE),A ;1 line down RET Z ADD A,B CP (HL) RET C ;until new <= max JR FDN01 ;ENDLOOP ; FNL - CARRIAGE RETURN IN DIRECTORY FNL: CALL GTDOFF FNL01 EQU $ ;LOOP LD A,(SELDE) ;pick up current ADD A,4 ;move to next line AND 1CH LD (SELDE),A ;start of next line RET Z ADD A,B LD HL,DECNT CP (HL) RET C ;until new <= max JR FNL01 ;ENDLOOP ; GTDOFF - GET DIRECTORY DISPLAY OFFSET ; New common routine to compact code - Aug 90 gah GTDOFF: LD HL,DECNT LD A,(DIROFF) LD B,A ;get start of display RET ; DIRPOS - POSITION TO PRINT DIRECTORY ENTRY DIRPOS: LD (DIRNUM),A ;save entry position LD HL,DRTAB ;table of directory-display lines RRCA RRCA ;divide count by 4 AND 0FH ;make it line count CALL AAHL LD B,(HL) ;pick up line position LD HL,DCTAB LD A,(DIRNUM) ;pick up entry again AND 03H ;make count into column number CALL AAHL LD H,(HL) ;get column position LD L,B ; and line number JP CURS ;go position cursor DIRNUM: DS 1 ;directory-entry number ; STFL - SELECT FILE STFL: CALL CFCB ;copy fcb from dir list ret z ;exit if no files - gah JP SETF ;go set file mode ; CFCB - COPY FCB FROM DIRECTORY LIST CFCB: LD A,(DECNT) OR A JR Z,CFCB01 ;CASE no files LD A,(SELDE) ;else get selected entry number LD B,A LD A,(DIROFF) ADD A,B ;add display start LD L,A LD H,0 LD DE,(MEMRY) ;base of table CALL H16D ;hl = hl * 16 + de LD DE,WRKFN ;start of file name LD BC,11 LDIR ;move de over to fcb XOR A LD (WRKEX),A dec a ;clear z flag RET CFCB01: CALL ALRM ;sound alarm (preserves flags) LD HL,FNFMSG LD (ERRTXT),HL ;set file not found error RET ; TYPE - TYPE SELECTED FILE ; Revised - 2 Sept 86 pgm TYPE: CALL CFCB ;set up fcb ret z ;exit if no files - gah CALL TFLE ;test file LD A,(FLERR) OR A JR NZ,TYPE03 ;exit if file not found $NPANEL TYPEPN ;else display panel (clears the screen) $FLD TYPEFN $STRO DRIVNM ;new filename display XOR A LD (BUFPOS),A ;buffer offset 0 LD (LINESC+1),A ;reset line count LD (BASEAD+1),A LD (TQUED),A ;flag file data not queued INC A LD (LINESC),A ;line number 1 LD (BASEAD),A ;initialize page 1 CALL TGET ;prime first character LD HL,(PGEPTR) ;get starting addr of page-queue pointers LD (CURPG@),HL ;set current page entry to first LD (MAXPG@),HL ; and last LD A,TRUE LD (TYPEX),A ;set no exit LD (TYDSP),A ;request display TYPE01: LD A,(TYDSP) ;LOOP OR A JR Z,TYPE02 ;IF no display required XOR A ;ELSE LD (TYDSP),A ; reset request LD (TUNPUT),A ;flag for no screen output call vmcrof ;turn off cursor call csnd ;clear file-display area call dpagpn CALL TYPG ;display page call drngpn call vmcron ;turn on cursor TYPE02 EQU $ ;ENDIF $IFLD TYPIP ;get command $MTCH TYPLST CALL NZ,ALRM ;if invalid, sound alarm JR NZ,TYPE02 ;loop for a command $EXVA TYPVEC ;execute command LD A,(TYPEX) OR A JR NZ,TYPE01 ;ENDLOOP TYPE03: LD A,TRUE ;exit if flag set LD (DRMDLD),A ;request directory list RET ; DPAGPN, DRNGPN - PANEL DISPLAYS ; Now separate routines to eliminate repetitious code - gah DPAGPN: $FLD PGENUM $HEXW BASEAD ;display page number $FLD RECNUM $HEXW RELREC ;display record number $FLD LINNUM ;new line-number display LD HL,(LINESC) JP HEXW DRNGPN: $FLD RECNM2 ;display ranges $HEXW RELREC $FLD LINNM2 LD HL,(LASTLN) JP HEXW TYPEPN: DB 10 ;new display and options - 15 Sept 86 pgm DB 01,03,'Next page',0 DB 01,29,'Forward paging',0 DB 01,56,'Select Sector',0 DB 02,03,'Previous page',0 DB 02,29,'Backward paging',0 DB 02,56,'Return to file List',0 DB 03,03,'Go to page No.',0 ; DB 03,27,'Return after paging',0 ;removed - gah DB 03,29,'Top of file',0 DB 03,56,'Exit from SuperZap',0 DB 04,26,'Select option ==>',0 DB 9 DB 01,00,'N',0 DB 01,26,'F',0 DB 01,53,'S',0 DB 02,00,'P',0 DB 02,26,'B',0 DB 02,53,'L',0 DB 03,00,'G',0 ; DB 03,24,'R',0 ;out - gah DB 03,26,'T',0 DB 03,53,'Z',0 PGENUM: DB 06,00,'Page ',0 RECNUM: DB 06,26,'Sectors ',0 RECNM2: DB 06,38,'-',0 LINNUM: DB 06,59,'Lines ',0 LINNM2: DB 06,69,'-',0 TYPEFN: DB 05,00,'File: ',0 TYPIP: DB 04,43,0 ;new input position TYPFL: DB 08,00,0 ;first character position TCSEND: DB 06,38,' ',0 ;TCLEND:DB 06,70,' ',0 ;not used - gah HITMSG: DB 07,00,'HIT ANY KEY to halt paging',0 DECS: DB 10,'0123456789' ;new data for decimal input TYPLST: DB 9,'NLPTZFBGS' TYPVEC EQU $ DW TYPF ;next page ; DW TYPR ;return after paging (removed - gah) DW TYPL ;return to directory list DW TYPB ;previous page DW TYPT ;go to top of file DW TYPZ ;exit SuperZap DW FTYP ;forward paging DW BTYP ;backward paging DW TYPP ;display selected page DW TYPS ;display selected sector in page TYPEX: DS 1 ;exit flag TYDSP: DS 1 ;display request TYPEOP: DS 1 ;end of page ;MAXREC:DS 2 ;last sector read (not used - gah) SAVBA: DS 2 ;temporary storage, basead LASTLN: DS 2 ;line count TARGET: DS 2 ;store for page number sought FNDTR: DS 2 ;store for last track in gtnxt TQUED: DS 1 ;flag for page queue ; TYPF - TYPE NEXT PAGE ; Now returns READST as found - i.e., z flag clear if eof, set otherwise TYPF: LD A,(READST) OR A JP NZ,ALRM ;if eof, go sound alarm (preserves af) TYPFF: CALL UPDPTR ;else update page-queue pointer LD A,TRUE LD (TYDSP),A ;request display INC A ;ensure zero returned RET ; UPDPTR - UPDATE PAGE POINTER ; Made a separate routine to fix page-queue bug in 'FTYP' - gah UPDPTR: LD HL,(CURPG@) LD DE,8 ADD HL,DE LD (CURPG@),HL ;update current pointer RET ; TYPB - TYPE PREVIOUS PAGE ; Returns z flag clear if at top of file, set otherwise ; Added bell if already at top of file - gah TYPB: call chktop jp z,alrm ;if top of file, sound alarm and exit TYPBB: EX DE,HL LD DE,8 OR A SBC HL,DE CALL LPGE ;load page data LD A,TRUE LD (TYDSP),A ;request display RET ; CHKTOP - CHECK FOR TOP OF FILE IN TYPE ; Made a separate routine for use with BTYP - gah CHKTOP: LD HL,(PGEPTR) LD DE,(CURPG@) OR A SBC HL,DE RET ; TYPR - RETURN AFTER PAGING ; Now returns status found - i.e., non-z if eof, z otherwise ; Made an internal routine only - gah TYPR: LD HL,(CURPG@) LD DE,(MAXPG@) XOR A SBC HL,DE JR Z,TYPR01 ;IF not end of file EX DE,HL ;ELSE restore top of queue LD DE,8 OR A SBC HL,DE CALL LPGE ;load last page LD A,TRUE LD (TYDSP),A ;request display TYPR01 EQU $ ;ENDIF INC A ;return status (0 or 1) RET ; TYPT - GO TO TOP OF FILE TYPT: call chktop jp z,alrm ;sound alarm, exit if already at top TYPTT: LD HL,(PGEPTR) ;else CALL LPGE ; load first page LD A,TRUE LD (TYDSP),A ;request display RET ; TYPZ - EXIT TYPE TO CP/M TYPZ: CALL SETX ;set exit mode and fall thru to request exit ; TYPL - EXIT TYPE TO DIRECTORY LIST TYPL: XOR A LD (TYPEX),A ;request exit RET ; TYPG - TYPE A PAGE TYPG: LD HL,(MAXPG@) ;get max page number LD DE,(CURPG@) ; and current OR A SBC HL,DE JR NZ,TYPG01 ;exit if end of queue LD HL,TYCURC LD DE,(MAXPG@) LD BC,8 LDIR ;copy page data LD (MAXPG@),DE ;update max pointer TYPG01: $FLD TYPFL ;position for first character (margin omitted) XOR A LD (TYPEOP),A ;reset end of page LD (PGECOL),A ;column 0 LD (PGELNE),A ;line 0 TYPG02: LD A,(TYPEOP) ;LOOP OR A JR NZ,TYPG04 ;CASE eop LD A,(COMFLG) OR A LD A,(TYCURC) JR Z,TYPG05 ;CASE not .COM file CALL TPUT ;else output character immediately LD A,(READST) OR A JR NZ,TYPG04 ;CASE eof LD A,(TYPEOP) TYPG03: OR A JR NZ,TYPG04 ;CASE eop CALL TGET ;get next character JR TYPG02 ;ENDLOOP TYPG04: LD HL,(BASEAD) CALL BCDU ;do bcd incrementing LD (BASEAD),HL ;increment page number RET TYPG05: CP $TAB JR Z,TYPG08 ;CASE tab CP CR JR Z,TYPG09 ;CASE cr LD HL,SOFT1 ;process "softs" CP (HL) JR Z,TYPG10 INC HL ;soft2 CP (HL) JR Z,TYPG10 INC HL ;now, process "hards" CP (HL) JR Z,TYPG09 INC HL ;hard2 CP (HL) JR Z,TYPG09 TYPG06: CALL TPUT TYPG07: LD A,(READST) JR TYPG03 TYPG08 EQU $ ;LOOP LD A,' ' ;space-fill to tab stops CALL TPUT ;put space LD A,(PGECOL) AND 07H JR Z,TYPG07 ;exit if tab stop reached JR TYPG08 ;ENDLOOP TYPG09: LD A,(READST) ;check for trailing lf OR A JR Z,TYPG11 ;check for eof LD A,CR ;else output cr JR TYPG06 TYPG10: CALL TYNL ;print newline for softs JR TYPG07 TYPG11: LD A,(BUFPOS) LD HL,FBUFF CALL AAHL LD A,(HL) CP LF PUSH AF ;save result CALL TYNL ; but do newline anyway POP AF CALL Z,TGET ; and swallow character if lf there JR TYPG07 PGECOL: DS 1 ;column number PGELNE: DS 1 ;line number TUNPUT: DB 0 ;flag for dummy paging ops (no left margin) ; TGET - GET CHARACTER FOR TYPE TGET: LD A,(READST) OR A JR NZ,TGET01 ;IF eof LD HL,BUFPOS ;ELSE LD A,(HL) ; get current offset INC (HL) ;bump pointer for next get LD HL,FBUFF CALL AAHL ;point to current character LD A,(HL) LD (TYCURC),A ;get character LD A,(BUFPOS) CP 80H JR NZ,TGET01 ;IF bufpos <> 80H LD HL,(RELREC) ;ELSE INC HL LD (RELREC),HL ; set next sector XOR A LD (BUFPOS),A ;buffer offset = 0 CALL RDFS ;read sector TGET01 EQU $ ;ENDIF / ENDIF LD A,(TYCURC) ;return character RET ; TPUT - TYPE A CHARACTER TPUT: LD B,A ;save character LD A,(PGECOL) CP 79 ;changed for 80 cols - no left margin CALL Z,TYNL ;if col = 79, type new line LD A,(TYPEOP) OR A RET NZ ;exit if not eop LD A,(TUNPUT) ;IF unput flagged OR A ;skip screen output JR NZ,TPUT01 ; and just count lines LD A,B ;ELSE CALL ASCO ; output character TPUT01: LD HL,PGECOL ;ENDIF INC (HL) ;increment column count RET ; TYNL - TYPE NEW LINE TYNL: XOR A LD (PGECOL),A ;set col 0 LD HL,(LINESC) ;get file line count LD (LASTLN),HL CALL BCDU ;incremented LD (LINESC),HL LD HL,PGELNE INC (HL) ;now page line count up LD A,16 CP (HL) JR Z,TYNL01 ;CASE page line = 16 LD A,(TUNPUT) ;else check if just counting lines OR A RET NZ ;exit if so LD A,CR CALL CHRO LD A,LF JP CHRO ;output cr/lf TYNL01: LD A,TRUE LD (TYPEOP),A ;set eop RET ; FTYP - PAGE FORWARD THRU FILE TILL KEY HIT OR END OF FILE ; Revised, new options and supporting subroutines added - 3 Sept 86 pgm ; Fixed failure to update page-queue pointer - 14 Aug 1990 gah FTYP: ld a,(readst) or a ;check for eof on last read jp nz,alrm ;if so, sound alarm and exit call updptr ;else update page-queue pointer - gah call vmcrof ;turn off cursor CALL PAGIN FTYP01 EQU $ ;LOOP call chkchr ;check for key input call dpagpn ;display panel CALL TYPG ld a,(readst) or a JR NZ,FTYP02 ;CASE not eof CALL TYPFF ;else page forward call drngpn JR FTYP01 ;ENDLOOP FTYP02: CALL TYPR ;return after paging LD A,TRUE LD (TQUED),A ;fall thru to next ; PGEND - NEW SUBROUTINE FOR FTYP AND BTYP PGEND: XOR A LD (TUNPUT),A ;clear unput flag DEC A LD (TYPEX),A LD (TYDSP),A ld a,7 call clrl ;clear msg line jp vmcron ;go turn on cursor ; BTYP - PAGE BACKWARD THROUGH FILE UNTIL KEY HIT OR TOP OF FILE BTYP: call chktop jp z,alrm ;sound alarm, exit if already at top call vmcrof ;else turn off cursor CALL PAGIN BTYP01 EQU $ ;LOOP call chkchr ;check for key input CALL TYPG $FLD RECNM2 $HEXW RELREC $FLD LINNM2 $HEXW LINESC call chktop JR Z,BTYP02 ;CASE we're at top call typbb ;else page backward call dpagpn ; and display panel JR BTYP01 ;ENDLOOP BTYP02: CALL TYPTT ;playing safe against overrun JR PGEND ; CHKCHR - NEW SUBROUTINE FOR FTYP AND BTYP ; Kills the alarm when paging is interrupted by a keystroke - gah CHKCHR: call const or a ret z ;exit if no key input call chri ;dump out key pop af ;balance stack jr pgend ; PAGIN - NEW SUBROUTINE FOR FTYP AND BTYP PAGIN: LD A,TRUE LD (TUNPUT),A ;set unput flag CALL CSND ;clear type area CALL VMINV ;use inverse video $FLD HITMSG JP VMNORM ; CSND - CLEAR TYPE AREA TO END CSND: PUSH BC PUSH DE LD B,16 ;clearing 16 lines LD A,(TYPFL) ;get starting point DEC A CSND01: INC A ;clear file-display area CALL CLRL DJNZ CSND01 POP DE POP BC RET ; BCDU - INCREMENT PACKED BCD DATA IN HL BY 1 BCDU: LD A,1 BCDU01: ADD A,L ;entry point for increment > 1 in accumulator DAA LD L,A LD A,0 ADC A,H DAA LD H,A RET ; TYPP - SELECT AND DISPLAY SCREEN PAGE ; Now calls routine separately to get decimal page input, ; based on BASEAD variable. TYPP: CALL GTPG ;get the page LD HL,(BASEAD) LD A,L OR H JR NZ,TYPP01 ;IF zero page INC A ;ELSE make it page 1 LD (BASEAD),A TYPP01: LD HL,(BASEAD) ;ENDIF LD (TARGET),HL LD A,(TQUED) OR A CALL Z,TYPQ ;if all data queued LD DE,6 ;offset to page data in structure CALL TLOC JR TEXIT ; GTPG - SELECT SCREEN PAGE TO DISPLAY GTPG: LD HL,(RELREC) ;get current record number LD (SAVFSC),HL ; and save it LD HL,(BASEAD) ;get current page number LD (SAVBA),HL ; and save it LD HL,0 LD (BASEAD),HL ;zero out page number GTPG01 EQU $ ;LOOP $FLD PGENUM ;display field $HEXW BASEAD ;display page number CALL CHRF ;get a keystroke $MTCH DECS ;check for decimal digit JR Z,GTPG02 ;CASE valid decimal input - process input CP $LEFT JR Z,GTPG03 ;CASE backspace (for correction) CP $ESC JR Z,GTPG04 ;CASE escape - restore variables and exit CP CR JR Z,TEXIT ;CASE cr - got input, so exit CALL ALRM ;default - ring bell and loop JR GTPG01 ;ENDLOOP GTPG02: LD A,L LD HL,(BASEAD) ADD HL,HL ;move it in ADD HL,HL ADD HL,HL ADD HL,HL CALL BCDU01 ;bcd-add hl and a LD (BASEAD),HL JR GTPG01 ; and loop until cr GTPG03: LD HL,BASEAD+1 ;run back to earlier value XOR A RRD DEC HL RRD JR GTPG01 ; and loop GTPG04: LD HL,(SAVFSC) ;simply restore variables LD (RELREC),HL ; to old values and exit LD HL,(SAVBA) dec hl ;correction for typp/tloc - gah LD (BASEAD),HL TEXIT: LD A,TRUE ;common exit point when done LD (TYDSP),A RET ; TYPS - GET REQUEST FOR SECTOR TO TYPE AND FIND IT FOR DISPLAY ; Calls new routine GTHEX TYPS: LD HL,(RELREC) ;get current sector number LD (SAVFSC),HL ; and save it LD (OLDHEX),HL ; in work area, too LD HL,0 ;set to start LD (HEXFIG),HL $FLD TCSEND ;clear end of range bit LD HL,RECNUM ;save screen address LD (HXHED),HL ; in storage area for gthex XOR A ;clear hxdis flag to zero LD (HXDIS),A CALL GTHEX LD HL,(HEXFIG) ;get sector target ld a,l or h jr z,typs01 dec hl ;correction for tloc - gah TYPS01: LD (TARGET),HL ; and save it for later EX DE,HL LD HL,(SAVFSC) ;play safe by restoring posn LD (RELREC),HL LD A,(TQUED) OR A CALL Z,TYPQ ;ensure file queued LD DE,1 ;give de offset for sector data CALL TLOC ;find position to display ;(returns non-zero on bad read) JR TEXIT ; GTHEX - GET INPUT OF HEX SECTOR FOR TYPING GTHEX EQU $ ;LOOP LD A,(HXDIS) ;first check what (if any) OR A ; top-of-loop display requirements are JR Z,GTHX02 ;0 means called from typs - none needed CP 1 ;1 means called from sfsn JR Z,GTHX03 CP 2 ;2 means called from spbl JR Z,GTHX01 CALL UBLK ;3 means called from sptn or spsn GTHX01: CALL DPSI GTHX02: LD HL,(HXHED) ;get address of header field CALL DFLD ;display it $HEXW HEXFIG ;show figures CALL CHRF ;get folded input $MTCH HEXCHR JR Z,GTHX04 ;CASE valid hex input - process it CP $ESC JR Z,GTHX05 ;CASE escape - restore variables and exit CP $LEFT JR Z,GTHX06 ;CASE backspace (for correction) CP CR RET Z ;CASE cr - got input, so exit CALL ALRM ;default - ring bell JR GTHEX ;ENDLOOP GTHX03: CALL DFSI ;display file-sector info JR GTHX02 ; and loop GTHX04: EX DE,HL LD HL,(HEXFIG) CALL H16D LD (HEXFIG),HL ;move it in JR GTHEX ; and loop GTHX05: LD HL,(OLDHEX) ;restore variables LD (HEXFIG),HL RET GTHX06: LD HL,HEXFIG+1 ;undo last input XOR A RRD DEC HL RRD JR GTHEX ; and loop for more HXHED: DS 2 ;store display field to position for hex input HEXFIG: DS 2 ;main hex variable worked on OLDHEX: DS 2 ;original form of hex variable HXDIS: DB 0 ;multivalue flag indicating display required ; TLOC - FIND PLACE IN QUEUE FOR MATCH TLOC: PUSH DE ;preserve offset to tycurc position LD HL,(PGEPTR) ADD HL,DE ;point to field we want LD BC,8 ;size of the queue structure TLOC01: LD DE,(TARGET) ;get in what we're looking for PUSH HL ;record where we're at CALL LDHL ;get the current field OR A SBC HL,DE ;check against 'target' JR NC,TLOC02 ;CASE not found yet POP HL ;else get back where we're at POP DE ; and offset to tycurc, PUSH DE ; saving it again ADD HL,BC ;move to next queue item PUSH HL ;save its address OR A ;(clear carry flag) SBC HL,DE LD DE,6 ;now, check its basead value ADD HL,DE ;(we're really hacking here... CALL LDHL ; binary search WOULD be better) LD A,L ;anyway...because this is an until OR H ; zero basead means endofq POP HL ;fall thru JR NZ,TLOC01 ; or loop if more POP DE ;search failed PUSH AF ;preserve z flag set CALL TYPR ;set up end-of-file parameters CALL ALRM ;say it didn't really work POP AF ; but signal z set - ok RET TLOC02: POP HL JR Z,TLOC03 ;IF not past it SBC HL,BC ;ELSE go back one (carry is already clear) TLOC03: POP DE ;ENDIF SBC HL,DE ;restore offset to top of entry ; and fall thru to load page data ; LPGE - LOAD PAGE DATA FROM QUEUE AT (HL) LPGE: LD (CURPG@),HL ;set current pointer LD DE,TYCURC LD BC,8 LDIR ;copy page data JP RDFS ;go read first sector of page ;(signals nz on bad read, z if found) ; TYPQ - COMPILE QUEUE OF DATA FOR WHOLE FILE TYPQ: call vmcrof ;turn off cursor CALL CSND ;clear display area LD A,TRUE LD (TUNPUT),A ;set unput flag CALL TYPR ;load last data queued TYPQ01: call dpagpn ;display progress CALL TYPG ; using dummy paging process call drngpn ;show end of ranges ld a,(readst) or a call z,typff ; getting next page JR Z,TYPQ01 ;loop until eof LD HL,(CURPG@) ;insert null terminators LD DE,8 ADD HL,DE XOR A LD B,E TYPQ02: LD (HL),A INC HL DJNZ TYPQ02 LD (TUNPUT),A ;reset dummy run flag DEC A ;set queued-already flag LD (TQUED),A jp vmcron ;go turn on cursor ; CHUN - CHANGE USER NUMBER (code mostly copied from CHDD) ; Fixed to reselect current drive instead of default - gah CHUN: $CFLD UNMSG ;clear msg field LD A,TRUE LD (DRMDLD),A $IFLD UNMSG CP $ESC RET Z SUB '0' ;make user number 0-9 JP C,ALRM ;if illegal user number, go sound alarm CP 10 ;check for 0..9 JR C,CHUN01 SUB 7 CP 16 ;check for A..F JP NC,ALRM ;go sound the alarm CHUN01: LD E,A LD C,USERNO CALL CPM ; LD C,GETDEF ;won't work! - gah ; CALL CPM ld a,(curan) ;reselect current drive - gah CALL CHDR XOR A LD (SELDE),A ;back to first directory page RET UNMSG: DB 12,17,'Enter hex user number or press ESC ==>',0 ; CHDD - CHANGE DIRECTORY DRIVE ; Now displays selected drive letter - gah CHDD: LD A,TRUE LD (DRMDLD),A ;request list on return CHDD01 EQU $ ;LOOP ld a,12 call clrl ;clear prompt line $IFLD DSKMSG ;prompt for drive CP $ESC RET Z ;CASE escape - just exit cp 'A' jr c,chdd02 ;CASE non-alpha char - sound alarm and loop push af ;else call chro ; display drive letter - gah pop af SUB 'A' ;make drive id CALL CHDR ;change disk JR Z,CHDD02 ;if illegal drive, sound alarm and loop XOR A LD (SELDE),A ;select first entry RET CHDD02: CALL ALRM ;sound the alarm JR CHDD01 ;ENDLOOP DSKMSG: DB 12,20,'Enter drive letter or press ESC ==>',0 ;NFDMSG:DB '** No files on drive **',0 ;not used - gah ; SAFN - SET DIRECTORY MASK SAFN: $NPANEL AFNPNL ;display set afn panel LD A,TRUE LD (DRMDLD),A ;request directory list LD HL,LMDFCB+1 LD DE,CPYAFN LD BC,11 LDIR ;take local copy of dir search name CALL DAFN ;display current mask XOR A LD (IMODE),A ;reset insert mode LD (NMODE),A ;set name field LD (AFNCNT),A ;set count = 0 ld (ascii),a ;reset ascii in case of search - gah LD HL,(AFNPNM) LD (AFNCUR),HL ;set start address on screen LD HL,CPYAFN LD (AFNCHP),HL ;save start address in memory LD A,8 LD (AFNMAX),A ;set length of field SAFN01 EQU $ ;LOOP CALL AFNC ;position cursor CALL CHRF ;get a character CP $ESC RET Z ;CASE escape - exit CP CR JR Z,SAFN02 ;CASE cr - reset current selection $MTCH AFNACD JR Z,SAFN03 ;CASE valid ctrl character $MTCH AFNINV JR Z,SAFN04 ;CASE in illegal-character set CP ' ' JR C,SAFN04 ;CASE not ctrl character CALL PAFN ;else put character in string JR SAFN01 ;ENDLOOP SAFN02: LD HL,CPYAFN CALL LSEL ;copy new name to fcb CALL RDIR ;read directory XOR A LD (SELDE),A ;reset current selection RET SAFN03: $EXVA AFNAVC ;perform action JR SAFN01 ; and loop SAFN04: CALL ALRM ;ring bell JR SAFN01 ; and loop AFNINV: DB 8,',.:;<>[]' ;invalid filename characters (any more?...) IMODE: DS 1 ;insert on/off NMODE: DS 1 ;name/type field flag AFNCNT: DS 1 ;current position in name AFNCUR: DS 2 ;cursor position of current field AFNCHP: DS 2 ;address of current field AFNMAX: DS 1 ;length of current part CPYAFN: DS 11 ;copy of directory mask AFNPNL: DB 10 ;field count DB 02,04,'Cursor left',0 DB 02,29,'Insert on/off',0 DB 02,58,'Toggle name/type',0 DB 03,04,'Cursor right',0 DB 03,29,'Delete character',0 DB 03,58,'Use current mask',0 DB 07,14,'File name ==>',0 DB 07,37,'<=',0 ;filename end marker DB 09,14,'File type ==>',0 DB 09,32,'<=',0 ;filetype end marker DB 6 DB 02,00,'^',$LEFT+40H,0 DB 02,25,'^',$INSRT+40H,0 DB 02,54,'TAB',0 DB 03,00,'^',$RIGHT+40H,0 DB 03,25,'DEL',0 DB 03,54,'ESC',0 AFNPNM: DB 07,28,0 ;position of name AFNPEX: DB 09,28,0 ;position of type INSMSG: DB 05,29,'Insert',0 AFNACD: DB 8,$LEFT,$RIGHT,$DELETE,$INSRT,$TAB,' .*' AFNAVC EQU $ DW AFNL ;cursor left DW AFNR ;cursor right DW AFND ;delete character DW AFNI ;toggle insert mode DW AFNT ;toggle name mode DW AFNS ;space-fill field DW AFNP ;period DW AFNQ ;'?' fill (used by '*') ; AFND - DELETE CHARACTER IN AFN ; Added extra code for use with 'ASIN' - July 90 gah AFND: LD HL,(AFNCHP) ;address of current field LD A,(AFNCNT) LD C,A ;save count CALL AAHL ;address of current character LD E,L ;destination in de LD D,H INC HL ;source in hl LD A,(AFNMAX) ;length of field SUB C ;length remaining DEC A ;length to move JR Z,AFND01 ;IF something to move LD C,A ;ELSE set up count LD B,0 LDIR ;move field left AFND01: LD A,' ' ;ENDIF LD (DE),A ;blank last character ld a,(ascii) or a ;check for ascii find jr z,dafn ;if not, then go display directory name $fld strpos ld hl,pattrn ld b,20 ;maximum size of search string afnd02: ld a,(hl) call chro inc hl djnz afnd02 ret ; DAFN - DISPLAY DIRECTORY MASK DAFN: $FLD AFNPNM ;position for name LD HL,CPYAFN LD B,8 ;length of name DAFN01: LD A,(HL) ;LOOP CALL CHRO ;print a character INC HL ;point to next DJNZ DAFN01 ;UNTIL end of field $FLD AFNPEX ;position for type LD HL,CPYAFN+8 LD B,3 ;length of type DAFN02: LD A,(HL) ;LOOP CALL CHRO ;print character INC HL ;point to next DJNZ DAFN02 ;UNTIL end of field RET ; AFNP - PERIOD IN AFN AFNP: LD A,(NMODE) OR A RET NZ ;exit if not in name field ;else fall thru to space-fill ; AFNS - SPACE-FILL AFN AFNS: LD A,' ' ;space (blank) JR AFNF ; AFNQ - '?'-FILL AFN AFNQ: LD A,'?' ;wildcard ; AFNF - FILL AFN FIELD AFNF: LD HL,(AFNCHP) LD (FILLCH),A LD A,(AFNCNT) LD B,A ;save count CALL AAHL ;position in field LD A,(AFNMAX) SUB B LD B,A ;save count LD A,(FILLCH) AFNF01: LD (HL),A ;insert space INC HL ;point to next character DJNZ AFNF01 ;loop until end of field CALL DAFN ;display field JR AFNT ; and go position in other half FILLCH: DS 1 ;character to fill afn ; PAFN - PUT CHARACTER IN STRING PAFN: PUSH AF ;save character LD A,(IMODE) OR A JR Z,PAFN01 ;IF insert on CALL AFNM ;ELSE make space PAFN01 EQU $ ;ENDIF LD HL,(AFNCHP) ;get character position LD A,(AFNCNT) CALL AAHL ;add count to hl POP AF ;restore character LD (HL),A ;put it in string CALL CHRO ;display character LD A,(IMODE) OR A JR Z,AFNR ;if insert on, go move cursor CALL DAFN ;display full name ; and fall thru to move cursor ; AFNR - CURSOR RIGHT IN AFN AFNR: LD HL,(AFNCHP) LD A,(AFNCNT) CALL AAHL ;point to current character LD A,(HL) CP ' ' JR Z,AFNT ;if space, go change mode LD HL,AFNCNT ;else LD A,(AFNMAX) ; get field max INC (HL) ; and increment position CP (HL) RET NZ ;exit if out of range ;else fall thru to toggle mode ; AFNT - TOGGLE NAME/TYPE FIELD AFNT: XOR A LD (AFNCNT),A ;reset count LD A,(NMODE) CPL LD (NMODE),A ;toggle field flag OR A JR NZ,AFNT02 ;CASE now type field LD HL,(AFNPNM) ;get position for name LD DE,CPYAFN LD A,8 ;maximum length for name AFNT01: LD (AFNMAX),A ;set maximum length of field LD (AFNCHP),DE ;set start address LD (AFNCUR),HL ;set start position RET AFNT02: LD HL,(AFNPEX) ;get position for type LD DE,CPYAFN+8 LD A,3 ;maximum length for type JR AFNT01 ; AFNM - MAKE SPACE FOR INSERT AFNM: LD HL,(AFNCHP) ;address of current field LD A,(AFNMAX) DEC A ;adjust count to offset CALL AAHL ;address of last character LD E,L ;destination in de LD D,H DEC HL ;source in hl LD A,(AFNCNT) ;current offset LD C,A LD A,(AFNMAX) SUB C ;length remaining DEC A ;length to move RET Z ;exit if nothing to move LD C,A ;set up count LD B,0 LDDR ;move field right RET ; AFNL - CURSOR LEFT IN AFN AFNL: LD A,(AFNCNT) OR A JR NZ,AFNL04 ;CASE not start of field CALL AFNT ;else toggle mode LD HL,(AFNCHP) LD A,(AFNMAX) ;get end of field count DEC A ;point to last character in field LD B,A ;set count DEC A ;point to previous CALL AAHL LD A,' ' AFNL01: CP (HL) JR NZ,AFNL02 ;IF previous not a space DEC HL ;ELSE decrement pointer DJNZ AFNL01 ; and loop until end of field AFNL02 EQU $ ;ENDIF LD A,B ;restore count AFNL03: LD (AFNCNT),A ;backspace position RET AFNL04: DEC A ;backspace to previous position JR AFNL03 ; APNL - CURSOR LEFT IN FIELD APNL: LD A,(AFNCNT) OR A RET Z ;do nothing DEC A LD (AFNCNT),A RET ; APNR - CURSOR RIGHT IN FIELD APNR: LD HL,AFNMAX LD A,(AFNCNT) INC A CP (HL) RET Z ;do nothing LD HL,(AFNCHP) LD (AFNCNT),A ;increment position DEC A CALL AAHL LD A,(HL) ;display character at current position JP CHRO ; AFNI - TOGGLE AFN INSERT MODE AFNI: LD A,(IMODE) CPL LD (IMODE),A ;toggle mode flag LD HL,INSMSG ;point to insert message OR A JP Z,CFLD ;if now insert mode, go clear it push hl call vminv ;use inverse video - gah pop hl CALL DFLD ;go display it jp vmnorm ; AFNC - POSITION CURSOR IN AFN AFNC: LD HL,(AFNCUR) ;get start of field LD A,(AFNCNT) ;get offset ADD A,H LD H,A ;offset cursor JP CURS ;go position cursor ; TFLE - TEST FILE TFLE: XOR A LD (FLERR),A ;reset error flag LD DE,WRKFCB ;point to working fcb LD C,OPEN CALL CPM ;attempt to open file LD HL,FNFMSG ;set file not found error INC A JR Z,TFLE01 ;IF open error LD HL,0 ;ELSE LD (RELREC),HL ; initialize record counter LD (SAVFSC),HL LD DE,WRKFN CALL FMTN LD A,(WRKDR) ADD A,'@' LD (DRIVNM),A ;format name and drive CALL RDFS ;read sector RET Z ;exit if good read LD HL,NRFMSG ;else set error msg TFLE01: LD (ERRTXT),HL ;ENDIF LD A,TRUE LD (FLERR),A ;set error flag RET FLERR: DS 1 ;file-error flag ; PSMD - PHYSICAL-SECTOR MODE PSMD: LD HL,(PSMDER) LD (ERRFLD),HL ;set error field pointer LD A,TRUE LD (RPANEL),A ;request panel LD (PMNEWD),A ;flag new disk PSMD01 EQU $ ;LOOP CALL ZBSA ;clear address counter LD A,(PMNEWD) OR A JR Z,PSMD02 ;IF not a new disk XOR A ;ELSE LD (PMNEWD),A ; reset flag LD A,(CURAN) LD C,A CALL SELDSK ;select physical disk CALL HOME ;home the disk LD HL,0 LD (PSMDSC),HL ;set sector to 0 ; LD (PSMDTR),HL ;set track to 0 ; The above used to set the track to 0, but I found that not very useful, ; so I changed it to point to the beginning of the directory. - jhb LD HL,(DPBOFF) LD (PSMDTR),HL PSMD02: LD A,(RPANEL) ;ENDIF OR A JR Z,PSMD03 ;IF panel not required XOR A ;ELSE LD (RPANEL),A ; reset flag $NPANEL PSMDPN ;display physical-mode panel $FLD PCBMSG CALL DCBI ;display clipboard data PSMD03 EQU $ ;ENDIF CALL PRDD ;read and display sector CALL ERRP ;process error messages PSMD04: $IFLD SELMSG ;issue selmsg, get command $MTCH PSMDLS ;get command CALL NZ,ALRM ;if invalid, sound alarm JR NZ,PSMD04 ; and loop $EXVA PSMDVC ;else execute action LD A,(WTG) CP 'P' RET NZ ;exit if not physical-sector mode JR PSMD01 ;ENDLOOP PMNEWD: DS 1 ;new-disk flag ; GENERAL BIOS ENTRY POINT FOR CP/M 3 BIOS3: LD (AVAL),A ;save caller's register values LD (BCVAL),BC ; in front of BIOS parameter block LD (DEVAL),DE LD (HLVAL),HL POP HL ;get return address for figuring which ; routine was called (also leaves proper ; return address on stack!) LD DE,LBIOS-3 ;base of jump table XOR A ;clear carry flag SBC HL,DE ;(BIOS function) * 3 now in HL LD B,A LD A,L FNCALC: SUB 3 ;figure out which BIOS function was called JR Z,GOTFN INC B JR FNCALC GOTFN: LD A,B ;stash it in BIOS parameter block LD DE,BIOSFN LD (DE),A LD C,50 ;CP/M 3 direct BIOS call JP CPM BIOSFN: DEFS 1 ;CP/M 3 BIOS parameter block AVAL: DEFS 1 ;entry values of registers on BIOS call BCVAL: DEFS 2 DEVAL: DEFS 2 HLVAL: DEFS 2 ; LOCAL DISK PARAMETER HEADER ; ; It seems that the DPH layouts for CP/M 2.2 and CP/M 3 are different. ; In particular, there are 10 bytes between DPHXLT and DPHDPB instead ; of the 8 shown here. We will correct for this when we are making a ; local copy of the DPB. - jhb DPHLCL EQU $ DPHXLT: DS 2 ;sector-translation vector DS 6 ;filler DPHDIR: DS 2 ;directory-buffer vector DPHDPB: DS 2 ;disk-parameter-block vector DPHCSV: DS 2 ;changed-disk-scratchpad vector DPHALV: DS 2 ;allocation-block-bitmap vector DPHDP3 EQU DPHDPB+2 ;equivalence for CP/M 3 ; LOCAL DISK PARAMETER BLOCK DPBLCL EQU $ DPBSPT: DS 2 ;CP/M logical sectors per track DPBBSH: DS 1 ;block-shift factor DPBBLM: DS 1 ;block mask DPBEXM: DS 1 ;extent mask DPBDSM: DS 2 ;disk size maximum DPBDRM: DS 2 ;directory size maximum DPBAL0: DS 1 ;allocation-block bitmap 0 DPBAL1: DS 1 ; 1 DPBCKS: DS 2 ;directory-check-scratchpad vector DPBOFF: DS 2 ;system-track offset DPBPSH: DS 1 ;physical-sector size (CP/M 3 only) DPBPSM: DS 1 ;physical-sector mask (CP/M 3 only) ; LOCAL DISK PARAMETER EXTENSIONS DPETPD: DS 2 ;tracks per disk DPESPB: DS 2 ;sectors per block DPERSC: DS 2 ;reserved sectors PSMDTR: DS 2 ;physical-sector-mode track PSMDSC: DS 2 ; sector PSMDBL: DS 2 ; block ;PHYSEC:DS 2 ;not used - gah ; PHYSICAL-SECTOR-MODE MESSAGES, PANEL, AND ACTION VECTORS TRKMSG: DB 11,04,'Enter Hex Track:',0 ;overlaid by ctrmsg SECMSG: DB 11,21,'Enter Hex Sector:',0 ;overlaid by cscmsg BLKMSG: DB 11,40,'Enter Hex Block:',0 ;overlaid by cblmsg DIDMSG: DB 11,61,' Enter Drive ID:',0 ;overlaid by cdkmsg PSMDPN: DB 18 ;field count DB 02,03,'Next sector',0 DB 02,33,'Select Track',0 DB 02,57,'Find ASCII string',0 DB 03,03,'Previous sector',0 DB 03,33,'Select Sector',0 DB 03,57,'Find Hex sequence',0 DB 04,03,'Next track',0 DB 04,33,'Select Block',0 DB 04,57,'Return to file List',0 DB 05,03,'Previous track',0 DB 05,33,'Select Drive',0 DB 05,57,'Exit from SuperZap',0 DB 06,03,'Clipboard operations',0 DB 07,57,'Edit sector',0 CTRMSG: DB 11,04,' Current Track ',0 ;overlaid by trkmsg CSCMSG: DB 11,21,' Current Sector ',0 ;overlaid by secmsg CBLMSG: DB 11,40,' Current Block ',0 ;overlaid by blkmsg CDKMSG: DB 11,61,'Current Drive ',0 ;overlaid by didmsg DB 14 DB 02,00,'N',0 DB 02,30,'T',0 DB 02,54,'A',0 DB 03,00,'P',0 DB 03,30,'S',0 DB 03,54,'H',0 DB 04,00,'I',0 DB 04,30,'B',0 DB 04,54,'L',0 DB 05,00,'O',0 DB 05,30,'D',0 DB 05,54,'Z',0 DB 06,00,'C',0 DB 07,54,'E',0 PSMDER: DB 09,54 ;error field set right farther down PCBMSG: DB 07,03,'Clipboard :- ',0 ;up a line ; FILE STATISTICS FIELDS PSTRFL: DB 12,11,0 ;(deleted PSTRIP) - pgm PSSCFL: DB 12,28,0 ;(deleted PSSCIP) PSBLFL: DB 12,47,0 ;(deleted PSBLIP) PSDKFL: DB 12,67,0 PSMDLS: DB 14,'NEPSITOZLBDCAH' ;was 12 - added fasc, fhex PSMDVC EQU $ DW NXPS ;next physical sector DW PSCH ;edit physical sector DW PRPS ;previous physical sector DW SPSN ;set physical sector number DW FRTR ;forward track DW SPTN ;set physical track number DW BWTR ;backward track DW SETX ;set exit mode DW PTOD ;change to directory mode DW SPBL ;set physical block DW CHPD ;change physical disk DW PCBM ;physical clipboard manager DW FASC ;find ascii string DW FHEX ;find hex sequence ; CHPD - CHANGE PHYSICAL DISK ; Now displays input drive letter, looping on invalid selection - gah CHPD: $FLD DIDMSG ;display prompt CHPD01 EQU $ ;LOOP $FLD PSDKFL ;position for disk id LD A,(CURAN) ;get absolute drive number ADD A,'A' ;make it alpha CALL CHRO ;display drive id ld a,$left call chro ;backspace over drive letter - gah CALL CHRF CP $ESC JR Z,CHPD02 ;IF escape - redisplay current cp 'A' jr c,chpd03 ;CASE non-alpha char - sound alarm and loop push af call chro ;display selected drive letter - gah pop af SUB 'A' ;make it drive number CALL CHDR ;change drive JR Z,CHPD03 ;if invalid drive, sound alarm and loop LD A,TRUE LD (PMNEWD),A ;flag new disk CHPD02: LD HL,CDKMSG ;ENDIF JP DFLD ;go redisplay current CHPD03: CALL ALRM ;sound alarm JR CHPD01 ;ENDLOOP ; PRDD - READ AND DISPLAY PHYSICAL SECTOR PRDD: CALL PSRD ;read physical sector ld hl,sbohdr call dpnll ;display sector-buffer-offset header LD HL,FBUFF CALL WRBF ;display buffer contents CALL UBLK ;update block ; and fall thru to display sector info ; DPSI - DISPLAY PHYSICAL-SECTOR INFORMATION DPSI: $FLD PSTRFL ;position cursor for track number $HEXW PSMDTR ;display track $FLD PSSCFL ;position for sector number $HEXW PSMDSC ;display sector $FLD PSBLFL ;position for block number $HEXW PSMDBL ;display block $FLD PSDKFL ;position for disk id LD A,(CURAN) ;get absolute drive number ADD A,'A' ;make it alpha call chro ;display drive id ld a,':' JP CHRO ;add a colon - gah ; UBLK - UPDATE BLOCK NUMBER UBLK: LD DE,(PSMDTR) LD BC,(DPBSPT) CALL MULT LD DE,(PSMDSC) ADD HL,DE ;calculate absolute sector LD DE,(DPERSC) OR A SBC HL,DE JR C,UBLK01 ;IF within system area EX DE,HL ;ELSE LD BC,(DPESPB) CALL DIVD ; calculate block number LD HL,(DPBDSM) OR A SBC HL,DE JR NC,UBLK02 ;skip next if block not in range UBLK01 EQU $ ;ENDIF LD DE,0 ;set block zero UBLK02: LD (PSMDBL),DE ;set new block number RET ; NXPS - NEXT PHYSICAL SECTOR NXPS: LD HL,(PSMDSC) INC HL LD (PSMDSC),HL ;increment physical-sector number LD DE,(DPBSPT) OR A SBC HL,DE RET C ;exit if track overflow LD HL,0 LD (PSMDSC),HL ;set to first sector ; and fall thru to advance track ; FRTR - NEXT TRACK (FORWARD) FRTR: LD HL,(PSMDTR) INC HL LD (PSMDTR),HL LD DE,(DPETPD) OR A SBC HL,DE RET C ;exit if disk overflow LD HL,0 LD (PSMDTR),HL ;set to first track RET ; PRPS - PREVIOUS PHYSICAL SECTOR PRPS: LD HL,(PSMDSC) LD A,H OR L JR NZ,PRPS01 ;IF sector non-zero CALL BWTR ;ELSE go back a track LD HL,(DPBSPT) ; and set up for decrement PRPS01: DEC HL ;ENDIF LD (PSMDSC),HL ;decr to previous sector RET ; SPSN - SET PHYSICAL SECTOR NUMBER ; Revised to use GTHEX routine - 20 Sept 86 pgm SPSN: $CFLD SELMSG ;clear msg field LD HL,(PSMDSC) LD (SAVPSC),HL ;save record number LD (OLDHEX),HL ; - second save $FLD SECMSG ;display set sector LD HL,PSSCFL LD (HXHED),HL LD HL,0 LD (HEXFIG),HL ;zero hex work variable LD A,3 LD (HXDIS),A SPSN01: CALL GTHEX ;LOOP LD HL,(HEXFIG) LD (PSMDSC),HL LD DE,(DPBSPT) OR A SBC HL,DE LD HL,CSCMSG ;if sector within range JP C,DFLD ; display current sector message CALL ALRM ;else signal out of range LD HL,(OLDHEX) LD (HEXFIG),HL ; and restore original sector JR SPSN01 ;ENDLOOP SAVPSC: DS 2 ;saved physical-sector number ; SPTN - SET PHYSICAL TRACK NUMBER ; Modified for gthex - 20 Sept 86 pgm SPTN: $CFLD SELMSG ;clear msg field LD HL,(PSMDTR) LD (SAVPTR),HL ;save track number LD (OLDHEX),HL ;twice - again $FLD TRKMSG ;display track message LD HL,PSTRFL LD (HXHED),HL LD HL,0 LD (HEXFIG),HL ;zero work data LD A,3 LD (HXDIS),A SPTN01: CALL GTHEX ;LOOP LD HL,(HEXFIG) LD (PSMDTR),HL LD DE,(DPETPD) OR A SBC HL,DE LD HL,CTRMSG ;if track within range JP C,DFLD ; redisplay track message CALL ALRM ;else signal error LD HL,(SAVPTR) LD (HEXFIG),HL ; and restore work data JR SPTN01 ;ENDLOOP SAVPTR: DS 2 ;saved track number ; BWTR - PREVIOUS TRACK (BACKWARD) BWTR: LD HL,(PSMDTR) LD A,H OR L JR NZ,BWTR01 ;IF track non-zero LD HL,(DPETPD) ;ELSE set up for decrement BWTR01: DEC HL ;ENDIF LD (PSMDTR),HL ;decrement to previous track RET ; SPBL - SET PHYSICAL BLOCK ; Modified for gthex - pgm SPBL: $CFLD SELMSG ;clear msg field LD HL,(PSMDBL) LD (SAVPBL),HL ;save block number LD (OLDHEX),HL $FLD BLKMSG ;display block message LD HL,PSBLFL LD (HXHED),HL LD HL,0 LD (HEXFIG),HL ;zero variable LD A,2 LD (HXDIS),A SPBL01: CALL GTHEX ;LOOP LD HL,(HEXFIG) LD (PSMDBL),HL LD DE,(DPBDSM) EX DE,HL OR A SBC HL,DE JP P,SPBL02 ;CASE block within range CALL ALRM ;else signal error LD HL,(OLDHEX) LD (HEXFIG),HL ; and restore to original JR SPBL01 ;ENDLOOP SPBL02: LD DE,(PSMDBL) LD BC,(DPESPB) CALL MULT LD DE,(DPERSC) ADD HL,DE ;calculate absolute sector EX DE,HL LD BC,(DPBSPT) CALL DIVD LD (PSMDTR),DE ;set track LD (PSMDSC),HL ;set sector LD HL,CBLMSG ;redisplay current block message JP DFLD SAVPBL: DS 2 ;saved block number ; CLIPBOARD PANEL AND ACTION VECTORS PCBMPN: DB 3 DB 02,04,'Copy current sector to clipboard',0 DB 03,04,'Exchange current sector with clipboard',0 DB 04,04,'Return to sector display',0 DB 3 DB 02,01,'C',0 DB 03,01,'X',0 DB 04,00,'ESC',0 PCBCUR: DB 11,00,'Current :- ',0 PCBCBD: DB 12,00,'Clipboard :- ',0 PCBML: DB 3,$ESC,'CX' PCBMV EQU $ DW PCBX ;exit clipboard manager DW PLCB ;load clipboard DW PXCB ;exchange current sector with clipboard PCBX: RET ; PCBM - PHYSICAL CLIPBOARD MANAGER PCBM: $NPANEL PCBMPN ;display panel $FLD PCBCUR ;position for current info $STRO CBDMSG LD A,(CURAN) ADD A,'A' CALL CHRO ;display drive ld a,':' call chro ;add a colon - gah $STRO CBTMSG $HEXW PSMDTR ;track $STRO CBSMSG $HEXW PSMDSC ;sector $FLD PCBCBD ;position for clipboard data CALL DCBD CALL CBCI ;get command $EXVA PCBMV ;process command JR RQPANL ;request panel ; PXCB - EXCHANGE CURRENT PHYSICAL SECTOR WITH CLIPBOARD ; Fixed to actually work as intended! - 21 Feb 89 gah PXCB: LD A,(CBTYPE) OR A JP Z,ALRM ;if clipboard empty, go ring bell LD BC,(CBADDR) CALL DMASET ;set CP/M buffer call ioaddr ;make it effective NOW - gah CALL PSWR ;write buffer LD BC,FBUFF CALL DMASET ;restore dma ; and fall thru to copy old buffer ; PLCB - LOAD CLIPBOARD (PHYSICAL) PLCB: LD HL,FBUFF LD DE,(CBADDR) LD BC,128 LDIR ;copy the buffer LD A,1 LD (CBTYPE),A ;set type LD A,(CURAN) LD (CBDRIV),A ;set drive LD HL,(PSMDTR) LD (CBNAME),HL ;set track LD HL,(PSMDSC) LD (CBSECT),HL ;set sector RET ; LSEL - LIST FILE SELECTION STUB MASK POINTED TO BY HL LSEL: LD DE,LMDFN LD BC,11 LDIR RET ; PSCH - EDIT PHYSICAL SECTOR PSCH: CALL SCCH ;go into sector-change mode LD A,(SCCHWR) OR A JR Z,RQPANL ;IF write not required CALL PSWR ;ELSE write out sector RQPANL: LD A,TRUE ;ENDIF LD (RPANEL),A ;request panel RET ; SCCH - SECTOR-CHANGE MODE SCCH: LD HL,HLAREA CALL CLRA ;clear the help area $PANEL SCCHPN ;display sector-editing panel XOR A LD (BUFPOS),A ;buffer position 0 LD (SCCHEX),A ;set exit false LD (SCCHWR),A ;set write flag false LD (ASCII),A ;set ascii false LD (LOORD),A ;start with hi-order hex digit SCCH01: CALL SLCP ;LOOP CALL UDCP ;position cursor CALL CHRI CP ' ' JR C,SCCH04 ;CASE control code LD A,(ASCII) OR A LD A,(INCH) ;get input character JR Z,SCCH06 ;CASE not ascii mode - make hex change CP ' ' JR C,SCCH05 ;CASE character below ascii range CP $MAXASC JR NC,SCCH05 ;CASE character above ascii range PUSH AF ;else PUSH AF ; save character LD HL,FBUFF LD A,(BUFPOS) ;get buffer offset CALL AAHL ;point to character POP AF ;restore character LD (HL),A ; to buffer CALL ASCO ;echo it CALL SHUDCP ;position cursor in hex area POP AF ;restore character CALL HEXO SCCH02: CALL RGHT ;move cursor for next SCCH03: LD A,(SCCHEX) OR A RET NZ ;exit if end of updates JR SCCH01 ;ENDLOOP SCCH04: $MTCH SCCHLS; ;check for valid control code JR NZ,SCCH05 ;if invalid code, sound alarm and loop $EXVA SCCHVC ;else act on control code JR SCCH03 ;check for exit and loop SCCH05: CALL ALRM ;sound the alarm JR SCCH01 ; and loop for another character SCCH06: CALL FOLD LD (INCH),A ;save folded input character $MTCH HEXCHR JR NZ,SCCH05 ;CASE invalid hex digit LD C,L ;set hex value of nibble in c LD A,(INCH) CALL ASCO ;echo it LD HL,FBUFF ;base of buffer LD A,(BUFPOS) ;get offset CALL AAHL ;hl = a (current character) LD B,(HL) ;b = current character LD A,(LOORD) OR A LD A,0F0H ;set mask JR NZ,SCCH07 ;IF lo nybble, go set mask LD A,C ;ELSE get character in accumulator RLCA ; and switch nybbles RLCA RLCA RLCA ;hex = hex * 16 AND 0F0H ;clear any mince left LD C,A ;back to c register LD A,0FH ;set mask SCCH07 EQU $ ;ENDIF AND B ;mask nibble OR C ;insert new value LD (HL),A ;replace in buffer PUSH AF ;save it for ascii CALL SACP ;set cursor address for ascii display CALL UDCP ;update cursor position POP AF ;pick up new character CALL ASCO ;display it JR SCCH02 ;go advance cursor HEXCHR: DB 16,'0123456789ABCDEF' ;valid hex digits SCCHEX: DB 0 ;exit flag SCCHWR: DB 0 ;write flag ; SECTOR-EDIT PANEL AND ACTION VECTORS SCCHPN: DB 8 DB 02,04,'Cursor left',0 DB 02,44,'New line',0 DB 03,04,'Cursor right',0 DB 03,44,'Toggle hex/ASCII field',0 DB 04,04,'Cursor up',0 DB 04,44,'Write changes to disk',0 DB 05,04,'Cursor down',0 DB 05,44,'Quit and cancel changes',0 DB 8 DB 02,00,'^',$LEFT+40H,0 DB 02,40,'CR',0 DB 03,00,'^',$RIGHT+40H,0 DB 03,40,'TAB',0 DB 04,00,'^',$UP+40H,0 DB 04,40,'^',$END+40H,0 DB 05,00,'^',$DOWN+40H,0 DB 05,40,'^',$QUIT+40H,0 SCCHLS: DB 8,$LEFT,$TAB,$DOWN,$UP,$RIGHT,CR,$END,$QUIT SCCHVC EQU $ DW LEFT ;move cursor left DW TOGL ;toggle between hex and ascii fields DW DOWN ;move cursor down one line DW UPWD ;move cursor up one line DW RGHT ;move cursor right DW NWLN ;move cursor to start of new line DW CHND ;end edit and write out changes DW QUIT ;end edit without saving changes ; LEFT - MOVE CURSOR LEFT LEFT: LD A,(LOORD) OR A JR NZ,LEFT01 ;IF high or ascii LD A,(BUFPOS) DEC A AND 7FH LD (BUFPOS),A ;decrement position LEFT01: LD A,(ASCII) ;ENDIF OR A RET NZ ;exit if hex mode LD A,(LOORD) CPL JR TOGLL ;toggle digit ; RGHT - MOVE CURSOR RIGHT RGHT: LD A,(ASCII) OR A LD A,(LOORD) JR NZ,RGHT01 ;IF hex mode CPL ;ELSE toggle hex digit LD (LOORD),A RGHT01: OR A ;ENDIF RET NZ ;exit if high order or ascii LD A,(BUFPOS) INC A JR SETBP ; TOGL - TOGGLE BETWEEN HEX AND ASCII TOGL: LD A,(ASCII) CPL LD (ASCII),A ;toggle ascii mode flag LD A,FALSE TOGLL: LD (LOORD),A ;indicate high-order digit RET ; UPWD - MOVE CURSOR UP ONE LINE UPWD: LD A,(BUFPOS) SUB 16 JR SETBP ; DOWN - MOVE CURSOR DOWN ONE LINE DOWN: LD A,(BUFPOS) ADD A,16 SETBP: AND 7FH SETBP1: LD (BUFPOS),A ;increment position RET ; NWLN - MOV CURSOR TO START OF NEW LINE NWLN: LD A,FALSE LD (LOORD),A ;indicate high-order hex digit LD A,(BUFPOS) ADD A,16 AND 70H JR SETBP1 ; CHND - END EDIT AND WRITE OUT CHANGES CHND: OR A ;clear z flag (leave set for QUIT) ; QUIT - END EDIT AND DISCARD CHANGES QUIT: LD A,TRUE LD (SCCHEX),A ;signal exit RET Z ;exit if QUIT LD (SCCHWR),A ;signal write RET ; DCBD - DISPLAY CLIPBOARD DATA DCBD: CALL DCBI ;display clipboard info LD A,(CBTYPE) OR A RET Z ;exit if clipboard empty ld hl,sbohdr ;else call dpnll ; display sector-buffer-offset header CALL ZBSA ; clear address counter LD HL,(CBADDR) ; and fall thru to display data ; WRBF - DISPLAY FILE DATA IN SECTOR BUFFER WRBF: push hl ;save buffer pointer - gah call vmcrof ;turn off cursor XOR A LD (BUFPOS),A ;set offset to 0 pop de ;get buffer pointer in de WRBF01 EQU $ ;LOOP (hex and ascii line) PUSH DE ;save buffer pointer PUSH DE ; and again for ascii XOR A LD (CPOS),A ;position 1 CALL STLP ;set line cursor position CALL UDCP ;update cursor CALL PRTADR ;display address LD A,(BASEAD+2) ADD A,10H LD (BASEAD+2),A ;increment addr for next line CALL SHUDCP ;position cursor in hex area POP DE ;get current address WRBF02 EQU $ ;LOOP (bytes in hex) LD A,(DE) ;get character there INC DE ;increment buffer pointer CALL HEXO ;print byte CALL SPCO ;print space LD HL,BUFPOS INC (HL) ;increment to next column LD A,3 AND (HL) JR NZ,WRBF03 ;IF not end of group CALL SPCO ;ELSE print space WRBF03: LD A,0FH ;ENDIF AND (HL) JR NZ,WRBF02 ;UNTIL 16 bytes displayed LD A,(HL) SUB 16 LD (HL),A ;reset buffer offset CALL SACP ;position for ascii LD HL,CPOS DEC (HL) ;back off 1 for margin CALL UDCP ;position cursor LD A,'|' CALL CHRO ;print margin POP DE ;restore character pointer WRBF04 EQU $ ;LOOP (bytes in ascii) LD A,(DE) ;get current character INC DE ;increment pointer CALL ASCO ;print character LD HL,BUFPOS INC (HL) ;increment buffer offset LD A,0FH AND (HL) JR NZ,WRBF04 ;UNTIL 16 bytes displayed LD A,'|' CALL CHRO ;print margin LD A,(HL) AND 7FH ;if reached end of buffer jp z,vmcron ; turn on cursor and exit JR WRBF01 ;UNTIL 128 bytes displayed ; CURSOR-POSITION TABLES FOR HEX AND ASCII DISPLAY DRTAB: DB 14 ;first line of directory-display area LPTAB: DB 15,16,17,18,19,20,21,22 HCTAB: DB 09,12,15,18,22,25,28,31,35,38,41,44,48,51,54,57 ACTAB: DB 63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78 DCTAB: DB 00,20,40,60 ; ZBSA - ZERO BASE ADDRESS ZBSA: ld hl,basead XOR A ld (hl),a inc hl ld (hl),a inc hl ld (hl),a RET ; PRTADR - PRINT FILE ADDRESS PRTADR: $HEXW BASEAD ;display 2 bytes LD A,(BASEAD+2) JP HEXO ; STLP - SET UP LINE POSITION STLP: LD HL,LPTAB ;get base of line table LD A,(BUFPOS) RRA ;move to lo nybble RRA RRA RRA AND 0FH CALL AAHL LD A,(HL) ;get value LD (LPOS),A ;set up line position RET ; SLCP - SET CURSOR TO CURRENT LINE AND COLUMN POSITION IN BUFFER SLCP: CALL STLP ;set up line position LD A,(ASCII) OR A JR NZ,SACP ;if not in ascii display mode CALL SHCP ;else set up for hex display LD A,(LOORD) OR A RET Z ;exit if low-order digit LD HL,CPOS INC (HL) ;increment column position RET ASCII: DB 0 ;ascii flag LOORD: DB 0 ;lo-order-byte flag ; SHCP - SET CURSOR ADDRESS FOR HEX DISPLAY SHCP: LD HL,HCTAB JR SETPOS ; SACP - SET CURSOR ADDRESS FOR ASCII DISPLAY SACP: LD HL,ACTAB SETPOS: LD A,(BUFPOS) AND 0FH CALL AAHL LD A,(HL) ;pick up value LD (CPOS),A ;set up column position RET ; CHDR - CHANGE TO DRIVE IN A REGISTER ; Fixed to use DPH of requested drive after disk-system reset - gah CHDR: LD (SAVDRV),A ;save requested drive LD C,A CALL SELDSK ;locate dph LD A,H OR L JR Z,CHDR01 ;if invalid drive, reselect current LD C,RESET ;else CALL CPM ; reset disk system ld a,(savdrv) ;now, reselect requested drive ld c,a ; *AFTER* CP/M disk reset, call seldsk ; which always defaults to drive A:!!! - gah PUSH HL ;save dph LD HL,-1 LD (PRVSEC),HL ;clear prvtrk and prvsec to force LD (PRVTRK),HL ; physical I/O on next access ; <<< INITIALIZE PHYSICAL CONTROL BLOCKS >>> ; If CP/M 3.1, then the DPH is not necessarily in the same memory bank as ; this program, but the banked BDOS does us the favor of making a local ; copy in common memory. POP HL ;restore dph LD DE,DPHLCL LD BC,16 LDIR ;take local copy of DPH LD HL,(DPHDPB) ;DPB pointer for CP/M 2.x LD A,(CPM3) ;check which version of CP/M OR A ; so we get the DPB pointer right JR Z,COPYDPB ;skip reload if CP/M 2.2 LD HL,(DPHDP3) ;get CP/M 3 DPB pointer COPYDPB:LD DE,DPBLCL LD BC,17 ;increased from 15 for CP/M+ LDIR ;take local copy of DPB LD DE,(DPBSPT) LD BC,(DPBOFF) CALL MULT ;hl returns number of system sectors PUSH HL LD (DPERSC),HL ;save reserved sectors LD A,(DPBBLM) LD E,A LD D,0 INC DE LD (DPESPB),DE ;save sectors per block LD BC,(DPBDSM) CALL MULT ;hl returns number of file sectors POP DE ADD HL,DE ;hl contains sectors per disk LD DE,(DPBSPT) DEC DE ADD HL,DE ;ready to round up EX DE,HL LD BC,(DPBSPT) CALL DIVD ;de returns tracks per disk LD (DPETPD),DE ;save tracks per disk ; and initialize FCBs LD A,(SAVDRV) ;restore requested drive LD (CURAN),A ;save as absolute disk number INC A LD (WRKDR),A ;put it in work FCB LD (LMDDR),A ; and directory FCB CALL RDIR ;read directory LD A,TRUE OR A ;set flags non-zero RET CHDR01: LD A,(CURAN) ;get current drive id LD C,A CALL SELDSK ;reselect it XOR A ;set zero flags RET SAVDRV: DS 1 ;temporary storage for selected drive ; DLST - DIRECTORY LISTING DLST: $FLD DDLMSG LD DE,LMDFN ;location of filename LD A,(CURAN) ;get disk id ADD A,'A' ;convert to ascii letter LD (DRIVNM),A ;put drive name in message CALL FMTN $STRO DRIVNM LD DE,(FSTDE@) LD A,(DIROFF) ;get starting entry LD L,A LD H,0 CALL H16D ;hl = count * length + first LD (NXTDE@),HL ;point to first display XOR A LD (PRTCNT),A DLST01: LD A,(DIROFF) ;LOOP LD B,A LD A,(DECNT) SUB B LD HL,PRTCNT CP (HL) RET Z ;exit if all entries processed LD A,(HL) ;get display counter CALL DIRPOS ;position to display LD A,$FLAGCH ;load flag character CALL CHRO ;print it CALL SPCO ; and space LD DE,(NXTDE@) ;point entry to print CALL FMTN ;format filename $STRO FILENM ;print name LD HL,(NXTDE@) LD DE,16 ADD HL,DE LD (NXTDE@),HL ;update table pointer LD HL,PRTCNT INC (HL) ;increment display counter LD A,32 CP (HL) RET Z ;exit if display full JR DLST01 ;ENDLOOP DDLMSG: DB 12,23,'Directory List - ',0 ; RDIR - READ DIRECTORY RDIR: XOR A LD (DECNT),A ;no entries in table LD (SELDE),A ;select list entry 0 LD (DIROFF),A ;display starts at 0 LD HL,(MEMRY) LD (NXTDE@),HL ;where to insert pointer LD (FSTDE@),HL ;start of table pointer DEC HL LD (TOPDE@),HL ;top of table LD DE,LMDFCB LD C,FNDFST CALL CPM ;get first directory entry CP 0FFH JR Z,RDIR02 ;exit if no file matched LD HL,FBUFF ;point to record RRCA ;multiply offset by 32 RRCA RRCA CALL AAHL ;address of current directory entry LD (NEWDE@),HL ;save it CALL INSRT ;put matched entry in table LD HL,(TOPDE@) LD DE,16 ADD HL,DE LD (TOPDE@),HL ;mark top of table RDIR01: LD DE,LMDFCB ;LOOP LD C,FNDNXT CALL CPM ;find next match CP 0FFH JR Z,RDIR02 ;exit if no more LD HL,FBUFF ;point to record RRCA ;multiply directory code by 32 RRCA RRCA CALL AAHL LD (NEWDE@),HL ;save it CALL ORDER ;find out where to put it CALL INSRT ;put entry in table JR RDIR01 ;ENDLOOP RDIR02: LD HL,(TOPDE@) INC HL LD (PGEPTR),HL ;mark start of paging pointers RET ; INSRT - PUT DIRECTORY ENTRY IN TABLE INSRT: LD HL,(NEWDE@) ;get address of new entry INC HL ;don't copy drive byte LD DE,(NXTDE@) ;get table pointer LD BC,16 ;length of entry LDIR ;save entry LD HL,DECNT INC (HL) ;increment entry count RET ; ORDER - UPDATE THE DIRECTORY TABLE ORDER: LD HL,(FSTDE@) ORDER1: LD DE,(TOPDE@) ;LOOP EX DE,HL OR A SBC HL,DE JP M,ORDER2 ;CASE end of table PUSH DE ;else save current pointer LD HL,(NEWDE@) ;point to new entry INC HL ;ignore drive id field LD BC,11 ;length of filename CALL CPST ;compare filename POP DE ;restore current pointer JP M,ORDER2 ;exit if current > new LD HL,16 ADD HL,DE ;point to next entry JR ORDER1 ;ENDLOOP ORDER2: LD (NXTDE@),DE ;save insert address LD HL,(TOPDE@) INC HL OR A SBC HL,DE LD C,L ;length to move LD B,H LD HL,(TOPDE@) ;current top of table PUSH HL ;save current top LD DE,16 ADD HL,DE ;new top of table LD (TOPDE@),HL ;save new top POP DE ;restore old top LD A,B OR C RET Z ;exit if nothing to move EX DE,HL ;dest = new, src = old top address LDDR ;move table up 16 bytes RET ; CPST - COMPARE STRING (HL)0:6 WITH (DE)0:6 LENGTH (BC) CPST: XOR A LD (CPSTCN),A ;compare condition is = CPST01: LD A,B ;LOOP OR C JR Z,CPST02 ;CASE we're done PUSH BC ;else save counter LD A,(DE) ;get 2nd string character AND 7FH ;ignore high bit LD B,A ;save it LD A,(HL) ;get 1st string character AND 7FH ;ignore hi bit SUB B ;compare current characters LD (CPSTCN),A ;save result POP BC ;retrieve counter JR NZ,CPST02 ;exit if not equal INC HL INC DE DEC BC ;point to next characters JR CPST01 ;ENDLOOP CPST02: LD A,(CPSTCN) ;pick up conditions OR A ;set cpu flags RET CPSTCN: DS 1 ;compare condition ; CLRA - CLEAR AREA FROM LINE H FOR L CLRA: LD B,L LD A,H CLRA01: CALL CLRL INC A DJNZ CLRA01 LD HL,0 LD (PRVERR),HL ;no error now displayed RET ; FMTN - FORMAT FILE NAME FROM FCB POINTED TO BY DE INTO FILENM FMTN: LD HL,FILENM LD B,8 ;length 8 FMTN01: LD A,(DE) ;LOOP AND 7FH ;strip high bit LD (HL),A ;copy character INC HL INC DE DJNZ FMTN01 ;UNTIL name done LD (HL),'.' ;insert separator INC HL LD A,(DE) AND 80H LD (RO),A ;set r/o flag LD B,3 ;length 3 FMTN02: LD A,(DE) ;LOOP AND 7FH ;strip high bit LD (HL),A ;copy character INC HL INC DE ;point to next DJNZ FMTN02 ;UNTIL type done LD A,(RO) OR A ;test r/o flag LD A,'W' ;assume r/w mode JR Z,FMTN03 ;IF read/only LD A,'O' ;select r/o mode FMTN03: LD (FDMDRS),A ;ELSE set mode XOR A LD (COMFLG),A ;clear .COM flag LD HL,COMSTR LD DE,FILENM+9 ;point to type LD BC,3 CALL CPST RET NZ ;IF .COM file LD A,TRUE LD (COMFLG),A ;set flag RET ;ENDIF COMSTR: DB 'COM' ;.COM file type ;------------------- ; FILE I/O ROUTINES ;------------------- ; DMASET - RECORD THE DATA-TRANSFER ADDRESS FOR DISK OPERATIONS DMASET: LD (DMA),BC RET DMA: DEFW 0080H ;default at entry to this program ; IOADDR - SET THE DATA-TRANSFER ADDRESS FOR DISK OPERATIONS IOADDR: LD DE,(DMA) LD C,SDMA JP CPM ; RDFS - READ FILE-RELATIVE SECTOR RDFS: PUSH BC ;save bc XOR A LD (WRKOV),A LD HL,(WRKRR) LD (SAVFSC),HL ;save current record LD HL,(RELREC) LD (WRKRR),HL ;set record number CALL IOADDR ;set data pointer LD DE,WRKFCB ;point to fcb LD C,READRN CALL CPM ;read the record LD (READST),A ;save status OR A JR Z,RDFS01 ;IF good read LD HL,(SAVFSC) ;ELSE LD (RELREC),HL ; restore record number LD (WRKRR),HL RDFS01: POP BC ;ENDIF RET ; WRFS - WRITE FILE-RELATIVE SECTOR BACK TO DISK WRFS: CALL IOADDR ;set data pointer LD DE,WRKFCB ;point to fcb LD C,WRITRN ;random write JP CPM ;go do it ; PHYS3 - TEST IF CP/M PLUS AND IF SO, THEN CHANGE SECTOR NUMBER ; TO CONFORM TO PHYSICAL SECTOR SIZE PHYS3: LD A,(CPM3) OR A PUSH AF ;save result for caller JR Z,PEXIT ;no transformation needed for CP/M 2.2 LD A,(DPBPSH) ;pick up physical sector size from DPH INC A ;pre-increment for shift loop PSHIFT: DEC A ;count down the number of shifts JR Z,PEXIT ;CASE we're done SRL B ;bc := bc/2 SRA C JR PSHIFT ;around again PEXIT: POP AF RET ; SECPNT - BUILD ADDRESS OF 128-BYTE "LOGICAL" SECTOR WITHIN PSBUFF ; On exit, HL holds the required address, and BC contains the value 128 ; (ready for an LDIR instruction). SECPNT: LD HL,(PSMDSC) ;get sector number LD A,(DPBPSM) ;get physical sector mask AND L ;calculate which 128-byte chunk LD HL,PSBUFF LD BC,128 ;chunk size POFF: RET Z ;exit now if address calculated ADD HL,BC ;else increment pointer DEC A JR POFF ;around again ; PSRD - READ PHYSICAL SECTOR PSRD: CALL IOADDR ;we'll override this later if CP/M 3.x LD BC,(PSMDTR) CALL SETTRK ;select track LD BC,(PSMDSC) CALL PHYS3 ;if CP/M 3.x, then change to physical PUSH BC ;save sector number during tests JR Z,PSRD01 ;IF CP/M 2.2 LD HL,(PRVSEC) ;ELSE see if same physical sector as last time SBC HL,BC ;(carry flag already clear) JR NZ,PSRD01 ;do read if different LD BC,(PRVTRK) ;check track LD HL,(PSMDTR) SBC HL,BC JR Z,PSRD04 ;CASE different PSRD01 EQU $ ;ENDIF POP BC ;get back sector number LD (PRVSEC),BC ;record sector... LD HL,(PSMDTR) LD (PRVTRK),HL ; ...and track ; LD DE,(DPBOFF) ; OR A ; SBC HL,DE ; JR C,STSA ;if not system track LD DE,(DPHXLT) CALL SECTRN ;do sector translation LD C,L LD B,H STSA: CALL SETSEC LD A,(CPM3) OR A JR Z,PSRD02 ;IF CP/M 3 LD BC,PSBUFF ;ELSE use physical sector buffer CALL SETDMA PSRD02 EQU $ ;ENDIF CALL READ ;read sector PUSH AF ;preserve result LD A,(CPM3) OR A JR Z,PSRD03 ;IF CP/M 2.2 CALL IOADDR ;ELSE restore DMA CALL SECPNT ;calculate address in psbuff LD DE,(DMA) ;where to put the data LDIR ;copy it PSRD03: POP AF ;ENDIF RET ;If we get here, then we are running under CP/M+ and already have the ;correct physical sector in memory. All we have to do is deliver the ;appropriate logical sector to the rest of the program. PSRD04: POP BC ;align stack CALL SECPNT ;build pointer into psbuff LD DE,(DMA) ;where to put the data LDIR ;move 128 bytes RET ; PSWR - WRITE PHYSICAL SECTOR PSWR: LD A,(CPM3) ;decide which method to use OR A JR Z,PSWR1 ;IF CP/M 2.2 CALL SECPNT ;ELSE calculate address within psbuff EX DE,HL ;put destination address into de LD HL,(DMA) ;where to get the data LDIR ;move the data LD BC,PSBUFF ;set address for data transfer CALL SETDMA PSWR1 EQU $ ;ENDIF LD C,WRDIR ;use bios directory-sector code to force write CALL WRITE ;write out sector PUSH AF ;save result for caller CALL IOADDR ;restore data address POP AF RET WRDIR EQU 1 ;BIOS directory-sector code PRVSEC: DW -1 ;physical sector number PRVTRK: DW -1 ;physical track number ;------------------ ; UTILITY ROUTINES ;------------------ ; H16D - HL = HL * 16 + DE H16D: ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,DE RET ; ERRP - PROCESS ERROR DISPLAYS ERRP: LD HL,(PRVERR) LD A,H OR L JR Z,ERRP01 ;IF previous error PUSH HL ;ELSE save text address $FLD ERRFLD ;position cursor POP HL CALL CSTR ;clear string LD HL,0 LD (PRVERR),HL ;clear pointer ERRP01: LD HL,(ERRTXT) ;ENDIF LD A,H OR L RET Z ;exit if error not set LD (PRVERR),HL ;save text address PUSH HL ;save text pointer $FLD ERRFLD ;position cursor call vminv ;use inverse video - gah pop hl CALL STRO ;output text call vmnorm CALL ALRM ;sound alarm LD HL,0 LD (ERRTXT),HL ;clear text pointer RET ;ENDIF ; MTCH - BYTE LIST MATCHER MTCH: PUSH BC ;save bc LD C,(HL) ;bc = length LD B,0 INC HL ;point to start of list PUSH BC ;save length CPIR ;scan list POP HL ;restore length to hl JR NZ,MTCH01 ;IF found OR A ;ELSE SBC HL,BC ; subtract residue to give offset + 1 DEC HL ;hl is offset CP A ;set z flag MTCH01 EQU $ ;ENDIF POP BC ;restore bc RET ; EXVA - JUMP TO ROUTINE AT OFFSET 2*HL FROM DE EXVA: ADD HL,HL ;derive action address ADD HL,DE ;note: z flag unaffected! CALL LDHL JP (HL) ; LDHL - LOAD HL WITH (HL) LDHL: PUSH AF ;save flags LD A,(HL) ;get lo byte INC HL LD H,(HL) ;get hi byte in H LD L,A ; and lo byte in L POP AF ;restore flags RET ; AAHL - HL = HL + A AAHL: PUSH DE ;save de LD E,A LD D,0 ADD HL,DE POP DE ;restore de RET ; MULT - MULTIPLY DE BY BC TO GIVE PRODUCT IN HL AND OVERFLOW IN DE MULT: LD HL,0 ;zero product LD A,16 ;set loop count OR A ;clear carry MULT01: EX DE,HL ;LOOP ADC HL,HL ;shift de left 1 (and into carry) EX DE,HL JR NC,MULT02 ;IF bit shifted out of de is clear ADD HL,BC ;ELSE add multiplicand to result JR NC,MULT02 ;IF no overflow INC DE ;ELSE propagate into de MULT02 EQU $ ;ENDIF / ENDIF DEC A ;decrement loop counter RET Z ;exit if counter went to zero ADD HL,HL ;shift left 1 (overflow added by adc) JR MULT01 ;ENDLOOP ; DIVD - DIVIDE DE BY BC TO GIVE REMAINDER IN HL AND QUOTIENT IN DE DIVD: LD HL,0 ;zero remainder LD A,16 ;set loop count DIVD01 EQU $ ;LOOP ADD HL,HL ;shift remainder left 1 EX DE,HL ADD HL,HL ;shift divisor left 1 EX DE,HL JR NC,DIVD02 ;IF no carry INC HL ;ELSE increment result DIVD02 EQU $ ;ENDIF OR A ;clear carry flag SBC HL,BC ;subtract divisor INC DE ;increment quotient JP P,DIVD03 ;IF result is positive ADD HL,BC ;ELSE back off subtract DEC DE ; and decrement quotient DIVD03 EQU $ ;ENDIF DEC A ;decrement loop counter RET Z ;exit if counter went to zero JR DIVD01 ;ENDLOOP ; PTOD - CHANGE TO DIRECTORY MODE PTOD: LD A,(CURAN) CALL CHDR ;reselect current disk ; and fall thru to set directory mode ; SETD - SET DIRECTORY MODE SETD: LD A,'D' DB 01H ;disguise next ld instructions ; SETF - SET FILE MODE SETF: LD A,'F' DB 01H ; SETP - SET PHYSICAL SECTOR MODE SETP: LD A,'P' DB 01H ; SETX - SET EXIT MODE SETX: LD A,'X' LD (WTG),A RET ;--------------------- ; SCREEN I/O ROUTINES ;--------------------- ; CHRI - INPUT CHARACTER ; Use BIOS call to support systems with software cursor CHRI: PUSH BC PUSH DE PUSH HL CALL CONIN LD (INCH),A POP HL POP DE POP BC RET ; CHRF - GET FOLDED CHARACTER CHRF: CALL CHRI ; FOLD - FOLD CHARACTER IN A TO UPPERCASE IF REQUIRED FOLD: CP 'a' RET C CP 'z'+1 RET NC ;IF not uppercase AND 5FH ;fold character RET ;ENDIF ; ALRM - SOUND THE CONSOLE BELL ; Preserves accumulator and flags ALRM: PUSH AF LD A,BEL JR OUTCH ; SPCO - OUTPUT SPACE TO SCREEN SPCO: PUSH AF LD A,' ' OUTCH: CALL CHRO POP AF RET ; SHUDCP - POSITION CURSOR IN HEX AREA SHUDCP: CALL SHCP ;set cursor address for hex display ; and fall thru to update cursor position ; UDCP - UPDATE CURSOR POSITION TO LPOS/CPOS UDCP: ld hl,lpos ;get line/column numbers call ldhl ; in hl ; and fall thru to position cursor ; CURS - SET CURSOR POSITION TO LINE L, COLUMN H ; Added equate dependence for outputting infix and suffix strings - gah CURS: PUSH AF PUSH HL $STRL CPPREF ;output cursor-position prefix POP HL PUSH HL LD A,(ROW1ST) ;row or column? OR A PUSH AF ;save row/column flag CALL COORD if insffx $STRL CPMID ;output cursor-position infix endif POP AF ;recover row/column flag DEC A ;toggle it for 2nd coordinate POP HL CALL COORD if insffx $STRL CPEND ;output cursor-position suffix endif POP AF RET LPOS: DB 0 ;line number CPOS: DB 0 ;column number ; COORD - OUTPUT A CURSOR-POSITION COORDINATE ; L contains line number (row) ; H contains horizontal position (column number) ; Z flag is set if H coordinate required, reset if L COORD: JR Z,DOHOR LD A,(ROWOFF) ADD A,L JR EITHER DOHOR: LD A,(COLOFF) ADD A,H EITHER: LD E,A LD A,(CPBIN) OR A JR Z,DECOUT LD A,E ;fall thru to output character ; CHRO - OUTPUT CHARACTER IN A CHRO: PUSH BC PUSH DE PUSH HL CHROUT: LD C,A CALL CONOUT ;use BIOS function for speed POP HL POP DE POP BC RET ; DECOUT - CONVERT 16-BIT NUMBER IN DE TO DECIMAL AND OUTPUT TO THE SCREEN ; Leading zeros are suppressed; number is treated as unsigned. DECOUT: PUSH BC PUSH DE PUSH HL EX DE,HL LD DE,-1 ;initialize quotient LD BC,-10 ;radix DVLP: ADD HL,BC ;subtract radix INC DE ;increment quotient JR C,DVLP ;(slow way to divide) SBC HL,BC ;correct for extra subtract EX DE,HL LD A,H OR L ;test for zero CALL NZ,DECOUT ;recursive call LD A,'0' ADD A,E ;convert digit for display JR CHROUT ;go write it to screen ; HEXW - OUTPUT WORD IN HL TO SCREEN HEXW: PUSH AF LD A,H CALL HEXO LD A,L CALL HEXO POP AF RET ; HEXO - OUTPUT BYTE IN A IN HEX TO SCREEN HEXO: PUSH AF RRA ;reverse nybbles RRA RRA RRA CALL HEXC ;print hi nybble POP AF ; and fall thru to print lo nybble ; HEXC - OUTPUT LOW NYBBLE IN A IN HEX TO SCREEN HEXC: AND 0FH ;lose hi nybble ADD A,90H DAA ADC A,40H DAA JR CHRO ;go output hex character ; CLRL - CLEAR LINE CONTAINED IN A CLRL: PUSH AF PUSH HL LD L,A ;line (a) LD H,0 ;col 0 CALL CURS ;position to line $STRL CLLSTR ;print clear-line string POP HL POP AF RET ; CLRS - CLEAR SCREEN AND HOME CURSOR CLRS: PUSH AF PUSH HL $STRL CLSSTR ;print clear-screen string LD HL,0 LD (PRVERR),HL ;clear prev error POP HL POP AF RET ; DHDR - CLEAR SCREEN AND DISPLAY HEADER DHDR: CALL CLRS LD HL,HDRMSG ; DFLD - DISPLAY FIELD DFLD: PUSH HL CALL LDHL CALL CURS ;set cursor position POP HL INC HL INC HL ;fall thru to output string ; STRO - OUTPUT STRING POINTED TO BY HL AND DELIMITED BY A NULL STRO EQU $ ;LOOP LD A,(HL) ;get character INC HL ;bump pointer OR A ;check for null terminator RET Z ;exit if found CALL CHRO ;else output character JR STRO ;ENDLOOP ; CFLD - CLEAR FIELD CFLD: PUSH HL CALL LDHL CALL CURS ;set cursor position POP HL INC HL INC HL ;fall thru to clear string ; CSTR - CLEAR STRING POINTED TO BY HL CSTR EQU $ ;LOOP LD A,(HL) ;get character INC HL ;bump pointer OR A ;check for null terminator RET Z ;exit if found CALL SPCO ;else output space JR CSTR ;ENDLOOP ; STRL - OUTPUT LENGTH-PREFIXED STRING POINTED TO BY HL STRL: PUSH BC ;save bc LD B,(HL) ;get length byte INC B ;increment it for use as counter STRL01 EQU $ ;LOOP INC HL ;increment pointer DEC B ;decrement counter JP Z,STRL02 ;exit if counter reached zero LD A,(HL) ;else get character CALL CHRO ; and output it JP STRL01 ;ENDLOOP STRL02: POP BC ;restore bc RET ; DPNL - DISPLAY PANEL ; Displays first field in normal video, then next field in highlight - gah DPNL: call dpnl01 DPNLL: push hl call vmhi ;use highlight - gah pop hl call dpnl01 jr vmunhi DPNL01: LD B,(HL) INC HL DPNL02: PUSH BC CALL DFLD ;display field POP BC DJNZ DPNL02 RET ; ASCO - OUTPUT ASCII CHARACTER OR '.' TO SCREEN ; Modified to use inverse video to display ASCII characters with high bit set. ; The idea is to make sector displays more readable. - Jan 86 jhb ASCO: OR A ;check high bit PUSH AF ;save high bit flag PUSH AF ;save character during video-mode change CALL M,VMINV ;turn on inverse video POP AF ;recover character for display AND 7FH ;mask off high bit CP $MAXASC JP NC,ASCO01 ;IF out of ascii range CP ' ' JP NC,ASCO02 ;IF not ctrl character ASCO01 EQU $ ;ENDIF LD A,'.' ;default for undisplayable ASCO02 EQU $ ;ENDIF CALL CHRO ;output character POP AF ;did we turn on inverse? RET P ;nope, so just return ;else fall thru to reset normal video ; VIDEO FUNCTIONS VMNORM: LD HL,VNORM ;normal video JP STRL ;use absolute jump for speed VMINV: LD HL,VINV ;inverse video JP STRL ;use absolute jump for speed VMHI: LD HL,VHILIT ;highlight JR STRL VMUNHI: LD HL,VUNHIL ;highlight off JR STRL VMBLNK: LD HL,VBLNK ;blinking video JR STRL VMUNBL: LD HL,VUNBL ;unblinking video JR STRL VMCRON: LD HL,VCRON ;cursor on JR STRL VMCROF: LD HL,VCROFF ;cursor off JR STRL ; END OF CODE PSBUFF EQU $ ;physical-sector i/o buffer ENDCDE EQU $+2048 END INIT