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 >
Assembly Source File  |  1988-08-01  |  38KB  |  1,276 lines

  1. ;----------------------------------------------------------------
  2. ; RAMVIEW: A memory-resident memory-viewer.
  3. ; Frank Dever & David Thomas, WindowDOS Associates
  4. ;----------------------------------------------------------------
  5. ; scan codes
  6. ;----------------------------------------------------------------
  7. U_ARR        EQU    72            ;up arrow
  8. D_ARR        EQU    80            ;down arrow
  9. PGUP        EQU    73            ;page up
  10. PGDN        EQU    81            ;page down
  11. L_ARR        EQU    75            ;left arrow
  12. R_ARR        EQU    77            ;right arrow
  13. HOME        EQU    71            ;home
  14. END_KEY        EQU    79            ;end
  15. INT9_BUSY    EQU    1
  16. INT10_BUSY    EQU    2
  17. INT16_BUSY    EQU    4
  18. SHIFT_MASK    EQU    8            ;Alt
  19. HOTKEY        EQU    13H            ;R
  20.  
  21. CR        EQU    0DH
  22. LF        EQU    0AH
  23.  
  24. _TEXT    SEGMENT    PARA    PUBLIC    'CODE'
  25.     ASSUME    CS:_TEXT,DS:_TEXT
  26.         ORG 100H
  27. START:
  28.         JMP    RES
  29.  
  30. INSTALLED    DB      "RAMVIEW 1.00 (c) 1988, Ziff Communications Co."
  31.                 DB      CR,LF,"PC Magazine ",254," Frank Dever & David Thomas"
  32.                 DB      CR,LF,"Hotkey is Alt-R",CR,LF,"$",1AH
  33. UNINSTALLED     DB    "RAMVIEW Uninstalled",CR,LF,"$"
  34.  
  35. DISABLE         DB    0     ;flag for inapropriate de-installation
  36.  
  37. LABEL0      DB    " ABS  SEG  OFF   0  1  2  3  4  5  6  7"
  38.         DB    "  8  9  A  B  C  D  E  F       ASCII",0
  39.  
  40. START_DISPLAY    DB    " GOTO ADDRESS: 0000:0000",0
  41.  
  42. COMMANDLINE    DB    "(G)oto   (H)ex Search   (A)scii Search   (N)ext"
  43.         DB    "     ",24," ",25," PgUp PgDn Home End Esc ",0
  44.  
  45. CURSOR_POS    DW    0
  46. CURSOR_TYPE    DW    0607H            ;for turning cursor on/off
  47. START_OFFSET        DW    0            ;top addr shown on screen
  48. START_SEGMENT       DW    0
  49. END_OFFSET          DW    0FH            ;last segment in search
  50. END_SEGMENT         DW    0FFFFH            ;fixed to ffff:f
  51. SEARCH_SEGMENTS     DW    0            ;# segments to search
  52. SEARCH_BYTES        DW    0            ;# bytes left after search
  53. HEX_SIEVE           DB    " "            ;hex with space
  54. ADDR_SIEVE          DB    "01234567890ABCDEF"     ;hex without space
  55. CHAR_SIEVE          DB 0            ;all characters
  56. ASCII_SEARCH_PROMPT    DB "ASCII Search String: ",0   ;ascii search prompt
  57. HEX_SEARCH_PROMPT    DB "HEX Search String: ",0     ;hex search prompt
  58. ASCII_SEARCH_AREA    DB 20 DUP (" "),0              ;ascii search string
  59. HEX_SEARCH_AREA        DB 20 DUP (" "),0    ;hex search string
  60. LAST_SEARCH_STRING  DW 0            ;pointer to last string
  61. LAST_STRING_LENGTH  DW 0            ;last string length
  62. OUR_SS              DW 0
  63. OUR_SP              DW 0
  64. THEIR_SS            DW 0
  65. THEIR_SP            DW 0
  66. ADDR_INT9H          DD 0
  67. ADDR_INT10H         DD 0
  68. BUSY                DB 0
  69. BIOS_SEG            DW 40H
  70. DIFF            DW 0            ;# of chars on a line > 80
  71. ROW                 DW 0            ;display row counter
  72. FLICKER_FREE        DB 0            ;snowy monitor flag
  73.  
  74. ;-----------------------------------------------------------------
  75. ;  code relating to residency
  76. ;-----------------------------------------------------------------
  77. RES        PROC    NEAR
  78.  
  79.         CLD
  80.         CALL    PROGRAM_ALREADY_IN
  81.         JNZ    NOT_IN            ;else, it's ok to install
  82.         CALL    UNINSTALL            
  83.         MOV    AX,4C01H        ;terminate with error code
  84.         INT    21H
  85. NOT_IN:
  86.         MOV    OUR_SS,CS        ;set stack seg
  87.         MOV    OUR_SP,OFFSET LAST_BYTE+4000+256    ; and pointer
  88.         CALL    INSTALL
  89.         MOV    DX,OFFSET INSTALLED    ;already in
  90.         MOV    AH,9
  91.         INT    21H
  92.                         ;program, screen buf, stack
  93.         MOV    DX,(OFFSET LAST_BYTE-OFFSET _TEXT+4000+256+15) SHR 4
  94.         MOV    AX,3100H        ;stay resident
  95.         INT    21H
  96. RES ENDP
  97. ;----------------------------------------------------------------------
  98. INT10H PROC FAR
  99.         OR    CS:BUSY,INT10_BUSY    ;recursion protection
  100.         PUSHF
  101.         CALL    CS:ADDR_INT10H
  102.         PUSHF
  103.         AND    CS:BUSY,NOT(INT10_BUSY)
  104.         POPF
  105.         RET    2            ;preserve flags
  106. INT10H ENDP
  107. ;----------------------------------------------------------------------
  108. INT9H PROC FAR
  109.         STI
  110.         PUSH    AX            ;save working register
  111.         CMP    CS:DISABLE,-1        ;if disabled, do nothing
  112.         JE    NOT_US
  113.         IN    AL,60H            ;get key from keyboard port
  114.         CMP    AL,HOTKEY        ;is it our hotkey?
  115.         JNE    NOT_US            ;if not, exit
  116.         MOV    AH,2            ;otherwise
  117.         INT    16H            ;get shift status
  118.         AND    AL,0FH
  119.         CMP    AL,SHIFT_MASK        ;test the shift status
  120.         JNE    NOT_US            ;if not shift combo, exit
  121.         IN    AL,61H            ;These instructions reset
  122.         MOV    AH,AL            ; the keyboard.
  123.         OR    AL,80H
  124.         OUT    61H,AL
  125.         MOV    AL,AH
  126.         JMP    SHORT $+2        ;I/O delay for fast AT's
  127.         OUT    61H,AL
  128.         CLI                ;Disable interrupts and
  129.         MOV    AL,20H            ;reset the int controller
  130.         OUT    20H,AL
  131.         STI
  132.         CMP    CS:BUSY,0        ;recursion protection
  133.         JNE    WE_ARE_BUSY        ;dont allow re-entrancy
  134.         OR    CS:BUSY,INT9_BUSY    ;set flag for protection
  135.         CALL    ADJUST_FOR_VIDEO_MODE
  136.         JC    CANT_POP_UP
  137.         CALL    MEM            ;call our program
  138. CANT_POP_UP:
  139.         CLI                ;disable kbd momentarily
  140.         AND    CS:BUSY,NOT(INT9_BUSY)    ;reset protection
  141. WE_ARE_BUSY:
  142.         POP    AX            ;restore working register
  143.         IRET                ;return to foreground
  144. NOT_US:
  145.         POP    AX            ;restore working register
  146.         CLI
  147.         JMP    CS:ADDR_INT9H        ;let ROM code do its work
  148. INT9H ENDP
  149.  
  150. ;-----------------------------------------------------------------
  151. ;check for text modes and set offset
  152. ;for lines > than 80 characters in length
  153. ;-----------------------------------------------------------------
  154. ADJUST_FOR_VIDEO_MODE PROC NEAR
  155.  
  156.         PUSH    BX
  157.         MOV    AH,15            ;get present mode
  158.         INT    10H
  159.  
  160.         CMP    AH,80
  161.         JB    BAD_MODE
  162.  
  163.         MOV    BYTE PTR CS:DIFF,AH    ;calc the # of chars > 80
  164.         SUB    CS:BYTE PTR DIFF,80    ;on the line & save in diff
  165.         CMP    AL,7            ;7 is mono
  166.         JNE    TRY_COLOR
  167. MODE_OK:
  168.         CLC
  169.         POP    BX
  170.         RET
  171. TRY_COLOR:
  172.         CMP    AL,3            ;3 is color 80x25
  173.         JBE    MODE_OK
  174. BAD_MODE:
  175.         STC                ;not good mode
  176.         POP    BX
  177.         RET
  178.  
  179. ADJUST_FOR_VIDEO_MODE ENDP
  180.  
  181. ;-----------------------------------------------------------------
  182. ;main routine called by pressing hot key
  183. ;-----------------------------------------------------------------
  184. MEM PROC NEAR
  185.         CALL    SWAPIN            ;new stack
  186.         MOV    AX,CS            ;our data segment
  187.         MOV    DS,AX
  188.         CALL    FLICKER            ;determine presence of snow
  189.         CALL    SAVE_CURSOR        ;save cursor
  190.         CALL    CURSOR_OFF        ;turn cursor off
  191.         CALL    SAVE_SCREEN        ;save screen
  192.         CALL    CLEAR_SCREEN        ;clear screen
  193.         CALL    PROGRAM            ;do our program
  194.         CALL    RESTORE_SCREEN        ;put screen back
  195.         CALL    CURSOR_ON        ;turn cursor on
  196.         CALL    RESTORE_CURSOR
  197.         CALL    SWAPOUT            ;put stack back
  198.         RET                ;that's all
  199. MEM ENDP
  200.  
  201. PROGRAM PROC NEAR
  202.         XOR    AX,AX            ;row 0
  203.         MOV    BX,AX            ;col 0
  204.         MOV    SI,OFFSET LABEL0    ;bottom line
  205.         CALL    DISPLAY_STRING        ;show header line
  206. NEXT_SCREEN:
  207.         CALL    BODY            ;put hex display up
  208.         MOV    AX,24            ;last row
  209.         XOR    BX,BX            ;column 0
  210.         MOV    SI,OFFSET COMMANDLINE    ;command line
  211.         CALL    DISPLAY_STRING        ;show it
  212.         CALL    MENU            ;go get keystroke
  213.         JNC    NEXT_SCREEN        ;until esc is pressed
  214. EXIT:
  215.         RET
  216. PROGRAM ENDP
  217.  
  218. ;-----------------------------------------------------------------
  219. ;cursor routines                          
  220. ;-----------------------------------------------------------------
  221. SAVE_CURSOR PROC NEAR
  222.         MOV    ES,BIOS_SEG
  223.         MOV    AX,ES:[60H]        ;get present cursor type
  224.         MOV    CURSOR_TYPE,AX        ;save it
  225.         CALL    GETPOS
  226.         MOV    CURSOR_POS,DX
  227.         RET
  228. SAVE_CURSOR ENDP
  229. ;----------------------------------------------------------------------
  230. RESTORE_CURSOR PROC NEAR
  231.         MOV    DX,CURSOR_POS
  232.         CALL    SETPOS
  233.         RET
  234. RESTORE_CURSOR ENDP
  235. ;----------------------------------------------------------------------
  236. SETPOS PROC NEAR
  237.         MOV    AH,2            ;set cursor position
  238.         XOR    BH,BH            ;active page
  239.         INT    10H            ;set cursor position to dx
  240.         RET
  241. SETPOS ENDP
  242. ;----------------------------------------------------------------------
  243. GETPOS PROC NEAR
  244.         MOV    AH,3            ;get cursor position
  245.         XOR    BH,BH            ;active page
  246.         INT    10H            ;get cursor position in dx
  247.         RET
  248. GETPOS ENDP
  249. ;----------------------------------------------------------------------
  250. CURSOR_OFF PROC NEAR
  251.         PUSH    CX
  252.         MOV    CX,2B0CH        ;turn off cursor value
  253.         CALL    SETCUR
  254.         POP    CX
  255.         RET
  256. CURSOR_OFF ENDP
  257. ;----------------------------------------------------------------------
  258. CURSOR_ON PROC NEAR
  259.         PUSH    CX
  260.         MOV    CX,CURSOR_TYPE        ;turn on cursor value
  261.         CALL    SETCUR
  262.         POP    CX
  263.         RET
  264. CURSOR_ON ENDP
  265. ;----------------------------------------------------------------------
  266. SETCUR PROC NEAR
  267.         PUSH    AX
  268.         MOV    AH,1            ;function to set cursor shape
  269.         INT    10H            ;do it
  270.         POP    AX
  271.         RET                ;that's all
  272. SETCUR  ENDP
  273. ;-----------------------------------------------------------------
  274. ;screen routines
  275. ;-----------------------------------------------------------------
  276. SAVE_SCREEN PROC NEAR
  277.         CALL    TURN_OFF_CRT
  278.         PUSH    DS            ;save data segment
  279.         XOR    AX,AX
  280.         MOV    BX,AX
  281.         CALL    CALC_SCRN_ADDR        ;address of (0,0)
  282.         MOV    SI,OFFSET LAST_BYTE    ;buffer is past end of prog
  283.         PUSH    DS            ;exchange
  284.         PUSH    ES            ;ds and es
  285.         POP    DS
  286.         POP    ES
  287.         XCHG    DI,SI            ;exchange source,destination
  288.         MOV    BX,25
  289. SAVE_NEXT_LINE:
  290.         MOV    CX,80            ;save 2000
  291.         REP    MOVSW            ;words
  292.         ADD    SI,CS:DIFF        ;go to next
  293.         ADD    SI,CS:DIFF        ;line
  294.         DEC    BX            ;25 lines
  295.         JNZ    SAVE_NEXT_LINE
  296.         POP    DS            ;restore data segment
  297.         CALL    TURN_ON_CRT
  298.         RET
  299. SAVE_SCREEN ENDP
  300. ;-----------------------------------------------------------------
  301. CLEAR_SCREEN PROC NEAR
  302.         CALL    TURN_OFF_CRT
  303.         XOR    AX,AX
  304.         MOV    BX,AX
  305.         CALL    CALC_SCRN_ADDR        ;address of (0,0)
  306.         MOV    AX,0720H        ;space with normal attribute
  307.         MOV    BX,24
  308. CLEAR_NEXT_LINE:
  309.         MOV    CX,80
  310.         REP    STOSW            ;words
  311.         ADD    DI,CS:DIFF        ;go to next
  312.         ADD    DI,CS:DIFF        ;line
  313.         DEC    BX            ;24 lines
  314.         JNZ    CLEAR_NEXT_LINE
  315.         CALL    TURN_ON_CRT
  316.         RET
  317. CLEAR_SCREEN ENDP
  318. ;-----------------------------------------------------------------
  319. RESTORE_SCREEN PROC NEAR
  320.         CALL    TURN_OFF_CRT
  321.         XOR    AX,AX
  322.         MOV    BX,AX
  323.         CALL    CALC_SCRN_ADDR        ;address of (0,0)
  324.         MOV    SI,OFFSET LAST_BYTE    ;buffer past end of program
  325.         MOV     BX,25
  326. RESTORE_NEXT_LINE:
  327.         MOV    CX,80            ;save 2000
  328.         REP    MOVSW            ;words
  329.         ADD    DI,CS:DIFF        ;go to next
  330.         ADD    DI,CS:DIFF        ;line
  331.         REP    MOVSW            ;words
  332.         DEC    BX            ;25 lines
  333.         JNZ    RESTORE_NEXT_LINE
  334.         CALL    TURN_ON_CRT
  335.         RET
  336. RESTORE_SCREEN ENDP
  337. ;-----------------------------------------------------------------
  338. TURN_ON_CRT PROC NEAR
  339.         CMP    CS:FLICKER_FREE,-1    ;is it flicker free?
  340.         JZ    NOSNOW            ;if so, dont turn crt_on
  341.         PUSH    AX
  342.         PUSH    DX
  343.         PUSH    ES
  344.         CALL    WAIT_VERT
  345.         MOV    DX,3D8H
  346.         MOV    ES,BIOS_SEG
  347.         MOV    AL,ES:BYTE PTR[65H]    ;get crt mode setting
  348.         OUT    DX,AL            ;set crt back to previous mode
  349.         POP    ES
  350.         POP    DX
  351.         POP    AX
  352. NOSNOW:
  353.         RET
  354. TURN_ON_CRT ENDP
  355. ;-----------------------------------------------------------------
  356. FLICKER PROC NEAR
  357.         MOV    FLICKER_FREE,0        ;assume snowy monitor
  358.         MOV    AX,1A00H
  359.         INT    10H            ;Use PC Magazine's method
  360.         CMP    AL,1AH            ;of determining
  361.         JZ    FLICKFREE        ;vga or mda active
  362.         MOV    AH,12H
  363.         MOV    BL,10H
  364.         INT    10H
  365.         CMP    BL,10H
  366.         JNZ    FLICKFREE        ;if bl changed, its ega
  367.         MOV    AX,40H
  368.         MOV    ES,AX
  369.         TEST    ES:BYTE PTR[63H],40H    ;check for mda (= no flicker)
  370.         JNZ    ITS_CGA
  371. FLICKFREE:
  372.         MOV    FLICKER_FREE,-1
  373. ITS_CGA:
  374.         RET
  375. FLICKER ENDP
  376. ;-----------------------------------------------------------------
  377. TURN_OFF_CRT PROC NEAR
  378.         CMP    CS:FLICKER_FREE,-1    ;is it flicker free?
  379.         JZ    NO_SNOW
  380.         PUSH    DX
  381.         PUSH    AX
  382.         CALL    WAIT_VERT
  383.         MOV    AL,25H            ;mask to turn off crt
  384.         MOV    DX,3D8H
  385.         OUT    DX,AL            ;turn it off
  386.         POP    AX
  387.         POP    DX
  388. NO_SNOW:
  389.         RET
  390. TURN_OFF_CRT ENDP
  391. ;-----------------------------------------------------------------
  392. WAIT_VERT PROC NEAR
  393.         CMP    CS:FLICKER_FREE,-1    ;is it flicker free?
  394.         JZ    NOWAIT
  395.         PUSH    AX
  396.         PUSH    DX
  397.         MOV    DX,3DAH            ;color status port
  398. WAIT0:
  399.         IN    AL,DX
  400.         TEST    AL,8
  401.         JNZ    WAIT0            ;wait for vertical off
  402. WAIT1:
  403.         IN    AL,DX
  404.         TEST    AL,8
  405.         JZ    WAIT1            ;wait for verical on
  406.         POP    DX
  407.         POP    AX
  408. NOWAIT:
  409.         RET
  410. WAIT_VERT ENDP
  411.  
  412. ;-----------------------------------------------------------------
  413. ;stack routines
  414. ;-----------------------------------------------------------------
  415. RETADDR DW 0
  416. SWAPIN PROC NEAR
  417.         POP    CS:RETADDR        ;save callers address
  418.         MOV    CS:THEIR_SS,SS        ;save their stack
  419.         MOV    CS:THEIR_SP,SP
  420.         MOV    SS,CS:OUR_SS        ;switch to our stack
  421.         MOV    SP,CS:OUR_SP
  422.         PUSH    AX            ;save all registers
  423.         PUSH    BX
  424.         PUSH    CX
  425.         PUSH    DX
  426.         PUSH    SI
  427.         PUSH    DI
  428.         PUSH    ES
  429.         PUSH    DS
  430.         PUSH    BP
  431.         JMP    CS:RETADDR        ;return to caller
  432. SWAPIN ENDP
  433. ;-----------------------------------------------------------------
  434. SWAPOUT PROC NEAR
  435.         POP    CS:RETADDR        ;save callers address
  436.         POP    BP            ;restore all registers
  437.         POP    DS
  438.         POP    ES
  439.         POP    DI
  440.         POP    SI
  441.         POP    DX
  442.         POP    CX
  443.         POP    BX
  444.         POP    AX
  445.         MOV    SS,CS:THEIR_SS        ;restore callers stack
  446.         MOV    SP,CS:THEIR_SP
  447.         JMP    CS:RETADDR        ;return to caller
  448. SWAPOUT ENDP
  449.  
  450. ;-----------------------------------------------------------------          
  451. ;clears last line
  452. ;-----------------------------------------------------------------
  453. CLEAR_LAST_LINE PROC NEAR
  454.         CALL    WAIT_VERT
  455.         MOV    AX,24            ;row 24
  456.         XOR    BX,BX            ;col 0
  457.         CALL    CALC_SCRN_ADDR        ;get es:di for that address
  458.         MOV    CX,80            ;80 words
  459.         MOV    AX,0720H        ;normal attribute spaces
  460.         REP    STOSW            ;clear it
  461.         RET                ;that's all
  462. CLEAR_LAST_LINE ENDP
  463.  
  464. ;-----------------------------------------------------------------
  465. ;menu accept and key input
  466. ;-----------------------------------------------------------------
  467. MENU PROC NEAR
  468. NEXT_MENU_KEY:
  469.         CALL    GETKEY            ;input a key
  470.         CMP    AH,2            ;if scan code is less than 2
  471.         JBE    QUIT_EXIT        ; the key is Esc
  472. NOT_ESC:
  473.         AND    AL,0DFH            ;make all ascii caps
  474.         CMP    AL,"G"            ;G)o
  475.         JNZ    NOT_GOTO
  476.         CALL    GOTO            ;get start addr
  477.         JMP    MENU_EXIT
  478. NOT_GOTO:
  479.         CMP    AL,"A"            ;A)scii search
  480.         JNZ    NOT_ASCII_SEARCH
  481.         CALL    ASCII_SEARCH        ;find ascii string
  482.         JMP    MENU_EXIT
  483. NOT_ASCII_SEARCH:
  484.         CMP    AL,"H"            ;H)ex search
  485.         JNZ    NOT_HEX_SEARCH
  486.         CALL    HEX_SEARCH        ;find hex string
  487.         JMP    MENU_EXIT
  488. NOT_HEX_SEARCH:
  489.         CMP    AL,"N"            ;N)ext search
  490.         JNZ    NOT_NEXT_SEARCH
  491.         CALL    NEXT_SEARCH        ;find next string
  492.         JMP    MENU_EXIT
  493. NOT_NEXT_SEARCH:
  494.         CMP    AH,U_ARR        ;up arrow
  495.         JNZ    NOT_UP
  496.         MOV    AX,-10H
  497.         JMP    SHORT MOVEIT
  498. NOT_UP:
  499.         CMP    AH,HOME            ;go to beginning of memory
  500.         JNZ    NOT_HOME
  501.         MOV    START_OFFSET,0
  502.         MOV    START_SEGMENT,0
  503.         JMP    SHORT MENU_EXIT
  504. NOT_HOME:
  505.         CMP    AH,END_KEY        ;go to end of memory
  506.         JNZ    NOT_END
  507.         MOV    START_OFFSET,0FE90H    ;top of last page
  508.         MOV    START_SEGMENT,0F000H
  509.         JMP    SHORT MENU_EXIT
  510. NOT_END:
  511.         CMP    AH,D_ARR        ;down arrow
  512.         JNZ    NOT_DOWN
  513.         MOV    AX,10H
  514.         JMP    SHORT MOVEIT
  515. NOT_DOWN:
  516.         CMP    AH,PGUP            ;page up
  517.         JNZ    NEXT_CHECK
  518.         MOV    AX,-170H
  519.         JMP    SHORT MOVEIT
  520. NEXT_CHECK:
  521.         CMP    AH,PGDN            ;page down
  522.         MOV    AX,170H
  523.         JZ    MOVEIT
  524.         JMP    NEXT_MENU_KEY
  525. MOVEIT:
  526.         CALL    MOVE
  527. MENU_EXIT:
  528.         CLC                ;clear carry for exit
  529. QUIT_EXIT:
  530.         RET                ;that's all
  531. MENU ENDP
  532.  
  533. ;-----------------------------------------------------------------          
  534. ;sets starting segment and offset for display
  535. ;-----------------------------------------------------------------
  536. MOVE PROC NEAR
  537.         OR    AX,AX            ;is the movement signed
  538.         JNS    ADDIT            ;no-add to seg:off
  539.         NEG    AX            ;otherwise make positive
  540.         SUB    START_OFFSET,AX        ;subtract from offset
  541.         JNC    MOVE_EXIT        ;if no carry, done
  542.         SUB    START_SEGMENT,1000H    ;else wrap segment
  543.         JMP    SHORT MOVE_EXIT
  544. ADDIT:
  545.         ADD    START_OFFSET,AX        ;add movement to offset
  546.         JNC    MOVE_EXIT        ;if no carry, done
  547.         ADD    START_SEGMENT,1000H    ;else wrap segment
  548. MOVE_EXIT:
  549.         RET
  550. MOVE ENDP
  551.  
  552. ;-----------------------------------------------------------------
  553. ;ascii search routine
  554. ;-----------------------------------------------------------------
  555. ASCII_SEARCH PROC NEAR
  556.         CALL    CLEAR_LAST_LINE        ;clear line for input
  557.         MOV    AX,24            ;last row
  558.         XOR    BX,BX            ;first col
  559.         MOV    SI,OFFSET ASCII_SEARCH_PROMPT    ;prompt
  560.         CALL    DISPLAY_STRING        ;show the prompt
  561.         CALL    STRLEN            ;find out how long prompt is
  562.         MOV    DL,CL            ;dl = col after prompt
  563.         MOV    DH,24            ;dx = row col
  564.         MOV    SI,OFFSET ASCII_SEARCH_AREA    ;
  565.         MOV    CX,20            ;size of the string
  566.         CALL    CLEAR_BUF
  567.         MOV    DI,OFFSET CHAR_SIEVE    ;pointer to sieve
  568.         MOV    BX," "            ;get
  569.             ;dx=row col,cx=size,bl=replace,si=prompt,di=sieve
  570.         CALL    INPUT
  571.         MOV    SI,OFFSET ASCII_SEARCH_AREA ;pointer to search string
  572.         MOV    LAST_SEARCH_STRING,SI    ;save ptr to str for next
  573.         CALL    STRLEN            ;how long?
  574.         MOV    LAST_STRING_LENGTH,CX    ;save length for next
  575.         JCXZ    NO_SEARCH        ;if not, dont search
  576.         CALL    SEARCH_MEM        ;cx=length si=string
  577. NO_SEARCH:
  578.         RET                ;that's all
  579. ASCII_SEARCH ENDP
  580.  
  581. ;-----------------------------------------------------------------
  582. ;find next occurrence
  583. ;-----------------------------------------------------------------
  584. NEXT_SEARCH PROC NEAR
  585.         MOV    SI,LAST_SEARCH_STRING    ;get address of last string
  586.         MOV    CX,LAST_STRING_LENGTH
  587.         JCXZ    NO_NEXT            ;dont search
  588.         ADD    START_OFFSET,1        ;move over one to start
  589.         JNC    NOS_WRAP        ;if it causes wrap,
  590.         ADD    START_SEGMENT,1000H    ;wrap segment
  591. NOS_WRAP:
  592.         CALL    SEARCH_MEM        ;search for next string
  593. NO_NEXT:
  594.         RET                ;that's all
  595. NEXT_SEARCH ENDP
  596.  
  597. ;-----------------------------------------------------------------
  598. ;hex search routine
  599. ;-----------------------------------------------------------------
  600. HEX_SEARCH PROC NEAR
  601.         CALL    CLEAR_LAST_LINE        ;clear line for input
  602.         MOV    SI,OFFSET HEX_SEARCH_PROMPT    ;prompt
  603.         MOV    AX,24            ;last row
  604.         XOR    BX,BX            ;first col
  605.         CALL    DISPLAY_STRING        ;show the prompt
  606.         CALL    STRLEN            ;find out how long prompt is
  607.         MOV    DL,CL            ;dl = col after prompt
  608.         MOV    DH,24            ;dx = row col
  609.         MOV    SI,OFFSET HEX_SEARCH_AREA    ;
  610.         MOV    CX,20            ;size of the string
  611.         CALL    CLEAR_BUF
  612.         MOV    DI,OFFSET HEX_SIEVE    ;pointer to sieve
  613.         MOV    BX," "            ;replacement char
  614.             ;dx=row col,cx=size,bx=replace,si=prompt,di=sieve
  615.         CALL    INPUT
  616.         MOV    SI,OFFSET HEX_SEARCH_AREA ;pointer to search string
  617.         CALL    STRLEN
  618.         CMP    CL,1            ;must be at least two digits
  619.         JBE    NO_SEARCH        ;otherwise search fails
  620.         MOV    LAST_SEARCH_STRING,SI    ;save it
  621.         MOV    LAST_STRING_LENGTH,CX    ;save length
  622.         CALL    ELIMINATE_BLANKS    ;eliminate blanks in input
  623.         CALL    CONVERT_ASCII_HEX_TO_HEX_STRING    ;string into hex
  624.         MOV    LAST_STRING_LENGTH,CX    ;save length
  625.         CALL    SEARCH_MEM        ;find it
  626. NOSEARCH:
  627.         RET                ;that's all
  628. HEX_SEARCH ENDP
  629.  
  630. ;-----------------------------------------------------------------
  631. ;clear ds:[si] with (cx) spaces
  632. ;-----------------------------------------------------------------
  633. CLEAR_BUF PROC NEAR
  634.         PUSH    CX
  635.         PUSH    SI
  636. CLEARIT:
  637.         MOV    BYTE PTR [SI]," "
  638.         INC    SI
  639.         LOOP    CLEARIT
  640.         POP    SI
  641.         POP    CX
  642.         RET
  643. CLEAR_BUF ENDP
  644.  
  645. ;-----------------------------------------------------------------
  646. ;translate ascii hex string to binary string, return size in cx
  647. ;-----------------------------------------------------------------
  648. CONVERT_ASCII_HEX_TO_HEX_STRING PROC NEAR
  649.         PUSH    SI            ;save si for use in main
  650.         MOV    DI,SI            ;duplicate si
  651.         MOV    BX,SI            ;for later use
  652. NEXTC:
  653.         LODSW                ;get two ascii digits
  654.         OR    AL,AL            ;are we at the end
  655.         JZ    C_EXIT            ;if so, string is converted
  656.         OR    AH,AH            ;in case wrong # digits
  657.         JZ    C_EXIT            ;string is converted
  658.         CALL    ASCII_HEX_TO_HEX    ;translate ascii to binary
  659.         STOSB                ;put back in string
  660.         JMP    NEXTC            ;get next two characters
  661. C_EXIT:
  662.         XOR    AL,AL            ;clear al
  663.         STOSB                ;put terminator after this
  664.         SUB    DI,BX            ;find out how many bytes
  665.         LEA    CX,[DI-1]        ;we have converted
  666.         POP    SI            ;restore important register
  667.         RET                ;that's all
  668. CONVERT_ASCII_HEX_TO_HEX_STRING ENDP
  669.  
  670. ;-----------------------------------------------------------------
  671. ;close up blanks in a string
  672. ;-----------------------------------------------------------------
  673. ELIMINATE_BLANKS PROC NEAR
  674.         PUSH    SI            ;save si for main
  675.         PUSH    DS            ;set ds:si and es:di to same
  676.         POP    ES
  677.         MOV    DI,SI
  678. NEXT_SQ:
  679.         LODSB                ;get character
  680.         CMP    AL," "            ;if space
  681.         JZ    NEXT_SQ            ;skip it
  682.         STOSB                ;otherwise store it
  683.         OR    AL,AL            ;if zero
  684.         JNZ    NEXT_SQ            ;done whole string
  685. SQUOZE:
  686.         POP    SI            ;restore important register
  687.         RET                ;that's all
  688. ELIMINATE_BLANKS ENDP
  689.  
  690. ;-----------------------------------------------------------------
  691. ;go to command
  692. ;-----------------------------------------------------------------
  693. GOTO PROC NEAR
  694.         CALL    CLEAR_LAST_LINE        ;clear line for input
  695.         MOV    AX,24            ;row
  696.         XOR    BX,BX            ;col
  697.         MOV    SI,OFFSET START_DISPLAY    ;prompt
  698.         CALL    DISPLAY_STRING        ;show it
  699.         MOV    DX,180FH        ;row col
  700.         MOV    SI,OFFSET START_DISPLAY+15    ;destination
  701.         MOV    CX,9            ;size
  702.         MOV    DI,OFFSET ADDR_SIEVE    ;sieve
  703.         MOV    BX,"0"            ;replace char
  704.             ;dx=row col,cx=size,bx=replace,si=prompt,di=sieve
  705.         CALL    INPUT
  706.         MOV    SI,OFFSET START_DISPLAY+15    ;ascii address
  707.         MOV    DI,OFFSET START_SEGMENT    ;destination
  708.         CALL    CONVERT_ADDR        ;32 bit ascii address to ptr
  709.         CLC
  710.         RET
  711. GOTO ENDP
  712.  
  713. ;-----------------------------------------------------------------
  714. ;convert ascii to binary segment and offset
  715. ; si=ascii  di= pointer to destination
  716. ;-----------------------------------------------------------------
  717. CONVERT_ADDR PROC NEAR
  718.         PUSH    DS
  719.         POP    ES            ;set es for stos
  720.         INC    DI
  721.         CALL    CONVERT_BYTE        ;segment
  722.         CALL    CONVERT_BYTE
  723.         INC    SI            ;colon
  724.         CALL    CONVERT_BYTE        ;offset
  725.         CALL    CONVERT_BYTE
  726.         RET                ;that's all
  727. CONVERT_ADDR ENDP
  728. ;-----------------------------------------------------------------
  729. CONVERT_BYTE PROC NEAR
  730.         LODSW                ;get two chars
  731.         CALL    ASCII_HEX_TO_HEX    ;make hex
  732.         MOV    [DI],AL            ;put in destination
  733.         DEC    DI            ;set up for next character
  734.         RET                ;that's all
  735. CONVERT_BYTE ENDP
  736.  
  737. ;-----------------------------------------------------------------
  738. ;display main screen
  739. ;-----------------------------------------------------------------
  740. BODY PROC NEAR
  741.         CALL    TURN_OFF_CRT        ;turn off monitor if necessary
  742.         PUSH    BP            ;use the
  743.         MOV    BP,SP            ;stack
  744.         SUB    SP,8            ;for temporary variables
  745.         PUSH    DS            ;save ds for main routine
  746.         LES    BX,DWORD PTR START_OFFSET    ;get start pointer
  747.         MOV    [BP-2],BX        ;save on stack
  748.         MOV    [BP-4],ES        ;for later use
  749.         CALL    NORMALIZE        ;change es:bx so 10h <= bx >=0
  750.         MOV    [BP-6],BX        ;save value on stack
  751.         MOV    [BP-8],ES        ;for later use
  752.         MOV    DS,[BP-4]        ;get pointer
  753.         MOV    SI,[BP-2]        ;to memory to display
  754.         MOV    CS:ROW,0        ;initialize row counter
  755. NEXT_LINE:
  756.         INC    CS:ROW            ;next display row
  757.         MOV    AX,CS:ROW        ;row
  758.         XOR    BX,BX            ;col
  759.         CALL    CALC_SCRN_ADDR        ;get es:di for that address
  760.         MOV    CX,[BP-8]        ;hi part of norm 20 bit desc
  761.         CALL    WORD_OUT        ;print it
  762.         INC    WORD PTR[BP-8]        ;add 1 to seg = 16 bytes
  763.         MOV    AL,[BP-6]        ;get lo part
  764.         CALL    HEX_TO_ASCII_HEX    ;convert to ascii
  765.         XCHG    AL,AH            ;lowest significant nybble
  766.         CALL    CHAR_OUT        ;print lo part of 'ABS' value
  767.         CALL    SPACE_OUT        ;put separator
  768.         MOV    CX,[BP-4]        ;segment being displayed
  769.         CALL    WORD_OUT        ;print it
  770.         MOV    AL,":"            ;followed
  771.         CALL    CHAR_OUT        ;by a colon
  772.         MOV    CX,[BP-2]        ;offset this line
  773.         CALL    WORD_SPACE        ;print offset/space
  774.         MOV    CX,16            ;# characters to print
  775.         MOV    DX,SI            ;save ptr to present line
  776. HEX_PART:
  777.         LODSB                ;get character
  778.         CALL    BYTE_OUT        ;print two hex nybbles
  779.         CALL    SPACE_OUT        ;print space
  780.         LOOP    HEX_PART        ;all 16 hex digits
  781.         MOV    SI,DX            ;get ptr to present line
  782.         MOV    CX,16            ;all 16 hex digits
  783.         MOV    AL,70H            ;reverse the ascii part
  784. ASCII_PART:
  785.         MOVSB                ;print the ascii part
  786.         STOSB                ;reverse attribute on it
  787.         LOOP    ASCII_PART        ;all 16 ascii chars
  788.         ADD    WORD PTR[BP-6],10H    ;'ABS' + 16
  789.         ADC    WORD PTR[BP-8],0    ;
  790.         ADD    WORD PTR[BP-2],10H    ;'SEG:OFF' + 16
  791.         JNC    NO_WRAP            ;if it wraps
  792.         ADD    WORD PTR[BP-4],1000H    ;wrap the segment
  793.         MOV    DS,[BP-4]        ;get the data segment
  794. NO_WRAP:
  795.         CMP    CS:ROW,23        ;if not completely done
  796.         JB    NEXT_LINE        ;do another
  797.         POP    DS            ;restore ds for main routine
  798.         ADD    SP,8            ;clean off temporary variables
  799.         POP    BP            ;restore bp
  800.         CALL    TURN_ON_CRT        ;turn on monitor if necessary
  801.         RET                ;that's all
  802. BODY ENDP
  803.  
  804. WORD_SPACE LABEL NEAR
  805.         CALL    WORD_OUT        ;output two nybbles from cx
  806. SPACE_OUT LABEL NEAR                ;then
  807.         MOV    AL," "            ;output a space
  808.         JMP    SHORT CHAR_OUT
  809. WORD_OUT LABEL NEAR
  810.         MOV    AL,CH            ;get high nybble
  811.         CALL    BYTE_OUT        ;print it
  812.         MOV    AL,CL            ;get low nybble
  813. BYTE_OUT LABEL NEAR
  814.         CALL    HEX_TO_ASCII_HEX    ;cvt hex to two char nybbles
  815.         STOSB                ;print highest order nybble
  816.         INC    DI            ;skip attribute
  817.         MOV    AL,AH            ;get low order nybble
  818. CHAR_OUT LABEL NEAR
  819.         STOSB                ;print it
  820.         INC    DI            ;skip attribute
  821.         RET                ;that's all
  822.  
  823. END_MINUS_START PROC NEAR
  824.         LES    BX,DWORD PTR START_OFFSET    ;get end segment
  825.         CALL    NORMALIZE        ;change es:bx so 10h <= bx >=0
  826.         MOV    AX,ES            ;save normalized result
  827.         MOV    CX,BX            ;for later use
  828.         LES    BX,DWORD PTR END_OFFSET    ;get end address
  829.         CALL    NORMALIZE        ;change es:bx so 10h <= bx >=0
  830.         MOV    DX,ES            ;get end segment
  831.         SUB    DX,AX            ;calculate segments to search
  832.         MOV    SEARCH_SEGMENTS,DX
  833.         MOV    SEARCH_BYTES,BX        ;# bytes in final segment
  834.         MOV    ES,AX            ;set es:bx to
  835.         MOV    BX,CX            ;start address
  836.         RET                ;that's all
  837. END_MINUS_START ENDP
  838.  
  839. ;-----------------------------------------------------------------
  840. ;make 20 bit pointer in es:bx from segment:offset in es:bx
  841. ;-----------------------------------------------------------------
  842. NORMALIZE PROC NEAR
  843.         PUSH    AX            ;save these registers
  844.         PUSH    CX            ;for main routine
  845.         PUSH    DX            ;
  846.         MOV    AX,BX            ;get the offset
  847.         MOV    CL,4            ;make into
  848.         SHR    AX,CL            ;number of paragraphs
  849.         MOV    DX,ES            ;get segment
  850.         ADD    DX,AX            ;add in number of paragraphs
  851.         MOV    ES,DX            ;back into segment
  852.         SHL    AX,CL            ;calc offset into segment
  853.         SUB    BX,AX            ;paras - paras mod 16
  854.         POP    DX            ;retstore registers
  855.         POP    CX            ;for main routine
  856.         POP    AX
  857.         RET                ;that's all
  858. NORMALIZE ENDP
  859.  
  860. ;-----------------------------------------------------------------
  861. ;si = string  cx = string_size
  862. ;search for match of string beginning at start_segment
  863. ;-----------------------------------------------------------------
  864. SEARCH_MEM  PROC NEAR
  865.         MOV    DI,CX            ;save string size
  866.         CALL    END_MINUS_START        ;calculate search length
  867. LOOK_AGAIN:
  868.         CMP    SEARCH_SEGMENTS,1000H    ;more than or equal 64k?
  869.         JAE    MORE_THAN_ENOUGH    ;if so, search 64k
  870.         MOV    AX,SEARCH_SEGMENTS    ;otherwise, get what's left
  871.         MOV    CL,4            ;
  872.         SHL    AX,CL            ;segs*16 = bytes to search
  873.         ADD    AX,SEARCH_BYTES        ;add in the last few bytes
  874.         JMP    SHORT LOOK        ;and go look
  875. MORE_THAN_ENOUGH:
  876.         MOV    AX,-1            ;64k search
  877. LOOK:                       
  878.         SUB    AX,BX            ;subtract initial offset
  879.         JC    SEARCH_NOT_FOUND    ;offset < search size?
  880.         SUB    AX,DI            ;subtract off string size
  881.         JBE    SEARCH_NOT_FOUND    ;less than search size?
  882.         CMP    AX,DI            ;amount left to search
  883.         JB    SEARCH_NOT_FOUND    ;less than search size?
  884.         MOV    DX,AX            ;dx gets search size
  885.         MOV    CL,4            ;
  886.         SHR    DX,CL            ;number of segments to search
  887.         SUB    SEARCH_SEGMENTS,DX    ;decrease the amount to search
  888.                         ;si = string  di = string size
  889.         CALL    SEARCH            ;es:bx=ptr,ax=bytes to search
  890.         JZ    SEARCH_FOUND        ;if zero flag, string is found
  891.         ADD    AX,1            ;next character after fail
  892.         MOV    BX,AX            ;into es:bx
  893.         JNC    NOWR            ;if offset rolls over
  894.         MOV    AX,ES            ;add 64k
  895.         ADD    AX,1000H        ;to the
  896.         MOV    ES,AX            ;offset
  897. NOWR:
  898.         CALL    NORMALIZE        ;set to start at the top of
  899.         JMP    LOOK_AGAIN        ;a new segment
  900. SEARCH_NOT_FOUND:
  901.         XOR    AX,AX            ;start over
  902.         MOV    ES,AX
  903.         CMP    AL,1            ;clear zero flag
  904. SEARCH_FOUND:
  905.         MOV    START_SEGMENT,ES    ;set page
  906.         MOV    START_OFFSET,AX        ;address of found string
  907.         RET                ;that's all
  908. SEARCH_MEM ENDP
  909.  
  910. ;-----------------------------------------------------------------
  911. ;si = string di = string size es:bx = pointer to buffer to search
  912. ;ax = number of bytes in buffer to search. Zero flag set if found
  913. ;-----------------------------------------------------------------
  914. SEARCH PROC NEAR                ;si points at string
  915.         PUSH    BX
  916.         PUSH    DI
  917.         PUSH    SI
  918.         XCHG    BX,DI        ;string size, ptr to data area
  919.         MOV    CX,AX        ;# chars in segment to search
  920. BYTE_ADD:
  921.         LODSB            ;char for first part of search
  922. NEXT_SRCH:
  923.         REPNZ    SCASB        ;is first char in string in buffer
  924.         JNZ    NOT_FOUND    ;if not, no match
  925.         PUSH    DI        ;save against cmpsb
  926.         PUSH    SI
  927.         PUSH    CX
  928.         LEA    CX,[BX-1]    ;# chars in string - 1
  929.         JCXZ    ONE_CHAR    ;if one char search, we have found it
  930.         REP    CMPSB        ;otherwise compare rest of string
  931. ONE_CHAR:
  932.         POP    CX        ;restore for next cmpsb
  933.         POP    SI
  934.         POP    DI
  935.         JNZ    NEXT_SRCH    ;if zr = 0 then string not found
  936. NOT_FOUND:
  937.          LEA    AX,[DI-1]    ;ptr to last first character found
  938.          POP    SI
  939.          POP    DI
  940.          POP    BX
  941.          RET            ;that's all
  942. SEARCH ENDP
  943.  
  944. ;------------------------------------------------------------------
  945. ;dx=row:col,cx=max len,bx=replace character,si=prompt,di=sieve
  946. ;------------------------------------------------------------------
  947. INPUT PROC NEAR
  948.         PUSH    BP            ;create stack frame
  949.         MOV    BP,SP
  950.         SUB    SP,6
  951.         CALL    CURSOR_ON
  952.         MOV    [BP-2],CX        ;save size of destination
  953.         MOV    [BP-4],SI
  954.         MOV    [BP-6],DX
  955.         XOR    CX,CX            ;clear count of chars entered
  956. NEXT_DISPLAY:
  957.         PUSH    BX            ;save replace char
  958.         PUSH    SI
  959.         MOV    AL,[BP-5]        ;row
  960.         CBW                ;into ax
  961.         MOV    BL,[BP-6]        ;col
  962.         XOR    BH,BH            ;into bx
  963.         MOV    SI,[BP-4]
  964.         CALL    DISPLAY_STRING        ;show string at si
  965.         POP    SI
  966.         POP    BX            ;restore replace char
  967.         PUSH    DS            ;set up string addressing
  968.         POP    ES
  969. NEXT_KEY:
  970.         CMP    BYTE PTR[SI],":"    ;skip colon in destination
  971.         JNZ    NOT_COLON
  972.         INC    CX            ;next count
  973.         INC    DL            ;next col
  974.         INC    SI            ;point to next char
  975. NOT_COLON:
  976.         CALL    SETPOS            ;set cursor position
  977.         CALL    GETKEY            ;get next key
  978.         CMP    AH,1            ;if scan = 1
  979.         JZ    END_OF_INPUT;then it's esc
  980.         CMP     AH,1CH            ;if scan = 1ch
  981.         JZ    END_OF_INPUT        ;then it's carriage return
  982.         CMP    AH,L_ARR        ;if it's left arrow
  983.         JZ    BACK_SPACE        ;or
  984.         CMP    AH,0EH            ;if it's backspace key
  985.         JNZ    NOT_BACK_SPACE        ;then back up
  986. BACK_SPACE:
  987.         JCXZ    NEXT_KEY        ;if count 0 can't back up
  988.         DEC    CX            ;decrement count
  989.         DEC    DL            ;decrement column
  990.         DEC    SI            ;decrement pointer to chars
  991.         CMP    BYTE PTR[SI],":"    ;if pointer is to colon,
  992.         JZ    BACK_SPACE        ;then back up again
  993.         MOV    BYTE PTR[SI],BL        ;put replace character in
  994.         JMP    NEXT_DISPLAY        ;show line again
  995. NOT_BACK_SPACE:
  996.         CMP    CX,[BP-2]        ;is count = max count
  997.         JZ    NEXT_KEY        ;if so, can't put in buffer
  998. NEXT_INPUT:
  999.         CALL    VERIFY            ;ax = char di = sieve
  1000.         JNZ    NEXT_KEY        ;if illegal char get new key
  1001.         MOV    [SI],AL            ;otherwize put in buffer
  1002.         INC    CX            ;next count
  1003.         INC    SI            ;pointer to next char
  1004.         INC    DL            ;next column
  1005.         JMP    NEXT_DISPLAY        ;show line again
  1006. END_OF_INPUT:
  1007.         CMP    BL,"0"            ;if replace char is "0"
  1008.         JZ    NO_ZERO            ;dont put terminator in
  1009.         MOV    BYTE PTR[SI],0        ;terminate string
  1010. NO_ZERO:
  1011.         CALL    CURSOR_OFF
  1012.         ADD    SP,6            ;clean off stack
  1013.         POP    BP            ;
  1014.         RET                ;that's all
  1015. INPUT ENDP
  1016.  
  1017. GETKEY PROC NEAR
  1018.         XOR    AH,AH            ;getkey function number
  1019.         INT    16H            ;go get a key
  1020.         RET                ;return it
  1021. GETKEY ENDP
  1022.  
  1023. ;------------------------------------------------------------------
  1024. ;ax = row  bx = col        displays string at ds:si
  1025. ;------------------------------------------------------------------
  1026. DISPLAY_STRING PROC NEAR
  1027.         PUSH    SI            ;save si for main routines
  1028.         PUSH    DI
  1029.         CALL    CALC_SCRN_ADDR        ;get es:di for row col
  1030.         MOV    AH,7            ;get normal attribute
  1031.         CALL    WAIT_VERT
  1032. NEXT_CHAR:
  1033.         LODSB                ;get char from string
  1034.         OR    AL,AL            ;test for zero
  1035.         JZ    LAST_CHAR    ;if zero, string has been printed
  1036.         STOSW            ;put char and attribute on screen
  1037.         JMP    NEXT_CHAR    ;until string has been printed
  1038. LAST_CHAR:
  1039.         POP    DI
  1040.         POP    SI            ;restore si for main routines
  1041.         RET                ;that's all
  1042. DISPLAY_STRING ENDP
  1043.  
  1044. ;------------------------------------------------------------------
  1045. ;ax = row bx= col, returns es:di pointing to the screen address
  1046. ;------------------------------------------------------------------
  1047. CALC_SCRN_ADDR PROC NEAR
  1048.         PUSH    CX
  1049.         PUSH    DX            ;mul destroys dx
  1050.         PUSH    AX            ;save ax for later
  1051.         MOV    ES,CS:BIOS_SEG        ;into es
  1052.         MOV    AX,0B800H        ;screen seg = b800h
  1053.         CMP    ES:BYTE PTR[49H],7    ;if 40:49 == 7
  1054.         JNZ    COLOR            ;then
  1055.         MOV    AH,0B0H            ;screen seg = b000h
  1056. COLOR:
  1057.         MOV    ES,AX            ;into es
  1058.         POP    CX            ;get row
  1059.         MOV    AX,160            ;160 bytes to a row of text
  1060.         ADD    AX,CS:DIFF        ;# characters > 80
  1061.         ADD    AX,CS:DIFF        ;# of attribute bytes > 80
  1062.         MUL    CX            ;row * 160 + diff*2
  1063.         ADD    AX,BX            ;+col
  1064.         ADD    AX,BX            ;row*160 + col*2
  1065.         MOV    DI,AX            ;es:di points to right address
  1066.         POP    DX            ;restore dx
  1067.         POP    CX
  1068.         RET                ;that's all
  1069. CALC_SCRN_ADDR ENDP
  1070.  
  1071. ;------------------------------------------------------------------
  1072. ;ax = char di = sieve
  1073. ;------------------------------------------------------------------
  1074. VERIFY PROC NEAR
  1075.         PUSH    CX        ;save registers for main routines
  1076.         PUSH    DI
  1077.         PUSH    SI
  1078.         PUSH    DS
  1079.         POP    ES
  1080.         MOV    SI,DI            ;si = sieve address
  1081.         CALL    STRLEN            ;how many chars in sieve (cx)
  1082.         JCXZ    ANY_KEY            ;get key if no chars in sieve
  1083.         CMP    AL,"A"            ;if lower case
  1084.         JB    NOT_SMALL        ;
  1085.         AND    AL,0DFH            ;make upper case
  1086. NOT_SMALL:
  1087.         REPNZ    SCASB            ;search for char in the sieve
  1088. ANY_KEY:                    ;set zero flag to indicate it
  1089.         POP    SI            ;restore registers
  1090.         POP     DI
  1091.         POP    CX
  1092.         RET                ;that's all
  1093. VERIFY ENDP
  1094. ;----------------------------------------------------------------------
  1095. STRLEN PROC NEAR
  1096.         PUSH    SI            ;save si for main routines
  1097.         PUSH    AX
  1098.         MOV    CX,-1            ;count for string length
  1099. NEXTS:
  1100.         INC    CX            ;next count
  1101.         LODSB                ;next char
  1102.         OR    AL,AL            ;is it a zero
  1103.         JNZ    NEXTS            ;if not get next char
  1104.         POP    AX
  1105.         POP    SI            ;restore si for main routines
  1106.         RET                ;thats all
  1107. STRLEN ENDP
  1108.  
  1109. ;------------------------------------------------------------------
  1110. ;input: al = ascii lsb ah = ascii msb
  1111. ;   example: if hex is '3F', ah = '3' al = 'F'  result: al = 3Fh
  1112. ;output: al = hex byte
  1113. ;------------------------------------------------------------------
  1114. ASCII_HEX_TO_HEX PROC NEAR
  1115.         TEST    AH,40H            ;if "A" - "F"
  1116.         JZ    AH_EXIT            ;
  1117.         SUB    AH,"A"-10        ;make 10-15
  1118. AH_EXIT:
  1119.         TEST    AL,40H            ;if "A" - "F"
  1120.         JZ    AL_EXIT            ;
  1121.         SUB    AL,"A"-10        ;make 10-15
  1122. AL_EXIT:
  1123.         AND    AX,0F0FH        ;if "0" - "9"   make 0-9
  1124.         SHL    AL,1            ;
  1125.         SHL    AL,1            ;
  1126.         SHL    AL,1            ;    
  1127.         SHL    AL,1            ;
  1128.         OR    AL,AH            ;combine msn and lsn
  1129.         RET                ;that's all
  1130. ASCII_HEX_TO_HEX ENDP
  1131.  
  1132. ;------------------------------------------------------------------
  1133. ;input: al = char to be translated:
  1134. ;    example: if hex is '3F', al = '3' ah = 'F'
  1135. ;output: al = msb of translation, ah = lsb of translation
  1136. ;------------------------------------------------------------------
  1137. HEX_TO_ASCII_HEX PROC NEAR
  1138.         DB    0D4H,10H        ;div AL/16-remainder in al
  1139.         OR    AX,3030H        ;make ascii
  1140.         CMP    AL,"9"
  1141.         JBE    ALEXIT
  1142.         ADD    AL,7            ;if a - f make "A" - "F"
  1143. ALEXIT:
  1144.         CMP    AH,"9"
  1145.         JBE    AHEXIT
  1146.         ADD    AH,7            ;if a - f make "A" - "F"
  1147. AHEXIT:
  1148.         XCHG    AL,AH
  1149.         RET                ;that's all
  1150. HEX_TO_ASCII_HEX ENDP
  1151.  
  1152. LAST_BYTE LABEL BYTE            ;marks end of resident code and
  1153.                     ;start of memory used to save screen
  1154.  
  1155. INSTALLED_SEGMENT DW 0
  1156. DISABLED    DB    CR,LF,"RAMVIEW IS DISABLED",CR,LF,"$"
  1157. ENABLED        DB    CR,LF,"RAMVIEW IS RE-ENABLED",CR,LF,"$"
  1158.  
  1159. ;------------------------------------------------------------------
  1160. ;determine if vectors have changed since program was installed
  1161. ;------------------------------------------------------------------
  1162. HOOKED_VECTORS_SAME? PROC NEAR
  1163.         MOV    CX,INSTALLED_SEGMENT    ;get executing segment
  1164.         XOR    AX,AX            ;interrupt table segment
  1165.         MOV    ES,AX            ;into the extra segment
  1166.         CMP    CX,ES:[10H*4+2]        ;see if int 10h points at us
  1167.         JNZ    VECTOR_CHANGED
  1168.         CMP    CX,ES:[9*4+2]        ;see if int 9 points at us
  1169. VECTOR_CHANGED:
  1170.         RET
  1171. HOOKED_VECTORS_SAME? ENDP
  1172.  
  1173. ;------------------------------------------------------------------
  1174. ;determine if program is already installed
  1175. ;------------------------------------------------------------------
  1176. PROGRAM_ALREADY_IN  PROC NEAR
  1177.         NOT    WORD PTR START        ;only srch for active copy
  1178.         MOV    START_SEGMENT,60H    ;start after dos
  1179.         MOV    START_OFFSET,0        ;
  1180.         MOV    END_SEGMENT,CS        ;stop looking before you
  1181.         MOV    END_OFFSET,0        ; get to this program
  1182.         MOV    SI,OFFSET START        ;start at modified byte
  1183.         MOV    CX,25            ;enough of a match
  1184.         CALL    SEARCH_MEM        ;use our search
  1185.         PUSHF                ;save zr flag
  1186.         MOV    AX,START_SEGMENT    ;get address of find
  1187.         MOV    INSTALLED_SEGMENT,AX    ;save in installed address
  1188.         MOV    AX,START_OFFSET
  1189.         MOV    CL,4
  1190.         SHR    AX,CL
  1191.         SUB    AX,10H            ;adjust for psp
  1192.         ADD    INSTALLED_SEGMENT,AX
  1193.         MOV    START_SEGMENT,0        ;reset starting address
  1194.         MOV    START_OFFSET,0
  1195.         MOV    END_OFFSET,0FH        ;reset ending address
  1196.         MOV    END_SEGMENT,0FFFFH
  1197.         POPF                ;restore flgs from search
  1198.         RET
  1199. PROGRAM_ALREADY_IN  ENDP
  1200.  
  1201. ;------------------------------------------------------------------
  1202. ;uninstall routines
  1203. ;------------------------------------------------------------------
  1204. UNINSTALL PROC NEAR
  1205.         CALL    HOOKED_VECTORS_SAME?    ;if all vectors still hooked
  1206.         JZ    UNINSTALL_OK        ;go ahead and dis installed
  1207.  
  1208.         NOT    WORD PTR START
  1209.         MOV    ES,INSTALLED_SEGMENT    ;else, change the disable flag
  1210.         NOT    ES:DISABLE        ;in the installed program
  1211.         MOV    DX,OFFSET ENABLED    ;get the message corresponding
  1212.         CMP    ES:DISABLE,-1        ;to the action that causes
  1213.         JNZ    ITS_DISABLED        ;
  1214.         MOV    DX,OFFSET DISABLED    ;
  1215. ITS_DISABLED:                    ;
  1216.         MOV    AH,9            ;and display that message
  1217.         INT    21H
  1218.         JMP    SHORT UNINSTALL_EXIT    ;all done here.
  1219. UNINSTALL_OK:
  1220.         MOV    ES,INSTALLED_SEGMENT    ;get resident prog's psp
  1221.         MOV    DX,ES:WORD PTR ADDR_INT9H    ;put back int 9 vector
  1222.         MOV    DS,ES:WORD PTR ADDR_INT9H+2
  1223.         MOV    AH,25H
  1224.         MOV    AL,9
  1225.         INT    21H
  1226.         MOV    DX,ES:WORD PTR ADDR_INT10H    ;restore int 10h vector
  1227.         MOV    DS,ES:WORD PTR ADDR_INT10H+2
  1228.         MOV    AH,25H
  1229.         MOV    AL,10H
  1230.         INT    21H
  1231.         PUSH    ES
  1232.         MOV    ES,ES:[2CH]        ;get segment of environment
  1233.         MOV    AH,49H            ;belonging to resident program
  1234.         INT    21H            ;free it
  1235.         POP    ES
  1236.         MOV    AH,49H            ;free memory block of program
  1237.         INT    21H
  1238.         PUSH    CS
  1239.         POP    DS            ;get back our data segment
  1240.         MOV    DX,OFFSET UNINSTALLED
  1241.         MOV    AH,9
  1242.         INT    21H            ;for whom it may concern
  1243. UNINSTALL_EXIT:
  1244.         RET
  1245. UNINSTALL ENDP
  1246. ;----------------------------------------------------------------------
  1247. INSTALL PROC NEAR
  1248.         MOV    CL,9            ;link vector 9
  1249.         MOV    SI,OFFSET ADDR_INT9H
  1250.         MOV    DI,OFFSET INT9H
  1251.         CALL    INSTALL_VECTOR
  1252.         MOV    CL,10H            ;link vector 10h
  1253.         MOV    SI,OFFSET ADDR_INT10H
  1254.         MOV    DI,OFFSET INT10H
  1255.         CALL    INSTALL_VECTOR
  1256.         RET
  1257. INSTALL ENDP
  1258. ;----------------------------------------------------------------------
  1259. INSTALL_VECTOR PROC NEAR
  1260.  
  1261.         MOV    AL,CL            ;get vector number
  1262.         MOV    AH,35H            ;get interrupt vector
  1263.         INT    21H            ;
  1264.         MOV    [SI],BX            ;save interrupt vector
  1265.         MOV    [SI+2],ES        ;
  1266.         MOV    DX,DI            ;get replacement address
  1267.         MOV    AH,25H            ;set vector address
  1268.         MOV    AL,CL            ;for vector
  1269.         INT    21H
  1270.         RET
  1271.  
  1272. INSTALL_VECTOR ENDP
  1273.  
  1274. _TEXT ENDS
  1275.         END    START
  1276.