2000 ; LOGTSR Resident "Log Book" in XMS mem ; Oct 1995 Mats Petersson SM5SXL .MODEL TINY .386 .CODE ORG 100h start: jmp main ;**************************** Resident data scan db ? refresh_st db 0 screen dd 0b8000000h org_int9 dd ? first_time db 1 mstr STRUCT len dd 0 ; 32-bit number of bytes to transfer shand dw 0 ; Handle of source block soff dd 0 ; 32-bit offset into source block dhand dw 0 ; Handle of dest block doff dd 0 ; 32-bit offset into dest block mstr ENDS ms mstr <> time_str db 4 dup(?) xmsdriver dd ? xms_handle dw ? cur_x dw 1 cur_y dw 1 cur_start db ? cur_end db ? char_save dw ? xwidth db 160 log_hdr db 'TBGN TEND CALL NAME QTH FREQ MODE HIS MY PG 0', 0 tab_lst db 0, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1,10, 9, 8, 7, 6, 5, 4, 3, 2, 1 db 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,20,19,18,17,16,15,14,13,12,11 db 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,10, 9, 8, 7, 6, 5, 4, 3, 2, 1 db 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 shfttab_lst db 0, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 7, 8, 9 db 10, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 1, 2, 3, 4, 5, 6, 7, 8, 9 db 10,11,12,13,14,15,16,17,18,19,20, 1, 2, 3, 4, 5, 6, 7, 8, 9 db 10, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 7, 8, 9 inside_log db 0 log_page dw 1 ;**************************** NewInt9 -- New INT9 (key-press) proc. xms_move PROC NEAR mov si, offset ms mov ah, 0bh xor bl, bl ; reset error code to zero call xmsdriver ; call the XMS driver ret xms_move ENDP dir_wr PROC NEAR les di, screen sub ax, ax mov ax, cur_y ;row sub ax, 1 mul xwidth ;times bytes/row mov dx, cur_x ;column sub dx, 1 shl dx, 1 ;Take attribute byte in account add ax, dx add di, ax ;offset adress of screen now in di mov ax, word ptr es:[di] ;Save char to be overwritten mov char_save, ax mov word ptr es:[di], bx ;ASCII char and attribute ret dir_wr ENDP log_book PROC NEAR pusha push ds push es push cs pop ds cld mov inside_log, 1 call hide_cur mov ax, 0 call save_bg_log cmp first_time, 1 jnz not_first_time call init_logpages mov first_time, 0 jmp log_lp not_first_time: mov ax, 1 call rest_bg_log log_lp: mov ah, 10h int 16h cmp ah, 1 ;Quit if ESC jz log_ready call process_key jmp log_lp log_ready: mov ax, 1 call save_bg_log mov ax, 0 call rest_bg_log call show_cur mov inside_log, 0 pop es pop ds popa ret log_book ENDP process_key PROC NEAR push es ; look into BIOS data area sub dx, dx ; (segment 0) to check shift state mov es, dx mov dx, es:[417h] ; Get SHIFT-key flags test dx, 0000000000001000b ; Check if Alt-key pressed pop es jz no_alt cmp ah, 14h ;Check if Alt-T jnz no_alt call write_time jmp write_cursor no_alt: test dx, 0000000000000001b jz left_shift jmp shift_tab left_shift: test dx, 0000000000000010b jz no_shift shift_tab: cmp ah, 0fh ;Check if Shift-Tab jnz no_shift mov bx, char_save call dir_wr mov dx, cur_x mov bx, dx sub dl, shfttab_lst[bx] mov cur_x, dx jmp write_cursor no_shift: cmp ah, 48h ;Up arrow? jnz dn_arrow mov bx, char_save call dir_wr dec cur_y cmp cur_y, 2 jnz write_cursor inc cur_y jmp write_cursor dn_arrow: cmp ah, 50h ;Down arrow? jnz left_arrow mov bx, char_save call dir_wr inc cur_y cmp cur_y, 26 jnz write_cursor dec cur_y jmp write_cursor left_arrow: cmp ah, 4bh ;Left arrow? jnz right_arrow mov bx, char_save call dir_wr dec cur_x cmp cur_x, 0 jnz write_cursor inc cur_x jmp write_cursor right_arrow: cmp ah, 4dh ;Right arrow? jnz home mov bx, char_save call dir_wr inc cur_x cmp cur_x, 81 jnz write_cursor dec cur_x jmp write_cursor home: cmp ah, 47h ;Home? jnz k_end mov bx, char_save call dir_wr mov cur_x, 1 jmp write_cursor k_end: cmp ah, 4fh ;End? jnz pgup mov bx, char_save call dir_wr mov cur_x, 80 jmp write_cursor pgup: cmp ah, 49h ;PgUp? jnz pgdn mov bx, char_save call dir_wr mov cur_y, 3 jmp write_cursor pgdn: cmp ah, 51h ;PgDn? jnz delete mov bx, char_save call dir_wr mov cur_y, 25 jmp write_cursor delete: ;Delete? cmp ah, 53h jnz minus mov cur_x, 81 delete_lp: mov bx, 1f20h call dir_wr dec cur_x cmp cur_x, 0 jnz delete_lp inc cur_x mov bx, 1fb1h call dir_wr jmp over_write minus: ;Numkey Minus? cmp ah, 4ah jnz plus mov bx, char_save call dir_wr mov ax, 1 call save_bg_log dec log_page cmp log_page, 0 jnz chg_page inc log_page jmp chg_page plus: ;Numkey Plus? cmp ah, 4eh jnz cr mov bx, char_save call dir_wr mov ax, 1 call save_bg_log inc log_page cmp log_page, 5 jnz chg_page dec log_page chg_page: mov ax, 1 call rest_bg_log jmp write_cursor cr: cmp al, 0dh ;C/R? jnz bspace mov bx, char_save call dir_wr mov cur_x, 1 inc cur_y cmp cur_y, 26 jnz write_cursor dec cur_y jmp write_cursor bspace: cmp al, 08h ;Backspace? jnz tab mov bx, 1f20h call dir_wr dec cur_x cmp cur_x, 0 jnz no_zero inc cur_x no_zero: mov bx, 1fb1h call dir_wr mov char_save, 1f20h ;discard char under cursor if BS jmp over_write tab: cmp al, 09h ;Tab? jnz printable mov bx, char_save call dir_wr mov dx, cur_x mov bx, dx add dl, tab_lst[bx] mov cur_x, dx jmp write_cursor printable: mov bh, 1fh mov bl, al ;Printable character call dir_wr inc cur_x cmp cur_x, 81 jb no_newline mov cur_x, 1 inc cur_y cmp cur_y, 26 jz over_write no_newline: write_cursor: mov bx, 1fb1h call dir_wr over_write: ret process_key ENDP hide_cur PROC NEAR mov ah, 3 ; Get old cursor info mov bh, 0 int 10h mov cur_start, ch mov cur_end, cl mov ah,01h ; Hide cursor mov ch,00100110b mov cl,00000111b int 10H ret hide_cur ENDP show_cur PROC NEAR mov ah,01H mov ch, cur_start mov cl, cur_end int 10H ret show_cur ENDP save_bg_log PROC NEAR mov ms.doff, 0 cmp ax, 1 jnz save_bg xor eax, eax mov ax, 4000 mul log_page mov ms.doff, eax save_bg: mov ms.len, 4000 mov ms.shand, 0 mov edx, 0b8000000h mov ms.soff, edx mov dx, xms_handle mov ms.dhand, dx call xms_move ret save_bg_log ENDP rest_bg_log PROC NEAR mov ms.soff, 0 cmp ax, 1 jnz rest_bg xor eax, eax mov ax, 4000 mul log_page mov ms.soff, eax rest_bg: mov ms.len, 4000 mov dx, xms_handle mov ms.shand, dx mov ms.dhand, 0 mov edx, 0b8000000h mov ms.doff, edx call xms_move ret rest_bg_log ENDP init_logpages PROC NEAR mov cx, 4000/4 les di, screen mov eax,1f201f20h rep stosd next_page: mov cur_x, 1 mov cur_y, 1 mov si, offset log_hdr mov ax, log_page inc byte ptr[si+79] ;Page number hdr_lp: mov bh, 3eh mov bl, byte ptr[si] cmp bl, 0 jz hdr_rdy call dir_wr inc cur_x inc si jmp hdr_lp hdr_rdy: mov ax, 1 call save_bg_log inc log_page cmp log_page, 5 jb next_page mov log_page, 1 mov ax, 1 call rest_bg_log mov cur_x, 1 mov cur_y, 3 mov bx, 1fb1h call dir_wr ret init_logpages ENDP bcd2ascii PROC mov al,bl shr al,4 ;We want the high BCD nibble... and al,0fh add al,030h ; Convert BCD -> ASCII stosb ; Store in time string mov al,bl and al,0fh add al,030h stosb ret bcd2ascii ENDP 1cc8 write_time PROC mov ah,02h ;Read real time clock time int 1ah push cs pop es mov di, offset time_str mov bl,ch call bcd2ascii ; Store hours mov bl,cl call bcd2ascii ; Store minutes mov si, offset time_str mov cx, 4 time_lp: mov bh, 1fh mov bl, byte ptr[si] call dir_wr inc cur_x inc si loop time_lp ret write_time ENDP newint9 PROC FAR sti push ax cmp cs:inside_log, 1 ; Check if invoked while inside logbook jz no_hotkey ; If so, skip all further processing in al,60h ; Get scancode from keyboard processor cmp al, 0Fh ; Check if Tab key jz test_shift jmp no_hotkey test_shift: mov cs:scan, al ; Save scan code push es ; look into BIOS data area sub ax, ax ; (segment 0) to check shift state mov es, ax mov ax, es:[417h] ; Get SHIFT-key flags test ax, 0000000000001000b ; Check if Alt-key pressed pop es jz no_hotkey cli ; Disable interrupts while resetting in al, 61h ; Get current port 61h state or al, 10000000b ; Turn on bit 7 to signal clear keybrd out 61h, al ; Send to port and al, 01111111b ; Turn off bit 7 to signal break out 61h, al ; Send to port mov al, 20h ; Reset interrupt controller here to out 20h, al ; allow keyboard presses in log screen sti ; Reenable interrupts call log_book pop ax iret no_hotkey: pop ax ; Recover AX and fall through cli ; Interrupts cleared for service jmp cs:org_int9 ; jump to old Int 09 routine newint9 ENDP ;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ Transient Section ;**************************** Transient data header db 'LOGTSR v1.0 Resident Logbook by Mats Petersson SM5SXL',13, 10, '$' hotkeys db 'Press Alt-Tab to activate', 13, 10, 13, 10, '$' uninstalled db 13, 10, 'Un' installed db 'Installed Successfully',13,10,'$' syntax db 'Syntax: LOGTSR [/U]',13,10,'$' nomemory db 'Out of memory',13,10,'$' alreadyin db 'Already installed',13,10,'$' notfound db 'Resident copy not found',13,10,'$' cantunload db 'Can''t uninstall',13,10,'$' no_xms db 'No XMS driver installed!',13,10,'$' resname db 'LogTsr ' resseg dw 0 xms_freemem dw ? xms_totmem dw ? xmsdriv dd ? ;**************************** Main -- Main procedure main PROC mov ah,9 ;Print install message mov dx, offset header int 21h call findres ;Find resident copy mov al,'/' ;Search for slash xor cx, cx ;in command line mov cl, byte ptr cs:[80h] cmp cl, 0 jz nounload mov di, 81h repne scasb jne nounload ;No slash, don't unload mov dx, offset syntax ;DX = 'Syntax:' string cmp byte ptr[di], 'U' ;/U or /u, unload je unload cmp byte ptr[di], 'u' je unload cmp byte ptr[di], '?' ;/?, print syntax je error nounload: mov dx, offset alreadyin ;Point DX to error string cmp resseg, 0 ;Already installed? jne error mov dx, offset no_xms call xms_setup cmp ax, 0 jz error call xms_alloc cld ;Clear direction flag mov ax, offset lastbyte ;AX = last byte + 256 inc ah cmp ax, sp ;Check for too little memory jbe memOK mov dx, offset nomemory ;Print 'Out of memory' string error: mov ah, 9 int 21h mov ax, 4C01h ;Exit with error int 21h memOK: mov sp, ax ;Shrink stack jmp load ;Jump to Load procedure main ENDP ;**************************** Load -- TSR loader procedure load PROC mov ah, 49h mov es, cs:[2Ch] int 21h mov ax, 3509h ;Get and store old INT9 address int 21h mov word ptr[org_int9], bx mov word ptr[org_int9+2], es mov ax, 2509h ;Set new INT16 handler mov dx, offset newint9 int 21h mov ax, cs ;ES = MCB segment (CS - 1) dec ax mov es, ax mov si, offset resname ;Change resident name mov di, 8 mov cx, di rep movsb mov ah, 9 mov dx, offset hotkeys ;Print hot-key text int 21h mov ah, 9 ;Print 'Installed' string mov dx, offset installed int 21h mov dx, offset header ;Last byte of program lastbyte: int 27h ;DOS TSR service load ENDP ;**************************** Unload -- Uninstall procedure unload PROC mov cx, resseg ;CX = resident segment mov dx, offset notfound ;Point DX to error string test cx, cx ;Make sure it's in memory je error mov dx, offset cantunload ;Point DX to error string mov ax, 3509h ;Check to make sure that the int 21h ;interrupts still point to cmp bx, offset newint9 ;the resident copy... jne error mov es, resseg ;ES = resident segment mov ax, 2509h ;Reset INT9 vector mov dx, word ptr es:[org_int9] mov ds, word ptr es:[org_int9+2] int 21h push cs pop ds call xms_free mov ah, 49h ;Release memory segment int 21h mov byte ptr[installed], 'i';Fix 'Uninstalled' string mov ah,9 ;Print 'Uninstalled' string mov dx, offset uninstalled int 21h mov ax, 4C00h ;Quit program int 21h unload ENDP ;**************************** FindRes -- Find resident copy findres PROC pusha ;Save registers push es mov ax,5802h ;Save UMB link status int 21h push ax mov ax, 5803h ;Link UMBs mov bx, 1 int 21h mov ah, 52h ;Get Internal Config Table int 21h sub bx, 2 ;BX = first MCB mov bx, es:[bx] fr_lp: mov es, bx ;ES = MCB segment cmp dword ptr es:[8], 54676f4ch ;Check for signature je fr_found add bx, es:[3] ;Step to next one inc bx cmp byte ptr es:[0],'Z' ;Last one in chain? jne fr_lp ;Loop back mov bx,-1 ;Return 0 (-1 + 1 = 0) fr_found: inc bx mov resseg, bx ;Return resident segment mov ax, 5803h ;Restore UMB link status pop bx int 21h pop es popa ret findres ENDP xms_setup PROC mov ax, 4300h ; XMS Driver installation check int 2fh cmp al, 80h ; returns 80h if installed jz xmsfound mov ax, 0 ; XMS Driver not present jmp exit_setup xmsfound: mov ax, 4310h ; get address of XMS driver int 2fh mov word ptr[xmsdriver],bx ; store offset mov word ptr[xmsdriver+2], es ; store segment mov ax,1 exit_setup: ret xms_setup ENDP xms_get_freemem PROC mov ah,8 call xmsdriver mov xms_freemem,ax mov xms_totmem,dx ret xms_get_freemem ENDP xms_alloc PROC mov dx, 25 mov ah,09 call xmsdriver ; call the XMS driver mov xms_handle, dx ; return handle in AX ret xms_alloc ENDP xms_free PROC push es mov dx, word ptr es:[xms_handle] ; XMS handle mov ah, 0ah call dword ptr es:[xmsdriver] ; call the XMS driver pop es ret xms_free ENDP END start . 0