home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1993 May
/
SIMTEL_0593.ISO
/
msdos
/
sysutl
/
u.asm
< prev
next >
Wrap
Assembly Source File
|
1989-01-03
|
18KB
|
402 lines
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