home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / msugold.asm < prev    next >
Assembly Source File  |  2020-01-01  |  21KB  |  711 lines

  1.     PAGE    64,132
  2.     TITLE    GOLD key from NUMLOCK
  3.     NAME    GOLD
  4. ;
  5. ; This program maps the NUM LOCK key (scan code 45H) to another key
  6. ; (default is F1, scan code 3BH) for use with Kermit emulating a DEC VTxxx
  7. ; terminal.
  8. ;
  9. ; Version 2.4 -    June 1992
  10. ;        Fixed spurious recognition of PAUSE key as GOLD (caused by
  11. ;        presence of 45H in six byte sequence for PAUSE)
  12. ; Version 2.3 - June 1992
  13. ;        Added facility to have modifier (CTRL, SHIFT, ALT)
  14. ;        for chosen key
  15. ; Version 2.2 -    February 1992
  16. ;        Added safety checks to installation code
  17. ; Version 2.1 - June 1991
  18. ;        Changed default multiplex ID to 09FH (was 0DCH) to avoid
  19. ;        problems with some versions of the KEYB program.
  20. ; Version 2.0 - March 1991
  21. ;        SHIFT and NUM LOCK acts as normal NUM LOCK
  22. ;        ALT and NUM LOCK inverts current GOLD status
  23. ;        Fix for problem with some clone BIOSes
  24. ;        Fix non-detection of BIOS intercept support
  25. ;        Use INT 09H if interrupt intercept not available
  26. ;
  27. ; Bob Eager
  28. ;    rde@ukc.ac.uk        USENET (preferred over ibmpcug)
  29. ;    rde@ibmpcug.co.uk    USENET
  30. ;    100016,2770        CompuServe
  31. ;    +44 227 367270        Telephone
  32. ;
  33. ; You may distribute this program freely as long as all of the files that
  34. ; make up the package (see the documentation file) are kept with it (including
  35. ; this source file) and you don't try to make money from it either by selling
  36. ; it directly or incorporating it into a product you sell.
  37. ;
  38. ; Values for exit status:
  39. ;
  40. ;    0    - success
  41. ;    1    - could not install program
  42. ;    2    - no BIOS support present
  43. ;    3    - unsupported DOS version (< 3.0)
  44. ;    4    - invalid parameter
  45. ;
  46. ; Constants
  47. ; ---------
  48. ;
  49.     CR    = 0DH            ; Carriage return
  50.     LF    = 0AH            ; Linefeed
  51.     TAB    = 09H            ; Tab
  52. ;
  53.     ID    = 0DCH            ; Multiplex ID
  54. ;
  55.     NUMSCAN    = 045H            ; Num Lock scan code
  56.     P1SCAN    = 0E1H            ; Pause scan code byte 1
  57.     P2SCAN    = 01DH            ; Pause scan code byte 2
  58. ;
  59.     CSEG    SEGMENT BYTE PUBLIC 'CODE'
  60. ;
  61.     $BEGIN    EQU    $
  62. ;
  63.     ORG    0100H
  64. ;
  65.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
  66. ;
  67.     SUBTTL    Data areas
  68.     PAGE+
  69. ;
  70. ; The following jump to the initialisation code also provides three bytes
  71. ; of storage, which are used later by the resident part of the code.
  72. ;
  73. BEGIN:    JMP    INIT            ; jump to initialisation code
  74. ;
  75. ; Redefine storage for the above jump
  76. ;
  77.     ORG    BEGIN
  78. MBIT    EQU    THIS BYTE        ; Make/Break bit
  79.     ORG    BEGIN+1
  80. ONOFF    EQU    THIS BYTE        ; On/Off flag (0=off, initially on)
  81.     ORG    BEGIN+2
  82. SHFLAG    EQU    THIS BYTE        ; Shift bits changed flag (0=No, 1=Yes)
  83. ;
  84. ; Back to normal storage allocation
  85. ;
  86.     ORG    BEGIN+3
  87. ;
  88. ; The following four values may be changed if required.
  89. ;
  90. ; MPID        is the multiplex ID, and will only need alteration if some
  91. ;        other TSR is using the same value. Choose another at random
  92. ;        until it works!
  93. ; NEWKEY    is the make code value for the key to replace NUM LOCK.
  94. ;            Examples:
  95. ;                3B    - F1
  96. ;                1E    - A
  97. ;        See a key code table (e.g. in IBM Technical Reference Manual)
  98. ;        for the rest.
  99. ; MODE        is used to force a particular operation mode; it is particularly
  100. ;        useful when a BIOS says that it supports the keyboard intercept
  101. ;        function, but doesn't.
  102. ; MODBIT    is a way of specifying that a particular modifier key (CTRL,
  103. ;        ALT, or SHIFT) should be forced down when the replacement
  104. ;        keystroke is transmitted. Set as follows:
  105. ;            08H    - ALT
  106. ;            04H    - CTRL
  107. ;            02H    - left SHIFT
  108. ;            01H    - right SHIFT
  109. ;        These bits may be combined (e.g. 0CH for CTRL+ALT). Either
  110. ;        SHIFT key will generally work.
  111. ;
  112. MPID    DB    09FH            ; 102H Multiplex ID ** DO NOT MOVE **
  113. NEWKEY    DB    03BH            ; 103H Replacement key ** DO NOT MOVE **
  114. ;NEWKEY    DB    01EH            ; 103H Replacement key ** DO NOT MOVE **
  115. MODE    DB    0            ; 104H Mode selector ** DO NOT MOVE **
  116.                     ;    00H = auto
  117.                     ;    01H = use INT 15H
  118.                     ;    02H = use INT 09H
  119. MODBIT    DB    00H            ; 105H Replacement key modifier bit
  120. ;MODBIT    DB    08H            ; 105H Replacement key modifier bit
  121.                     ; *** DO NOT MOVE ***
  122. SAVESH    DB    0            ; Saved copy of shift flags
  123. STATE    DB    0            ; State for PAUSE recognition
  124. ;                    ; 0 = normal scan
  125. ;                    ; 1 = after E1
  126. ;                    ; 2 = after E1 1D
  127. ;
  128. INTOFF    DW    ?            ; Old interrupt vector offset
  129. INTSEG    DW    ?            ; Old interrupt vector segment
  130. I2FOFF    DW    ?            ; Old INT 2FH offset
  131. I2FSEG    DW    ?            ; Old INT 2FH segment
  132. ;
  133.     SUBTTL    INT 2FH (multiplex) handler
  134.     PAGE+
  135. ;
  136. ; This INT 2FH handler is hooked into the MS-DOS multiplex interrupt.
  137. ;
  138. ;    Input parameters:
  139. ;
  140. ;        AH    = handler ID (MPID for this program)
  141. ;              Calls with unrecognised handler IDs are passed on
  142. ;        AL    = function code
  143. ;                00    - get installation status
  144. ;                01    - get GOLD status
  145. ;                02    - set GOLD status
  146. ;
  147. ;    Output parameters:
  148. ;
  149. ;        AL    = result
  150. ;                Get installation status:
  151. ;                    FFH    - Already installed
  152. ;                Get GOLD status:
  153. ;                    00H    - OFF
  154. ;                    01H    - ON
  155. ;                Set GOLD status:
  156. ;                    00H    - OK
  157. ;
  158. I2FHAN    PROC    FAR
  159. ;
  160.     ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  161. ;
  162.     CMP    AH,MPID            ; for this program?
  163.     JE    I2FH10            ; j if so
  164.     JMP    DWORD PTR I2FOFF    ; else use old handler
  165. ;
  166. I2FH10:    OR    AL,AL            ; AL=0, get installation status?
  167.     JNE    I2FH20            ; j if not
  168.     MOV    AL,0FFH            ; indicate already installed
  169.     IRET                ; and return
  170. ;
  171. I2FH20:    DEC    AL            ; AL=1, get GOLD status?
  172.     JNE    I2FH30            ; j if not
  173.     MOV    AL,ONOFF        ; get value
  174.     IRET                ; and return
  175. ;
  176. I2FH30:    DEC    AL            ; AL=2, set GOLD status?
  177.     JNE    I2FH40            ; j if not
  178.     MOV    ONOFF,DL        ; set new value, drop through
  179. ;
  180. I2FH40:    IRET                ; and return
  181. ;
  182. I2FHAN    ENDP
  183. ;
  184.     SUBTTL    INT 15H (system services) handler
  185.     PAGE+
  186. ;
  187. ; This INT 15H handler is hooked into the BIOS system services interrupt.
  188. ; It is used only if the keyboard interrupt intercept capability is available
  189. ; in the BIOS.
  190. ;
  191. ;    Input parameters:
  192. ;        AH    - function. Only 4FH (keyboard intercept) is handled;
  193. ;              other values cause the action to be passed to the
  194. ;              previous handler.
  195. ;        AL    - scan code for key just pressed
  196. ;
  197. ;    Output parameters:
  198. ;        AL    - input scan code, or mapped version of it.
  199. ;        CY    - set to indicate that keystroke is to be processed.
  200. ;        All other register contents are preserved.
  201. ;
  202.     ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  203. ;
  204. I15HAN    PROC    FAR
  205. ;
  206.     CMP    AH,4FH            ; keyboard intercept function?
  207.     JE    I15H10            ; j if so
  208.     JMP    DWORD PTR INTOFF    ; else call old handler
  209. ;
  210. I15H10:    PUSH    AX            ; save register
  211.     PUSH    AX            ; save again
  212.     XOR    AL,AL            ; set zero
  213.     XCHG    AL,SHFLAG        ; get and clear flags bit
  214.     OR    AL,AL            ; set condition flags
  215.     JZ    I15H15            ; j if not currently changed
  216.     PUSH    DS            ; save data segment
  217.     MOV    AX,40H            ; BIOS data segment
  218.     MOV    DS,AX            ; address it
  219.     MOV    AL,CSEG:SAVESH        ; get saved keyboard flags
  220.     MOV    DS:[17H],AL        ; restore them
  221.     POP    DS            ; recover data segment
  222. I15H15:    POP    AX            ; recover register
  223.     CMP    STATE,0            ; normal state?
  224.     JE    I15H17            ; j if so
  225.     CMP    STATE,1            ; had just one PAUSE byte?
  226.     JE    I15H16            ; j if so
  227.     MOV    STATE,0            ; else in state 2 - reset state...
  228.     JMP    I15H60            ; ...and skip checks
  229. ;
  230. I15H16:    CMP    AL,P2SCAN        ; got second byte now?
  231.     JE    I15H18            ; j if so, => state 2
  232.     DEC    STATE            ; else reset state
  233.     JMP    SHORT I15H19        ; and perform normal checks
  234. ;
  235. I15H17:    CMP    AL,P1SCAN        ; possible PAUSE sequence?
  236.     JNE    I15H19            ; j if not, else => state 1
  237. ;
  238. I15H18:    INC    STATE            ; update state
  239.     JMP    SHORT I15H60        ; skip checks
  240. ;
  241. I15H19:    MOV    AH,AL            ; copy scan code
  242.     AND    AH,80H            ; isolate make/break bit
  243.     MOV    MBIT,AH            ; save it
  244.     AND    AL,7FH            ; mask out make/break bit
  245.     CMP    AL,NUMSCAN        ; NUM LOCK?
  246.     JNE    I15H60            ; j if not - just return
  247. ;
  248. ; NUM LOCK has been pressed. Check for SHIFT (retain normal action).
  249. ;
  250.     PUSH    DS            ; save segment
  251.     MOV    AX,40H            ; BIOS data segment
  252.     MOV    DS,AX            ; address BIOS data segment
  253.     MOV    AL,DS:[17H]        ; get keyboard flags
  254.     POP    DS            ; recover segment
  255.     AND    AL,0FH            ; mask out lock status
  256.     MOV    AH,AL            ; take copy for later comparison
  257.     CMP    ONOFF,0            ; is GOLD on?
  258.     JE    I15H20            ; j if not - do nothing here
  259.     AND    AL,03H            ; mask out ALT and CTRL status
  260.     JE    I15H20            ; j if not shifted
  261.     CMP    AH,AL            ; see if just SHIFT
  262.     JE    I15H60            ; if so, treat as normal NUM LOCK call
  263. ;
  264. ; Check for ALT (invert GOLD status). This needs to work whether GOLD is
  265. ; ON or OFF.
  266. ;
  267. I15H20:    MOV    AL,AH            ; recover shift status bits
  268.     AND    AL,08H            ; mask out CTRL and SHIFT status
  269.     JE    I15H40            ; j if not ALT - pass through
  270.     CMP    AH,AL            ; see if just ALT
  271.     JNE    I15H40            ; j if not - pass through
  272.     TEST    MBIT,80H        ; make operation?
  273.     JNE    I15H30            ; j if not - ignore
  274.     XOR    ONOFF,1            ; flip GOLD ON/OFF flag
  275. ;
  276. I15H30:    CLC                ; absorb keystroke
  277.     POP    AX            ; recover register
  278.     RETF    2            ; return, preserving flags
  279. ;
  280. I15H40:    CMP    ONOFF,0            ; is GOLD on?
  281.     JE    I15H60            ; j if not - do nothing
  282. ;
  283. I15H50:    PUSH    DS            ; save data segment
  284.     MOV    AX,40H            ; BIOS data segment
  285.     MOV    DS,AX            ; address BIOS data segment
  286.     MOV    AH,DS:[17H]        ; get keyboard flags
  287.     MOV    AL,CSEG:MODBIT        ; get extra modifier
  288.     OR    AL,AH            ; combine with existing ones
  289.     MOV    DS:[17H],AL        ; update keyboard flags
  290.     POP    DS            ; recover segment
  291.     MOV    SAVESH,AH        ; save old flags
  292.     INC    SHFLAG            ; mark changed
  293.     POP    AX            ; recover register
  294.     MOV    AL,NEWKEY        ; set replacement scan code
  295.     OR    AL,MBIT            ; include make/break bit, drop through
  296.     STC                ; make sure keystroke processed
  297.     RETF    2            ; return, preserving flags
  298. ;
  299. I15H60:    STC                ; make sure keystroke processed
  300.     POP    AX            ; recover register
  301.     RETF    2            ; return, preserving flags
  302. ;
  303. I15HAN    ENDP
  304. ;
  305. I15LEN    =    $ - I15HAN        ; length of INT 15H handler
  306. ;
  307.     SUBTTL    INT 09H (keyboard interrupt) handler
  308.     PAGE+
  309. ;
  310. ; This INT 09H handler is hooked into the keyboard interrupt vector.
  311. ; It is used only if the keyboard interrupt intercept facility is not
  312. ; available in the BIOS, and is moved in memory so that the space occupied
  313. ; by the INT 15H handler is not wasted.
  314. ;
  315. ;    Input parameters:
  316. ;        No explicit inputs. Implicit input from the keyboard
  317. ;        hardware.
  318. ;
  319. ;    Output parameters:
  320. ;        No explicit outputs. Control is passed to the normal keyboard
  321. ;        interrupt handler unless the keystroke is to be modified or
  322. ;        absorbed. Modified keystrokes are placed into the BIOS input
  323. ;        buffer.
  324. ;        All registers are preserved.
  325. ;
  326. I09HAN    PROC    FAR
  327. ;
  328.     PUSH    AX            ; save register
  329.     IN    AL,60H            ; get next character from hardware
  330.     PUSH    AX            ; save character
  331.     XOR    AL,AL            ; set zero
  332.     XCHG    AL,SHFLAG        ; get and clear flags bit
  333.     OR    AL,AL            ; set condition flags
  334.     JZ    I09H05            ; j if not currently changed
  335.     PUSH    DS            ; save data segment
  336.     MOV    AX,40H            ; BIOS data segment
  337.     MOV    DS,AX            ; address it
  338.     MOV    AL,CSEG:SAVESH        ; get saved keyboard flags
  339.     MOV    DS:[17H],AL        ; restore them
  340.     POP    DS            ; recover data segment
  341. I09H05:    POP    AX            ; recover character
  342.     CMP    STATE,0            ; normal state?
  343.     JE    I09H07            ; j if so
  344.     CMP    STATE,1            ; had just one PAUSE byte?
  345.     JE    I09H06            ; j if so
  346.     MOV    STATE,0            ; else in state 2 - reset state...
  347.     JMP    I09H80            ; ...and skip checks
  348. ;
  349. I09H06:    CMP    AL,P2SCAN        ; got second byte now?
  350.     JE    I09H08            ; j if so, => state 2
  351.     DEC    STATE            ; else reset state
  352.     JMP    SHORT I09H09        ; and perform normal checks
  353. ;
  354. I09H07:    CMP    AL,P1SCAN        ; possible PAUSE sequence?
  355.     JNE    I09H09            ; j if not, else => state 1
  356. ;
  357. I09H08:    INC    STATE            ; update state
  358.     JMP    I09H80            ; skip checks
  359. ;
  360. I09H09:    MOV    AH,AL            ; copy scan code
  361.     AND    AH,80H            ; isolate make/break bit
  362.     MOV    MBIT,AH            ; save it
  363.     AND    AL,7FH            ; mask out make/break bit
  364.     CMP    AL,NUMSCAN        ; NUM LOCK?
  365.     JE    I09H10            ; j if so
  366.     JMP    I09H80            ; else just pass on to original handler
  367. ;
  368. ; NUM LOCK has been pressed. Check for SHIFT (retain normal action).
  369. ;
  370. I09H10:    PUSH    DS            ; save segment
  371.     MOV    AX,40H            ; BIOS data segment
  372.     MOV    DS,AX            ; address BIOS data segment
  373.     MOV    AL,DS:[17H]        ; get keyboard flags
  374.     POP    DS            ; recover segment
  375.     AND    AL,0FH            ; mask out lock status
  376.     MOV    AH,AL            ; take copy for later comparison
  377.     CMP    ONOFF,0            ; is GOLD on?
  378.     JE    I09H20            ; j if not - do nothing here
  379.     AND    AL,03H            ; mask out ALT and CTRL status
  380.     JE    I09H20            ; j if not shifted
  381.     CMP    AH,AL            ; see if just SHIFT
  382.     JNE    I09H20            ; j if not
  383.     JMP    I09H80            ; else treat as normal NUM LOCK call
  384. ;
  385. ; Check for ALT (invert GOLD status). This needs to work whether GOLD is
  386. ; ON or OFF.
  387. ;
  388. I09H20:    MOV    AL,AH            ; recover shift status bits
  389.     AND    AL,08H            ; mask out CTRL and SHIFT status
  390.     JE    I09H30            ; j if not ALT - pass through
  391.     CMP    AH,AL            ; see if just ALT
  392.     JNE    I09H30            ; j if not - pass through
  393.     TEST    MBIT,80H        ; make operation?
  394.     JNE    I09H70            ; j if not - ignore
  395.     XOR    ONOFF,1            ; flip GOLD ON/OFF flag
  396.     JMP    SHORT I09H70        ; absorb keystroke and exit
  397. ;
  398. I09H30:    CMP    ONOFF,0            ; is GOLD on?
  399.     JE    I09H80            ; j if not - pass through
  400. ;
  401. I09H40:    TEST    MBIT,80H        ; break code?
  402.     JNZ    I09H70            ; j if so - ignore
  403.     PUSH    DS            ; save segment
  404.     PUSH    SI            ; save register
  405.     PUSH    BX            ; save register
  406.     MOV    AX,40H            ; BIOS data segment
  407.     MOV    DS,AX            ; address it
  408.     MOV    BX,DS:[1CH]        ; get offset of next slot in buffer
  409.     MOV    SI,BX            ; save for later
  410.     ADD    BX,2            ; advance pointer
  411.     CMP    BX,DS:[82H]        ; time to wrap?
  412.     JNZ    I09H50            ; j if not
  413.     MOV    BX,DS:[80H]        ; else do it
  414. ;
  415. I09H50:    CMP    BX,DS:[1AH]        ; buffer is full?
  416.     JZ    I09H60            ; j if so - discard character
  417.     MOV    AH,NEWKEY        ; set replacement scan code
  418.     XOR    AL,AL            ; extended code
  419.     MOV    WORD PTR [SI],AX    ; set into buffer
  420.     MOV    DS:[1CH],BX        ; save updated buffer pointer
  421.     MOV    AH,DS:[17H]        ; get keyboard flags
  422.     MOV    AL,CSEG:MODBIT        ; get extra modifier
  423.     OR    AL,AH            ; combine with existing ones
  424.     MOV    DS:[17H],AL        ; update keyboard flags
  425.     MOV    CSEG:SAVESH,AH        ; save old flags
  426.     INC    SHFLAG            ; mark changed
  427. ;
  428. I09H60:    POP    BX            ; recover register
  429.     POP    SI            ; recover register
  430.     POP    DS            ; recover segment
  431. ;
  432. ; Clear the keyboard port, acknowledging the character.
  433. ;
  434. I09H70:    IN    AL,61H            ; get control port
  435.     MOV    AH,AL            ; copy for later reset
  436.     OR    AL,80H            ; set bit to acknowledge
  437.     JMP    SHORT $+2        ; wait for settle
  438.     OUT    61H,AL            ; do the acknowledge
  439.     JMP    SHORT $+2        ; wait for settle
  440.     MOV    AL,AH            ; get original setting
  441.     OUT    61H,AL            ; put it back
  442.     JMP    SHORT $+2        ; wait for settle
  443.     MOV    AL,20H            ; End-Of-Interrupt
  444.     OUT    20H,AL            ; send to interrupt controller
  445.     POP    AX            ; recover register
  446.     IRET                ; return without calling original
  447. ;
  448. I09H80:    POP    AX            ; recover register
  449.     JMP    DWORD PTR INTOFF    ; jump to original interrupt handler
  450. ;
  451. I09HAN    ENDP
  452. ;
  453. I09LEN    =    $ - I09HAN        ; length of INT 09H handler
  454. ;
  455.     SUBTTL    Initialisation code
  456.     PAGE+
  457. ;
  458. ; This is the program initialisation code. It is not present in the resident
  459. ; copy of the program.
  460. ;
  461.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
  462. ;
  463. INIT:    MOV    ONOFF,1            ; set initial value
  464.     MOV    SHFLAG,0        ; set initial value
  465.     MOV    STATE,0            ; set initial value
  466. ;
  467. ; Select the operating mode
  468. ;
  469.     CMP    MODE,2            ; force INT 09H to be used?
  470.     JE    INIT50            ; j if so
  471.     PUSH    ES            ; save ES
  472.     MOV    AH,0C0H            ; see if keyboard intercept supported
  473.     INT    15H            ; get system configuration parameters
  474.     JNC    INIT10            ; j if configuration call supported
  475.     POP    ES            ; recover ES
  476.     JMP    SHORT INIT20        ; try for INT 09H mode
  477. ;
  478. INIT10:    TEST    BYTE PTR ES:[BX+5],10H    ; see if intercept flag set
  479.     POP    ES            ; recover ES
  480.     JNE    INIT30            ; j if intercept supported - use it
  481. ;
  482. INIT20:    CMP    MODE,1            ; force INT 15H mode?
  483.     JNE    INIT40            ; j if not - use INT 09H mode
  484.     LEA    DX,MES0            ; 'Sorry - this machine does not...'
  485.     MOV    AH,9            ; output message
  486.     INT    21H            ; do it
  487.     MOV    AX,4C02H        ; exit with error status
  488.     INT    21H
  489. ;
  490. INIT30:    MOV    MODE,1            ; select INT 15H mode
  491.     JMP    SHORT INIT50        ; check DOS version now
  492. ;
  493. INIT40:    MOV    MODE,2            ; select INT 09H mode
  494. ;
  495. ; The INT 2FH code will work only on DOS 3.0 and above. See if it is OK
  496. ; to use it.
  497. ;
  498. INIT50:    MOV    AX,3000H        ; get DOS version
  499.     INT    21H            ; returns minor in AH, major in AL
  500.     CMP    AL,3            ; see if 3 or greater
  501.     JGE    INIT60            ; j if so - OK
  502.     LEA    DX,MES1            ; 'Sorry - DOS 3.0 or above is...'
  503.     MOV    AH,9            ; output message
  504.     INT    21H            ; do it
  505.     MOV    AX,4C03H        ; exit with error status
  506.     INT    21H
  507. ;
  508. ; See if already installed
  509. ;
  510. INIT60:    MOV    AH,MPID            ; multiplex ID
  511.     XOR    AL,AL            ; function 00H
  512.     XOR    BX,BX            ; zero for safety
  513.     XOR    CX,CX            ; zero for safety
  514.     XOR    DX,DX            ; zero for safety
  515.     INT    2FH            ; call multiplex
  516.     PUSH    CS            ; restore DS in case corrupted...
  517.     POP    DS            ; ...by other program
  518.     PUSH    CS            ; restore ES...
  519.     POP    ES            ; ...for same reason
  520.     OR    AL,AL            ; see if OK to install (AL unchanged)
  521.     JZ    INIT70            ; j if so
  522.     CMP    AL,0FFH            ; already installed?
  523.     JE    INIT100            ; j if so - skip installation
  524.     LEA    DX,MES2            ; 'Cannot install program'
  525.     MOV    AH,9            ; output message
  526.     INT    21H            ; do it
  527.     MOV    AX,4C01H        ; exit with error status
  528.     INT    21H
  529. ;
  530. ; Program is not installed; install it now.
  531. ;
  532. INIT70:    PUSH    ES            ; save segment
  533.     MOV    AX,352FH        ; get old INT 2FH handler
  534.     INT    21H            ; returns value in ES:BX
  535.     MOV    I2FOFF,BX        ; save offset
  536.     MOV    I2FSEG,ES        ; save segment
  537.     LEA    DX,I2FHAN        ; point to new INT 2FH handler
  538.     MOV    AX,252FH        ; set INT 2FH vector
  539.     INT    21H            ; from DS:DX
  540. ;
  541. ; Perform installation conditional on the selected mode
  542. ;
  543.     CMP    MODE,1            ; use INT 15H mode?
  544.     JNE    INIT80            ; j if not - set up for INT 09H
  545. ;
  546. ; Use the INT 15H code, which uses the BIOS keyboard interrupt intercept
  547. ;
  548.     MOV    AX,3515H        ; get old INT 15H handler
  549.     INT    21H            ; returns value in ES:BX
  550.     MOV    INTOFF,BX        ; save offset
  551.     MOV    INTSEG,ES        ; save segment
  552.     LEA    DX,I15HAN        ; point to new INT 15H handler
  553.     MOV    AX,2515H        ; set INT 15H vector
  554.     INT    21H            ; from DS:DX
  555.     POP    ES            ; recover segment
  556.     MOV    WORD PTR INTLEN,I15LEN    ; save interrupt routine length
  557.     JMP    SHORT INIT90        ; rejoin common code
  558. ;
  559. ; Use the INT 09H code, which uses the keyboard hardware interrupt
  560. ;
  561. INIT80:    MOV    AX,3509H        ; get old INT 09H handler
  562.     INT    21H            ; returns value in ES:BX
  563.     MOV    INTOFF,BX        ; save offset
  564.     MOV    INTSEG,ES        ; save segment
  565.     LEA    DX,I15HAN        ; point to new INT 09H handler
  566.                     ; (where it WILL be)
  567.     MOV    AX,2509H        ; set INT 09H vector
  568.     INT    21H            ; from DS:DX
  569.     POP    ES            ; recover segment
  570.     MOV    CX,I09LEN        ; get interrupt routine length
  571.     MOV    INTLEN,CX        ; save it
  572.     CLD                ; autoincrement
  573.     MOV    SI,OFFSET I09HAN    ; get address of interrupt routine
  574.     MOV    DI,OFFSET I15HAN    ; where to move it
  575.     REP    MOVSB            ; do so
  576. ;
  577. ; Complete installation
  578. ;
  579. INIT90:    INC    BYTE PTR RESFLAG    ; remember to stay resident
  580. ;
  581. ; The program is now installed. Handle parameters.
  582. ;
  583. INIT100:CLD                ; autoincrement
  584.     MOV    SI,81H            ; offset of command tail
  585.     MOV    DI,81H            ; put characters back in same place
  586. ;
  587. INIT110:LODSB                ; get next command character
  588.     CMP    AL,CR            ; end of command?
  589.     JE    INIT130            ; j if so
  590.     CMP    AL,'a'            ; check if lower case alphabetic
  591.     JL    INIT120            ; j if not
  592.     CMP    AL,'z'            ; check range
  593.     JG    INIT120            ; j if not in range
  594.     SUB    AL,'a'-'A'        ; convert to upper case
  595. ;
  596. INIT120:STOSB                ; return possibly modified character
  597.     JMP    INIT110            ; keep scanning
  598. ;
  599. INIT130:MOV    SI,81H            ; back to start of command tail
  600. ;
  601. INIT140:LODSB                ; get next character
  602.     CMP    AL,' '            ; space?
  603.     JE    INIT140            ; j if so - ignore
  604.     CMP    AL,TAB            ; tab?
  605.     JE    INIT140            ; j if so - ignore
  606.     CMP    AL,CR            ; end of parameters?
  607.     JE    INIT150            ; j if so
  608.     DEC    SI            ; point back to first non-space
  609.     MOV    BX,SI            ; save pointer
  610.     MOV    CX,2            ; check for ON
  611.     LEA    DI,ON            ; 'ON'
  612.     REP    CMPSB            ; matched?
  613.     JE    INIT190            ; j if so
  614.     MOV    SI,BX            ; recover pointer
  615.     MOV    CX,3            ; check for OFF
  616.     LEA    DI,OFF            ; 'OFF'
  617.     REP    CMPSB            ; matched?
  618.     JE    INIT180            ; j if so
  619.     LEA    DX,MES4            ; 'Parameter must be ON or OFF'
  620.     MOV    AH,9            ; output message
  621.     INT    21H            ; do it
  622.     MOV    AX,4C01H        ; indicate error
  623.     INT    21H            ; and exit
  624. ;
  625. ; No parameter given - just report status unless initial installation
  626. ;
  627. INIT150:LEA    DX,MES3            ; 'GOLD is '
  628.     MOV    AH,9            ; output message
  629.     INT    21H            ; do it
  630.     MOV    AH,MPID            ; multiplex ID
  631.     MOV    AL,1            ; request status
  632.     INT    2FH            ; returns AL=0 for OFF, AL=1 for ON
  633.     OR    AL,AL            ; test value
  634.     JNZ    INIT160            ; j if ON
  635.     LEA    DX,OFF            ; 'OFF'
  636.     JMP    SHORT INIT170        ; join common code
  637. ;
  638. INIT160:LEA    DX,ON            ; 'ON'
  639. ;
  640. INIT170:MOV    AH,9            ; output message
  641.     INT    21H            ; do it
  642.     JMP    SHORT INIT220        ; use common code
  643. ;
  644. INIT180:XOR    DL,DL            ; clear flag
  645.     JMP    SHORT INIT200        ; jump to setting code
  646. ;
  647. INIT190:MOV    DL,1            ; set flag
  648. ;
  649. ; AL now contains the required GOLD setting flag. Check that the rest of
  650. ; the command line is blank, then if all is OK set the flag appropriately.
  651. ;
  652. INIT200:LODSB                ; get next character
  653.     CMP    AL,' '            ; space?
  654.     JE    INIT200            ; j if so - ignore
  655.     CMP    AL,TAB            ; tab?
  656.     JE    INIT200            ; j if so - ignore
  657.     CMP    AL,CR            ; end of parameters?
  658.     JE    INIT210            ; j if so
  659.     LEA    DX,MES5            ; 'Invalid parameter'
  660.     MOV    AH,9            ; output message
  661.     INT    21H            ; do it
  662.     MOV    AX,4C04H        ; indicate error
  663.     INT    21H            ; and exit
  664. ;
  665. ; The command line is OK. Set the GOLD flag.
  666. ;
  667. INIT210:MOV    AH,MPID            ; multiplex ID
  668.     MOV    AL,2            ; set flag from DL
  669.     INT    2FH            ; set new flag value in resident copy
  670. ;
  671. ; If this is not the first load of GOLD, just exit.
  672. ;
  673. INIT220:TEST    BYTE PTR RESFLAG,1    ; make resident?
  674.     JNE    INIT230            ; j if so
  675.     MOV    AX,4C00H        ; else just exit with success
  676.     INT    21H
  677. ;
  678. ; This is the first load of GOLD; terminate and stay resident
  679. ;
  680. INIT230:MOV    ES,ES:[2CH]        ; get environment segment
  681.     MOV    AH,49H            ; free memory for it
  682.     INT    21H            ; do it
  683.     MOV    DX,OFFSET I15HAN    ; size of common part
  684.     ADD    DX,INTLEN        ; add size of interrupt routine
  685.     ADD    DX,15            ; round to next paragraph
  686.     MOV    CL,4            ; amount to shift
  687.     SHR    DX,CL            ; convert to paragraphs
  688.     MOV    AX,3100H        ; exit with success status
  689.     INT    21H            ; and stay resident
  690. ;
  691. INTLEN    DW    ?            ; Size of selected interrupt handler
  692. RESFLAG    DB    0            ; Set to 1 if to stay resident
  693. ;
  694. ON    DB    'ON',CR,LF,'$'
  695. OFF    DB    'OFF',CR,LF,'$'
  696. MES0    DB    'Sorry - this machine does not support the GOLD utility',CR,LF
  697.     DB    'if the interrupt intercept mode is selected'
  698.     DB    CR,LF,'$'
  699. MES1    DB    'Sorry - DOS 3.0 or above is required for the GOLD utility'
  700.     DB    CR,LF,'$'
  701. MES2    DB    'Sorry - cannot install the GOLD utility',CR,LF,'$'
  702. MES3    DB    'GOLD is $'
  703. MES4    DB    'Parameter must be ON or OFF',CR,LF,'$'
  704. MES5    DB    'Invalid parameter',CR,LF,'$'
  705. ;
  706. INFO    DB    '====GOLD version 2.4===='
  707. ;
  708. CSEG    ENDS
  709. ;
  710.     END    BEGIN
  711.