home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / sprint / spfonts4.zip / SPFONT.ASM next >
Assembly Source File  |  1989-06-27  |  32KB  |  1,400 lines

  1. ; SPFONT - software fonts for Sprint
  2. ;
  3. ; Copyright (c) 1989 Andrew D. Morrow
  4. ;
  5. ; =======================================================================
  6. ;
  7. ; Edit History:
  8. ;
  9. ;   jan89, v0.1;  called HERC, released to Borland for comments
  10. ;  6mar89, v0.2;  renamed SPFONT, supports HERC and CGA, implemented as TSR
  11. ; 13mar89, v0.2a; support video function 14 (WriteTTY); @StringInput uses it.
  12. ; 29mar89, v0.2b; experiment with loading font file from command line
  13. ; 29mar89, v0.2c; forget 2b. install font table with SPFONTLD
  14. ; 31mar89, v0.2d; detect Hercules card
  15. ;  1apr89, v0.2e; expand fonttable to 8 fonts
  16. ;                 add word-underline attribute
  17. ;  6apr89, v0.2f; if /p, fonts 1-7 will print reverse video
  18. ;--- first Compuserve release
  19. ; 17apr89, v0.2g; fix scroll-down bug (FirstScanTable needed sentinel entry)
  20. ; 29apr89, v0.3;  support different character heights (up to 16 dots)
  21. ;  3may89, v0.3a; detect SPFONT already installed, add /u uninstall option
  22. ;  9may89, v0.3b; add /b non-blinking cursor option
  23. ;                 add blink & huge cursor video functions
  24. ; 10may89, v0.3c; /a option makes CGA cursor sizing look ok with large chars
  25. ; 17may89, v0.3d; don't display cursor when positioned off the screen
  26. ; 24jun89, v0.3e; /k option for block cursor at startup
  27. ;                 remove chars 0-31 from each font (since Sprint can't
  28. ;                   use them) -- a savings of 2K-3K
  29. ;                 don't display characters when cursor is off-screen either
  30. ; 25jun89, v0.3f; jump to video functions through an address table
  31. ;                 blink & huge cursor routines return original value
  32. ;--- second Compuserve release
  33. ;
  34. ; =======================================================================
  35. ;
  36. ; Future Enhancements:
  37. ;
  38. ; - /s option prevents snow on CGA
  39. ; - /m# user-defined video mode number (if SPFONTMODE chokes other TSRs)
  40. ; - /1-/7 options to choose fewer fonts in memory (/1=/p; missing fonts
  41. ;     would be replaced by reverse video)
  42. ; - EGA/VGA support
  43. ;
  44. ;
  45. ; =======================================================================
  46. ;
  47.     DOSSEG
  48.     .MODEL TINY
  49.  
  50. ; ***********************************************************************
  51. ; *                                    *
  52. ; *    Equates                                *
  53. ; *                                    *
  54. ; ***********************************************************************
  55.  
  56. SPFONTMODE    EQU    255        ; a unique video mode number
  57. PREVIOUSMODE    EQU    254
  58.  
  59. MAXFONTS    EQU    8        ; number of fonts supported
  60. CHARSPERFONT    EQU    224        ; from 20h to FFh
  61.  
  62. ; The following equates identify the differences between HERC and CGA
  63. ; video memory. Hopefully they will adequately describe EGA and VGA as well.
  64. ;
  65.     IFDEF    HERC
  66. VIDEOBASE    EQU    0b000h        ; video page 0
  67. MAXBANKS    EQU    4
  68. BANKSIZE    EQU    02000h
  69. MAXSCANLINES    EQU    348
  70. MAXCOLUMNS    EQU    90
  71.     ELSEIFDEF CGA
  72. VIDEOBASE    EQU    0b800h
  73. MAXBANKS    EQU    2
  74. BANKSIZE    EQU    02000h
  75. MAXSCANLINES    EQU    200
  76. MAXCOLUMNS    EQU    80
  77.     ELSE
  78.     ERR    missing /dHERC or /dCGA on TASM command line!
  79.     ENDIF
  80.  
  81. MAXROWS        EQU    (MAXSCANLINES/CHARHEIGHT)
  82.  
  83. ; Values for Attribute bits.  The bit-mapping bears no relation to standard
  84. ; IBM video attribute bytes.  The only file that has to know about this
  85. ; mapping is MAIN.SPL which maps typestyle to video attribute.  Unfortunately,
  86. ; if Sprint is started without SPFONT in memory, plain characters will
  87. ; be "inivsible".  The unused bits (4,3,2) are available for future fonts.
  88. ;
  89. RV        EQU    80h        ; reverse video
  90. UN        EQU    40h        ; underline
  91. WU        EQU    20h        ; word underline
  92. SO        EQU    10h        ; strikeout
  93. ATTRIBMASK    EQU    07h        ; up to MAXFONTS fonts
  94.  
  95. ; Bios interrupts called
  96. ;
  97. VIDEOINT    EQU    10h
  98. TIMERINT    EQU    1ch
  99. ENDINT        EQU    20h
  100. DOSINT        EQU    21h
  101. TSRINT        EQU    27h
  102.  
  103. ; Video functions supported.  Internally, Sprint only calls functions 2,6,7 & 9.
  104. ; The init & reset strings in the terminal driver call function 0.  Functions
  105. ; 1,3 & 15 have been implemented to support "hardware" macros that try to
  106. ; detect a Mono or Color monitor, or that want to manipulate the cursor shape.
  107. ; Functions 14 (and indirectly, 8) are used by @StringInput who uses DOS
  108. ; calls for character i/o so that SPFMT is as DOS-compatible as possible.
  109. ; Two non-standard cursor control functions are also supported; from a Sprint
  110. ; "hardware" string, cursor blink can be turned on & off and the cursor can
  111. ; be turned into a huge "cross" for better visibility.
  112. ;
  113. SETVID        EQU    0
  114. SETCSIZE    EQU    1
  115. SETCPOS        EQU    2
  116. GETCINFO    EQU    3        ; returns cx,dx
  117. SCROLLUP    EQU    6
  118. SCROLLDN    EQU    7
  119. GETCHAR        EQU    8        ; returns ax
  120. WRTCHAR        EQU    9
  121. WRITETTY    EQU    14
  122. GETVID        EQU    15        ; returns ax,bx
  123.  
  124. SETBLINK    EQU    16
  125. SETCROSS    EQU    17
  126.  
  127. ; DOS functions called (by the initialization code only!)
  128. PUTSTR        EQU    9
  129. GETVECT        EQU    35h
  130. SETVECT        EQU    25h
  131. DEALLOC        EQU    49h
  132.  
  133. ; States of the simulated cursor.  The CBUSY state protects the cursor
  134. ; from being manipulated by a timer interrupt when a video function is
  135. ; in progress.
  136. COFF        EQU    0
  137. CON        EQU    1
  138. CBUSY        EQU    2
  139.  
  140. ; ***********************************************************************
  141. ; *                                    *
  142. ; *    Entry point                            *
  143. ; *                                    *
  144. ; ***********************************************************************
  145.  
  146.     .CODE
  147.     ORG    100h
  148. Start:    jmp    Init
  149.     DW    FontAnchor        ; so that SPFONTLD can find table
  150.  
  151. ; ***********************************************************************
  152. ; *                                    *
  153. ; *    Data Variables                            *
  154. ; *                                    *
  155. ; ***********************************************************************
  156.  
  157. ; Note: Some of the Cursor variables (Top,Bot,Row,Col) are words
  158. ; even though only the bottom byte is significant.  Doing this
  159. ; makes the DrawCharacter and CursorToggle routines smaller and
  160. ; faster.  Routines that update these variables are careful to leave
  161. ; the high-order byte untouched.
  162.  
  163. PlainFontOnly    DB    0        ; assume all fonts wanted
  164.  
  165. OldVideoMode    DB    ?
  166. VideoActive    DB    0        ; initially inactive
  167.  
  168. OldVideoInt    DD    ?
  169. OldTimerInt    DD    ?
  170.  
  171. CursorState    DB    COFF
  172. CursorCount    DB    0        ; cursor initially disabled
  173.  
  174. CursorBlink    DB    1
  175. CursorCross    DB    0
  176. CursorAdjust    DB    0
  177.  
  178. CursorTop    DW    CHARHEIGHT-2
  179. CursorBot    DW    CHARHEIGHT-1
  180.  
  181. CursorRow    DW    0
  182. CursorCol    DW    0
  183.  
  184. TempCol        DW    ?
  185. TempTop        DW    ?
  186. TempBot        DW    ?
  187.  
  188. ScrollNLines    DW    ?
  189. ScrollFill    DW    ?
  190. ScrollUpper    DW    ?
  191. ScrollLower    DW    ?
  192. ScrollRange    DW    ?
  193.  
  194. ; ***********************************************************************
  195. ; *                                    *
  196. ; *    Timer Handler & Cursor Routines                    *
  197. ; *                                    *
  198. ; ***********************************************************************
  199.  
  200. ; Turning the cursor off and on every time we write a character is a
  201. ; waste of precious CPU time.  So turning on the cursor just sets a
  202. ; flag so that the timer interrupt will truly restore the cursor
  203. ; 50-100ms later.  If more video functions are called in the meantime
  204. ; the timer will keep being deferred until the screen is "idle".
  205. ; The only problem with this scheme is that holding the up- or down-
  206. ; arrow to scroll can cause the cursor to apparently "disappear" until
  207. ; you take your finger off the key!
  208. ;
  209. ; Another advantage of hooking the timer into the cursor routines is that
  210. ; a blinking cursor can be simulated.  The blink rate could be made
  211. ; programmable (or disabled for a non-blinking cursor), and the on/off
  212. ; cycle could be made "uneven".
  213.  
  214. CursorOff:
  215.     cmp    [CursorState],CON    ; if it's on ...
  216.     jne    @@cf1
  217.     call    CursorToggle        ; ... turn it off
  218. @@cf1:    mov    [CursorState],COFF    ; ... and note the fact
  219.     ret
  220.  
  221. CursorOn:
  222.     mov    [CursorCount],2        ; reset the timer
  223.     ret
  224.  
  225. ; Timer interrupts are generated by hardware so all registers are precious.
  226. ; Pushing the registers is done in two steps to that the expensive "big"
  227. ; push is done only when needed.
  228. ;
  229. ; The CursorCount variable is only zero when SPFONT mode is inactive.
  230. ; When the driver is active, a decrement to zero causes the cursor to be
  231. ; toggled and the variable reset to a non-zero value.  The only exception
  232. ; to this is when the timer interrupt occurs when a video function is
  233. ; executing.  CursorOff (via CursorToggle) has marked the cursor BUSY,
  234. ; and the timer interrupt will return with CursorCount at zero. When
  235. ; the video function is finished, CursorOn will set CursorCount non-zero
  236. ; and the timer will gain control again some time later.
  237. NewTimerHandler:
  238.     push    ax
  239.     push    ds
  240.     mov    ax,cs
  241.     mov    ds,ax
  242.  
  243.     cmp    [CursorCount],0        ; SPFONT active?
  244.     je    TimerDone        ; no, don't do anything!
  245.  
  246.     dec    [CursorCount]        ; time to toggle the cursor?
  247.     jnz    TimerDone        ; not yet
  248.  
  249.     push    es
  250.     push    di
  251.     push    bx
  252.     push    cx
  253.     push    dx
  254.  
  255.     cmp    [CursorState],COFF    ; if the cursor's off ...
  256.     jne    @@tm1
  257.     call    CursorToggle        ; ... turn it on ...
  258.     mov    [CursorState],CON
  259.     mov    [CursorCount],4        ; for about half a second
  260.     jmp    @@tm2
  261. @@tm1:
  262.     cmp    [CursorState],CON    ; if it's on ...
  263.     jne    @@tm2
  264.     cmp    [CursorBlink],0        ; ... and blinking is wanted ...
  265.     je    @@tm2
  266.     call    CursorToggle        ; ... do the opposite
  267.     mov    [CursorState],COFF
  268.     mov    [CursorCount],4
  269. @@tm2:
  270.     pop    dx
  271.     pop    cx
  272.     pop    bx
  273.     pop    di
  274.     pop    es
  275.  
  276. TimerDone:
  277.     pop    ds
  278.     pop    ax
  279.     jmp    cs:[OldTimerInt]    ; service other timers
  280.  
  281. CursorToggle:
  282.     mov    [CursorState],CBUSY    ; so a timer interrupt won't interfere
  283.     ;
  284.     cmp    [CursorCross],0        ; is a huge cursor wanted?
  285.     je    @@ct9
  286.     ;
  287.     xor    bx,bx            ; yes - toggle the whole row ...
  288.     mov    cx,MAXCOLUMNS
  289. @@ct1:    push    cx
  290.     push    bx
  291.     mov    ax,[CursorRow]
  292.     xor    cx,cx
  293.     mov    dx,CHARHEIGHT-1
  294.     call    DisplayCursor
  295.     pop    bx
  296.     inc    bx
  297.     pop    cx
  298.     loop    @@ct1
  299.     ;
  300.     xor    ax,ax            ; ... and the whole column ...
  301.     mov    cx,MAXROWS
  302. @@ct2:    push    cx
  303.     push    ax
  304.     mov    bx,[CursorCol]
  305.     xor    cx,cx
  306.     mov    dx,CHARHEIGHT-1
  307.     call    DisplayCursor
  308.     pop    ax
  309.     inc    ax
  310.     pop    cx
  311.     loop    @@ct2
  312.     ;
  313. @@ct9:    mov    ax,[CursorRow]        ; ... and/or just the exact position
  314.     mov    bx,[CursorCol]
  315.     mov    cx,[CursorTop]
  316.     mov    dx,[CursorBot]
  317.     jmp    DisplayCursor
  318.     
  319. ; ax=row, bx=col, cx=top, dx=bot
  320. DisplayCursor:
  321.     cmp    ax,MAXROWS        ; don't display cursor off the screen
  322.     jge    @@dcdone
  323.     cmp    bx,MAXCOLUMNS
  324.     jge    @@dcdone
  325.     ;
  326.     mov    [TempCol],bx
  327.     mov    [TempTop],cx
  328.     mov    [TempBot],dx
  329.     ;
  330.     IF CHARHEIGHT EQ 8
  331.      shl    ax,1            ; convert row -> ScanTable index in bx
  332.      shl    ax,1
  333.      shl    ax,1
  334.     ELSE
  335.      mov    ah,CHARHEIGHT
  336.      mul    ah
  337.     ENDIF
  338.     add    ax,[TempTop]
  339.     shl    ax,1
  340.     mov    bx,ax
  341.     ;
  342.     mov    ax,VIDEOBASE
  343.     mov    es,ax
  344.     ;
  345.     mov    cx,[TempBot]
  346.     sub    cx,[TempTop]
  347.     inc    cx
  348. @@dcloop:
  349.     mov    dx,[ScanTable+bx]
  350.     add    dx,[TempCol]
  351.     mov    di,dx
  352.     mov    al,es:[di]
  353.     xor    al,0ffh
  354.     mov    es:[di],al
  355.     add    bx,2
  356.     loop    @@dcloop
  357. @@dcdone:
  358.     ret
  359.  
  360. ; ***********************************************************************
  361. ; *                                    *
  362. ; *    Video Handler                            *
  363. ; *                                    *
  364. ; ***********************************************************************
  365.  
  366. ; Sprint is written in TurboC (I would hope!) and the manuals state
  367. ; that ax..dx and es are fair game, so we only have to save ds,si & di.
  368. ; Unfortunately, some TSR programs have been found that do not adequately
  369. ; save their registers during video calls, so in the interests of safety,
  370. ; all registers are saved.
  371. ;
  372. ; The low level routines DrawCharacter and CursorToggle destroy most
  373. ; registers so it is up to the video function to save any important
  374. ; registers.
  375. ;
  376. NewVideoHandler:
  377.     cmp    cs:[VideoActive],0ffh    ; are we in SPFONT mode?
  378.     je    ExecFunction        ; yes
  379.     cmp    ax,(SETVID*256)+SPFONTMODE ; switching to SPFONT mode?
  380.     je    ExecFunction        ; yes
  381.     jmp    cs:[OldVideoInt]    ; else pass onto old handler
  382.  
  383. ExecFunction:
  384.     push    ds            ; save important registers
  385.     push    si
  386.     push    di
  387.     mov    si,cs
  388.     mov    ds,si
  389.     ;
  390.     push    es            ; save everything else
  391.     push    dx
  392.     push    cx
  393.     push    bx
  394.     push    ax
  395.     ;
  396. @@exec:
  397.     push    ax
  398.     mov    al,ah
  399.     xor    ah,ah
  400.     sal    ax,1
  401.     mov    si,ax
  402.     pop    ax
  403.     cmp    si,ExecTableLen
  404.     jae    DoNothing
  405.     jmp    [ExecTable+si]
  406.  
  407. DoNothing:
  408.     jmp    ReturnVOID        ; video function not supported
  409.  
  410. ExecTable LABEL WORD
  411.     dw    OFFSET DoSetVideoMode
  412.     dw    OFFSET DoSetCursorSize
  413.     dw    OFFSET DoSetCursorPos
  414.     dw    OFFSET DoGetCursorInfo
  415.     dw    OFFSET DoNothing
  416.     dw    OFFSET DoNothing
  417.     dw    OFFSET DoScrollUp
  418.     dw    OFFSET DoScrollDown
  419.     dw    OFFSET DoGetCharInfo
  420.     dw    OFFSET DoWriteChar
  421.     dw    OFFSET DoNothing
  422.     dw    OFFSET DoNothing
  423.     dw    OFFSET DoNothing
  424.     dw    OFFSET DoNothing
  425.     dw    OFFSET DoWriteTTY
  426.     dw    OFFSET DoGetVideoParms
  427.     dw    OFFSET DoSetCursorBlink
  428.     dw    OFFSET DoSetCursorCross
  429. ExecTableLen EQU $-ExecTable
  430.  
  431. DoSetVideoMode:
  432.     cmp    al,SPFONTMODE        ; switch to SPFONT mode?
  433.     jne    @@sv1
  434.     mov    ah,GETVID        ; yes, remember current video mode
  435.     pushf
  436.     call    cs:[OldVideoInt]
  437.     mov    [OldVideoMode],al    ; (should we also save video page?)
  438.  
  439.     call    EnterGraphicsMode
  440.  
  441.     mov    [CursorRow],0
  442.     mov    [CursorCol],0
  443.     mov    [CursorState],COFF
  444.     mov    [CursorCount],1        ; next timer will toggle cursor on
  445.  
  446.     mov    cs:[VideoActive],0ffh    ; SPFONT active!
  447.     jmp    ReturnVOID
  448.  
  449. @@sv1:    cmp    al,PREVIOUSMODE        ; revert to previous mode?
  450.     jne    @@sv2
  451.     mov    al,[OldVideoMode]    ; yes (ah is still SETVID)
  452.  
  453. @@sv2:    mov    [CursorCount],0        ; disable the software cursor
  454.     mov    cs:[VideoActive],0    ; no longer in SPFONT
  455.     pushf
  456.     call    cs:[OldVideoInt]    ; let the old handler do the work
  457.     jmp    ReturnVOID
  458.     
  459. DoSetCursorSize:
  460.     push    cx
  461.     call    CursorOff
  462.     pop    cx
  463.  
  464.     cmp    ch,CHARHEIGHT-1        ; make sure top is 0..CHARHEIGHT-1
  465.     jle    @@sz1
  466.     mov    ch,CHARHEIGHT-1
  467. @@sz1:
  468.     cmp    cl,CHARHEIGHT-1        ; make sure bottom is 0..CHARHEIGHT-1
  469.     jle    @@sz2
  470.     mov    ch,CHARHEIGHT-1
  471. @@sz2:
  472.     cmp    ch,cl            ; make sure top <= bottom
  473.     jle    @@sz3
  474.     xchg    ch,cl
  475. @@sz3:
  476.  
  477.     IF CHARHEIGHT NE 8
  478.      cmp    [CursorAdjust],0    ; if cursor size adjusting wanted ...
  479.      je    @@sz9
  480.      cmp    cl,7            ; ... & changing CGA bottom line ...
  481.      jne    @@sz9
  482.      cmp    ch,0            ; ... then leave top line as is ...
  483.      je    @@sz8
  484.      sub    cl,ch
  485.      mov    ch,CHARHEIGHT-1
  486.      sub    ch,cl            ; ... else top = (CHARHEIGHT-1)-(bottom-top)
  487. @@sz8:     mov    cl,CHARHEIGHT-1        ; ... and set new bottom line
  488. @@sz9:
  489.     ENDIF
  490.  
  491.     mov    BYTE PTR [CursorTop],ch
  492.     mov    BYTE PTR [CursorBot],cl
  493.     call    CursorOn
  494.     jmp    ReturnVOID
  495.  
  496. DoSetCursorPos:
  497.     push    dx
  498.     call    CursorOff
  499.     pop    dx
  500.     mov    BYTE PTR [CursorRow],dh
  501.     mov    BYTE PTR [CursorCol],dl
  502.     call    CursorOn
  503.     jmp    ReturnVOID
  504.  
  505. DoGetCursorInfo:
  506.     mov    ch,BYTE PTR [CursorTop]
  507.     mov    cl,BYTE PTR [CursorBot]
  508.     mov    dh,BYTE PTR [CursorRow]
  509.     mov    dl,BYTE PTR [CursorCol]
  510.     jmp    ReturnCXDX
  511.  
  512. ; To properly determine the character/attribute under the cursor
  513. ; would require a lot of computation matching through the font tables.
  514. ; Returning just a "plain-space" seems to keep DOS perfectly happy.
  515. ;
  516. DoScrollUp:
  517.     call    ScrollPrep
  518.     call    CursorOff
  519.     call    ScrollUp
  520.     call    CursorOn
  521.     jmp    ReturnVOID
  522.  
  523. DoScrollDown:
  524.     call    ScrollPrep
  525.     call    CursorOff
  526.     call    ScrollDown
  527.     call    CursorOn
  528.     jmp    ReturnVOID
  529.  
  530. DoGetCharInfo:
  531.     mov    ax,' '*256+0        ; return char=space, attrib=plain
  532.     jmp    ReturnAX
  533.  
  534. DoWriteChar:
  535.     push    cx
  536.     push    bx
  537.     push    ax
  538.     call    CursorOff
  539.     pop    ax
  540.     pop    bx
  541.     pop    cx
  542. @@wc1:
  543.     push    cx
  544.     push    bx
  545.     push    ax
  546.     call    DrawCharacter
  547.     pop    ax
  548.     pop    bx
  549.     pop    cx
  550.     inc    BYTE PTR [CursorCol]
  551.     loop    @@wc1
  552.     call    CursorOn
  553.     jmp    ReturnVOID
  554.  
  555. ; Write a character as TTY.  @StringInput uses it so I must support it.
  556. ; Fortunately for me, only 65 characters of input is allowed (so line
  557. ; wrap should never occur) and backspace is the only editing character.
  558. ; CR & LF codes are sent when Enter is pressed, but these can be ignored
  559. ; since the screen driver repositions the cursor anyways.  Characters are
  560. ; always written in the "plain" attribute.
  561. ;
  562. ; entry: al=character
  563. DoWriteTTY:
  564.     cmp    al,0dh            ; cr?
  565.     je    @@ttyend
  566.     cmp    al,0ah            ; lf?
  567.     je    @@ttyend
  568.  
  569.     push    ax
  570.     call    CursorOff
  571.     pop    ax
  572.  
  573.     cmp    al,08h            ; backspace?
  574.     jne    @@tty1
  575.  
  576.     cmp    BYTE PTR [CursorCol],0    ; if at left edge ...
  577.     je    @@ttydone        ; ... do nothing
  578.     dec    BYTE PTR [CursorCol]    ; ... else just move cursor
  579.     jmp    @@ttydone
  580.  
  581. @@tty1:    mov    bl,0            ; plain attribute
  582.     call    DrawCharacter        ; print the char ...
  583.     inc    BYTE PTR [CursorCol]    ; ... and move the cursor
  584. @@ttydone:                ; common wrap-up
  585.     call    CursorOn
  586. @@ttyend:
  587.     jmp    ReturnVOID
  588.  
  589. ; will macros with hardware strings interpret SPFONTMODE as 'Mono' or 'Color'?
  590. DoGetVideoParms:
  591.     mov    ax,(MAXCOLUMNS*256)+SPFONTMODE
  592.     xor    bh,bh            ; always video page 0
  593.     jmp    ReturnAXBX
  594.  
  595. DoSetCursorBlink:
  596.     push    ax
  597.     call    CursorOff
  598.     pop    ax
  599.     mov    ah,[CursorBlink]    ; remember old value
  600.     cmp    al,2            ; if al >= 2 ...
  601.     jl    @@cbl1
  602.     mov    al,ah            ; ... then leave unchanged
  603. @@cbl1:    mov    [CursorBlink],al    ; store new value ...
  604.     push    ax
  605.     call    CursorOn
  606.     pop    ax
  607.     mov    al,ah            ; ... and return old one
  608.     xor    ah,ah
  609.     jmp    ReturnAX
  610.  
  611. DoSetCursorCross:
  612.     push    ax
  613.     call    CursorOff
  614.     pop    ax
  615.     mov    ah,[CursorCross]
  616.     cmp    al,2
  617.     jl    @@ccr1
  618.     mov    al,ah
  619. @@ccr1:    mov    [CursorCross],al
  620.     push    ax
  621.     call    CursorOn
  622.     pop    ax
  623.     mov    al,ah
  624.     xor    ah,ah
  625.     jmp    ReturnAX
  626.  
  627. ReturnAX:
  628.     pop    es            ; throw away saved ax
  629.     pop    bx
  630.     pop    cx
  631.     pop    dx
  632.     pop    es
  633.     jmp    VideoDone
  634. ReturnAXBX:
  635.     pop    es            ; throw away saved ax
  636.     pop    es            ; and bx
  637.     pop    cx
  638.     pop    dx
  639.     pop    es
  640.     jmp    VideoDone
  641. ReturnCXDX:
  642.     pop    ax
  643.     pop    bx
  644.     pop    es            ; throw away saved cx
  645.     pop    es            ; and dx
  646.     pop    es
  647.     jmp    VideoDone
  648. ReturnVOID:
  649.     pop    ax
  650.     pop    bx
  651.     pop    cx
  652.     pop    dx
  653.     pop    es
  654. VideoDone:
  655.     pop    di
  656.     pop    si
  657.     pop    ds
  658.     iret
  659.  
  660. ; ***********************************************************************
  661. ; *                                    *
  662. ; *    Video Subroutines                        *
  663. ; *                                    *
  664. ; ***********************************************************************
  665.  
  666. ; Scroll Up.  Although the function is defined to work on any rectangular
  667. ; area of the screen, Sprint only scrolls whole lines so the column numbers
  668. ; in cl & dl can be ignored.
  669. ;
  670. ; The technique used here is to compute the source and destination
  671. ; offsets for the first bank and the length of the block in that bank,
  672. ; then the data is moved in each of the banks.  Note that the computations
  673. ; have to take into account how many of the CHARHEIGHT scan lines of a character
  674. ; reside in a bank.  We also divide the length by 2 since we want to use
  675. ; a movsw command to move words instead of bytes.
  676. ;
  677. ; entry: al=Nlines, bh=fill attrib, ch=Upper row, dh=Lower row
  678. ;
  679. ScrollPrep:
  680.     xor    ah,ah
  681.     mov    [ScrollNLines],ax
  682.     mov    al,ch
  683.     mov    [ScrollUpper],ax
  684.     mov    al,dh
  685.     mov    [ScrollLower],ax
  686.  
  687.     sub    ax,[ScrollUpper]
  688.     inc    ax
  689.     mov    [ScrollRange],ax
  690.  
  691.     cmp    [ScrollNLines],0
  692.     je    @@su4            ; if Nlines = 0 ...
  693.     cmp    ax,[ScrollNLines]
  694.     jge    @@su5            ; ... or Range < Nlines ...
  695. @@su4:    mov    [ScrollNLines],ax    ; then Nlines = Range
  696. @@su5:
  697.  
  698.     xor    dx,dx            ; fill with zeros
  699.     test    bh,RV
  700.     jz    @@su2
  701.     dec    dx            ; fill with ones
  702. @@su2:    mov    [ScrollFill],dx
  703.     ret
  704.  
  705. ScrollUp:
  706.     cmp    ax,[ScrollNLines]    ; if scrolling whole range ...
  707.     je    @@sufill        ; ... then bypass move
  708.  
  709.     ; move data in each bank
  710.     ; compute source, destination & length for first bank
  711.     mov    ax,[ScrollUpper]
  712.     add    ax,[ScrollNLines]
  713.     shl    ax,1
  714.     mov    bx,ax
  715.     mov    si,[ScanFirstTable+bx]    ; si = U+N
  716.  
  717.     mov    ax,[ScrollUpper]
  718.     shl    ax,1
  719.     mov    bx,ax
  720.     mov    di,[ScanFirstTable+bx]    ; di = U
  721.  
  722.     mov    ax,[ScrollRange]
  723.     sub    ax,[ScrollNLines]
  724.     shl    ax,1
  725.     mov    bx,ax
  726.     mov    cx,[Rows2Words+bx]    ; cx = (L-U+1)-N
  727.  
  728.     mov    ax,VIDEOBASE
  729.     mov    es,ax
  730.     push    ds
  731.     mov    ds,ax
  732.     cld
  733.  
  734.     mov    bx,MAXBANKS
  735. @@su1:
  736.     push    cx
  737.     push    si
  738.     push    di
  739.  
  740.     rep movsw
  741.  
  742.     pop    di
  743.     pop    si
  744.     pop    cx
  745.  
  746.     add    si,BANKSIZE
  747.     add    di,BANKSIZE
  748.  
  749.     dec    bx
  750.     jnz    @@su1
  751.  
  752.     pop    ds
  753.  
  754.     ; fill empty region depending on attribute
  755.     ; compute source & length for first bank
  756. @@sufill:
  757.     mov    ax,[ScrollLower]
  758.     sub    ax,[ScrollNLines]
  759.     inc    ax
  760.     shl    ax,1            ; since ScanFirst is a word table
  761.     mov    bx,ax
  762.     mov    di,[ScanFirstTable+bx]    ; si = L-N+1
  763.  
  764.     mov    ax,[ScrollNLines]
  765.     shl    ax,1
  766.     mov    bx,ax
  767.     mov    cx,[Rows2Words+bx]    ; cx = N
  768.  
  769.     mov    ax,[ScrollFill]
  770.  
  771.     ; es and df are unchanged from above
  772.  
  773.     mov    bx,MAXBANKS
  774. @@su3:
  775.     push    cx
  776.     push    di
  777.  
  778.     rep stosw
  779.  
  780.     pop    di
  781.     pop    cx
  782.  
  783.     add    di,BANKSIZE
  784.  
  785.     dec    bx
  786.     jnz    @@su3
  787.  
  788.     ret
  789.  
  790. ScrollDown:
  791.     cmp    ax,[ScrollNLines]    ; if scrolling whole range ...
  792.     je    @@sdfill        ; ... then bypass move
  793.  
  794.     ; move data in each bank
  795.     ; compute source, destination & length for first bank
  796.     mov    ax,[ScrollRange]
  797.     sub    ax,[ScrollNLines]
  798.     add    ax,[ScrollUpper]
  799.     shl    ax,1
  800.     mov    bx,ax
  801.     mov    si,[ScanFirstTable+bx]    ; si = U+(R-N)
  802.     dec    si
  803.     dec    si
  804.  
  805.     mov    ax,[ScrollLower]
  806.     inc    ax
  807.     shl    ax,1
  808.     mov    bx,ax
  809.     mov    di,[ScanFirstTable+bx]    ; di = L+1
  810.     dec    di
  811.     dec    di
  812.  
  813.     mov    ax,[ScrollRange]
  814.     sub    ax,[ScrollNLines]
  815.     shl    ax,1
  816.     mov    bx,ax
  817.     mov    cx,[Rows2Words+bx]    ; cx = R-N
  818.  
  819.     mov    ax,VIDEOBASE
  820.     mov    es,ax
  821.     push    ds
  822.     mov    ds,ax
  823.     std
  824.  
  825.     mov    bx,MAXBANKS
  826. @@sd1:
  827.     push    cx
  828.     push    si
  829.     push    di
  830.  
  831.     rep movsw
  832.  
  833.     pop    di
  834.     pop    si
  835.     pop    cx
  836.  
  837.     add    si,BANKSIZE
  838.     add    di,BANKSIZE
  839.  
  840.     dec    bx
  841.     jnz    @@sd1
  842.  
  843.     pop    ds
  844.  
  845.     ; fill empty region depending on attribute
  846.     ; compute source & length for first bank
  847. @@sdfill:
  848.     mov    ax,[ScrollUpper]
  849.     add    ax,[ScrollNLines]
  850.     shl    ax,1            ; since ScanFirst is a word table
  851.     mov    bx,ax
  852.     mov    di,[ScanFirstTable+bx]    ; si = U+N
  853.     dec    di
  854.     dec    di
  855.  
  856.     mov    ax,[ScrollNLines]
  857.     shl    ax,1
  858.     mov    bx,ax
  859.     mov    cx,[Rows2Words+bx]    ; cx = N
  860.  
  861.     mov    ax,[ScrollFill]
  862.  
  863.     ; es and df are unchanged from above
  864.  
  865.     mov    bx,MAXBANKS
  866. @@sd3:
  867.     push    cx
  868.     push    di
  869.  
  870.     rep stosw
  871.  
  872.     pop    di
  873.     pop    cx
  874.  
  875.     add    di,BANKSIZE
  876.  
  877.     dec    bx
  878.     jnz    @@sd3
  879.  
  880.     ret
  881.  
  882. ; The critical DrawCharacter routine.  Almost any technique that make this
  883. ; routine faster is worth the effort.  The reverse, underline and strikeout
  884. ; attributes could be coded into font tables but all the combinations of 5
  885. ; attribute bits would require (2^5)*2K = 64K of font tables!  This is
  886. ; obviously too much.
  887. ;
  888. ; The code of the "inner loop" has been implemented as a macro loop
  889. ; (producing replicated code) for efficiency.
  890. ;
  891. ; Draw a character at the current row & column
  892. ; entry: al = character, bl=attribute
  893. ; uses:  ax,bx,cx,dx, si,di,es
  894. ;
  895. DrawCharacter:
  896.     test    bl,WU            ; word underline wanted?
  897.     jz    @@dc1
  898.     or    bl,UN            ; yes - assume underline ...
  899.     cmp    al,' '
  900.     jne    @@dc1
  901.     and    bl,NOT UN        ; ... except for spaces
  902. @@dc1:
  903.     cmp    [PlainFontOnly],0ffh    ; if only plain font in memory ...
  904.     jne    @@dc2
  905.     test    bl,ATTRIBMASK        ; ... and another font is wanted ...
  906.     jz    @@dc2
  907.     and    bl,NOT ATTRIBMASK    ; ... then print in plain font ...
  908.     or    bl,RV            ; ... with reverse video
  909. @@dc2:
  910.     sub    al,' '            ; adjust out unprintable characters
  911.     jnb    @@dc3
  912.     mov    al,0            ; unprintable characters print as space
  913. @@dc3:
  914.     IF CHARHEIGHT EQ 8
  915.      xor    ah,ah            ; convert char -> FontTable index in si
  916.      shl    ax,1            ; (*CHARHEIGHT bytes per entry)
  917.      shl    ax,1
  918.      shl    ax,1
  919.     ELSE
  920.      mov    ah,CHARHEIGHT
  921.      mul    ah
  922.     ENDIF
  923.     add    ax,OFFSET FontTable
  924.     mov    si,ax
  925.     mov    ax,bx            ; get attribute
  926.     and    ax,ATTRIBMASK        ; isolate font# bits
  927.     mov    cx,(CHARSPERFONT*CHARHEIGHT)
  928.     mul    cx            ; (*?K per font)
  929.     add    si,ax            ; index FontTable to desired font
  930.     mov    cx,bx            ; attribute in cl
  931.     ;
  932.     mov    ax,[CursorCol]
  933.     cmp    ax,MAXCOLUMNS
  934.     jge    @@nodraw
  935.     mov    ax,[CursorRow]
  936.     cmp    ax,MAXROWS
  937.     jge    @@nodraw
  938.     jmp    @@dc4
  939. @@nodraw: ret                ; cursor is off-screen
  940.  
  941. @@dc4:                    ; convert row -> ScanTable index in bx
  942.     IF CHARHEIGHT EQ 8
  943.      shl    ax,1
  944.      shl    ax,1
  945.      shl    ax,1
  946.     ELSE
  947.      mov    bx,CHARHEIGHT
  948.      mul    bx
  949.     ENDIF
  950.     shl    ax,1
  951.     mov    bx,ax
  952.     mov    ax,VIDEOBASE        ; es -> video memory
  953.     mov    es,ax
  954.     cld
  955.  
  956.     lup = 0
  957.     REPT CHARHEIGHT
  958.      mov    dx,[ScanTable+bx]
  959.      add    dx,[CursorCol]
  960.      mov    di,dx
  961.      lodsb
  962.      IF lup EQ (CHARHEIGHT/2)+1
  963.       test    cl,SO
  964.       jz    @@dc&lup&st
  965.       mov    al,0ffh
  966. @@dc&lup&st:
  967.      ENDIF
  968.      IF lup EQ (CHARHEIGHT-1)
  969.       test    cl,UN
  970.       jz    @@dc&lup&un
  971.       mov    al,0ffh
  972. @@dc&lup&un:
  973.      ENDIF
  974.      test    cl,RV
  975. ;     jz    @@dc&lup&rv
  976.      jz    $+4            ; since lup is not local to REPT
  977.      xor    al,0ffh
  978. ;@@dc&lup&rv:
  979.      stosb
  980.      add    bx,2
  981.     lup = lup + 1
  982.     ENDM
  983.  
  984.     ret
  985.  
  986. ClearVideo:
  987.     mov    cx,(MAXBANKS*BANKSIZE)/2
  988.     mov    ax,VIDEOBASE
  989.     mov    es,ax
  990.     xor    di,di
  991.     xor    ax,ax
  992.     cld
  993.     rep stosw
  994.     ret
  995.  
  996. ; ***********************************************************************
  997. ; *                                    *
  998. ; *    HERC Particulars (resident)                    *
  999. ; *                                    *
  1000. ; ***********************************************************************
  1001.  
  1002.     IFDEF    HERC
  1003.  
  1004. CONFIGPORT    EQU    3bfh
  1005. HALFCONFIG    EQU    1        ; all that SPFONT requires
  1006.  
  1007. MODEPORT    EQU    3b8h
  1008. TEXTMODE    EQU    00h
  1009. GRAPHMODE    EQU    02h
  1010. SCREENOFF    EQU    00h
  1011. SCREENON    EQU    08h
  1012. BLINKOFF    EQU    00h
  1013. BLINKON        EQU    20h
  1014. GPAGE0        EQU    00h
  1015. GPAGE1        EQU    80h
  1016.  
  1017. M6845PORT    EQU    3b4h
  1018. STATUSPORT    EQU    3bah
  1019.  
  1020. graphicsreg    DB    35h,2dh,2eh,7h,5bh,2h,57h,57h,2h,3h,0,0
  1021.  
  1022. EnterGraphicsMode:
  1023.     call    ClearVideo        ; clear display first to avoid ugly "flash"
  1024.  
  1025.     mov    al,HALFCONFIG
  1026.     mov    dx,CONFIGPORT
  1027.     out    dx,al
  1028.  
  1029.     mov    al,GRAPHMODE+GPAGE0+SCREENON
  1030.     mov    dx,MODEPORT
  1031.     out    dx,al
  1032.  
  1033.     xor    ah,ah            ; starting with register 0
  1034.     mov    cx,12            ; for 12 registers
  1035.     mov    dx,M6845PORT
  1036.     mov    si,OFFSET graphicsreg
  1037.     cld
  1038.     cli
  1039. @@rv1:
  1040.     mov    al,ah
  1041.     out    dx,al            ; select register
  1042.     inc    dx
  1043.     lodsb
  1044.     out    dx,al            ; write value
  1045.     inc    ah
  1046.     dec    dx
  1047.     loop    @@rv1
  1048.     sti
  1049.  
  1050.     mov    al,GRAPHMODE+GPAGE0+SCREENON
  1051.     mov    dx,MODEPORT
  1052.     out    dx,al
  1053.     ret
  1054.  
  1055.     ENDIF
  1056.  
  1057. ; ***********************************************************************
  1058. ; *                                    *
  1059. ; *    CGA Particulars                            *
  1060. ; *                                    *
  1061. ; ***********************************************************************
  1062.  
  1063.     IFDEF    CGA
  1064.  
  1065. EnterGraphicsMode:
  1066.     mov    ax,(SETVID*256)+6    ; enter 640x200 b/w mode
  1067.     pushf
  1068.     call    cs:[OldVideoInt]
  1069.     ret
  1070.  
  1071.     ENDIF
  1072.  
  1073. ; ***********************************************************************
  1074. ; *                                    *
  1075. ; *    Tables                                *
  1076. ; *                                    *
  1077. ; ***********************************************************************
  1078.  
  1079. ; This table gives the offset from VIDEOBASE for the start of each
  1080. ; scan line.  The increase in speed by avoiding multiplications
  1081. ; is worth the space.
  1082. ScanTable LABEL WORD
  1083.     scan = 0
  1084.     rept MAXSCANLINES/MAXBANKS
  1085.      bank = 0
  1086.      rept MAXBANKS
  1087.       DW    (bank*BANKSIZE)+(scan*MAXCOLUMNS)
  1088.       bank = bank+1
  1089.      endm
  1090.      scan = scan+1
  1091.     endm
  1092.  
  1093. ScanFirstTable LABEL WORD
  1094.     scan = 0
  1095.     rept MAXROWS+1
  1096.      DW    scan*MAXCOLUMNS*(CHARHEIGHT/MAXBANKS)
  1097.      scan = scan+1
  1098.     endm
  1099.  
  1100. Rows2Words LABEL WORD
  1101.     nrows = 0
  1102.     rept MAXROWS
  1103.      DW    (nrows*MAXCOLUMNS*(CHARHEIGHT/MAXBANKS))/2
  1104.      nrows = nrows+1
  1105.     endm
  1106.  
  1107. ; The font tables.  Currently there are eight fonts implemented (plain,
  1108. ; italic, bold, bold-italic, large, subscript, superscript & other).
  1109. ;
  1110. ; FontTable MUST be the last table before the installation code!  If the
  1111. ; /p option is given then all but the first (plain) font are discarded
  1112. ; when the TSR loads.  This is for the benefit of programmers who are
  1113. ; more interested in 43 lines of text than in fonts and who want to
  1114. ; sacrifice as little ram as possible.
  1115. ;
  1116. ; FontAnchor is used by SPFONTLD to assure that it is really patching a
  1117. ; copy of SPFONT and not scribbling over just any file.
  1118. ;
  1119. FontAnchor    DB    '<SPFONT>'    ; validation string
  1120. FontTableSize    DW    (MAXFONTS*CHARSPERFONT*CHARHEIGHT)
  1121. FontValid    DB    0        ; set to ff by SPFONTLD
  1122.  
  1123. FontTable LABEL BYTE
  1124.         DB    (CHARSPERFONT*CHARHEIGHT) DUP (0)
  1125. EndPlainFonts LABEL BYTE
  1126.         DB    ((MAXFONTS-1)*(CHARSPERFONT*CHARHEIGHT)) DUP (0)
  1127. EndAllFonts LABEL BYTE
  1128.  
  1129. ; ***********************************************************************
  1130. ; *                                    *
  1131. ; *    Installation                            *
  1132. ; *                                    *
  1133. ; ***********************************************************************
  1134.  
  1135. InstallWanted    DB    0        ; assume installation not wanted
  1136.  
  1137. Herald        DB    'SPFONT for '
  1138.     IFDEF    HERC
  1139.         DB    'Hercules'
  1140.     ENDIF
  1141.     IFDEF    CGA
  1142.         DB    'CGA'
  1143.     ENDIF
  1144.         DB    ' (v0.3f) by Andrew D. Morrow','$'
  1145.  
  1146. InstallMsg    DB    ' - Installed','$'
  1147.  
  1148. UninstallMsg    DB    ' - Uninstalled','$'
  1149.  
  1150. PlainMsg    DB    ' (Plain font only)','$'
  1151.  
  1152. CrLfMsg        DB    0dh,0ah,'$'
  1153.  
  1154. HelpMsg        DB    0dh,0ah
  1155.         DB    'Syntax: SPFONT [/options]',0dh,0ah
  1156.         DB    0dh,0ah
  1157.         DB    '/i  Install',0dh,0ah
  1158.         DB    '/p  load Plain font only (no bold,italic,etc.)',0dh,0ah
  1159.         DB    '/a  Adjust cursor size commands relative to CGA 0-7',0dh,0ah
  1160.         DB    '/b  start with nonBlinking cursor',0dh,0dh
  1161.         DB    '/k  start with blocK cursor',0dh,0ah
  1162.         DB    '/u  Uninstall',0dh,0ah
  1163.         DB    '$'
  1164.  
  1165. FontMsg        DB    'Font Table not loaded. Run SPFONTLD.',0dh,0ah,'$'
  1166.  
  1167. InMemMsg    DB    'SPFONT already installed',0dh,0ah,'$'
  1168.  
  1169. CantUnMsg    DB    'Cannot Uninstall',0dh,0ah,'$'
  1170.  
  1171.     IFDEF    HERC
  1172. NoHercMsg    DB    'Cannot detect Hercules Graphics Card',0dh,0ah,'$'
  1173.     ENDIF
  1174.  
  1175.     JUMPS        ; I don't care how inefficient the init code is!
  1176.  
  1177. Init:    
  1178.     ; print herald
  1179.     mov    dx,OFFSET Herald
  1180.     mov    ah,PUTSTR
  1181.     int    DOSINT
  1182.  
  1183.     ; parse command tail
  1184.     mov    bx,0080h        ; first 'inc bx' will skip tail length
  1185. CmdLup:    inc    bx
  1186.     cmp    BYTE PTR [bx],' '    ; deblank
  1187.     je    CmdLup
  1188.     cmp    BYTE PTR [bx],0dh    ; all done?
  1189.     je    EndCmd
  1190.     cmp    BYTE PTR [bx],'/'    ; there had better be an option
  1191.     jnz    DisplayHelpMsg
  1192.     inc    bx            ; look at which option
  1193.     mov    al,BYTE PTR [bx]
  1194.     and    al,01011111b        ; quick-and-dirty capitalization
  1195.     cmp    al,'I'
  1196.     jz    SelectInstall
  1197.     cmp    al,'P'
  1198.     jz    PlainFonts
  1199.     cmp    al,'B'
  1200.     jz    BlinkOff
  1201.     cmp    al,'K'
  1202.     jz    BlockCursor
  1203.     cmp    al,'A'
  1204.     jz    AdjustOn
  1205.     cmp    al,'U'
  1206.     jz    DoUninstall
  1207.     jmp    DisplayHelpMsg
  1208.  
  1209. SelectInstall:
  1210.     mov    [InstallWanted],1
  1211.     jmp    CmdLup
  1212.  
  1213. PlainFonts:
  1214.     mov    [PlainFontOnly],0ffh
  1215.     jmp    CmdLup
  1216.  
  1217. BlinkOff:
  1218.     mov    [CursorBlink],0
  1219.     jmp    CmdLup
  1220.  
  1221. BlockCursor:
  1222.     mov    [CursorTop],0
  1223.     mov    [CursorBot],CHARHEIGHT-1
  1224.     jmp    CmdLup
  1225.  
  1226. AdjustOn:
  1227.     mov    [CursorAdjust],0ffh
  1228.     jmp    CmdLup
  1229.  
  1230. EndCmd:
  1231.     cmp    [InstallWanted],0    ; if installation was not requested
  1232.     je    DisplayHelpMsg        ; then assume that user needs help
  1233.  
  1234.     mov    ax,(GETVECT*256)+VIDEOINT
  1235.     int    DOSINT
  1236.     cmp    bx,OFFSET NewVideoHandler
  1237.     mov    dx,OFFSET InMemMsg
  1238.     je    DisplayErrorMsg
  1239.  
  1240.     cmp    [FontValid],0
  1241.     mov    dx,OFFSET FontMsg
  1242.     je    DisplayErrorMsg
  1243.  
  1244.     IFDEF    HERC
  1245.      call    DetectHercules
  1246.      mov    dx,OFFSET NoHercMsg
  1247.      jz    DisplayErrorMsg
  1248.     ENDIF
  1249.  
  1250.     ; replace 18.2Hz timer
  1251.     mov    ax,(GETVECT*256)+TIMERINT
  1252.     int    DOSINT
  1253.     mov    WORD PTR cs:[OldTimerInt],bx
  1254.     mov    bx,es
  1255.     mov    WORD PTR cs:[OldTimerInt+2],bx
  1256.  
  1257.     mov    dx,OFFSET NewTimerHandler
  1258.     push    ds
  1259.     mov    ax,cs
  1260.     mov    ds,ax
  1261.     mov    ax,(SETVECT*256)+TIMERINT
  1262.     int    DOSINT
  1263.     pop    ds
  1264.  
  1265.     ; replace video driver
  1266.     mov    ax,(GETVECT*256)+VIDEOINT
  1267.     int    DOSINT
  1268.     mov    WORD PTR cs:[OldVideoInt],bx
  1269.     mov    bx,es
  1270.     mov    WORD PTR cs:[OldVideoInt+2],bx
  1271.  
  1272.     mov    dx,OFFSET NewVideoHandler
  1273.     push    ds
  1274.     mov    ax,cs
  1275.     mov    ds,ax
  1276.     mov    ax,(SETVECT*256)+VIDEOINT
  1277.     int    DOSINT
  1278.     pop    ds
  1279.  
  1280.     ; deallocate environment segment
  1281.     mov    ax,ds:[02ch]        ; get env segment from PSP
  1282.     mov    es,ax
  1283.     mov    ah,DEALLOC
  1284.     int    DOSINT
  1285.  
  1286.     ; acknowledge installation
  1287.     mov    dx,OFFSET InstallMsg
  1288.     mov    ah,PUTSTR
  1289.     int    DOSINT
  1290.     cmp    [PlainFontOnly],0ffh
  1291.     jne    @@ai1
  1292.     mov    dx,OFFSET PlainMsg
  1293.     mov    ah,PUTSTR
  1294.     int    DOSINT
  1295. @@ai1:
  1296.     ; terminate & stay resident
  1297.     mov    dx,OFFSET EndPlainFonts
  1298.     cmp    [PlainFontOnly],0ffh
  1299.     je    @@tsr
  1300.     mov    dx,OFFSET EndAllFonts
  1301. @@tsr:    int    TSRINT
  1302.  
  1303. DoUninstall:
  1304.     mov    ax,(GETVECT*256)+VIDEOINT    ; who owns video interrupt?
  1305.     int    DOSINT
  1306.     cmp    bx,OFFSET NewVideoHandler    ; another copy of SPFONT?
  1307.     mov    dx,OFFSET CantUnMsg
  1308.     jne    DisplayErrorMsg            ; no - sorry
  1309.  
  1310.     mov    ax,(GETVECT*256)+TIMERINT    ; who owns timer interrupt?
  1311.     int    DOSINT
  1312.     cmp    bx,OFFSET NewTimerHandler    ; another copy of SPFONT?
  1313.     mov    dx,OFFSET CantUnMsg
  1314.     jne    DisplayErrorMsg            ; no - sorry
  1315.  
  1316.     ; at this point, es = segment address of original SPFONT
  1317.  
  1318.     ; restore video
  1319.     mov    dx,WORD PTR es:[OldVideoInt]
  1320.     push    ds
  1321.     mov    ax,WORD PTR es:[OldVideoInt+2]
  1322.     mov    ds,ax
  1323.     mov    ax,(SETVECT*256)+VIDEOINT
  1324.     push    es
  1325.     int    DOSINT
  1326.     pop    es
  1327.     pop    ds
  1328.  
  1329.     ; restore timer
  1330.     mov    dx,WORD PTR es:[OldTimerInt]
  1331.     push    ds
  1332.     mov    ax,WORD PTR es:[OldTimerInt+2]
  1333.     mov    ds,ax
  1334.     mov    ax,(SETVECT*256)+TIMERINT
  1335.     push    es
  1336.     int    DOSINT
  1337.     pop    es
  1338.     pop    ds
  1339.  
  1340.     ; deallocate original copy of SPFONT
  1341.     mov    ah,DEALLOC
  1342.     int    DOSINT
  1343.  
  1344.     ; acknowledge uninstallation
  1345.     mov    dx,OFFSET UninstallMsg
  1346.     mov    ah,PUTSTR
  1347.     int    DOSINT
  1348.     int    ENDINT
  1349.  
  1350. DisplayHelpMsg:
  1351.     mov    dx,OFFSET HelpMsg
  1352. DisplayErrorMsg:
  1353.     push    dx
  1354.     mov    dx,OFFSET CrLfMsg
  1355.     mov    ah,PUTSTR        ; since herald doesn't crlf
  1356.     int    DOSINT
  1357.     pop    dx
  1358.     mov    ah,PUTSTR        ; print diagnostic
  1359.     int    DOSINT
  1360.     int    ENDINT            ; and quit without doing anything
  1361.  
  1362. ; ***********************************************************************
  1363. ; *                                    *
  1364. ; *    HERC Particulars (transient)                    *
  1365. ; *                                    *
  1366. ; ***********************************************************************
  1367.  
  1368.     IFDEF    HERC
  1369.  
  1370. ; returns ax=ffff if HGC found, else 0 (Zflag set appropriately)
  1371. DetectHercules:
  1372.     mov    ah,GETVID
  1373.     int    VIDEOINT
  1374.     cmp    al,7            ; in mono text mode?
  1375.     jne    @@dh8            ; no
  1376.  
  1377.     mov    dx,STATUSPORT
  1378.     in    al,dx
  1379.     and    al,80h            ; get current vertical retrace state
  1380.     mov    ah,al            ; and store it away
  1381.  
  1382.     mov    cx,0ffffh        ; wait a long time
  1383. @@dh1:    in    al,dx
  1384.     and    al,80h            ; get vertical retrace state again
  1385.     cmp    ah,al            ; any change?
  1386.     jne    @@dh9            ; yes - it's an HGC!
  1387.  
  1388.     loop    @@dh1            ; no - keep testing
  1389.  
  1390. @@dh8:    xor    ax,ax            ; return failure
  1391.     ret
  1392.  
  1393. @@dh9:    or    ax,0ffffh        ; return success
  1394.     ret
  1395.  
  1396.     ENDIF
  1397.  
  1398.     END    Start
  1399.