home *** CD-ROM | disk | FTP | other *** search
- Date: Sunday, 1 January 1989 11:43-MST
- From: <MULTI%TRIUMFCL.BITNET@CORNELLC.CIT.CORNELL.EDU>
- Re: TSR program that "unhooks" itself, see Issues 49,57 of 1988 digest
-
- Title U
- Page 80,132
- BUFLEN =64 ; Length of command save
- ;DBG =1 ; Define for printout
- GUARD =0 ; Length of guard band
- INTDOS =21h*4 ; Address of DOS vector
- PSPOFF =5Ch ; PSP above here overlaid
- RELOC =100h-PSPOFF ; Distance code shuffled
- ;
- .SFCOND ; Suppress false conditionals
- ;
- Code Segment
- ORG 100h
- Assume cs:code,ds:code
- start label byte
- count: jmp u ; Command being recalled
- punt: db 0EAh ; Far jump to DOS
- chain dw 2 dup(?) ; ...int 21h entry
- ;
- begin: cmp ah,0Ah ; Buffered keyboard input request?
- jne punt ; ...no, pass to DOS
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push es
- push ds
- pop es
- mov di,dx ; DS:DI --> user's buffer
- inc di ; Skip maximum byte count
- inc di ; Skip returned byte count
- mov bx,dx ; Load into index register
- cld ; Strings advance forwards
- retry: mov byte ptr [bx]+1,0 ; Zero returned byte count
- ;
- loop: call in ; Read char into AL reg
- loop1: cmp al,0Dh ; Entry process char in AL reg
- je done
- or al,al ; Function key?
- je f_key ; ...begins with null
- cmp al,"H"-64 ; Backspace
- je erase
- cmp al,"U"-64 ; ^U
- je erall
- cmp al,27 ; Escape
- je erall
- mov dx,[bx] ; Get both byte counts
- cmp dh,dl ; ...full if equal
- je bell ; ...ignore,bell if so
- stosb ; Save character
- call echo ; ...echo it
- cmp byte ptr [di]-1,"C"-64 ; ^C character
- je break ; ...causes interrupt
- inc byte ptr [bx]+1 ; End of checking, accept char.
- jmp loop ; ...back for more
- ;
- f_key: call in ; AL contains 2nd char
- or al,al ; Zero is break
- je break
- cmp al,61 ; F3 = Function Recall
- je recal
- cmp al,72 ; Cursor up,, same thing
- je recal
- cmp al,65 ; F7 = Function Recall Backwards
- je rbc
- cmp al,80 ; Cursor Down, same thing
- je rbc
- cmp al,64 ; F6 = Control-Z
- je ctrl_z
- jmp loop ; Ignore the remainder
- ;
- ctrl_z: mov al,"Z"-64 ; F6 is Control-Z
- jmp loop1 ; ...pretend from keyboard
- ;
- recal: jmp recall
- rbc: jmp rbck
- ;
- break: int 23h ; Control_Break
- call crlf ; ...as per documentation
- jnc retry ; ...carry clear, retry
- mov ax,4C00h ; Else do a kosher terminate
- int 21h ; ...do not know his PSP
- ;
- done: stosb ; Success, save 0Dh terminator
- call store ; Store the command
- pop es ; Done, restore reg. and exit
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- iret
- ;
- erase: call delete
- jmp loop
- ;
- erall: call delete
- cmp Byte ptr [bx]+1,0
- jne erall
- jmp loop
- ;
- bell: mov al,7
- call out
- jmp loop
- ;
- recall: call delete ; Attempt to delete char.
- cmp Byte ptr [bx+1],0 ; ...any left to delete
- jne recall ; ...yes, loop around
- ;
- push ds ; Save user's DS
- push bx ; ...and BX reg
- push cs ; Make DS the same
- pop ds ; ...as code seg
- ;
- xor bx,bx ; Go to start of buffer
- mov dx,word ptr count-RELOC ; DX is count of comands
- inc word ptr count-RELOC ; One more in stack
- ;
- rec0: dec dx ; This command
- je extrct ; ...yes
- ;
- mov cl,[save-RELOC+bx] ; Get saved byte count
- mov ch,0 ; ...make word
- jcxz rec90 ; End of commands
- inc cx ; ...skip past char count
- add bx,cx ; ...and string
- cmp bx,BUFLEN ; Buffer overflowed
- jae rec90
- jmp rec0 ; ...and continue
-
- rec90: xor bx,bx ; Back to start of buffer
- mov word ptr count-RELOC,2 ; Say one command there
- extrct: mov cl,[save-RELOC+bx] ; ...get char count
- mov ch,0 ; ...be safe
- lea si,[save+1-RELOC+bx] ; ds:SI --> input buffer
- inc bx ; Add in character counter
- add bx,cx ; Length of line
- cmp bx,BUFLEN ; ...will it fit?
- jae rec90 ; ...no, so restart
- pop bx
- cmp cl,es:[bx] ; Compare with new buffer
- jbe fit ; ...will fit
- mov cl,es:[bx] ; ...copy what will fit
- fit: mov es:[bx]+1,cl ; Get saved byte count
- jcxz nul ; ...all done
- lea di,[bx]+2 ; ES:DI --> user buffer
- ;
- l: lodsb ; Load AL from input buffer
- stosb ; Dump AL into output buffer
- call echo ; Echo AL on print screen
- loop l ; ...loop until CX=0
- ;
- nil: pop ds ; Restore user's DS
- jmp loop ; ...back for more
- ;
- nul: cmp save-RELOC,0 ; Buffer really empty?
- je nil ; ...yes, nothing to recall
- push bx ; Else save BX
- jmp rec90 ; ...EOB, go back to start
- ;
- rbck: sub word ptr cs:count-RELOC,2; Back two commands
- jle toofar
- bckr: jmp recall ; ...and recall
- toofar: push ds ; Must scan for the
- push bx ; ...end of buffer
- push cs ; Make DS the same
- pop ds ; ...as code seg.
- xor bx,bx ; Beginning of buffer
- mov word ptr count-RELOC,0 ; Start at command 0
- bck1: mov cl,[save-RELOC+bx] ; Get saved byte count
- mov ch,0 ; ...be safe
- jcxz bck90 ; Not very nice, null string
- inc cx ; Include char. count
- add bx,cx ; Now point at next string
- cmp bx,BUFLEN ; Buffer overflowed
- jae bck90 ; Not very nice
- inc word ptr count-RELOC ; Another kosher stored command
- jmp bck1
- ;
- bck90: cmp word ptr count-RELOC,0 ; Too small?
- ja bck91 ; ...no
- mov word ptr count-RELOC,1 ; Must have one command
- bck91: pop bx ; Got our answer
- pop ds ; ...restore
- jmp bckr ; Go to find command routine
- ;
- delete: cmp Byte ptr [bx]+1,0 ; Anything to delete
- je delret ; ...no, then nop
- dec di ; Back up pointer
- mov al,[di] ; ...AL has char
- dec Byte ptr [bx]+1 ; One less in buffer
- mov cx,1 ; Assume takes one print pos.
- cmp al," " ; ...space and above OK
- jae norm ; ...blank out one position
- inc cx ; Control char blank out two
- ;
- norm: mov al,"H"-64 ; Backspace over char.
- call out ; ...print backspace
- mov al," " ; Destructive overprint
- call out ; ...print space
- mov al,"H"-64 ; Backspace to one before
- call out ; ...print backspace
- loop norm ; Destroy one or two char.
- delret: ret ; ...all done
- ;
- in: mov ah,7 ; Read/no echo
- int 21h ; AL contains char
- ret ; ...back to user
- ;
- out: push dx ; Save register
- mov dl,al ; Get character to print
- mov ah,2 ; ...on print screen
- int 21h ; ...do DOS call supposed
- pop dx ; ...restore reg.
- ret ; ...to check for break
- ;
- echo: cmp al,32 ; Char in AL destroyed
- jae nocntl ; ...is space or above
- push ax ; Else save a copy
- mov al,"^" ; ...print ^ arrow
- call out ; ...this way
- pop ax ; Restore char in AL
- add al,"A"-1 ; ...map control to letter
- nocntl: call out ; Print the character
- ret ; ...back to DOS
- ;
-
- store: mov cl,[bx]+1 ; Char. count for new command
- mov ch,0 ; ...null hi order
- jcxz null ; ...no command
- inc cx ; ...include Count in string
- cmp cx,BUFLEN ; String too long
- ja null ; ...yes, don't save
- push cx ; ...save a copy
- neg cx ; ...negate length
- lea di,save+BUFLEN-RELOC-1 ; Source for shuffle
- lea si,save+BUFLEN-RELOC-1 ; Target for shuffle
- add si,cx ; ...back up source
- add cx,BUFLEN ; ...size of buffer to shuffle
- js null ; ...too big
- push ds ; Save old DS segment
- push cs
- pop ds ; DS = CS
- push cs
- pop es ; ES = CS
- std ; ...shuffle backwards
- ;
- rep movsb ; ...push old commands
- mov word ptr count-RELOC,1 ; ...reset buffer pointer
- ;
- pop ds ; Restore data segment
- pop cx ; Restore line length
- lea si,[bx]+1 ; Get address of counted line
- lea di,save-RELOC ; ES:DI --> Save buffer
- cld ; ...save forwards
- rep movsb ; ...save into local buffer
- Ifdef DEB
- call debug ; *** DEBUG ***
- endif
- null: ret ; ...back to caller
- ;
- crlf: push ax
- mov al,13
- call out
- mov al,10
- call out
- pop ax
- ret
- ;
- Ifdef DEB
- number: push ax
- push cx
- mov cx,4
- num: rol bp,1
- rol bp,1
- rol bp,1
- rol bp,1
- mov ax,bp
- and ax,0Fh
- add ax,"0"
- cmp ax,"9"
- jbe num1
- add ax,"A"-"9"-1
- num1: call out
- loop num
- pop cx
- pop ax
- ret
- ;
- debug: push ax
- push bx
- push ds
- push cs
- pop ds
- xor bx,bx
- deb0: test bx,63
- jne deb1
- call crlf
- mov bp,cs
- call number
- mov al,":"
- call out
- lea bp,[save-RELOC+bx]
- call number
- mov al," "
- call out
- deb1: mov al,[save-RELOC+bx]
- inc bx
- cmp al," "
- jae deb2
- mov al,"."
- deb2: call out
- cmp bx,BUFLEN+GUARD ; *** DEBUG ***
- jb deb0
- pop ds
- pop bx
- pop ax
- ret
- Endif
- ;
- impure label byte ; End of area to check for install
- ;
- save db ? ; Token null for buffer
- ;
- quit label byte ; End of permanent region
- ;
- u: xor dx,dx ; Get vector segment
- mov es,dx ; ...and load into ES
- lds si,dword ptr es:INTDOS ; DS:SI --> DOS interrupt routine
- mov cx,offset impure-begin ; ...this is pure code to compare
- push cs ; Save code segment
- pop es ; ES same as code seg.
- lea di,begin ; ES:DI --> our interrupt service
- rep cmpsb ; Are they the same?
- push cs ; Set data segment same as
- pop ds ; the code segment
- jz remove ; ...code compares, remove
- ;
- lea si,start ; DS:SI --> Code segment
- mov di,PSPOFF ; ES:DI --> Where relocates to
- mov cx,offset quit-start ; CX = bytes to relocate
- rep movsb ; ...shuffle section down
- ;
- mov ds,dx ; Reload vector segment
- mov si,INTDOS ; DS:SI --> DOS vector
- lea di,chain-RELOC ; ES:DI --> JMPF address
- movsw ; Move the offset
- movsw ; Move the segment
- push cs ; Equivalence code and
- pop ds ; ...data segments
- mov es,dx ; ES:DI --> DOS vector
- mov di,INTDOS
- lea ax,begin-RELOC ; AX is entry offset
- stosw ; ...store as DOS vector
- mov ax,cs ; CS is entry segment
- stosw ; ...store as DOS vector
- ;
- mov word ptr count-RELOC,1 ; ...reset count
- ;
- lea dx,msg1 ; Say editor installed
- mov ah,9h ; ...print string
- int 21h ; ...like so
- ;
- push ds:2Ch ; Get environ. segment
- pop es ; ...into ES register
- mov ah,49h ; ...then free
- int 21h ; ...the memory
- ;
- lea dx,save+BUFLEN-RELOC ; Last address to save
- int 27h ; ...terminate, stay resident
- ;
- remove: lea dx,msg2 ; Code already was installed
- mov ah,9h ; ...print string
- int 21h ; ...is function
- xor dx,dx ; Point to vector area
- mov es,dx ; ...to restore DOS
- lds si,dword ptr es:INTDOS ; Get saved dos interrupt
- mov di,INTDOS+4 ; Where to restore old DOS entry
- std ; ...copy backwards
- cmpsw ; Backspace SI and DI
- movsw ; ...restore segment
- movsw ; ...restore offset
- mov bx,ds ; Get PSP of stored program
- dec bx ; BX --> storage block
- mov ds,bx ; DS --> storage block
- mov word ptr ds:1,0 ; This deletes the PSP
- ret ; ...back to caller
- ;
- msg1: db "[Editor Installed]$" ; Hooked to DOS, resident
- msg2: db "[Editor Removed]$" ; Unhooked, gone from memory
- ;
- code ends
- ;
- End count
-