Category : Assembly Language Source Code
Archive   : TSR21.ZIP

Output of file : TSRDOSED.ASM contained in archive : TSR21.ZIP
comment \
Function Edits DOS command line (int 21-0A)
Author Robert Wagner
Date Written 09/15/87
Comment Inspired by DOSEDIT by J. Gernsbach

XSEG segment
db 'TSRDOSED 1.0, '
db 'Public Domain 1987 by Robert Wagner, '
db 'Software Lubbock, '
db '1500 Broadway (#1208), '
db 'Lubbock, Tx 79401 '
db '806-744-9940 (w), 806-745-5309 (h)'
XSEG ends

DSEG segment
tsr_struc db 'TSRDOSED' ; structure for communicating with TSR
tsr_current_ecb db 0 ; ecb
tsr_dispat_ecb db 0 ; ecb when dispatched
tsr_hotkeys db 0,0 ; hotkeys
tsr_entrypoint dd 0 ; entry point
tsr_emergency dd 0 ; entry point for emergency shutdown
tsr_comm_area dd 0 ; points to communication area
tsr_int_area dd intarray ; points to interrupt area
tsr_psp dw 0 ; psp of the task
tsr_screen dw 0 ; B000 or B800
tsr_screen_save dw 0 ; segment of screen save area
tsr_passthru db 0 ; if not 0, passthru
db 31 dup(0) ; 31 bytes for internal use

keytab dw 0006h,no_operation ; ack ; table of keys that require
dw 0008h,backspace_key ; bsp ; special handling
dw 000Dh,cr_key ; cr
dw 001Bh,escape_key ; esc
dw 4700h,home_key ; Home key
upk dw 4800h,up_arrow ; Up arrow
dw 4b00h,left_arrow ; Left arrow
dw 4d00h,right_arrow ; Right arrow
dw 4f00h,end_key ; End key
downk dw 5000h,down_arrow ; Down Arrow
dw 5300h,del_key ; Del key
dw 7500h,ctrl_end ; Ctrl End
number_of_keys equ ($ - keytab) / 4
keytab_end label word

buffer_pointer dw buffer ; points to current entry
buffer_limit dw buffer ; points to last valid byte
buffer db 512 dup(0) ; this is where I store prev commands
buffer_end label byte
DSEG ends

LSEG segment at 0
lseg_start label byte ; in order to make me re-entrant,
length_string_ss dw ? ; all my local variables are on the stack
index_string_ss dw ?
max_string_ss dw ?
pointer_to_screen_ss dw ?
screen_mode_ss db ? ; 7 = mono, else = cga
flags_ss db ?
insert_on equ 10000000b
arrow_failed equ 00000001b
any_key equ 00000010b
task_type_ss db 0 ; FEh for application, FFh for command
db 0 ; to pad to an even number of bytes
length_string equ length_string_ss[bp]
index_string equ index_string_ss[bp]
max_string equ max_string_ss[bp]
pointer_to_screen equ pointer_to_screen_ss[bp]
screen_mode equ screen_mode_ss[bp]
flags equ flags_ss[bp]
task_type equ task_type_ss[bp]
number_of_variables equ ($ - lseg_start) / 2
LSEG ends

CSEG segment
intarray dw 1 ; this tells TSR to intercept int 21
dw 21h
dd int21
int21a dd 0

assume cs:CSEG,ds:DSEG,ss:LSEG
int21 proc far ; my entry point
cmp ah,0Ah ; Is this function 0A?
je doit ; Nope, passthru
jmp dword ptr int21a

doit: sti
call pusha
call tsrdosed
call popa
mov al,0
int21 endp

tsrdosed proc near
xor ax,ax
mov cx,number_of_variables
main1: push ax ; initialize local variables
loop main1
mov bp,sp ; point to local variables
mov ax,ds ; move string pointer ds:dx to es:di
mov es,ax
mov di,dx
add di,2
mov length_string,-1
mov ax,DSEG ; initialize ds
mov ds,ax
mov ax,2003h ; clear the DOSbusy flag (in case Ctrl-Brk
int 2Fh ; left an int 21-08 hanging)
call get_task_type

mov al,es:[di-2]
xor ah,ah
dec ax
mov max_string,ax ; maximum size of his buffer
call get_screen_stuff
call display_cursor
call read_a_key
cmp dx,downk
je main2
cmp dx,upk
je main2
or flags,any_key
main2: xor bx,bx ; Set starting address of table 1
mov cx,number_of_keys ; Set counter to number of items in table 1
look1: cmp dx,keytab[bx]
je look2
add bx,4
loop look1
or dl,dl
jz main_line
call normal_keyboard_char
jmp main_line
look2: call keytab+2[bx]
jmp main_line
mainx: call move_string_to_buffer ; comes here on Cr
call remove_hats
mov ax,length_string ; place length into string
mov es:[di-1],al
add sp,number_of_variables * 2 ; discard local variables
tsrdosed endp

normal_keyboard_char proc near
test flags,insert_on
jz norm1
call make_a_hole
norm1: call deposit_dl_in_string
inc index_string
normal_keyboard_char endp

