home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pcmag
/
vol7n14.arc
/
RAMVIEW.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-08-01
|
38KB
|
1,276 lines
;----------------------------------------------------------------
; RAMVIEW: A memory-resident memory-viewer.
; Frank Dever & David Thomas, WindowDOS Associates
;----------------------------------------------------------------
; 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 8 ;Alt
HOTKEY EQU 13H ;R
CR EQU 0DH
LF EQU 0AH
_TEXT SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT
ORG 100H
START:
JMP RES
INSTALLED DB "RAMVIEW 1.00 (c) 1988, Ziff Communications Co."
DB CR,LF,"PC Magazine ",254," Frank Dever & David Thomas"
DB CR,LF,"Hotkey is Alt-R",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 (H)ex Search (A)scii Search (N)ext"
DB " ",24," ",25," PgUp PgDn Home End Esc ",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
;-----------------------------------------------------------------
; 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
RET 2 ;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
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
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 AX,0720H ;space with normal attribute
MOV BX,24
CLEAR_NEXT_LINE:
MOV CX,80
REP STOSW ;words
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 AX,0720H ;normal attribute spaces
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
JBE 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 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
;-----------------------------------------------------------------
;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
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
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
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,70H ;reverse the ascii part
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,7 ;get normal attribute
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