home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1987 / 12 / spectrum.asm < prev    next >
Assembly Source File  |  1987-03-26  |  26KB  |  813 lines

  1. ;----------------------------------------------------------------------
  2. ;  SPECTRUM is a memory resident utility that allows the EGA palette
  3. ;  registers to be mapped to any of the 64 possible colors provided by
  4. ;  the EGA.  The interface uses the cursor pad keys to select and change
  5. ;  the colors.  RIGHT/LEFT arrow selects the color to be mapped.  UP/DOWN
  6. ;  arrow changes the 2/3 intensity color bits RGB.  PGUP/PGDN changes the
  7. ;  1/3 intensity color bits rgb.  Home restores the default color mapping.
  8. ;  ESC exits and restores the colors at entry.  END exits and makes the
  9. ;  current screen colors permanent.  SPECTRUM is reasonably colorfast, but
  10. ;  if colors are lost, pop up and exit SPECTRUM to restore the colors.
  11. ;======================================================================
  12. CSEG    SEGMENT    PARA    PUBLIC    'CODE'
  13.         ORG    100H            ;COM file format
  14.  
  15.         ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
  16. ;----------------------------------------------------------------------
  17. ;  Equates - substituted literally when assembled.
  18. ;----------------------------------------------------------------------
  19. CR        EQU    0DH            ;HEX for carriage return
  20. LF        EQU    0AH            ; and line feed
  21.                         ;CTRL-TILDE
  22. HOTKEY        EQU    29H            ;SCAN code for tilde
  23. SHIFT_MASK    EQU    04H            ;Mask to pick out 'shifts'
  24.                         ;1000 = ALT     0100 = CTRL
  25.                         ;0010 = L SHIFT 0001 = R SHIFT
  26.  
  27. NROW        EQU    10            ;Number of rows in the window
  28. NCOL        EQU    80            ;Number of cols in the window
  29. BOX_ROW        EQU    10            ;Top row of window on screen
  30. BOX_COL        EQU    0            ;Left col of window on screen
  31. BW_ATTR        EQU    70H            ;Monochrome window
  32. CO_ATTR        EQU    17H            ;Color window
  33.  
  34. ;----------------------------------------------------------------------
  35. ;  COM file entry point is at 100h
  36. ;----------------------------------------------------------------------
  37. ENTPT:        JMP    INITIALIZE        ;Perform initialization
  38.  
  39. COPYRIGHT    DB    "SPECTRUM 1.0 (c) 1987, Ziff-Davis Publishing Corp."
  40.         DB    CR,LF,"$",01AH
  41. AUTHOR        DB    "Programmed by Robert L. Hummel"
  42. ;----------------------------------------------------------------------
  43. ;  Data used by INT_9 procedure.  Other data precedes other procedures.
  44. ;----------------------------------------------------------------------
  45. OLD_INT_9    DD    0            ;Storage for old vectors
  46. OLD_INT_10    DD    0
  47. OLD_INT_21    DD    0
  48. DOS_FLAG    DD    0            ;Address of dos critical flag
  49. INFO_PTR    DD    00000487H        ;0:487H
  50.  
  51. ACTIVE        DB    0            ;Inside pop-up
  52. LO_FN_FLAG    DB    0            ;When inside Int 21h
  53.  
  54. DISPLAY_PAGE    DB    0            ;Used by screen save
  55. CURSOR_POS    DW    0            ; to restore info
  56. ATTRIBUTE    DB    0            ;Window color
  57.  
  58. ;======================================================================
  59. ;  New Interrupt 9 routine. Invoked each key-press.
  60. ;  Test to see if our key combination has been typed.
  61. ;----------------------------------------------------------------------
  62. INT_9        PROC    FAR
  63.         ASSUME    CS:CSEG, DS:NOTHING, ES:NOTHING, SS:NOTHING
  64.                         ;(Flags saved by INT)
  65.         STI                ;Allow interrupts
  66.         PUSH    AX            ;Save used register
  67.  
  68.         IN    AL,60H            ;Get key scan code
  69.         CMP    AL,HOTKEY        ;Check if hot-key
  70.         JNE    PROCESS_KEY        ;If not, continue on.
  71.  
  72.         MOV    AH,2            ;Get shift status fn
  73.         INT    16H            ;Thru BIOS
  74.  
  75.         AND    AL,0FH            ;Test only for 'shift' keys
  76.         CMP    AL,SHIFT_MASK        ;If they match our combination
  77.         JE    OUR_KEY            ;then is our signal
  78. PROCESS_KEY:
  79.         POP    AX            ;Restore register
  80.         JMP    DWORD PTR CS:OLD_INT_9    ;Process key as normal
  81. OUR_KEY:
  82. ;----------------------------------------------------------------------
  83. ;  Reset the keyboard interrupt controller (forget the key stroke)
  84. ;----------------------------------------------------------------------
  85.         IN    AL,61H            ;These instructions reset
  86.         MOV    AH,AL            ; the keyboard.
  87.         OR    AL,80H
  88.         OUT    61H,AL
  89.         MOV    AL,AH
  90.         JMP    SHORT $+2        ;I/O delay for fast AT's
  91.         OUT    61H,AL
  92.         CLI                ;Disable interrupts and
  93.         MOV    AL,20H            ;reset the int controller
  94.         OUT    20H,AL
  95.         STI                ;Allow interrupts
  96. ;----------------------------------------------------------------------
  97. ;  If SPECTRUM is already active, or DOS is busy, simply return.
  98. ;----------------------------------------------------------------------
  99.         CMP    CS:ACTIVE,0        ;If already active
  100.         JNE    RETURN_A        ;  can't call again
  101.  
  102.         PUSH    DS            ;Save used registers
  103.         PUSH    BX
  104.         LDS    BX,CS:DOS_FLAG        ;If DOS critical flag is not
  105.         CMP    BYTE PTR [BX],0        ; busy (= 0)
  106.         JE    INVOKE            ;We can pop up
  107.  
  108.         CMP    CS:LO_FN_FLAG,0        ;If busy from low function
  109.         JNE    INVOKE            ; of Int 21h, go pop up
  110. RETURN_B:
  111.         POP    BX            ;Restore other registers
  112.         POP    DS
  113. RETURN_A:
  114.         POP    AX            ;Restore register
  115.         IRET                ;Go back where we came from
  116. INVOKE:
  117. ;----------------------------------------------------------------------
  118. ;  Test, and pop up, only if the EGA is the active monitor.
  119. ;----------------------------------------------------------------------
  120.         LDS    BX,CS:INFO_PTR        ;Get address of info byte
  121.         LDS    BX,[BX]            ; and then byte itself
  122.         TEST    BL,08H            ;Bit = 0 if EGA is active
  123.         JNZ    RETURN_B        ; else don't pop up
  124.  
  125. ;-----------------------------------------------------------------------------
  126. ;  Check for valid text video mode.  Set colors for BW or color modes.
  127. ;-----------------------------------------------------------------------------
  128.         MOV    ATTRIBUTE,CO_ATTR    ;Assume color window
  129.         MOV    AH,0FH            ;Get current video mode fn
  130.         INT    10H            ; Thru BIOS
  131.         MOV    DISPLAY_PAGE,BH        ;Save current page
  132.  
  133.         CMP    AL,3            ;One of the color text modes?
  134.         JBE    MODE_OK            ; thats ok
  135.         MOV    ATTRIBUTE,BW_ATTR    ;Assume mono window
  136.         CMP    AL,7            ;MONO 80x25 is valid
  137.         JNE     RETURN_B        ; else don't pop up
  138. MODE_OK:
  139. ;-----------------------------------------------------------------------------
  140. ;  If here, routine becomes active, save all other used registers.
  141. ;-----------------------------------------------------------------------------
  142.         INC    CS:ACTIVE        ;Set flag to prevent re-entry
  143.  
  144.         PUSH    CX            ;Save all registers for return
  145.         PUSH    DX
  146.         PUSH    DI
  147.         PUSH    SI
  148.         PUSH    ES
  149.         PUSH    BP
  150.  
  151.         PUSH    CS            ;Put our CS into these regs
  152.         POP    DS            ;So we can find our data
  153.         PUSH    CS
  154.         POP    ES            ;And our string moves
  155.     ASSUME    DS:CSEG,ES:CSEG            ;Tell the Assembler
  156. ;-----------------------------------------------------------------------------
  157. ;  Save the details of the current screen for later restoration.
  158. ;-----------------------------------------------------------------------------
  159.         MOV    AH,3            ;Get cursor position fn
  160.         INT    10H            ;Thru BIOS
  161.         MOV    CURSOR_POS,DX        ;Save position
  162.  
  163. ;-----------------------------------------------------------------------------
  164. ;  Save section of screen we will be writing over.
  165. ;-----------------------------------------------------------------------------
  166.         MOV    DI,OFFSET SCREEN_BUF    ;Destination for save
  167.         MOV    SI,0FFFFH        ;Switch tells proc to save
  168.         CALL    SCREEN
  169.  
  170.         CALL    CLR_BOX            ;Clear box & draw border
  171.         CALL    SPECTRUM        ;Do all color mapping
  172.  
  173. ;-----------------------------------------------------------------------------
  174. ;  Restore the screen to original state.
  175. ;-----------------------------------------------------------------------------
  176.         MOV    SI,OFFSET SCREEN_BUF    ;Address of saved screen
  177.         CALL    SCREEN            ;Restore
  178.  
  179.         MOV    AH,2            ;Set Cursor position fn
  180.         MOV    DX,CURSOR_POS        ;Restore old cursor position
  181.         INT    10H            ;Thru BIOS
  182.  
  183.         MOV    ACTIVE,0        ;Turn off active flag
  184.  
  185.         POP    BP            ;Restore all used registers
  186.         POP    ES
  187.         POP    SI
  188.         POP    DI
  189.         POP    DX
  190.         POP    CX
  191.         POP    BX
  192.         POP    DS
  193.         POP    AX
  194.  
  195.         IRET                ;Interrupt gets IRET
  196. INT_9    ENDP
  197.  
  198. ;======================================================================
  199. ;  Spectrum data & equates.
  200. ;----------------------------------------------------------------------
  201. RT_ARROW    EQU    4DH            ;Extended ASCII for keys
  202. LT_ARROW    EQU    4BH
  203. UP_ARROW    EQU    48H
  204. DN_ARROW    EQU    50H
  205. PAGE_UP        EQU    49H
  206. PAGE_DN        EQU    51H
  207. END_KEY        EQU    4FH
  208. HOME        EQU    47H
  209. ESCAPE        EQU    1BH            ;ASCII for escape
  210.  
  211. DEFAULT_COLORS    DB    00H,01H,02H,03H,04H,05H,14H,07H    ;Restore with home
  212.         DB    38H,39H,3AH,3BH,3CH,3DH,3EH,3FH
  213.  
  214. OLD_COLORS    DB    00H,01H,02H,03H,04H,05H,14H,07H    ;May be set by loader
  215.         DB    38H,39H,3AH,3BH,3CH,3DH,3EH,3FH
  216.  
  217. BOX_PTR        DB    0            ;Arrow location counter
  218.  
  219. ;----------------------------------------------------------------------
  220. ;  Display and set the colors for the EGA card by re-mapping the palette
  221. ;  registers.  Works best with EGD, but ok with CGD or MD.
  222. ;----------------------------------------------------------------------
  223. SPECTRUM    PROC    NEAR
  224.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  225.  
  226.         MOV    BOX_PTR,0        ;Point to 1st box
  227.         CALL    SP_3            ;Copy last known colors
  228.                         ;to scratch copy & set regs
  229. ;----------------------------------------------------------------------
  230. ;Set the pointer to the first box and listen for the required keystrokes
  231. ;    > move right to next box    < move left to previous box
  232. ;    ^ increment rgb signal        v decrement rgb signal
  233. ;    pgup increment RGB signal    pgdn decrement RGB signal
  234. ;    ESC abort changes        END save changes
  235. ;    HOME load default colors
  236. ;----------------------------------------------------------------------
  237. SP_1:
  238.         MOV    AH,2            ;Position cursor fn
  239.         MOV    DH,BOX_ROW+5        ;Row
  240.         MOV    DL,BOX_PTR        ;Column
  241.         SHL    DL,1            ; times 4
  242.         SHL    DL,1
  243.         ADD    DL,9            ; plus offset
  244.         INT    10H            ;Thru BIOS
  245.  
  246.         MOV    AX,0E18H        ;Write TTY, arrow char
  247.         INT    10H            ;Thru BIOS
  248.         MOV    AX,0E08H        ;Backspace under it
  249.         INT    10H            ;THRU BIOS
  250. SP_2:
  251.         XOR    AH,AH            ;Wait for keystroke in AL
  252.         INT    16H            ;Thru BIOS
  253.  
  254.         CMP    AL,ESCAPE        ;If ESCAPE character, leave
  255.         JNE    CMP_0A
  256. SP_3:
  257.         MOV    SI,OFFSET OLD_COLORS    ;Copy old colors
  258.         MOV    DI,OFFSET NEW_COLORS    ; to scratch copy
  259. SP_4:
  260.         MOV    CX,16            ;Bytes to move
  261.         REP    MOVSB            ; move 'em
  262.         CALL    COLOR_BARS        ;Set palette registers
  263.         RET                ;Return to calling procedure
  264. CMP_0A:
  265.         XOR    AL,AL            ;If not extended ASCII
  266.         JNZ    SP_2            ; ignore it
  267.  
  268.         CMP    AH,END_KEY        ;END key means
  269.         JNE    CMP_0B
  270.         MOV    SI,OFFSET NEW_COLORS    ;New colors become
  271.         MOV    DI,OFFSET OLD_COLORS    ; permanent
  272.         JMP    SP_4
  273. CMP_0B:
  274.         CMP    AH,HOME            ;HOME means
  275.         JNE    CMP_0C
  276.         MOV    SI,OFFSET DEFAULT_COLORS ;Reset to power-up colors
  277.         MOV    DI,OFFSET NEW_COLORS     ; in scratch copy
  278.         CALL    SP_4            ;Change the registers
  279.         JMP    SP_1            ;Go wait for more keys
  280. CMP_0C:
  281.         CMP    AH,RT_ARROW        ;Right arrow means
  282.         JNE    CMP_1
  283.         INC    BOX_PTR            ; move to next box
  284. CMP_0:
  285.         MOV    AX,0E20H        ;Write space over arrow
  286.         INT    10H            ;Thru BIOS
  287.         AND    BOX_PTR,15        ;Modulo 16 arithmetic
  288.         JMP    SP_1            ;Redraw arrow
  289. CMP_1:
  290.         CMP    AH,LT_ARROW        ;Previous box
  291.         JNE    CMP_2
  292.         DEC    BOX_PTR
  293.         JMP    CMP_0            ;Adjust pointer
  294. ;----------------------------------------------------------------------
  295. ;  Decode the palette value in case we need it.
  296. ;----------------------------------------------------------------------
  297. CMP_2:
  298.         XOR    BH,BH            ;What register are we
  299.         MOV    BL,BOX_PTR        ; pointing to?
  300.         MOV    CL,BYTE PTR NEW_COLORS[BX] ;Get palette value
  301.         MOV    CH,CL            ;Duplicate
  302.         AND    CX,3807H        ;CH=rgb, CL=RGB
  303.  
  304.         CMP    AH,UP_ARROW
  305.         JNE    CMP_3
  306.         INC    CL            ;Next RGB color
  307. CMP_2A:
  308.         AND    CL,7            ;7 = 00000111B
  309.         JMP    SHORT COMBINE
  310. CMP_3:
  311.         CMP    AH,DN_ARROW
  312.         JNE    CMP_4
  313.         DEC    CL            ;Previous RGB color
  314.         JMP    CMP_2A
  315. CMP_4:
  316.         CMP    AH,PAGE_UP
  317.         JNE    CMP_5
  318.         ADD    CH,8            ;next rgb color
  319. CMP_4A:
  320.         AND    CH,38H            ;38H = 00111000b
  321.         JMP    SHORT COMBINE
  322. CMP_5:
  323.         CMP    AH,PAGE_DN
  324.         JNE    CMP_6
  325.         ADD    CH,38H            ;Previous rgb color
  326.         JMP    CMP_4A
  327. COMBINE:
  328.         OR    CL,CH            ;Combine CL & CH
  329.         MOV    BYTE PTR NEW_COLORS[BX],CL ;Update color table
  330.         CALL    COLOR_BARS        ; and palette registers
  331. CMP_6:
  332.         JMP    SP_1            ;Wait for next keystroke
  333. SPECTRUM    ENDP
  334.  
  335. ;======================================================================
  336. ;  COLOR_BARS calls the EGA BIOS to map the attributes 0 thru 15 to the
  337. ;  values in NEW_COLORS using the palette registers.  To simplify use
  338. ;  of the utility, the colors are labeled by a two digit number.  The
  339. ;  first digit is the decimal equivalent of the three major colors RGB.
  340. ;  The second digit is rgb similarly.  Finally, two rows of blocks of the
  341. ;  color are displayed on screen.
  342. ;      This routine depends heavily on values remaining in registers
  343. ;  after BIOS calls.  Pay attention when modifying.
  344. ;    No registers are preserved.
  345. ;----------------------------------------------------------------------
  346. COLOR_BARS    PROC    NEAR
  347.  
  348.         CLD                ;String moves forward
  349.         MOV    SI,OFFSET NEW_COLORS    ;Set palette value to these
  350.         MOV    CX,16            ;Number of palette values
  351.  
  352.         MOV    DL,BOX_COL+8        ;Col for numerical labels
  353. CLR_BAR1:
  354.         PUSH    CX            ;Save counter
  355.         MOV    DH,BOX_ROW+6        ;Row for register # labels
  356.  
  357.         MOV    AH,2            ;Position cursor function
  358.         MOV    BH,DISPLAY_PAGE
  359.         INT    10H            ;Thru BIOS
  360.  
  361.         MOV    AL,16            ;Get palette #
  362.         SUB    AL,CL            ; in AL
  363.         PUSH    AX            ;Save palette #
  364.         XOR    AH,AH
  365.         AAA                ;Convert AL to decimal digits
  366.         MOV    CL,4            ;AH=10's, AL=1's
  367.         SHL    AH,CL
  368.         OR    AL,AH
  369.         CALL    HEX2CON            ;Write to screen
  370.  
  371.         SUB    DH,4            ;Row for value # labels
  372.         MOV    AH,2            ;Position cursor function
  373.         INT    10H            ;Thru BIOS
  374.  
  375.         LODSB                ;Get value in AL
  376.         POP    BX            ;Retrieve palette # in BL
  377.         MOV    BH,AL            ;Attribute in BH
  378.         MOV    AX,1000H        ;Set palette register fn
  379.         INT    10H            ;Thru BIOS
  380. ;----------------------------------------------------------------------
  381. ;  Translate the hex color code into our (RGB)(rgb) numbering and display.
  382. ;----------------------------------------------------------------------
  383.         MOV    AL,BH            ;Retrieve attribute
  384.         MOV    AH,AL            ;rgbRGB in both AH & AL
  385.         MOV    CL,3            ;Shift count
  386.         SHR    AL,CL            ;Put rgb in lower 4 bits
  387.  
  388.         AND    AH,7            ;RGB bits
  389.         MOV    CL,4            ;Shift count
  390.         SHL    AH,CL            ;Put RGB in upper 4 bits
  391.         OR    AL,AH            ;Combine into single byte
  392.         CALL    HEX2CON            ;Print AL to CON as 2 hex
  393.                         ; digits.
  394.         MOV    BH,DISPLAY_PAGE
  395.         DEC    DL            ;Box begins 1 col to the left
  396.         CALL    DRAW_BAR        ;Draw two rows
  397.  
  398.         ADD    DL,5            ;Col for next label
  399.         POP    CX            ;Restore counter
  400.         LOOP    CLR_BAR1
  401.         RET
  402. COLOR_BARS    ENDP
  403.  
  404. ;======================================================================
  405. ;  DRAW_BAR - Draw two rows of Block graphics char to show foreground
  406. ;  color.  AX,DX,CX destroyed.
  407. ;----------------------------------------------------------------------
  408. DRAW_BAR    PROC    NEAR
  409.  
  410.         CALL    DRAW_1            ;Call ourself to repeat
  411. DRAW_1:
  412.         INC    DH            ;Down one row
  413.         MOV    AH,2            ;Position cursor function
  414.         INT    10H            ;Thru BIOS
  415.  
  416.         MOV    AX,09DBH        ;Write repeated char/attr
  417.         MOV    CX,4            ; 4 copies of block
  418.         INT    10H            ; Thru BIOS
  419.  
  420.         RET                ;Double duty
  421. DRAW_BAR    ENDP
  422.  
  423. ;======================================================================
  424. ;  HEX2CON - print AL to CON as 2 hex digits.
  425. ;    AX destroyed.  Other registers preserved.
  426. ;-----------------------------------------------------------------------------
  427. HEX2CON        PROC    NEAR
  428.  
  429.         PUSH    AX            ;Save reg for second digit
  430.  
  431.         PUSH    CX            ;Save CX for use in shift
  432.         MOV    CL,4            ;Shift 4 bits
  433.         SHR    AL,CL            ;Get high 4 bits in low end
  434.         POP    CX            ;Restore register
  435.  
  436.         CALL    H2C            ;Print the digit in AL
  437.         POP    AX            ;Get back original AL
  438.         AND    AL,0FH            ;Take second digit
  439. H2C:
  440.         ADD    AL,90H            ;Convert AL to ASCII
  441.         DAA
  442.         ADC    AL,40H
  443.         DAA
  444.         MOV    AH,0EH            ;Write TTY
  445.         INT    10H            ; Thru BIOS
  446.  
  447.         RET                ;Double duty
  448.  
  449. HEX2CON        ENDP
  450.  
  451. ;======================================================================
  452. ;  Perform the screen save/restore.
  453. ;  SAVE:    SI=FFFF, DI=buffer address
  454. ;  RESTORE: SI=buffer address, DI=don't care
  455. ;----------------------------------------------------------------------
  456. SCREEN        PROC    NEAR
  457.  
  458.         CLD                ;String moves forward
  459.         MOV    BH,DISPLAY_PAGE        ;Just to be sure, reset page
  460.  
  461.         MOV    CX,NROW            ;Row loop
  462.         MOV    DH,BOX_ROW        ;Init row pointer
  463. ROW_LOOP:
  464.         PUSH    CX            ;Prepare for...
  465.         MOV    CX,NCOL            ;...column loop
  466.         MOV    DL,BOX_COL        ;Column Pointer
  467. COL_LOOP:
  468.         PUSH    CX            ;Need for write-char fn
  469.         MOV    AH,2            ;Position cursor fn
  470.         INT    10H            ;Thru BIOS
  471.  
  472.         CMP    SI,0FFFFH        ;SI =FFFF if SAVE
  473.         JE    DO_SAVE
  474.                         ;RESTORE
  475.         LODSW                ;AX <- [SI]
  476.                         ;AH=ATTR AL=CHAR
  477.         MOV    BL,AH            ;Put attribute where needed
  478.         MOV    AH,9            ;Write char fn
  479.         MOV    CX,01            ;Write one copy of char
  480.         INT    10H            ;Thru BIOS
  481.         JMP    SHORT DO_LOOP
  482. DO_SAVE:
  483.         MOV    AH,8            ;Get char & attribute fn
  484.         INT    10H            ;Thru BIOS
  485.         STOSW                ;[di+=2]=ax
  486. DO_LOOP:
  487.         INC    DL            ;Next column
  488.         POP    CX            ;Restore Counter
  489.         LOOP    COL_LOOP        ;Close Inner loop
  490.  
  491.         POP    CX            ;Return to outer loop
  492.         INC    DH            ;Next row
  493.         LOOP    ROW_LOOP        ;Close Outer loop
  494.         RET
  495.  
  496. SCREEN        ENDP
  497.  
  498. ;======================================================================
  499. ;  Clear a window (box) for our information on the screen.
  500. ;  Add a border, name, and help line for a nice touch.
  501. ;----------------------------------------------------------------------
  502. BOX_MSG        DB    BOX_COL+2,BOX_ROW,0B5H,"SPECTRUM 1.0",0C6H,0
  503. BOX_CHARS    DB    0C9H,0CDH,0BBH,0BAH,020H,0BAH,0C8H,0CDH,0BCH
  504. HELP_MSG    DB    BOX_COL+7,BOX_ROW+NROW-2
  505.         DB    "COLOR=",27,26,"  RGB=",24,25,"  rgb=PgUp/Dn  "
  506.         DB    "Save=END  Cancel=ESC  Default=HOME",0
  507.  
  508. CLR_BOX        PROC    NEAR
  509.  
  510.         MOV    AX,0600H        ;Scroll entire window fn
  511.         MOV    CH,BOX_ROW        ;Upper row
  512.         MOV    CL,BOX_COL        ;Left column
  513.         MOV    DH,BOX_ROW + NROW - 1    ;Bottom row
  514.         MOV    DL,BOX_COL + NCOL - 1    ;Right column
  515.         MOV    BH,ATTRIBUTE        ;Window color
  516.         INT    10H            ;Thru BIOS
  517.  
  518.         MOV    BH,DISPLAY_PAGE        ;Use current page
  519.         MOV    SI,OFFSET BOX_CHARS    ;Window border chars
  520.         MOV    DX,CX            ;Cursor from last call
  521.         MOV    CX,NROW            ;Number of rows to draw
  522. CB_1:
  523.         PUSH    CX            ;Save counter
  524.         MOV    DL,BOX_COL        ;Starting column
  525.  
  526.         MOV    AH,2            ;Position cursor
  527.         INT    10H            ; Thru BIOS
  528.  
  529.         LODSB                ;Get leftmost char
  530.         MOV    AH,0EH            ;Write char TTY
  531.         INT    10H            ; Thru BIOS
  532.  
  533.         LODSB                ;Get middle char
  534.         MOV    AH,0AH            ;Write repeated char
  535.         MOV    CX,NCOL-2        ; This many times
  536.         INT    10H            ; Thru BIOS
  537.  
  538.         MOV    AH,2            ;Position cursor
  539.         MOV    DL,BOX_COL + NCOL - 1    ;Col = righthand edge
  540.         INT    10H            ; Thru BIOS
  541.  
  542.         LODSB                ;Get rightmost char
  543.         MOV    AH,0EH            ;Write char TTY
  544.         INT    10H            ; Thru BIOS
  545.  
  546.         INC    DH            ;Next row
  547.         POP    CX            ;Restore counter
  548.  
  549.         CMP    CL,NROW            ;If first row
  550.         JE    CB_2            ; choose next 3 chars
  551.         CMP    CL,2            ;If last row
  552.         JE    CB_2            ; choose next 3 chars
  553.         SUB    SI,3            ;Else, repeat these 3 again
  554. CB_2:
  555.         LOOP    CB_1            ;Row loop
  556.  
  557.         MOV    SI,OFFSET BOX_MSG    ;Write program name on box
  558.         CALL    WR_MESSAGE
  559.         MOV    SI,OFFSET HELP_MSG    ;And help line on bottom
  560.         CALL    WR_MESSAGE
  561.  
  562.         RET
  563. CLR_BOX        ENDP
  564.  
  565. ;======================================================================
  566. ;  Fill in the window information on screen. String format is col,row,text,0.
  567. ;  DS:SI points to string.
  568. ;----------------------------------------------------------------------
  569. WR_MESSAGE    PROC    NEAR
  570.  
  571.         MOV    BH,DISPLAY_PAGE        ;This page
  572.         LODSW                ;Get intended position
  573.         MOV    DX,AX            ; in DX
  574.         MOV    AH,2            ;Position cursor
  575. MSG_LOOP:
  576.         INT    10H            ;Thru BIOS
  577.         MOV    AH,0EH            ;Write AL as TTY
  578.         LODSB                ;Get next char
  579.         OR    AL,AL            ;If 0, end of string
  580.         JNZ    MSG_LOOP        ; else, repeat
  581.         RET
  582.  
  583. WR_MESSAGE    ENDP
  584.  
  585. ;======================================================================
  586. ;  Video Int 10h intercept.  If mode is changed, reset colors.
  587. ;  A font load changes modes internally and causes a reload.
  588. ;----------------------------------------------------------------------
  589. INT_10        PROC    FAR
  590.  
  591.         OR    AH,AH            ;If video mode change
  592.         JZ    VIDEO_1            ; handle specially
  593.         CMP    AH,11H            ;Or possible font load
  594.         JZ    VIDEO_1            ; (internal mode change)
  595.         JMP    DWORD PTR CS:OLD_INT_10    ;Resume old Video interrupt
  596. VIDEO_1:
  597.         STI                ;Allow interrupts
  598.         PUSHF                ;Simulate original interrupt
  599.         CALL    DWORD PTR CS:OLD_INT_10    ; and return here
  600.  
  601.         PUSH    AX            ;Save used registers
  602.         PUSH    BX
  603.  
  604.         MOV    AH,0FH            ;Get current video mode
  605.         INT    10H            ; Thru BIOS
  606.         CMP    AL,4            ;If color text modes
  607.         JBE    VIDEO_2
  608.         CMP    AL,7            ; or mono text mode
  609.         JNE    VIDEO_4
  610. VIDEO_2:
  611.         PUSH    CX            ;Reset the palette regs
  612.         PUSH    SI
  613.  
  614.         MOV    CX,16            ;# of registers to set
  615.         MOV    SI,OFFSET CS:OLD_COLORS+15    ;end of colors
  616. VIDEO_3:
  617.         MOV    AX,1000H        ;Set palette register
  618.         MOV    BL,CL
  619.         DEC    BL            ;Palette # in BL
  620.         MOV    BH,CS:[SI]        ;Attribute in BH
  621.         DEC    SI            ;Move pointer
  622.         INT    10H            ; Thru BIOS
  623.         LOOP    VIDEO_3
  624.  
  625.         POP    SI            ;Restore registers
  626.         POP    CX
  627. VIDEO_4:
  628.         POP    BX
  629.         POP    AX
  630.         RET    2            ;Far return, pop flags
  631.                         ;to simulate IRET
  632. INT_10        ENDP
  633.  
  634. ;======================================================================
  635. ;  DOS Int 21h intercept.  Set flag while uninterruptable
  636. ;  The purpose of this procedure is to keep pop-up from taking control
  637. ;  of the machine when doing so would cause a crash.
  638. ;  (Function 0 changed to 4CH to avoid DOS problems with CS register.)
  639. ;----------------------------------------------------------------------
  640. INT_21        PROC    FAR
  641.  
  642.         MOV    CS:LO_FN_FLAG,0        ;Assume Not function 1-Ch
  643.         CMP    AH,0            ;If program is using DOS fn 0
  644.         JNE    CHECK
  645.         MOV    AH,4CH            ;Change it to 4Ch
  646. GO_DIRECT:
  647.         JMP    DWORD PTR CS:OLD_INT_21    ;Jump to original routine
  648. CHECK:
  649.         CMP    AH,0CH            ;DOS functions call under 0DH
  650.         JA    GO_DIRECT
  651.  
  652.         INC    CS:LO_FN_FLAG        ;Is low function
  653.  
  654.         PUSHF                ;Simulate interrupt
  655.         CALL    DWORD PTR CS:OLD_INT_21    ; with FAR CALL
  656.  
  657.         MOV    CS:LO_FN_FLAG,0        ;Turn off flag
  658.         RET    2            ;Return to INT source and
  659.                         ;discard old flags
  660. INT_21    ENDP
  661.  
  662. ;======================================================================
  663. ;  Data here is allocated after the program loads into memory to save space
  664. ;  in the COM file so the basic listing will be smaller.
  665. ;  PC variable used to keep track of relative addresses.
  666. ;----------------------------------------------------------------------
  667. PC        =    $            ;Set imaginary counter
  668.  
  669. SCREEN_BUF    =    PC            ;DB NROW*NCOL*2 DUP(?)
  670. PC        =    PC + NROW * NCOL * 2
  671.  
  672. NEW_COLORS    =    PC            ;DB 16 DUP(?)
  673. PC        =    PC + 16
  674.  
  675. LAST_BYTE    =    PC
  676.  
  677. ;======================================================================
  678. ;  Hook the necessary interrupts to avoid a collision.
  679. ;  Terminate and Stay Resident (TSR).
  680. ;----------------------------------------------------------------------
  681. INITIALIZE    PROC    NEAR
  682.         ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING, SS:CSEG
  683.  
  684.         MOV    DX,OFFSET COPYRIGHT    ;Say who we are as we leave
  685.         MOV    AH,9            ;Display string function
  686.         INT    21H            ;Thru DOS
  687.  
  688. ;----------------------------------------------------------------------
  689. ;  If command line parameters are present, load them into the registers
  690. ;----------------------------------------------------------------------
  691.         CMP    BYTE PTR DS:[80H],48    ;Must be 48 chars min to load
  692.         JB    NO_ARGS
  693.  
  694.         MOV    SI,82H            ;First parameter
  695.         MOV    DI,OFFSET OLD_COLORS    ;Destination
  696.         MOV    CX,16
  697. PARM_LOOP:
  698.         LODSW                ;Get digits
  699.         AND    AX,0CFCFH        ;Ascii to hex
  700.         SHL    AH,1
  701.         SHL    AH,1
  702.         SHL    AH,1
  703.         OR    AL,AH            ;Combine in AH
  704.         STOSB                ;Put in OLD_COLORS
  705.         INC    SI            ;Skip past delimiter
  706.         MOV    BH,AL            ;Palette value in BH
  707.         MOV    AX,1000H        ;Set palette fn
  708.         MOV    BL,16            ;Get palette number
  709.         SUB    BL,CL            ; in BL
  710.         INT    10H            ;Thru BIOS
  711.         LOOP    PARM_LOOP
  712. NO_ARGS:
  713. ;----------------------------------------------------------------------
  714. ;  Check if already loaded in memory.  Don't load multiple copies.
  715. ;----------------------------------------------------------------------
  716.         MOV    WORD PTR [ENTPT+0],0    ;Modify to avoid false match
  717.         MOV    WORD PTR [ENTPT+2],0
  718.  
  719.         XOR    BX,BX            ;BX = segment to compare
  720.         MOV    AX,CS            ;AX = our segment
  721. NEXT_PARA:
  722.         INC    BX            ;Next paragraph
  723.         CMP    AX,BX            ;If current paragraph...
  724.         MOV    ES,BX            ;Set search segment
  725.         JE    END_SEARCH        ;...stop
  726.         MOV    SI,OFFSET COPYRIGHT    ;String to compare
  727.         MOV    DI,SI            ;Offset is same
  728.         MOV    CX,16            ;Compare first 16 bytes
  729.         REP    CMPSB            ;CMP DS:SI TO ES:DI
  730.         OR    CX,CX            ;All matched?
  731.         JNZ    NEXT_PARA        ;No.
  732.                         ;Found a copy in memory
  733.         CMP    BYTE PTR DS:[80H],48    ;If no parameters
  734.         JL    LEAVE_NO_TRACE        ; do nothing
  735.  
  736.         MOV    SI,OFFSET OLD_COLORS    ;Load colors into memory
  737.         MOV    DI,SI
  738.         MOV    CX,16
  739.         REP    MOVSB            ;From DS:SI to ES:DI
  740. LEAVE_NO_TRACE:
  741.         MOV    AX,4C01H        ;Terminate with 'error'
  742.         INT    21H            ;Thru DOS
  743. END_SEARCH:
  744. ;----------------------------------------------------------------------
  745. ;  Get a pointer to the DOS Critical Flag, a one-byte location in low memory
  746. ;  that is set when DOS is in an uninterruptable state.  Location is returned
  747. ;  in ES:BX.  This is undocumented, but works in DOS 2.0 - 3.21
  748. ;----------------------------------------------------------------------
  749.         MOV    AH,34H            ;Get Interrupt Flag address
  750.         INT    21H
  751.  
  752.         MOV    WORD PTR DOS_FLAG[0],BX    ;offset
  753.         MOV    WORD PTR DOS_FLAG[2],ES    ;segment
  754. ;----------------------------------------------------------------------
  755. ;  Hook the keyboard interrupt 9h for the hot-key detection routine.
  756. ;  Hook DOS Interrupt 21h to set busy flag.
  757. ;----------------------------------------------------------------------
  758.         PUSH    DS            ;Reset ES to point to same
  759.         POP    ES            ; segment as DS
  760.  
  761.         MOV    AL,9            ;Interrupt number
  762.         MOV    DI,OFFSET OLD_INT_9    ;Store vector here
  763.         MOV    DX,OFFSET INT_9        ;New interrupt procedure
  764.         CALL    SET_INT            ;Make change
  765.  
  766.         MOV    AL,10H
  767.         MOV    DI,OFFSET OLD_INT_10
  768.         MOV    DX,OFFSET INT_10
  769.         CALL    SET_INT
  770.  
  771.         MOV    AL,21H
  772.         MOV    DI,OFFSET OLD_INT_21
  773.         MOV    DX,OFFSET INT_21
  774.         CALL    SET_INT
  775.  
  776. ;----------------------------------------------------------------------
  777. ;  Deallocate the copy of the environment loaded with the program.
  778. ;  Establish memory residency and terminate.
  779. ;----------------------------------------------------------------------
  780.         MOV    AX,WORD PTR DS:[2CH]    ;Address of environment
  781.         MOV    ES,AX            ;In ES register
  782.         MOV    AH,49H            ;Release allocated memory
  783.         INT    21H            ;Thru DOS
  784.  
  785.         MOV    DX,(OFFSET LAST_BYTE - OFFSET CSEG + 15) SHR 4
  786.         MOV    AX,3100H        ;Keep (TSR)
  787.         INT    21H            ;Thru DOS
  788.  
  789. INITIALIZE    ENDP
  790.  
  791. ;======================================================================
  792. ;  Get/Save/Set the interrupt vector.  AL contains vector number.
  793. ;  ES:DI points to DWORD destination for old address.
  794. ;  DS:DX points to new interrupt address.  AX destroyed.
  795. ;----------------------------------------------------------------------
  796. SET_INT        PROC    NEAR
  797.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  798.  
  799.         PUSH    AX            ;Save vector # in AL
  800.         MOV    AH,35H            ;Get address function
  801.         INT    21H            ;Thru DOS
  802.         MOV    WORD PTR [DI+0],BX    ;Save address in ES:DI
  803.         MOV    WORD PTR [DI+2],ES
  804.         POP    AX            ;Get AL back
  805.         MOV    AH,25H            ;Set new address to DS:DX
  806.         INT    21H            ;Thru DOS
  807.         RET
  808.  
  809. SET_INT        ENDP
  810.  
  811. CSEG    ENDS
  812. END    ENTPT
  813.