title History utility name ('HISTRSX') ; RSX HISTRSX1 OS equ 0000h BDOS equ 0005h .string equ 9 .kbdrd equ 10 .SCB equ 49 .RSX equ 60 _CO equ 4 RSX_Oxx equ 55 RSX_CL equ 56 null equ 00h lf equ 0ah cr equ 0dh eot equ '$' ; ; SCB offsets ; SCB@ equ 3ah ; SCB.WRM equ 068h SCB.CCP equ 0b4h SCB.COL equ 0b7h SCB.RIN equ 0bah CCP.ACT equ 10000000b RECALL equ 'W'-'@' DELLFT equ 'X'-'@' DELRGT equ 'K'-'@' CUU equ '_'-'@' ; PCW cursor up CUD equ '^'-'@' ; PCW cursor down all equ 11111111b ROWS equ 24 ROWMAX equ 100 _LD.HL equ 021h HISTBF equ 300 ; Size of history buffer ; #### RSX HEADER BEGINS ### ; ds 6 ; xx00: Serial number jp BegRSX ; xx06: Jump to RSX _BDOS: jp BDOS+1 ; xx09: Jump to next RSX dw BDOS+2 ; xx0C: Address of previous RSX RSXperm: db -1 ; xx0E: Permanent flag db 0 ; xx0F: Bank flag db 'HIST ' ; xx10: Name of RSX db 0 ; xx18: Loader flag db 0,0 ; xx19: Reserved ; ; #### RSX HEADER ENDS ### ; BegRSX: ld a,c ; Get BDOS function cp .RSX ; Test RSX call jr z,RSXcall ; Yeap ld a,(RSXactive) ; Test RSX active or a jr z,_BDOS ; Go to BDOS if not ld a,c cp .kbdrd ; Test read from keyboard jr nz,_BDOS ; Nope, enter BDOS ld a,e ; Test edit old buffer or d jr z,_BDOS ; Enter BDOS if so ld hl,(SCBadr) ; Get address of SCB ld l,SCB.RIN ; Point to input redirection ld a,(hl) inc l or (hl) jr nz,_BDOS ; Enter BDOS if redirected ld l,SCB.CCP ; Point to CCP flags ld a,(hl) and CCP.ACT ; Extract executing bit ld (CCPexe),a push de xor a ; Clear ... ld (EARLY$CHAR),a ; ... early character ld (AHEAD$CHAR),a ; ... ahead character ld hl,-1 ld (l04a9),hl call SaveBIOS ; Save BIOS vectors call _BDOS ; Call BDOS call RestBIOS ; Restore BIOS vectors pop de inc de ld a,(de) ; Get length or a ; Test any character in there ret z ; Nope ld c,a ; Set length ld b,0 inc de ; Skip for start of input call isinBuff ; Test string already in buffer call nz,put2Buff ; Nope, insert it ret RSXcall: ld a,(de) ; Get RSX parameter cp RSX_CL ; Test clear RSX parameters jr z,ClrBuff cp RSX_Oxx ; Test install or remove RSX jr nz,_BDOS ; Neither, try other call ; ; Install or remove HISTORY RSX ; ld a,(RSXactive) ; Test active or a jr z,InstRSX ; Nope ; ; Remove HISTORY RSX ; ld a,-1 ld (RSXperm),a ; Set permanent nope inc a ld (RSXactive),a ; Set passive ld de,$REMOVE ld c,.string call _BDOS ; Tell RSX removed xor a ; Set success ret ; ; Install HISTORY RSX ; InstRSX: call _BDOS ; Call RSX or a ret z ; End if previous ld (RSXactive),a ; Set active xor a ld (RSXperm),a ld de,SCBpb ld c,.SCB call _BDOS ; Get address of SCB ld (SCBadr),hl ; Save it ld l,SCB.WRM ; Point to warm boot vector ld de,2*3 ld b,4 ld a,_LD.HL InstVec: ld (hl),a ; Set opcode into vectors add hl,de djnz InstVec ld hl,(OS+1) ; Get BIOS vector ld a,3*(_CO-1) call adda ; Build address of console output ld (OS@COT),hl ; Save it ld de,$ACTIVE ld c,.string call _BDOS ; Tell history active ; ; Clear parameters of HISTORY RSX ; ClrBuff: ld hl,NULL ld (Q.TOP),hl ; Clear pointers ld (Q.BOT),hl ld hl,Q.BUF ; Init buffer address ld (Q.PTR),hl xor a ; Set success ret ; ; BIOS intercepted function 'Warm start' ; MY@WARM: ld sp,LocStk ; Get local stack call RestBIOS ; Restore BIOS vectors jp OS@WARM ; Execute original warm start ; ; BIOS intercepted function 'Console status' ; MY@CST: ld a,(AHEAD$CHAR) ; Get ahead character or a jr nz,IS@CST ; There is one ld a,(EARLY$CHAR) ; Test early character or a jp z,OS@CST ; Get state via BIOS if neither IS@CST: or all ret ; ; BIOS intercepted function 'Console input' ; MY@CIN: ld hl,AHEAD$CHAR ld a,(hl) ; Get ahead character ld (hl),null ; Clear it or a jr z,l01f7 ld a,DELLFT ret l01f7: ld a,(EARLY$CHAR) ; Get early character or a ; Test one jr nz,l0214 ; Yeap call OS@CIN ; Get character from BIOS cp CUU ; Test cursor up jr z,l020b cp CUD ; Test cursor down jr z,l020b cp RECALL ret nz l020b: ld (EARLY$CHAR),a ; Save as early ... ld (AHEAD$CHAR),a ; ... and ahead character ld a,DELRGT ret l0214: cp RECALL jr z,l028e xor a ld (RowSel),a ; Clear rows l021c: ld a,(RowSel) ; Get rows cp ROWMAX ; Test max jr nc,l0243 inc a ; Advance row ld (RowSel),a ; Save it ld hl,(l04a9) inc hl ld a,h or l jr z,l0232 dec hl jr l024a l0232: ld a,(EARLY$CHAR) ; Get early character cp CUU ; Test cursor up ld hl,(Q.BOT) ; Get up pointer jr z,l023f ; Yeap ld hl,(Q.TOP) ; Get down pointer l023f: ld a,h ; Test any here or l jr nz,l025e ; Yeap l0243: ld a,(EARLY$CHAR) ; Get early character call RestBIOS ; Restore BIOS vectors ret l024a: ld a,(EARLY$CHAR) ; Get early character cp CUU ; Test cursor up jr z,l027e ; Yeap inc hl inc hl ld e,(hl) inc hl ld d,(hl) ex de,hl ld a,h or l jr nz,l025e ld hl,(Q.TOP) ; Get down pointer l025e: ld (l04a9),hl ld a,4 call adda ; HL:=HL+A ld a,(CCPexe) cp (hl) ; Test same level jr nz,l021c ; Nope inc hl inc hl ex de,hl ld hl,(SCBadr) ld l,SCB.RIN ; Point to input redirection ld (hl),e inc hl ld (hl),d xor a ld (EARLY$CHAR),a ; Clear early character dec de ld a,(de) ret l027e: ld hl,(l04a9) ld e,(hl) inc hl ld d,(hl) ex de,hl ld a,h or l jr nz,l025e ld hl,(Q.BOT) ; Get up pointer jr l025e l028e: xor a ld (RowSel),a ; Clear row ld hl,(Q.TOP) ; Get down pointer l0295: ld (l04ab),hl ld a,h or l jr z,l02b4 ld a,4 call adda ; HL:=HL+A ld a,(CCPexe) cp (hl) ; Test same level inc hl call z,PrNxtRow ; Print string if so ld hl,(l04ab) inc hl inc hl ld e,(hl) inc hl ld d,(hl) ex de,hl jr l0295 l02b4: call ClrLine ; Clear line from left to cursor xor a ld (EARLY$CHAR),a ; Clear early character jp MY@CIN ; ; Clear line from left to cursor ; ClrLine: push hl call NL ; Give new line on console ld hl,(SCBadr) ld l,SCB.COL ; Point to console column ld a,(hl) ; Fetch it or a jr z,ClrLinEx ; Already left position ld b,a ld c,' ' ClrLineLoop: call MY@COT ; Put to console djnz ClrLineLoop ClrLinEx: pop hl ret ; ; Save BIOS vectors and set new ones ; SaveBIOS: push bc push de ld hl,(OS+1) ; Get vector ld de,OS@WARM ld bc,OS.HEAD ldir ; Save vectors ld de,(OS+1) ld hl,OS@NEW ld bc,OS.HEAD ldir ; Set new vectors pop de pop bc ret ; ; Restore BIOS vectors ; RestBIOS: push de ld de,(OS+1) ; Get vector ld hl,OS@WARM ld bc,OS.HEAD ldir ; Set original ones pop de ret ; ; Original BIOS vectors ; OS@WARM: ds 3 ; Warm start OS@CST: ds 3 ; Console status OS@CIN: ds 3 ; Console input OS.HEAD equ $-OS@WARM ; ; New BIOS vectors ; OS@NEW: jp MY@WARM ; Warm start jp MY@CST ; Console status jp MY@CIN ; Console input ; ; Console output via BIOS ; MY@COT: push hl push bc OS@COT equ $+1 call $-$ pop bc pop hl ret ; ; Convert character to upper case ; toupper: cp 'a' ; Test range ret c cp 'z'+1 ret nc sub 'a'-'A' ; Convert ret ; ; Compare strings ^HL:^DE with length in reg BC ; streq: push bc ld a,(de) ; Get character call toupper ; As upper case ld c,a ld a,(hl) ; Once again call toupper cp c ; Compare pop bc ret nz ; No match inc de inc hl dec bc ld a,c ; Test done or b jr nz,streq ; Nope ld a,(hl) ; Verify real end or a ret ; ; Test string ^DE with length in reg BC already in history buffer ; Z set says string already found ; notinBuff: inc a ; Set NZ indicating not found ret isinBuff: ld hl,(Q.TOP) ; Get down pointer srcNxt: ld a,l ; Test end or h jr z,notinBuff ; Yeap push hl pop ix ; Copy history pointer ld a,(CCPexe) ; Get level cp (ix+4) ; Test same jr nz,srcNxtLnk ; Nope ld a,5 call adda ; HL:=HL+A push bc push de call streq ; Compare strings pop de pop bc ret z ; Found srcNxtLnk: ld l,(ix+2) ; Get pointer to next block ld h,(ix+2+1) jr srcNxt ; ; Insert string ^DE with length in reg BC into history buffer ; put2Buff: ld hl,(Q.PTR) ; Get buffer address add hl,bc ; Add length of new string ld a,6 call adda ; HL:=HL+A push de ld de,Q.BUF+HISTBF or a sbc hl,de ; Test enough buffer space jr c,putItNow ; Yeap, insert it call DelFirst ; Delete first entry pop de jr put2Buff ; Retry putItNow: ld hl,(Q.BOT) ; Get up pointer ld a,h ; Test any in or l jr nz,putGo ; Yeap ld hl,Q.BUF ; Init address if not putGo: ld de,(Q.PTR) ; Get buffer address inc hl inc hl ld (hl),e ; Store link to next inc hl ld (hl),d ex de,hl dec de ; Fix to base dec de dec de ld (Q.BOT),hl ; Save top address ld (hl),e ; Save link to previous inc hl ld (hl),d inc hl xor a ld (hl),a ; Ground link to next inc hl ld (hl),a inc hl ld a,(CCPexe) ; Get CCP execution flag ld (hl),a ; Unpack inc hl pop de ex de,hl ldir ; Unpack string xor a ld (de),a ; Close it inc de ld (Q.PTR),de ; Set buffer address ld hl,(Q.TOP) ; Get down pointer ld a,h ; Test any there or l ret nz ; Yeap ld hl,(Q.BOT) ; Get top address ld (Q.TOP),hl ; Set root node ld (hl),a ; Ground it inc hl ld (hl),a ret ; ; Delete first string ; DelFirst: ld hl,(Q.TOP) ; Get down pointer ld a,h ; Test any or l ret z ; Nope inc hl inc hl ld e,(hl) ; Get pointer to next inc hl ld d,(hl) ld a,d ; Test next pointer or e jr nz,goDel ; Got it ex de,hl jp ClrBuff ; Clear list goDel: push bc ld hl,(Q.TOP) ; Get down pointer push de ex de,hl or a sbc hl,de ; Calculate gap ld (DelPtr),hl ; Save pointer ld b,h ld c,l ld hl,HISTBF or a sbc hl,bc ; Calculate length ld b,h ld c,l ld hl,(Q.TOP) ; Get down pointer pop de ex de,hl ldir ; Unpack data ld hl,(Q.TOP) ; Get down pointer xor a ld (hl),a ; Ground pointer to previous inc hl ld (hl),a inc hl DelLoop: ld e,(hl) ; Fetch pointer to next inc hl ld d,(hl) ld a,d ; Test defined or e jr z,DelDone ; Yeap, that'a all push hl ld hl,(DelPtr) ; Get back pointer ex de,hl or a sbc hl,de ; Calculate new address ex de,hl pop hl ld (hl),d ; Save dec hl ld (hl),e ex de,hl dec de dec de ld (hl),e inc hl ld (hl),d inc hl jr DelLoop DelDone: dec hl ; Fix for start dec hl dec hl ld (Q.BOT),hl ; Save top address ld hl,(Q.PTR) ; Get buffer address ld de,(DelPtr) ; Get deletion address or a sbc hl,de ld (Q.PTR),hl ; Set buffer address pop bc ret ; ; Advance row count and print message ; PrNxtRow: push hl ld hl,RowSel ; Point to row ld a,(hl) inc (hl) ; Advance it cp ROWS-1 ; Test screen filled call z,WtChar ; Wait for more call ClrLine ; Clear line from left to cursor pop hl ; ; Print zero closed string ^HL to console ; PrStrg: ld a,(hl) ; Get character or a ; Test end ret z ; Yeap inc hl ld c,a call MY@COT ; Put to console jr PrStrg ; ; Wait for character ; WtChar: ld (hl),0 ; Clear row call NL ; Give new line on console ld hl,$MORE call PrStrg ; Tell we expect more call OS@CIN ; Get any character from BIOS ld hl,$CLEAR jr PrStrg ; Clear message on screen ; ; Put new line to console ; NL: ld c,cr call MY@COT ; Put new line to console ld c,lf jp MY@COT ; ; Add Accu to reg HL ; adda: add a,l ld l,a ; Add accu ret nc inc h ; Remember carry ret ; $REMOVE: db cr,lf,'History RSX removed',eot $ACTIVE: db cr,lf,'History RSX active',eot $MORE: db '[more]',null $CLEAR: db cr,' ',cr,null AHEAD$CHAR: db null Q.TOP: dw 0 ; Queue top pointer Q.BOT: dw 0 ; Queue bottom pointer SCBadr: dw 0 ; Address of SCB SCBpb: db SCB@ db 0 RSXactive: db 0 ; Active if <> 0 EARLY$CHAR: db null l04a9: dw 0 l04ab: dw 0 DelPtr: dw 0 ; Deletion pointer CCPexe: db 0 ; CCP executing if <> 0 RowSel: db 0 ; Row selection Q.PTR: dw Q.BUF ; Input buffer pointer Q.BUF: ds HISTBF ; Input buffer ; ds 2*3 LocStk: end