deposit_dl_in_string proc near
mov bx,index_string
cmp bx,max_string
jge nogo
cmp bx,length_string
jle deph1
mov length_string,bx
deph1: cmp dl,' ' ; insert hat if necessary
jae deph2
cmp dl,0Dh
je deph2
mov dh,dl
mov dl,'^'
mov es:[di][bx],dl
mov ah,2
int 21h
inc index_string
mov dl,dh
add dl,64
jmp deposit_dl_in_string
deph2: mov es:[di][bx],dl
mov ah,2
int 21h
jmp short dephx
nogo: mov ah,2
mov dl,7
int 21h
dephx: ret
deposit_dl_in_string endp

cr_key proc near
call end_key
inc max_string
call deposit_dl_in_string
pop ax ; discard my return
jmp mainx
cr_key endp

no_operation proc near
no_operation endp

backspace_key proc near
call left_arrow
call display_cursor
call del_key
backspace_key endp

escape_key proc near
call home_key
call display_cursor
call ctrl_end
call display_cursor
escape_key endp

left_arrow proc near
cmp index_string,0
je leftx
dec index_string
leftx: ret
left_arrow endp

right_arrow proc near
mov ax,length_string
inc ax
cmp index_string,ax
jge rightx
inc index_string
rightx: ret
right_arrow endp

home_key proc near
mov index_string,0
home_key endp

end_key proc near
mov ax,length_string
inc ax
mov index_string,ax
end_key endp

ctrl_end proc near
mov cx,length_string
sub cx,index_string
add cx,1
jle ctrlex
push index_string
mov dl,' '
ctrle1: call deposit_dl_in_string
inc index_string
loop ctrle1
pop index_string
mov ax,index_string
dec ax
mov length_string,ax
ctrlex: ret
ctrl_end endp

del_key proc near
push index_string
mov cx,length_string
sub cx,index_string
jle del2
del1: mov bx,index_string
mov dl,es:[di][bx+1]
call deposit_dl_in_string
inc index_string
loop del1
del2: call ctrl_end
pop index_string
delx: ret
del_key endp

make_a_hole proc near ; insert key is on
mov cx,length_string ; shift string right one byte
sub cx,index_string
add cx,1
jle holex
push dx
push index_string
mov bx,length_string
inc bx
mov index_string,bx
hole1: push cx
call display_cursor
mov bx,index_string
mov dl,es:[di][bx-1]
call deposit_dl_in_string
dec index_string
pop cx
loop hole1
pop index_string
call display_cursor
pop dx
holex: ret
make_a_hole endp

up_arrow proc near
call escape_key
call backward_buffer
call move_buffer_to_string
up_arrow endp

down_arrow proc near
call escape_key
mov al,flags
and flags,not arrow_failed
test al,any_key or arrow_failed
jnz down1
call forward_buffer
down1: call move_buffer_to_string
down_arrow endp

read_a_key proc near
xor dx,dx
mov ah,8
int 21h
or dl,al
jnz readkx
mov ah,8
int 21h
or dh,al
readkx: ret
read_a_key endp

display_cursor proc near
mov ah,2 ; get shift keys
int 16h
and flags,not insert_on
or flags,al
test al,10000000b
jnz big_cursor
normal_cursor: ; set cursor size to normal
mov cx,0B0Ch
cmp screen_mode,7
je setc1
mov cx,0607h
setc1: jmp short setc2
big_cursor: ; set cursor size to enlarged
mov cx,060Ch
cmp screen_mode,7
je setc2
mov cx,0407h
setc2: mov ah,1
int 10h ; call BIOS to set cursor size
mov dx,pointer_to_screen
add dx,index_string
xor bh,bh
mov ah,2
int 10h ; call BIOS to position cursor
display_cursor endp

get_screen_stuff proc near
xor bh,bh
mov ah,3
int 10h ; Read cursor position and shape
mov pointer_to_screen,dx ; dh = line, dl = col
mov ah,0Fh
int 10h ; read mode
mov screen_mode,al
get_screen_stuff endp

forward_buffer proc near ; go to next buffer entry
or flags,arrow_failed
mov bh,task_type
mov si,buffer_pointer
fwd1: cmp si,buffer_limit
ja fwdx
cmp byte ptr ds:[si],0FEh ; make sure it's a valid entry
jb fwdx
mov al,ds:[si+1] ; go on to the next entry
xor ah,ah
add si,ax
cmp ds:[si],bh ; check its type
jne fwd1 ; NOTD (not our type dear)
and flags,not arrow_failed
fwdx: mov buffer_pointer,si
forward_buffer endp

backward_buffer proc near ; go to previous buffer entry
or flags,arrow_failed
mov bh,task_type
mov si,buffer_pointer
bkw1: cmp si,offset buffer
jbe bkwx
dec si
cmp ds:[si],bh
jne bkw1
and flags,not arrow_failed
bkwx: mov buffer_pointer,si
backward_buffer endp

