; Installation program for ZERR ; Version 13 ; July 9, 1990 ; Rob Friefeld ; ZERR ID vers equ 16 ; Version of target file ; TARGET FILE OFFSETS veroffset equ 15h ; Version number check location idoffset equ 0dh ; Name of target program cmdoffset equ 1ah ; Start of commands in target file patoffset equ 17h ; Patch byte offset lshoffset equ 3bh ; Name to check on shell stack name_len equ 8 ; Max length of name preoffset equ 31h ; Transient invocation prefix pref_len equ 9 ; Max length of prefix recs equ 3 ; Records of target file to read ; EDITOR INSTALLATION SCREEN cmds equ 21 ; Number of commands to install cmax equ 3 ; Number of columns rmax equ 7 ; Number of rows col_width equ 28 ; Column width roffset equ 10 ; Blank rows at top coffset equ 3 ; Blank cols at left meta_mark equ '#' ; Mark a shifted command include sysdef.lib .request vlib,z3lib,syslib ext pfn2,retud,dutdir ext z3vinit,cls,ereol,gotoxy,at,stndout,stndend,tinit,dinit ext getmsg,putcst,z3log ext pafdc,phlfdc ext $memry ecnofile equ 10 ; Z34 error code "No File" ehcall equ 14 ; Invoke error handler ; ZERR will have one of these strings embedded progid0 macro dc 'ZERR ' db vers endm progid1 macro dc 'ZERR+LSH' db vers endm ; ;===== PROGRAM HEADER ; entry: jp start db 'Z3ENV' db 1 envaddr: dw 0fe00h ; Include the two program ID strings here prog0: progid0 chklen equ $-prog0 prog1: progid1 ; ; COMMAND DESCRIPTIONS ; text: dc 'Lead-in Key' dc 'Backspace' dc 'Char Left' dc 'Char Right' dc 'Word Left' dc 'Word Right' dc 'Line End/ Start' dc 'Line Start' dc 'Line End' dc 'Delete Char' dc 'Delete Left' dc 'Delete Word Rt' dc 'Delete Word Lt' dc 'Delete Line' dc 'Delete to EOL' dc 'Toggle Insert' dc 'Enter Control' dc 'Execute Line' dc 'Abort Line' dc 'Skip Command' dc 'Kill Command' ; ;===== PROGRAM START ; start: ld (stksav),sp ; Set up local stack ld hl,($memry) ld de,48 add hl,de ld (filebuf),hl ; Set up file pointer ld sp,hl ; ; Init ; ld hl,(envaddr) ; Init vlib call z3vinit call tinit ; Set Up Arrow Keys ld hl,(envaddr) ; Pt to environment descriptor ld de,80h+10h ; Pt to arrow key info add hl,de ld de,edcurt ; Pt to cursor table ld bc,0404h ; 4 arrow keys ld a,(hl) or a jr z,arrowx ; No arrow keys arrow: ldi inc de ; Pt to next entry inc de djnz arrow arrowx: ; ;===== READ TARGET FILE ; ld a,(fcb+1) ; Check for help request cp '/' jp z,idinfo ld a,(fcb+9) cp ' ' call z,default_type call savusr ; Save user number call open ; Open the file jp z,nofile ld a,readf ; Read it into filebuf ld bc,recs ld hl,(filebuf) call r$wdata call close ; Close file now ; ; Verify version number of file just read ; call vercheck jp nz,vers_error ; ;===== MAIN MENU ; main_menu: call menu ; Show menu screen call get_char call case ; Scan list of choices db '1' dw patch db '2' dw edctls db 'X' dw exit db '.' dw exit db 'S' dw quit db 0 jr main_menu menu: call cls call print db cr,lf db ' ' db '>>> ZERR ' db vers/10 + '0','.',vers mod 10 + '0',0 ld a,(revnum) call cout call print db ' INSTALLATION <<<' dc cr,lf,lf call pfile call print db cr,lf,lf db ' 1 Set default options',cr,lf db ' 2 Install control keys',cr,lf,lf db ' S Save changes and quit',cr,lf db ' X Quit',cr,lf db lf dc 'Choice: ' ret ; ;===== CONTROL KEY INSTALLATION ; header: call cls call print db cr,lf db ' Letters in the table below represent CONTROL KEYS. Those followed',cr,lf db ' by a "#" are shifted keys which are scanned only after the lead-in key',cr,lf db ' has been pressed. Each command must be assigned a unique key.',cr,lf,lf db ' ',1 db 'Cursor Movement: ^E Up, ^D Rt, ^X Dn, ^S Lt (Or Arrow Keys) ',cr,lf,2 db ' ',1 db 'Quit: ^C or "." Skip: CR, ESC, DEL, TAB: Use Key Disable: "-"' db 2,0 ret edctls: call header ; Command screen info ld hl,(fileptr) ; Point to start of target ld de,cmdoffset ; Point to command list add hl,de ld (cmd_list),hl ; Save this xor a ; Start with command 0 ; ; Display current command list ; HL points to an element of the command list ; From its position in the list, a cursor row and column is computed ; The command character and text string describing it are printed ; pscreen: cp cmds ; Done them all? jp nc,edit_cmd ; Yes ld (cmd_num),a ; Store current command # call set_pos ; Set row, col to it call edcrs ; Move cursor ld a,(hl) ; Get the command char inc hl ; Point to next push af and 7fh ; Mask it off call case db del ; Special handling for some chars dw delprint db '[' dw escprint db 'M' dw crprint db 'I' dw tabprint db 0 ; Case terminator call cout ; Else just print it pscr0: pop af ; Recover original char bit 7,a ; Test high bit (meta key) ld a,meta_mark jr nz,pscr1 ; Result was "yes" ld a,' ' pscr1: call cout call ptext ; Print text associated with this command ld a,(cmd_num) ; Next command inc a jr pscreen ; Print special chars ; delprint: call vprint dc bs,bs,'DEL' jr pscr0 escprint: call vprint dc bs,bs,'ESC' jr pscr0 crprint: call vprint dc bs,'CR' jr pscr0 tabprint: call vprint dc bs,bs,'TAB' jr pscr0 ; Print text for current command number ; Text lines are high bit terminated ; ptext: push hl call print dc ' ' ld a,(cmd_num) ld b,a ; Count lines to one wanted ld hl,text or a jr z,ptext2 ptext1: ld a,(hl) inc hl or a jp p,ptext1 djnz ptext1 ptext2: call printhl ; Now print it pop hl ret ; ; Move cursor to row,col for current index ; edcrs: push hl push bc ld a,(rindex) add roffset ld h,a ld bc,(cindex) ld b,col_width call multbc add coffset ld l,a call gotoxy pop bc pop hl ret ; B * C in A ; multbc: xor a add c djnz $-1 ret ; ; Get row,col corresponding to current command # ; get_pos: ld a,(cmd_num) ld c,-1 gp1: inc c sub rmax jr nc,gp1 add rmax ld b,a ret ; c = cindex, b = rindex ; ; Save row,col for command # ; set_pos: call get_pos ld (cindex),bc ret ; ; Edit the command table ; edit_cmd: call reset_ind ; Start at first command edit: call edcrs ; Move cursor to it call get_char ; User input edit1: ld e,a ; Save char call cmd_point ; HL -> current position in command list call case db esc ; Acceptable control keys dw entesc ; For convenience, these are entered directly db tab dw enttab db cr dw entcr db del dw entdel db 'E'-'@' ; Compare to editing controls dw edup db 'D'-'@' dw edrt db 'X'-'@' dw eddn db 'S'-'@' dw edlt db 'C'-'@' ; Quit dw main_menu db '.' dw main_menu db ' ' dw ednext ; Arrow Key Definitons from TCAP ; edcurt: db 'E'-'@' ; These are overloaded dw edup db 'X'-'@' dw eddn db 'D'-'@' dw edrt db 'S'-'@' dw edlt db 0 cp 21h jp nc,enter ; Any char > space jp edit ; No match ; Cursor movement ; edrt: call inc_col jr edmove edlt: call dec_col jr edmove edup: call dec_row jr edmove eddn: call inc_row edmove: call new_cmd jr edit ; Go to next element MOD total elements ednext: call inc_row ld a,(rindex) or a jr nz,edmove call inc_col jr edmove ; Enter char in command table ; At this point, char is in E and HL -> position in command table ; enter: call vprint ; Erase current char dc 2,bs,bs,' ' call rprint ; Standout print new char enter1: call change ; Set flag to indicate something altered ld (hl),e ; Load new command in table call get_char ; Now check for shifted command ld e,meta_mark cp e jr z,enter2 ; Yes push af ; No, erase possible # on screen call vprint dc 2,' ',bs,bs pop af jp edit1 ; and take this as next char enter2: set 7,(hl) call rprint jp edit rprint: call stndout ld a,e call cout call stndend ret entdel: call vprint dc bs,bs,1,'DEL' jr enter1 entesc: ld e,'[' ; Char equiv call vprint dc bs,bs,1,'ESC' jr enter1 enttab: ld e,'I' call vprint dc bs,bs,1,'TAB' jr enter1 entcr: ld e,'M' call vprint dc bs,bs,' ',1,'CR' jr enter1 ; Set HL to command # in table ; cmd_point: push de ld de,(cmd_num) ld d,0 ld hl,(cmd_list) add hl,de pop de ret new_cmd: ld bc,(cindex) ld b,rmax call multbc ld b,a ld a,(rindex) add b ld (cmd_num),a cp cmds ret c call reset_ind ret reset_ind: xor a ld (cindex),a ld (rindex),a ld (cmd_num),a ret inc_row: ld hl,rindex ld e,rmax-1 jr inc_index inc_col: ld hl,cindex ld e,cmax-1 inc_index: inc (hl) ld a,e cp (hl) ret nc ld (hl),0 ret dec_row: ld hl,rindex ld e,rmax-1 jr dec_index dec_col: ld hl,cindex ld e,cmax-1 dec_index: ld a,(hl) or a jr z,dci1 dec (hl) ret dci1: ld (hl),e ret ; ;===== PATCH DEFAULTS ; row defl 3 patch: call cls call print db 'Default Configuration Installation: to skip a field' dc cr patch0: call patflags ; Y/N options call patprefix ; Transient invocation prefix. ld a,(zl_flag) ; LSH version? or a call z,lshname patch1: call print dc cr,lf,lf,'All OK? (Y/n) ' call get_char cp 'N' jp z,patch0 jp main_menu ; Set patch pointer from offset in DE hl_to_ptr: ld hl,(fileptr) add hl,de ld (patptr),hl ret ; Patch flag values ; patflags: call AT db row,1 ld de,patoffset ; Point to patch bytes call hl_to_ptr call print dc cr,'Do you like beeps?' call YNprompt inc hl call print dc cr,lf,'Insert On?' call YNprompt inc hl call print dc cr,lf,'Destructive Backspace?' ; Get a flag value and accept a Y/N input to set it ; YNprompt: call print dc cr,lf,' Current Value: (Y/N) ' call YN0 call print dc ' -> ' call get_char cp 'Y' jr nz,YN3 ld (hl),-1 jr YN3a YN3: cp 'N' jr nz,YN0 ld (hl),0 YN3a: call change jp cout YN0: ld a,(hl) or a ld a,'N' jr z,YN2 YN1: ld a,'Y' YN2: jp cout ; Transient invocation prefix ; row defl row+7 patprefix: ld de,preoffset ; Point to prefix string call hl_to_ptr ld h,row ld l,1 call gotoxy call print ; Modified by Carson Wilson 8 Sep 89 to prefix an arbitrary string ; and continue processing if CSF bit 4 is set on entry (signals that ; a transient version of a resident command should be invoked). db cr db 'The ZCPR command status flag may signal that a transient version of a',cr,lf db 'resident command should be invoked by prefixing the bad command with ":".',cr,lf db 'The prefix can be a directory reference, or the feature can be disabled with',cr,lf db 'a null prefix (enter "0")',cr,lf,lf dc 'Current prefix -> ' ld hl,(patptr) call printhl call ereol call print db cr,lf dc ' _________',cr ld h,row+6 ld l,19 call gotoxy ld hl,tbuf ld a,pref_len call rdbuf1 call sksp ret z call change ld de,(patptr) ld a,(hl) cp '0' jr z,patnull patprefix1: ld a,(hl) call upcase ld (de),a inc hl inc de or a ret z jr patprefix1 patnull: ld b,pref_len xor a patnull1: ld (de),a inc de djnz patnull1 ret ; Name for shell stack match ; row defl row+8 lshname: ld de,lshoffset ; Yes, get name for stack comparison call hl_to_ptr ld h,row ld l,1 call gotoxy call print db cr db 'To correct LSH''s history file, ZERR must know what name LSH will have on',cr,lf db 'the shell stack. Do not install a directory reference.',cr,lf,lf dc 'Current name -> ' ld hl,(patptr) call printhl call ereol call print db cr,lf dc ' ________',cr ld h,row+4 ld l,17 call gotoxy ld hl,tbuf ld a,name_len call rdbuf1 call sksp ret z call change ld de,(patptr) jp patprefix1 ; ; READ LINE FROM USER INTO INPUT LINE BUFFER ; Enter A = max char count rdbuf: ld a,60 ; Default input size rdbufA: ld hl,tbuf rdbuf1: push bc push de ld (hl),a ex de,hl ; Set de as ptr to buffer ld c,10 ; Bdos readln push de ; Save ptr call bdos pop hl ; Pt to char count inc hl ld e,(hl) ; Get char count ld d,0 inc hl ; Pt to first char push hl ; Save ptr add hl,de ; Pt to after last char ld (hl),0 ; Store ending 0 pop hl ; Pt to first char pop de pop bc ret ; Skip to next non-blank sksp: ld a,(hl) ; Get char inc hl ; Pt to next cp ' ' ; Skip spaces jr z,sksp dec hl ; Pt to good char or a ; Set eol flag ret ; ;===== DISK ROUTINES ; ; Store user for fcb1 ; savusr: ld a,(fcb+13) ld (usr),a ret ; Put user from stored value ; putusr: ld a,(usr) ld (fcb+13),a ret ; Prepare fcb1 for output file ; zcontrol: ld hl,fcb+12 ; Zero control bytes ld b,24 xor a ld (hl),a inc hl djnz $-3 ret ; Open file in fcb1 ; open: call putusr ld de,fcb call Z3LOG ld c,openf call bdos inc a ret ; Z = No file ; Close file in fcb1 ; close: ld c,closef bdosfcb: ld de,fcb jp bdos ; ; READ/WRITE A DATA FILE ; Enter: HL -> start ; BC = number of records, caller's responsibility to avoid ovfl ; A = WRITEF or READF ; File in FCB1 is open ; Return: NZ = error r$wdata: ld (r$wdatf),a r$wdat1: ld a,c ; BC record counter or b ret z ; done dec bc push bc ; save count push hl ; save dma addr ex de,hl ; set it ld c,setdmaf call bdos r$wdatf equ $+1 ld c,readf ; execute selected function call bdosfcb pop hl ; restore dma pop bc ; restore count or a ret nz ; Error ld de,128 add hl,de ; Point to next record jr r$wdat1 ; Print file name in fcb ; pfile: call vprint dc 1,'File: ' ld de,fcb call RETUD ; Drive in b, user in c ld a,b add 'A' call cout ld a,c call pafdc call DUTDIR ; Print NDR entry call nz,pfile2 call print dc ':' inc de call PFN2 call stndend ret pfile2: call print dc '/' ld b,8 pfile2a: ld a,(hl) inc hl cp ' ' call nz,cout djnz pfile2a ret ; ;===== CONSOLE ROUTINES ; print: vprint: ex (sp),hl call vprint1 ex (sp),hl ret ; ; Print String (terminated in 0) pted to by HL ; printhl: vprint1: ld a,(hl) ; Done? inc hl ; Pt to next or a ; 0 terminator ret z cp dim ; Standout? jr z,vprint1d cp bright ; Standend? jr z,vprint1b call cout ; Print char or a ret m jr vprint1 vprint1d: call stndout ; Dim jr vprint1 vprint1b: call stndend ; Bright jr vprint1 ; Console input routine, no echo cin: push hl push de push bc cin1: ld c,6 ld e,-1 call 5 or a jr z,cin1 pop bc pop de pop hl ret ; Console Output Routine cout: push hl push de push bc push af ; Save AF, too and 7fh ; Mask out MSB ld e,a ; Transfer character to E ld c,2 ; BDOS conout function number call 5 pop af pop bc pop de pop hl ret get_char: call cin ; Upper case char in A ; upcase: cp 'a' ret c cp 'z'+1 ret nc and 5fh ret ; ; Case - jump table scanner, version 1.1 ; Affect only alternate registers. ; Format: call case ;call with value to match in A ; db val1 ;first val to match ; dw addr1 ;jump address ; ... ; db 0 ;end table ; else next instuction executes if no match case: exx ; Preserve regs ex (sp),hl ; Hl -> next addr after call ex af,af' ; Save char xor a case1: ex af,af' ; Restore char cp (hl) ; Match? inc hl ; Set pointer to val's jump addr jr z,case0 ; If match, jump inc hl ; Point to next val inc hl ex af,af' ; Check for list terminator cp (hl) jr nz,case1 ; Keep looking inc hl ; No match, execute next instruction ex af,af' ; Restore A casex: ex (sp),hl exx ; Restore other regs ret case0: ld e,(hl) ; Load address inc hl ld d,(hl) ex de,hl jr casex ; Go ; ;===== EXITS ; exit: ld a,(change_flag) or a jp nz,save_it call stndend call cls exit0: call dinit ld sp,(stksav) ret nofile: call print dc ' No file' call getmsg ld (hl),ecnofile ld a,ehcall call putcst jr exit0 idinfo: call print db 'ZERRINST - Default option and command key installation for ZERR ' db vers/10 + '0','.',vers mod 10 + '0',cr,lf db ' Syntax: ZERRINST ',0 jp exit0 ; Set change flag change: push af xor a dec a ld (change_flag),a pop af ret ; Inquire whether to save save_it: xor a ld (change_flag),a call print dc ' Save changes (Y/n)? ' call get_char cp 'N' jp z,exit ; Save changes and exit quit: call print dc ' Saved' call zcontrol call open ld bc,recs ld a,writef ld hl,(filebuf) call r$wdata call close jp exit ; Check version number and program type (ZERR or ZERRLSH) of target file vercheck: ld hl,(filebuf) ld (fileptr),hl call checkZERR ret z ; ZERR, type3 call checkZERRLSH jr nz,vercheck1 ; Not a type3 vercheck0: xor a ld (zl_flag),a ; Mark program to install ret vercheck1: ld hl,(filebuf) ; Set up on second page for type4 program ld de,100h add hl,de ld (fileptr),hl call checkZERR ret z ; ZERR, type4 call checkZERRLSH jr z,vercheck0 ret ; No matches checkZERRLSH: ld de,prog1 ; ZERRLSH? jr verchk checkZERR: ld de,prog0 verchk: ld hl,(fileptr) ld bc,idoffset add hl,bc ld b,chklen verchk1: ld a,(de) cp (hl) ret nz inc de inc hl djnz verchk1 ld a,(hl) ; Revision # ld (revnum),a ret vers_error: call print db ' Installs only ZERR, Version ' db vers/10+'0','.',vers mod 10 + '0',0 jp exit0 default_type: ld hl,def_type ld de,fcb+9 ld bc,3 ldir ret ; ;===== DATA ; ; Initialized def_type: db 'COM' zl_flag: db 0ffh ; ZERR = FF, ZERRLSH = 0 change_flag: db 0 ; Any changes made? cindex: db 0 ; Column index rindex: db 0 ; Row index cmd_num: db 0 ; Current command number ; Uninitialized revnum ds 1 ; Revision # stksav ds 2 ; Old stack pointer usr ds 1 ; User number filebuf ds 2 ; File buffer pointer fileptr ds 2 ; Installation pointer patptr ds 2 ; Patching pointer cmd_list ds 2 ; Start of command list end