;---------------------------------------------------------------- ; RAMVIEW: A memory-resident memory-viewer. ; Frank Dever & David Thomas, WindowDOS Associates ;---------------------------------------------------------------- ; modified 9/9/1988 by Patrick Philippot - Draveil - France ; removed RET 2 bug in INT 10h handling routine (see line 120) ; added color control - see EQUates ; modified 12/16/1989 by Patrick Philippot - Draveil - France ; added editing capabilities ;---------------------------------------------------------------- ; scan codes ;---------------------------------------------------------------- U_ARR EQU 72 ;up arrow D_ARR EQU 80 ;down arrow PGUP EQU 73 ;page up PGDN EQU 81 ;page down L_ARR EQU 75 ;left arrow R_ARR EQU 77 ;right arrow HOME EQU 71 ;home END_KEY EQU 79 ;end INT9_BUSY EQU 1 INT10_BUSY EQU 2 INT16_BUSY EQU 4 SHIFT_MASK EQU 2 ;Shift HOTKEY EQU 36H ;Shift CR EQU 0DH LF EQU 0AH TOPLINE_ATTR EQU 30H ; top line attribute BOTLINE_ATTR EQU 30H ; bottom line attribute PROMPT_ATTR EQU 31H ; prompt attribute ASCII_ATTR EQU 1BH ; ascii part attribute NORM_ATTR EQU 07H ; normal text attribute ABS_ATTR EQU 02H ; absolute address part attribute ADDR_ATTR EQU 06H ; address part attribute LEFT_LIM_HEX EQU 16 ; left limit of hex display RIGHT_LIM_HEX EQU 62 ; right limit of hex display LEFT_LIM_ASC EQU 64 ; left limit of ascii display RIGHT_LIM_ASC EQU 79 ; right limit of ascii display _TEXT SEGMENT PARA PUBLIC 'CODE' ASSUME CS:_TEXT,DS:_TEXT ORG 100H START: JMP RES INSTALLED DB "RAMVIEW 1.03 (c) 1988, Ziff Communications Co." DB CR,LF,"PC Magazine ",254," Frank Dever & David Thomas" DB CR,LF,"Enhancements by Patrick Philippot" DB CR,LF,"Hotkey is LShift-RShift",CR,LF,"$",1AH UNINSTALLED DB "RAMVIEW Uninstalled",CR,LF,"$" DISABLE DB 0 ;flag for inapropriate de-installation LABEL0 DB " ABS SEG OFF 0 1 2 3 4 5 6 7" DB " 8 9 A B C D E F ASCII ",0 START_DISPLAY DB " GOTO ADDRESS: 0000:0000",0 COMMANDLINE DB "(G)oto (E)dit (H)ex Search (A)scii Search (N)ext" DB " ",24," ",25," PgUp PgDn Home End Esc ",0 EDIT_MSG DB "Edit mode active - Hit Escape to quit",0 EDIT_PROMPT DB "(H)exadecimal or (A)scii edition?",0 CURSOR_POS DW 0 CURSOR_TYPE DW 0607H ;for turning cursor on/off START_OFFSET DW 0 ;top addr shown on screen START_SEGMENT DW 0 END_OFFSET DW 0FH ;last segment in search END_SEGMENT DW 0FFFFH ;fixed to ffff:f SEARCH_SEGMENTS DW 0 ;# segments to search SEARCH_BYTES DW 0 ;# bytes left after search HEX_SIEVE DB " " ;hex with space ADDR_SIEVE DB "01234567890ABCDEF" ;hex without space CHAR_SIEVE DB 0 ;all characters ASCII_SEARCH_PROMPT DB "ASCII Search String: ",0 ;ascii search prompt HEX_SEARCH_PROMPT DB "HEX Search String: ",0 ;hex search prompt ASCII_SEARCH_AREA DB 20 DUP (" "),0 ;ascii search string HEX_SEARCH_AREA DB 20 DUP (" "),0 ;hex search string LAST_SEARCH_STRING DW 0 ;pointer to last string LAST_STRING_LENGTH DW 0 ;last string length OUR_SS DW 0 OUR_SP DW 0 THEIR_SS DW 0 THEIR_SP DW 0 ADDR_INT9H DD 0 ADDR_INT10H DD 0 BUSY DB 0 BIOS_SEG DW 40H DIFF DW 0 ;# of chars on a line > 80 ROW DW 0 ;display row counter FLICKER_FREE DB 0 ;snowy monitor flag TEXT_ATTR DB 0 ;display text attribute _ROW DB 0 _COL DB 0 ;----------------------------------------------------------------- ; code relating to residency ;----------------------------------------------------------------- RES PROC NEAR CLD CALL PROGRAM_ALREADY_IN JNZ NOT_IN ;else, it's ok to install CALL UNINSTALL MOV AX,4C01H ;terminate with error code INT 21H NOT_IN: MOV OUR_SS,CS ;set stack seg MOV OUR_SP,OFFSET LAST_BYTE+4000+256 ; and pointer CALL INSTALL MOV DX,OFFSET INSTALLED ;already in MOV AH,9 INT 21H ;program, screen buf, stack MOV DX,(OFFSET LAST_BYTE-OFFSET _TEXT+4000+256+15) SHR 4 MOV AX,3100H ;stay resident INT 21H RES ENDP ;---------------------------------------------------------------------- INT10H PROC FAR OR CS:BUSY,INT10_BUSY ;recursion protection PUSHF CALL CS:ADDR_INT10H PUSHF AND CS:BUSY,NOT(INT10_BUSY) POPF IRET ; was RET 2 in ver. 1.00 preserve flags INT10H ENDP ;---------------------------------------------------------------------- INT9H PROC FAR STI PUSH AX ;save working register CMP CS:DISABLE,-1 ;if disabled, do nothing JE NOT_US IN AL,60H ;get key from keyboard port CMP AL,HOTKEY ;is it our hotkey? JNE NOT_US ;if not, exit MOV AH,2 ;otherwise INT 16H ;get shift status AND AL,0FH CMP AL,SHIFT_MASK ;test the shift status JNE NOT_US ;if not shift combo, exit IN AL,61H ;These instructions reset MOV AH,AL ; the keyboard. OR AL,80H OUT 61H,AL MOV AL,AH JMP SHORT $+2 ;I/O delay for fast AT's OUT 61H,AL CLI ;Disable interrupts and MOV AL,20H ;reset the int controller OUT 20H,AL STI CMP CS:BUSY,0 ;recursion protection JNE WE_ARE_BUSY ;dont allow re-entrancy OR CS:BUSY,INT9_BUSY ;set flag for protection CALL ADJUST_FOR_VIDEO_MODE JC CANT_POP_UP CALL MEM ;call our program CANT_POP_UP: CLI ;disable kbd momentarily AND CS:BUSY,NOT(INT9_BUSY) ;reset protection WE_ARE_BUSY: POP AX ;restore working register IRET ;return to foreground NOT_US: POP AX ;restore working register CLI JMP CS:ADDR_INT9H ;let ROM code do its work INT9H ENDP ;----------------------------------------------------------------- ;check for text modes and set offset ;for lines > than 80 characters in length ;----------------------------------------------------------------- ADJUST_FOR_VIDEO_MODE PROC NEAR PUSH BX MOV AH,15 ;get present mode INT 10H CMP AH,80 JB BAD_MODE MOV BYTE PTR CS:DIFF,AH ;calc the # of chars > 80 SUB CS:BYTE PTR DIFF,80 ;on the line & save in diff CMP AL,7 ;7 is mono JNE TRY_COLOR MODE_OK: CLC POP BX RET TRY_COLOR: CMP AL,3 ;3 is color 80x25 JBE MODE_OK BAD_MODE: STC ;not good mode POP BX RET ADJUST_FOR_VIDEO_MODE ENDP ;----------------------------------------------------------------- ;main routine called by pressing hot key ;----------------------------------------------------------------- MEM PROC NEAR CALL SWAPIN ;new stack MOV AX,CS ;our data segment MOV DS,AX CALL FLICKER ;determine presence of snow CALL SAVE_CURSOR ;save cursor CALL CURSOR_OFF ;turn cursor off CALL SAVE_SCREEN ;save screen CALL CLEAR_SCREEN ;clear screen CALL PROGRAM ;do our program CALL RESTORE_SCREEN ;put screen back CALL CURSOR_ON ;turn cursor on CALL RESTORE_CURSOR CALL SWAPOUT ;put stack back RET ;that's all MEM ENDP PROGRAM PROC NEAR XOR AX,AX ;row 0 MOV BX,AX ;col 0 MOV SI,OFFSET LABEL0 ;bottom line MOV TEXT_ATTR, TOPLINE_ATTR ;modified P. Philippot CALL DISPLAY_STRING ;show header line NEXT_SCREEN: CALL BODY ;put hex display up MOV AX,24 ;last row XOR BX,BX ;column 0 MOV SI,OFFSET COMMANDLINE ;command line MOV TEXT_ATTR, BOTLINE_ATTR ;modified P. Philippot CALL DISPLAY_STRING ;show it CALL MENU ;go get keystroke JNC NEXT_SCREEN ;until esc is pressed EXIT: RET PROGRAM ENDP ;----------------------------------------------------------------- ;cursor routines ;----------------------------------------------------------------- SAVE_CURSOR PROC NEAR MOV ES,BIOS_SEG MOV AX,ES:[60H] ;get present cursor type MOV CURSOR_TYPE,AX ;save it CALL GETPOS MOV CURSOR_POS,DX RET SAVE_CURSOR ENDP ;---------------------------------------------------------------------- RESTORE_CURSOR PROC NEAR MOV DX,CURSOR_POS CALL SETPOS RET RESTORE_CURSOR ENDP ;---------------------------------------------------------------------- SETPOS PROC NEAR MOV AH,2 ;set cursor position XOR BH,BH ;active page INT 10H ;set cursor position to dx RET SETPOS ENDP ;---------------------------------------------------------------------- GETPOS PROC NEAR MOV AH,3 ;get cursor position XOR BH,BH ;active page INT 10H ;get cursor position in dx RET GETPOS ENDP ;---------------------------------------------------------------------- CURSOR_OFF PROC NEAR PUSH CX MOV CX,2B0CH ;turn off cursor value CALL SETCUR POP CX RET CURSOR_OFF ENDP ;---------------------------------------------------------------------- CURSOR_ON PROC NEAR PUSH CX MOV CX,CURSOR_TYPE ;turn on cursor value CALL SETCUR POP CX RET CURSOR_ON ENDP ;---------------------------------------------------------------------- SETCUR PROC NEAR PUSH AX MOV AH,1 ;function to set cursor shape INT 10H ;do it POP AX RET ;that's all SETCUR ENDP ;----------------------------------------------------------------- ;screen routines ;----------------------------------------------------------------- SAVE_SCREEN PROC NEAR CALL TURN_OFF_CRT PUSH DS ;save data segment XOR AX,AX MOV BX,AX CALL CALC_SCRN_ADDR ;address of (0,0) MOV SI,OFFSET LAST_BYTE ;buffer is past end of prog PUSH DS ;exchange PUSH ES ;ds and es POP DS POP ES XCHG DI,SI ;exchange source,destination MOV BX,25 SAVE_NEXT_LINE: MOV CX,80 ;save 2000 REP MOVSW ;words ADD SI,CS:DIFF ;go to next ADD SI,CS:DIFF ;line DEC BX ;25 lines JNZ SAVE_NEXT_LINE POP DS ;restore data segment CALL TURN_ON_CRT RET SAVE_SCREEN ENDP ;----------------------------------------------------------------- CLEAR_SCREEN PROC NEAR CALL TURN_OFF_CRT XOR AX,AX MOV BX,AX CALL CALC_SCRN_ADDR ;address of (0,0) MOV AL,20H ;space with normal attribute MOV BX,24 CLEAR_NEXT_LINE: MOV AH,ABS_ATTR ;modified P. Philippot MOV CX,6 ; REP STOSW ; MOV AH,ADDR_ATTR ; MOV CX,10 ; REP STOSW ; MOV AH,NORM_ATTR ; MOV CX,64 ; REP STOSW ; ADD DI,CS:DIFF ;go to next ADD DI,CS:DIFF ;line DEC BX ;24 lines JNZ CLEAR_NEXT_LINE CALL TURN_ON_CRT RET CLEAR_SCREEN ENDP ;----------------------------------------------------------------- RESTORE_SCREEN PROC NEAR CALL TURN_OFF_CRT XOR AX,AX MOV BX,AX CALL CALC_SCRN_ADDR ;address of (0,0) MOV SI,OFFSET LAST_BYTE ;buffer past end of program MOV BX,25 RESTORE_NEXT_LINE: MOV CX,80 ;save 2000 REP MOVSW ;words ADD DI,CS:DIFF ;go to next ADD DI,CS:DIFF ;line REP MOVSW ;words DEC BX ;25 lines JNZ RESTORE_NEXT_LINE CALL TURN_ON_CRT RET RESTORE_SCREEN ENDP ;----------------------------------------------------------------- TURN_ON_CRT PROC NEAR CMP CS:FLICKER_FREE,-1 ;is it flicker free? JZ NOSNOW ;if so, dont turn crt_on PUSH AX PUSH DX PUSH ES CALL WAIT_VERT MOV DX,3D8H MOV ES,BIOS_SEG MOV AL,ES:BYTE PTR[65H] ;get crt mode setting OUT DX,AL ;set crt back to previous mode POP ES POP DX POP AX NOSNOW: RET TURN_ON_CRT ENDP ;----------------------------------------------------------------- FLICKER PROC NEAR MOV FLICKER_FREE,0 ;assume snowy monitor MOV AX,1A00H INT 10H ;Use PC Magazine's method CMP AL,1AH ;of determining JZ FLICKFREE ;vga or mda active MOV AH,12H MOV BL,10H INT 10H CMP BL,10H JNZ FLICKFREE ;if bl changed, its ega MOV AX,40H MOV ES,AX TEST ES:BYTE PTR[63H],40H ;check for mda (= no flicker) JNZ ITS_CGA FLICKFREE: MOV FLICKER_FREE,-1 ITS_CGA: RET FLICKER ENDP ;----------------------------------------------------------------- TURN_OFF_CRT PROC NEAR CMP CS:FLICKER_FREE,-1 ;is it flicker free? JZ NO_SNOW PUSH DX PUSH AX CALL WAIT_VERT MOV AL,25H ;mask to turn off crt MOV DX,3D8H OUT DX,AL ;turn it off POP AX POP DX NO_SNOW: RET TURN_OFF_CRT ENDP ;----------------------------------------------------------------- WAIT_VERT PROC NEAR CMP CS:FLICKER_FREE,-1 ;is it flicker free? JZ NOWAIT PUSH AX PUSH DX MOV DX,3DAH ;color status port WAIT0: IN AL,DX TEST AL,8 JNZ WAIT0 ;wait for vertical off WAIT1: IN AL,DX TEST AL,8 JZ WAIT1 ;wait for verical on POP DX POP AX NOWAIT: RET WAIT_VERT ENDP ;----------------------------------------------------------------- ;stack routines ;----------------------------------------------------------------- RETADDR DW 0 SWAPIN PROC NEAR POP CS:RETADDR ;save callers address MOV CS:THEIR_SS,SS ;save their stack MOV CS:THEIR_SP,SP MOV SS,CS:OUR_SS ;switch to our stack MOV SP,CS:OUR_SP PUSH AX ;save all registers PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH ES PUSH DS PUSH BP JMP CS:RETADDR ;return to caller SWAPIN ENDP ;----------------------------------------------------------------- SWAPOUT PROC NEAR POP CS:RETADDR ;save callers address POP BP ;restore all registers POP DS POP ES POP DI POP SI POP DX POP CX POP BX POP AX MOV SS,CS:THEIR_SS ;restore callers stack MOV SP,CS:THEIR_SP JMP CS:RETADDR ;return to caller SWAPOUT ENDP ;----------------------------------------------------------------- ;clears last line ;----------------------------------------------------------------- CLEAR_LAST_LINE PROC NEAR CALL WAIT_VERT MOV AX,24 ;row 24 XOR BX,BX ;col 0 CALL CALC_SCRN_ADDR ;get es:di for that address MOV CX,80 ;80 words MOV AL,20H ;normal attribute spaces MOV AH,BOTLINE_ATTR ;modified P.Philippot REP STOSW ;clear it RET ;that's all CLEAR_LAST_LINE ENDP ;----------------------------------------------------------------- ;menu accept and key input ;----------------------------------------------------------------- MENU PROC NEAR NEXT_MENU_KEY: CALL GETKEY ;input a key CMP AH,2 ;if scan code is less than 2 JA NOT_ESC JMP QUIT_EXIT ; the key is Esc NOT_ESC: AND AL,0DFH ;make all ascii caps CMP AL,"G" ;G)o JNZ NOT_GOTO CALL GOTO ;get start addr JMP MENU_EXIT NOT_GOTO: CMP AL,"A" ;A)scii search JNZ NOT_ASCII_SEARCH CALL ASCII_SEARCH ;find ascii string JMP MENU_EXIT NOT_ASCII_SEARCH: CMP AL,"H" ;H)ex search JNZ NOT_HEX_SEARCH CALL HEX_SEARCH ;find hex string JMP MENU_EXIT NOT_HEX_SEARCH: CMP AL,"N" ;N)ext search JNZ NOT_NEXT_SEARCH CALL NEXT_SEARCH ;find next string JMP MENU_EXIT NOT_NEXT_SEARCH: CMP AL, "E" JNZ NOT_EDIT CALL EDIT ;Edit memory hexa JMP MENU_EXIT NOT_EDIT: CMP AH,U_ARR ;up arrow JNZ NOT_UP MOV AX,-10H JMP SHORT MOVEIT NOT_UP: CMP AH,HOME ;go to beginning of memory JNZ NOT_HOME MOV START_OFFSET,0 MOV START_SEGMENT,0 JMP SHORT MENU_EXIT NOT_HOME: CMP AH,END_KEY ;go to end of memory JNZ NOT_END MOV START_OFFSET,0FE90H ;top of last page MOV START_SEGMENT,0F000H JMP SHORT MENU_EXIT NOT_END: CMP AH,D_ARR ;down arrow JNZ NOT_DOWN MOV AX,10H JMP SHORT MOVEIT NOT_DOWN: CMP AH,PGUP ;page up JNZ NEXT_CHECK MOV AX,-170H JMP SHORT MOVEIT NEXT_CHECK: CMP AH,PGDN ;page down MOV AX,170H JZ MOVEIT JMP NEXT_MENU_KEY MOVEIT: CALL MOVE MENU_EXIT: CLC ;clear carry for exit QUIT_EXIT: RET ;that's all MENU ENDP ;----------------------------------------------------------------- ;sets starting segment and offset for display ;----------------------------------------------------------------- MOVE PROC NEAR OR AX,AX ;is the movement signed JNS ADDIT ;no-add to seg:off NEG AX ;otherwise make positive SUB START_OFFSET,AX ;subtract from offset JNC MOVE_EXIT ;if no carry, done SUB START_SEGMENT,1000H ;else wrap segment JMP SHORT MOVE_EXIT ADDIT: ADD START_OFFSET,AX ;add movement to offset JNC MOVE_EXIT ;if no carry, done ADD START_SEGMENT,1000H ;else wrap segment MOVE_EXIT: RET MOVE ENDP ;----------------------------------------------------------------- ;edit memory routines (added by Patrick Philippot) ;----------------------------------------------------------------- BEGIN_EDIT PROC NEAR PUSH AX PUSH BX PUSH SI CALL CLEAR_LAST_LINE MOV AX,24 ;last row XOR BX,BX ;column 0 MOV SI,OFFSET EDIT_MSG ;edit message MOV TEXT_ATTR, BOTLINE_ATTR CALL DISPLAY_STRING ;show it CALL CURSOR_ON MOV _ROW, 1 POP SI POP BX POP AX RET BEGIN_EDIT ENDP ;----------------------------------------------------------------- ;set cursor position ;----------------------------------------------------------------- SET_POS PROC NEAR PUSH AX PUSH BX PUSH DX MOV DH, _ROW ;set row and col MOV DL, _COL ;and call bios MOV AH, 2 XOR BH, BH INT 10h POP DX POP BX POP AX RET SET_POS ENDP ;----------------------------------------------------------------- ;move cursor up one row and wrap ;----------------------------------------------------------------- MOVE_UP PROC NEAR CMP _ROW, 1 ;need to wrap ? JE NotUp ;yes DEC _ROW JMP Done_Up NotUp: MOV _ROW, 23 Done_Up: CALL SET_POS ;set cursor pos RET MOVE_UP ENDP ;----------------------------------------------------------------- ;move cursor down one row and wrap ;----------------------------------------------------------------- MOVE_DOWN PROC NEAR CMP _ROW, 23 ;need to wrap ? JE NotDown ;yes INC _ROW JMP Done_Down NotDown: MOV _ROW, 1 Done_Down: CALL SET_POS RET MOVE_DOWN ENDP ;----------------------------------------------------------------- ;move cursor left one col and wrap - hexa ;----------------------------------------------------------------- MOVE_LEFT_HEX PROC NEAR PUSH AX PUSH BX CMP _COL, LEFT_LIM_HEX ;need to wrap ? JE NoLeft ;yes MOV AL, _COL ;compute if a column SUB AL, LEFT_LIM_HEX ;has to be skipped over XOR AH, AH MOV BL, 3 DIV BL CMP AH, 0 JNE NoSkip DEC _COL ;yes, skip it NoSkip: DEC _COL JMP Done_Left NoLeft: MOV _COL, RIGHT_LIM_HEX CALL MOVE_UP Done_Left: CALL SET_POS POP BX POP AX RET MOVE_LEFT_HEX ENDP ;----------------------------------------------------------------- ;move cursor right one col and wrap - hexa ;----------------------------------------------------------------- MOVE_RIGHT_HEX PROC NEAR PUSH AX PUSH BX CMP _COL, RIGHT_LIM_HEX ;need to wrap ? JE NoRight ;yes INC _COL MOV AL, _COL ;compute if a column has SUB AL, LEFT_LIM_HEX ;to be skipped over INC AL XOR AH, AH MOV BL, 3 DIV BL CMP AH, 0 JNE Done_Right INC _COL ;yes, skip it JMP Done_Right NoRight: MOV _COL, LEFT_LIM_HEX CALL MOVE_DOWN Done_Right: CALL SET_POS POP BX POP AX RET MOVE_RIGHT_HEX ENDP ;----------------------------------------------------------------- ;write the nibble at current memory position ;----------------------------------------------------------------- WRITE_IT_HEX PROC NEAR PUSH ES ;save registers PUSH SI PUSH AX PUSH BX PUSH CX PUSH DX MOV ES, START_SEGMENT ;get working address MOV BX, START_OFFSET CALL NORMALIZE PUSH AX MOV AL, _ROW ;compute offset from XOR AH, AH ;start address DEC AX MOV DL, 16 MUL DL MOV SI, AX MOV AL, _COL SUB AL, LEFT_LIM_HEX XOR AH, AH MOV DL, 3 DIV DL PUSH AX XOR AH, AH ADD SI, AX MOV DL, BYTE PTR ES:[BX][SI];get the value at this offset POP AX CMP AH, 0 POP AX JNE Do_RightNibble MOV CL, 4 SHL AL, CL AND AL, 0F0h AND DL, 0Fh JMP Or_It Do_RightNibble: AND AL, 0Fh AND DL, 0F0h Or_It: OR DL, AL ;modify it MOV BYTE PTR ES:[BX][SI], DL;store it POP DX POP CX POP BX POP AX POP SI POP ES CALL BODY ;display new value CALL MOVE_RIGHT_HEX ;go to next nibble RET WRITE_IT_HEX ENDP ;----------------------------------------------------------------- ;edit memory displayed by the current screen - hexa ;----------------------------------------------------------------- EDIT_HEX PROC NEAR CALL BEGIN_EDIT MOV _COL, LEFT_LIM_HEX ;set cursor pos line 2 col 17 CALL SET_POS GetNextHex: CALL GETKEY ;wait for a key CMP AH, 1 ;if escape then exit JE Exit_EditH CMP AH, U_ARR ;up arrow ? JNE TestDown CALL MOVE_UP ;yes go up JMP GetNextHex TestDown: CMP AH, D_ARR ;down arrow ? JNE TestLeft CALL MOVE_DOWN ;yes go down JMP GetNextHex TestLeft: CMP AH, L_ARR ;left arrow ? JNE TestRight CALL MOVE_LEFT_HEX ;yes go left JMP GetNextHex TestRight: CMP AH, R_ARR ;right arrow ? JNE TestDigit1 CALL MOVE_RIGHT_HEX ;yes go right JMP GetNextHex TestDigit1: CMP AL, "0" ;1-0 digit ? JL GetNextHex CMP AL, "9" JG TestDigit2 SUB AL, "0" CALL WRITE_IT_HEX ;yes write it JMP GetNextHex TestDigit2: AND AL, 0DFH ;make all ascii caps CMP AL, "A" ;A-F digit ? JL GetNextHex CMP AL, "F" JG GetNextHex SUB AL, "7" CALL WRITE_IT_HEX ;yes write it JMP GetNextHex ;loop until escape Exit_EditH: CALL CURSOR_OFF RET EDIT_HEX ENDP ;----------------------------------------------------------------- ;move cursor left one col and wrap - ascii ;----------------------------------------------------------------- MOVE_LEFT_ASC PROC NEAR CMP _COL, LEFT_LIM_ASC ;need to wrap ? JE NoLeftAsc ;yes DEC _COL JMP Done_Left_Asc NoLeftAsc: MOV _COL, RIGHT_LIM_ASC CALL MOVE_UP Done_Left_Asc: CALL SET_POS RET MOVE_LEFT_ASC ENDP ;----------------------------------------------------------------- ;move cursor right one col and wrap - ascii ;----------------------------------------------------------------- MOVE_RIGHT_ASC PROC NEAR CMP _COL, RIGHT_LIM_ASC ;need to wrap ? JE NoRightAsc ;yes INC _COL JMP Done_Right_Asc NoRightAsc: MOV _COL, LEFT_LIM_ASC CALL MOVE_DOWN Done_Right_Asc: CALL SET_POS RET MOVE_RIGHT_ASC ENDP ;----------------------------------------------------------------- ;write the character at current memory position ;----------------------------------------------------------------- WRITE_IT_ASC PROC NEAR PUSH ES ;save registers PUSH SI PUSH BX PUSH DX PUSH AX MOV ES, START_SEGMENT ;get working address MOV BX, START_OFFSET CALL NORMALIZE MOV AL, _ROW ;compute offset from XOR AH, AH ;start address DEC AX MOV DL, 16 MUL DL MOV SI, AX MOV AL, _COL SUB AL, LEFT_LIM_ASC XOR AH, AH ADD SI, AX POP AX MOV BYTE PTR ES:[BX][SI], AL CALL BODY ;display new value CALL MOVE_RIGHT_ASC ;go to next nibble POP DX POP BX POP SI POP ES RET WRITE_IT_ASC ENDP ;----------------------------------------------------------------- ;edit memory displayed by the current screen - ascii ;----------------------------------------------------------------- EDIT_ASC PROC NEAR CALL BEGIN_EDIT MOV _COL, LEFT_LIM_ASC ;set cursor pos line 2 col 17 CALL SET_POS GetNextAsc: CALL GETKEY ;wait for a key CMP AH, 1 ;if escape then exit JE Exit_EditA CMP AH, U_ARR ;up arrow ? JNE TestDownAsc CALL MOVE_UP ;yes go up JMP GetNextAsc TestDownAsc: CMP AH, D_ARR ;down arrow ? JNE TestLeftAsc CALL MOVE_DOWN ;yes go down JMP GetNextAsc TestLeftAsc: CMP AH, L_ARR ;left arrow ? JNE TestRightAsc CALL MOVE_LEFT_ASC ;yes go left JMP GetNextAsc TestRightAsc: CMP AH, R_ARR ;right arrow ? JNE WriteChar CALL MOVE_RIGHT_ASC ;yes go right JMP GetNextAsc WriteChar: CMP AL, 0 JE Exit_EditA CALL WRITE_IT_ASC ;otherwise write it JMP GetNextAsc Exit_EditA: CALL CURSOR_OFF RET EDIT_ASC ENDP ;----------------------------------------------------------------- ;choose between ascii or hexadecimal edition ;----------------------------------------------------------------- EDIT PROC NEAR PUSH AX PUSH BX PUSH SI CALL CLEAR_LAST_LINE MOV AX,24 ;last row XOR BX,BX ;column 0 MOV SI,OFFSET EDIT_PROMPT ;edit message MOV TEXT_ATTR, BOTLINE_ATTR CALL DISPLAY_STRING ;show it GetChoice: CALL GETKEY CMP AH, 1 ;if escape then exit JE Exit_Edit AND AL, 0DFH ;make all ascii caps CMP AL, "H" JNE AsciiTest CALL EDIT_HEX JMP Exit_Edit AsciiTest: CMP AL, "A" JNE GetChoice CALL EDIT_ASC Exit_Edit: POP SI POP BX POP AX RET EDIT ENDP ;----------------------------------------------------------------- ;ascii search routine ;----------------------------------------------------------------- ASCII_SEARCH PROC NEAR CALL CLEAR_LAST_LINE ;clear line for input MOV AX,24 ;last row XOR BX,BX ;first col MOV SI,OFFSET ASCII_SEARCH_PROMPT ;prompt MOV TEXT_ATTR, PROMPT_ATTR ;modified P.Philippot CALL DISPLAY_STRING ;show the prompt CALL STRLEN ;find out how long prompt is MOV DL,CL ;dl = col after prompt MOV DH,24 ;dx = row col MOV SI,OFFSET ASCII_SEARCH_AREA ; MOV CX,20 ;size of the string CALL CLEAR_BUF MOV DI,OFFSET CHAR_SIEVE ;pointer to sieve MOV BX," " ;get ;dx=row col,cx=size,bl=replace,si=prompt,di=sieve CALL INPUT MOV SI,OFFSET ASCII_SEARCH_AREA ;pointer to search string MOV LAST_SEARCH_STRING,SI ;save ptr to str for next CALL STRLEN ;how long? MOV LAST_STRING_LENGTH,CX ;save length for next JCXZ NO_SEARCH ;if not, dont search CALL SEARCH_MEM ;cx=length si=string NO_SEARCH: RET ;that's all ASCII_SEARCH ENDP ;----------------------------------------------------------------- ;find next occurrence ;----------------------------------------------------------------- NEXT_SEARCH PROC NEAR MOV SI,LAST_SEARCH_STRING ;get address of last string MOV CX,LAST_STRING_LENGTH JCXZ NO_NEXT ;dont search ADD START_OFFSET,1 ;move over one to start JNC NOS_WRAP ;if it causes wrap, ADD START_SEGMENT,1000H ;wrap segment NOS_WRAP: CALL SEARCH_MEM ;search for next string NO_NEXT: RET ;that's all NEXT_SEARCH ENDP ;----------------------------------------------------------------- ;hex search routine ;----------------------------------------------------------------- HEX_SEARCH PROC NEAR CALL CLEAR_LAST_LINE ;clear line for input MOV SI,OFFSET HEX_SEARCH_PROMPT ;prompt MOV AX,24 ;last row XOR BX,BX ;first col MOV TEXT_ATTR, PROMPT_ATTR ;modified P.Philippot CALL DISPLAY_STRING ;show the prompt CALL STRLEN ;find out how long prompt is MOV DL,CL ;dl = col after prompt MOV DH,24 ;dx = row col MOV SI,OFFSET HEX_SEARCH_AREA ; MOV CX,20 ;size of the string CALL CLEAR_BUF MOV DI,OFFSET HEX_SIEVE ;pointer to sieve MOV BX," " ;replacement char ;dx=row col,cx=size,bx=replace,si=prompt,di=sieve CALL INPUT MOV SI,OFFSET HEX_SEARCH_AREA ;pointer to search string CALL STRLEN CMP CL,1 ;must be at least two digits JBE NO_SEARCH ;otherwise search fails MOV LAST_SEARCH_STRING,SI ;save it MOV LAST_STRING_LENGTH,CX ;save length CALL ELIMINATE_BLANKS ;eliminate blanks in input CALL CONVERT_ASCII_HEX_TO_HEX_STRING ;string into hex MOV LAST_STRING_LENGTH,CX ;save length CALL SEARCH_MEM ;find it NOSEARCH: RET ;that's all HEX_SEARCH ENDP ;----------------------------------------------------------------- ;clear ds:[si] with (cx) spaces ;----------------------------------------------------------------- CLEAR_BUF PROC NEAR PUSH CX PUSH SI CLEARIT: MOV BYTE PTR [SI]," " INC SI LOOP CLEARIT POP SI POP CX RET CLEAR_BUF ENDP ;----------------------------------------------------------------- ;translate ascii hex string to binary string, return size in cx ;----------------------------------------------------------------- CONVERT_ASCII_HEX_TO_HEX_STRING PROC NEAR PUSH SI ;save si for use in main MOV DI,SI ;duplicate si MOV BX,SI ;for later use NEXTC: LODSW ;get two ascii digits OR AL,AL ;are we at the end JZ C_EXIT ;if so, string is converted OR AH,AH ;in case wrong # digits JZ C_EXIT ;string is converted CALL ASCII_HEX_TO_HEX ;translate ascii to binary STOSB ;put back in string JMP NEXTC ;get next two characters C_EXIT: XOR AL,AL ;clear al STOSB ;put terminator after this SUB DI,BX ;find out how many bytes LEA CX,[DI-1] ;we have converted POP SI ;restore important register RET ;that's all CONVERT_ASCII_HEX_TO_HEX_STRING ENDP ;----------------------------------------------------------------- ;close up blanks in a string ;----------------------------------------------------------------- ELIMINATE_BLANKS PROC NEAR PUSH SI ;save si for main PUSH DS ;set ds:si and es:di to same POP ES MOV DI,SI NEXT_SQ: LODSB ;get character CMP AL," " ;if space JZ NEXT_SQ ;skip it STOSB ;otherwise store it OR AL,AL ;if zero JNZ NEXT_SQ ;done whole string SQUOZE: POP SI ;restore important register RET ;that's all ELIMINATE_BLANKS ENDP ;----------------------------------------------------------------- ;go to command ;----------------------------------------------------------------- GOTO PROC NEAR CALL CLEAR_LAST_LINE ;clear line for input MOV AX,24 ;row XOR BX,BX ;col MOV SI,OFFSET START_DISPLAY ;prompt MOV TEXT_ATTR, PROMPT_ATTR ;modified P.Philippot CALL DISPLAY_STRING ;show it MOV DX,180FH ;row col MOV SI,OFFSET START_DISPLAY+15 ;destination MOV CX,9 ;size MOV DI,OFFSET ADDR_SIEVE ;sieve MOV BX,"0" ;replace char ;dx=row col,cx=size,bx=replace,si=prompt,di=sieve CALL INPUT MOV SI,OFFSET START_DISPLAY+15 ;ascii address MOV DI,OFFSET START_SEGMENT ;destination CALL CONVERT_ADDR ;32 bit ascii address to ptr CLC RET GOTO ENDP ;----------------------------------------------------------------- ;convert ascii to binary segment and offset ; si=ascii di= pointer to destination ;----------------------------------------------------------------- CONVERT_ADDR PROC NEAR PUSH DS POP ES ;set es for stos INC DI CALL CONVERT_BYTE ;segment CALL CONVERT_BYTE INC SI ;colon CALL CONVERT_BYTE ;offset CALL CONVERT_BYTE RET ;that's all CONVERT_ADDR ENDP ;----------------------------------------------------------------- CONVERT_BYTE PROC NEAR LODSW ;get two chars CALL ASCII_HEX_TO_HEX ;make hex MOV [DI],AL ;put in destination DEC DI ;set up for next character RET ;that's all CONVERT_BYTE ENDP ;----------------------------------------------------------------- ;display main screen ;----------------------------------------------------------------- BODY PROC NEAR CALL TURN_OFF_CRT ;turn off monitor if necessary PUSH BP ;use the MOV BP,SP ;stack SUB SP,8 ;for temporary variables PUSH DS ;save ds for main routine LES BX,DWORD PTR START_OFFSET ;get start pointer MOV [BP-2],BX ;save on stack MOV [BP-4],ES ;for later use CALL NORMALIZE ;change es:bx so 10h <= bx >=0 MOV [BP-6],BX ;save value on stack MOV [BP-8],ES ;for later use MOV DS,[BP-4] ;get pointer MOV SI,[BP-2] ;to memory to display MOV CS:ROW,0 ;initialize row counter NEXT_LINE: INC CS:ROW ;next display row MOV AX,CS:ROW ;row XOR BX,BX ;col CALL CALC_SCRN_ADDR ;get es:di for that address MOV CX,[BP-8] ;hi part of norm 20 bit desc CALL WORD_OUT ;print it INC WORD PTR[BP-8] ;add 1 to seg = 16 bytes MOV AL,[BP-6] ;get lo part CALL HEX_TO_ASCII_HEX ;convert to ascii XCHG AL,AH ;lowest significant nybble CALL CHAR_OUT ;print lo part of 'ABS' value CALL SPACE_OUT ;put separator MOV CX,[BP-4] ;segment being displayed CALL WORD_OUT ;print it MOV AL,":" ;followed CALL CHAR_OUT ;by a colon MOV CX,[BP-2] ;offset this line CALL WORD_SPACE ;print offset/space MOV CX,16 ;# characters to print MOV DX,SI ;save ptr to present line HEX_PART: LODSB ;get character CALL BYTE_OUT ;print two hex nybbles CALL SPACE_OUT ;print space LOOP HEX_PART ;all 16 hex digits MOV SI,DX ;get ptr to present line MOV CX,16 ;all 16 hex digits MOV AL,ASCII_ATTR ;modified P.Philippot ASCII_PART: MOVSB ;print the ascii part STOSB ;reverse attribute on it LOOP ASCII_PART ;all 16 ascii chars ADD WORD PTR[BP-6],10H ;'ABS' + 16 ADC WORD PTR[BP-8],0 ; ADD WORD PTR[BP-2],10H ;'SEG:OFF' + 16 JNC NO_WRAP ;if it wraps ADD WORD PTR[BP-4],1000H ;wrap the segment MOV DS,[BP-4] ;get the data segment NO_WRAP: CMP CS:ROW,23 ;if not completely done JB NEXT_LINE ;do another POP DS ;restore ds for main routine ADD SP,8 ;clean off temporary variables POP BP ;restore bp CALL TURN_ON_CRT ;turn on monitor if necessary RET ;that's all BODY ENDP WORD_SPACE LABEL NEAR CALL WORD_OUT ;output two nybbles from cx SPACE_OUT LABEL NEAR ;then MOV AL," " ;output a space JMP SHORT CHAR_OUT WORD_OUT LABEL NEAR MOV AL,CH ;get high nybble CALL BYTE_OUT ;print it MOV AL,CL ;get low nybble BYTE_OUT LABEL NEAR CALL HEX_TO_ASCII_HEX ;cvt hex to two char nybbles STOSB ;print highest order nybble INC DI ;skip attribute MOV AL,AH ;get low order nybble CHAR_OUT LABEL NEAR STOSB ;print it INC DI ;skip attribute RET ;that's all END_MINUS_START PROC NEAR LES BX,DWORD PTR START_OFFSET ;get end segment CALL NORMALIZE ;change es:bx so 10h <= bx >=0 MOV AX,ES ;save normalized result MOV CX,BX ;for later use LES BX,DWORD PTR END_OFFSET ;get end address CALL NORMALIZE ;change es:bx so 10h <= bx >=0 MOV DX,ES ;get end segment SUB DX,AX ;calculate segments to search MOV SEARCH_SEGMENTS,DX MOV SEARCH_BYTES,BX ;# bytes in final segment MOV ES,AX ;set es:bx to MOV BX,CX ;start address RET ;that's all END_MINUS_START ENDP ;----------------------------------------------------------------- ;make 20 bit pointer in es:bx from segment:offset in es:bx ;----------------------------------------------------------------- NORMALIZE PROC NEAR PUSH AX ;save these registers PUSH CX ;for main routine PUSH DX ; MOV AX,BX ;get the offset MOV CL,4 ;make into SHR AX,CL ;number of paragraphs MOV DX,ES ;get segment ADD DX,AX ;add in number of paragraphs MOV ES,DX ;back into segment SHL AX,CL ;calc offset into segment SUB BX,AX ;paras - paras mod 16 POP DX ;retstore registers POP CX ;for main routine POP AX RET ;that's all NORMALIZE ENDP ;----------------------------------------------------------------- ;si = string cx = string_size ;search for match of string beginning at start_segment ;----------------------------------------------------------------- SEARCH_MEM PROC NEAR MOV DI,CX ;save string size CALL END_MINUS_START ;calculate search length LOOK_AGAIN: CMP SEARCH_SEGMENTS,1000H ;more than or equal 64k? JAE MORE_THAN_ENOUGH ;if so, search 64k MOV AX,SEARCH_SEGMENTS ;otherwise, get what's left MOV CL,4 ; SHL AX,CL ;segs*16 = bytes to search ADD AX,SEARCH_BYTES ;add in the last few bytes JMP SHORT LOOK ;and go look MORE_THAN_ENOUGH: MOV AX,-1 ;64k search LOOK: SUB AX,BX ;subtract initial offset JC SEARCH_NOT_FOUND ;offset < search size? SUB AX,DI ;subtract off string size JBE SEARCH_NOT_FOUND ;less than search size? CMP AX,DI ;amount left to search JB SEARCH_NOT_FOUND ;less than search size? MOV DX,AX ;dx gets search size MOV CL,4 ; SHR DX,CL ;number of segments to search SUB SEARCH_SEGMENTS,DX ;decrease the amount to search ;si = string di = string size CALL SEARCH ;es:bx=ptr,ax=bytes to search JZ SEARCH_FOUND ;if zero flag, string is found ADD AX,1 ;next character after fail MOV BX,AX ;into es:bx JNC NOWR ;if offset rolls over MOV AX,ES ;add 64k ADD AX,1000H ;to the MOV ES,AX ;offset NOWR: CALL NORMALIZE ;set to start at the top of JMP LOOK_AGAIN ;a new segment SEARCH_NOT_FOUND: XOR AX,AX ;start over MOV ES,AX CMP AL,1 ;clear zero flag SEARCH_FOUND: MOV START_SEGMENT,ES ;set page MOV START_OFFSET,AX ;address of found string RET ;that's all SEARCH_MEM ENDP ;----------------------------------------------------------------- ;si = string di = string size es:bx = pointer to buffer to search ;ax = number of bytes in buffer to search. Zero flag set if found ;----------------------------------------------------------------- SEARCH PROC NEAR ;si points at string PUSH BX PUSH DI PUSH SI XCHG BX,DI ;string size, ptr to data area MOV CX,AX ;# chars in segment to search BYTE_ADD: LODSB ;char for first part of search NEXT_SRCH: REPNZ SCASB ;is first char in string in buffer JNZ NOT_FOUND ;if not, no match PUSH DI ;save against cmpsb PUSH SI PUSH CX LEA CX,[BX-1] ;# chars in string - 1 JCXZ ONE_CHAR ;if one char search, we have found it REP CMPSB ;otherwise compare rest of string ONE_CHAR: POP CX ;restore for next cmpsb POP SI POP DI JNZ NEXT_SRCH ;if zr = 0 then string not found NOT_FOUND: LEA AX,[DI-1] ;ptr to last first character found POP SI POP DI POP BX RET ;that's all SEARCH ENDP ;------------------------------------------------------------------ ;dx=row:col,cx=max len,bx=replace character,si=prompt,di=sieve ;------------------------------------------------------------------ INPUT PROC NEAR PUSH BP ;create stack frame MOV BP,SP SUB SP,6 CALL CURSOR_ON MOV [BP-2],CX ;save size of destination MOV [BP-4],SI MOV [BP-6],DX XOR CX,CX ;clear count of chars entered NEXT_DISPLAY: PUSH BX ;save replace char PUSH SI MOV AL,[BP-5] ;row CBW ;into ax MOV BL,[BP-6] ;col XOR BH,BH ;into bx MOV SI,[BP-4] CALL DISPLAY_STRING ;show string at si POP SI POP BX ;restore replace char PUSH DS ;set up string addressing POP ES NEXT_KEY: CMP BYTE PTR[SI],":" ;skip colon in destination JNZ NOT_COLON INC CX ;next count INC DL ;next col INC SI ;point to next char NOT_COLON: CALL SETPOS ;set cursor position CALL GETKEY ;get next key CMP AH,1 ;if scan = 1 JZ END_OF_INPUT;then it's esc CMP AH,1CH ;if scan = 1ch JZ END_OF_INPUT ;then it's carriage return CMP AH,L_ARR ;if it's left arrow JZ BACK_SPACE ;or CMP AH,0EH ;if it's backspace key JNZ NOT_BACK_SPACE ;then back up BACK_SPACE: JCXZ NEXT_KEY ;if count 0 can't back up DEC CX ;decrement count DEC DL ;decrement column DEC SI ;decrement pointer to chars CMP BYTE PTR[SI],":" ;if pointer is to colon, JZ BACK_SPACE ;then back up again MOV BYTE PTR[SI],BL ;put replace character in JMP NEXT_DISPLAY ;show line again NOT_BACK_SPACE: CMP CX,[BP-2] ;is count = max count JZ NEXT_KEY ;if so, can't put in buffer NEXT_INPUT: CALL VERIFY ;ax = char di = sieve JNZ NEXT_KEY ;if illegal char get new key MOV [SI],AL ;otherwize put in buffer INC CX ;next count INC SI ;pointer to next char INC DL ;next column JMP NEXT_DISPLAY ;show line again END_OF_INPUT: CMP BL,"0" ;if replace char is "0" JZ NO_ZERO ;dont put terminator in MOV BYTE PTR[SI],0 ;terminate string NO_ZERO: CALL CURSOR_OFF ADD SP,6 ;clean off stack POP BP ; RET ;that's all INPUT ENDP GETKEY PROC NEAR XOR AH,AH ;getkey function number INT 16H ;go get a key RET ;return it GETKEY ENDP ;------------------------------------------------------------------ ;ax = row bx = col displays string at ds:si ;------------------------------------------------------------------ DISPLAY_STRING PROC NEAR PUSH SI ;save si for main routines PUSH DI CALL CALC_SCRN_ADDR ;get es:di for row col MOV AH,TEXT_ATTR ;modified P.Philippot CALL WAIT_VERT NEXT_CHAR: LODSB ;get char from string OR AL,AL ;test for zero JZ LAST_CHAR ;if zero, string has been printed STOSW ;put char and attribute on screen JMP NEXT_CHAR ;until string has been printed LAST_CHAR: POP DI POP SI ;restore si for main routines RET ;that's all DISPLAY_STRING ENDP ;------------------------------------------------------------------ ;ax = row bx= col, returns es:di pointing to the screen address ;------------------------------------------------------------------ CALC_SCRN_ADDR PROC NEAR PUSH CX PUSH DX ;mul destroys dx PUSH AX ;save ax for later MOV ES,CS:BIOS_SEG ;into es MOV AX,0B800H ;screen seg = b800h CMP ES:BYTE PTR[49H],7 ;if 40:49 == 7 JNZ COLOR ;then MOV AH,0B0H ;screen seg = b000h COLOR: MOV ES,AX ;into es POP CX ;get row MOV AX,160 ;160 bytes to a row of text ADD AX,CS:DIFF ;# characters > 80 ADD AX,CS:DIFF ;# of attribute bytes > 80 MUL CX ;row * 160 + diff*2 ADD AX,BX ;+col ADD AX,BX ;row*160 + col*2 MOV DI,AX ;es:di points to right address POP DX ;restore dx POP CX RET ;that's all CALC_SCRN_ADDR ENDP ;------------------------------------------------------------------ ;ax = char di = sieve ;------------------------------------------------------------------ VERIFY PROC NEAR PUSH CX ;save registers for main routines PUSH DI PUSH SI PUSH DS POP ES MOV SI,DI ;si = sieve address CALL STRLEN ;how many chars in sieve (cx) JCXZ ANY_KEY ;get key if no chars in sieve CMP AL,"A" ;if lower case JB NOT_SMALL ; AND AL,0DFH ;make upper case NOT_SMALL: REPNZ SCASB ;search for char in the sieve ANY_KEY: ;set zero flag to indicate it POP SI ;restore registers POP DI POP CX RET ;that's all VERIFY ENDP ;---------------------------------------------------------------------- STRLEN PROC NEAR PUSH SI ;save si for main routines PUSH AX MOV CX,-1 ;count for string length NEXTS: INC CX ;next count LODSB ;next char OR AL,AL ;is it a zero JNZ NEXTS ;if not get next char POP AX POP SI ;restore si for main routines RET ;thats all STRLEN ENDP ;------------------------------------------------------------------ ;input: al = ascii lsb ah = ascii msb ; example: if hex is '3F', ah = '3' al = 'F' result: al = 3Fh ;output: al = hex byte ;------------------------------------------------------------------ ASCII_HEX_TO_HEX PROC NEAR TEST AH,40H ;if "A" - "F" JZ AH_EXIT ; SUB AH,"A"-10 ;make 10-15 AH_EXIT: TEST AL,40H ;if "A" - "F" JZ AL_EXIT ; SUB AL,"A"-10 ;make 10-15 AL_EXIT: AND AX,0F0FH ;if "0" - "9" make 0-9 SHL AL,1 ; SHL AL,1 ; SHL AL,1 ; SHL AL,1 ; OR AL,AH ;combine msn and lsn RET ;that's all ASCII_HEX_TO_HEX ENDP ;------------------------------------------------------------------ ;input: al = char to be translated: ; example: if hex is '3F', al = '3' ah = 'F' ;output: al = msb of translation, ah = lsb of translation ;------------------------------------------------------------------ HEX_TO_ASCII_HEX PROC NEAR DB 0D4H,10H ;div AL/16-remainder in al OR AX,3030H ;make ascii CMP AL,"9" JBE ALEXIT ADD AL,7 ;if a - f make "A" - "F" ALEXIT: CMP AH,"9" JBE AHEXIT ADD AH,7 ;if a - f make "A" - "F" AHEXIT: XCHG AL,AH RET ;that's all HEX_TO_ASCII_HEX ENDP LAST_BYTE LABEL BYTE ;marks end of resident code and ;start of memory used to save screen INSTALLED_SEGMENT DW 0 DISABLED DB CR,LF,"RAMVIEW IS DISABLED",CR,LF,"$" ENABLED DB CR,LF,"RAMVIEW IS RE-ENABLED",CR,LF,"$" ;------------------------------------------------------------------ ;determine if vectors have changed since program was installed ;------------------------------------------------------------------ HOOKED_VECTORS_SAME? PROC NEAR MOV CX,INSTALLED_SEGMENT ;get executing segment XOR AX,AX ;interrupt table segment MOV ES,AX ;into the extra segment CMP CX,ES:[10H*4+2] ;see if int 10h points at us JNZ VECTOR_CHANGED CMP CX,ES:[9*4+2] ;see if int 9 points at us VECTOR_CHANGED: RET HOOKED_VECTORS_SAME? ENDP ;------------------------------------------------------------------ ;determine if program is already installed ;------------------------------------------------------------------ PROGRAM_ALREADY_IN PROC NEAR NOT WORD PTR START ;only srch for active copy MOV START_SEGMENT,60H ;start after dos MOV START_OFFSET,0 ; MOV END_SEGMENT,CS ;stop looking before you MOV END_OFFSET,0 ; get to this program MOV SI,OFFSET START ;start at modified byte MOV CX,25 ;enough of a match CALL SEARCH_MEM ;use our search PUSHF ;save zr flag MOV AX,START_SEGMENT ;get address of find MOV INSTALLED_SEGMENT,AX ;save in installed address MOV AX,START_OFFSET MOV CL,4 SHR AX,CL SUB AX,10H ;adjust for psp ADD INSTALLED_SEGMENT,AX MOV START_SEGMENT,0 ;reset starting address MOV START_OFFSET,0 MOV END_OFFSET,0FH ;reset ending address MOV END_SEGMENT,0FFFFH POPF ;restore flgs from search RET PROGRAM_ALREADY_IN ENDP ;------------------------------------------------------------------ ;uninstall routines ;------------------------------------------------------------------ UNINSTALL PROC NEAR CALL HOOKED_VECTORS_SAME? ;if all vectors still hooked JZ UNINSTALL_OK ;go ahead and dis installed NOT WORD PTR START MOV ES,INSTALLED_SEGMENT ;else, change the disable flag NOT ES:DISABLE ;in the installed program MOV DX,OFFSET ENABLED ;get the message corresponding CMP ES:DISABLE,-1 ;to the action that causes JNZ ITS_DISABLED ; MOV DX,OFFSET DISABLED ; ITS_DISABLED: ; MOV AH,9 ;and display that message INT 21H JMP SHORT UNINSTALL_EXIT ;all done here. UNINSTALL_OK: MOV ES,INSTALLED_SEGMENT ;get resident prog's psp MOV DX,ES:WORD PTR ADDR_INT9H ;put back int 9 vector MOV DS,ES:WORD PTR ADDR_INT9H+2 MOV AH,25H MOV AL,9 INT 21H MOV DX,ES:WORD PTR ADDR_INT10H ;restore int 10h vector MOV DS,ES:WORD PTR ADDR_INT10H+2 MOV AH,25H MOV AL,10H INT 21H PUSH ES MOV ES,ES:[2CH] ;get segment of environment MOV AH,49H ;belonging to resident program INT 21H ;free it POP ES MOV AH,49H ;free memory block of program INT 21H PUSH CS POP DS ;get back our data segment MOV DX,OFFSET UNINSTALLED MOV AH,9 INT 21H ;for whom it may concern UNINSTALL_EXIT: RET UNINSTALL ENDP ;---------------------------------------------------------------------- INSTALL PROC NEAR MOV CL,9 ;link vector 9 MOV SI,OFFSET ADDR_INT9H MOV DI,OFFSET INT9H CALL INSTALL_VECTOR MOV CL,10H ;link vector 10h MOV SI,OFFSET ADDR_INT10H MOV DI,OFFSET INT10H CALL INSTALL_VECTOR RET INSTALL ENDP ;---------------------------------------------------------------------- INSTALL_VECTOR PROC NEAR MOV AL,CL ;get vector number MOV AH,35H ;get interrupt vector INT 21H ; MOV [SI],BX ;save interrupt vector MOV [SI+2],ES ; MOV DX,DI ;get replacement address MOV AH,25H ;set vector address MOV AL,CL ;for vector INT 21H RET INSTALL_VECTOR ENDP _TEXT ENDS END START