move_buffer_to_string proc near ; copy buffer entry into string
test flags,arrow_failed
jnz outputx
mov si,buffer_pointer
cmp al,task_type
jne outputx
xor ah,ah
mov cx,ax
sub cx,2
output1: lodsb
mov dl,al
call deposit_dl_in_string
inc index_string
loop output1
and flags,not any_key
outputx: ret
move_buffer_to_string endp

move_string_to_buffer proc near ; copy string into buffer
push es
push di
mov ax,2004 ; turn off TSR
mov bl,1
int 2Fh
mov dx,length_string ; length of new guy
add dx,2
mov si,buffer_pointer
move1: call delete_buffer ; delete one string (current or first)
lea si,buffer
lea cx,buffer_end-1
sub cx,buffer_limit
cmp dx,cx ; see if room available (leave 1 on end)
jge move1 ; if not go delete entry 1
cmp dx,2 ; do not store null strings
jle move2
call insert_buffer ; insert it
call forward_buffer ; make next entry the current one
move2: mov ax,2004 ; turn on TSR
mov bl,-1
int 2Fh
pop di
pop es
movex: ret
move_string_to_buffer endp

delete_buffer proc near
cmp byte ptr ds:[si],0FEh ; make sure it's a string
jb delex
mov al,ds:[si+1] ; get its length
xor ah,ah
push ds
pop es
mov di,si ; point to string about to be deleted
mov bx,si ; remember where it was
add si,ax ; point to the next string
mov cx,buffer_limit ; calculate length of move
sub cx,si
add cx,1
jle delex
rep movsb ; shift tail end of buffer to delete string
dec di
mov buffer_limit,di ; di is new limit
cmp buffer_pointer,bx ; if pointer is below this point
jbe delex ; move it left so it still points at
sub buffer_pointer,ax ; the same string
delex: ret
delete_buffer endp

insert_buffer proc near
push ds
pop es
mov si,buffer_limit ; point to end of buffer (sending)
mov di,si ; receiving = sending + size of insert
add di,dx
mov buffer_limit,di
mov cx,si ; compute length
sub cx,buffer_pointer
add cx,1
jle insert1
rep movsb ; shift tail end of buffer
insert1: mov di,buffer_pointer ; get receiving
mov al,task_type ; store type
mov al,dl ; store length
push ds
push bp
mov bp,sp
mov si,ss:[bp+6] ; get sending
mov ds,ss:[bp+8]
mov cx,dx ; get length
sub cx,2
rep movsb ; move string to buffer
pop bp
pop ds
insert_buffer endp

remove_hats proc near
push di
mov si,di
mov cx,length_string
inc cx
hats1: lods byte ptr es:[si]
cmp al,'^'
jne hats2
cmp cx,2
jle hats2
dec length_string
dec cx
lods byte ptr es:[si]
sub al,64
hats2: stosb
loop hats1
pop di
remove_hats endp

get_task_type proc near
push es
mov task_type,0FFh
mov ah,51h ; get psp of current task
int 21h
mov es,bx
cmp byte ptr es:[0],0CDh ; make sure it's a program
jne gettx
cmp bx,es:[16h] ; is it its own parent?
je gettx ; y - it's DOS (primary or secondary)
mov task_type,0FEh ; n - it's an application
gettx: pop es
get_task_type endp

pusha proc near ; push all the registers
push bx
push cx
push dx
push ds
push si
push es
push di
push bp
push ax
push bp
mov bp,sp
xchg ax,ss:[bp+20]
xchg ax,ss:[bp+2]
pop bp ; recover bp
pusha endp

popa proc near ; pop all the registers
pop ax ; return address
mov bp,sp
xchg ax,ss:[bp+16]
pop bp
pop di
pop es
pop si
pop ds
pop dx
pop cx
pop bx
popa endp

CSEG ends ; end of resident program

RSEG segment memory 'himem'
okmsg db 'TSRDOSED 1.0 resident.',13,10,'$'
badmsg db 'TSRDOSED not resident.',13,10,'$'

assume cs:RSEG,ds:DSEG
makeres proc far ; make myself resident
mov ax,DSEG
mov ds,ax
mov tsr_psp,es
mov bx,seg EOM
sub bx,tsr_psp
mov ah,4Ah ; release memory I'm not using
int 21h

lea si,tsr_struc ; setup params for TSR
mov ax,2001h ; log onto TSR
int 2Fh
cmp al,0FFh ; make sure TSR was there
jne stop_run

lea dx,okmsg
call display
mov dx,RSEG
sub dx,tsr_psp
mov ax,3100h ; ---- terminate and stay resident ----
int 21h
makeres endp

stop_run proc near
lea dx,badmsg
call display
mov ax,4CFFh ; error termination
int 21h
stop_run endp

display proc near ; displays a line (via DOS)

push ds
push cs
pop ds
mov ah,9
int 21h
pop ds
display endp
RSEG ends

SSEG segment stack 'himem'
dw 128 dup(?)
SSEG ends

EOM segment memory 'himem'
EOM ends
end makeres

  3 Responses to “Category : Assembly Language Source Code
Archive   : TSR21.ZIP

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: