home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
PROGRAM
/
C
/
AMISL082
/
NOTE.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-04-20
|
21KB
|
876 lines
;-----------------------------------------------------------------------
; NOTE.ASM Public Domain 1992 Ralf Brown
; You may do with this software whatever you want, but
; common courtesy dictates that you not remove my name
; from it.
;
; Popup to append one or more lines to a text file. Demonstration of the
; use of DOS from within an AMIS-compliant TSR.
; Note: popup may be done from the commandline or via a hotkey; however,
; the hotkey support requires a newer BIOS which has the INT 15/4F
; keyboard intercept
;
; Version 0.81
; LastEdit: 4/20/92
;-----------------------------------------------------------------------
__TINY__ equ 1 ; using Tiny model
INCLUDE AMIS.MAC
;-----------------------------------------------------------------------
;
VERSION_NUM equ 0051h ; v0.81
VERSION_STR equ "0.81"
WINDOW_TOP equ 0 ; topmost row of TSR's popup window
WINDOW_LEFT equ 5 ; leftmost column of TSR's popup window
WINDOW_HEIGHT equ 3 ; height (including frame) of popup window
WINDOW_WIDTH equ 70 ; width (including frame) of popup window
LOCAL_STACK_SIZE equ 128 ; size of local stack in bytes
HOTKEY_SCAN equ 31h ; scan code for 'N' key
HOTKEY_NAME equ "N"
;-----------------------------------------------------------------------
; Declare our segments in the order we want them in the executable.
;
_TEXT SEGMENT PUBLIC BYTE 'CODE'
_TEXT ENDS
TSRgroup@
;-----------------------------------------------------------------------
; Put the resident code into its own segment so that all the offsets are
; proper for the new location after copying it into a UMB or down into
; the PSP.
;
TSRcode@
start_TSRcode label byte
;-----------------------------------------------------------------------
; Since we need a TSR, but might be loaded into a UMB or at the top of
; conventional memory, we make a copy of the all-important first 64 bytes
; of the PSP here. After relocation, this copy will start at offset 0
;
TSR_PSP db 64 dup (?)
;-----------------------------------------------------------------------
; TSR's initialized data storage
;
TSRdata@
TSR_name db "NOTE",0
int13_busy db 0
want_popup db 0
want_shutdown db 0
TSR_activated db 0
popup_INT28 db 0
;;; add TSR-specific initialized data below
CRLF_buffer db 13,10
TSRdataEnd@
;-----------------------------------------------------------------------
; TSR's uninitialized data storage
;
TSRbss@
INDOS_ptr dd ?
CRITERR_ptr dd ?
interrupted_DTA dd ?
interrupted_PSP dw ?
interrupted_SP dw ?
interrupted_SS dw ?
interrupted_cursorpos dw ?
display_page_attr label word
display_attr db ?
display_page db ?
screen_width db ?
cursor_pos label word
cursor_x db ?
cursor_y db ?
screen_buffer db (WINDOW_HEIGHT*WINDOW_WIDTH*2) dup (?)
local_stack db LOCAL_STACK_SIZE dup (?)
local_stack_bottom label byte
;;; add TSR-specific uninitialized data below
notefile_handle dw ?
edit_buffer db WINDOW_WIDTH-2 dup (?)
TSRbssEnd@
;-----------------------------------------------------------------------
TSR_main proc near
ASSUME DS:TGROUP,ES:NOTHING
xor si,si ; SI stores line length
TSR_main_loop:
mov dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
add dx,si
call TSR_move_cursor
call TSR_getkey
cmp al,0Dh ; Enter pressed?
je TSR_main_line_end
cmp al,27 ; Esc pressed?
je TSR_main_done
cmp al,8
je backspace
cmp al,0 ; extended ASCII?
je TSR_main_loop ; if yes, ignore
cmp al,0E0h
jne got_char
cmp ah,0
jne TSR_main_loop
got_char:
cmp si,WINDOW_WIDTH-2
jb store_char
beep:
mov ax,0E07h ; beep
int 10h
jmp TSR_main_loop
store_char:
mov edit_buffer[si],al
inc si ; remember that we got another char
call TSR_put_char
jmp TSR_main_loop
backspace:
or si,si
jz beep
dec si
mov dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
add dx,si
call TSR_move_cursor
mov al,' '
call TSR_put_char
jmp TSR_main_loop
TSR_main_line_end:
mov ah,40h
mov bx,notefile_handle
mov cx,si
mov dx,offset TGROUP:edit_buffer
int 21h
mov ah,40h
mov cx,2
mov dx,offset TGROUP:CRLF_buffer
int 21h
call TSR_clear_window
jmp TSR_main ; restart for next line
TSR_main_done:
mov bx,notefile_handle
mov ah,45h ; DUP handle
int 21h
jc TSR_main_exit ; quit now if unable to duplicate
mov bx,ax
mov ah,3Eh ; close duplicate
int 21h
TSR_main_exit:
ret
TSR_main endp
;-----------------------------------------------------------------------
; Function that performs any necessary cleanup prior to the TSR being
; removed from memory. At the time it is called, the TSR is effectively
; popped up, though it has not modified the screen. If this routine needs
; to write on the screen, it must save and restore the screen contents
; itself
;
TSR_shutdown proc near
mov bx,notefile_handle
mov ah,3Eh ; close the file
int 21h
ret
TSR_shutdown endp
;-----------------------------------------------------------------------
TSR_INT24_handler:
mov al,03h ; FAIL, for now
iret
;-----------------------------------------------------------------------
; Simply ignore Ctrl-Break and Ctrl-C interrupts
;
TSR_INT1B_handler:
TSR_INT23_handler:
iret
;=======================================================================
; It should not be necessary to make any changes between here and the
; end of the resident portion in order to modify this code for a different
; purpose.
;=======================================================================
;-----------------------------------------------------------------------
;
TSR_getkey proc near
mov ah,11h ; keystroke available?
int 16h
jnz TSR_getkey_got_one ; if yes, get it, otherwise
int 28h ; give other TSRs a chance to do work
jmp TSR_getkey
TSR_getkey_got_one:
mov ah,10h ; get the keystroke
int 16h
ret
TSR_getkey endp
;-----------------------------------------------------------------------
; entry: DH = row, DL = column
;
TSR_move_cursor proc near
ASSUME DS:TGROUP,ES:NOTHING
mov cursor_pos,dx
mov bh,display_page
mov ah,2 ; BIOS move-cursor function
int 10h
ret
TSR_move_cursor endp
;-----------------------------------------------------------------------
; entry: AL = char
; exit: AH,BX,CX,DX destroyed
;
TSR_put_char proc near
mov cx,1
;; fall through to TSR_put_line
TSR_put_char endp
;-----------------------------------------------------------------------
; entry: AL = char, CX = repeat count
; exit: AX,BX,CX,DX destroyed
;
TSR_put_line proc near
ASSUME DS:TGROUP,ES:NOTHING
add cursor_x,cl
mov bx,display_page_attr
mov ah,9
int 10h
mov al,cursor_x
cmp al,screen_width
jb TSR_put_line_done
mov cursor_x,0
inc cursor_y
;
; need to handle case of falling off the bottom
;
TSR_put_line_done:
mov dx,cursor_pos
mov ah,2 ; set cursor position
int 10h
ret
TSR_put_line endp
;-----------------------------------------------------------------------
save_screen proc near
ASSUME DS:TGROUP,ES:NOTHING
mov ah,0Fh
int 10h ; get video mode and active page
mov display_page,bh
mov screen_width,ah
mov ah,3 ; get cursor position on page BH
int 10h
mov interrupted_cursorpos,dx
push ds
pop es
ASSUME ES:TGROUP
mov di,offset TGROUP:screen_buffer
mov dh,WINDOW_TOP
save_screen_loop1:
mov dl,WINDOW_LEFT
save_screen_loop2:
mov ah,2 ; set cursor position on page BH
int 10h
mov ah,8 ; read character&attribute on page BH
int 10h
stosw ; and remember them for later restore
inc dl
cmp dl,WINDOW_LEFT+WINDOW_WIDTH
jb save_screen_loop2
inc dh
cmp dh,WINDOW_TOP+WINDOW_HEIGHT
jb save_screen_loop1
ret
save_screen endp
;-----------------------------------------------------------------------
framed_window proc near
ASSUME DS:TGROUP,ES:NOTHING
mov dx,256*WINDOW_TOP + WINDOW_LEFT
call TSR_move_cursor
mov display_attr,0Fh ; bright white on black
mov al,201 ; double upper left corner
call TSR_put_char
mov cx,WINDOW_WIDTH-2
mov al,205
call TSR_put_line
mov al,187 ; double upper right corner
call TSR_put_char
push si
mov dx,256*(WINDOW_TOP+1) + WINDOW_LEFT
frame_loop:
mov si,dx
call TSR_move_cursor
mov al,186 ; double vertical bar
call TSR_put_char
mov dx,si
mov dl,WINDOW_LEFT+WINDOW_WIDTH-1
call TSR_move_cursor
mov al,186 ; double vertical bar
call TSR_put_char
mov dx,si
inc dh
cmp dh,WINDOW_TOP+WINDOW_HEIGHT-1
jb frame_loop
pop si
mov dx,256*(WINDOW_TOP+WINDOW_HEIGHT-1) + WINDOW_LEFT
call TSR_move_cursor
mov display_attr,0Fh ; bright white on black
mov al,200 ; double lower left corner
call TSR_put_char
mov cx,WINDOW_WIDTH-2
mov al,205
call TSR_put_line
mov al,188 ; double lower right corner
call TSR_put_char
;
; frame is done, now add the title
;
mov dx,256*WINDOW_TOP + (WINDOW_LEFT+2)
call TSR_move_cursor
mov si,offset TGROUP:TSR_name
frame_name_loop:
lodsb
or al,al
jz frame_name_done
call TSR_put_char
jmp frame_name_loop
frame_name_done:
mov dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
call TSR_move_cursor
mov display_attr,07h ; dim white on black
;; fall through to TSR_clear_window ;;
framed_window endp
;-----------------------------------------------------------------------
TSR_clear_window proc near
mov bh,display_attr
mov cx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
mov dx,256*(WINDOW_TOP+WINDOW_HEIGHT-2) + (WINDOW_LEFT+WINDOW_WIDTH-2)
mov ax,0600h ; clear popup window area
int 10h
ret
TSR_clear_window endp
;-----------------------------------------------------------------------
restore_screen proc near
ASSUME DS:TGROUP,ES:NOTHING
mov si,offset TGROUP:screen_buffer
mov dh,WINDOW_TOP
rest_screen_loop1:
mov dl,WINDOW_LEFT
rest_screen_loop2:
mov ah,2
mov bh,display_page
int 10h ; set cursor position
lodsw ; get character and attribute to restore
mov bl,ah ; BL <- attribute
mov cx,1
mov ah,9 ; write character&attribute
int 10h
inc dl
cmp dl,WINDOW_LEFT+WINDOW_WIDTH
jb rest_screen_loop2
inc dh
cmp dh,WINDOW_TOP+WINDOW_HEIGHT
jb rest_screen_loop1
mov dx,interrupted_cursorpos
mov ah,2 ; restore cursor position
int 10h
ret
restore_screen endp
;-----------------------------------------------------------------------
; requires DS = TGROUP and interrupts enabled on entry; may destroy BX
;
popup proc near
mov want_popup,0 ; we are finally popping up
mov TSR_activated,1
;
; switch to a local stack so that we are assured of enough stack space
;
push ax
mov interrupted_SS,ss
mov interrupted_SP,sp
mov ax,cs
cli
mov ss,ax
ASSUME SS:TGROUP
mov sp,offset RESIDENT_CODE:local_stack_bottom
sti
push es
push di
push si
push bp
push dx
push cx
push bx
;
; switch to our own PSP and store current DTA
;
mov ah,51h
int 21h
mov interrupted_PSP,bx
mov bx,cs
mov ah,50h
int 21h
mov ah,2Fh ; get DTA
int 21h
ASSUME ES:NOTHING
mov word ptr interrupted_DTA,bx
mov word ptr interrupted_DTA+2,es
GRAB_INTERRUPT 1Bh,TSR_INT1B_handler
GRAB_INTERRUPT 23h,TSR_INT23_handler
GRAB_INTERRUPT 24h,TSR_INT24_handler
mov al,0
xchg al,want_shutdown ; get and clear shutdown flag
or al,al ; was it set?
jz do_popup ; if not, regular popup
call TSR_shutdown
jmp short popup_done
do_popup:
call save_screen
call framed_window
call TSR_main ; the actual guts of the TSR
call restore_screen
popup_done:
RESTORE_INTERRUPT 1Bh
RESTORE_INTERRUPT 23h
RESTORE_INTERRUPT 24h
;
; restore the original PSP and DTA
;
mov bx,interrupted_PSP
mov ah,50h
int 21h
push ds
lds dx,interrupted_DTA
ASSUME DS:NOTHING
mov ah,1Ah
int 21h
pop ds
ASSUME DS:TGROUP
pop bx
pop cx
pop dx
pop bp
pop si
pop di
pop es
;
; finally, switch back to original stack
;
cli
mov ss,interrupted_SS
ASSUME SS:NOTHING
mov sp,interrupted_SP
sti
mov TSR_activated,0 ; no longer popped up, so OK to pop again
pop ax
ret
popup endp
;-----------------------------------------------------------------------
attempt_popup proc near
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
mov want_popup,1 ; remember that a popup was requested
;; fall through to try_popup ;;
attempt_popup endp
try_popup proc near
pushf
sti ; OK to interrupt
cmp int13_busy,0
jnz try_popup_done
cmp TSR_activated,0
jnz try_popup_done
push ds
push bx
lds bx,INDOS_ptr
ASSUME DS:NOTHING
cmp byte ptr [bx],1
jb try_popup_1
ja try_popup_2
cmp popup_INT28,0 ; if activated via INT 28, INDOS flag is
jz try_popup_2 ; allowed to be 1 rather than 0
try_popup_1:
lds bx,CRITERR_ptr
ASSUME DS:NOTHING
cmp byte ptr [bx],0
jne try_popup_2
push cs
pop ds
ASSUME DS:TGROUP
call popup
try_popup_2:
ASSUME DS:NOTHING
pop bx
pop ds
ASSUME DS:NOTHING
try_popup_done:
popf
ret
try_popup endp
;-----------------------------------------------------------------------
API_popup proc near
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
call attempt_popup
mov al,AMIS_POPUP_WILLDO ; can't pop up now, will do so when able
cmp want_popup,1 ; did we manage to pop up?
je API_popup_done
mov al,AMIS_SUCCESSFUL ; successful
xor bx,bx ; no return code
API_popup_done:
ret
API_popup endp
;-----------------------------------------------------------------------
remov proc near
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
inc want_shutdown
call try_popup
mov al,0
xchg al,want_shutdown ; get and clear shutdown flag
cmp al,0 ; if no longer set, shutdown successful
je remov_successful
mov al,AMIS_UNINST_TRYLATER
ret
remov_successful:
mov al,AMIS_UNINST_SAFE_OFF ; no resident remover, now disabled
mov bx,0 ; seg of block to free (will be patched)
ALTMPX$PSP equ word ptr ($-2) ; magic name of word to be patched with
; actual memory block segment by TSR
; installation code
ret
remov endp
;-----------------------------------------------------------------------
; Declare the interrupt vectors hooked by the program, then set up the
; Alternate Multiplex Interrupt Spec handler
;
HOOKED_INTS 13h,15h,21h,28h
ALTMPX 'Ralf B','NOTE',VERSION_NUM,"Append notes to a file",,,API_popup,remov,Y
;-----------------------------------------------------------------------
; Can't pop up when disk is busy, so try to pop up on return
; We can save one byte by specifying the hardware reset handler set up by
; the ALTMPX macro above
;
int13_handler proc far
ISP_HEADER 13h,hw_reset_2Dh
pushf
inc int13_busy
call ORIG_INT13h
pushf
dec int13_busy
cmp want_popup,0
je int13_done
call try_popup
int13_done:
popf
ret 2
int13_handler endp
;-----------------------------------------------------------------------
; Hotkey checker. Hotkey is Shift+Shift+Key, where Key is patched in at
; installation.
;
int15_handler proc far
ISP_HEADER 15h
jnc int15_done
pushf
sti
cmp ax,4F00h+HOTKEY_SCAN ; can also patch with actual scan code
hotkey_scancode equ byte ptr ($-2) ; at installation time
jne not_hotkey
cmp TSR_activated,0
jne not_hotkey ; ignore hotkey if already popped up
push ds
push ax
xor ax,ax
mov ds,ax
mov al,ds:[417h] ; get shift states
and al,3 ; Shift+Shift
cmp al,3 ; both pressed?
pop ax
pop ds
jne not_hotkey
;
; yes, we got our hotkey
;
call attempt_popup
popf
clc ; throw out scan code
ret 2
not_hotkey:
popf
int15_done:
jmp ORIG_INT15h
int15_handler endp
;-----------------------------------------------------------------------
; Can't pop up when DOS is busy, so try to pop up on return
;
int21_handler proc far
ISP_HEADER 21h
pushf
call ORIG_INT21h
pushf
sti
cmp want_popup,0
je int21_done
call try_popup
int21_done:
popf
ret 2
int21_handler endp
;-----------------------------------------------------------------------
; Can't pop up when DOS is busy, but can do so during an INT 28h
;
ISP_HEADER 28h
sti
cmp want_popup,0
je int28_done
inc popup_INT28
call try_popup
dec popup_INT28
int28_done:
jmp ORIG_INT28h
;-----------------------------------------------------------------------
resident_code_end label byte
TSRcodeEnd@
TSRdata@
resident_data_end label byte
TSRdataEnd@
TSRbss@
resident_bss_end label byte
TSRbssEnd@
resident_code_size equ offset TGROUP:resident_bss_end
;-----------------------------------------------------------------------
_TEXT SEGMENT 'CODE'
ASSUME cs:_TEXT,ds:_TEXT,es:_TEXT,ss:_TEXT
ORG 100h
NOTE:
DISPLAY_STRING banner
CHECK_DOS_VER 3,00 ; we use features not available in 2.x
mov bx,1000h ; set memory block to 64K
mov ah,4Ah
int 21h
mov si,81h ; SI -> command line
cld ; ensure proper direction for string ops
cmdline_loop:
lodsb
cmp al,' ' ; skip blanks and tabs on commandline
je cmdline_loop
cmp al,9
je cmdline_loop
cmp al,'-'
je got_cmdline_switch
bad_cmdline:
jmp usage
got_cmdline_switch:
lodsb ; get next character
and al,0DFh ; force to uppercase
cmp al,'R'
jne not_removing
jmp removing
not_removing:
cmp al,'I'
jne bad_cmdline
installing:
;
; place any necessary pre-initialization here
;
mov dx,si ; point at filename
mov filename_start,si
scan_filename_loop:
lodsb
cmp al,' '
ja scan_filename_loop
mov byte ptr [si-1],0 ; turn filename into ASCIZ
mov ax,3DC1h ; open, no-inherit/DENYNONE/write-only
int 21h
jnc open_successful
mov ax,3C00h ; if unable to open, try creating file
int 21h
jnc create_successful
jmp open_failed
open_successful:
create_successful:
mov bx,ax
mov ah,3Eh ; close the file again; we now know
int 21h ; we can access it
;
; find out whether keyboard intercept is available
;
stc
mov ah,0C0h
int 15h ; get ROM BIOS configuration data
ASSUME ES:NOTHING
mov dx,offset _TEXT:no_hotkey_msg
jc no_kbd_intercept
test byte ptr es:[bx+5],10h ; have keyboard intercept?
jz no_kbd_intercept
mov dx,offset _TEXT:hotkey_msg
no_kbd_intercept:
mov ah,9
int 21h
;
; get and store pointers to DOS busy flags
;
mov ah,34h
int 21h
ASSUME ES:NOTHING
mov word ptr _TEXT:INDOS_ptr,bx
mov word ptr _TEXT:INDOS_ptr+2,es
push ds
mov ax,5D06h
int 21h
ASSUME DS:NOTHING
mov word ptr _TEXT:CRITERR_ptr+2,ds
pop ds
ASSUME DS:_TEXT
mov word ptr _TEXT:CRITERR_ptr,si
;
; now go install the TSR
;
INSTALL_TSR <offset _TEXT:start_TSRcode>,RELBYTE,resident_code_size,BYTE,,BEST,TOPMEM,inst_patch,already_installed
removing:
UNINSTALL <offset _TEXT:start_TSRcode>,RELBYTE,cant_uninstall
push cs
pop ds
DISPLAY_STRING uninstalled_msg
mov ax,4C00h
int 21h
already_installed:
mov dx,offset _TEXT:already_inst_msg
jmp short exit_with_error
open_failed:
mov dx,offset _TEXT:cant_access_msg
jmp short exit_with_error
usage:
mov dx,offset _TEXT:usage_msg
jmp short exit_with_error
cant_uninstall:
mov dx,offset _TEXT:cant_remove_msg
exit_with_error:
mov ah,9
int 21h
mov ax,4C01h
int 21h
inst_patch:
push ax ; remember resident segment
DISPLAY_STRING installed_msg
pop ax ; get back resident segment
push es
mov es,ax
ASSUME ES:TGROUP
;
; close all files which will not be used by the TSR
;
mov bx,0 ; for this TSR, don't need handles 0-4
close_file_loop:
mov ah,3Eh
int 21h
inc bx
cmp bx,4
jbe close_file_loop
;
; now copy the PSP into the resident portion
;
xor si,si
xor di,di
mov cx,size TSR_PSP
cld
rep movsb
mov es:[36h],es ; adjust JFT pointer in copied PSP
mov bx,es
mov ah,50h ; set PSP segment so TSR owns file
int 21h
push cs
pop ds
ASSUME DS:_TEXT
mov dx,filename_start
mov ax,3DC1h ; open, no-inherit/DENYNONE/write-only
int 21h
jnc reopen_successful
xor ax,ax ; point at a closed handle
reopen_successful:
mov TGROUP:notefile_handle,ax
mov bx,ax
xor cx,cx
xor dx,dx
mov ax,4202h ; position to end of file
int 21h
mov ah,50h ; restore PSP segment
mov bx,cs
int 21h
;
; finally, zero out the JFT in our PSP so that the exit won't close
; the files that the TSR does need
;
les di,cs:[0034h] ; pointer to JFT
mov cx,cs:[0032h] ; size of JFT
mov al,0FFh ; closed-file flag
rep stosb
pop es
ASSUME ES:NOTHING
ret
banner db 'NOTE v',VERSION_STR,' Public Domain 1992 Ralf Brown',13,10,'$'
usage_msg db "Usage:",9,"NOTE -Ifile",9,"Install using <file> as notepad",13,10
db 9,"NOTE -R",9,9,"Remove from memory",13,10
db "$"
hotkey_msg db "Press Shift-Shift-",HOTKEY_NAME," to pop up",13,10,"$"
no_hotkey_msg db "Hotkey is not available on this machine",13,10,"$"
installed_msg db "Installed.",13,10,"$"
already_inst_msg db 13,10,"Already installed.",13,10,"$"
cant_remove_msg db "Can't remove from memory.",13,10,"$"
uninstalled_msg db "Removed.",13,10,"$"
cant_access_msg db "Unable to open or create notepad file",13,10,"$"
filename_start dw ?
_TEXT ENDS
end NOTE