home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / books / masmsc.db < prev    next >
Encoding:
Text File  |  1991-03-01  |  463.4 KB  |  9,664 lines

  1. %@1@%%@AH@%Microsoft MASM: Sample Code from v6.0%@EH@%%@AE@%
  2. %@NL@%
  3. %@NL@%
  4. %@2@%%@AH@%ALARM.ASM%@AE@%%@EH@%%@NL@%
  5. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\TSR\ALARM.ASM%@AE@%%@NL@%
  6. %@NL@%
  7. %@AB@%;* ALARM.ASM - A simple memory-resident program that beeps the speaker%@AE@%%@NL@%
  8. %@AB@%;* at a prearranged time.  Can be loaded more than once for multiple%@AE@%%@NL@%
  9. %@AB@%;* alarm settings.  During installation, ALARM establishes a handler%@AE@%%@NL@%
  10. %@AB@%;* for the timer interrupt (interrupt 08).  It then terminates through%@AE@%%@NL@%
  11. %@AB@%;* the Terminate-and-Stay-Resident function (function 31h).  After the%@AE@%%@NL@%
  12. %@AB@%;* alarm sounds, the resident portion of the program retires by setting%@AE@%%@NL@%
  13. %@AB@%;* a flag that prevents further processing in the handler.%@AE@%%@NL@%
  14. %@AB@%;*%@AE@%%@NL@%
  15. %@AB@%;* NOTE: You must assemble this program as a .COM file, either as a PWB%@AE@%%@NL@%
  16. %@AB@%;*       build option or with the ML /AT switch.%@AE@%%@NL@%
  17. %@NL@%
  18.         .MODEL tiny, pascal, os_dos%@NL@%
  19.         .STACK%@NL@%
  20. %@NL@%
  21.         .CODE%@NL@%
  22. %@NL@%
  23.         ORG     5Dh                     %@AB@%; Location of time argument in PSP,%@AE@%%@NL@%
  24. CountDown       LABEL   WORD            %@AB@%;   converted to number of 5-second%@AE@%%@NL@%
  25.                                         %@AB@%;   intervals to elapse%@AE@%%@NL@%
  26.         .STARTUP%@NL@%
  27.         jmp     Install                 %@AB@%; Jump over data and resident code%@AE@%%@NL@%
  28. %@NL@%
  29. %@AB@%; Data must be in code segment so it won't be thrown away with Install code.%@AE@%%@NL@%
  30. %@NL@%
  31. OldTimer        DWORD   ?               %@AB@%; Address of original timer routine%@AE@%%@NL@%
  32. tick_91         BYTE    91              %@AB@%; Counts 91 clock ticks (5 seconds)%@AE@%%@NL@%
  33. TimerActiveFlag BYTE    0               %@AB@%; Active flag for timer handler%@AE@%%@NL@%
  34. %@NL@%
  35. %@AB@%;* NewTimer - Handler routine for timer interrupt (interrupt 08).%@AE@%%@NL@%
  36. %@AB@%;* Decrements CountDown every 5 seconds.  No other action is taken%@AE@%%@NL@%
  37. %@AB@%;* until CountDown reaches 0, at which time the speaker sounds.%@AE@%%@NL@%
  38. %@NL@%
  39. NewTimer PROC   FAR%@NL@%
  40. %@NL@%
  41.         .IF     cs:TimerActiveFlag != 0 %@AB@%; If timer busy or retired:%@AE@%%@NL@%
  42.         jmp     cs:OldTimer             %@AB@%; Jump to original timer routine%@AE@%%@NL@%
  43.         .ENDIF%@NL@%
  44.         inc     cs:TimerActiveFlag      %@AB@%; Set active flag%@AE@%%@NL@%
  45.         pushf                           %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
  46.         call    cs:OldTimer             %@AB@%;   then far-calling original routine%@AE@%%@NL@%
  47.         sti                             %@AB@%; Enable interrupts%@AE@%%@NL@%
  48.         push    ds                      %@AB@%; Preserve DS register%@AE@%%@NL@%
  49.         push    cs                      %@AB@%; Point DS to current segment for%@AE@%%@NL@%
  50.         pop     ds                      %@AB@%;   further memory access%@AE@%%@NL@%
  51.         dec     tick_91                 %@AB@%; Count down for 91 ticks%@AE@%%@NL@%
  52.         .IF     zero?                   %@AB@%; If 91 ticks have elapsed:%@AE@%%@NL@%
  53.         mov     tick_91, 91             %@AB@%; Reset secondary counter and%@AE@%%@NL@%
  54.         dec     CountDown               %@AB@%;   subtract one 5-second interval%@AE@%%@NL@%
  55.         .IF     zero?                   %@AB@%; If CountDown drained:%@AE@%%@NL@%
  56.         call    Sound                   %@AB@%; Sound speaker%@AE@%%@NL@%
  57.         inc     TimerActiveFlag         %@AB@%; Alarm has sounded, set flag%@AE@%%@NL@%
  58.         .ENDIF%@NL@%
  59.         .ENDIF%@NL@%
  60. %@NL@%
  61.         dec     TimerActiveFlag         %@AB@%; Decrement active flag%@AE@%%@NL@%
  62.         pop     ds                      %@AB@%; Recover DS%@AE@%%@NL@%
  63.         iret                            %@AB@%; Return from interrupt handler%@AE@%%@NL@%
  64. %@NL@%
  65. NewTimer ENDP%@NL@%
  66. %@NL@%
  67. %@NL@%
  68. %@AB@%;* Sound - Sounds speaker with the following tone and duration:%@AE@%%@NL@%
  69. %@NL@%
  70. BEEP_TONE       EQU     440             %@AB@%; Beep tone in hertz%@AE@%%@NL@%
  71. BEEP_DURATION   EQU     6               %@AB@%; Number of clocks during beep,%@AE@%%@NL@%
  72.                                         %@AB@%;   where 18 clocks = approx 1 second%@AE@%%@NL@%
  73. %@NL@%
  74. Sound   PROC    USES ax bx cx dx es     %@AB@%; Save registers used in this routine%@AE@%%@NL@%
  75.         mov     al, 0B6h                %@AB@%; Initialize channel 2 of%@AE@%%@NL@%
  76.         out     43h, al                 %@AB@%;   timer chip%@AE@%%@NL@%
  77.         mov     dx, 12h                 %@AB@%; Divide 1,193,180 hertz%@AE@%%@NL@%
  78.         mov     ax, 34DCh               %@AB@%;   (clock frequency) by%@AE@%%@NL@%
  79.         mov     bx, BEEP_TONE           %@AB@%;   desired frequency%@AE@%%@NL@%
  80.         div     bx                      %@AB@%; Result is timer clock count%@AE@%%@NL@%
  81.         out     42h, al                 %@AB@%; Low byte of count to timer%@AE@%%@NL@%
  82.         mov     al, ah%@NL@%
  83.         out     42h, al                 %@AB@%; High byte of count to timer%@AE@%%@NL@%
  84.         in      al, 61h                 %@AB@%; Read value from port 61h%@AE@%%@NL@%
  85.         or      al, 3                   %@AB@%; Set first two bits%@AE@%%@NL@%
  86.         out     61h, al                 %@AB@%; Turn speaker on%@AE@%%@NL@%
  87. %@NL@%
  88. %@AB@%; Pause for specified number of clock ticks%@AE@%%@NL@%
  89. %@NL@%
  90.         mov     dx, BEEP_DURATION       %@AB@%; Beep duration in clock ticks%@AE@%%@NL@%
  91.         sub     cx, cx                  %@AB@%; CX:DX = tick count for pause%@AE@%%@NL@%
  92.         mov     es, cx                  %@AB@%; Point ES to low memory data%@AE@%%@NL@%
  93.         add     dx, es:[46Ch]           %@AB@%; Add current tick count to CX:DX%@AE@%%@NL@%
  94.         adc     cx, es:[46Eh]           %@AB@%; Result is target count in CX:DX%@AE@%%@NL@%
  95.         .REPEAT%@NL@%
  96.         mov     bx, es:[46Ch]           %@AB@%; Now repeatedly poll clock%@AE@%%@NL@%
  97.         mov     ax, es:[46Eh]           %@AB@%;   count until the target%@AE@%%@NL@%
  98.         sub     bx, dx                  %@AB@%;   time is reached%@AE@%%@NL@%
  99.         sbb     ax, cx%@NL@%
  100.         .UNTIL  !carry?%@NL@%
  101. %@NL@%
  102.         in      al, 61h                 %@AB@%; When time elapses, get port value%@AE@%%@NL@%
  103.         xor     al, 3                   %@AB@%; Kill bits 0-1 to turn%@AE@%%@NL@%
  104.         out     61h, al                 %@AB@%;   speaker off%@AE@%%@NL@%
  105.         ret%@NL@%
  106. %@NL@%
  107. Sound   ENDP%@NL@%
  108. %@NL@%
  109. %@NL@%
  110. %@NL@%
  111. %@AB@%;* Install - Converts ASCII argument to valid binary number, replaces%@AE@%%@NL@%
  112. %@AB@%;* NewTimer as the interrupt handler for the timer, then makes program%@AE@%%@NL@%
  113. %@AB@%;* memory-resident by exiting through function 31h.%@AE@%%@NL@%
  114. %@AB@%;*%@AE@%%@NL@%
  115. %@AB@%;* This procedure marks the end of the TSR's resident section and the%@AE@%%@NL@%
  116. %@AB@%;* beginning of the installation section.  When ALARM terminates through%@AE@%%@NL@%
  117. %@AB@%;* function 31h, the above code and data remain resident in memory.  The%@AE@%%@NL@%
  118. %@AB@%;* memory occupied by the following code is returned to DOS.%@AE@%%@NL@%
  119. %@NL@%
  120. %@NL@%
  121. Install PROC%@NL@%
  122. %@NL@%
  123. %@AB@%; Time argument is in hhmm military format.  Convert ASCII digits to%@AE@%%@NL@%
  124. %@AB@%; number of minutes since midnight, then convert current time to number%@AE@%%@NL@%
  125. %@AB@%; of minutes since midnight.  Difference is number of minutes to elapse%@AE@%%@NL@%
  126. %@AB@%; until alarm sounds.  Convert to seconds-to-elapse, divide by 5 seconds,%@AE@%%@NL@%
  127. %@AB@%; and store result in word CountDown.%@AE@%%@NL@%
  128. %@NL@%
  129. DEFAULT_TIME    EQU     3600            %@AB@%; Default alarm setting = 1 hour%@AE@%%@NL@%
  130.                                         %@AB@%;   (in seconds) from present time%@AE@%%@NL@%
  131.         mov     ax, DEFAULT_TIME%@NL@%
  132.         cwd                             %@AB@%; DX:AX = default time in seconds%@AE@%%@NL@%
  133.         .IF     BYTE PTR CountDown != ' '%@AB@%;If not blank argument:%@AE@%%@NL@%
  134.         xor     CountDown[0], '00'      %@AB@%; Convert 4 bytes of ASCII%@AE@%%@NL@%
  135.         xor     CountDown[2], '00'      %@AB@%;   argument to binary%@AE@%%@NL@%
  136. %@NL@%
  137.         mov     al, 10                  %@AB@%; Multiply 1st hour digit by 10%@AE@%%@NL@%
  138.         mul     BYTE PTR CountDown[0]   %@AB@%;   and add to 2nd hour digit%@AE@%%@NL@%
  139.         add     al, BYTE PTR CountDown[1]%@NL@%
  140.         mov     bh, al                  %@AB@%; BH = hour for alarm to go off%@AE@%%@NL@%
  141.         mov     al, 10                  %@AB@%; Repeat procedure for minutes%@AE@%%@NL@%
  142.         mul     BYTE PTR CountDown[2]   %@AB@%; Multiply 1st minute digit by 10%@AE@%%@NL@%
  143.         add     al, BYTE PTR CountDown[3] %@AB@%;   and add to 2nd minute digit%@AE@%%@NL@%
  144.         mov     bl, al                  %@AB@%; BL = minute for alarm to go off%@AE@%%@NL@%
  145.         mov     ah, 2Ch                 %@AB@%; Request function 2Ch%@AE@%%@NL@%
  146.         int     21h                     %@AB@%; Get Time (CX = current hour/min)%@AE@%%@NL@%
  147.         mov     dl, dh%@NL@%
  148.         sub     dh, dh%@NL@%
  149.         push    dx                      %@AB@%; Save DX = current seconds%@AE@%%@NL@%
  150. %@NL@%
  151.         mov     al, 60                  %@AB@%; Multiply current hour by 60%@AE@%%@NL@%
  152.         mul     ch                      %@AB@%;   to convert to minutes%@AE@%%@NL@%
  153.         sub     ch, ch%@NL@%
  154.         add     cx, ax                  %@AB@%; Add current minutes to result%@AE@%%@NL@%
  155.                                         %@AB@%; CX = minutes since midnight%@AE@%%@NL@%
  156.         mov     al, 60                  %@AB@%; Multiply alarm hour by 60%@AE@%%@NL@%
  157.         mul     bh                      %@AB@%;   to convert to minutes%@AE@%%@NL@%
  158.         sub     bh, bh%@NL@%
  159.         add     ax, bx                  %@AB@%; AX = number of minutes since%@AE@%%@NL@%
  160.                                         %@AB@%;   midnight for alarm setting%@AE@%%@NL@%
  161.         sub     ax, cx                  %@AB@%; AX = time in minutes to elapse%@AE@%%@NL@%
  162.                                         %@AB@%;   before alarm sounds%@AE@%%@NL@%
  163.         .IF     carry?                  %@AB@%; If alarm time is tomorrow:%@AE@%%@NL@%
  164.         add     ax, 24 * 60             %@AB@%; Add minutes in a day%@AE@%%@NL@%
  165.         .ENDIF%@NL@%
  166. %@NL@%
  167.         mov     bx, 60%@NL@%
  168.         mul     bx                      %@AB@%; DX:AX = minutes-to-elapse-times-60%@AE@%%@NL@%
  169.         pop     bx                      %@AB@%; Recover current seconds%@AE@%%@NL@%
  170.         sub     ax, bx                  %@AB@%; DX:AX = seconds to elapse before%@AE@%%@NL@%
  171.         sbb     dx, 0                   %@AB@%;   alarm activates%@AE@%%@NL@%
  172.         .IF     carry?                  %@AB@%; If negative:%@AE@%%@NL@%
  173.         mov     ax, 5                   %@AB@%; Assume 5 seconds%@AE@%%@NL@%
  174.         cwd%@NL@%
  175.         .ENDIF%@NL@%
  176.         .ENDIF%@NL@%
  177. %@NL@%
  178.         mov     bx, 5                   %@AB@%; Divide result by 5 seconds%@AE@%%@NL@%
  179.         div     bx                      %@AB@%; AX = number of 5-second intervals%@AE@%%@NL@%
  180.         mov     CountDown, ax           %@AB@%;   to elapse before alarm sounds%@AE@%%@NL@%
  181. %@NL@%
  182.         mov     ax, 3508h               %@AB@%; Request function 35h%@AE@%%@NL@%
  183.         int     21h                     %@AB@%; Get Vector for timer (interrupt 08)%@AE@%%@NL@%
  184.         mov     WORD PTR OldTimer[0], bx%@AB@%; Store address of original%@AE@%%@NL@%
  185.         mov     WORD PTR OldTimer[2], es%@AB@%;   timer interrupt%@AE@%%@NL@%
  186.         mov     ax, 2508h               %@AB@%; Request function 25h%@AE@%%@NL@%
  187.         mov     dx, OFFSET NewTimer     %@AB@%; DS:DX points to new timer handler%@AE@%%@NL@%
  188.         int     21h                     %@AB@%; Set Vector with address of NewTimer%@AE@%%@NL@%
  189. %@NL@%
  190.         mov     dx, OFFSET Install      %@AB@%; DX = bytes in resident section%@AE@%%@NL@%
  191.         mov     cl, 4%@NL@%
  192.         shr     dx, cl                  %@AB@%; Convert to number of paragraphs%@AE@%%@NL@%
  193.         inc     dx                      %@AB@%;   plus one%@AE@%%@NL@%
  194.         mov     ax, 3100h               %@AB@%; Request function 31h, error code=0%@AE@%%@NL@%
  195.         int     21h                     %@AB@%; Terminate-and-Stay-Resident%@AE@%%@NL@%
  196. %@NL@%
  197. Install ENDP%@NL@%
  198. %@NL@%
  199.         END%@NL@%
  200. %@NL@%
  201. %@NL@%
  202. %@2@%%@AH@%BASIC.ASM%@AE@%%@EH@%%@NL@%
  203. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\MIXED\BASIC.ASM%@AE@%%@NL@%
  204. %@NL@%
  205. %@AB@%; Called by BASMAIN.BAS%@AE@%%@NL@%
  206. %@AB@%; Assemble with ML /c BASIC.ASM%@AE@%%@NL@%
  207. %@NL@%
  208.         .MODEL  medium%@NL@%
  209. %@NL@%
  210. Power2  PROTO   PASCAL, Factor:PTR WORD, Power:PTR WORD%@NL@%
  211.         .CODE%@NL@%
  212. Power2  PROC    PASCAL, Factor:PTR WORD, Power:PTR WORD%@NL@%
  213. %@NL@%
  214.         mov     bx, WORD PTR Factor   %@AB@%; Load Factor into%@AE@%%@NL@%
  215.         mov     ax, [bx]              %@AB@%;  AX%@AE@%%@NL@%
  216.         mov     bx, WORD PTR Power    %@AB@%; Load Power into%@AE@%%@NL@%
  217.         mov     cx, [bx]              %@AB@%;   CX%@AE@%%@NL@%
  218.         shl     ax, cl                %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
  219. %@NL@%
  220.         ret%@NL@%
  221. Power2  ENDP%@NL@%
  222. %@NL@%
  223.         END%@NL@%
  224. %@NL@%
  225. %@NL@%
  226. %@2@%%@AH@%C.ASM%@AE@%%@EH@%%@NL@%
  227. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\MIXED\C.ASM%@AE@%%@NL@%
  228. %@NL@%
  229. %@AB@%;  Called from main program in CMAIN.C%@AE@%%@NL@%
  230. %@AB@%;  Assemble with ML /c C.ASM%@AE@%%@NL@%
  231. %@NL@%
  232.         .MODEL  small, c%@NL@%
  233. %@NL@%
  234. Power2  PROTO C factor:SWORD, power:SWORD%@NL@%
  235.         .CODE%@NL@%
  236. %@NL@%
  237. Power2  PROC  C factor:SWORD, power:SWORD%@NL@%
  238.         mov     ax, factor    %@AB@%; Load Arg1 into AX%@AE@%%@NL@%
  239.         mov     cx, power     %@AB@%; Load Arg2 into CX%@AE@%%@NL@%
  240.         shl     ax, cl        %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
  241.                               %@AB@%; Leave return value in AX%@AE@%%@NL@%
  242.         ret%@NL@%
  243. Power2  ENDP%@NL@%
  244.         END%@NL@%
  245. %@NL@%
  246. %@NL@%
  247. %@2@%%@AH@%COMMON.ASM%@AE@%%@EH@%%@NL@%
  248. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\DEMOS\COMMON.ASM%@AE@%%@NL@%
  249. %@NL@%
  250.         .MODEL  small, pascal, os_dos%@NL@%
  251.         INCLUDE demo.inc%@NL@%
  252. %@NL@%
  253.         .DATA%@NL@%
  254. vconfig VIDCONFIG <>           %@AB@%; Global video configuration structure%@AE@%%@NL@%
  255. %@NL@%
  256.         .CODE%@NL@%
  257. %@NL@%
  258. %@AB@%;* GetVidConfig - Determines current video configuration and initializes%@AE@%%@NL@%
  259. %@AB@%;* the vconfig structure.%@AE@%%@NL@%
  260. %@AB@%;*%@AE@%%@NL@%
  261. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 0 (Set Video Mode)%@AE@%%@NL@%
  262. %@AB@%;*                           10h, Function 0Fh (Get Current Video Mode)%@AE@%%@NL@%
  263. %@AB@%;*                           10h, Function 1Ah (Video Display Combination)%@AE@%%@NL@%
  264. %@AB@%;*%@AE@%%@NL@%
  265. %@AB@%;* Uses:    vconfig - Video configuration structure, declared in the%@AE@%%@NL@%
  266. %@AB@%;*          DEMO.INC include file.%@AE@%%@NL@%
  267. %@AB@%;*%@AE@%%@NL@%
  268. %@AB@%;* Params:  None%@AE@%%@NL@%
  269. %@AB@%;*%@AE@%%@NL@%
  270. %@AB@%;* Return:  None%@AE@%%@NL@%
  271. %@NL@%
  272. GetVidConfig PROC%@NL@%
  273. %@NL@%
  274.         mov     ax, 1A00h               %@AB@%; Get video info for VGA%@AE@%%@NL@%
  275.         int     10h%@NL@%
  276. chkVGA:%@NL@%
  277.         cmp     al, 1Ah                 %@AB@%; Is VGA or MCGA present?%@AE@%%@NL@%
  278.         jne     chkEGA                  %@AB@%; No?  Then check for EGA%@AE@%%@NL@%
  279. %@NL@%
  280.         cmp     bl, 2                   %@AB@%; If VGA exists as secondary adapter,%@AE@%%@NL@%
  281.         je      isCGA                   %@AB@%;   check for CGA and mono as primary%@AE@%%@NL@%
  282.         jb      isMONO%@NL@%
  283.         cmp     bl, 5                   %@AB@%; If EGA is primary, do normal%@AE@%%@NL@%
  284.         jbe     chkEGA                  %@AB@%;   EGA checking%@AE@%%@NL@%
  285. chkMCGA:%@NL@%
  286.         mov     vconfig.adapter, MCGA   %@AB@%; Yes?  Assume MCGA%@AE@%%@NL@%
  287.         mov     vconfig.display, COLOR%@NL@%
  288.         cmp     bl, 8                   %@AB@%; Correct assumption?%@AE@%%@NL@%
  289.         ja      gotmode                 %@AB@%; Yes?  Continue%@AE@%%@NL@%
  290. isVGA:%@NL@%
  291.         mov     vconfig.adapter, VGA    %@AB@%; Assume it's VGA color%@AE@%%@NL@%
  292.         je      gotmode                 %@AB@%; Yes?  Continue%@AE@%%@NL@%
  293.         mov     vconfig.display, MONO   %@AB@%; No?  Must be VGA mono%@AE@%%@NL@%
  294.         jmp     gotmode                 %@AB@%; Finished with VGA, so jump%@AE@%%@NL@%
  295. chkEGA:%@NL@%
  296.         mov     ah, 12h                 %@AB@%; Call EGA status function%@AE@%%@NL@%
  297.         mov     bl, 10h%@NL@%
  298.         sub     cx, cx                  %@AB@%; Clear status bits%@AE@%%@NL@%
  299.         int     10h%@NL@%
  300.         jcxz    chkCGA                  %@AB@%; If CX is unchanged, not EGA%@AE@%%@NL@%
  301. isEGA:%@NL@%
  302.         mov     vconfig.adapter, EGA    %@AB@%; Set structure fields for EGA%@AE@%%@NL@%
  303.         mov     vconfig.display, MONO   %@AB@%; Assume EGA mono%@AE@%%@NL@%
  304.         or      bh, bh                  %@AB@%; Correct assumption?%@AE@%%@NL@%
  305.         jnz     gotmode                 %@AB@%; Yes?  Continue%@AE@%%@NL@%
  306.         mov     vconfig.display, COLOR  %@AB@%; No?  Must be EGA color%@AE@%%@NL@%
  307.         jmp     gotmode                 %@AB@%; Finished with EGA, so jump%@AE@%%@NL@%
  308. chkCGA:%@NL@%
  309.         int     11h                     %@AB@%; Get equipment list%@AE@%%@NL@%
  310.         and     al, 30h                 %@AB@%; If bits 4-5 set, monochrome%@AE@%%@NL@%
  311.         cmp     al, 30h                 %@AB@%; Monochrome text mode?%@AE@%%@NL@%
  312.         je      isMONO                  %@AB@%; Yes?  Continue%@AE@%%@NL@%
  313. isCGA:%@NL@%
  314.         mov     vconfig.adapter, CGA    %@AB@%; No?  Must be CGA%@AE@%%@NL@%
  315.         mov     vconfig.display, COLOR%@NL@%
  316.         jmp     gotmode%@NL@%
  317. isMONO:%@NL@%
  318.         mov     vconfig.adapter, MDA    %@AB@%; Set MONO%@AE@%%@NL@%
  319.         mov     vconfig.display, MONO%@NL@%
  320. gotmode:%@NL@%
  321.         mov     ah, 0Fh%@NL@%
  322.         int     10h                     %@AB@%; Get current mode%@AE@%%@NL@%
  323.         mov     vconfig.mode, al        %@AB@%; Record mode%@AE@%%@NL@%
  324.         mov     vconfig.dpage, bh       %@AB@%;   and current page%@AE@%%@NL@%
  325.         mov     al, vconfig.display     %@AB@%; Multiply display value%@AE@%%@NL@%
  326.         cbw                             %@AB@%;   (which is either 0 or 1)%@AE@%%@NL@%
  327.         mov     bx, 800h                %@AB@%;   by 800h, then add to B000h%@AE@%%@NL@%
  328.         mul     bx                      %@AB@%;   for segment address of%@AE@%%@NL@%
  329.         add     ax, 0B000h              %@AB@%;   video buffer%@AE@%%@NL@%
  330.         add     ah, vconfig.dpage       %@AB@%; Adding display page gives%@AE@%%@NL@%
  331.         mov     vconfig.sgmnt, ax       %@AB@%;   address of current page%@AE@%%@NL@%
  332. %@NL@%
  333.         sub     ax, ax%@NL@%
  334.         mov     es, ax%@NL@%
  335.         mov     al, es:[44Ah]           %@AB@%; Get number of display cols%@AE@%%@NL@%
  336.         mov     vconfig.cols, al        %@AB@%; Store in structure%@AE@%%@NL@%
  337.         mov     vconfig.rows, 24        %@AB@%; Assume bottom row # = 24%@AE@%%@NL@%
  338.         cmp     vconfig.adapter, EGA    %@AB@%; EGA or VGA?%@AE@%%@NL@%
  339.         jl      exit                    %@AB@%; No?  Exit%@AE@%%@NL@%
  340.         mov     ax, 1130h               %@AB@%; Yes?  Request character info%@AE@%%@NL@%
  341.         sub     bh, bh                  %@AB@%; Set BH to valid value%@AE@%%@NL@%
  342.         push    bp                      %@AB@%; BP will change, so save it%@AE@%%@NL@%
  343.         int     10h                     %@AB@%; Get number of rows/screen%@AE@%%@NL@%
  344.         mov     vconfig.rows, dl        %@AB@%; Keep in structure%@AE@%%@NL@%
  345.         pop     bp                      %@AB@%; Restore BP%@AE@%%@NL@%
  346. exit:%@NL@%
  347.         ret%@NL@%
  348. %@NL@%
  349. GetVidConfig ENDP%@NL@%
  350. %@NL@%
  351. %@NL@%
  352. %@AB@%;* GetCurPos - Gets current cursor position.%@AE@%%@NL@%
  353. %@AB@%;*%@AE@%%@NL@%
  354. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  355. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  356. %@AB@%;*%@AE@%%@NL@%
  357. %@AB@%;* Params:  None%@AE@%%@NL@%
  358. %@AB@%;*%@AE@%%@NL@%
  359. %@AB@%;* Return:  Short integer with high byte = row, low byte = column%@AE@%%@NL@%
  360. %@NL@%
  361. GetCurPos PROC USES bx dx%@NL@%
  362. %@NL@%
  363.         mov     ah, 3                   %@AB@%; Function 3%@AE@%%@NL@%
  364.         mov     bh, vconfig.dpage%@NL@%
  365.         int     10h                     %@AB@%; Get cursor position%@AE@%%@NL@%
  366.         mov     ax, dx%@NL@%
  367.         ret%@NL@%
  368. %@NL@%
  369. GetCurPos ENDP%@NL@%
  370. %@NL@%
  371. %@NL@%
  372. %@AB@%;* SetCurPos - Sets cursor position.%@AE@%%@NL@%
  373. %@AB@%;*%@AE@%%@NL@%
  374. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 2 (Set Cursor Position)%@AE@%%@NL@%
  375. %@AB@%;*%@AE@%%@NL@%
  376. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  377. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  378. %@AB@%;*%@AE@%%@NL@%
  379. %@AB@%;* Params:  Row - Target row%@AE@%%@NL@%
  380. %@AB@%;*          Col - Target column%@AE@%%@NL@%
  381. %@AB@%;*%@AE@%%@NL@%
  382. %@AB@%;* Return:  None%@AE@%%@NL@%
  383. %@NL@%
  384. SetCurPos PROC USES bx dx,%@NL@%
  385.         Row:WORD,%@NL@%
  386.         Col:WORD%@NL@%
  387. %@NL@%
  388.         mov     dh, BYTE PTR Row        %@AB@%; DH = row%@AE@%%@NL@%
  389.         mov     dl, BYTE ptr Col        %@AB@%; DL = column%@AE@%%@NL@%
  390.         mov     ah, 2                   %@AB@%; Function 2%@AE@%%@NL@%
  391.         mov     bh, vconfig.dpage       %@AB@%; Current page%@AE@%%@NL@%
  392.         int     10h                     %@AB@%; Set cursor position%@AE@%%@NL@%
  393.         ret%@NL@%
  394. %@NL@%
  395. SetCurPos ENDP%@NL@%
  396. %@NL@%
  397. %@NL@%
  398. %@AB@%;* StrWrite - Writes ASCIIZ string to video memory at specified row/column.%@AE@%%@NL@%
  399. %@AB@%;*%@AE@%%@NL@%
  400. %@AB@%;* Shows:   Instructions - lodsb     stosb%@AE@%%@NL@%
  401. %@AB@%;*%@AE@%%@NL@%
  402. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  403. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  404. %@AB@%;*%@AE@%%@NL@%
  405. %@AB@%;* Params:  Row - Row coordinate%@AE@%%@NL@%
  406. %@AB@%;*          Col - Column coordinate%@AE@%%@NL@%
  407. %@AB@%;*          Sptr - Pointer to string%@AE@%%@NL@%
  408. %@AB@%;*%@AE@%%@NL@%
  409. %@AB@%;* Return:  None%@AE@%%@NL@%
  410. %@NL@%
  411. StrWrite PROC USES ds si di,%@NL@%
  412.         Row:WORD,%@NL@%
  413.         Col:WORD,%@NL@%
  414.         Sptr:PTR BYTE%@NL@%
  415. %@NL@%
  416.         GetVidOffset Row, Col           %@AB@%; Get video offset for these coords%@AE@%%@NL@%
  417.         mov     di, ax                  %@AB@%; Copy to DI%@AE@%%@NL@%
  418.         LoadPtr ds, si, Sptr            %@AB@%; DS:SI points to string%@AE@%%@NL@%
  419.         mov     es, vconfig.sgmnt       %@AB@%; ES:DI points to video RAM%@AE@%%@NL@%
  420.         .WHILE  1                       %@AB@%; Loop forever (or until break)%@AE@%%@NL@%
  421.         lodsb                           %@AB@%; Get 1 character from string%@AE@%%@NL@%
  422.         .BREAK .IF al == 0              %@AB@%; Quit if null terminator%@AE@%%@NL@%
  423. %@NL@%
  424. %@AB@%; For CGA systems, StrWrite waits for the video to begin a horizontal%@AE@%%@NL@%
  425. %@AB@%; retrace before writing a character to memory. This avoids the problem%@AE@%%@NL@%
  426. %@AB@%; of video snow inherent with some (though not all) color/graphics adapters.%@AE@%%@NL@%
  427. %@AB@%; It also demonstrates a somewhat different approach to the problem than the%@AE@%%@NL@%
  428. %@AB@%; one taken in the WinOpen and WinClose procedures.%@AE@%%@NL@%
  429. %@NL@%
  430.         .IF vconfig.adapter != CGA      %@AB@%; If not CGA, skip this step%@AE@%%@NL@%
  431.         push    ax                      %@AB@%; Save character%@AE@%%@NL@%
  432.         mov     dx, 3DAh                %@AB@%; Address of status register%@AE@%%@NL@%
  433.         cli                             %@AB@%; Disallow interruptions%@AE@%%@NL@%
  434.         .REPEAT%@NL@%
  435.         in      al, dx                  %@AB@%; Read current video status%@AE@%%@NL@%
  436.         .UNTIL  !(al & 1)               %@AB@%; Until horizontal retrace done%@AE@%%@NL@%
  437. %@NL@%
  438.         .REPEAT%@NL@%
  439.         in      al, dx                  %@AB@%; No?  Read status again%@AE@%%@NL@%
  440.         .UNTIL  al & 1                  %@AB@%; Until retrace starts%@AE@%%@NL@%
  441.         pop     ax                      %@AB@%; Recover character%@AE@%%@NL@%
  442.         .ENDIF  %@AB@%; CGA only%@AE@%%@NL@%
  443. %@NL@%
  444.         stosb                           %@AB@%; Write char to video buffer%@AE@%%@NL@%
  445.         sti                             %@AB@%; Reenable interrupts in case CGA%@AE@%%@NL@%
  446.         inc     di                      %@AB@%; Skip attribute byte%@AE@%%@NL@%
  447.         .ENDW%@NL@%
  448.         ret%@NL@%
  449. %@NL@%
  450. StrWrite ENDP%@NL@%
  451. %@NL@%
  452. %@NL@%
  453. %@AB@%;* StrInput - Gets input string from keyboard using BIOS. Signals idle%@AE@%%@NL@%
  454. %@AB@%;* state by calling interrupt 28h while polling for keypress, making%@AE@%%@NL@%
  455. %@AB@%;* the procedure useful in TSR programs. Terminates when Enter or Esc%@AE@%%@NL@%
  456. %@AB@%;* keys pressed.%@AE@%%@NL@%
  457. %@AB@%;*%@AE@%%@NL@%
  458. %@AB@%;* Shows:   DOS interrupt - Interrupt 28h (DOS Idle Interrupt)%@AE@%%@NL@%
  459. %@AB@%;*%@AE@%%@NL@%
  460. %@AB@%;* Params:  Row - Row coordinate%@AE@%%@NL@%
  461. %@AB@%;*          Col - Column coordinate%@AE@%%@NL@%
  462. %@AB@%;*          Max - Maximum allowable string length%@AE@%%@NL@%
  463. %@AB@%;*          Sptr - Pointer to string%@AE@%%@NL@%
  464. %@AB@%;*%@AE@%%@NL@%
  465. %@AB@%;* Return:  Short integer with terminating char%@AE@%%@NL@%
  466. %@NL@%
  467. StrInput PROC USES ds si,%@NL@%
  468.         Row:WORD,%@NL@%
  469.         Col:WORD,%@NL@%
  470.         Max:WORD,%@NL@%
  471.         Sptr:PBYTE%@NL@%
  472. %@NL@%
  473.         LoadPtr ds, si, Sptr            %@AB@%; DS:SI points to string%@AE@%%@NL@%
  474.         add     Max, si%@NL@%
  475.         dec     Max                     %@AB@%; MAX now points to string limit%@AE@%%@NL@%
  476. %@NL@%
  477.         .WHILE  1                       %@AB@%; Get key until break or continue%@AE@%%@NL@%
  478. loop1:%@NL@%
  479.         INVOKE  StrWrite,               %@AB@%; Display input string%@AE@%%@NL@%
  480.                 Row,%@NL@%
  481.                 Col,%@NL@%
  482.                 si%@NL@%
  483. %@NL@%
  484.         mov     bx, si%@NL@%
  485.         mov     dx, Col                 %@AB@%; DL = cursor column%@AE@%%@NL@%
  486. %@NL@%
  487.         .WHILE  (BYTE PTR [bx] != 0)    %@AB@%; Scan string for null terminator%@AE@%%@NL@%
  488.         inc     bx                      %@AB@%; Else try next character%@AE@%%@NL@%
  489.         inc     dx                      %@AB@%;   and increment cursor column%@AE@%%@NL@%
  490.         .ENDW%@NL@%
  491. %@NL@%
  492.         %@AB@%; Set cursor position, pass row and column (DX)%@AE@%%@NL@%
  493.         INVOKE  SetCurPos,%@NL@%
  494.                 Row,%@NL@%
  495.                 dx%@NL@%
  496. %@NL@%
  497.         .REPEAT%@NL@%
  498.         int     28h                     %@AB@%; Signal idle state%@AE@%%@NL@%
  499.         mov     ah, 1%@NL@%
  500.         int     16h                     %@AB@%; Key waiting?%@AE@%%@NL@%
  501.         .CONTINUE .IF zero?%@NL@%
  502.         sub     ah, ah%@NL@%
  503.         int     16h                     %@AB@%; Yes?  Get key%@AE@%%@NL@%
  504. %@NL@%
  505.         cmp     ah, LEFT                %@AB@%; Left arrow key?%@AE@%%@NL@%
  506.         je      backspace               %@AB@%; Treat like backspace%@AE@%%@NL@%
  507.         .UNTIL  al != 0                 %@AB@%; Ignore all other special keys%@AE@%%@NL@%
  508. %@NL@%
  509.         .BREAK  .IF al == ESCAPE        %@AB@%; Exit if Esc key%@AE@%%@NL@%
  510.         .BREAK  .IF al == CR            %@AB@%; Exit if Return key%@AE@%%@NL@%
  511. %@NL@%
  512.         .IF     al == BACKSP            %@AB@%; If backspace or left, handle it%@AE@%%@NL@%
  513. backspace:%@NL@%
  514.         cmp     bx, si                  %@AB@%; At first letter?%@AE@%%@NL@%
  515.         jbe     loop1                   %@AB@%; Yes?  Ignore backspace%@AE@%%@NL@%
  516.         dec     bx                      %@AB@%; No?  Point to preceding char%@AE@%%@NL@%
  517.         dec     dx                      %@AB@%; Decrement column%@AE@%%@NL@%
  518.         mov     BYTE PTR [bx], ' '      %@AB@%; Blank char%@AE@%%@NL@%
  519.         push    bx                      %@AB@%; Preserve pointer%@AE@%%@NL@%
  520.         INVOKE  StrWrite,               %@AB@%; Overwrite last char with blank%@AE@%%@NL@%
  521.                 Row,%@NL@%
  522.                 dx,%@NL@%
  523.                 bx%@NL@%
  524. %@NL@%
  525.         pop     bx%@NL@%
  526.         mov     BYTE PTR [bx], 0        %@AB@%; Make last char the new terminator%@AE@%%@NL@%
  527.         .CONTINUE%@NL@%
  528.         .ENDIF%@NL@%
  529. %@NL@%
  530.         .CONTINUE .IF bx > Max          %@AB@%; Ignore key if too many letters%@AE@%%@NL@%
  531.         sub     ah, ah%@NL@%
  532.         mov     [bx], ax                %@AB@%; Store letter and null terminator%@AE@%%@NL@%
  533.         .ENDW%@NL@%
  534. %@NL@%
  535.         ret%@NL@%
  536. %@NL@%
  537. StrInput ENDP%@NL@%
  538. %@NL@%
  539. %@NL@%
  540. %@AB@%;* ClearBox - Clears portion of screen with specified fill attribute.%@AE@%%@NL@%
  541. %@AB@%;*%@AE@%%@NL@%
  542. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 6 (Scroll Up)%@AE@%%@NL@%
  543. %@AB@%;*%@AE@%%@NL@%
  544. %@AB@%;* Params:  Attr - Fill attribute%@AE@%%@NL@%
  545. %@AB@%;*          Row1 - Top screen row of cleared section%@AE@%%@NL@%
  546. %@AB@%;*          Col1 - Left column of cleared section%@AE@%%@NL@%
  547. %@AB@%;*          Row2 - Bottom screen row of cleared section%@AE@%%@NL@%
  548. %@AB@%;*          Col2 - Right column of cleared section%@AE@%%@NL@%
  549. %@AB@%;*%@AE@%%@NL@%
  550. %@AB@%;* Return:  None%@AE@%%@NL@%
  551. %@NL@%
  552. ClearBox PROC,%@NL@%
  553.         Attr:WORD,%@NL@%
  554.         Row1:WORD,%@NL@%
  555.         Col1:WORD,%@NL@%
  556.         Row2:WORD,%@NL@%
  557.         Col2:WORD%@NL@%
  558. %@NL@%
  559.         mov     ax, 0600h               %@AB@%; Scroll service%@AE@%%@NL@%
  560.         mov     bh, BYTE PTR Attr       %@AB@%; BH = fill attribute%@AE@%%@NL@%
  561.         mov     ch, BYTE PTR Row1       %@AB@%; CH = top row of clear area%@AE@%%@NL@%
  562.         mov     cl, BYTE PTR Col1       %@AB@%; CL = left column%@AE@%%@NL@%
  563.         mov     dh, BYTE PTR Row2       %@AB@%; DH = bottom row of clear area%@AE@%%@NL@%
  564.         mov     dl, BYTE PTR Col2       %@AB@%; DL = right column%@AE@%%@NL@%
  565.         int     10h                     %@AB@%; Clear screen by scrolling up%@AE@%%@NL@%
  566.         ret%@NL@%
  567. %@NL@%
  568. ClearBox ENDP%@NL@%
  569. %@NL@%
  570. %@NL@%
  571. %@AB@%;* DisableCga - Disables CGA video by reprogramming the control register.%@AE@%%@NL@%
  572. %@AB@%;*%@AE@%%@NL@%
  573. %@AB@%;* Shows:   Instructions - cli     sti%@AE@%%@NL@%
  574. %@AB@%;*%@AE@%%@NL@%
  575. %@AB@%;* Params:  None%@AE@%%@NL@%
  576. %@AB@%;*%@AE@%%@NL@%
  577. %@AB@%;* Return:  None%@AE@%%@NL@%
  578. %@NL@%
  579. DisableCga PROC USES ax cx dx           %@AB@%; Preserve registers%@AE@%%@NL@%
  580. %@NL@%
  581.         mov     cx, -1                  %@AB@%; Set maximum loop count%@AE@%%@NL@%
  582.         mov     dx, 03DAh               %@AB@%; Address of status register%@AE@%%@NL@%
  583. %@NL@%
  584.         .REPEAT%@NL@%
  585.         in      al, dx                  %@AB@%; Get video status%@AE@%%@NL@%
  586.         .UNTILCXZ !(al & 8)             %@AB@%; Until retrace end/timeout%@AE@%%@NL@%
  587.         cli                             %@AB@%; Disallow interruptions%@AE@%%@NL@%
  588.         mov     cx, -1                  %@AB@%; Reset loop count%@AE@%%@NL@%
  589. %@NL@%
  590.         .REPEAT%@NL@%
  591.         in      al, dx                  %@AB@%; Get video status%@AE@%%@NL@%
  592.         .UNTILCXZ al & 8                %@AB@%; Until retrace start/timeout%@AE@%%@NL@%
  593. %@NL@%
  594.         sub     dx, 2                   %@AB@%; DX = address of control reg%@AE@%%@NL@%
  595.         mov     al, 1                   %@AB@%; Value to disable CGA video%@AE@%%@NL@%
  596.         out     dx, al                  %@AB@%; Disable video%@AE@%%@NL@%
  597.         sti                             %@AB@%; Reenable interrupts%@AE@%%@NL@%
  598.         ret%@NL@%
  599. %@NL@%
  600. DisableCga ENDP%@NL@%
  601. %@NL@%
  602. %@NL@%
  603. %@AB@%;* EnableCga - Enables CGA video by reprogramming the control register.%@AE@%%@NL@%
  604. %@AB@%;*%@AE@%%@NL@%
  605. %@AB@%;* Params:  None%@AE@%%@NL@%
  606. %@AB@%;*%@AE@%%@NL@%
  607. %@AB@%;* Return:  None%@AE@%%@NL@%
  608. %@NL@%
  609. EnableCga PROC USES ax dx es                    %@AB@%; Preserve registers%@AE@%%@NL@%
  610. %@NL@%
  611.         sub     ax, ax%@NL@%
  612.         mov     es, ax                          %@AB@%; Point ES to low memory%@AE@%%@NL@%
  613.         mov     al, es:[0465h]                  %@AB@%; Get former mode setting%@AE@%%@NL@%
  614.         mov     dx, 03D8h                       %@AB@%; Address of control register%@AE@%%@NL@%
  615.         out     dx, al                          %@AB@%; Enable video%@AE@%%@NL@%
  616.         ret%@NL@%
  617. %@NL@%
  618. EnableCga ENDP%@NL@%
  619. %@NL@%
  620. %@NL@%
  621. %@AB@%;* GetVer - Gets DOS version.%@AE@%%@NL@%
  622. %@AB@%;*%@AE@%%@NL@%
  623. %@AB@%;* Shows:   DOS Function - 30h (Get MS-DOS Version Number)%@AE@%%@NL@%
  624. %@AB@%;*%@AE@%%@NL@%
  625. %@AB@%;* Params:  None%@AE@%%@NL@%
  626. %@AB@%;*%@AE@%%@NL@%
  627. %@AB@%;* Return:  Short integer of form (M*100)+m, where M is major%@AE@%%@NL@%
  628. %@AB@%;*          version number and m is minor version, or 0 if%@AE@%%@NL@%
  629. %@AB@%;*          DOS version earlier than 2.0%@AE@%%@NL@%
  630. %@NL@%
  631. GetVer  PROC%@NL@%
  632. %@NL@%
  633.         mov     ah, 30h                 %@AB@%; DOS Function 30h%@AE@%%@NL@%
  634.         int     21h                     %@AB@%; Get MS-DOS Version Number%@AE@%%@NL@%
  635.         .IF     al == 0                 %@AB@%; If version, version 1%@AE@%%@NL@%
  636.         sub     ax, ax                  %@AB@%; Set AX to 0%@AE@%%@NL@%
  637.         .ELSE                           %@AB@%; Version 2.0 or higher%@AE@%%@NL@%
  638.         sub     ch, ch                  %@AB@%; Zero CH and move minor%@AE@%%@NL@%
  639.         mov     cl, ah                  %@AB@%;   version number into CX%@AE@%%@NL@%
  640.         mov     bl, 100%@NL@%
  641.         mul     bl                      %@AB@%; Multiply major by 10%@AE@%%@NL@%
  642.         add     ax, cx                  %@AB@%; Add minor to major*10%@AE@%%@NL@%
  643.         .ENDIF%@NL@%
  644.         ret                             %@AB@%; Return result in AX%@AE@%%@NL@%
  645. %@NL@%
  646. GetVer  ENDP%@NL@%
  647. %@NL@%
  648.         END%@NL@%
  649. %@NL@%
  650. %@NL@%
  651. %@2@%%@AH@%FILE.ASM%@AE@%%@EH@%%@NL@%
  652. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\DEMOS\FILE.ASM%@AE@%%@NL@%
  653. %@NL@%
  654.         .MODEL small, pascal, os_dos%@NL@%
  655.         INCLUDE demo.inc%@NL@%
  656.         .CODE%@NL@%
  657. %@NL@%
  658. %@AB@%;* ReadCharAttr - Reads character and display attribute at cursor location.%@AE@%%@NL@%
  659. %@AB@%;*%@AE@%%@NL@%
  660. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 8 (Read Character and Attribute%@AE@%%@NL@%
  661. %@AB@%;*                                at Cursor)%@AE@%%@NL@%
  662. %@AB@%;*%@AE@%%@NL@%
  663. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  664. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  665. %@AB@%;*%@AE@%%@NL@%
  666. %@AB@%;* Params:  Attr - Pointer to short integer for display attribute%@AE@%%@NL@%
  667. %@AB@%;*%@AE@%%@NL@%
  668. %@AB@%;* Return:  Short integer with ASCII value of character%@AE@%%@NL@%
  669. %@NL@%
  670. ReadCharAttr PROC USES di,%@NL@%
  671.         Attr:PWORD%@NL@%
  672. %@NL@%
  673.         mov     ah, 8                   %@AB@%; Function 8%@AE@%%@NL@%
  674.         mov     bh, vconfig.dpage       %@AB@%; Current page%@AE@%%@NL@%
  675.         int     10h                     %@AB@%; Read Character and Attribute%@AE@%%@NL@%
  676.         sub     bh, bh%@NL@%
  677.         mov     bl, ah                  %@AB@%; BX = attribute%@AE@%%@NL@%
  678.         cbw                             %@AB@%; AX = character%@AE@%%@NL@%
  679.         LoadPtr es, di, Attr            %@AB@%; ES:DI = pointer to int%@AE@%%@NL@%
  680.         mov     es:[di], bx             %@AB@%; Copy attribute%@AE@%%@NL@%
  681.         ret%@NL@%
  682. %@NL@%
  683. ReadCharAttr ENDP%@NL@%
  684. %@NL@%
  685. %@NL@%
  686. %@AB@%;* CopyFile - Copies a file from a specified directory to another. Allows%@AE@%%@NL@%
  687. %@AB@%;* two different copy methods. See the OpenFile, CloseFile, ReadFile, and%@AE@%%@NL@%
  688. %@AB@%;* WriteFile procedures for specific examples on opening, closing, reading%@AE@%%@NL@%
  689. %@AB@%;* from, and writing to files.%@AE@%%@NL@%
  690. %@AB@%;*%@AE@%%@NL@%
  691. %@AB@%;* Shows:   DOS Functions - 3Ch (Create File)%@AE@%%@NL@%
  692. %@AB@%;*                          5Bh (Create New File)%@AE@%%@NL@%
  693. %@AB@%;*          Instruction - clc%@AE@%%@NL@%
  694. %@AB@%;*%@AE@%%@NL@%
  695. %@AB@%;* Params:  Imode  - 0 = Create new target file or overwrite existing file%@AE@%%@NL@%
  696. %@AB@%;*                   1 = Abort and return error code if target file already%@AE@%%@NL@%
  697. %@AB@%;*                       exists (only for DOS versions 3.0 and higher)%@AE@%%@NL@%
  698. %@AB@%;*          Fspec1 - Pointer to ASCIIZ source file specification%@AE@%%@NL@%
  699. %@AB@%;*          Fspec2 - Pointer to ASCIIZ target file specification%@AE@%%@NL@%
  700. %@AB@%;*%@AE@%%@NL@%
  701. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  702. %@AB@%;*          0 if successful%@AE@%%@NL@%
  703. %@AB@%;*          1 if error%@AE@%%@NL@%
  704. %@NL@%
  705.         .DATA%@NL@%
  706. Buffer  BYTE    BUFFERSIZE DUP (?)     %@AB@%; Buffer for diskette read%@AE@%%@NL@%
  707. %@NL@%
  708.         .CODE%@NL@%
  709. %@NL@%
  710. CopyFile PROC USES ds si di,%@NL@%
  711.         Imode:WORD,%@NL@%
  712.         Fspec1:PBYTE,%@NL@%
  713.         Fspec2:PBYTE%@NL@%
  714. %@NL@%
  715.         LOCAL eof_flag:BYTE%@NL@%
  716. %@NL@%
  717. %@AB@%; Open source file for read only%@AE@%%@NL@%
  718. %@NL@%
  719.         LoadPtr ds, dx, Fspec1          %@AB@%; Point DS:DX to source file%@AE@%%@NL@%
  720.         mov     ax, 3D00h               %@AB@%; AH = function #, AL = access code%@AE@%%@NL@%
  721.         int     21h                     %@AB@%; Open File (for read only)%@AE@%%@NL@%
  722.         jc      e_exit%@NL@%
  723.         mov     si, ax                  %@AB@%; SI = file handle for source%@AE@%%@NL@%
  724. %@NL@%
  725. %@AB@%; Open target file according to copy mode%@AE@%%@NL@%
  726. %@NL@%
  727.         LoadPtr ds, dx, Fspec2          %@AB@%; Point DS:DX to target file%@AE@%%@NL@%
  728.         .IF     Imode != 1              %@AB@%; If Imode (DOS function) is not 1%@AE@%%@NL@%
  729.         mov     ah, 3Ch                 %@AB@%; Request Create File%@AE@%%@NL@%
  730.         .ELSE%@NL@%
  731. %@NL@%
  732.         %@AB@%; Check DOS version%@AE@%%@NL@%
  733.         INVOKE  GetVer%@NL@%
  734. %@NL@%
  735.         cmp     ax, 300                 %@AB@%; 3.0 or higher?%@AE@%%@NL@%
  736.         jb      close                   %@AB@%; No?  Abort with error code%@AE@%%@NL@%
  737.         mov     ah, 5Bh                 %@AB@%; Request Create New File%@AE@%%@NL@%
  738.         .ENDIF%@NL@%
  739.         sub     cx, cx                  %@AB@%; Normal attribute for target%@AE@%%@NL@%
  740.         int     21h                     %@AB@%; DOS function for target file%@AE@%%@NL@%
  741.         jc      close                   %@AB@%; If open error, abort%@AE@%%@NL@%
  742.         mov     di, ax                  %@AB@%; DI = file handle for target%@AE@%%@NL@%
  743. %@NL@%
  744. %@AB@%; Both files successfully opened. Now read from source and copy to target.%@AE@%%@NL@%
  745. %@NL@%
  746.         mov     ax, @data%@NL@%
  747.         mov     ds, ax                  %@AB@%; DS:DX = buffer. Read/write%@AE@%%@NL@%
  748.         mov     dx, OFFSET Buffer       %@AB@%;   to and from here.%@AE@%%@NL@%
  749.         mov     eof_flag, 0             %@AB@%; Initialize end-of-file flag%@AE@%%@NL@%
  750. %@NL@%
  751.         .REPEAT%@NL@%
  752.         mov     bx, si                  %@AB@%; Handle for source file%@AE@%%@NL@%
  753.         mov     cx, BUFFERSIZE          %@AB@%; CX = number of bytes to read%@AE@%%@NL@%
  754.         mov     ah, 3Fh                 %@AB@%; Request DOS read%@AE@%%@NL@%
  755.         int     21h                     %@AB@%; Read from File%@AE@%%@NL@%
  756.         jc      close                   %@AB@%; If error, exit%@AE@%%@NL@%
  757.         .IF     ax != cx                %@AB@%; If bytes not read successfully:%@AE@%%@NL@%
  758.         inc     eof_flag                %@AB@%; Raise flag%@AE@%%@NL@%
  759.         .ENDIF%@NL@%
  760.         mov     bx, di                  %@AB@%; Handle for target file%@AE@%%@NL@%
  761.         mov     cx, ax                  %@AB@%; Write number of bytes read%@AE@%%@NL@%
  762.         mov     ah, 40h                 %@AB@%; Request DOS write%@AE@%%@NL@%
  763.         int     21h                     %@AB@%; Write from buffer to target file%@AE@%%@NL@%
  764.         jc      close                   %@AB@%; If error, exit%@AE@%%@NL@%
  765.         .UNTIL  eof_flag != 0           %@AB@%; Loop to read next block%@AE@%%@NL@%
  766.         clc                             %@AB@%; Clear CY to indicate%@AE@%%@NL@%
  767. close:%@NL@%
  768.         pushf                           %@AB@%; Preserve flags while closing%@AE@%%@NL@%
  769.         mov     bx, di                  %@AB@%; Handle for target file%@AE@%%@NL@%
  770.         mov     ah, 3Eh                 %@AB@%; Request DOS Function 3Eh%@AE@%%@NL@%
  771.         int     21h                     %@AB@%; Close File%@AE@%%@NL@%
  772.         sub     ax, ax                  %@AB@%; Clear error code%@AE@%%@NL@%
  773.         popf                            %@AB@%; Recover flags%@AE@%%@NL@%
  774.         .IF     carry?%@NL@%
  775. e_exit:%@NL@%
  776.         mov     ax, 1                   %@AB@%; Else set error code%@AE@%%@NL@%
  777.         .ENDIF%@NL@%
  778.         ret%@NL@%
  779. %@NL@%
  780. CopyFile ENDP%@NL@%
  781. %@NL@%
  782. %@NL@%
  783. %@AB@%;* ChangeDrive - Changes default drive.%@AE@%%@NL@%
  784. %@AB@%;*%@AE@%%@NL@%
  785. %@AB@%;* Shows:   DOS Function - 0Eh (Select Disk)%@AE@%%@NL@%
  786. %@AB@%;*%@AE@%%@NL@%
  787. %@AB@%;* Params:  Drive - Uppercase letter designation for new drive%@AE@%%@NL@%
  788. %@AB@%;*%@AE@%%@NL@%
  789. %@AB@%;* Return:  None%@AE@%%@NL@%
  790. %@NL@%
  791. ChangeDrive PROC,%@NL@%
  792.         Drive:WORD%@NL@%
  793. %@NL@%
  794.         mov     ah, 0Eh                 %@AB@%; DOS Function 0Eh%@AE@%%@NL@%
  795.         mov     dx, Drive               %@AB@%; Drive designation in DL,%@AE@%%@NL@%
  796.         sub     dl, 'A'                 %@AB@%;   0=A, 1=B, 2=C, etc%@AE@%%@NL@%
  797.         int     21h                     %@AB@%; Select Disk%@AE@%%@NL@%
  798.         ret%@NL@%
  799. %@NL@%
  800. ChangeDrive ENDP%@NL@%
  801. %@NL@%
  802. %@NL@%
  803. %@AB@%;* GetCurDrive - Gets designation of current drive.%@AE@%%@NL@%
  804. %@AB@%;*%@AE@%%@NL@%
  805. %@AB@%;* Shows:   DOS Function - 19h (Get Current Disk)%@AE@%%@NL@%
  806. %@AB@%;*          Instruction - cbw%@AE@%%@NL@%
  807. %@AB@%;*%@AE@%%@NL@%
  808. %@AB@%;* Params:  None%@AE@%%@NL@%
  809. %@AB@%;*%@AE@%%@NL@%
  810. %@AB@%;* Return:  Short integer with drive designation%@AE@%%@NL@%
  811. %@AB@%;*          0 = A, 1 = B, 2 = C, etc.%@AE@%%@NL@%
  812. %@NL@%
  813. GetCurDrive PROC%@NL@%
  814. %@NL@%
  815.         mov     ah, 19h                 %@AB@%; DOS Function 19h%@AE@%%@NL@%
  816.         int     21h                     %@AB@%; Get Current Disk%@AE@%%@NL@%
  817.         cbw                             %@AB@%; AX = drive designation%@AE@%%@NL@%
  818.         ret%@NL@%
  819. %@NL@%
  820. GetCurDrive ENDP%@NL@%
  821. %@NL@%
  822. %@NL@%
  823. %@AB@%;* SetDTA - Sets address for new Disk Transfer Area.%@AE@%%@NL@%
  824. %@AB@%;*%@AE@%%@NL@%
  825. %@AB@%;* Shows:   DOS Function - 1Ah (Set DTA Address)%@AE@%%@NL@%
  826. %@AB@%;*%@AE@%%@NL@%
  827. %@AB@%;* Params:  Dta - Far pointer to new transfer address%@AE@%%@NL@%
  828. %@AB@%;*%@AE@%%@NL@%
  829. %@AB@%;* Return:  None%@AE@%%@NL@%
  830. %@NL@%
  831. SetDTA  PROC USES ds,%@NL@%
  832.         Dta:FPBYTE%@NL@%
  833. %@NL@%
  834.         lds     dx, [Dta]               %@AB@%; Point DS:DX to DTA%@AE@%%@NL@%
  835.         mov     ah, 1Ah                 %@AB@%; DOS Function 1Ah%@AE@%%@NL@%
  836.         int     21h                     %@AB@%; Set DTA Address%@AE@%%@NL@%
  837.         ret%@NL@%
  838. %@NL@%
  839. SetDTA  ENDP%@NL@%
  840. %@NL@%
  841. %@NL@%
  842. %@AB@%;* GetDTA - Gets address of current Disk Transfer Area.%@AE@%%@NL@%
  843. %@AB@%;*%@AE@%%@NL@%
  844. %@AB@%;* Shows:   DOS Function - 2Fh (Get DTA Address)%@AE@%%@NL@%
  845. %@AB@%;*%@AE@%%@NL@%
  846. %@AB@%;* Params:  Dta - Far pointer to receive transfer address%@AE@%%@NL@%
  847. %@AB@%;*%@AE@%%@NL@%
  848. %@AB@%;* Return:  None%@AE@%%@NL@%
  849. %@NL@%
  850. GetDTA  PROC,%@NL@%
  851.         Dta:FPBYTE%@NL@%
  852. %@NL@%
  853.         mov     ah, 2Fh                 %@AB@%; DOS Function 2Fh%@AE@%%@NL@%
  854.         int     21h                     %@AB@%; Get DTA Address in ES:BX%@AE@%%@NL@%
  855.         mov     ax, es                  %@AB@%; Save DTA segment%@AE@%%@NL@%
  856.         mov     dx, bx                  %@AB@%; Save DTA offset%@AE@%%@NL@%
  857.         les     bx, Dta                 %@AB@%; Now ES:BX points to variable%@AE@%%@NL@%
  858.         mov     es:[bx], dx             %@AB@%; Copy DTA address to%@AE@%%@NL@%
  859.         mov     es:[bx+2], ax           %@AB@%;       dta variable%@AE@%%@NL@%
  860.         ret%@NL@%
  861. %@NL@%
  862. GetDTA  ENDP%@NL@%
  863. %@NL@%
  864. %@NL@%
  865. %@AB@%;* CreateFile - Creates file with specified attribute.%@AE@%%@NL@%
  866. %@AB@%;*%@AE@%%@NL@%
  867. %@AB@%;* Shows:   DOS Function - 3Ch (Create File)%@AE@%%@NL@%
  868. %@AB@%;*%@AE@%%@NL@%
  869. %@AB@%;* Params:  Attr - Attribute code:  0 = normal        8 = volume label%@AE@%%@NL@%
  870. %@AB@%;*                                        1 = read only    16 = subdirectory%@AE@%%@NL@%
  871. %@AB@%;*                                        2 = hidden              32 = archive%@AE@%%@NL@%
  872. %@AB@%;*                                        4 = system%@AE@%%@NL@%
  873. %@AB@%;*          Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
  874. %@AB@%;*%@AE@%%@NL@%
  875. %@AB@%;* Return:  Short integer with file handle or -1 for error%@AE@%%@NL@%
  876. %@NL@%
  877. CreateFile PROC USES ds,%@NL@%
  878.         Attr:WORD, Fspec:PBYTE%@NL@%
  879. %@NL@%
  880.         LoadPtr ds, dx, Fspec           %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
  881.         mov     cx, Attr                %@AB@%; CX = attribute%@AE@%%@NL@%
  882.         mov     ah, 3Ch                 %@AB@%; AH = function number%@AE@%%@NL@%
  883.         int     21h                     %@AB@%; Create file%@AE@%%@NL@%
  884.         .IF     carry?%@NL@%
  885.         mov     ax, -1                  %@AB@%; Set error code%@AE@%%@NL@%
  886.         .ENDIF%@NL@%
  887.         ret%@NL@%
  888. %@NL@%
  889. CreateFile ENDP%@NL@%
  890. %@NL@%
  891. %@NL@%
  892. %@AB@%;* OpenFile - Opens specified file for reading or writing. See the CopyFile%@AE@%%@NL@%
  893. %@AB@%;* procedure for another example of using DOS Function 3Dh to open files.%@AE@%%@NL@%
  894. %@AB@%;*%@AE@%%@NL@%
  895. %@AB@%;* Shows:   DOS Function - 3Dh (Open File)%@AE@%%@NL@%
  896. %@AB@%;*%@AE@%%@NL@%
  897. %@AB@%;* Params:  Access - Access code:  0 = read    1 = write    2 = read/write%@AE@%%@NL@%
  898. %@AB@%;*          Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
  899. %@AB@%;*%@AE@%%@NL@%
  900. %@AB@%;* Return:  Short integer with file handle or -1 for error%@AE@%%@NL@%
  901. %@NL@%
  902. OpenFile PROC USES ds,%@NL@%
  903.         Access:WORD, Fspec:PBYTE%@NL@%
  904. %@NL@%
  905.         LoadPtr ds, dx, Fspec           %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
  906.         mov     ax, Access              %@AB@%; AL = access code%@AE@%%@NL@%
  907.         mov     ah, 3Dh                 %@AB@%; AH = function number%@AE@%%@NL@%
  908.         int     21h                     %@AB@%; Open file%@AE@%%@NL@%
  909.         .IF     carry?%@NL@%
  910.         mov     ax, -1                  %@AB@%; Set error code%@AE@%%@NL@%
  911.         .ENDIF%@NL@%
  912.         ret%@NL@%
  913. %@NL@%
  914. OpenFile ENDP%@NL@%
  915. %@NL@%
  916. %@NL@%
  917. %@AB@%;* CloseFile - Closes an open file, specified by handle. See the CopyFile%@AE@%%@NL@%
  918. %@AB@%;* procedure for another example of using DOS Function 3Eh to close files.%@AE@%%@NL@%
  919. %@AB@%;*%@AE@%%@NL@%
  920. %@AB@%;* Shows:   DOS Function - 3EH (Close File)%@AE@%%@NL@%
  921. %@AB@%;*%@AE@%%@NL@%
  922. %@AB@%;* Params:  Handle - File handle%@AE@%%@NL@%
  923. %@AB@%;*%@AE@%%@NL@%
  924. %@AB@%;* Return:  None%@AE@%%@NL@%
  925. %@NL@%
  926. CloseFile PROC,%@NL@%
  927.         Handle:WORD%@NL@%
  928. %@NL@%
  929.         mov     bx, Handle              %@AB@%; BX = file handle%@AE@%%@NL@%
  930.         mov     ah, 3Eh                 %@AB@%; DOS Function 3Eh%@AE@%%@NL@%
  931.         int     21h                     %@AB@%; Close file%@AE@%%@NL@%
  932.         ret%@NL@%
  933. %@NL@%
  934. CloseFile ENDP%@NL@%
  935. %@NL@%
  936. %@NL@%
  937. %@AB@%;* ReadFile - Read from open file to specified buffer. See the CopyFile%@AE@%%@NL@%
  938. %@AB@%;* procedure for another example of using DOS Function 3Fh to read files.%@AE@%%@NL@%
  939. %@AB@%;*%@AE@%%@NL@%
  940. %@AB@%;* Shows:   DOS Function - 3Fh (Read File or Device)%@AE@%%@NL@%
  941. %@AB@%;*%@AE@%%@NL@%
  942. %@AB@%;* Params:  Handle - File handle%@AE@%%@NL@%
  943. %@AB@%;*          Len - Number of bytes to read%@AE@%%@NL@%
  944. %@AB@%;*          Pbuff - Pointer to buffer%@AE@%%@NL@%
  945. %@AB@%;*%@AE@%%@NL@%
  946. %@AB@%;* Return:  Short integer with number of bytes read, or 0 if read error%@AE@%%@NL@%
  947. %@NL@%
  948. ReadFile PROC USES ds di,%@NL@%
  949.         Handle:WORD, Len:WORD, Pbuff:PBYTE%@NL@%
  950. %@NL@%
  951.         LoadPtr ds, dx, Pbuff           %@AB@%; Point DS:DX to buffer%@AE@%%@NL@%
  952.         mov     di, dx                  %@AB@%; Keep string offset in DI%@AE@%%@NL@%
  953.         mov     bx, Handle              %@AB@%; BX = handle%@AE@%%@NL@%
  954.         mov     cx, Len                 %@AB@%; CX = number of bytes to read%@AE@%%@NL@%
  955.         mov     ah, 3Fh                 %@AB@%; Request DOS read%@AE@%%@NL@%
  956.         int     21h                     %@AB@%; Read File%@AE@%%@NL@%
  957.         .IF     carry?%@NL@%
  958.         sub     ax, ax                  %@AB@%; Set error code%@AE@%%@NL@%
  959.         .ENDIF%@NL@%
  960.         ret%@NL@%
  961. %@NL@%
  962. ReadFile ENDP%@NL@%
  963. %@NL@%
  964. %@NL@%
  965. %@AB@%;* WriteFile - Write ASCIIZ string to file. If Handle = 0, the string is%@AE@%%@NL@%
  966. %@AB@%;* written to STDOUT (console). See the CopyFile procedure for another%@AE@%%@NL@%
  967. %@AB@%;* example of using DOS Function 40h to write to files.%@AE@%%@NL@%
  968. %@AB@%;*%@AE@%%@NL@%
  969. %@AB@%;* Shows:   DOS Function - 40h (Write File or Device)%@AE@%%@NL@%
  970. %@AB@%;*          Instructions - inc      dec%@AE@%%@NL@%
  971. %@AB@%;*%@AE@%%@NL@%
  972. %@AB@%;* Params:  Handle - File handle%@AE@%%@NL@%
  973. %@AB@%;*          SPtr - Pointer to ASCIIZ string%@AE@%%@NL@%
  974. %@AB@%;*%@AE@%%@NL@%
  975. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  976. %@AB@%;*          0 if successful%@AE@%%@NL@%
  977. %@AB@%;*          1 if write error%@AE@%%@NL@%
  978. %@AB@%;*          2 if number of bytes written not equal to string length%@AE@%%@NL@%
  979. %@NL@%
  980. WriteFile PROC USES ds di,%@NL@%
  981.         Handle:WORD, Sptr:PBYTE%@NL@%
  982. %@NL@%
  983.         LoadPtr es, di, Sptr            %@AB@%; Point ES:DI to string%@AE@%%@NL@%
  984.         push    di                      %@AB@%; Hold on to string pointer%@AE@%%@NL@%
  985.         mov     cx, -1                  %@AB@%; Set CX to maximum%@AE@%%@NL@%
  986.         sub     al, al                  %@AB@%; AL = 0%@AE@%%@NL@%
  987.         repne   scasb                   %@AB@%; Scan string for NULL%@AE@%%@NL@%
  988.         pop     dx                      %@AB@%; Recover string pointer%@AE@%%@NL@%
  989.         dec     di%@NL@%
  990.         sub     di, dx                  %@AB@%; Get string length (w/o NULL)%@AE@%%@NL@%
  991.         mov     cx, di                  %@AB@%; Put it into CX%@AE@%%@NL@%
  992.         mov     bx, Handle              %@AB@%; Load BX with handle%@AE@%%@NL@%
  993.         push    es                      %@AB@%; Set DS to ES to ensure%@AE@%%@NL@%
  994.         pop     ds                      %@AB@%;   DS:DX points to string%@AE@%%@NL@%
  995.         mov     ah, 40h                 %@AB@%; Request DOS write%@AE@%%@NL@%
  996.         int     21h                     %@AB@%; Write File or Device%@AE@%%@NL@%
  997.         mov     bx, ax                  %@AB@%; Get number of bytes written%@AE@%%@NL@%
  998.         mov     ax, 0                   %@AB@%; Set error code, preserve carry%@AE@%%@NL@%
  999.         .IF     carry?                   %@AB@%; If carry:%@AE@%%@NL@%
  1000.         inc     ax                      %@AB@%; Increment once for write error%@AE@%%@NL@%
  1001.         .ENDIF  %@AB@%; carry%@AE@%%@NL@%
  1002.         .IF     bx != cx                %@AB@%; If bytes not all written:%@AE@%%@NL@%
  1003.         inc     ax                      %@AB@%; Increment twice%@AE@%%@NL@%
  1004.         .ENDIF  %@AB@%; bx ! cx%@AE@%%@NL@%
  1005.         ret%@NL@%
  1006. %@NL@%
  1007. WriteFile ENDP%@NL@%
  1008. %@NL@%
  1009. %@NL@%
  1010. %@AB@%;* GetDiskSize - Gets size information from specified disk.%@AE@%%@NL@%
  1011. %@AB@%;*%@AE@%%@NL@%
  1012. %@AB@%;* Shows:   DOS Function - 36h (Get Drive Allocation Information)%@AE@%%@NL@%
  1013. %@AB@%;*%@AE@%%@NL@%
  1014. %@AB@%;* Params:  Drive - Drive code (0 = default, 1 = A, 2 = B, etc.)%@AE@%%@NL@%
  1015. %@AB@%;*          Disk  - Pointer to a structure with 4 short integer members:%@AE@%%@NL@%
  1016. %@AB@%;*                      Member 1 - Total clusters on disk%@AE@%%@NL@%
  1017. %@AB@%;*                      Member 2 - Number of available clusters%@AE@%%@NL@%
  1018. %@AB@%;*                      Member 3 - Sectors/cluster (-1 if invalid drive)%@AE@%%@NL@%
  1019. %@AB@%;*                      Member 4 - Bytes/sector%@AE@%%@NL@%
  1020. %@AB@%;*%@AE@%%@NL@%
  1021. %@AB@%;* Return:  None%@AE@%%@NL@%
  1022. %@NL@%
  1023. GetDiskSize PROC USES di,%@NL@%
  1024.         Drive:WORD, Disk:PDISKSTAT%@NL@%
  1025. %@NL@%
  1026.         mov     dx, Drive               %@AB@%; DL = drive code%@AE@%%@NL@%
  1027.         mov     ah, 36h                 %@AB@%; DOS Function 36h%@AE@%%@NL@%
  1028.         int     21h                     %@AB@%; Get Drive Allocation Information%@AE@%%@NL@%
  1029.         LoadPtr es, di, Disk            %@AB@%; ES:DI = disk structure%@AE@%%@NL@%
  1030.         mov     (DISKSTAT PTR es:[di]).\%@NL@%
  1031.                 total, dx               %@AB@%; DX = total clusters%@AE@%%@NL@%
  1032.         mov     (DISKSTAT PTR es:[di]).\%@NL@%
  1033.                 avail, bx               %@AB@%; BX = number of free clusters%@AE@%%@NL@%
  1034.         mov     (DISKSTAT PTR es:[di]).\%@NL@%
  1035.                 sects, ax               %@AB@%; AX = sectors/cluster%@AE@%%@NL@%
  1036.         mov     (DISKSTAT PTR es:[di]).\%@NL@%
  1037.                 bytes, cx               %@AB@%; CX = bytes/sector%@AE@%%@NL@%
  1038.         ret%@NL@%
  1039. %@NL@%
  1040. GetDiskSize ENDP%@NL@%
  1041. %@NL@%
  1042. %@NL@%
  1043. %@AB@%;* MakeDir - Creates a specified subdirectory.%@AE@%%@NL@%
  1044. %@AB@%;*%@AE@%%@NL@%
  1045. %@AB@%;* Shows:   DOS Function - 39h (Create Directory)%@AE@%%@NL@%
  1046. %@AB@%;*%@AE@%%@NL@%
  1047. %@AB@%;* Params:  Pspec - Pointer to ASCIIZ pathname of new subdirectory%@AE@%%@NL@%
  1048. %@AB@%;*%@AE@%%@NL@%
  1049. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1050. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1051. %@AB@%;*          1 if create error%@AE@%%@NL@%
  1052. %@NL@%
  1053. MakeDir PROC USES ds,%@NL@%
  1054.         Pspec:PBYTE%@NL@%
  1055. %@NL@%
  1056.         LoadPtr ds, dx, Pspec           %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
  1057.         mov     ah, 39h                 %@AB@%; DOS Function 39h%@AE@%%@NL@%
  1058.         int     21h                     %@AB@%; Create Directory%@AE@%%@NL@%
  1059.         mov     ax, 0                   %@AB@%; Set error code, keep flags%@AE@%%@NL@%
  1060.         .IF     carry?%@NL@%
  1061.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1062.         .ENDIF%@NL@%
  1063.         ret%@NL@%
  1064. %@NL@%
  1065. MakeDir ENDP%@NL@%
  1066. %@NL@%
  1067. %@NL@%
  1068. %@AB@%;* RemoveDir - Removes a specified subdirectory.%@AE@%%@NL@%
  1069. %@AB@%;*%@AE@%%@NL@%
  1070. %@AB@%;* Shows:   DOS Function - 3Ah (Delete Directory)%@AE@%%@NL@%
  1071. %@AB@%;*%@AE@%%@NL@%
  1072. %@AB@%;* Params:  Pspec - Pointer to ASCIIZ pathname of subdirectory%@AE@%%@NL@%
  1073. %@AB@%;*%@AE@%%@NL@%
  1074. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1075. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1076. %@AB@%;*          1 if delete error or subdirectory not empty%@AE@%%@NL@%
  1077. %@NL@%
  1078. RemoveDir PROC USES ds,%@NL@%
  1079.         Pspec:PBYTE%@NL@%
  1080. %@NL@%
  1081.         LoadPtr ds, dx, Pspec           %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
  1082.         mov     ah, 3Ah                 %@AB@%; DOS Function 3Ah%@AE@%%@NL@%
  1083.         int     21h                     %@AB@%; Delete Directory%@AE@%%@NL@%
  1084.         mov     ax, 0                   %@AB@%; Set error code, keep flags%@AE@%%@NL@%
  1085.         .IF     carry?%@NL@%
  1086.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1087.         .ENDIF%@NL@%
  1088.         ret%@NL@%
  1089. %@NL@%
  1090. RemoveDir ENDP%@NL@%
  1091. %@NL@%
  1092. %@NL@%
  1093. %@AB@%;* ChangeDir - Changes current (default) directory.%@AE@%%@NL@%
  1094. %@AB@%;*%@AE@%%@NL@%
  1095. %@AB@%;* Shows:   DOS Function - 3Bh (Set Current Directory)%@AE@%%@NL@%
  1096. %@AB@%;*%@AE@%%@NL@%
  1097. %@AB@%;* Params:  Pspec - Pointer to ASCIIZ pathname of target subdirectory%@AE@%%@NL@%
  1098. %@AB@%;*%@AE@%%@NL@%
  1099. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1100. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1101. %@AB@%;*          1 if delete error or subdirectory not empty%@AE@%%@NL@%
  1102. %@NL@%
  1103. ChangeDir PROC USES ds,%@NL@%
  1104.         Pspec:PBYTE%@NL@%
  1105. %@NL@%
  1106.         LoadPtr ds, dx, Pspec           %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
  1107.         mov     ah, 3Bh                 %@AB@%; DOS Function 3Bh%@AE@%%@NL@%
  1108.         int     21h                     %@AB@%; Set Current Directory%@AE@%%@NL@%
  1109.         mov     ax, 0                   %@AB@%; Set error code, keep flags%@AE@%%@NL@%
  1110.         .IF     carry?%@NL@%
  1111.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1112.         .ENDIF%@NL@%
  1113.         ret%@NL@%
  1114. %@NL@%
  1115. ChangeDir ENDP%@NL@%
  1116. %@NL@%
  1117. %@NL@%
  1118. %@AB@%;* DelFile - Deletes a specified file.%@AE@%%@NL@%
  1119. %@AB@%;*%@AE@%%@NL@%
  1120. %@AB@%;* Shows:   DOS Function - 41h (Delete File)%@AE@%%@NL@%
  1121. %@AB@%;*%@AE@%%@NL@%
  1122. %@AB@%;* Params:  Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
  1123. %@AB@%;*%@AE@%%@NL@%
  1124. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1125. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1126. %@AB@%;*          1 if delete error%@AE@%%@NL@%
  1127. %@NL@%
  1128. DelFile PROC USES ds,%@NL@%
  1129.         Fspec:PBYTE%@NL@%
  1130. %@NL@%
  1131.         LoadPtr ds, dx, Fspec           %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
  1132.         mov     ah, 41h                 %@AB@%; DOS Function 41h%@AE@%%@NL@%
  1133.         int     21h                     %@AB@%; Delete File%@AE@%%@NL@%
  1134.         mov     ax, 0                   %@AB@%; Set error code, keep flags%@AE@%%@NL@%
  1135.         .IF     carry?%@NL@%
  1136.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1137.         .ENDIF%@NL@%
  1138.         ret%@NL@%
  1139. %@NL@%
  1140. DelFile ENDP%@NL@%
  1141. %@NL@%
  1142. %@NL@%
  1143. %@AB@%;* Rewind - Rewinds an open file, specified by handle. See the GetFileSize%@AE@%%@NL@%
  1144. %@AB@%;* procedure for an example of using Function 42h to determine file size.%@AE@%%@NL@%
  1145. %@AB@%;*%@AE@%%@NL@%
  1146. %@AB@%;* Shows:   DOS Function - 42h (Set File Pointer)%@AE@%%@NL@%
  1147. %@AB@%;*%@AE@%%@NL@%
  1148. %@AB@%;* Params:  Handle - File handle%@AE@%%@NL@%
  1149. %@AB@%;*%@AE@%%@NL@%
  1150. %@AB@%;* Return:  None%@AE@%%@NL@%
  1151. %@NL@%
  1152. Rewind  PROC,%@NL@%
  1153.         Handle:WORD%@NL@%
  1154. %@NL@%
  1155.         mov     bx, Handle              %@AB@%; BX = file handle%@AE@%%@NL@%
  1156.         mov     ax, 4200h               %@AB@%; AH = function #,%@AE@%%@NL@%
  1157.                                         %@AB@%; AL = move to beginning of%@AE@%%@NL@%
  1158.         sub     cx, cx                  %@AB@%;      file plus offset%@AE@%%@NL@%
  1159.         sub     dx, dx                  %@AB@%; CX:DX = offset (zero)%@AE@%%@NL@%
  1160.         int     21h                     %@AB@%; Set File Pointer%@AE@%%@NL@%
  1161.         ret%@NL@%
  1162. %@NL@%
  1163. Rewind  ENDP%@NL@%
  1164. %@NL@%
  1165. %@NL@%
  1166. %@AB@%;* GetFileSize - Gets the size of an open file, specified by handle.%@AE@%%@NL@%
  1167. %@AB@%;*%@AE@%%@NL@%
  1168. %@AB@%;* Shows:   DOS Function - 42h (Set File Pointer)%@AE@%%@NL@%
  1169. %@AB@%;*%@AE@%%@NL@%
  1170. %@AB@%;* Params:  Handle - File handle%@AE@%%@NL@%
  1171. %@AB@%;*%@AE@%%@NL@%
  1172. %@AB@%;* Return:  Long integer with file size in bytes%@AE@%%@NL@%
  1173. %@NL@%
  1174. GetFileSize PROC,%@NL@%
  1175.         Handle:WORD%@NL@%
  1176. %@NL@%
  1177.         mov     bx, Handle              %@AB@%; BX = file handle%@AE@%%@NL@%
  1178.         mov     ax, 4202h               %@AB@%; AH = function #,%@AE@%%@NL@%
  1179.                                         %@AB@%; AL = move to end of%@AE@%%@NL@%
  1180.         sub     cx, cx                  %@AB@%;      file plus offset%@AE@%%@NL@%
  1181.         sub     dx, dx                  %@AB@%; CX:DX = offset (zero)%@AE@%%@NL@%
  1182.         int     21h                     %@AB@%; Set File Pointer%@AE@%%@NL@%
  1183.         mov     ax, dx                  %@AB@%; Set DX:AX = file size in%@AE@%%@NL@%
  1184.         mov     dx, cx                  %@AB@%;   bytes, return long int%@AE@%%@NL@%
  1185.         ret%@NL@%
  1186. %@NL@%
  1187. GetFileSize ENDP%@NL@%
  1188. %@NL@%
  1189. %@NL@%
  1190. %@AB@%;* GetAttribute - Gets the attribute(s) of a specified file.%@AE@%%@NL@%
  1191. %@AB@%;*%@AE@%%@NL@%
  1192. %@AB@%;* Shows:   DOS Function - 43h (Get or Set File Attributes)%@AE@%%@NL@%
  1193. %@AB@%;*%@AE@%%@NL@%
  1194. %@AB@%;* Params:  Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
  1195. %@AB@%;*%@AE@%%@NL@%
  1196. %@AB@%;* Return:  Short integer with file attribute bits set as follows:%@AE@%%@NL@%
  1197. %@AB@%;*                bit 0 = read-only              bit 3 = volume label%@AE@%%@NL@%
  1198. %@AB@%;*                bit 1 = hidden                 bit 4 = subdirectory%@AE@%%@NL@%
  1199. %@AB@%;*                bit 2 = system                 bit 5 = archive%@AE@%%@NL@%
  1200. %@AB@%;*          0 indicates normal data file%@AE@%%@NL@%
  1201. %@AB@%;*          -1 indicates error%@AE@%%@NL@%
  1202. %@NL@%
  1203. GetAttribute PROC USES ds,%@NL@%
  1204.         Fspec:PBYTE%@NL@%
  1205. %@NL@%
  1206.         LoadPtr ds, dx, Fspec           %@AB@%; DS:DX = file specification%@AE@%%@NL@%
  1207.         mov     ax, 4300h               %@AB@%; AH = function #%@AE@%%@NL@%
  1208.                                         %@AB@%; AL = 0 (return attribute)%@AE@%%@NL@%
  1209.         int     21h                     %@AB@%; Get File Attributes%@AE@%%@NL@%
  1210.         mov     ax, -1                  %@AB@%; Set code, keep flags%@AE@%%@NL@%
  1211.         .IF     !carry?%@NL@%
  1212.         mov     ax, cx                  %@AB@%; Return with file attribute bits%@AE@%%@NL@%
  1213.         .ENDIF%@NL@%
  1214.         ret%@NL@%
  1215. %@NL@%
  1216. GetAttribute ENDP%@NL@%
  1217. %@NL@%
  1218. %@NL@%
  1219. %@AB@%;* SetAttribute - Sets the attribute(s) of a specified file.%@AE@%%@NL@%
  1220. %@AB@%;*%@AE@%%@NL@%
  1221. %@AB@%;* Shows:   DOS Function - 43h (Get or Set File Attributes)%@AE@%%@NL@%
  1222. %@AB@%;*%@AE@%%@NL@%
  1223. %@AB@%;* Params:  Attr - Attribute bits set as follows:%@AE@%%@NL@%
  1224. %@AB@%;*                        bit 0 = read-only      bit 3 = volume label%@AE@%%@NL@%
  1225. %@AB@%;*                        bit 1 = hidden                 bit 4 = subdirectory%@AE@%%@NL@%
  1226. %@AB@%;*                        bit 2 = system                 bit 5 = archive%@AE@%%@NL@%
  1227. %@AB@%;*                 (Attr = 0 for normal data file)%@AE@%%@NL@%
  1228. %@AB@%;*          Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
  1229. %@AB@%;*%@AE@%%@NL@%
  1230. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1231. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1232. %@AB@%;*          1 if delete error%@AE@%%@NL@%
  1233. %@NL@%
  1234. SetAttribute PROC USES ds,%@NL@%
  1235.         Attr:WORD,%@NL@%
  1236.         Fspec:PBYTE%@NL@%
  1237. %@NL@%
  1238.         LoadPtr ds, dx, Fspec           %@AB@%; DS:DX = file specification%@AE@%%@NL@%
  1239.         mov     cx, Attr                %@AB@%; Put attribute code in CX%@AE@%%@NL@%
  1240.         mov     ax, 4301h               %@AB@%; AH = function #%@AE@%%@NL@%
  1241.                                         %@AB@%; AL = 1 (set attribute)%@AE@%%@NL@%
  1242.         int     21h                     %@AB@%; Set File Attributes%@AE@%%@NL@%
  1243.         mov     ax, 0                   %@AB@%; Clear code, keep flags%@AE@%%@NL@%
  1244.         .IF     carry?%@NL@%
  1245.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1246.         .ENDIF%@NL@%
  1247.         ret%@NL@%
  1248. %@NL@%
  1249. SetAttribute ENDP%@NL@%
  1250. %@NL@%
  1251. %@NL@%
  1252. %@AB@%;* GetCurDir - Gets the current directory of default drive.%@AE@%%@NL@%
  1253. %@AB@%;*%@AE@%%@NL@%
  1254. %@AB@%;* Shows:   DOS Function - 47h (Get Current Directory)%@AE@%%@NL@%
  1255. %@AB@%;*%@AE@%%@NL@%
  1256. %@AB@%;* Params:  Spec - Pointer to 64-byte buffer to receive directory%@AE@%%@NL@%
  1257. %@AB@%;*          path. Path terminates with 0 but does not include%@AE@%%@NL@%
  1258. %@AB@%;*          drive and does not begin with backslash.%@AE@%%@NL@%
  1259. %@AB@%;*%@AE@%%@NL@%
  1260. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1261. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1262. %@AB@%;*          1 if delete error or subdirectory not empty%@AE@%%@NL@%
  1263. %@NL@%
  1264. GetCurDir PROC USES ds si,%@NL@%
  1265.         Spec:PBYTE%@NL@%
  1266. %@NL@%
  1267.         LoadPtr ds, si, Spec            %@AB@%; DS:SI = spec address%@AE@%%@NL@%
  1268.         mov     ah, 47h                 %@AB@%; AH = function number%@AE@%%@NL@%
  1269.         sub     dl, dl                  %@AB@%; DL = current drive (0)%@AE@%%@NL@%
  1270.         int     21h                     %@AB@%; Get Current Directory%@AE@%%@NL@%
  1271.         mov     ax, 0                   %@AB@%; Set error code, keep flags%@AE@%%@NL@%
  1272.         .IF     carry?%@NL@%
  1273.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1274.         .ENDIF%@NL@%
  1275.         ret%@NL@%
  1276. %@NL@%
  1277. GetCurDir ENDP%@NL@%
  1278. %@NL@%
  1279. %@NL@%
  1280. %@AB@%;* FindFirst - Finds first entry in given directory matching specification.%@AE@%%@NL@%
  1281. %@AB@%;*%@AE@%%@NL@%
  1282. %@AB@%;* Shows:   DOS Function - 4Eh (Find First File)%@AE@%%@NL@%
  1283. %@AB@%;*          Instructions - pushf    popf%@AE@%%@NL@%
  1284. %@AB@%;*%@AE@%%@NL@%
  1285. %@AB@%;* Params:  Attr - Attribute code (see header comments for CreateFile)%@AE@%%@NL@%
  1286. %@AB@%;*          Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
  1287. %@AB@%;*          Finfo - Pointer to 43-byte buffer to receive%@AE@%%@NL@%
  1288. %@AB@%;*                      data from matched entry%@AE@%%@NL@%
  1289. %@AB@%;*%@AE@%%@NL@%
  1290. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1291. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1292. %@AB@%;*          1 if no match found%@AE@%%@NL@%
  1293. %@NL@%
  1294.         .DATA%@NL@%
  1295. OldDta  FPVOID  ?                       %@AB@%; Storage for old DTA address%@AE@%%@NL@%
  1296. %@NL@%
  1297.         .CODE%@NL@%
  1298. %@NL@%
  1299. FindFirst PROC USES ds,%@NL@%
  1300.         Attr:WORD,%@NL@%
  1301.         Fspec:PBYTE,%@NL@%
  1302.         Finfo:PFILEINFO%@NL@%
  1303. %@NL@%
  1304.         %@AB@%; Get current DTA address, pass address of pointer to hold value%@AE@%%@NL@%
  1305.         INVOKE  GetDTA,%@NL@%
  1306.                 ADDR OldDta%@NL@%
  1307. %@NL@%
  1308.         mov     cx, Attr                %@AB@%; Load CX with file attribute%@AE@%%@NL@%
  1309. %@NL@%
  1310.         %@AB@%; Set DTA address, pass pointer to structure%@AE@%%@NL@%
  1311.         INVOKE  SetDTA,%@NL@%
  1312.                 Finfo%@NL@%
  1313. %@NL@%
  1314.         LoadPtr ds, dx, Fspec           %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
  1315.         mov     ah, 4Eh                 %@AB@%; AH = function number%@AE@%%@NL@%
  1316.         int     21h                     %@AB@%; Find First File%@AE@%%@NL@%
  1317. %@NL@%
  1318.         pushf                           %@AB@%; Preserve flags%@AE@%%@NL@%
  1319. %@NL@%
  1320.         %@AB@%; Restore DTA address, pass pointer%@AE@%%@NL@%
  1321.         INVOKE  SetDTA,%@NL@%
  1322.                 OldDta%@NL@%
  1323. %@NL@%
  1324.         sub     ax, ax                  %@AB@%; Set error code%@AE@%%@NL@%
  1325.         popf                            %@AB@%; Recover flags%@AE@%%@NL@%
  1326.         .IF     carry?%@NL@%
  1327.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1328.         .ENDIF%@NL@%
  1329.         ret%@NL@%
  1330. %@NL@%
  1331. FindFirst ENDP%@NL@%
  1332. %@NL@%
  1333. %@NL@%
  1334. %@AB@%;* FindNext - Finds next entry in given directory matching specification.%@AE@%%@NL@%
  1335. %@AB@%;* (Should be called only after successfully calling the FindFirst procedure.)%@AE@%%@NL@%
  1336. %@AB@%;*%@AE@%%@NL@%
  1337. %@AB@%;* Shows:   DOS Function - 4Fh (Find Next File)%@AE@%%@NL@%
  1338. %@AB@%;*          Operator - OFFSET%@AE@%%@NL@%
  1339. %@AB@%;*%@AE@%%@NL@%
  1340. %@AB@%;* Params:  Finfo - Pointer to 43-byte buffer. This must be the same buffer%@AE@%%@NL@%
  1341. %@AB@%;*                      (or a duplicate) returned from the FindFirst procedure.%@AE@%%@NL@%
  1342. %@AB@%;*%@AE@%%@NL@%
  1343. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1344. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1345. %@AB@%;*          1 if no more matches found%@AE@%%@NL@%
  1346. %@NL@%
  1347. FindNext PROC USES ds,%@NL@%
  1348.         Finfo:PFILEINFO%@NL@%
  1349. %@NL@%
  1350.         %@AB@%; Get current DTA address, pass address of pointer to hold value%@AE@%%@NL@%
  1351.         INVOKE  GetDTA,%@NL@%
  1352.                 ADDR OldDta%@NL@%
  1353. %@NL@%
  1354.         %@AB@%; Set DTA address, pass pointer to structure%@AE@%%@NL@%
  1355.         INVOKE  SetDTA,%@NL@%
  1356.                 Finfo%@NL@%
  1357. %@NL@%
  1358.         mov     ah, 4Fh                 %@AB@%; AH = function number%@AE@%%@NL@%
  1359.         int     21h                     %@AB@%; Find Next File%@AE@%%@NL@%
  1360. %@NL@%
  1361.         pushf                           %@AB@%; Preserve flags%@AE@%%@NL@%
  1362. %@NL@%
  1363.         %@AB@%; Restore DTA address, pass pointer%@AE@%%@NL@%
  1364.         INVOKE  SetDTA,%@NL@%
  1365.                 OldDta%@NL@%
  1366. %@NL@%
  1367.         sub     ax, ax                  %@AB@%; Set error code%@AE@%%@NL@%
  1368.         popf                            %@AB@%; Recover flags%@AE@%%@NL@%
  1369.         .IF     carry?%@NL@%
  1370.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1371.         .ENDIF%@NL@%
  1372.         ret%@NL@%
  1373. %@NL@%
  1374. FindNext ENDP%@NL@%
  1375. %@NL@%
  1376. %@NL@%
  1377. %@AB@%;* RenameFile - Renames specified file.%@AE@%%@NL@%
  1378. %@AB@%;*%@AE@%%@NL@%
  1379. %@AB@%;* Shows:   DOS Function - 56h (Rename File)%@AE@%%@NL@%
  1380. %@AB@%;*%@AE@%%@NL@%
  1381. %@AB@%;* Params:  Fspec1 - Pointer to old ASCIIZ file specification%@AE@%%@NL@%
  1382. %@AB@%;*          Fspec2 - Pointer to new ASCIIZ file specification%@AE@%%@NL@%
  1383. %@AB@%;*%@AE@%%@NL@%
  1384. %@AB@%;*          The drive must be the same for both arguments, but the path%@AE@%%@NL@%
  1385. %@AB@%;*          does not. This allows files to be moved between directories.%@AE@%%@NL@%
  1386. %@AB@%;*%@AE@%%@NL@%
  1387. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1388. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1389. %@AB@%;*          1 if error%@AE@%%@NL@%
  1390. %@NL@%
  1391. RenameFile PROC USES ds di,%@NL@%
  1392.         Fspec1:PBYTE,%@NL@%
  1393.         Fspec2:PBYTE%@NL@%
  1394. %@NL@%
  1395.         LoadPtr ds, dx, Fspec1          %@AB@%; Point DS:DX to old file spec%@AE@%%@NL@%
  1396.         LoadPtr es, di, Fspec2          %@AB@%; Point ES:DI to new file spec%@AE@%%@NL@%
  1397.         mov     ah, 56h                 %@AB@%; AH = function number%@AE@%%@NL@%
  1398.         int     21h                     %@AB@%; Rename File%@AE@%%@NL@%
  1399.         mov     ax, 0                   %@AB@%; Clear error code, keep flags%@AE@%%@NL@%
  1400.         .IF     carry?%@NL@%
  1401.         inc     ax                      %@AB@%; Set error code to 1%@AE@%%@NL@%
  1402.         .ENDIF%@NL@%
  1403.         ret%@NL@%
  1404. %@NL@%
  1405. RenameFile ENDP%@NL@%
  1406. %@NL@%
  1407. %@NL@%
  1408. %@AB@%;* GetFileTime - Gets date/time for open file specified by handle.%@AE@%%@NL@%
  1409. %@AB@%;*%@AE@%%@NL@%
  1410. %@AB@%;* Shows:   DOS Function - 57h (Get or Set File Date and Time)%@AE@%%@NL@%
  1411. %@AB@%;*          Instructions - shl     shr%@AE@%%@NL@%
  1412. %@AB@%;*%@AE@%%@NL@%
  1413. %@AB@%;* Params:  Handle - Handle of open file%@AE@%%@NL@%
  1414. %@AB@%;*          Sptr - Pointer to 18-byte buffer to receive date/time%@AE@%%@NL@%
  1415. %@AB@%;*%@AE@%%@NL@%
  1416. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  1417. %@AB@%;*          0 if successful%@AE@%%@NL@%
  1418. %@AB@%;*          1 if error%@AE@%%@NL@%
  1419. %@NL@%
  1420. GetFileTime PROC USES di,%@NL@%
  1421.         Handle:WORD,%@NL@%
  1422.         Sptr:PBYTE%@NL@%
  1423. %@NL@%
  1424.         mov     ax, 5700h               %@AB@%; AH = function number%@AE@%%@NL@%
  1425.                                         %@AB@%; AL = get request%@AE@%%@NL@%
  1426.         mov     bx, Handle              %@AB@%; BX = file handle%@AE@%%@NL@%
  1427.         int     21h                     %@AB@%; Get File Date and Time%@AE@%%@NL@%
  1428.         mov     ax, 1                   %@AB@%; Set error code, keep flags%@AE@%%@NL@%
  1429.         .IF     !carry?                 %@AB@%; If not carry, continue%@AE@%%@NL@%
  1430.         mov     bx, cx                  %@AB@%; Else save time in BX%@AE@%%@NL@%
  1431.         mov     al, bl                  %@AB@%; Get low byte of time%@AE@%%@NL@%
  1432.         and     al, 00011111y           %@AB@%; Mask to get 2-second incrs,%@AE@%%@NL@%
  1433.         shl     al, 1                   %@AB@%;   convert to seconds%@AE@%%@NL@%
  1434.         push    ax                      %@AB@%; Save seconds%@AE@%%@NL@%
  1435.         mov     cl, 5%@NL@%
  1436.         shr     bx, cl                  %@AB@%; Shift minutes into low byte%@AE@%%@NL@%
  1437.         mov     al, bl                  %@AB@%; Get new low byte%@AE@%%@NL@%
  1438.         and     al, 00111111y           %@AB@%; Mask to get minutes%@AE@%%@NL@%
  1439.         push    ax                      %@AB@%; Save minutes%@AE@%%@NL@%
  1440.         mov     cl, 6%@NL@%
  1441.         shr     bx, cl                  %@AB@%; Shift hours into low byte%@AE@%%@NL@%
  1442.         push    bx                      %@AB@%; Save hours%@AE@%%@NL@%
  1443. %@NL@%
  1444.         mov     bl, dl                  %@AB@%; Get low byte of date%@AE@%%@NL@%
  1445.         and     bl, 00011111y           %@AB@%; Mask to get day in BX%@AE@%%@NL@%
  1446.         mov     cl, 5%@NL@%
  1447.         shr     dx, cl                  %@AB@%; Shift month into low byte%@AE@%%@NL@%
  1448.         mov     al, dl                  %@AB@%; Get new low byte%@AE@%%@NL@%
  1449.         and     al, 00001111y           %@AB@%; Mask to get month%@AE@%%@NL@%
  1450.         mov     cl, 4%@NL@%
  1451.         shr     dx, cl                  %@AB@%; Shift year into low byte%@AE@%%@NL@%
  1452.         add     dx, 80                  %@AB@%; Year is relative to 1980%@AE@%%@NL@%
  1453.         push    dx                      %@AB@%; Save year%@AE@%%@NL@%
  1454.         push    bx                      %@AB@%; Save day%@AE@%%@NL@%
  1455.         push    ax                      %@AB@%; Save month%@AE@%%@NL@%
  1456. %@NL@%
  1457.         LoadPtr es, di, Sptr            %@AB@%; Point ES:DI to 18-byte%@AE@%%@NL@%
  1458.         mov     cx, 6                   %@AB@%;   string%@AE@%%@NL@%
  1459. %@NL@%
  1460.         .REPEAT%@NL@%
  1461.         pop     ax                      %@AB@%; Get 6 numbers sequentially in AL%@AE@%%@NL@%
  1462.         aam                             %@AB@%; Convert to unpacked BCD%@AE@%%@NL@%
  1463.         xchg    al, ah                  %@AB@%; Switch bytes for word move%@AE@%%@NL@%
  1464.         or      ax, '00'                %@AB@%; Make ASCII numerals%@AE@%%@NL@%
  1465.         stosw                           %@AB@%; Copy to string%@AE@%%@NL@%
  1466.         mov     al, '-'                 %@AB@%; Separator for date text%@AE@%%@NL@%
  1467.         cmp     cl, 4                   %@AB@%; First 3 iters are for date%@AE@%%@NL@%
  1468.         jg      @F                      %@AB@%; If CX=6 or 5, insert hyphen%@AE@%%@NL@%
  1469.         mov     al, ' '                 %@AB@%; Separator date and time%@AE@%%@NL@%
  1470.         je      @F                      %@AB@%; If CX = 4, insert hyphen%@AE@%%@NL@%
  1471.         mov     al, ':'                 %@AB@%; Separator for time text%@AE@%%@NL@%
  1472.         .IF     cl != 1%@NL@%
  1473. @@:     stosb                           %@AB@%; Copy separator to string%@AE@%%@NL@%
  1474.         .ENDIF%@NL@%
  1475.         .UNTILCXZ%@NL@%
  1476. %@NL@%
  1477.         sub     ax, ax                  %@AB@%; Clear return code%@AE@%%@NL@%
  1478.         stosb                           %@AB@%; Terminate string with null%@AE@%%@NL@%
  1479.         .ENDIF                          %@AB@%;   to make ASCIIZ%@AE@%%@NL@%
  1480.         ret%@NL@%
  1481. %@NL@%
  1482. GetFileTime ENDP%@NL@%
  1483. %@NL@%
  1484. %@NL@%
  1485. %@AB@%;* UniqueFile - Creates and opens a new file with a name unique to the%@AE@%%@NL@%
  1486. %@AB@%;* specified directory. The name is manufactured from the current time,%@AE@%%@NL@%
  1487. %@AB@%;* making it useful for temporary files. For DOS versions 3.0 and higher.%@AE@%%@NL@%
  1488. %@AB@%;*%@AE@%%@NL@%
  1489. %@AB@%;* Shows:   DOS Function - 5Ah (Create Temporary File)%@AE@%%@NL@%
  1490. %@AB@%;*%@AE@%%@NL@%
  1491. %@AB@%;* Params:  Attr - Attribute code (see header comments for CreateFile)%@AE@%%@NL@%
  1492. %@AB@%;*          Pspec - Pointer to ASCIIZ path specification%@AE@%%@NL@%
  1493. %@AB@%;*%@AE@%%@NL@%
  1494. %@AB@%;* Return:  Short integer with file handle or -1 for error%@AE@%%@NL@%
  1495. %@NL@%
  1496. UniqueFile PROC USES ds,%@NL@%
  1497.         Attr:WORD,%@NL@%
  1498.         Pspec:PBYTE%@NL@%
  1499. %@NL@%
  1500.         %@AB@%; Get DOS version%@AE@%%@NL@%
  1501.         INVOKE  GetVer%@NL@%
  1502. %@NL@%
  1503.         cmp     ax, 300                 %@AB@%; 3.0 or higher?%@AE@%%@NL@%
  1504.         jb      e_exit                  %@AB@%; No?  Quit with error%@AE@%%@NL@%
  1505.         LoadPtr ds, dx, Pspec           %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
  1506.         mov     cx, Attr                %@AB@%; CX = attribute%@AE@%%@NL@%
  1507.         mov     ah, 5Ah                 %@AB@%; AH = function number%@AE@%%@NL@%
  1508.         int     21h                     %@AB@%; Create Temporary File%@AE@%%@NL@%
  1509.         .IF     carry?%@NL@%
  1510. e_exit: mov     ax, -1                  %@AB@%; Set error code%@AE@%%@NL@%
  1511.         .ENDIF%@NL@%
  1512.         ret%@NL@%
  1513. %@NL@%
  1514. UniqueFile ENDP%@NL@%
  1515. %@NL@%
  1516. %@NL@%
  1517. %@AB@%;* CreateNewFile - Creates a new file with specified attribute. Differs%@AE@%%@NL@%
  1518. %@AB@%;* from the CreateFile procedure in that it returns an error if file%@AE@%%@NL@%
  1519. %@AB@%;* already exists. For DOS versions 3.0 and higher.%@AE@%%@NL@%
  1520. %@AB@%;*%@AE@%%@NL@%
  1521. %@AB@%;* Shows:   DOS Function - 5Bh (Create New File)%@AE@%%@NL@%
  1522. %@AB@%;*%@AE@%%@NL@%
  1523. %@AB@%;* Params:  Attr - Attribute code (see header comments for CreateFile)%@AE@%%@NL@%
  1524. %@AB@%;*          Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
  1525. %@AB@%;*%@AE@%%@NL@%
  1526. %@AB@%;* Return:  Short integer with file handle or -1 for error%@AE@%%@NL@%
  1527. %@NL@%
  1528. CreateNewFile PROC USES ds,%@NL@%
  1529.         Attr:WORD,%@NL@%
  1530.         Fspec:PBYTE%@NL@%
  1531. %@NL@%
  1532.         LoadPtr ds, dx, Fspec           %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
  1533.         mov     cx, Attr                %@AB@%; CX = attribute%@AE@%%@NL@%
  1534.         mov     ah, 5Bh                 %@AB@%; AH = function number%@AE@%%@NL@%
  1535.         int     21h                     %@AB@%; Create New File%@AE@%%@NL@%
  1536.         .IF     carry?%@NL@%
  1537.         mov     ax, -1                  %@AB@%; Set error code%@AE@%%@NL@%
  1538.         .ENDIF%@NL@%
  1539.         ret%@NL@%
  1540. %@NL@%
  1541. CreateNewFile ENDP%@NL@%
  1542. %@NL@%
  1543. %@NL@%
  1544. %@AB@%;* StrCompare - Compares two strings for equality. See StrWrite, StrFindChar,%@AE@%%@NL@%
  1545. %@AB@%;* WinOpen, and WinClose procedures for other examples of string instructions.%@AE@%%@NL@%
  1546. %@AB@%;*%@AE@%%@NL@%
  1547. %@AB@%;* Shows:   Instructions - cmpsb     cmpsw     repe     jcxz%@AE@%%@NL@%
  1548. %@AB@%;*%@AE@%%@NL@%
  1549. %@AB@%;* Params:  Sptr1 - Pointer to first string%@AE@%%@NL@%
  1550. %@AB@%;*          Sptr2 - Pointer to second string%@AE@%%@NL@%
  1551. %@AB@%;*          Len  - Length in bytes for comparison. Strings need not be of%@AE@%%@NL@%
  1552. %@AB@%;*                 equal length; however if len is an even number, comparison%@AE@%%@NL@%
  1553. %@AB@%;*                 is made on a word-by-word basis and thus is more efficient.%@AE@%%@NL@%
  1554. %@AB@%;*%@AE@%%@NL@%
  1555. %@AB@%;* Return:  Null pointer if strings match; else pointer to string #1 where%@AE@%%@NL@%
  1556. %@AB@%;*          match failed.%@AE@%%@NL@%
  1557. %@NL@%
  1558. StrCompare PROC USES ds di si,%@NL@%
  1559.         Sptr1:PBYTE,%@NL@%
  1560.         Sptr2:PBYTE,%@NL@%
  1561.         Len:WORD%@NL@%
  1562. %@NL@%
  1563.         LoadPtr es, di, Sptr1           %@AB@%; ES:DI points to string #1%@AE@%%@NL@%
  1564.         LoadPtr ds, si, Sptr2           %@AB@%; DS:SI points to string #2%@AE@%%@NL@%
  1565.         mov     cx, Len                 %@AB@%; Length of search in bytes%@AE@%%@NL@%
  1566.         and     al, 0                   %@AB@%; Set ZR flag in case CX = 0%@AE@%%@NL@%
  1567.         .IF     cx != 0                 %@AB@%; If length is not 0:%@AE@%%@NL@%
  1568.         .IF     !(cl & 1)               %@AB@%; If not even number:%@AE@%%@NL@%
  1569.         repe    cmpsb                   %@AB@%; Compare byte-by-byte%@AE@%%@NL@%
  1570.         .ELSE                           %@AB@%; Else compare word-by-word%@AE@%%@NL@%
  1571.         shr     cx, 1                   %@AB@%; Decrease count by half%@AE@%%@NL@%
  1572.         repe    cmpsw                   %@AB@%; Compare word-by-word%@AE@%%@NL@%
  1573.         sub     di, 2                   %@AB@%; Back up 2 characters%@AE@%%@NL@%
  1574.         sub     si, 2%@NL@%
  1575.         cmpsb                           %@AB@%; Match?%@AE@%%@NL@%
  1576.         .IF     zero?                   %@AB@%; No?  Then failure%@AE@%%@NL@%
  1577.         cmpsb                           %@AB@%; Compare last characters%@AE@%%@NL@%
  1578.         .ENDIF  %@AB@%; zero%@AE@%%@NL@%
  1579.         .ENDIF  %@AB@%; cl & 1%@AE@%%@NL@%
  1580.         .ENDIF  %@AB@%; cx != 0%@AE@%%@NL@%
  1581. %@NL@%
  1582.         mov     ax, 0                   %@AB@%; Set null pointer without%@AE@%%@NL@%
  1583.         mov     dx, 0                   %@AB@%;   disturbing flags%@AE@%%@NL@%
  1584.         .IF     !zero?                  %@AB@%; If no match:%@AE@%%@NL@%
  1585.         dec     di                      %@AB@%; Point to failure%@AE@%%@NL@%
  1586.         mov     ax, di%@NL@%
  1587.         mov     dx, es%@NL@%
  1588.         .ENDIF%@NL@%
  1589.         ret%@NL@%
  1590. %@NL@%
  1591. StrCompare ENDP%@NL@%
  1592. %@NL@%
  1593. %@NL@%
  1594. %@AB@%;* StrFindChar - Finds first occurence of character in given ASCIIZ string,%@AE@%%@NL@%
  1595. %@AB@%;* searching either from beginning or end of string. See StrWrite, WinOpen,%@AE@%%@NL@%
  1596. %@AB@%;* WinClose, and StrCompare procedures for other examples of string%@AE@%%@NL@%
  1597. %@AB@%;* instructions.%@AE@%%@NL@%
  1598. %@AB@%;*%@AE@%%@NL@%
  1599. %@AB@%;* Shows:   Instructions - repne     scasb    cld     std%@AE@%%@NL@%
  1600. %@AB@%;*%@AE@%%@NL@%
  1601. %@AB@%;* Params:  Ichar - Character to search for%@AE@%%@NL@%
  1602. %@AB@%;*          Sptr - Pointer to ASCIIZ string in which to search%@AE@%%@NL@%
  1603. %@AB@%;*          Direct - Direction flag:%@AE@%%@NL@%
  1604. %@AB@%;*                       0 = search from start to end%@AE@%%@NL@%
  1605. %@AB@%;*                       1 = search from end to start%@AE@%%@NL@%
  1606. %@AB@%;*%@AE@%%@NL@%
  1607. %@AB@%;* Return:  Null pointer if character not found, else pointer to string where%@AE@%%@NL@%
  1608. %@AB@%;*          character first encountered%@AE@%%@NL@%
  1609. %@NL@%
  1610. StrFindChar PROC USES ds di si,%@NL@%
  1611.         IChar:SBYTE,%@NL@%
  1612.         Sptr:PBYTE,%@NL@%
  1613.         Direct:WORD%@NL@%
  1614. %@NL@%
  1615.         LoadPtr es, di, Sptr            %@AB@%; ES:DI points to string%@AE@%%@NL@%
  1616.         LoadPtr ds, si, Sptr            %@AB@%;   as does DS:SI%@AE@%%@NL@%
  1617.         mov     cx, -1                  %@AB@%; Set scan counter to maximum%@AE@%%@NL@%
  1618.         mov     bx, cx                  %@AB@%; BX = max string tail%@AE@%%@NL@%
  1619.         cld                             %@AB@%; Assume head-to-tail search%@AE@%%@NL@%
  1620. %@NL@%
  1621.         .IF     Direct != 0             %@AB@%; If assumption correct:%@AE@%%@NL@%
  1622.         mov     bx, di                  %@AB@%; Set BX to byte before%@AE@%%@NL@%
  1623.         dec     bx                      %@AB@%;   string head and scan%@AE@%%@NL@%
  1624.         sub     al, al                  %@AB@%;   string for null terminator%@AE@%%@NL@%
  1625.         push    cx                      %@AB@%;   to find string tail%@AE@%%@NL@%
  1626.         repne   scasb%@NL@%
  1627.         pop     cx                      %@AB@%; Recover scan counter%@AE@%%@NL@%
  1628.         dec     di                      %@AB@%; Backup pointer to last%@AE@%%@NL@%
  1629.         dec     di                      %@AB@%;   character in string and%@AE@%%@NL@%
  1630.         mov     si, di                  %@AB@%;   begin search from there%@AE@%%@NL@%
  1631.         std                             %@AB@%; Set direction flag%@AE@%%@NL@%
  1632.         .ENDIF%@NL@%
  1633. %@NL@%
  1634.         .REPEAT%@NL@%
  1635.         lodsb                           %@AB@%; Get first char from string%@AE@%%@NL@%
  1636.         .IF     (si == bx) || (al == 0) %@AB@%; If at head or tail limit:%@AE@%%@NL@%
  1637.         sub     ax, ax                  %@AB@%; No match%@AE@%%@NL@%
  1638.         sub     dx, dx                  %@AB@%; Set null pointer%@AE@%%@NL@%
  1639.         jmp     exit%@NL@%
  1640.         .ENDIF%@NL@%
  1641.         .UNTILCXZ al == IChar%@NL@%
  1642. %@NL@%
  1643.         mov     ax, si                  %@AB@%; Match, so point to first%@AE@%%@NL@%
  1644.         dec     ax                      %@AB@%;   occurence%@AE@%%@NL@%
  1645.         .IF     Direct != 0             %@AB@%; If head-to-tail search:%@AE@%%@NL@%
  1646.         inc     ax                      %@AB@%; Adjust pointer forward%@AE@%%@NL@%
  1647.         inc     ax%@NL@%
  1648.         mov     dx, ds                  %@AB@%; Pointer segment%@AE@%%@NL@%
  1649.         .ENDIF%@NL@%
  1650. exit:%@NL@%
  1651.         ret%@NL@%
  1652. %@NL@%
  1653. StrFindChar ENDP%@NL@%
  1654. %@NL@%
  1655. %@NL@%
  1656. %@AB@%;* GetStr - Gets a string of up to 128 characters from the user. Since%@AE@%%@NL@%
  1657. %@AB@%;* this function uses the DOS input mechanism, it can use the DOS editing%@AE@%%@NL@%
  1658. %@AB@%;* keys or the keys of a DOS command-line editor if one is loaded.%@AE@%%@NL@%
  1659. %@AB@%;*%@AE@%%@NL@%
  1660. %@AB@%;* Shows:   DOS Function - 0Ah (Buffered Keyboard Input)%@AE@%%@NL@%
  1661. %@AB@%;*          Directive    - EQU%@AE@%%@NL@%
  1662. %@AB@%;*%@AE@%%@NL@%
  1663. %@AB@%;* Params:  Strbuf - Pointer to area where input string will be placed%@AE@%%@NL@%
  1664. %@AB@%;*          Maxlen - Maximum length (up to 128 characters) of string%@AE@%%@NL@%
  1665. %@AB@%;*%@AE@%%@NL@%
  1666. %@AB@%;* Return:  0 if successful, 1 if error (Maxlen is too long)%@AE@%%@NL@%
  1667. %@NL@%
  1668.         .DATA%@NL@%
  1669. MAXSTR  EQU     128%@NL@%
  1670. max     BYTE    MAXSTR%@NL@%
  1671. actual  BYTE    ?%@NL@%
  1672. string  BYTE    MAXSTR DUP (?)%@NL@%
  1673. %@NL@%
  1674.         .CODE%@NL@%
  1675. GetStr  PROC USES si di,%@NL@%
  1676.         Strbuf:PBYTE,%@NL@%
  1677.         Maxlen:WORD%@NL@%
  1678. %@NL@%
  1679.         mov     ax, 1                   %@AB@%; Assume error%@AE@%%@NL@%
  1680.         mov     cx, Maxlen              %@AB@%; Copy length to register%@AE@%%@NL@%
  1681. %@NL@%
  1682.         .IF (cx != 0) && (cx <= MAXSTR) %@AB@%; Error if 0 or too long%@AE@%%@NL@%
  1683.         mov     max, cl                 %@AB@%; Load maximum length%@AE@%%@NL@%
  1684.         mov     ah, 0Ah                 %@AB@%; Request DOS Function 0Ah%@AE@%%@NL@%
  1685.         mov     dx, OFFSET max          %@AB@%; Load offset of string%@AE@%%@NL@%
  1686.         int     21h                     %@AB@%; Buffered Keyboard Input%@AE@%%@NL@%
  1687. %@NL@%
  1688.         mov     bl, actual              %@AB@%; Put number of characters read%@AE@%%@NL@%
  1689.         sub     bh, bh                  %@AB@%;   in BX%@AE@%%@NL@%
  1690.         mov     string[bx], 0           %@AB@%; Null-terminate string%@AE@%%@NL@%
  1691.         mov     cx, bx                  %@AB@%; Put count in CX%@AE@%%@NL@%
  1692.         inc     cx                      %@AB@%; Plus one for the null terminator%@AE@%%@NL@%
  1693. %@NL@%
  1694.         LoadPtr es, di, Strbuf          %@AB@%; ES:DI points to destination buffer%@AE@%%@NL@%
  1695.         mov     si, OFFSET string       %@AB@%; DS:SI points to source string%@AE@%%@NL@%
  1696.         rep     movsb                   %@AB@%; Copy source to destination%@AE@%%@NL@%
  1697.         sub     ax, ax                  %@AB@%; Return 0 for success%@AE@%%@NL@%
  1698.         .ENDIF%@NL@%
  1699. %@NL@%
  1700.         ret%@NL@%
  1701. %@NL@%
  1702. GetStr  ENDP%@NL@%
  1703. %@NL@%
  1704.         END%@NL@%
  1705. %@NL@%
  1706. %@NL@%
  1707. %@2@%%@AH@%FORTRAN.ASM%@AE@%%@EH@%%@NL@%
  1708. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\MIXED\FORTRAN.ASM%@AE@%%@NL@%
  1709. %@NL@%
  1710. %@AB@%; Power2 routine called by FMAIN.FOR%@AE@%%@NL@%
  1711. %@AB@%; Assemble with ML /c FORTRAN.ASM%@AE@%%@NL@%
  1712. %@NL@%
  1713.         .MODEL LARGE, FORTRAN%@NL@%
  1714. %@NL@%
  1715. Power2  PROTO  FORTRAN, factor:FAR PTR SWORD, power:FAR PTR SWORD%@NL@%
  1716. %@NL@%
  1717.         .CODE%@NL@%
  1718. %@NL@%
  1719. Power2  PROC   FORTRAN, factor:FAR PTR SWORD, power:FAR PTR SWORD%@NL@%
  1720. %@NL@%
  1721.         les     bx, factor%@NL@%
  1722.         mov     ax, ES:[bx]%@NL@%
  1723.         les     bx, power%@NL@%
  1724.         mov     cx, ES:[bx]%@NL@%
  1725.         shl     ax, cl%@NL@%
  1726.         ret%@NL@%
  1727. Power2  ENDP%@NL@%
  1728.         END%@NL@%
  1729. %@NL@%
  1730. %@NL@%
  1731. %@2@%%@AH@%HANDLERS.ASM%@AE@%%@EH@%%@NL@%
  1732. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\TSR\HANDLERS.ASM%@AE@%%@NL@%
  1733. %@NL@%
  1734.         .MODEL  small, pascal, os_dos%@NL@%
  1735. %@NL@%
  1736. %@AB@%; Prototypes for internal procedures%@AE@%%@NL@%
  1737. Activate        PROTO  NEAR%@NL@%
  1738. CheckRequest    PROTO  NEAR%@NL@%
  1739. CheckDos        PROTO  NEAR%@NL@%
  1740. CheckHardware   PROTO  NEAR%@NL@%
  1741. GetDosFlags     PROTO  NEAR%@NL@%
  1742. %@NL@%
  1743.         INCLUDE tsr.inc%@NL@%
  1744. %@NL@%
  1745.         .CODE%@NL@%
  1746. %@NL@%
  1747. %@AB@%; Stack buffer used by TSR. Size is determined by constant STACK_SIZ,%@AE@%%@NL@%
  1748. %@AB@%; declared in TSR.INC file. NewStack points to top of stack.%@AE@%%@NL@%
  1749. %@NL@%
  1750.          EVEN%@NL@%
  1751.          BYTE   STACK_SIZ DUP(?)        %@AB@%; Stack buffer%@AE@%%@NL@%
  1752. NewStack LABEL BYTE                     %@AB@%; Pointer to top of stack%@AE@%%@NL@%
  1753. %@NL@%
  1754. %@AB@%; Structures for interrupt handlers or "interrupt service routines".%@AE@%%@NL@%
  1755. %@AB@%; The following handlers are replaced during installation. Such routines%@AE@%%@NL@%
  1756. %@AB@%; usually set a flag to indicate they are active, optionally do some%@AE@%%@NL@%
  1757. %@AB@%; processing (such as detecting a hot key), call the old system interrupt%@AE@%%@NL@%
  1758. %@AB@%; routine, and when finished clear the active flag.%@AE@%%@NL@%
  1759. %@NL@%
  1760. HandArray       LABEL   BYTE                    %@AB@%; Array of handler structures%@AE@%%@NL@%
  1761. %@AB@%;                Num   Flag     OldHand  NewHand%@AE@%%@NL@%
  1762. intClock  INTR  < 8h,  FALSE,   NULL,    Clock>%@NL@%
  1763. intKeybrd INTR  < 9h,  FALSE,   NULL,    Keybrd>%@NL@%
  1764. intVideo  INTR  <10h,  FALSE,   NULL,    Video>%@NL@%
  1765. intDiskIO INTR  <13h,  FALSE,   NULL,    DiskIO>%@NL@%
  1766. intMisc   INTR  <15h,  FALSE,   NULL,    SkipMiscServ>%@NL@%
  1767. intIdle   INTR  <28h,  FALSE,   NULL,    Idle>%@NL@%
  1768. intMultex INTR  <2Fh,  FALSE,   NULL,    Multiplex>%@NL@%
  1769. %@NL@%
  1770. CHAND   EQU     ($ - HandArray) / (SIZEOF INTR) %@AB@%; Number of handlers in array%@AE@%%@NL@%
  1771. %@NL@%
  1772. %@AB@%; Interrupt trap routines. These interrupt routines are set up%@AE@%%@NL@%
  1773. %@AB@%; temporarily to trap keyboard break errors and critical errors%@AE@%%@NL@%
  1774. %@AB@%; while the TSR is active. When the TSR finishes its tasks, it%@AE@%%@NL@%
  1775. %@AB@%; restores the old interrupts before returning.%@AE@%%@NL@%
  1776. %@NL@%
  1777. TrapArray       LABEL   BYTE                    %@AB@%; Array of trap structures%@AE@%%@NL@%
  1778. %@AB@%;                Num   Flag     OldHand  NewHand%@AE@%%@NL@%
  1779. intCtrlBk INTR  <1Bh,  FALSE,   NULL,    CtrlBreak>%@NL@%
  1780. intCtrlC  INTR  <23h,  FALSE,   NULL,    CtrlC>%@NL@%
  1781. intCritEr INTR  <24h,  FALSE,   NULL,    CritError>%@NL@%
  1782. %@NL@%
  1783. CTRAP   EQU     ($ - TrapArray) / (SIZEOF INTR) %@AB@%; Number of traps in array%@AE@%%@NL@%
  1784. %@NL@%
  1785. %@AB@%; Address of application's stack. Before calling the main body of the TSR,%@AE@%%@NL@%
  1786. %@AB@%; the Activate procedure stores the application's stack address, then resets%@AE@%%@NL@%
  1787. %@AB@%; SS:SP to point to LABEL NewStack (see above). This gives the TSR its own%@AE@%%@NL@%
  1788. %@AB@%; stack space without making demands on the current stack. Activate restores%@AE@%%@NL@%
  1789. %@AB@%; the application's stack before returning.%@AE@%%@NL@%
  1790. %@NL@%
  1791. OldStackAddr    FPVOID  ?               %@AB@%; SS:SP pointer to application stack%@AE@%%@NL@%
  1792. %@NL@%
  1793. %@AB@%; The TSR must set up its own disk transfer area if it calls DOS functions%@AE@%%@NL@%
  1794. %@AB@%; that use the DTA (see Section 17.5.3 of the Programmer's Guide). DTA_SIZ%@AE@%%@NL@%
  1795. %@AB@%; is defined in the TSR.INC include file.%@AE@%%@NL@%
  1796. %@NL@%
  1797.                 IFDEF   DTA_SIZ%@NL@%
  1798. OldDtaAddr      FPVOID  ?               %@AB@%; Address of application's DTA%@AE@%%@NL@%
  1799. DtaBuff         BYTE    DTA_SIZ DUP(?)  %@AB@%; DTA buffer%@AE@%%@NL@%
  1800.                 ENDIF%@NL@%
  1801. %@NL@%
  1802. %@AB@%; Multiplex data. STR_LEN is defined in the TSR.INC include file%@AE@%%@NL@%
  1803. %@NL@%
  1804. IDnumber        BYTE    0               %@AB@%; TSR's identity number%@AE@%%@NL@%
  1805. IDstring        BYTE    STR_LEN DUP (0) %@AB@%; Copy of identifier string%@AE@%%@NL@%
  1806. IDstrlen        WORD    ?               %@AB@%; Length of identifier string%@AE@%%@NL@%
  1807. ShareAddr       FPVOID  ?               %@AB@%; Address of shared memory%@AE@%%@NL@%
  1808. %@NL@%
  1809. %@AB@%; Miscellaneous data%@AE@%%@NL@%
  1810. %@NL@%
  1811. TsrRequestFlag  BYTE    FALSE           %@AB@%; Flag set when hot key is pressed%@AE@%%@NL@%
  1812. TsrActiveFlag   BYTE    FALSE           %@AB@%; Flag set when TSR executes%@AE@%%@NL@%
  1813. BreakCheckFlag  BYTE    ?               %@AB@%; Break-checking status of application%@AE@%%@NL@%
  1814. TsrPspSeg       WORD    ?               %@AB@%; Segment address of PSP%@AE@%%@NL@%
  1815. TsrAddr         FPVOID  ?               %@AB@%; Pointer to main part of TSR%@AE@%%@NL@%
  1816. CritErrAddr     FPVOID  ?               %@AB@%; Pointer to MS-DOS critical error flag%@AE@%%@NL@%
  1817. InDosAddr       FPVOID  ?               %@AB@%; Pointer to MS-DOS InDos flag%@AE@%%@NL@%
  1818. %@NL@%
  1819. %@AB@%; Scan and shift codes for hot key. Install procedure initializes%@AE@%%@NL@%
  1820. %@AB@%; HotScan, HotShift, and HotMask during installation.%@AE@%%@NL@%
  1821. %@NL@%
  1822. HotScan         BYTE    ?               %@AB@%; Scan code hot key%@AE@%%@NL@%
  1823. HotShift        BYTE    ?               %@AB@%; Shift value of hot key%@AE@%%@NL@%
  1824. HotMask         BYTE    ?               %@AB@%; Mask unwanted shift values%@AE@%%@NL@%
  1825. %@NL@%
  1826. Version         LABEL   WORD            %@AB@%; DOS version number%@AE@%%@NL@%
  1827. minor           BYTE    ?%@NL@%
  1828. major           BYTE    ?%@NL@%
  1829. %@NL@%
  1830. %@AB@%; Timer data, used when the TSR is activated at a preset time instead%@AE@%%@NL@%
  1831. %@AB@%; of activated from the keyboard. The following variables serve the%@AE@%%@NL@%
  1832. %@AB@%; same purposes as the counter variables used in the ALARM.ASM program%@AE@%%@NL@%
  1833. %@AB@%; presented in Section 17.3 of the Programmer's Guide. Refer to the%@AE@%%@NL@%
  1834. %@AB@%; header comments in the Install procedure for an explanation of how%@AE@%%@NL@%
  1835. %@AB@%; to set up a time-activated TSR.%@AE@%%@NL@%
  1836. %@NL@%
  1837. Tick91          BYTE    91              %@AB@%; Measures 91 timer ticks (5 seconds)%@AE@%%@NL@%
  1838. CountDown       WORD    0               %@AB@%; Counts 5-second intervals%@AE@%%@NL@%
  1839. %@NL@%
  1840. %@NL@%
  1841. %@NL@%
  1842. %@AB@%;* Clock - Interrupt handler for Interrupt 08 (timer). Executes at each%@AE@%%@NL@%
  1843. %@AB@%;* timer interrupt, which occur an average of 18.2 times per second. Clock%@AE@%%@NL@%
  1844. %@AB@%;* first allows the original timer service routine to execute. It then%@AE@%%@NL@%
  1845. %@AB@%;* checks the flag TsrRequestFlag maintained either by the keyboard handler%@AE@%%@NL@%
  1846. %@AB@%;* (if keyboard-activated) or by this procedure (if time-activated). If%@AE@%%@NL@%
  1847. %@AB@%;* TsrRequestFlag = TRUE and system is okay, Clock invokes the TSR by%@AE@%%@NL@%
  1848. %@AB@%;* calling the Activate procedure. Uses an active flag to prevent the%@AE@%%@NL@%
  1849. %@AB@%;* Clock procedure from being reentered while executing.%@AE@%%@NL@%
  1850. %@AB@%;*%@AE@%%@NL@%
  1851. %@AB@%;* Uses:   intClock, TsrActiveFlag, CountDown%@AE@%%@NL@%
  1852. %@AB@%;*%@AE@%%@NL@%
  1853. %@AB@%;* Params: None%@AE@%%@NL@%
  1854. %@AB@%;*%@AE@%%@NL@%
  1855. %@AB@%;* Return: None%@AE@%%@NL@%
  1856. %@NL@%
  1857. Clock   PROC    FAR%@NL@%
  1858. %@NL@%
  1859.         pushf                           %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
  1860.         call    cs:intClock.OldHand     %@AB@%;   far-calling orig Int 08 routine%@AE@%%@NL@%
  1861. %@NL@%
  1862.         .IF     cs:intClock.Flag == FALSE %@AB@%; If not already in this handler:%@AE@%%@NL@%
  1863.         mov     cs:intClock.Flag, TRUE  %@AB@%; Set active flag%@AE@%%@NL@%
  1864. %@NL@%
  1865.         sti                             %@AB@%; Interrupts are okay%@AE@%%@NL@%
  1866.         push    ds                      %@AB@%; Save application's DS%@AE@%%@NL@%
  1867.         push    cs%@NL@%
  1868.         pop     ds                      %@AB@%; Set DS to resident code segment%@AE@%%@NL@%
  1869.         ASSUME  ds:@code%@NL@%
  1870. %@NL@%
  1871.         INVOKE  CheckRequest            %@AB@%; Check conditions%@AE@%%@NL@%
  1872.         .IF     !carry?                 %@AB@%; If TSR requested and safe:%@AE@%%@NL@%
  1873.         mov     TsrActiveFlag, TRUE     %@AB@%; Activate TSR%@AE@%%@NL@%
  1874.         INVOKE  Activate%@NL@%
  1875.         mov     TsrActiveFlag, FALSE%@NL@%
  1876.         .ENDIF                          %@AB@%; End carry flag check%@AE@%%@NL@%
  1877. %@NL@%
  1878.         cmp     CountDown, 0            %@AB@%; If CountDown = 0, TSR is not time-%@AE@%%@NL@%
  1879.         je      ticked                  %@AB@%;   activated or has already executed%@AE@%%@NL@%
  1880.         dec     Tick91                  %@AB@%; Else count down 91 timer ticks%@AE@%%@NL@%
  1881.         jnz     ticked                  %@AB@%; If 91 ticks have not elapsed, exit%@AE@%%@NL@%
  1882.         mov     Tick91, 91              %@AB@%; Else reset secondary counter and%@AE@%%@NL@%
  1883.         dec     CountDown               %@AB@%;   subract one 5-second interval%@AE@%%@NL@%
  1884.         ja      ticked                  %@AB@%; If counter not yet drained, exit%@AE@%%@NL@%
  1885.         mov     TsrRequestFlag, TRUE    %@AB@%; Else raise request flag%@AE@%%@NL@%
  1886. ticked:%@NL@%
  1887.         mov     intClock.Flag, FALSE    %@AB@%; Clear active flag%@AE@%%@NL@%
  1888.         pop     ds                      %@AB@%; Recover application's DS%@AE@%%@NL@%
  1889.         ASSUME  ds:NOTHING%@NL@%
  1890. %@NL@%
  1891.         .ENDIF                          %@AB@%; End in-handler check%@AE@%%@NL@%
  1892.         iret%@NL@%
  1893. %@NL@%
  1894. Clock   ENDP%@NL@%
  1895. %@NL@%
  1896. %@NL@%
  1897. %@AB@%;* Keybrd - Interrupt handler for Interrupt 09 (keyboard).%@AE@%%@NL@%
  1898. %@AB@%;*%@AE@%%@NL@%
  1899. %@AB@%;* IBM PC/AT and compatibles:%@AE@%%@NL@%
  1900. %@AB@%;*      Gets the scan code of the current keystroke from port 60h. Then%@AE@%%@NL@%
  1901. %@AB@%;*      compares the scan code and shift state to the hot key. If they%@AE@%%@NL@%
  1902. %@AB@%;*      match, sets TsrRequestFlag to signal the handlers Clock and Idle%@AE@%%@NL@%
  1903. %@AB@%;*      that the TSR is requested.%@AE@%%@NL@%
  1904. %@AB@%;*%@AE@%%@NL@%
  1905. %@AB@%;* IBM PS/2 series:%@AE@%%@NL@%
  1906. %@AB@%;*      Only the instructions at KeybrdMonitor (see below) are installed%@AE@%%@NL@%
  1907. %@AB@%;*      as Interrupt 09 handler, since above method should not be used to%@AE@%%@NL@%
  1908. %@AB@%;*      determine current keystroke in IBM PS/2 series. In this case, the%@AE@%%@NL@%
  1909. %@AB@%;*      Interrupt 15h handler MiscServ takes care of checking the scan codes%@AE@%%@NL@%
  1910. %@AB@%;*      and setting the request flag when the hot key is pressed.%@AE@%%@NL@%
  1911. %@AB@%;*%@AE@%%@NL@%
  1912. %@AB@%;* Time-activated TSRs:%@AE@%%@NL@%
  1913. %@AB@%;*      If the TSR is activated by time instead of by a hotkey, KeybrdMonitor%@AE@%%@NL@%
  1914. %@AB@%;*      serves as the Interrupt 09 handler for both PC/AT and PS/2 systems.%@AE@%%@NL@%
  1915. %@AB@%;*%@AE@%%@NL@%
  1916. %@AB@%;* Uses:   intKeybrd, TsrRequestFlag%@AE@%%@NL@%
  1917. %@AB@%;*%@AE@%%@NL@%
  1918. %@AB@%;* Params: None%@AE@%%@NL@%
  1919. %@AB@%;*%@AE@%%@NL@%
  1920. %@AB@%;* Return: None%@AE@%%@NL@%
  1921. %@NL@%
  1922. Keybrd  PROC    FAR%@NL@%
  1923. %@NL@%
  1924.         sti                             %@AB@%; Interrupts are okay%@AE@%%@NL@%
  1925.         push    ax                      %@AB@%; Save AX register%@AE@%%@NL@%
  1926.         in      al, 60h                 %@AB@%; AL = scan code of current key%@AE@%%@NL@%
  1927.         call    CheckHotKey             %@AB@%; Check for hot key%@AE@%%@NL@%
  1928.         .IF     !carry?                 %@AB@%; If not hot key:%@AE@%%@NL@%
  1929. %@NL@%
  1930. %@AB@%; Hot key pressed. Reset the keyboard to throw away keystroke.%@AE@%%@NL@%
  1931. %@NL@%
  1932.         cli                             %@AB@%; Disable interrupts while resetting%@AE@%%@NL@%
  1933.         in      al, 61h                 %@AB@%; Get current port 61h state%@AE@%%@NL@%
  1934.         or      al, 10000000y           %@AB@%; Turn on bit 7 to signal clear keybrd%@AE@%%@NL@%
  1935.         out     61h, al                 %@AB@%; Send to port%@AE@%%@NL@%
  1936.         and     al, 01111111y           %@AB@%; Turn off bit 7 to signal break%@AE@%%@NL@%
  1937.         out     61h, al                 %@AB@%; Send to port%@AE@%%@NL@%
  1938.         mov     al, 20h                 %@AB@%; Reset interrupt controller%@AE@%%@NL@%
  1939.         out     20h, al%@NL@%
  1940.         sti                             %@AB@%; Reenable interrupts%@AE@%%@NL@%
  1941. %@NL@%
  1942.         pop     ax                      %@AB@%; Recover AX%@AE@%%@NL@%
  1943.         mov     cs:TsrRequestFlag, TRUE %@AB@%; Raise request flag%@AE@%%@NL@%
  1944.         iret                            %@AB@%; Exit interrupt handler%@AE@%%@NL@%
  1945.         .ENDIF                          %@AB@%; End hot-key check%@AE@%%@NL@%
  1946. %@NL@%
  1947. %@AB@%; No hot key was pressed, so let normal Int 09 service routine take over%@AE@%%@NL@%
  1948. %@NL@%
  1949.         pop     ax                      %@AB@%; Recover AX and fall through%@AE@%%@NL@%
  1950.         cli                             %@AB@%; Interrupts cleared for service%@AE@%%@NL@%
  1951. %@NL@%
  1952. KeybrdMonitor LABEL FAR                 %@AB@%; Installed as Int 09 handler for%@AE@%%@NL@%
  1953.                                         %@AB@%;   PS/2 or for time-activated TSR%@AE@%%@NL@%
  1954.         mov     cs:intKeybrd.Flag, TRUE %@AB@%; Signal that interrupt is busy%@AE@%%@NL@%
  1955.         pushf                           %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
  1956.         call    cs:intKeybrd.OldHand    %@AB@%;   far-calling old Int 09 routine%@AE@%%@NL@%
  1957.         mov     cs:intKeybrd.Flag, FALSE%@NL@%
  1958.         iret%@NL@%
  1959. %@NL@%
  1960. Keybrd  ENDP%@NL@%
  1961. %@NL@%
  1962. %@NL@%
  1963. %@AB@%;* Video - Interrupt handler for Interrupt 10h (video). Allows the original%@AE@%%@NL@%
  1964. %@AB@%;* video service routine to execute. Maintains an active flag to prevent%@AE@%%@NL@%
  1965. %@AB@%;* the TSR from being called while Interrupt 10h is executing.%@AE@%%@NL@%
  1966. %@AB@%;*%@AE@%%@NL@%
  1967. %@AB@%;* Uses:   intVideo%@AE@%%@NL@%
  1968. %@AB@%;*%@AE@%%@NL@%
  1969. %@AB@%;* Params: Registers passed to Interrupt 10h%@AE@%%@NL@%
  1970. %@AB@%;*%@AE@%%@NL@%
  1971. %@AB@%;* Return: Registers returned by Interrupt 10h%@AE@%%@NL@%
  1972. %@NL@%
  1973. Video   PROC    FAR%@NL@%
  1974. %@NL@%
  1975.         mov     cs:intVideo.Flag, TRUE  %@AB@%; Set active flag%@AE@%%@NL@%
  1976.         pushf                           %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
  1977.         call    cs:intVideo.OldHand     %@AB@%;   far-calling old Int 10h routine%@AE@%%@NL@%
  1978.         mov     cs:intVideo.Flag, FALSE %@AB@%; Clear active flag%@AE@%%@NL@%
  1979.         iret%@NL@%
  1980. %@NL@%
  1981. Video   ENDP%@NL@%
  1982. %@NL@%
  1983. %@NL@%
  1984. %@AB@%;* DiskIO - Interrupt handler for Interrupt 13h (disk I/O). Allows the%@AE@%%@NL@%
  1985. %@AB@%;* original disk I/O service routine to execute. Maintains an active flag%@AE@%%@NL@%
  1986. %@AB@%;* to prevent the TSR from being called while Interrupt 13h is executing.%@AE@%%@NL@%
  1987. %@AB@%;*%@AE@%%@NL@%
  1988. %@AB@%;* Uses:   intDiskIO%@AE@%%@NL@%
  1989. %@AB@%;*%@AE@%%@NL@%
  1990. %@AB@%;* Params: Registers passed to Interrupt 13h%@AE@%%@NL@%
  1991. %@AB@%;*%@AE@%%@NL@%
  1992. %@AB@%;* Return: Registers and the carry flag returned by Interrupt 13h%@AE@%%@NL@%
  1993. %@NL@%
  1994. DiskIO  PROC    FAR%@NL@%
  1995. %@NL@%
  1996.         mov     cs:intDiskIO.Flag, TRUE %@AB@%; Set active flag%@AE@%%@NL@%
  1997.         pushf                           %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
  1998.         call    cs:intDiskIO.OldHand    %@AB@%;   far-calling old Int 13h routine%@AE@%%@NL@%
  1999.         mov     cs:intDiskIO.Flag, FALSE%@AB@%; Clear active flag without%@AE@%%@NL@%
  2000.                                         %@AB@%;   disturbing flags register%@AE@%%@NL@%
  2001.         sti                             %@AB@%; Enable interrupts%@AE@%%@NL@%
  2002.         ret     2                       %@AB@%; Simulate IRET without popping flags%@AE@%%@NL@%
  2003.                                         %@AB@%;   (since services use carry flag)%@AE@%%@NL@%
  2004. DiskIO  ENDP%@NL@%
  2005. %@NL@%
  2006. %@NL@%
  2007. %@AB@%;* MiscServ - Interrupt handler for Interrupt 15h (Miscellaneous System%@AE@%%@NL@%
  2008. %@AB@%;* Services).%@AE@%%@NL@%
  2009. %@AB@%;*%@AE@%%@NL@%
  2010. %@AB@%;* IBM PC/AT and compatibles:%@AE@%%@NL@%
  2011. %@AB@%;*     Stub at SkipMiscServ is used as handler, bypassing all calls to%@AE@%%@NL@%
  2012. %@AB@%;*     Interrupt 15h. Keypresses are checked by Keybrd (Int 09 handler).%@AE@%%@NL@%
  2013. %@AB@%;*%@AE@%%@NL@%
  2014. %@AB@%;* IBM PS/2 series:%@AE@%%@NL@%
  2015. %@AB@%;*     This procedure handles calls to Interrupt 15h, searching for%@AE@%%@NL@%
  2016. %@AB@%;*     Function 4Fh (Keyboard Intercept Service). When AH = 4Fh, gets%@AE@%%@NL@%
  2017. %@AB@%;*     scan code of current keystroke in AL register. Then compares the%@AE@%%@NL@%
  2018. %@AB@%;*     scan code and shift state to the hot key. If they match, sets%@AE@%%@NL@%
  2019. %@AB@%;*     TsrRequestFlag to signal the handlers Clock and Idle that the%@AE@%%@NL@%
  2020. %@AB@%;*     TSR is requested.%@AE@%%@NL@%
  2021. %@AB@%;*%@AE@%%@NL@%
  2022. %@AB@%;* Uses:   intMisc, TsrRequestFlag%@AE@%%@NL@%
  2023. %@AB@%;*%@AE@%%@NL@%
  2024. %@AB@%;* Params: Registers passed to Interrupt 15h%@AE@%%@NL@%
  2025. %@AB@%;*%@AE@%%@NL@%
  2026. %@AB@%;* Return: Registers returned by Interrupt 15h%@AE@%%@NL@%
  2027. %@NL@%
  2028. MiscServ PROC   FAR%@NL@%
  2029. %@NL@%
  2030.         sti                             %@AB@%; Interrupts okay%@AE@%%@NL@%
  2031.         .IF     ah == 4Fh               %@AB@%; If Keyboard Intercept Service:%@AE@%%@NL@%
  2032.         push    ax                      %@AB@%; Preserve AX%@AE@%%@NL@%
  2033.         call    CheckHotKey             %@AB@%; Check for hot key%@AE@%%@NL@%
  2034.         pop     ax%@NL@%
  2035.         .IF     !carry?                 %@AB@%; If hot key:%@AE@%%@NL@%
  2036.         mov     cs:TsrRequestFlag, TRUE %@AB@%; Raise request flag%@AE@%%@NL@%
  2037.         clc                             %@AB@%; Signal BIOS not to process the key%@AE@%%@NL@%
  2038.         ret     2                       %@AB@%; Simulate IRET without popping flags%@AE@%%@NL@%
  2039.         .ENDIF                          %@AB@%; End carry flag check%@AE@%%@NL@%
  2040.         .ENDIF                          %@AB@%; End Keyboard Intercept check%@AE@%%@NL@%
  2041. %@NL@%
  2042.         cli                             %@AB@%; Disable interrupts and fall through%@AE@%%@NL@%
  2043. %@NL@%
  2044. SkipMiscServ LABEL FAR                  %@AB@%; Interrupt 15h handler if PC/AT%@AE@%%@NL@%
  2045. %@NL@%
  2046.         jmp     cs:intMisc.OldHand%@NL@%
  2047. %@NL@%
  2048. MiscServ ENDP%@NL@%
  2049. %@NL@%
  2050. %@NL@%
  2051. %@AB@%;* CtrlBreak - Interrupt trap for Interrupt 1Bh (CTRL+BREAK Handler).%@AE@%%@NL@%
  2052. %@AB@%;* Disables CTRL+BREAK processing.%@AE@%%@NL@%
  2053. %@AB@%;*%@AE@%%@NL@%
  2054. %@AB@%;* Params: None%@AE@%%@NL@%
  2055. %@AB@%;*%@AE@%%@NL@%
  2056. %@AB@%;* Return: None%@AE@%%@NL@%
  2057. %@NL@%
  2058. CtrlBreak PROC  FAR%@NL@%
  2059. %@NL@%
  2060.         iret%@NL@%
  2061. %@NL@%
  2062. CtrlBreak ENDP%@NL@%
  2063. %@NL@%
  2064. %@NL@%
  2065. %@AB@%;* CtrlC - Interrupt trap for Interrupt 23h (CTRL+C Handler).%@AE@%%@NL@%
  2066. %@AB@%;* Disables CTRL+C processing.%@AE@%%@NL@%
  2067. %@AB@%;*%@AE@%%@NL@%
  2068. %@AB@%;* Params: None%@AE@%%@NL@%
  2069. %@AB@%;*%@AE@%%@NL@%
  2070. %@AB@%;* Return: None%@AE@%%@NL@%
  2071. %@NL@%
  2072. CtrlC   PROC    FAR%@NL@%
  2073. %@NL@%
  2074.         iret%@NL@%
  2075. %@NL@%
  2076. CtrlC   ENDP%@NL@%
  2077. %@NL@%
  2078. %@NL@%
  2079. %@AB@%;* CritError - Interrupt trap for Interrupt 24h (Critical Error Handler).%@AE@%%@NL@%
  2080. %@AB@%;* Disables critical error processing.%@AE@%%@NL@%
  2081. %@AB@%;*%@AE@%%@NL@%
  2082. %@AB@%;* Params: None%@AE@%%@NL@%
  2083. %@AB@%;*%@AE@%%@NL@%
  2084. %@AB@%;* Return: AL = Stop code 0 or 3%@AE@%%@NL@%
  2085. %@NL@%
  2086. CritError PROC  FAR%@NL@%
  2087. %@NL@%
  2088.         sti%@NL@%
  2089.         sub     al, al                  %@AB@%; Assume DOS 2.x%@AE@%%@NL@%
  2090.                                         %@AB@%; Set AL = 0 for ignore error%@AE@%%@NL@%
  2091.         .IF     cs:major != 2           %@AB@%; If DOS 3.x, set AL = 3%@AE@%%@NL@%
  2092.         mov     al, 3                   %@AB@%;  DOS call fails%@AE@%%@NL@%
  2093.         .ENDIF%@NL@%
  2094. %@NL@%
  2095.         iret%@NL@%
  2096. %@NL@%
  2097. CritError ENDP%@NL@%
  2098. %@NL@%
  2099. %@NL@%
  2100. %@AB@%;* Idle - Interrupt handler for Interrupt 28h (DOS Idle). Allows the%@AE@%%@NL@%
  2101. %@AB@%;* original Interrupt 28h service routine to execute. Then checks the%@AE@%%@NL@%
  2102. %@AB@%;* request flag TsrRequestFlag maintained either by the keyboard handler%@AE@%%@NL@%
  2103. %@AB@%;* (keyboard-activated TSR) or by the timer handler (time-activated TSR).%@AE@%%@NL@%
  2104. %@AB@%;* See header comments above for Clock, Keybrd, and MiscServ procedures.%@AE@%%@NL@%
  2105. %@AB@%;*%@AE@%%@NL@%
  2106. %@AB@%;* If TsrRequestFlag = TRUE and system is in interruptable state, Idle%@AE@%%@NL@%
  2107. %@AB@%;* invokes the TSR by calling the Activate procedure. Uses an active flag%@AE@%%@NL@%
  2108. %@AB@%;* to prevent the Idle procedure from being reentered while executing.%@AE@%%@NL@%
  2109. %@AB@%;*%@AE@%%@NL@%
  2110. %@AB@%;* Uses:   intIdle and TsrActiveFlag%@AE@%%@NL@%
  2111. %@AB@%;*%@AE@%%@NL@%
  2112. %@AB@%;* Params: None%@AE@%%@NL@%
  2113. %@AB@%;*%@AE@%%@NL@%
  2114. %@AB@%;* Return: None%@AE@%%@NL@%
  2115. %@NL@%
  2116. Idle    PROC    FAR%@NL@%
  2117. %@NL@%
  2118.         pushf                           %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
  2119.         call    cs:intIdle.OldHand      %@AB@%;   far-calling old Int 28h routine%@AE@%%@NL@%
  2120. %@NL@%
  2121.         .IF     cs:intIdle.Flag == FALSE%@AB@%; If not already in this handler:%@AE@%%@NL@%
  2122.         mov     cs:intIdle.Flag, TRUE   %@AB@%; Set active flag%@AE@%%@NL@%
  2123. %@NL@%
  2124.         sti                             %@AB@%; Interrupts are okay%@AE@%%@NL@%
  2125.         push    ds                      %@AB@%; Save application's DS%@AE@%%@NL@%
  2126.         push    cs%@NL@%
  2127.         pop     ds                      %@AB@%; Set DS to resident code segment%@AE@%%@NL@%
  2128.         ASSUME  ds:@code%@NL@%
  2129. %@NL@%
  2130.         INVOKE  CheckRequest            %@AB@%; Check conditions%@AE@%%@NL@%
  2131.         .IF     !carry?                 %@AB@%; If TSR requested and safe:%@AE@%%@NL@%
  2132.         mov     TsrActiveFlag, TRUE     %@AB@%; Activate TSR%@AE@%%@NL@%
  2133.         INVOKE  Activate%@NL@%
  2134.         mov     TsrActiveFlag, FALSE%@NL@%
  2135.         .ENDIF                          %@AB@%; End carry flag check%@AE@%%@NL@%
  2136. %@NL@%
  2137.         mov     intIdle.Flag, FALSE     %@AB@%; Clear active flag%@AE@%%@NL@%
  2138.         pop     ds                      %@AB@%; Recover application's DS%@AE@%%@NL@%
  2139.         .ENDIF                          %@AB@%; End in-handler check%@AE@%%@NL@%
  2140. %@NL@%
  2141.         iret%@NL@%
  2142. %@NL@%
  2143. Idle    ENDP%@NL@%
  2144. %@NL@%
  2145. %@NL@%
  2146. %@AB@%;* Multiplex - Handler for Interrupt 2Fh (Multiplex Interrupt). Checks%@AE@%%@NL@%
  2147. %@AB@%;* AH for this TSR's identity number. If no match (indicating call is%@AE@%%@NL@%
  2148. %@AB@%;* not intended for this TSR), Multiplex passes control to the previous%@AE@%%@NL@%
  2149. %@AB@%;* Interrupt 2Fh handler.%@AE@%%@NL@%
  2150. %@AB@%;*%@AE@%%@NL@%
  2151. %@AB@%;* Params: AH = Handler identity number%@AE@%%@NL@%
  2152. %@AB@%;*         AL = Function number 0-2%@AE@%%@NL@%
  2153. %@AB@%;*%@AE@%%@NL@%
  2154. %@AB@%;* Return: AL    = 0FFh (function 0)%@AE@%%@NL@%
  2155. %@AB@%;*         ES:DI = Pointer to identifier string (function 0)%@AE@%%@NL@%
  2156. %@AB@%;*         ES:DI = Pointer to resident PSP segment (function 1)%@AE@%%@NL@%
  2157. %@AB@%;*         ES:DI = Pointer to shared memory (function 2)%@AE@%%@NL@%
  2158. %@NL@%
  2159. Multiplex PROC  FAR%@NL@%
  2160. %@NL@%
  2161.         .IF     ah != cs:IDnumber       %@AB@%; If this handler not reqested:%@AE@%%@NL@%
  2162.         jmp     cs:intMultex.OldHand    %@AB@%; Pass control to old Int 2Fh handler%@AE@%%@NL@%
  2163.         .ENDIF%@NL@%
  2164. %@NL@%
  2165.         .IF     al == 0                 %@AB@%; If function 0 (verify presence):%@AE@%%@NL@%
  2166.         mov     al, 0FFh                %@AB@%; AL = 0FFh,%@AE@%%@NL@%
  2167.         push    cs                      %@AB@%; ES = resident code segment%@AE@%%@NL@%
  2168.         pop     es%@NL@%
  2169.         mov     di, OFFSET IDstring     %@AB@%; DI = offset of identifier string%@AE@%%@NL@%
  2170. %@NL@%
  2171.         .ELSEIF al == 1                 %@AB@%; If function 1 (get PSP address):%@AE@%%@NL@%
  2172.         mov     es, cs:TsrPspSeg        %@AB@%; ES:DI = far address of resident PSP%@AE@%%@NL@%
  2173.         sub     di, di%@NL@%
  2174. %@NL@%
  2175.         .ELSE%@NL@%
  2176.         les     di, cs:ShareAddr        %@AB@%; If function 2 (get shared memory):%@AE@%%@NL@%
  2177.         .ENDIF                          %@AB@%;    set ES:DI = far address%@AE@%%@NL@%
  2178. %@NL@%
  2179. NoMultiplex LABEL  FAR                  %@AB@%; Secondary entry for null Multiplex%@AE@%%@NL@%
  2180. %@NL@%
  2181.         iret%@NL@%
  2182. %@NL@%
  2183. Multiplex ENDP%@NL@%
  2184. %@NL@%
  2185. %@NL@%
  2186. %@AB@%;* CheckHotKey - Checks current keystroke for hot key. Called from Keybrd%@AE@%%@NL@%
  2187. %@AB@%;* handler if IBM PC/AT or compatible, or from MiscServ handler if PS/2.%@AE@%%@NL@%
  2188. %@AB@%;*%@AE@%%@NL@%
  2189. %@AB@%;* Uses:   HotScan, HotShift, HotMask, and SHFT_STAT%@AE@%%@NL@%
  2190. %@AB@%;*%@AE@%%@NL@%
  2191. %@AB@%;* Params: AL = Scan code%@AE@%%@NL@%
  2192. %@AB@%;*%@AE@%%@NL@%
  2193. %@AB@%;* Return: Carry flag set = FALSE; carry flag clear = TRUE%@AE@%%@NL@%
  2194. %@NL@%
  2195. CheckHotKey PROC NEAR%@NL@%
  2196. %@NL@%
  2197.         cmp     al, cs:HotScan          %@AB@%; If current scan code isn't code%@AE@%%@NL@%
  2198.         jne     e_exit                  %@AB@%;   for hot key, exit with carry set%@AE@%%@NL@%
  2199. %@NL@%
  2200.         push    es                      %@AB@%; Else look into BIOS data area%@AE@%%@NL@%
  2201.         sub     ax, ax                  %@AB@%;   (segment 0) to check shift state%@AE@%%@NL@%
  2202.         mov     es, ax%@NL@%
  2203.         mov     al, es:[SHFT_STAT]      %@AB@%; Get shift-key flags%@AE@%%@NL@%
  2204.         and     al, cs:HotMask          %@AB@%; AND with "don't care" mask%@AE@%%@NL@%
  2205.         cmp     al, cs:HotShift         %@AB@%; Compare result with hot shift key%@AE@%%@NL@%
  2206.         pop     es%@NL@%
  2207.         je      exit                    %@AB@%; If match, exit with carry clear%@AE@%%@NL@%
  2208. %@NL@%
  2209. e_exit: stc                             %@AB@%; Set carry if not hot key%@AE@%%@NL@%
  2210. exit:   ret%@NL@%
  2211. %@NL@%
  2212. CheckHotKey ENDP%@NL@%
  2213. %@NL@%
  2214. %@NL@%
  2215. %@AB@%;* CheckRequest - Checks request flag and system status using the%@AE@%%@NL@%
  2216. %@AB@%;* following logic:%@AE@%%@NL@%
  2217. %@AB@%;*%@AE@%%@NL@%
  2218. %@AB@%;*         IF (TsrRequestFlag AND (NOT TsrActiveFlag)%@AE@%%@NL@%
  2219. %@AB@%;*             AND DosStatus AND HardwareStatus)%@AE@%%@NL@%
  2220. %@AB@%;*             return TRUE%@AE@%%@NL@%
  2221. %@AB@%;*         ELSE%@AE@%%@NL@%
  2222. %@AB@%;*             return FALSE%@AE@%%@NL@%
  2223. %@AB@%;*%@AE@%%@NL@%
  2224. %@AB@%;* Uses:   TsrRequestFlag and TsrActiveFlag%@AE@%%@NL@%
  2225. %@AB@%;*%@AE@%%@NL@%
  2226. %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
  2227. %@AB@%;*%@AE@%%@NL@%
  2228. %@AB@%;* Return: Carry flag set = TRUE; carry flag clear = FALSE%@AE@%%@NL@%
  2229. %@NL@%
  2230. CheckRequest PROC NEAR%@NL@%
  2231. %@NL@%
  2232.         rol     TsrRequestFlag, 1       %@AB@%; Rotate high bit into carry - set%@AE@%%@NL@%
  2233.                                         %@AB@%;   if TRUE (-1), clear if FALSE (0)%@AE@%%@NL@%
  2234.         cmc                             %@AB@%; NOT carry%@AE@%%@NL@%
  2235. %@NL@%
  2236.         .IF     !carry?                 %@AB@%; If TsrRequestFlag = TRUE:%@AE@%%@NL@%
  2237.         ror     TsrActiveFlag, 1        %@AB@%; Rotate low bit into carry - set%@AE@%%@NL@%
  2238.                                         %@AB@%;   if TRUE (-1), clear if FALSE (0)%@AE@%%@NL@%
  2239.         .IF     !carry?                 %@AB@%; If TsrActiveFlag = FALSE:%@AE@%%@NL@%
  2240.         INVOKE  CheckDos                %@AB@%; Is DOS in interruptable state?%@AE@%%@NL@%
  2241. %@NL@%
  2242.         .IF     !carry?                 %@AB@%; If so:%@AE@%%@NL@%
  2243.         INVOKE  CheckHardware           %@AB@%; If hardware or BIOS unstable,%@AE@%%@NL@%
  2244.         .ENDIF                          %@AB@%;  set carry and exit%@AE@%%@NL@%
  2245.         .ENDIF%@NL@%
  2246.         .ENDIF%@NL@%
  2247.         ret%@NL@%
  2248. %@NL@%
  2249. CheckRequest ENDP%@NL@%
  2250. %@NL@%
  2251. %@NL@%
  2252. %@AB@%;* CheckDos - Checks status of MS-DOS using the following logic:%@AE@%%@NL@%
  2253. %@AB@%;*%@AE@%%@NL@%
  2254. %@AB@%;*         IF (NOT CritErr) AND ((NOT InDos) OR (Idle AND InDos))%@AE@%%@NL@%
  2255. %@AB@%;*             return DosStatus = TRUE%@AE@%%@NL@%
  2256. %@AB@%;*         ELSE%@AE@%%@NL@%
  2257. %@AB@%;*             return DosStatus = FALSE%@AE@%%@NL@%
  2258. %@AB@%;*%@AE@%%@NL@%
  2259. %@AB@%;* Uses:   CritErrAddr, InDosAddr, and intIdle%@AE@%%@NL@%
  2260. %@AB@%;*%@AE@%%@NL@%
  2261. %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
  2262. %@AB@%;*%@AE@%%@NL@%
  2263. %@AB@%;* Return: Carry flag set if MS-DOS is busy%@AE@%%@NL@%
  2264. %@NL@%
  2265. CheckDos PROC   NEAR USES es bx ax%@NL@%
  2266. %@NL@%
  2267.         les     bx, CritErrAddr%@NL@%
  2268.         mov     ah, es:[bx]             %@AB@%; AH = value of CritErr flag%@AE@%%@NL@%
  2269. %@NL@%
  2270.         les     bx, InDosAddr%@NL@%
  2271.         mov     al, es:[bx]             %@AB@%; AL = value of InDos flag%@AE@%%@NL@%
  2272. %@NL@%
  2273.         sub     bx, bx                  %@AB@%; BH = 0, BL = 0%@AE@%%@NL@%
  2274.         cmp     bl, intIdle.Flag        %@AB@%; Carry flag set if call is from%@AE@%%@NL@%
  2275.                                         %@AB@%;   Interrupt 28h handler%@AE@%%@NL@%
  2276.         rcl     bl, 1                   %@AB@%; Rotate carry into BL: TRUE if Idle%@AE@%%@NL@%
  2277.         cmp     bx, ax                  %@AB@%; Carry flag clear if CritErr = 0%@AE@%%@NL@%
  2278.                                         %@AB@%;   and InDos <= BL%@AE@%%@NL@%
  2279.         ret%@NL@%
  2280. %@NL@%
  2281. CheckDos ENDP%@NL@%
  2282. %@NL@%
  2283. %@NL@%
  2284. %@AB@%;* CheckHardware - Checks status of BIOS and hardware using the%@AE@%%@NL@%
  2285. %@AB@%;* following logic:%@AE@%%@NL@%
  2286. %@AB@%;*%@AE@%%@NL@%
  2287. %@AB@%;*         IF HardwareActive OR KeybrdActive OR VideoActive OR DiskIOActive%@AE@%%@NL@%
  2288. %@AB@%;*             return HardwareStatus = FALSE%@AE@%%@NL@%
  2289. %@AB@%;*         ELSE%@AE@%%@NL@%
  2290. %@AB@%;*             return HardwareStatus = TRUE%@AE@%%@NL@%
  2291. %@AB@%;*%@AE@%%@NL@%
  2292. %@AB@%;* Uses:   intKeybrd, intVideo, and intDiskIO%@AE@%%@NL@%
  2293. %@AB@%;*%@AE@%%@NL@%
  2294. %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
  2295. %@AB@%;*%@AE@%%@NL@%
  2296. %@AB@%;* Return: Carry flag set if hardware or BIOS is busy%@AE@%%@NL@%
  2297. %@NL@%
  2298. CheckHardware PROC NEAR USES ax%@NL@%
  2299. %@NL@%
  2300. %@AB@%; Verify hardware interrupt status by interrogating Intel 8259A%@AE@%%@NL@%
  2301. %@AB@%; Programmable Interrupt Controller%@AE@%%@NL@%
  2302. %@NL@%
  2303.         mov     ax, 00001011y           %@AB@%; AL = 0CW3 for Intel 8259A%@AE@%%@NL@%
  2304.                                         %@AB@%;   (RR = 1, RIS = 1)%@AE@%%@NL@%
  2305.         out     20h, al                 %@AB@%; Request 8259A in-service register%@AE@%%@NL@%
  2306.         jmp     delay                   %@AB@%; Wait a few cycles%@AE@%%@NL@%
  2307. delay:%@NL@%
  2308.         in      al, 20h                 %@AB@%; AL = hardware interrupts being%@AE@%%@NL@%
  2309.         cmp     ah, al                  %@AB@%;   serviced (bit = 1 if in service)%@AE@%%@NL@%
  2310. %@NL@%
  2311.         .IF     !carry?                 %@AB@%; If no hard interrupts in service:%@AE@%%@NL@%
  2312.         sub     al, al                  %@AB@%; Verify BIOS interrupts not active%@AE@%%@NL@%
  2313.         cmp     al, intKeybrd.Flag      %@AB@%; Check Interrupt 09 handler%@AE@%%@NL@%
  2314. %@NL@%
  2315.         .IF     !carry?                 %@AB@%; If Int 09 not active:%@AE@%%@NL@%
  2316.         cmp     al, intVideo.Flag       %@AB@%; Check Interrupt 10h handler%@AE@%%@NL@%
  2317. %@NL@%
  2318.         .IF     !carry?                 %@AB@%; If Int 10h not active:%@AE@%%@NL@%
  2319.         cmp     al, intDiskIO.Flag      %@AB@%; Check Interrupt 13h handler%@AE@%%@NL@%
  2320.         .ENDIF                          %@AB@%; Return with carry set if%@AE@%%@NL@%
  2321.         .ENDIF                          %@AB@%;   Interrupt 09, 10h, or 13h%@AE@%%@NL@%
  2322.         .ENDIF                          %@AB@%;   is active%@AE@%%@NL@%
  2323. %@NL@%
  2324.         ret%@NL@%
  2325. %@NL@%
  2326. CheckHardware ENDP%@NL@%
  2327. %@NL@%
  2328. %@NL@%
  2329. %@AB@%;* Activate - Sets up for far call to TSR with the following steps:%@AE@%%@NL@%
  2330. %@AB@%;*%@AE@%%@NL@%
  2331. %@AB@%;*   1.  Stores stack pointer SS:SP and switches to new stack%@AE@%%@NL@%
  2332. %@AB@%;*   2.  Pushes registers onto new stack%@AE@%%@NL@%
  2333. %@AB@%;*   3.  Stores vectors for Interrupts 1Bh, 23h, and 23h, and%@AE@%%@NL@%
  2334. %@AB@%;*       replaces them with addresses of error-trapping handlers%@AE@%%@NL@%
  2335. %@AB@%;*   4.  Stores DOS Ctrl+C checking flag, then turns off checking%@AE@%%@NL@%
  2336. %@AB@%;*   5.  If required, stores DTA address and switches to new DTA%@AE@%%@NL@%
  2337. %@AB@%;*%@AE@%%@NL@%
  2338. %@AB@%;* When TSR returns, restores all the above.%@AE@%%@NL@%
  2339. %@AB@%;*%@AE@%%@NL@%
  2340. %@AB@%;* Uses:   Reads or writes the following globals:%@AE@%%@NL@%
  2341. %@AB@%;*         OldStackAddr, TrapArray, BreakCheckFlag, TsrRequestFlag%@AE@%%@NL@%
  2342. %@AB@%;*%@AE@%%@NL@%
  2343. %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
  2344. %@AB@%;*%@AE@%%@NL@%
  2345. %@AB@%;* Return: None%@AE@%%@NL@%
  2346. %@NL@%
  2347. Activate PROC   NEAR%@NL@%
  2348. %@NL@%
  2349. %@AB@%; Step 1.  Set up a new stack%@AE@%%@NL@%
  2350. %@NL@%
  2351.         mov     WORD PTR OldStackAddr[0], sp    %@AB@%; Save current%@AE@%%@NL@%
  2352.         mov     WORD PTR OldStackAddr[2], ss    %@AB@%;   stack pointer%@AE@%%@NL@%
  2353. %@NL@%
  2354.         cli                                     %@AB@%; Turn off interrupts while%@AE@%%@NL@%
  2355.         push    cs                              %@AB@%;   changing stack%@AE@%%@NL@%
  2356.         pop     ss                              %@AB@%; New stack begins%@AE@%%@NL@%
  2357.         mov     sp, OFFSET NewStack             %@AB@%;   at LABEL NewStack%@AE@%%@NL@%
  2358.         sti%@NL@%
  2359. %@NL@%
  2360. %@AB@%; Step 2.  Preserve registers (DS already saved in Clock or Idle)%@AE@%%@NL@%
  2361. %@NL@%
  2362.         push    ax%@NL@%
  2363.         push    bx%@NL@%
  2364.         push    cx%@NL@%
  2365.         push    dx%@NL@%
  2366.         push    si%@NL@%
  2367.         push    di%@NL@%
  2368.         push    bp%@NL@%
  2369.         push    es%@NL@%
  2370. %@NL@%
  2371.         cld                                     %@AB@%; Clear direction flag%@AE@%%@NL@%
  2372. %@NL@%
  2373. %@AB@%; Step 3.  Set up trapping handlers for keyboard breaks and DOS%@AE@%%@NL@%
  2374. %@AB@%; critical errors (Interrupts 1Bh, 23h, and 24h)%@AE@%%@NL@%
  2375. %@NL@%
  2376.         mov     cx, CTRAP                       %@AB@%; CX = number of handlers%@AE@%%@NL@%
  2377.         mov     si, OFFSET TrapArray            %@AB@%; DS:SI points to trap array%@AE@%%@NL@%
  2378. %@NL@%
  2379.         .REPEAT%@NL@%
  2380.         mov     al, [si]                        %@AB@%; AL = interrupt number%@AE@%%@NL@%
  2381.         mov     ah, 35h                         %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
  2382.         int     21h                             %@AB@%; Get Interrupt Vector (ES:BX)%@AE@%%@NL@%
  2383.         mov     WORD PTR [si].INTR.OldHand[0], bx %@AB@%; Save far address of%@AE@%%@NL@%
  2384.         mov     WORD PTR [si].INTR.OldHand[2], es %@AB@%;   application's handler%@AE@%%@NL@%
  2385.         mov     dx, WORD PTR [si].INTR.NewHand[0] %@AB@%; DS:DX points to TSR's hand%@AE@%%@NL@%
  2386.         mov     ah, 25h                         %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
  2387.         int     21h                             %@AB@%; Set Interrupt Vector%@AE@%%@NL@%
  2388.         add     si, SIZEOF INTR                 %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
  2389.         .UNTILCXZ%@NL@%
  2390. %@NL@%
  2391. %@AB@%; Step 4.  Disable MS-DOS break checking during disk I/O%@AE@%%@NL@%
  2392. %@NL@%
  2393.         mov     ax, 3300h               %@AB@%; Request DOS Function 33h%@AE@%%@NL@%
  2394.         int     21h                     %@AB@%; Get Ctrl-Break Flag in DL%@AE@%%@NL@%
  2395.         mov     BreakCheckFlag, dl      %@AB@%; Preserve it%@AE@%%@NL@%
  2396. %@NL@%
  2397.         sub     dl, dl                  %@AB@%; DL = 0 to disable I/O break checking%@AE@%%@NL@%
  2398.         mov     ax, 3301h               %@AB@%; Request DOS Function 33h%@AE@%%@NL@%
  2399.         int     21h                     %@AB@%; Set Ctrl-Break Flag from DL%@AE@%%@NL@%
  2400. %@NL@%
  2401. %@AB@%; Step 5.  If TSR requires a disk transfer area, store address of current%@AE@%%@NL@%
  2402. %@AB@%; DTA and switch buffer address to this segment. See Section 17.5.3 of%@AE@%%@NL@%
  2403. %@AB@%; Programmer's Guide for more information about the DTA.%@AE@%%@NL@%
  2404. %@NL@%
  2405.         IFDEF   DTA_SIZ%@NL@%
  2406.         mov     ah, 2Fh                         %@AB@%; Request DOS Function 2Fh%@AE@%%@NL@%
  2407.         int     21h                             %@AB@%; Get DTA Address into ES:BX%@AE@%%@NL@%
  2408.         mov     WORD PTR OldDtaAddr[0], bx      %@AB@%; Store address%@AE@%%@NL@%
  2409.         mov     WORD PTR OldDtaAddr[2], es%@NL@%
  2410. %@NL@%
  2411.         mov     dx, OFFSET DtaBuff              %@AB@%; DS:DX points to new DTA%@AE@%%@NL@%
  2412.         mov     ah, 1Ah                         %@AB@%; Request DOS Function 1Ah%@AE@%%@NL@%
  2413.         int     21h                             %@AB@%; Set DTA Address%@AE@%%@NL@%
  2414.         ENDIF%@NL@%
  2415. %@NL@%
  2416. %@AB@%; Call main body of TSR.%@AE@%%@NL@%
  2417. %@NL@%
  2418.         mov     ax, @data%@NL@%
  2419.         mov     ds, ax                          %@AB@%; Initialize DS and ES%@AE@%%@NL@%
  2420.         mov     es, ax                          %@AB@%;   to data segment%@AE@%%@NL@%
  2421. %@NL@%
  2422.         call    cs:TsrAddr                      %@AB@%; Call main part of TSR%@AE@%%@NL@%
  2423. %@NL@%
  2424.         push    cs%@NL@%
  2425.         pop     ds                              %@AB@%; Reset DS to this segment%@AE@%%@NL@%
  2426. %@NL@%
  2427. %@AB@%; Undo step 5.  Restore previous DTA (if required)%@AE@%%@NL@%
  2428. %@NL@%
  2429.         IFDEF   DTA_SIZ%@NL@%
  2430.         push    ds                      %@AB@%; Preserve DS%@AE@%%@NL@%
  2431.         lds     dx, OldDtaAddr          %@AB@%; DS:DX points to application's DTA%@AE@%%@NL@%
  2432.         mov     ah, 1Ah                 %@AB@%; Request DOS Function 1Ah%@AE@%%@NL@%
  2433.         int     21h                     %@AB@%; Set DTA Address%@AE@%%@NL@%
  2434.         pop     ds%@NL@%
  2435.         ENDIF%@NL@%
  2436. %@NL@%
  2437. %@AB@%; Undo step 4.  Restore previous MS-DOS break checking%@AE@%%@NL@%
  2438. %@NL@%
  2439.         mov     dl, BreakCheckFlag      %@AB@%; DL = previous break state%@AE@%%@NL@%
  2440.         mov     ax, 3301h               %@AB@%; Request DOS Function 33h%@AE@%%@NL@%
  2441.         int     21h                     %@AB@%; Set Ctrl-Break Flag from DL%@AE@%%@NL@%
  2442. %@NL@%
  2443. %@AB@%; Undo step 3.  Restore previous vectors for error-trapping handlers%@AE@%%@NL@%
  2444. %@NL@%
  2445.         mov     cx, CTRAP%@NL@%
  2446.         mov     di, OFFSET TrapArray%@NL@%
  2447.         push    ds                      %@AB@%; Preserve DS%@AE@%%@NL@%
  2448.         push    ds                      %@AB@%; ES = resident code segment%@AE@%%@NL@%
  2449.         pop     es%@NL@%
  2450. %@NL@%
  2451.         .REPEAT%@NL@%
  2452.         mov     al, es:[di]             %@AB@%; AL = interrupt number%@AE@%%@NL@%
  2453.         lds     dx, es:[di].INTR.OldHand%@AB@%; DS:DX points to application's handler%@AE@%%@NL@%
  2454.         mov     ah, 25h                 %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
  2455.         int     21h                     %@AB@%; Set Interrupt Vector from DS:DX%@AE@%%@NL@%
  2456.         add     di, SIZEOF INTR         %@AB@%; ES:DI points to next in list%@AE@%%@NL@%
  2457.         .UNTILCXZ%@NL@%
  2458.         pop     ds%@NL@%
  2459. %@NL@%
  2460. %@AB@%; Undo step 2.  Restore registers from stack%@AE@%%@NL@%
  2461. %@NL@%
  2462.         pop     es%@NL@%
  2463.         pop     bp%@NL@%
  2464.         pop     di%@NL@%
  2465.         pop     si%@NL@%
  2466.         pop     dx%@NL@%
  2467.         pop     cx%@NL@%
  2468.         pop     bx%@NL@%
  2469.         pop     ax%@NL@%
  2470. %@NL@%
  2471. %@AB@%; Undo step 1.  Restore address of original stack to SS:SP%@AE@%%@NL@%
  2472. %@NL@%
  2473.         cli%@NL@%
  2474.         mov     sp, WORD PTR OldStackAddr[0]%@NL@%
  2475.         mov     ss, WORD PTR OldStackAddr[2]%@NL@%
  2476.         sti%@NL@%
  2477. %@NL@%
  2478. %@AB@%; Clear request flag and return to caller (Clock or Idle procedure)%@AE@%%@NL@%
  2479. %@NL@%
  2480.         mov     TsrRequestFlag, FALSE%@NL@%
  2481.         ret%@NL@%
  2482. %@NL@%
  2483. Activate ENDP%@NL@%
  2484. %@NL@%
  2485. %@NL@%
  2486. %@NL@%
  2487. %@AB@%;* INSTALLATION SECTION - The following code is executed only during%@AE@%%@NL@%
  2488. %@AB@%;* the TSR's installation phase. When the program terminates through%@AE@%%@NL@%
  2489. %@AB@%;* Function 31h, the above code and data remain resident; memory%@AE@%%@NL@%
  2490. %@AB@%;* occupied by the following code segment is returned to the operating%@AE@%%@NL@%
  2491. %@AB@%;* system.%@AE@%%@NL@%
  2492. %@NL@%
  2493. DGROUP  GROUP INSTALLCODE%@NL@%
  2494. %@NL@%
  2495. INSTALLCODE SEGMENT PARA PUBLIC 'CODE2'%@NL@%
  2496.         ASSUME  ds:@code%@NL@%
  2497. %@NL@%
  2498. %@AB@%;* Install - Prepares for installation of a TSR by chaining interrupt%@AE@%%@NL@%
  2499. %@AB@%;* handlers and initializing pointers to DOS flags. Install does not%@AE@%%@NL@%
  2500. %@AB@%;* call the Terminate-and-Stay-Resident function.%@AE@%%@NL@%
  2501. %@AB@%;*%@AE@%%@NL@%
  2502. %@AB@%;* This library of routines accomodates both keyboard-activated and%@AE@%%@NL@%
  2503. %@AB@%;* time-activated TSRs. The latter are TSRs that activate at a preset%@AE@%%@NL@%
  2504. %@AB@%;* time. If the first parameter (Param1) is a valid scan code, Install%@AE@%%@NL@%
  2505. %@AB@%;* assumes the TSR is activated from the keyboard and sets up a keyboard%@AE@%%@NL@%
  2506. %@AB@%;* handler to search for the hotkey. If Param1 is null, Install assumes%@AE@%%@NL@%
  2507. %@AB@%;* the next two parameters (Param2 and Param3) are respectively the hour%@AE@%%@NL@%
  2508. %@AB@%;* and minute at which the TSR is to activate. In this case, Install%@AE@%%@NL@%
  2509. %@AB@%;* calls GetTimeToElapse to initialize the variable CountDown and sets%@AE@%%@NL@%
  2510. %@AB@%;* up KeybrdMonitor as the keyboard handler. CountDown and the secondary%@AE@%%@NL@%
  2511. %@AB@%;* counter Tick91 serve here the same functions as they do for the%@AE@%%@NL@%
  2512. %@AB@%;* ALARM.ASM program presented in Section 17.3 of the Programmer's Guide.%@AE@%%@NL@%
  2513. %@AB@%;* Install is callable from a high-level language.%@AE@%%@NL@%
  2514. %@AB@%;*%@AE@%%@NL@%
  2515. %@AB@%;* Uses:   InDosAddr, CritErrAddr, CHAND,%@AE@%%@NL@%
  2516. %@AB@%;*         HandArray, CTRAP, TrapArray%@AE@%%@NL@%
  2517. %@AB@%;*%@AE@%%@NL@%
  2518. %@AB@%;*                  Keyboard-activated                 Time-activated%@AE@%%@NL@%
  2519. %@AB@%;*                  ------------------                 --------------%@AE@%%@NL@%
  2520. %@AB@%;* Params: Param1 - Scan code for hotkey               0%@AE@%%@NL@%
  2521. %@AB@%;*         Param2 - Bit value for shift hotkey         Hour to activate%@AE@%%@NL@%
  2522. %@AB@%;*         Param3 - Bit mask for shift hotkey          Minute to activate%@AE@%%@NL@%
  2523. %@AB@%;*         Param4 - Far address of main TSR procedure  (same)%@AE@%%@NL@%
  2524. %@AB@%;*%@AE@%%@NL@%
  2525. %@AB@%;* Return: AX = 0 if successful, or one of the following codes:%@AE@%%@NL@%
  2526. %@AB@%;*         IS_INSTALLED           FLAGS_NOT_FOUND        NO_IDNUM%@AE@%%@NL@%
  2527. %@AB@%;*         ALREADY_INSTALLED      WRONG_DOS%@AE@%%@NL@%
  2528. %@NL@%
  2529. Install PROC    FAR USES ds si di,%@NL@%
  2530.         Param1:WORD, Param2:WORD, Param3:WORD, Param4:FAR PTR FAR%@NL@%
  2531. %@NL@%
  2532.         mov     ax, @code%@NL@%
  2533.         mov     ds, ax                          %@AB@%; Point DS to code segment%@AE@%%@NL@%
  2534. %@NL@%
  2535. %@AB@%; Get and store parameters passed from main program module%@AE@%%@NL@%
  2536. %@NL@%
  2537.         mov     al, BYTE PTR Param1%@NL@%
  2538.         mov     HotScan, al                     %@AB@%; Store hot key scan code%@AE@%%@NL@%
  2539.         mov     al, BYTE PTR Param2             %@AB@%;   or flag for time-activate%@AE@%%@NL@%
  2540.         mov     HotShift, al                    %@AB@%; Store hot key shift value%@AE@%%@NL@%
  2541.         mov     al, BYTE PTR Param3             %@AB@%;   or hour value%@AE@%%@NL@%
  2542.         mov     HotMask, al                     %@AB@%; Store hot key shift mask%@AE@%%@NL@%
  2543.                                                 %@AB@%;   or minute value%@AE@%%@NL@%
  2544.         mov     ax, WORD PTR Param4[0]%@NL@%
  2545.         mov     bx, WORD PTR Param4[2]%@NL@%
  2546.         mov     WORD PTR TsrAddr[0], ax         %@AB@%; Store segment:offset of%@AE@%%@NL@%
  2547.         mov     WORD PTR TsrAddr[2], bx         %@AB@%;   TSR's main code%@AE@%%@NL@%
  2548. %@NL@%
  2549. %@AB@%; Get addresses of DOS flags, then check for prior installation%@AE@%%@NL@%
  2550. %@NL@%
  2551.         INVOKE  GetDosFlags             %@AB@%; Find DOS service flags%@AE@%%@NL@%
  2552.         or      ax, ax%@NL@%
  2553.         jnz     exit                    %@AB@%; If flags not found, quit%@AE@%%@NL@%
  2554. %@NL@%
  2555.         sub     al, al                  %@AB@%; Request multiplex function 0%@AE@%%@NL@%
  2556.         call    CallMultiplex           %@AB@%; Invoke Interrupt 2Fh%@AE@%%@NL@%
  2557.         cmp     ax, NOT_INSTALLED       %@AB@%; Check for presence of resident TSR%@AE@%%@NL@%
  2558. %@NL@%
  2559.         .IF     !zero?                  %@AB@%; If TSR is installed:%@AE@%%@NL@%
  2560.         cmp     ax, IS_INSTALLED        %@AB@%; Return with appropriate%@AE@%%@NL@%
  2561.         jne     exit                    %@AB@%;   error code%@AE@%%@NL@%
  2562.         mov     ax, ALREADY_INSTALLED%@NL@%
  2563.         jmp     exit%@NL@%
  2564.         .ENDIF%@NL@%
  2565. %@NL@%
  2566. %@AB@%; Check if TSR is to activate at the hour:minute specified by Param2:Param3.%@AE@%%@NL@%
  2567. %@AB@%; If so, determine the number of 5-second intervals that must elapse before%@AE@%%@NL@%
  2568. %@AB@%; activation, then set up the code at the far LABEL KeybrdMonitor to serve%@AE@%%@NL@%
  2569. %@AB@%; as the keyboard handler.%@AE@%%@NL@%
  2570. %@NL@%
  2571.         .IF     HotScan == 0            %@AB@%; If valid scan code given:%@AE@%%@NL@%
  2572.         mov     ah, HotShift            %@AB@%; AH = hour to activate%@AE@%%@NL@%
  2573.         mov     al, HotMask             %@AB@%; AL = minute to activate%@AE@%%@NL@%
  2574.         call    GetTimeToElapse         %@AB@%; Get number of 5-second intervals%@AE@%%@NL@%
  2575.         mov     CountDown, ax           %@AB@%;   to elapse before activation%@AE@%%@NL@%
  2576. %@NL@%
  2577.         .ELSE                           %@AB@%; Force use of KeybrdMonitor as%@AE@%%@NL@%
  2578.                                         %@AB@%;   keyboard handler%@AE@%%@NL@%
  2579.         cmp     Version, 031Eh          %@AB@%; DOS Version 3.3 or higher?%@AE@%%@NL@%
  2580.         jb      setup                   %@AB@%; No?  Skip next step%@AE@%%@NL@%
  2581. %@NL@%
  2582. %@AB@%; Test for IBM PS/2 series. If not PS/2, use Keybrd and SkipMiscServ as%@AE@%%@NL@%
  2583. %@AB@%; handlers for Interrupts 09 and 15h respectively. If PS/2 system, set up%@AE@%%@NL@%
  2584. %@AB@%; KeybrdMonitor as the Interrupt 09 handler. Audit keystrokes with MiscServ%@AE@%%@NL@%
  2585. %@AB@%; handler, which searches for the hot key by handling calls to Interrupt 15h%@AE@%%@NL@%
  2586. %@AB@%; (Miscellaneous System Services). Refer to Section 17.2.1 of the Programmer's%@AE@%%@NL@%
  2587. %@AB@%; Guide for more information about keyboard handlers.%@AE@%%@NL@%
  2588. %@NL@%
  2589.         mov     ax, 0C00h               %@AB@%; Function 0Ch (Get System%@AE@%%@NL@%
  2590.         int     15h                     %@AB@%;   Configuration Parameters)%@AE@%%@NL@%
  2591.         sti                             %@AB@%; Compaq ROM may leave disabled%@AE@%%@NL@%
  2592. %@NL@%
  2593.         jc      setup                   %@AB@%; If carry set,%@AE@%%@NL@%
  2594.         or      ah, ah                  %@AB@%;   or if AH not 0,%@AE@%%@NL@%
  2595.         jnz     setup                   %@AB@%;   services are not supported%@AE@%%@NL@%
  2596. %@NL@%
  2597.         test    BYTE PTR es:[bx+5], 00010000y   %@AB@%; Test byte 4 to see if%@AE@%%@NL@%
  2598.         jz      setup                           %@AB@%;   intercept is implemented%@AE@%%@NL@%
  2599. %@NL@%
  2600.         mov     ax, OFFSET MiscServ             %@AB@%; If so, set up MiscServ as%@AE@%%@NL@%
  2601.         mov     WORD PTR intMisc.NewHand, ax    %@AB@%;   Interrupt 15h handler%@AE@%%@NL@%
  2602.         .ENDIF%@NL@%
  2603. %@NL@%
  2604.         mov     ax, OFFSET KeybrdMonitor        %@AB@%; Set up KeybrdMonitor as%@AE@%%@NL@%
  2605.         mov     WORD PTR intKeybrd.NewHand, ax  %@AB@%;   Interrupt 09 handler%@AE@%%@NL@%
  2606. %@NL@%
  2607. %@AB@%; Interrupt structure is now initialized for either PC/AT or PS/2 system.%@AE@%%@NL@%
  2608. %@AB@%; Get existing handler addresses from interrupt vector table, store in%@AE@%%@NL@%
  2609. %@AB@%; OldHand member, and replace with addresses of new handlers.%@AE@%%@NL@%
  2610. %@NL@%
  2611. setup:%@NL@%
  2612.         mov     cx, CHAND               %@AB@%; CX = count of handlers%@AE@%%@NL@%
  2613.         mov     si, OFFSET HandArray    %@AB@%; SI = offset of handler structures%@AE@%%@NL@%
  2614. %@NL@%
  2615.         .REPEAT%@NL@%
  2616.         mov     ah, 35h                 %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
  2617.         mov     al, [si]                %@AB@%; AL = interrupt number%@AE@%%@NL@%
  2618.         int     21h                     %@AB@%; Get Interrupt Vector in ES:BX%@AE@%%@NL@%
  2619.         mov     WORD PTR [si].INTR.OldHand[0], bx %@AB@%; Save far address%@AE@%%@NL@%
  2620.         mov     WORD PTR [si].INTR.OldHand[2], es %@AB@%;  of current handler%@AE@%%@NL@%
  2621.         mov     dx, WORD PTR [si].INTR.NewHand[0] %@AB@%; DS:DX points to TSR handler%@AE@%%@NL@%
  2622.         mov     ah, 25h                 %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
  2623.         int     21h                     %@AB@%; Set Interrupt Vector from DS:DX%@AE@%%@NL@%
  2624.         add     si, SIZEOF INTR         %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
  2625.         .UNTILCXZ%@NL@%
  2626. %@NL@%
  2627.         sub     ax, ax                  %@AB@%; Clear return code%@AE@%%@NL@%
  2628. exit:%@NL@%
  2629.         ret                             %@AB@%; Return to caller%@AE@%%@NL@%
  2630. %@NL@%
  2631. Install ENDP%@NL@%
  2632. %@NL@%
  2633. %@NL@%
  2634. %@AB@%;* Deinstall - Prepares for deinstallation of a TSR. Deinstall is the%@AE@%%@NL@%
  2635. %@AB@%;* complement of the Install procedure. It restores to the vector table%@AE@%%@NL@%
  2636. %@AB@%;* the original addresses replaced during installation, thus unhooking%@AE@%%@NL@%
  2637. %@AB@%;* the TSR's handlers. Checks to see if another TSR has installed handlers%@AE@%%@NL@%
  2638. %@AB@%;* for the interrupts in array HandArray. If so, the procedure fails with%@AE@%%@NL@%
  2639. %@AB@%;* an appropriate error code. Callable from a high-level language.%@AE@%%@NL@%
  2640. %@AB@%;*%@AE@%%@NL@%
  2641. %@AB@%;* Params: None%@AE@%%@NL@%
  2642. %@AB@%;*%@AE@%%@NL@%
  2643. %@AB@%;* Return: AX = Segment address of resident portion's PSP or%@AE@%%@NL@%
  2644. %@AB@%;*              one of the following error codes:%@AE@%%@NL@%
  2645. %@AB@%;*              CANT_DEINSTALL           WRONG_DOS%@AE@%%@NL@%
  2646. %@NL@%
  2647. Deinstall PROC  FAR USES ds si di%@NL@%
  2648. %@NL@%
  2649.         mov     ax, @code%@NL@%
  2650.         mov     ds, ax                  %@AB@%; Point DS to code segment%@AE@%%@NL@%
  2651. %@NL@%
  2652.         sub     al, al                  %@AB@%; Request multiplex function 0%@AE@%%@NL@%
  2653.         call    CallMultiplex           %@AB@%; Get resident code segment in ES%@AE@%%@NL@%
  2654. %@NL@%
  2655.         cmp     ax, IS_INSTALLED        %@AB@%; If not resident,%@AE@%%@NL@%
  2656.         jne     exit                    %@AB@%;   exit with error%@AE@%%@NL@%
  2657.         push    es                      %@AB@%; Else point DS to%@AE@%%@NL@%
  2658.         pop     ds                      %@AB@%;   resident code segment%@AE@%%@NL@%
  2659.         mov     cx, CHAND               %@AB@%; Count of handlers%@AE@%%@NL@%
  2660.         mov     si, OFFSET HandArray    %@AB@%; SI points to handler structures%@AE@%%@NL@%
  2661. %@NL@%
  2662. %@AB@%; Read current vectors for TSR's interrupt handlers and compare with far%@AE@%%@NL@%
  2663. %@AB@%; addresses. If mismatch, another TSR has installed new handlers and ours%@AE@%%@NL@%
  2664. %@AB@%; cannot be safely deinstalled.%@AE@%%@NL@%
  2665. %@NL@%
  2666.         .REPEAT%@NL@%
  2667.         mov     al, [si]                %@AB@%; AL = interrupt number%@AE@%%@NL@%
  2668.         mov     ah, 35h                 %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
  2669.         int     21h                     %@AB@%; Get Interrupt Vector in ES:BX%@AE@%%@NL@%
  2670.         cmp     bx, WORD PTR [si].INTR.NewHand[0] %@AB@%; If offset different,%@AE@%%@NL@%
  2671.         jne     e_exit                            %@AB@%;   error%@AE@%%@NL@%
  2672.         mov     ax, es%@NL@%
  2673.         cmp     ax, WORD PTR [si].INTR.NewHand[2] %@AB@%; If segment different,%@AE@%%@NL@%
  2674.         jne     e_exit                            %@AB@%;   error%@AE@%%@NL@%
  2675.         add     si, SIZEOF INTR         %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
  2676.         .UNTILCXZ%@NL@%
  2677. %@NL@%
  2678. %@AB@%; If no interrupts replaced, call TSR's multiplex handler to locate%@AE@%%@NL@%
  2679. %@AB@%; address of resident portion's PSP. Although the PSP is not required%@AE@%%@NL@%
  2680. %@AB@%; until memory is returned to DOS, the call must be done now before%@AE@%%@NL@%
  2681. %@AB@%; unhooking the multiplex handler.%@AE@%%@NL@%
  2682. %@NL@%
  2683.         mov     al, 1                   %@AB@%; Request multiplex function 1%@AE@%%@NL@%
  2684.         call    CallMultiplex           %@AB@%; Get resident code's PSP in ES%@AE@%%@NL@%
  2685.         push    es                      %@AB@%; Save it%@AE@%%@NL@%
  2686. %@NL@%
  2687. %@AB@%; Unhook all handlers by restoring the original vectors to vector table.%@AE@%%@NL@%
  2688. %@NL@%
  2689.         mov     cx, CHAND               %@AB@%; Count of installed handlers%@AE@%%@NL@%
  2690.         mov     si, OFFSET HandArray    %@AB@%; SI points to handler structures%@AE@%%@NL@%
  2691. %@NL@%
  2692.         .REPEAT%@NL@%
  2693.         mov     al, [si]                %@AB@%; AL = interrupt number%@AE@%%@NL@%
  2694.         push    ds                      %@AB@%; Preserve DS segment%@AE@%%@NL@%
  2695.         lds     dx, [si].INTR.OldHand   %@AB@%; Put vector in DS:DX%@AE@%%@NL@%
  2696.         mov     ah, 25h                 %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
  2697.         int     21h                     %@AB@%; Set Interrupt Vector from DS:DX%@AE@%%@NL@%
  2698.         pop     ds%@NL@%
  2699.         add     si, SIZEOF INTR         %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
  2700.         .UNTILCXZ%@NL@%
  2701. %@NL@%
  2702.         pop     ax                      %@AB@%; Return address of resident PSP%@AE@%%@NL@%
  2703.         jmp     exit                    %@AB@%;  to signal success%@AE@%%@NL@%
  2704. e_exit:%@NL@%
  2705.         mov     ax, CANT_DEINSTALL%@NL@%
  2706. exit:%@NL@%
  2707.         ret%@NL@%
  2708. %@NL@%
  2709. Deinstall ENDP%@NL@%
  2710. %@NL@%
  2711. %@NL@%
  2712. %@AB@%;* GetVersion - Gets the DOS version and stores it in a global variable as%@AE@%%@NL@%
  2713. %@AB@%;* well as returning it in AX.%@AE@%%@NL@%
  2714. %@AB@%;*%@AE@%%@NL@%
  2715. %@AB@%;* Uses:   Version%@AE@%%@NL@%
  2716. %@AB@%;*%@AE@%%@NL@%
  2717. %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
  2718. %@AB@%;*%@AE@%%@NL@%
  2719. %@AB@%;* Return: AH = Major version%@AE@%%@NL@%
  2720. %@AB@%;*         AL = Minor version%@AE@%%@NL@%
  2721. %@NL@%
  2722. GetVersion PROC NEAR%@NL@%
  2723. %@NL@%
  2724.         mov     ax, 3000h               %@AB@%; Request DOS Function 30h%@AE@%%@NL@%
  2725.         int     21h                     %@AB@%; Get MS-DOS Version Number%@AE@%%@NL@%
  2726.         .IF     al < 2                  %@AB@%; If Version 1.x:%@AE@%%@NL@%
  2727.         mov     ax, WRONG_DOS           %@AB@%; Abort with WRONG_DOS as error code%@AE@%%@NL@%
  2728.         .ELSE%@NL@%
  2729.         xchg    ah, al                  %@AB@%; AH = major, AL = minor version%@AE@%%@NL@%
  2730.         mov     Version, ax             %@AB@%; Save in global%@AE@%%@NL@%
  2731.         .ENDIF%@NL@%
  2732.         ret%@NL@%
  2733. %@NL@%
  2734. GetVersion ENDP%@NL@%
  2735. %@NL@%
  2736. %@NL@%
  2737. %@AB@%;* GetDosFlags - Gets pointers to DOS's InDos and Critical Error flags.%@AE@%%@NL@%
  2738. %@AB@%;*%@AE@%%@NL@%
  2739. %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
  2740. %@AB@%;*%@AE@%%@NL@%
  2741. %@AB@%;* Return: 0 if successful, or the following error code:%@AE@%%@NL@%
  2742. %@AB@%;*         FLAGS_NOT_FOUND%@AE@%%@NL@%
  2743. %@NL@%
  2744. GetDosFlags PROC NEAR%@NL@%
  2745. %@NL@%
  2746. %@AB@%; Get InDOS address from MS-DOS%@AE@%%@NL@%
  2747. %@NL@%
  2748.         mov     ah, 34h                         %@AB@%; Request DOS Function 34h%@AE@%%@NL@%
  2749.         int     21h                             %@AB@%; Get Address of InDos Flag%@AE@%%@NL@%
  2750.         mov     WORD PTR InDosAddr[0], bx       %@AB@%; Store address (ES:BX)%@AE@%%@NL@%
  2751.         mov     WORD PTR InDosAddr[2], es       %@AB@%;   for later access%@AE@%%@NL@%
  2752. %@NL@%
  2753. %@AB@%; Determine address of Critical Error Flag%@AE@%%@NL@%
  2754. %@NL@%
  2755.         mov     ax, Version             %@AB@%; AX = DOS version number%@AE@%%@NL@%
  2756. %@NL@%
  2757. %@AB@%; If DOS 3.1 or greater and not OS/2 compatibility mode, Critical Error%@AE@%%@NL@%
  2758. %@AB@%; flag is in byte preceding InDOS flag%@AE@%%@NL@%
  2759.         .IF     (ah < 10) && (ah >= 3) && (al >= 10)%@NL@%
  2760.         dec     bx                      %@AB@%; BX points to byte before InDos flag%@AE@%%@NL@%
  2761. %@NL@%
  2762.         .ELSE%@NL@%
  2763. %@AB@%; For earlier versions, the only reliable method is to scan through%@AE@%%@NL@%
  2764. %@AB@%; DOS to find an INT 28h instruction in a specific context.%@AE@%%@NL@%
  2765. %@NL@%
  2766.         mov     cx, 0FFFFh              %@AB@%; Maximum bytes to scan%@AE@%%@NL@%
  2767.         sub     di, di                  %@AB@%; ES:DI = start of DOS segment%@AE@%%@NL@%
  2768. %@NL@%
  2769. INT_28  EQU     028CDh%@NL@%
  2770. %@NL@%
  2771.         .REPEAT%@NL@%
  2772.         mov     ax, INT_28              %@AB@%; Load opcode for INT 28h%@AE@%%@NL@%
  2773. %@NL@%
  2774.         .REPEAT%@NL@%
  2775.         repne   scasb                   %@AB@%; Scan for first byte of opcode%@AE@%%@NL@%
  2776. %@NL@%
  2777.         .IF     !zero?%@NL@%
  2778.         mov     ax, FLAGS_NOT_FOUND     %@AB@%; Return error if not found%@AE@%%@NL@%
  2779.         jmp     exit%@NL@%
  2780.         .ENDIF%@NL@%
  2781.         .UNTIL  ah == es:[di]           %@AB@%; For each matching first byte,%@AE@%%@NL@%
  2782.                                         %@AB@%;  check the second byte until match%@AE@%%@NL@%
  2783. %@NL@%
  2784. %@AB@%; See if INT 28h is in this context:%@AE@%%@NL@%
  2785. %@AB@%;                                       ;     (-7)    (-5)%@AE@%%@NL@%
  2786. %@AB@%;       CMP     ss:[CritErrFlag], 0     ;  36, 80, 3E,  ?,  ?,  0%@AE@%%@NL@%
  2787. %@AB@%;       JNE     NearLabel               ;  75,  ?%@AE@%%@NL@%
  2788.         int     28h                     %@AB@%;  CD, 28%@AE@%%@NL@%
  2789. %@AB@%;                                       ;  (0) (1)%@AE@%%@NL@%
  2790. CMP_SS    EQU   3E80h%@NL@%
  2791. P_CMP_SS  EQU   8%@NL@%
  2792. P_CMP_OP  EQU   6%@NL@%
  2793. %@NL@%
  2794.         mov     ax, CMP_SS              %@AB@%; Load and compare opcode to CMP%@AE@%%@NL@%
  2795.         .IF     ax == es:[di-P_CMP_SS]  %@AB@%; If match:%@AE@%%@NL@%
  2796.         mov     bx, es:[di-P_CMP_OP]    %@AB@%; BX = offset of%@AE@%%@NL@%
  2797.         jmp     exit                    %@AB@%;   Critical Error Flag%@AE@%%@NL@%
  2798.         .ENDIF%@NL@%
  2799. %@NL@%
  2800. %@AB@%; See if INT 28h is in this context:%@AE@%%@NL@%
  2801. %@AB@%;                                       ;     (-12)   (-10)%@AE@%%@NL@%
  2802. %@AB@%;       TEST    ?s:[CritErr], 0FFh      ;  ?6  F6, 06,  ?,  ?, FF%@AE@%%@NL@%
  2803. %@AB@%;       JNE     NearLabel               ;  75, ?%@AE@%%@NL@%
  2804. %@AB@%;       PUSH    ss:[CritErrFlag]        ;  36, FF, 36,  ?,  ?%@AE@%%@NL@%
  2805.         int     28h                     %@AB@%;  CD, 28%@AE@%%@NL@%
  2806. %@AB@%;                                       ;  (0) (1)%@AE@%%@NL@%
  2807. TEST_SS   EQU   06F6h%@NL@%
  2808. P_TEST_SS EQU   13%@NL@%
  2809. P_TEST_OP EQU   11%@NL@%
  2810. %@NL@%
  2811.         mov     ax, TEST_SS             %@AB@%; Load AX = opcode for TEST%@AE@%%@NL@%
  2812.         .UNTIL  ax == es:[di-P_TEST_SS] %@AB@%; If not TEST, continue scan%@AE@%%@NL@%
  2813. %@NL@%
  2814.         mov     bx, es:[di-P_TEST_OP]   %@AB@%; Else load BX with offset of%@AE@%%@NL@%
  2815.         .ENDIF                          %@AB@%;   Critical Error flag%@AE@%%@NL@%
  2816. exit:%@NL@%
  2817.         mov     WORD PTR CritErrAddr[0], bx     %@AB@%; Store address of%@AE@%%@NL@%
  2818.         mov     WORD PTR CritErrAddr[2], es     %@AB@%;   Critical Error Flag%@AE@%%@NL@%
  2819.         sub     ax, ax                          %@AB@%; Clear error code%@AE@%%@NL@%
  2820.         ret%@NL@%
  2821. %@NL@%
  2822. GetDosFlags ENDP%@NL@%
  2823. %@NL@%
  2824. %@NL@%
  2825. %@AB@%;* GetTimeToElapse - Determines number of 5-second intervals that%@AE@%%@NL@%
  2826. %@AB@%;* must elapse between specified hour:minute and current time.%@AE@%%@NL@%
  2827. %@AB@%;*%@AE@%%@NL@%
  2828. %@AB@%;* Params: AH = Hour%@AE@%%@NL@%
  2829. %@AB@%;*         AL = Minute%@AE@%%@NL@%
  2830. %@AB@%;*%@AE@%%@NL@%
  2831. %@AB@%;* Return: AX = Number of 5-second intervals%@AE@%%@NL@%
  2832. %@NL@%
  2833. GetTimeToElapse PROC NEAR%@NL@%
  2834. %@NL@%
  2835.         push    ax                      %@AB@%; Save hour:minute%@AE@%%@NL@%
  2836.         mov     ah, 2Ch                 %@AB@%; Request DOS Function 2Ch%@AE@%%@NL@%
  2837.         int     21h                     %@AB@%; Get Time (CH:CL = hour:minute)%@AE@%%@NL@%
  2838.         pop     bx                      %@AB@%; Recover hour:minute%@AE@%%@NL@%
  2839.         mov     dl, dh%@NL@%
  2840.         sub     dh, dh%@NL@%
  2841.         push    dx                      %@AB@%; Save DX = current seconds%@AE@%%@NL@%
  2842. %@NL@%
  2843.         mov     al, 60                  %@AB@%; 60 minutes/hour%@AE@%%@NL@%
  2844.         mul     bh                      %@AB@%; Mutiply by specified hour%@AE@%%@NL@%
  2845.         sub     bh, bh%@NL@%
  2846.         add     bx, ax                  %@AB@%; BX = minutes from midnight%@AE@%%@NL@%
  2847.                                         %@AB@%;   to activation time%@AE@%%@NL@%
  2848.         mov     al, 60                  %@AB@%; 60 minutes/hour%@AE@%%@NL@%
  2849.         mul     ch                      %@AB@%; Multiply by current hour%@AE@%%@NL@%
  2850.         sub     ch, ch%@NL@%
  2851.         add     ax, cx                  %@AB@%; AX = minutes from midnight%@AE@%%@NL@%
  2852.                                         %@AB@%;   to current time%@AE@%%@NL@%
  2853.         sub     bx, ax                  %@AB@%; BX = minutes to elapse before%@AE@%%@NL@%
  2854.         .IF     carry?                  %@AB@%; If activation is tomorrow:%@AE@%%@NL@%
  2855.         add     bx, 24 * 60             %@AB@%;  add number of minutes per day%@AE@%%@NL@%
  2856.         .ENDIF%@NL@%
  2857. %@NL@%
  2858.         mov     ax, 60%@NL@%
  2859.         mul     bx                      %@AB@%; DX:AX = minutes-to-elapse-times-60%@AE@%%@NL@%
  2860.         pop     bx                      %@AB@%; Recover current seconds%@AE@%%@NL@%
  2861.         sub     ax, bx                  %@AB@%; DX:AX = seconds to elapse before%@AE@%%@NL@%
  2862.         sbb     dx, 0                   %@AB@%;   activation%@AE@%%@NL@%
  2863.         .IF     carry?                  %@AB@%; If negative:%@AE@%%@NL@%
  2864.         mov     ax, 5                   %@AB@%; Assume 5 seconds%@AE@%%@NL@%
  2865.         cwd%@NL@%
  2866.         .ENDIF%@NL@%
  2867. %@NL@%
  2868.         mov     bx, 5                   %@AB@%; Divide result by 5 seconds%@AE@%%@NL@%
  2869.         div     bx                      %@AB@%; AX = number of 5-second intervals%@AE@%%@NL@%
  2870.         ret%@NL@%
  2871. %@NL@%
  2872. GetTimeToElapse ENDP%@NL@%
  2873. %@NL@%
  2874. %@NL@%
  2875. %@AB@%;* CallMultiplex - Calls the Multiplex Interrupt (Interrupt 2Fh).%@AE@%%@NL@%
  2876. %@AB@%;*%@AE@%%@NL@%
  2877. %@AB@%;* Uses:   IDstring%@AE@%%@NL@%
  2878. %@AB@%;*%@AE@%%@NL@%
  2879. %@AB@%;* Params: AL = Function number for multiplex handler%@AE@%%@NL@%
  2880. %@AB@%;*%@AE@%%@NL@%
  2881. %@AB@%;* Return: AX    = One of the following return codes:%@AE@%%@NL@%
  2882. %@AB@%;*                 NOT_INSTALLED      IS_INSTALLED       NO_IDNUM%@AE@%%@NL@%
  2883. %@AB@%;*         ES:DI = Resident code segment:identifier string (function 0)%@AE@%%@NL@%
  2884. %@AB@%;*         ES:DI = Resident PSP segment address (function 1)%@AE@%%@NL@%
  2885. %@AB@%;*         ES:DI = Far address of shared memory (function 2)%@AE@%%@NL@%
  2886. %@NL@%
  2887. CallMultiplex PROC FAR USES ds%@NL@%
  2888. %@NL@%
  2889.         push    ax                      %@AB@%; Save function number%@AE@%%@NL@%
  2890.         mov     ax, @code%@NL@%
  2891.         mov     ds, ax                  %@AB@%; Point DS to code segment%@AE@%%@NL@%
  2892. %@NL@%
  2893. %@AB@%; First, check 2Fh vector. DOS Version 2.x may leave the vector null%@AE@%%@NL@%
  2894. %@AB@%; if PRINT.COM is not installed. If vector is null, point it to IRET%@AE@%%@NL@%
  2895. %@AB@%; instruction at LABEL NoMultiplex. This allows the new multiplex%@AE@%%@NL@%
  2896. %@AB@%; handler to pass control, if necessary, to a proper existing routine.%@AE@%%@NL@%
  2897. %@NL@%
  2898.         mov     ax, 352Fh               %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
  2899.         int     21h                     %@AB@%; Get Interrupt Vector in ES:BX%@AE@%%@NL@%
  2900.         mov     ax, es%@NL@%
  2901.         or      ax, bx%@NL@%
  2902.         .IF     zero?                   %@AB@%; If Null vector:%@AE@%%@NL@%
  2903.         mov     dx, OFFSET NoMultiplex  %@AB@%; Set vector to IRET instruction%@AE@%%@NL@%
  2904.         mov     ax, 252Fh               %@AB@%;   at LABEL NoMultiplex%@AE@%%@NL@%
  2905.         int     21h                     %@AB@%; Set Interrupt Vector%@AE@%%@NL@%
  2906.         .ENDIF%@NL@%
  2907. %@NL@%
  2908. %@AB@%; Second, call Interrupt 2Fh with function 0 (presence request). Cycle%@AE@%%@NL@%
  2909. %@AB@%; through allowable identity numbers (192 to 255) until TSR's multiplex%@AE@%%@NL@%
  2910. %@AB@%; handler returns ES:DI = IDstring to verify its presence or until call%@AE@%%@NL@%
  2911. %@AB@%; returns AL = 0, indicating the TSR is not installed.%@AE@%%@NL@%
  2912. %@NL@%
  2913.         mov     dh, 192                 %@AB@%; Start with identity number = 192%@AE@%%@NL@%
  2914. %@NL@%
  2915.         .REPEAT%@NL@%
  2916.         mov     ah, dh                  %@AB@%; Call Multiplex with AH = trial ID%@AE@%%@NL@%
  2917.         sub     al, al                  %@AB@%;   and AL = function 0%@AE@%%@NL@%
  2918.         push    dx                      %@AB@%; Save DH and DS in case call%@AE@%%@NL@%
  2919.         push    ds                      %@AB@%;   destroys them%@AE@%%@NL@%
  2920.         int     2Fh                     %@AB@%; Multiplex%@AE@%%@NL@%
  2921.         pop     ds                      %@AB@%; Recover DS and%@AE@%%@NL@%
  2922.         pop     dx                      %@AB@%;   current ID number in DH%@AE@%%@NL@%
  2923.         or      al, al                  %@AB@%; Does a handler claim this ID number?%@AE@%%@NL@%
  2924.         jz      no                      %@AB@%; If not, stop search%@AE@%%@NL@%
  2925. %@NL@%
  2926.         .IF     al == 0FFh              %@AB@%; If handler ready to process calls:%@AE@%%@NL@%
  2927.         mov     si, OFFSET IDstring     %@AB@%; Point DS:SI to ID string, compare%@AE@%%@NL@%
  2928.         mov     cx, IDstrlen            %@AB@%;   with string at ES:DI returned%@AE@%%@NL@%
  2929.         repe    cmpsb                   %@AB@%;   by multiplex handler%@AE@%%@NL@%
  2930.         je      yes                     %@AB@%; If equal, TSR's handler is found%@AE@%%@NL@%
  2931.         .ENDIF%@NL@%
  2932. %@NL@%
  2933.         inc     dh                      %@AB@%; This handler is not the one%@AE@%%@NL@%
  2934.         .UNTIL  zero?                   %@AB@%; Try next identity number up to 255%@AE@%%@NL@%
  2935. %@NL@%
  2936.         mov     ax, NO_IDNUM            %@AB@%; In the unlikely event that numbers%@AE@%%@NL@%
  2937.         jmp     e_exit                  %@AB@%;   192-255 are all taken, quit%@AE@%%@NL@%
  2938. %@NL@%
  2939. %@AB@%; Third, assuming handler is found and verified, process the multiplex%@AE@%%@NL@%
  2940. %@AB@%; call with the requested function number.%@AE@%%@NL@%
  2941. %@NL@%
  2942. yes:%@NL@%
  2943.         pop     ax                      %@AB@%; AL = original function number%@AE@%%@NL@%
  2944.         mov     ah, dh                  %@AB@%; AH = identity number%@AE@%%@NL@%
  2945.         int     2Fh                     %@AB@%; Multiplex%@AE@%%@NL@%
  2946.         mov     ax, IS_INSTALLED        %@AB@%; Signal that handler has been found%@AE@%%@NL@%
  2947.         jmp     exit                    %@AB@%;   and quit%@AE@%%@NL@%
  2948. %@NL@%
  2949. %@AB@%; Reaching this section means multiplex handler (and TSR) not installed.%@AE@%%@NL@%
  2950. %@AB@%; Since the value in DH is not claimed by any handler, it will be used as%@AE@%%@NL@%
  2951. %@AB@%; the resident TSR's identity number.  Save the number in resident code%@AE@%%@NL@%
  2952. %@AB@%; segment so multiplex handler can find it.%@AE@%%@NL@%
  2953. %@NL@%
  2954. no:%@NL@%
  2955.         mov     IDnumber, dh            %@AB@%; Save multiplex identity number%@AE@%%@NL@%
  2956.         mov     ax, NOT_INSTALLED       %@AB@%; Signal handler is not installed%@AE@%%@NL@%
  2957. e_exit:%@NL@%
  2958.         pop     bx                      %@AB@%; Remove function number from stack%@AE@%%@NL@%
  2959. exit:%@NL@%
  2960.         ret%@NL@%
  2961. %@NL@%
  2962. CallMultiplex ENDP%@NL@%
  2963. %@NL@%
  2964. %@NL@%
  2965. %@AB@%;* InitTsr - Initializes DOS version variables and multiplex data with%@AE@%%@NL@%
  2966. %@AB@%;* following parameters. This procedure must execute before calling%@AE@%%@NL@%
  2967. %@AB@%;* either the Install, Deinstall, or CallMultiplex procedures. Callable%@AE@%%@NL@%
  2968. %@AB@%;* from a high-level language.%@AE@%%@NL@%
  2969. %@AB@%;*%@AE@%%@NL@%
  2970. %@AB@%;* Uses:   IDstring%@AE@%%@NL@%
  2971. %@AB@%;*%@AE@%%@NL@%
  2972. %@AB@%;* Params: PspParam - Segment address of PSP%@AE@%%@NL@%
  2973. %@AB@%;*         StrParam - Far address of TSR's identifier string%@AE@%%@NL@%
  2974. %@AB@%;*         ShrParam - Far address of shared memory%@AE@%%@NL@%
  2975. %@AB@%;*%@AE@%%@NL@%
  2976. %@AB@%;* Return: AX = WRONG_DOS if not DOS Version 2.0 or higher%@AE@%%@NL@%
  2977. %@NL@%
  2978. InitTsr PROC    FAR USES ds es si di,%@NL@%
  2979.         PspParam:WORD, StrParam:FPVOID, ShrParam:FPVOID%@NL@%
  2980. %@NL@%
  2981.         mov     ax, @code%@NL@%
  2982.         mov     ds, ax                          %@AB@%; Point DS and ES%@AE@%%@NL@%
  2983.         mov     es, ax                          %@AB@%;   to code segment%@AE@%%@NL@%
  2984. %@NL@%
  2985. %@AB@%; Get and store parameters passed from main program module%@AE@%%@NL@%
  2986. %@NL@%
  2987.         mov     ax, PspParam%@NL@%
  2988.         mov     TsrPspSeg, ax                   %@AB@%; Store PSP segment address%@AE@%%@NL@%
  2989. %@NL@%
  2990.         mov     ax, WORD PTR ShrParam[0]%@NL@%
  2991.         mov     bx, WORD PTR ShrParam[2]%@NL@%
  2992.         mov     WORD PTR ShareAddr[0], ax       %@AB@%; Store far address of%@AE@%%@NL@%
  2993.         mov     WORD PTR ShareAddr[2], bx       %@AB@%;   shared memory%@AE@%%@NL@%
  2994. %@NL@%
  2995.         push    ds%@NL@%
  2996.         mov     si, WORD PTR StrParam[0]        %@AB@%; DS:SI points to multiplex%@AE@%%@NL@%
  2997.         mov     ax, WORD PTR StrParam[2]        %@AB@%;   identifier string%@AE@%%@NL@%
  2998.         mov     ds, ax%@NL@%
  2999.         mov     di, OFFSET IDstring             %@AB@%; Copy string to IDstring%@AE@%%@NL@%
  3000.         mov     cx, STR_LEN                     %@AB@%;   at ES:DI so multiplex%@AE@%%@NL@%
  3001.                                                 %@AB@%;   handler has a copy%@AE@%%@NL@%
  3002.         .REPEAT%@NL@%
  3003.         lodsb                                   %@AB@%; Copy STR_LEN characters%@AE@%%@NL@%
  3004.         .BREAK .IF al == 0                      %@AB@%;   or until null-terminator%@AE@%%@NL@%
  3005.         stosb                                   %@AB@%;   found%@AE@%%@NL@%
  3006.         .UNTILCXZ%@NL@%
  3007. %@NL@%
  3008.         pop     ds                              %@AB@%; Recover DS = code segment%@AE@%%@NL@%
  3009.         mov     ax, STR_LEN%@NL@%
  3010.         sub     ax, cx%@NL@%
  3011.         mov     IDstrlen, ax                    %@AB@%; Store string length%@AE@%%@NL@%
  3012. %@NL@%
  3013.         INVOKE  GetVersion                      %@AB@%; Return AX = version number%@AE@%%@NL@%
  3014.         ret                                     %@AB@%;   or WRONG_DOS%@AE@%%@NL@%
  3015. %@NL@%
  3016. InitTsr ENDP%@NL@%
  3017. %@NL@%
  3018. %@NL@%
  3019. INSTALLCODE ENDS%@NL@%
  3020. %@NL@%
  3021.         END%@NL@%
  3022. %@NL@%
  3023. %@NL@%
  3024. %@2@%%@AH@%INSTALL.ASM%@AE@%%@EH@%%@NL@%
  3025. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\TSR\INSTALL.ASM%@AE@%%@NL@%
  3026. %@NL@%
  3027.         .MODEL  small, pascal, os_dos%@NL@%
  3028.         INCLUDE tsr.inc%@NL@%
  3029. %@NL@%
  3030. %@AB@%;* INSTALLATION SECTION - The following code and data are used only%@AE@%%@NL@%
  3031. %@AB@%;* during the TSR's installation phase. When the program terminates%@AE@%%@NL@%
  3032. %@AB@%;* through Function 31h, memory occupied by the following code and%@AE@%%@NL@%
  3033. %@AB@%;* data segments is returned to the operating system.%@AE@%%@NL@%
  3034. %@NL@%
  3035. DGROUP  GROUP INSTALLCODE, INSTALLDATA%@NL@%
  3036. %@NL@%
  3037. INSTALLDATA SEGMENT WORD PUBLIC 'DATA2' %@AB@%; Data segment for installation phase%@AE@%%@NL@%
  3038. %@NL@%
  3039.         PUBLIC  _MsgTbl%@NL@%
  3040. %@NL@%
  3041. _MsgTbl WORD    Msg0                    %@AB@%; Deinstalled okay%@AE@%%@NL@%
  3042.         WORD    Msg1                    %@AB@%; Installed okay%@AE@%%@NL@%
  3043.         WORD    Msg2                    %@AB@%; Already installed%@AE@%%@NL@%
  3044.         WORD    Msg3                    %@AB@%; Can't install%@AE@%%@NL@%
  3045.         WORD    Msg4                    %@AB@%; Can't find flag%@AE@%%@NL@%
  3046.         WORD    Msg5                    %@AB@%; Can't deinstall%@AE@%%@NL@%
  3047.         WORD    Msg6                    %@AB@%; Requires DOS 2+%@AE@%%@NL@%
  3048.         WORD    Msg7                    %@AB@%; MCB damaged%@AE@%%@NL@%
  3049.         WORD    Msg8                    %@AB@%; Invalid ID%@AE@%%@NL@%
  3050.         WORD    Msg9                    %@AB@%; Invalid memory block address%@AE@%%@NL@%
  3051.         WORD    Msg10                   %@AB@%; Successful access%@AE@%%@NL@%
  3052.         WORD    Msg11                   %@AB@%; Can't access%@AE@%%@NL@%
  3053.         WORD    Msg12                   %@AB@%; Unrecognized option%@AE@%%@NL@%
  3054. %@NL@%
  3055. Msg0    BYTE    CR, LF, "TSR deinstalled", CR, LF, 0%@NL@%
  3056. Msg1    BYTE    CR, LF, "TSR installed", CR, LF, 0%@NL@%
  3057. Msg2    BYTE    CR, LF, "TSR already installed", CR, LF, 0%@NL@%
  3058. Msg3    BYTE    CR, LF, "Can't install TSR", CR, LF, 0%@NL@%
  3059. Msg4    BYTE    CR, LF, "Can't find MS-DOS Critical Error Flag", CR, LF, 0%@NL@%
  3060. Msg5    BYTE    CR, LF, "Can't deinstall TSR", CR, LF, 0%@NL@%
  3061. Msg6    BYTE    CR, LF, "Requires MS-DOS 2.0 or later", CR, LF, 0%@NL@%
  3062. Msg7    BYTE    CR, LF, "Memory Control Block damaged", CR, LF, 0%@NL@%
  3063. Msg8    BYTE    CR, LF, "No ID numbers available", CR, LF, 0%@NL@%
  3064. Msg9    BYTE    CR, LF, "Can't free memory block:  invalid address", CR, LF,0%@NL@%
  3065. Msg10   BYTE    CR, LF, "TSR successfully accessed", CR, LF, 0%@NL@%
  3066. Msg11   BYTE    CR, LF, "Can't access:  TSR not installed", CR, LF, 0%@NL@%
  3067. Msg12   BYTE    CR, LF, "Unrecognized option", CR, LF, 0%@NL@%
  3068. %@NL@%
  3069. INSTALLDATA ENDS%@NL@%
  3070. %@NL@%
  3071. %@NL@%
  3072. INSTALLCODE SEGMENT PARA PUBLIC 'CODE2'%@NL@%
  3073. %@NL@%
  3074.         ASSUME  ds:@data%@NL@%
  3075. %@NL@%
  3076. %@AB@%;* GetOptions - Scans command line for argument of form /X or -X%@AE@%%@NL@%
  3077. %@AB@%;* where X = specified ASCII character. Presumes that argument is%@AE@%%@NL@%
  3078. %@AB@%;* preceded by either '/' or '-'. Comparisons are case-insensitive.%@AE@%%@NL@%
  3079. %@AB@%;* Designed to be callable only from an assembly language program.%@AE@%%@NL@%
  3080. %@AB@%;*%@AE@%%@NL@%
  3081. %@AB@%;* Params: ES = Segment address of Program Segment Prefix%@AE@%%@NL@%
  3082. %@AB@%;*         AL = Argument character for which to scan%@AE@%%@NL@%
  3083. %@AB@%;*%@AE@%%@NL@%
  3084. %@AB@%;* Return: AX    = One of the following codes:%@AE@%%@NL@%
  3085. %@AB@%;*                 NO_ARGUMENT  if empty command line%@AE@%%@NL@%
  3086. %@AB@%;*                 OK_ARGUMENT  if argument found%@AE@%%@NL@%
  3087. %@AB@%;*                 BAD_ARGUMENT if argument not as specified%@AE@%%@NL@%
  3088. %@AB@%;*         ES:DI = Pointer to found argument%@AE@%%@NL@%
  3089. %@NL@%
  3090. GetOptions PROC NEAR%@NL@%
  3091. %@NL@%
  3092.         and     al, 11011111y           %@AB@%; Make character upper-case%@AE@%%@NL@%
  3093.         mov     ah, NO_ARGUMENT         %@AB@%; Assume no argument%@AE@%%@NL@%
  3094.         mov     di, 80h                 %@AB@%; Point to command line%@AE@%%@NL@%
  3095.         sub     ch, ch%@NL@%
  3096.         mov     cl, BYTE PTR es:[di]    %@AB@%; Command-line count%@AE@%%@NL@%
  3097.         jcxz    exit                    %@AB@%; If none, quit%@AE@%%@NL@%
  3098.         sub     bx, bx                  %@AB@%; Initialize flag%@AE@%%@NL@%
  3099. %@NL@%
  3100. %@AB@%; Find start of argument%@AE@%%@NL@%
  3101. %@NL@%
  3102. loop1:%@NL@%
  3103.         inc     di                      %@AB@%; Point to next character%@AE@%%@NL@%
  3104.         mov     dl, es:[di]             %@AB@%; Get character from argument list%@AE@%%@NL@%
  3105.         cmp     dl, '/'                 %@AB@%; Find option prefix '/'%@AE@%%@NL@%
  3106.         je      analyze%@NL@%
  3107.         cmp     dl, '-'                 %@AB@%;   or option prefix '-'%@AE@%%@NL@%
  3108.         je      analyze%@NL@%
  3109.         .IF     (dl != ' ') && (dl != TAB ) %@AB@%; If not white space:%@AE@%%@NL@%
  3110.         inc     bx                      %@AB@%; Set flag if command line not empty%@AE@%%@NL@%
  3111.         .ENDIF%@NL@%
  3112. %@NL@%
  3113.         loop    loop1%@NL@%
  3114. %@NL@%
  3115.         or      bx, bx                  %@AB@%; Empty command line?%@AE@%%@NL@%
  3116.         jz      exit                    %@AB@%; Yes?  Normal exit%@AE@%%@NL@%
  3117.         jmp     SHORT e_exit            %@AB@%; Error if no argument is preceded%@AE@%%@NL@%
  3118.                                         %@AB@%;    by '-' or '/' prefixes%@AE@%%@NL@%
  3119. %@NL@%
  3120. %@AB@%; '/' or '-' prefix found. Compare command-line character%@AE@%%@NL@%
  3121. %@AB@%; with character specified in AL.%@AE@%%@NL@%
  3122. analyze:%@NL@%
  3123.         mov     ah, OK_ARGUMENT         %@AB@%; Assume argument is okay%@AE@%%@NL@%
  3124.         inc     di%@NL@%
  3125.         mov     dl, es:[di]%@NL@%
  3126.         and     dl, 11011111y           %@AB@%; Convert to upper-case%@AE@%%@NL@%
  3127.         cmp     dl, al                  %@AB@%; Argument as specified?%@AE@%%@NL@%
  3128.         je      exit                    %@AB@%; If so, normal exit%@AE@%%@NL@%
  3129.         mov     ah, BAD_ARGUMENT        %@AB@%; Else signal bad argument,%@AE@%%@NL@%
  3130.         inc     bx                      %@AB@%;   raise flag, and%@AE@%%@NL@%
  3131.         jmp     loop1                   %@AB@%;   continue scan%@AE@%%@NL@%
  3132. %@NL@%
  3133. e_exit:%@NL@%
  3134.         mov     ah, BAD_ARGUMENT%@NL@%
  3135. exit:%@NL@%
  3136.         mov     al, ah%@NL@%
  3137.         cbw                             %@AB@%; AX = return code%@AE@%%@NL@%
  3138.         ret%@NL@%
  3139. %@NL@%
  3140. GetOptions ENDP%@NL@%
  3141. %@NL@%
  3142. %@NL@%
  3143. %@AB@%;* FatalError - Displays an error message and exits to DOS.%@AE@%%@NL@%
  3144. %@AB@%;* Callable from a high-level language.%@AE@%%@NL@%
  3145. %@AB@%;*%@AE@%%@NL@%
  3146. %@AB@%;* Params: Err = Error number%@AE@%%@NL@%
  3147. %@AB@%;*%@AE@%%@NL@%
  3148. %@AB@%;* Return: AL = Error number returned to DOS (except DOS 1.x)%@AE@%%@NL@%
  3149. %@NL@%
  3150. FatalError PROC FAR,%@NL@%
  3151.         Err:WORD%@NL@%
  3152. %@NL@%
  3153.         mov     ax, Err%@NL@%
  3154.         push    ax%@NL@%
  3155.         mov     bx, @data%@NL@%
  3156.         mov     ds, bx                  %@AB@%; DS points to DGROUP%@AE@%%@NL@%
  3157.         mov     bx, OFFSET _MsgTbl%@NL@%
  3158.         shl     ax, 1                   %@AB@%; Double to get offset into _MsgTbl%@AE@%%@NL@%
  3159.         add     bx, ax                  %@AB@%; BX = table index%@AE@%%@NL@%
  3160.         mov     si, [bx]                %@AB@%; DS:SI points to message%@AE@%%@NL@%
  3161.         sub     bx, bx                  %@AB@%; BH = page 0%@AE@%%@NL@%
  3162.         mov     ah, 0Eh                 %@AB@%; Request video Function 0Eh%@AE@%%@NL@%
  3163. %@NL@%
  3164.         .WHILE  1%@NL@%
  3165.         lodsb                           %@AB@%; Get character from ASCIIZ string%@AE@%%@NL@%
  3166.         .BREAK .IF al == 0              %@AB@%; Break if null terminator%@AE@%%@NL@%
  3167.         int     10h                     %@AB@%; Display text, advance cursor%@AE@%%@NL@%
  3168.         .ENDW%@NL@%
  3169. %@NL@%
  3170.         pop     ax                      %@AB@%; Recover original error code%@AE@%%@NL@%
  3171. %@NL@%
  3172.         .IF     ax == WRONG_DOS         %@AB@%; If DOS error:%@AE@%%@NL@%
  3173.         int     20h                     %@AB@%; Terminate Program (Version 1.x)%@AE@%%@NL@%
  3174.         .ELSE                           %@AB@%; Else:%@AE@%%@NL@%
  3175.         mov     ah, 4Ch                 %@AB@%; Request DOS Function 4Ch%@AE@%%@NL@%
  3176.         int     21h                     %@AB@%; Terminate Program (2.x and later)%@AE@%%@NL@%
  3177.         .ENDIF%@NL@%
  3178. %@NL@%
  3179. FatalError ENDP%@NL@%
  3180. %@NL@%
  3181. %@NL@%
  3182. %@AB@%;* KeepTsr -  Calls Terminate-and-Stay-Resident function to%@AE@%%@NL@%
  3183. %@AB@%;* make TSR resident. Callable from a high-level language.%@AE@%%@NL@%
  3184. %@AB@%;*%@AE@%%@NL@%
  3185. %@AB@%;* Params:  ParaNum - Number of paragraphs in resident block%@AE@%%@NL@%
  3186. %@AB@%;*%@AE@%%@NL@%
  3187. %@AB@%;* Return:  DOS return code = 0%@AE@%%@NL@%
  3188. %@NL@%
  3189. KeepTsr PROC    FAR,%@NL@%
  3190.         ParaNum:WORD%@NL@%
  3191. %@NL@%
  3192.         mov     ax, @data%@NL@%
  3193.         mov     ds, ax                  %@AB@%; DS:SI points to "Program%@AE@%%@NL@%
  3194.         mov     si, OFFSET Msg1         %@AB@%;   installed" message%@AE@%%@NL@%
  3195.         sub     bx, bx                  %@AB@%; BH = page 0%@AE@%%@NL@%
  3196.         mov     ah, 0Eh                 %@AB@%; Request video Function 0Eh%@AE@%%@NL@%
  3197. %@NL@%
  3198.         .WHILE  1%@NL@%
  3199.         lodsb                           %@AB@%; Get character from ASCIIZ string%@AE@%%@NL@%
  3200.         .BREAK .IF al == 0              %@AB@%; Break if null terminator%@AE@%%@NL@%
  3201.         int     10h                     %@AB@%; Display text, advance cursor%@AE@%%@NL@%
  3202.         .ENDW%@NL@%
  3203. %@NL@%
  3204.         mov     dx, ParaNum             %@AB@%; DX = number of paragraphs%@AE@%%@NL@%
  3205.         mov     ax, 3100h               %@AB@%; Request Function 31h, err code = 0%@AE@%%@NL@%
  3206.         int     21h                     %@AB@%; Terminate-and-Stay-Resident%@AE@%%@NL@%
  3207.         ret%@NL@%
  3208. %@NL@%
  3209. KeepTsr ENDP%@NL@%
  3210. %@NL@%
  3211. %@NL@%
  3212. %@AB@%;* FreeTsr - Deinstalls TSR by freeing its two memory blocks: program%@AE@%%@NL@%
  3213. %@AB@%;* block (located at PSP) and environment block (located from address%@AE@%%@NL@%
  3214. %@AB@%;* at offset 2Ch of PSP). Callable from a high-level language.%@AE@%%@NL@%
  3215. %@AB@%;*%@AE@%%@NL@%
  3216. %@AB@%;* Params:  PspSeg - Segment address of TSR's Program Segment Prefix%@AE@%%@NL@%
  3217. %@AB@%;*%@AE@%%@NL@%
  3218. %@AB@%;* Return:  AX = 0 if successful, or one of the following error codes:%@AE@%%@NL@%
  3219. %@AB@%;*          MCB_DESTROYED       if Memory Control Block damaged%@AE@%%@NL@%
  3220. %@AB@%;*          INVALID_ADDR        if invalid block address%@AE@%%@NL@%
  3221. %@NL@%
  3222. FreeTsr PROC    FAR,%@NL@%
  3223.         PspSeg:WORD%@NL@%
  3224. %@NL@%
  3225.         mov     es, PspSeg              %@AB@%; ES = address of resident PSP%@AE@%%@NL@%
  3226.         mov     ah, 49h                 %@AB@%; Request DOS Function 49h%@AE@%%@NL@%
  3227.         int     21h                     %@AB@%; Release Memory in program block%@AE@%%@NL@%
  3228. %@NL@%
  3229.         .IF     !carry?                 %@AB@%; If no error:%@AE@%%@NL@%
  3230.         mov     es, es:[2Ch]            %@AB@%; ES = address of environment block%@AE@%%@NL@%
  3231.         mov     ah, 49h                 %@AB@%; Request DOS Function 49h%@AE@%%@NL@%
  3232.         int     21h                     %@AB@%; Release Memory in environment block%@AE@%%@NL@%
  3233.         .IF     !carry?                 %@AB@%; If no error:%@AE@%%@NL@%
  3234.         sub     ax, ax                  %@AB@%; Return AX = 0%@AE@%%@NL@%
  3235.         .ENDIF                          %@AB@%; Else exit with AX = error code%@AE@%%@NL@%
  3236.         .ENDIF%@NL@%
  3237. %@NL@%
  3238.         ret%@NL@%
  3239. %@NL@%
  3240. FreeTsr ENDP%@NL@%
  3241. %@NL@%
  3242. %@NL@%
  3243. %@AB@%;* CallMultiplexC - Interface for CallMultiplex procedure to make it%@AE@%%@NL@%
  3244. %@AB@%;* callable from a high-level language. Separating this ability from%@AE@%%@NL@%
  3245. %@AB@%;* the original CallMultiplex procedure keeps assembly-language calls%@AE@%%@NL@%
  3246. %@AB@%;* to CallMultiplex neater and more concise.%@AE@%%@NL@%
  3247. %@AB@%;*%@AE@%%@NL@%
  3248. %@AB@%;* Params: FuncNum - Function number for multiplex handler%@AE@%%@NL@%
  3249. %@AB@%;*         RecvPtr - Far address to recieve ES:DI pointer%@AE@%%@NL@%
  3250. %@AB@%;*%@AE@%%@NL@%
  3251. %@AB@%;* Return: One of the following return codes:%@AE@%%@NL@%
  3252. %@AB@%;*              NOT_INSTALLED      IS_INSTALLED       NO_IDNUM%@AE@%%@NL@%
  3253. %@AB@%;*         ES:DI pointer written to address in RecvPtr%@AE@%%@NL@%
  3254. %@NL@%
  3255. CallMultiplexC PROC FAR USES ds si di,%@NL@%
  3256.         FuncNum:WORD, RecvPtr:FPVOID%@NL@%
  3257. %@NL@%
  3258.         mov     al, BYTE PTR FuncNum    %@AB@%; AL = function number%@AE@%%@NL@%
  3259.         call    CallMultiplex           %@AB@%; Multiplex%@AE@%%@NL@%
  3260. %@NL@%
  3261.         lds     si, RecvPtr             %@AB@%; DS:SI = far address of pointer%@AE@%%@NL@%
  3262.         mov     [si], di                %@AB@%; Return ES:DI pointer for the%@AE@%%@NL@%
  3263.         mov     [si+2], es              %@AB@%;   benefit of high-level callers%@AE@%%@NL@%
  3264.         ret%@NL@%
  3265. %@NL@%
  3266. CallMultiplexC ENDP%@NL@%
  3267. %@NL@%
  3268. %@NL@%
  3269. %@AB@%;* GetResidentSize - Returns the number of paragraphs between Program%@AE@%%@NL@%
  3270. %@AB@%;* Segment Prefix and beginning of INSTALLCODE. This routine allows%@AE@%%@NL@%
  3271. %@AB@%;* TSRs written in a high-level language to determine the size in%@AE@%%@NL@%
  3272. %@AB@%;* paragraphs required to make the program resident.%@AE@%%@NL@%
  3273. %@AB@%;*%@AE@%%@NL@%
  3274. %@AB@%;* Params: PspSeg - PSP segment address%@AE@%%@NL@%
  3275. %@AB@%;*%@AE@%%@NL@%
  3276. %@AB@%;* Return: AX = Number of paragraphs%@AE@%%@NL@%
  3277. %@NL@%
  3278. GetResidentSize PROC FAR,%@NL@%
  3279.         PspSeg:WORD%@NL@%
  3280. %@NL@%
  3281.         mov     ax, INSTALLCODE         %@AB@%; Bottom of resident section%@AE@%%@NL@%
  3282.         sub     ax, PspSeg              %@AB@%; AX = number of paragraphs in%@AE@%%@NL@%
  3283.         ret                             %@AB@%;   block to be made resident%@AE@%%@NL@%
  3284. %@NL@%
  3285. GetResidentSize ENDP%@NL@%
  3286. %@NL@%
  3287. %@NL@%
  3288. INSTALLCODE ENDS%@NL@%
  3289. %@NL@%
  3290.         END%@NL@%
  3291. %@NL@%
  3292. %@NL@%
  3293. %@2@%%@AH@%MATH.ASM%@AE@%%@EH@%%@NL@%
  3294. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\DEMOS\MATH.ASM%@AE@%%@NL@%
  3295. %@NL@%
  3296.         .MODEL  small, pascal, os_dos%@NL@%
  3297.         INCLUDE demo.inc%@NL@%
  3298.         .CODE%@NL@%
  3299. %@NL@%
  3300. %@AB@%;* AddLong - Adds two double-word (long) integers.%@AE@%%@NL@%
  3301. %@AB@%;*%@AE@%%@NL@%
  3302. %@AB@%;* Shows:   Instructions - add     adc%@AE@%%@NL@%
  3303. %@AB@%;*          Operator - PTR%@AE@%%@NL@%
  3304. %@AB@%;*%@AE@%%@NL@%
  3305. %@AB@%;* Params:  Long1 - First integer%@AE@%%@NL@%
  3306. %@AB@%;*          Long2 - Second integer%@AE@%%@NL@%
  3307. %@AB@%;*%@AE@%%@NL@%
  3308. %@AB@%;* Return:  Sum as long integer%@AE@%%@NL@%
  3309. %@NL@%
  3310. AddLong PROC,%@NL@%
  3311.         Long1:SDWORD, Long2:SDWORD%@NL@%
  3312. %@NL@%
  3313.         mov     ax, WORD PTR Long1[0]   %@AB@%; AX = low word, long1%@AE@%%@NL@%
  3314.         mov     dx, WORD PTR Long1[2]   %@AB@%; DX = high word, long1%@AE@%%@NL@%
  3315.         add     ax, WORD PTR Long2[0]   %@AB@%; Add low word, long2%@AE@%%@NL@%
  3316.         adc     dx, WORD PTR Long2[2]   %@AB@%; Add high word, long2%@AE@%%@NL@%
  3317.         ret                             %@AB@%; Result returned as DX:AX%@AE@%%@NL@%
  3318. %@NL@%
  3319. AddLong ENDP%@NL@%
  3320. %@NL@%
  3321. %@AB@%;* SubLong - Subtracts a double-word (long) integer from another.%@AE@%%@NL@%
  3322. %@AB@%;*%@AE@%%@NL@%
  3323. %@AB@%;* Shows:   Instructions -  sub     sbb%@AE@%%@NL@%
  3324. %@AB@%;*%@AE@%%@NL@%
  3325. %@AB@%;* Params:  Long1 - First integer%@AE@%%@NL@%
  3326. %@AB@%;*          Long2 - Second integer%@AE@%%@NL@%
  3327. %@AB@%;*%@AE@%%@NL@%
  3328. %@AB@%;* Return:  Difference as long integer%@AE@%%@NL@%
  3329. %@NL@%
  3330. SubLong PROC,%@NL@%
  3331.         Long1:SDWORD, Long2:SDWORD%@NL@%
  3332. %@NL@%
  3333.         mov     ax, WORD PTR Long1[0]   %@AB@%; AX = low word, long1%@AE@%%@NL@%
  3334.         mov     dx, WORD PTR Long1[2]   %@AB@%; DX = high word, long1%@AE@%%@NL@%
  3335.         sub     ax, WORD PTR Long2[0]   %@AB@%; Subtract low word, long2%@AE@%%@NL@%
  3336.         sbb     dx, WORD PTR Long2[2]   %@AB@%; Subtract high word, long2%@AE@%%@NL@%
  3337.         ret                             %@AB@%; Result returned as DX:AX%@AE@%%@NL@%
  3338. %@NL@%
  3339. SubLong ENDP%@NL@%
  3340. %@NL@%
  3341. %@NL@%
  3342. %@AB@%;* MulLong - Multiplies two unsigned double-word (long) integers. The%@AE@%%@NL@%
  3343. %@AB@%;* procedure allows for a product of twice the length of the multipliers,%@AE@%%@NL@%
  3344. %@AB@%;* thus preventing overflows. The result is copied into a 4-word data area%@AE@%%@NL@%
  3345. %@AB@%;* and a pointer to the data area is returned.%@AE@%%@NL@%
  3346. %@AB@%;*%@AE@%%@NL@%
  3347. %@AB@%;* Shows:   Instruction - mul%@AE@%%@NL@%
  3348. %@AB@%;*          Predefined equate - @data%@AE@%%@NL@%
  3349. %@AB@%;*%@AE@%%@NL@%
  3350. %@AB@%;* Params:  Long1 - First integer (multiplicand)%@AE@%%@NL@%
  3351. %@AB@%;*          Long2 - Second integer (multiplier)%@AE@%%@NL@%
  3352. %@AB@%;*%@AE@%%@NL@%
  3353. %@AB@%;* Return:  Pointer to quadword result%@AE@%%@NL@%
  3354. %@NL@%
  3355.         .DATA%@NL@%
  3356.         PUBLIC result%@NL@%
  3357. result  QWORD   WORD PTR ?              %@AB@%; Result from MulLong%@AE@%%@NL@%
  3358. %@NL@%
  3359.         .CODE%@NL@%
  3360. MulLong PROC,%@NL@%
  3361.         Long1:DWORD, Long2:DWORD%@NL@%
  3362. %@NL@%
  3363.         mov     ax, WORD PTR Long2[2]   %@AB@%; Multiply long2 high word%@AE@%%@NL@%
  3364.         mul     WORD PTR Long1[2]       %@AB@%;   by long1 high word%@AE@%%@NL@%
  3365.         mov     WORD PTR result[4], ax%@NL@%
  3366.         mov     WORD PTR result[6], dx%@NL@%
  3367. %@NL@%
  3368.         mov     ax, WORD PTR Long2[2]   %@AB@%; Multiply long2 high word%@AE@%%@NL@%
  3369.         mul     WORD PTR Long1[0]       %@AB@%;   by long1 low word%@AE@%%@NL@%
  3370.         mov     WORD PTR result[2], ax%@NL@%
  3371.         add     WORD PTR result[4], dx%@NL@%
  3372.         adc     WORD PTR result[6], 0   %@AB@%; Add any remnant carry%@AE@%%@NL@%
  3373. %@NL@%
  3374.         mov     ax, WORD PTR Long2[0]   %@AB@%; Multiply long2 low word%@AE@%%@NL@%
  3375.         mul     WORD PTR Long1[2]       %@AB@%;   by long1 high word%@AE@%%@NL@%
  3376.         add     WORD PTR result[2], ax%@NL@%
  3377.         adc     WORD PTR result[4], dx%@NL@%
  3378.         adc     WORD PTR result[6], 0   %@AB@%; Add any remnant carry%@AE@%%@NL@%
  3379. %@NL@%
  3380.         mov     ax, WORD PTR Long2[0]   %@AB@%; Multiply long2 low word%@AE@%%@NL@%
  3381.         mul     WORD PTR Long1[0]       %@AB@%;   by long1 low word%@AE@%%@NL@%
  3382.         mov     WORD PTR result[0], ax%@NL@%
  3383.         add     WORD PTR result[2], dx%@NL@%
  3384.         adc     WORD PTR result[4], 0   %@AB@%; Add any remnant carry%@AE@%%@NL@%
  3385. %@NL@%
  3386.         mov     ax, OFFSET result       %@AB@%; Return pointer%@AE@%%@NL@%
  3387.         mov     dx, @data               %@AB@%;   to result%@AE@%%@NL@%
  3388.         ret%@NL@%
  3389. %@NL@%
  3390. MulLong ENDP%@NL@%
  3391. %@NL@%
  3392. %@NL@%
  3393. %@AB@%;* ImulLong - Multiplies two signed double-word integers. Because the imul%@AE@%%@NL@%
  3394. %@AB@%;* instruction (illustrated here) treats each word as a signed number, its%@AE@%%@NL@%
  3395. %@AB@%;* use is impractical when multiplying multi-word values. Thus the technique%@AE@%%@NL@%
  3396. %@AB@%;* used in the MulLong procedure can't be adopted here. Instead, ImulLong%@AE@%%@NL@%
  3397. %@AB@%;* is broken into three sections arranged in ascending order of computational%@AE@%%@NL@%
  3398. %@AB@%;* overhead. The procedure tests the values of the two integers and selects%@AE@%%@NL@%
  3399. %@AB@%;* the section that involves the minimum required effort to multiply them.%@AE@%%@NL@%
  3400. %@AB@%;*%@AE@%%@NL@%
  3401. %@AB@%;* Shows:   Instruction - imul%@AE@%%@NL@%
  3402. %@AB@%;*%@AE@%%@NL@%
  3403. %@AB@%;* Params:  Long1 - First integer (multiplicand)%@AE@%%@NL@%
  3404. %@AB@%;*          Long2 - Second integer (multiplier)%@AE@%%@NL@%
  3405. %@AB@%;*%@AE@%%@NL@%
  3406. %@AB@%;* Return:  Result as long integer%@AE@%%@NL@%
  3407. %@NL@%
  3408. ImulLong PROC USES si,%@NL@%
  3409.         Long1:SDWORD, Long2:SDWORD%@NL@%
  3410. %@NL@%
  3411. %@AB@%; Section 1 tests for integers in the range of 0 to 65,535. If both%@AE@%%@NL@%
  3412. %@AB@%; numbers are within these limits, they're treated as unsigned short%@AE@%%@NL@%
  3413. %@AB@%; integers.%@AE@%%@NL@%
  3414. %@NL@%
  3415.         mov     ax, WORD PTR Long2[0]   %@AB@%; AX = low word of long2%@AE@%%@NL@%
  3416.         mov     dx, WORD PTR Long2[2]   %@AB@%; DX = high word of long2%@AE@%%@NL@%
  3417.         mov     bx, WORD PTR Long1[0]   %@AB@%; BX = low word of long1%@AE@%%@NL@%
  3418.         mov     cx, WORD PTR Long1[2]   %@AB@%; CX = high word of long1%@AE@%%@NL@%
  3419.         .IF     (dx == 0) && (cx == 0)  %@AB@%; If both high words are zero:%@AE@%%@NL@%
  3420.         mul     bx                      %@AB@%;   Multiply the low words%@AE@%%@NL@%
  3421.         jmp     exit                    %@AB@%;   and exit section 1%@AE@%%@NL@%
  3422.         .ENDIF%@NL@%
  3423. %@NL@%
  3424. %@AB@%; Section 2 tests for integers in the range of -32,768 to 32,767. If%@AE@%%@NL@%
  3425. %@AB@%; both numbers are within these limits, they're treated as signed short%@AE@%%@NL@%
  3426. %@AB@%; integers.%@AE@%%@NL@%
  3427. %@NL@%
  3428.         push    ax                      %@AB@%; Save long2 low word%@AE@%%@NL@%
  3429.         push    bx                      %@AB@%; Save long1 low word%@AE@%%@NL@%
  3430.         or      dx, dx                  %@AB@%; High word of long2 = 0?%@AE@%%@NL@%
  3431.         jnz     notzhi2                 %@AB@%; No?  Test for negative%@AE@%%@NL@%
  3432.         test    ah, 80h                 %@AB@%; Low word of long2 in range?%@AE@%%@NL@%
  3433.         jz      notnlo2                 %@AB@%; Yes?  long2 ok, so test long1%@AE@%%@NL@%
  3434.         jmp     sect3                   %@AB@%; No?  Go to section 3%@AE@%%@NL@%
  3435. notzhi2:%@NL@%
  3436.         cmp     dx, 0FFFFh              %@AB@%; Empty with sign flag set?%@AE@%%@NL@%
  3437.         jne     sect3                   %@AB@%; No?  Go to section 3%@AE@%%@NL@%
  3438.         test    ah, 80h                 %@AB@%; High bit set in low word?%@AE@%%@NL@%
  3439.         jz      sect3                   %@AB@%; No?  Low word is too high%@AE@%%@NL@%
  3440. notnlo2:%@NL@%
  3441.         or      cx, cx                  %@AB@%; High word of long1 = 0?%@AE@%%@NL@%
  3442.         jnz     notzhi1                 %@AB@%; No?  Test for negative%@AE@%%@NL@%
  3443.         test    bh, 80h                 %@AB@%; Low word of long1 in range?%@AE@%%@NL@%
  3444.         jz      notnlo1                 %@AB@%; Yes?  long1 ok, so use sect 2%@AE@%%@NL@%
  3445.         jmp     sect3                   %@AB@%; No?  Go to section 3%@AE@%%@NL@%
  3446. notzhi1:%@NL@%
  3447.         cmp     cx, 0FFFFh              %@AB@%; Empty with sign flag set?%@AE@%%@NL@%
  3448.         jne     sect3                   %@AB@%; No?  Go to section 3%@AE@%%@NL@%
  3449.         test    bh, 80h                 %@AB@%; High bit set in low word?%@AE@%%@NL@%
  3450.         jz      sect3                   %@AB@%; No?  Low word is too high%@AE@%%@NL@%
  3451. notnlo1:%@NL@%
  3452.         imul    bx                      %@AB@%; Multiply low words%@AE@%%@NL@%
  3453.         pop     bx                      %@AB@%; Clean stack%@AE@%%@NL@%
  3454.         pop     bx%@NL@%
  3455.         jmp     exit                    %@AB@%; Exit section 2%@AE@%%@NL@%
  3456. %@NL@%
  3457. %@AB@%; Section 3 involves the most computational overhead. It treats the two%@AE@%%@NL@%
  3458. %@AB@%; numbers as signed long (double-word) integers.%@AE@%%@NL@%
  3459. %@NL@%
  3460. sect3:%@NL@%
  3461.         pop     bx                      %@AB@%; Recover long1 low word%@AE@%%@NL@%
  3462.         pop     ax                      %@AB@%; Recover long2 low word%@AE@%%@NL@%
  3463.         mov     si, dx                  %@AB@%; SI = long2 high word%@AE@%%@NL@%
  3464.         push    ax                      %@AB@%; Save long2 low word%@AE@%%@NL@%
  3465.         mul     cx                      %@AB@%; long1 high word x long2 low word%@AE@%%@NL@%
  3466.         mov     cx, ax                  %@AB@%; Accumulate products in CX%@AE@%%@NL@%
  3467.         mov     ax, bx                  %@AB@%; AX = low word of long1%@AE@%%@NL@%
  3468.         mul     si                      %@AB@%; Multiply by long2 high word%@AE@%%@NL@%
  3469.         add     cx, ax                  %@AB@%; Add to previous product%@AE@%%@NL@%
  3470.         pop     ax                      %@AB@%; Recover long2 low word%@AE@%%@NL@%
  3471.         mul     bx                      %@AB@%; Multiply by long1 low word%@AE@%%@NL@%
  3472.         add     dx, cx                  %@AB@%; Add to product high word%@AE@%%@NL@%
  3473. exit:%@NL@%
  3474.         ret                             %@AB@%; Return result as DX:AX%@AE@%%@NL@%
  3475. %@NL@%
  3476. ImulLong ENDP%@NL@%
  3477. %@NL@%
  3478. %@NL@%
  3479. %@AB@%;* DivLong - Divides an unsigned long integer by an unsigned short integer.%@AE@%%@NL@%
  3480. %@AB@%;* The procedure does not check for overflow or divide-by-zero.%@AE@%%@NL@%
  3481. %@AB@%;*%@AE@%%@NL@%
  3482. %@AB@%;* Shows:   Instruction -  div%@AE@%%@NL@%
  3483. %@AB@%;*%@AE@%%@NL@%
  3484. %@AB@%;* Params:  Long1 - First integer (dividend)%@AE@%%@NL@%
  3485. %@AB@%;*          Short2 - Second integer (divisor)%@AE@%%@NL@%
  3486. %@AB@%;*          Remn - Pointer to remainder%@AE@%%@NL@%
  3487. %@AB@%;*%@AE@%%@NL@%
  3488. %@AB@%;* Return:  Quotient as short integer%@AE@%%@NL@%
  3489. %@NL@%
  3490. DivLong PROC USES di,%@NL@%
  3491.         Long1:DWORD, Short2:WORD, Remn:PWORD%@NL@%
  3492. %@NL@%
  3493.         mov     ax, WORD PTR Long1[0]   %@AB@%; AX = low word of dividend%@AE@%%@NL@%
  3494.         mov     dx, WORD PTR Long1[2]   %@AB@%; DX = high word of dividend%@AE@%%@NL@%
  3495.         div     Short2                  %@AB@%; Divide by short integer%@AE@%%@NL@%
  3496.         LoadPtr es, di, Remn            %@AB@%; Point ES:DI to remainder%@AE@%%@NL@%
  3497.         mov     es:[di], dx             %@AB@%; Copy remainder%@AE@%%@NL@%
  3498.         ret                             %@AB@%; Return with AX = quotient%@AE@%%@NL@%
  3499. %@NL@%
  3500. DivLong ENDP%@NL@%
  3501. %@NL@%
  3502. %@NL@%
  3503. %@AB@%;* IdivLong - Divides a signed long integer by a signed short integer.%@AE@%%@NL@%
  3504. %@AB@%;* The procedure does not check for overflow or divide-by-zero.%@AE@%%@NL@%
  3505. %@AB@%;*%@AE@%%@NL@%
  3506. %@AB@%;* Shows:   Instruction - idiv%@AE@%%@NL@%
  3507. %@AB@%;*%@AE@%%@NL@%
  3508. %@AB@%;* Params:  Long1 - First integer (dividend)%@AE@%%@NL@%
  3509. %@AB@%;*          Short2 - Second integer (divisor)%@AE@%%@NL@%
  3510. %@AB@%;*          Remn - Pointer to remainder%@AE@%%@NL@%
  3511. %@AB@%;*%@AE@%%@NL@%
  3512. %@AB@%;* Return:  Quotient as short integer%@AE@%%@NL@%
  3513. %@NL@%
  3514. IdivLong PROC USES di,%@NL@%
  3515.         Long1:SDWORD, Short2:SWORD, Remn:PSWORD%@NL@%
  3516. %@NL@%
  3517.         mov     ax, WORD PTR Long1[0]   %@AB@%; AX = low word of dividend%@AE@%%@NL@%
  3518.         mov     dx, WORD PTR Long1[2]   %@AB@%; DX = high word of dividend%@AE@%%@NL@%
  3519.         idiv    Short2                  %@AB@%; Divide by short integer%@AE@%%@NL@%
  3520.         LoadPtr es, di, Remn            %@AB@%; ES:DI = remainder%@AE@%%@NL@%
  3521.         mov     es:[di], dx             %@AB@%; Copy remainder%@AE@%%@NL@%
  3522.         ret                             %@AB@%; Return with AX = quotient%@AE@%%@NL@%
  3523. %@NL@%
  3524. IdivLong ENDP%@NL@%
  3525. %@NL@%
  3526. %@NL@%
  3527. %@AB@%;* Quadratic - Solves for the roots of a quadratic equation of form%@AE@%%@NL@%
  3528. %@AB@%;*                        A*x*x + B*x + C = 0%@AE@%%@NL@%
  3529. %@AB@%;* using floating-point instructions. This procedure requires either a math%@AE@%%@NL@%
  3530. %@AB@%;* coprocessor or emulation code.%@AE@%%@NL@%
  3531. %@AB@%;*%@AE@%%@NL@%
  3532. %@AB@%;* Shows:   Instructions - sahf     fld1     fld     fadd     fmul%@AE@%%@NL@%
  3533. %@AB@%;*                         fxch     fsubr    fchs    fsubp    fstp%@AE@%%@NL@%
  3534. %@AB@%;*                         fst      fstsw    fdivr   fwait    ftst%@AE@%%@NL@%
  3535. %@AB@%;*%@AE@%%@NL@%
  3536. %@AB@%;* Params:  a - Constant for 2nd-order term%@AE@%%@NL@%
  3537. %@AB@%;*          b - Constant for 1st-order term%@AE@%%@NL@%
  3538. %@AB@%;*          c - Equation constant%@AE@%%@NL@%
  3539. %@AB@%;*          R1 - Pointer to 1st root%@AE@%%@NL@%
  3540. %@AB@%;*          R2 - Pointer to 2nd root%@AE@%%@NL@%
  3541. %@AB@%;*%@AE@%%@NL@%
  3542. %@AB@%;* Return:  Short integer with return code%@AE@%%@NL@%
  3543. %@AB@%;*          0 if both roots found%@AE@%%@NL@%
  3544. %@AB@%;*          1 if single root (placed in R1)%@AE@%%@NL@%
  3545. %@AB@%;*          2 if indeterminate%@AE@%%@NL@%
  3546. %@NL@%
  3547. Quadratic PROC USES ds di si,%@NL@%
  3548.         aa:DWORD, bb:DWORD, cc:DWORD, r1:PDWORD, r2:PDWORD%@NL@%
  3549. %@NL@%
  3550.         LOCAL status:WORD               %@AB@%; Intermediate status%@AE@%%@NL@%
  3551. %@NL@%
  3552.         LoadPtr es, di, r1              %@AB@%; ES:DI points to 1st root%@AE@%%@NL@%
  3553.         LoadPtr ds, si, r2              %@AB@%; DS:SI points to 2nd root%@AE@%%@NL@%
  3554.         sub     bx, bx                  %@AB@%; Clear error code%@AE@%%@NL@%
  3555.         fld1                            %@AB@%; Load top of stack with 1%@AE@%%@NL@%
  3556.         fadd    st, st                  %@AB@%; Double it to make 2%@AE@%%@NL@%
  3557.         fld     st                      %@AB@%; Copy to next register%@AE@%%@NL@%
  3558.         fmul    aa                      %@AB@%; ST register = 2a%@AE@%%@NL@%
  3559.         ftst                            %@AB@%; Test current ST value%@AE@%%@NL@%
  3560.         fstsw   status                  %@AB@%; Copy status to local word%@AE@%%@NL@%
  3561.         fwait                           %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
  3562.         mov     ax, status              %@AB@%; Copy status into AX%@AE@%%@NL@%
  3563.         sahf                            %@AB@%; Load flag register%@AE@%%@NL@%
  3564.         jnz     notzero                 %@AB@%; If C3 set, a = 0, in which case%@AE@%%@NL@%
  3565.                                         %@AB@%;   solution is x = -c / b%@AE@%%@NL@%
  3566.         fld     cc                      %@AB@%; Load c parameter%@AE@%%@NL@%
  3567.         fchs                            %@AB@%; Reverse sign%@AE@%%@NL@%
  3568.         fld     bb                      %@AB@%; Load b parameter%@AE@%%@NL@%
  3569.         ftst                            %@AB@%; Test current ST value%@AE@%%@NL@%
  3570.         fstsw   status                  %@AB@%; Copy status to local word%@AE@%%@NL@%
  3571.         fwait                           %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
  3572.         mov     ax, status              %@AB@%; Copy status into AX%@AE@%%@NL@%
  3573.         sahf                            %@AB@%; Load flag register%@AE@%%@NL@%
  3574.         jz      exit2                   %@AB@%; If C3 set, b = 0, in which case%@AE@%%@NL@%
  3575.                                         %@AB@%; division by zero%@AE@%%@NL@%
  3576.         fdiv                            %@AB@%; Divide by B%@AE@%%@NL@%
  3577.         fstp    DWORD PTR es:[di]       %@AB@%; Copy result and pop stack%@AE@%%@NL@%
  3578.         fstp    st                      %@AB@%; Clean up stack%@AE@%%@NL@%
  3579.         jmp     exit1                   %@AB@%; Return with code = 1%@AE@%%@NL@%
  3580. notzero:%@NL@%
  3581.         fmul    st(1), st               %@AB@%; ST(1) register = 4a%@AE@%%@NL@%
  3582.         fxch                            %@AB@%; Exchange ST and ST(1)%@AE@%%@NL@%
  3583.         fmul    cc                      %@AB@%; ST register = 4ac%@AE@%%@NL@%
  3584.         ftst                            %@AB@%; Test current ST value%@AE@%%@NL@%
  3585.         fstsw   status                  %@AB@%; Copy status to local word%@AE@%%@NL@%
  3586.         fwait                           %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
  3587.         mov     ax, status              %@AB@%; Copy status into AX%@AE@%%@NL@%
  3588.         sahf                            %@AB@%; Load flag register%@AE@%%@NL@%
  3589.         jp      exit2                   %@AB@%; If C2 set, 4*a*c is infinite%@AE@%%@NL@%
  3590. %@NL@%
  3591.         fld     bb                      %@AB@%; Else load b parameter%@AE@%%@NL@%
  3592.         fmul    st, st                  %@AB@%; Square it; ST register = b*b%@AE@%%@NL@%
  3593.         fsubr                           %@AB@%; ST register = b*b - 4*a*c%@AE@%%@NL@%
  3594.         ftst                            %@AB@%; Test current ST value%@AE@%%@NL@%
  3595.         fstsw   status                  %@AB@%; Copy status to local word%@AE@%%@NL@%
  3596.         fwait                           %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
  3597.         mov     ax, status              %@AB@%; Copy status into AX%@AE@%%@NL@%
  3598.         sahf                            %@AB@%; Load flag register%@AE@%%@NL@%
  3599.         jc      exit2                   %@AB@%; If C0 set, b*b < 4ac%@AE@%%@NL@%
  3600.         jnz     tworoot                 %@AB@%; If C3 set, b*b = 4ac, in which%@AE@%%@NL@%
  3601.         inc     bx                      %@AB@%;   case only 1 root so set flag%@AE@%%@NL@%
  3602. tworoot:%@NL@%
  3603.         fsqrt                           %@AB@%; Get square root%@AE@%%@NL@%
  3604.         fld     bb                      %@AB@%; Load b parameter%@AE@%%@NL@%
  3605.         fchs                            %@AB@%; Reverse sign%@AE@%%@NL@%
  3606.         fxch                            %@AB@%; Exchange ST and ST1%@AE@%%@NL@%
  3607.         fld     st                      %@AB@%; Copy square root to next reg%@AE@%%@NL@%
  3608.         fadd    st, st(2)               %@AB@%; ST = -b + sqrt(b*b - 4*a*c)%@AE@%%@NL@%
  3609.         fxch                            %@AB@%; Exchange ST and ST1%@AE@%%@NL@%
  3610.         fsubp   st(2), st               %@AB@%; ST = -b - sqrt(b*b - 4*a*c)%@AE@%%@NL@%
  3611. %@NL@%
  3612.         fdiv    st, st(2)               %@AB@%; Divide 1st dividend by 2*a%@AE@%%@NL@%
  3613.         fstp    DWORD PTR es:[di]       %@AB@%; Copy result, pop stack%@AE@%%@NL@%
  3614.         fdivr                           %@AB@%; Divide 2nd dividend by 2*a%@AE@%%@NL@%
  3615.         fstp    DWORD PTR ds:[si]       %@AB@%; Copy result, pop stack%@AE@%%@NL@%
  3616.         jmp     exit                    %@AB@%; Return with code%@AE@%%@NL@%
  3617. exit2:%@NL@%
  3618.         inc     bx                      %@AB@%; Error code = 2 for indeterminancy%@AE@%%@NL@%
  3619.         fstp    st                      %@AB@%; Clean stack%@AE@%%@NL@%
  3620. exit1:%@NL@%
  3621.         inc     bx                      %@AB@%; Error code = 1 for single root%@AE@%%@NL@%
  3622.         fstp    st                      %@AB@%; Clean stack%@AE@%%@NL@%
  3623. exit:%@NL@%
  3624.         mov ax, bx%@NL@%
  3625.         ret%@NL@%
  3626. %@NL@%
  3627. Quadratic ENDP%@NL@%
  3628. %@NL@%
  3629.         END%@NL@%
  3630. %@NL@%
  3631. %@NL@%
  3632. %@2@%%@AH@%MISC.ASM%@AE@%%@EH@%%@NL@%
  3633. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\DEMOS\MISC.ASM%@AE@%%@NL@%
  3634. %@NL@%
  3635.         .modeL  small, pascal, os_dos%@NL@%
  3636.         INCLUDE demo.inc%@NL@%
  3637. %@NL@%
  3638.         .DATA%@NL@%
  3639. _psp    PSEG    ?               %@AB@%; Segment of PSP%@AE@%%@NL@%
  3640. _env    PSEG    ?               %@AB@%; Segment of environment%@AE@%%@NL@%
  3641. %@NL@%
  3642.         .CODE%@NL@%
  3643. %@NL@%
  3644. %@AB@%;* WinOpen - Saves portion of screen to allocated memory, then opens a window%@AE@%%@NL@%
  3645. %@AB@%;* with specified fill attribute. See also the WinClose procedure.%@AE@%%@NL@%
  3646. %@AB@%;*%@AE@%%@NL@%
  3647. %@AB@%;* Shows:   DOS Function - 48h (Allocate Memory Block)%@AE@%%@NL@%
  3648. %@AB@%;*          Instructions - movsw      stosw     rep%@AE@%%@NL@%
  3649. %@AB@%;*%@AE@%%@NL@%
  3650. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  3651. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  3652. %@AB@%;*%@AE@%%@NL@%
  3653. %@AB@%;* Params:  Row1 - Row at top of window%@AE@%%@NL@%
  3654. %@AB@%;*          Col1 - Column at left edge of window%@AE@%%@NL@%
  3655. %@AB@%;*          Row2 - Row at bottom of window%@AE@%%@NL@%
  3656. %@AB@%;*          Col2 - Column at right edge of window%@AE@%%@NL@%
  3657. %@AB@%;*          Attr - Fill attribute for window%@AE@%%@NL@%
  3658. %@AB@%;*%@AE@%%@NL@%
  3659. %@AB@%;* Return:  Short integer with segment address of allocated buffer, or%@AE@%%@NL@%
  3660. %@AB@%;*          0 if unable to allocate memory%@AE@%%@NL@%
  3661. %@NL@%
  3662. WinOpen PROC USES ds di si,%@NL@%
  3663.         Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD, Attr:WORD%@NL@%
  3664. %@NL@%
  3665.         GetVidOffset Row1, Col1         %@AB@%; Get offset in video segment%@AE@%%@NL@%
  3666.         mov     si, ax                  %@AB@%; SI = video offset for window%@AE@%%@NL@%
  3667.         mov     bx, Row2%@NL@%
  3668.         sub     bx, Row1%@NL@%
  3669.         inc     bx                      %@AB@%; BX = number of window rows%@AE@%%@NL@%
  3670.         mov     cx, Col2%@NL@%
  3671.         sub     cx, Col1%@NL@%
  3672.         inc     cx                      %@AB@%; CX = number of columns%@AE@%%@NL@%
  3673. %@NL@%
  3674.         mov     ax, cx                  %@AB@%; Compute number of video%@AE@%%@NL@%
  3675.         mul     bl                      %@AB@%;   cells in window%@AE@%%@NL@%
  3676.         add     ax, 3                   %@AB@%; Plus 3 additional entries%@AE@%%@NL@%
  3677.         shr     ax, 1                   %@AB@%; Shift right 3 times to%@AE@%%@NL@%
  3678.         shr     ax, 1                   %@AB@%;   multiply by 2 bytes/cell,%@AE@%%@NL@%
  3679.         shr     ax, 1                   %@AB@%;   divide by 16 bytes/para%@AE@%%@NL@%
  3680.         inc     ax                      %@AB@%; Add a paragraph%@AE@%%@NL@%
  3681.         push    bx                      %@AB@%; Save number of rows%@AE@%%@NL@%
  3682.         mov     bx, ax                  %@AB@%; BX = number of paragraphs%@AE@%%@NL@%
  3683.         mov     ah, 48h                 %@AB@%; Request DOS Function 48h%@AE@%%@NL@%
  3684.         int     21h                     %@AB@%; Allocate Memory Block%@AE@%%@NL@%
  3685.         pop     bx%@NL@%
  3686. %@NL@%
  3687.         .IF     carry?                  %@AB@%; If unsuccessful:%@AE@%%@NL@%
  3688.         sub     ax, ax                  %@AB@%; Return null pointer%@AE@%%@NL@%
  3689.         .ELSE%@NL@%
  3690.         mov     es, ax                  %@AB@%; Point ES:DI to allocated%@AE@%%@NL@%
  3691.         sub     di, di                  %@AB@%;   buffer%@AE@%%@NL@%
  3692.         mov     ax, si%@NL@%
  3693.         stosw                           %@AB@%; Copy video offset to buffer%@AE@%%@NL@%
  3694.         mov     ax, bx%@NL@%
  3695.         stosw                           %@AB@%; Number of rows to buffer%@AE@%%@NL@%
  3696.         mov     ax, cx%@NL@%
  3697.         stosw                           %@AB@%; Number of cols to buffer%@AE@%%@NL@%
  3698.         mov     ax, 160                 %@AB@%; Number of video cells/row%@AE@%%@NL@%
  3699.         mov     ds, vconfig.sgmnt       %@AB@%; DS = video segment%@AE@%%@NL@%
  3700. %@NL@%
  3701.         .REPEAT%@NL@%
  3702.         push    si                      %@AB@%; Save ptr to start of line%@AE@%%@NL@%
  3703.         push    cx                      %@AB@%;   and number of columns%@AE@%%@NL@%
  3704. %@NL@%
  3705. %@AB@%; For CGA adapters, WinOpen avoids screen "snow" by disabling the video prior%@AE@%%@NL@%
  3706. %@AB@%; to block memory moves, then reenabling it. Although this technique can%@AE@%%@NL@%
  3707. %@AB@%; result in brief flickering, it demonstrates the fastest way to access a%@AE@%%@NL@%
  3708. %@AB@%; block in the CGA video buffer without causing display snow. See also the%@AE@%%@NL@%
  3709. %@AB@%; StrWrite procedure for another solution to the problem of CGA snow.%@AE@%%@NL@%
  3710. %@NL@%
  3711.         .IF     vconfig.adapter == CGA  %@AB@%; If not CGA adapter,%@AE@%%@NL@%
  3712.         INVOKE  DisableCga              %@AB@%;   disable video%@AE@%%@NL@%
  3713.         .ENDIF%@NL@%
  3714. %@NL@%
  3715.         rep     movsw                   %@AB@%; Copy one row to buffer%@AE@%%@NL@%
  3716. %@NL@%
  3717.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter,%@AE@%%@NL@%
  3718.         INVOKE  EnableCga               %@AB@%;   reenable CGA video%@AE@%%@NL@%
  3719.         .ENDIF%@NL@%
  3720.         pop     cx                      %@AB@%; Recover number of columns%@AE@%%@NL@%
  3721.         pop     si                      %@AB@%;   and start of line%@AE@%%@NL@%
  3722.         add     si, ax                  %@AB@%; Point to start of next line%@AE@%%@NL@%
  3723.         dec     bx                      %@AB@%; Decrement row counter%@AE@%%@NL@%
  3724.         .UNTIL  zero?                   %@AB@%; Until no rows remain%@AE@%%@NL@%
  3725. %@NL@%
  3726. %@AB@%; Screen contents (including display attributes) are now copied to buffer.%@AE@%%@NL@%
  3727. %@AB@%; Next open window, overwriting the screen portion just saved.%@AE@%%@NL@%
  3728. %@NL@%
  3729.         mov     ax, 0600h               %@AB@%; Scroll service%@AE@%%@NL@%
  3730.         mov     bh, BYTE PTR Attr       %@AB@%; Fill attribute%@AE@%%@NL@%
  3731.         mov     cx, Col1                %@AB@%; CX = row/col for upper left%@AE@%%@NL@%
  3732.         mov     ch, BYTE PTR Row1%@NL@%
  3733.         mov     dx, Col2                %@AB@%; DX = row/col for lower right%@AE@%%@NL@%
  3734.         mov     dh, BYTE PTR Row2%@NL@%
  3735.         int     10h                     %@AB@%; Blank window area on screen%@AE@%%@NL@%
  3736.         mov     ax, es                  %@AB@%; Return address of allocated%@AE@%%@NL@%
  3737.         .ENDIF                          %@AB@%;   segment%@AE@%%@NL@%
  3738.         ret%@NL@%
  3739. %@NL@%
  3740. WinOpen ENDP%@NL@%
  3741. %@NL@%
  3742. %@NL@%
  3743. %@AB@%;* WinClose - "Closes" a window previously opened by the WinOpen procedure.%@AE@%%@NL@%
  3744. %@AB@%;* See also the WinOpen procedure.%@AE@%%@NL@%
  3745. %@AB@%;*%@AE@%%@NL@%
  3746. %@AB@%;* Shows:   DOS Function - 49h (Release Memory Block)%@AE@%%@NL@%
  3747. %@AB@%;*          Instructions - lodsw%@AE@%%@NL@%
  3748. %@AB@%;*          Operators - : (segment override)     SEG%@AE@%%@NL@%
  3749. %@AB@%;*%@AE@%%@NL@%
  3750. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  3751. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  3752. %@AB@%;*%@AE@%%@NL@%
  3753. %@AB@%;* Params:  Adr - Segment address of buffer that holds screen contents%@AE@%%@NL@%
  3754. %@AB@%;*                 saved in WinOpen procedure%@AE@%%@NL@%
  3755. %@AB@%;*%@AE@%%@NL@%
  3756. %@AB@%;* Return:  None%@AE@%%@NL@%
  3757. %@NL@%
  3758. WinClose PROC USES ds di si,%@NL@%
  3759.         Adr:WORD%@NL@%
  3760. %@NL@%
  3761.         mov     ds, Adr                 %@AB@%; DS:SI points to buffer%@AE@%%@NL@%
  3762.         sub     si, si%@NL@%
  3763.         lodsw%@NL@%
  3764.         mov     di, ax                  %@AB@%; DI = video offset of window%@AE@%%@NL@%
  3765.         lodsw%@NL@%
  3766.         mov     bx, ax                  %@AB@%; BX = number of window rows%@AE@%%@NL@%
  3767.         lodsw%@NL@%
  3768.         mov     cx, ax                  %@AB@%; CX = number of columns%@AE@%%@NL@%
  3769. %@NL@%
  3770.         mov     ax, SEG vconfig.sgmnt%@NL@%
  3771.         mov     es, ax                  %@AB@%; Point ES to data segment%@AE@%%@NL@%
  3772.         push    es:vconfig.sgmnt%@NL@%
  3773.         pop     es                      %@AB@%; ES = video segment%@AE@%%@NL@%
  3774.         mov     ax, 160                 %@AB@%; Number of video cells/row%@AE@%%@NL@%
  3775. %@NL@%
  3776.         .REPEAT%@NL@%
  3777.         push    di                      %@AB@%; Save ptr to start of line%@AE@%%@NL@%
  3778.         push    cx                      %@AB@%;   and number of columns%@AE@%%@NL@%
  3779. %@NL@%
  3780. %@AB@%; Disable CGA video prior to memory move to avoid screen snow. (See the%@AE@%%@NL@%
  3781. %@AB@%; WinOpen and StrWrite procedures for further discussions on CGA snow.)%@AE@%%@NL@%
  3782. %@NL@%
  3783.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter,%@AE@%%@NL@%
  3784.         INVOKE  DisableCga              %@AB@%;   disable video%@AE@%%@NL@%
  3785.         .ENDIF%@NL@%
  3786. %@NL@%
  3787.         rep     movsw                   %@AB@%; Copy one row to buffer%@AE@%%@NL@%
  3788. %@NL@%
  3789.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter,%@AE@%%@NL@%
  3790.         INVOKE  EnableCga               %@AB@%;   reenable CGA video%@AE@%%@NL@%
  3791.         .ENDIF%@NL@%
  3792.         pop     cx                      %@AB@%; Recover number of columns%@AE@%%@NL@%
  3793.         pop     di                      %@AB@%;   and start of line%@AE@%%@NL@%
  3794.         add     di, ax                  %@AB@%; Point to start of next line%@AE@%%@NL@%
  3795.         dec     bx                      %@AB@%; Decrement row counter%@AE@%%@NL@%
  3796.         .UNTIL  zero?                   %@AB@%;   until no rows remain%@AE@%%@NL@%
  3797. %@NL@%
  3798.         mov     ah, 49h                 %@AB@%; Request DOS Function 49h%@AE@%%@NL@%
  3799.         mov     es, Adr%@NL@%
  3800.         int     21h                     %@AB@%; Release Memory Block%@AE@%%@NL@%
  3801.         ret%@NL@%
  3802. %@NL@%
  3803. WinClose ENDP%@NL@%
  3804. %@NL@%
  3805. %@NL@%
  3806. %@AB@%;* SetCurSize - Sets cursor size.%@AE@%%@NL@%
  3807. %@AB@%;*%@AE@%%@NL@%
  3808. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 1 (Set Cursor Type)%@AE@%%@NL@%
  3809. %@AB@%;*%@AE@%%@NL@%
  3810. %@AB@%;* Params:  Scan1 - Starting scan line%@AE@%%@NL@%
  3811. %@AB@%;*          Scan2 - Ending scan line%@AE@%%@NL@%
  3812. %@AB@%;*%@AE@%%@NL@%
  3813. %@AB@%;* Return:  None%@AE@%%@NL@%
  3814. %@NL@%
  3815. SetCurSize PROC,%@NL@%
  3816.         Scan1:WORD, Scan2:WORD%@NL@%
  3817. %@NL@%
  3818.         mov     cx, Scan2               %@AB@%; CL = ending scan line%@AE@%%@NL@%
  3819.         mov     ch, BYTE PTR Scan1      %@AB@%; CH = starting scan line%@AE@%%@NL@%
  3820.         mov     ah, 1                   %@AB@%; Function 1%@AE@%%@NL@%
  3821.         int     10h                     %@AB@%; Set Cursor Type%@AE@%%@NL@%
  3822.         ret%@NL@%
  3823. %@NL@%
  3824. SetCurSize ENDP%@NL@%
  3825. %@NL@%
  3826. %@NL@%
  3827. %@AB@%;* GetCurSize - Gets current cursor size.%@AE@%%@NL@%
  3828. %@AB@%;*%@AE@%%@NL@%
  3829. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 3 (Get Cursor Position)%@AE@%%@NL@%
  3830. %@AB@%;*%@AE@%%@NL@%
  3831. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  3832. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  3833. %@AB@%;*%@AE@%%@NL@%
  3834. %@AB@%;* Params:  None%@AE@%%@NL@%
  3835. %@AB@%;*%@AE@%%@NL@%
  3836. %@AB@%;* Return:  Short integer with high byte = top scan line,%@AE@%%@NL@%
  3837. %@AB@%;*                             low byte  = bottom scan line%@AE@%%@NL@%
  3838. %@NL@%
  3839. GetCurSize PROC%@NL@%
  3840. %@NL@%
  3841.         mov     ah, 3                   %@AB@%; Function 3%@AE@%%@NL@%
  3842.         mov     bh, vconfig.dpage%@NL@%
  3843.         int     10h                     %@AB@%; Get Cursor Position%@AE@%%@NL@%
  3844.         mov     ax, cx                  %@AB@%; Return cursor size%@AE@%%@NL@%
  3845.         ret%@NL@%
  3846. %@NL@%
  3847. GetCurSize ENDP%@NL@%
  3848. %@NL@%
  3849. %@NL@%
  3850. %@AB@%;* GetShift - Gets current shift status. Checks for extended keyboard,%@AE@%%@NL@%
  3851. %@AB@%;* and if available returns additional shift information.%@AE@%%@NL@%
  3852. %@AB@%;*%@AE@%%@NL@%
  3853. %@AB@%;* Shows:   BIOS Interrupt - 16h, Functions 2 and 12h (Get Keyboard Flags)%@AE@%%@NL@%
  3854. %@AB@%;*%@AE@%%@NL@%
  3855. %@AB@%;* Params:  None%@AE@%%@NL@%
  3856. %@AB@%;*%@AE@%%@NL@%
  3857. %@AB@%;* Return:  Long integer%@AE@%%@NL@%
  3858. %@AB@%;*          high word = 0 for non-extended keyboard%@AE@%%@NL@%
  3859. %@AB@%;*                      1 for extended keyboard%@AE@%%@NL@%
  3860. %@AB@%;*          low word has following bits set when indicated keys are pressed:%@AE@%%@NL@%
  3861. %@AB@%;*          0 - Right shift                   8 - Left Ctrl%@AE@%%@NL@%
  3862. %@AB@%;*          1 - Left shift                    9 - Left Alt%@AE@%%@NL@%
  3863. %@AB@%;*          2 - Ctrl                         10 - Right Ctrl%@AE@%%@NL@%
  3864. %@AB@%;*          3 - Alt                          11 - Right Alt%@AE@%%@NL@%
  3865. %@AB@%;*          4 - Scroll Lock active           12 - Scroll Lock pressed%@AE@%%@NL@%
  3866. %@AB@%;*          5 - Num Lock active              13 - Num Lock pressed%@AE@%%@NL@%
  3867. %@AB@%;*          6 - Caps Lock active             14 - Caps Lock pressed%@AE@%%@NL@%
  3868. %@AB@%;*          7 - Insert toggled               15 - Sys Req pressed%@AE@%%@NL@%
  3869. %@NL@%
  3870. GetShift PROC%@NL@%
  3871. %@NL@%
  3872.         sub     dx, dx                  %@AB@%; Assume non-extended keyboard%@AE@%%@NL@%
  3873.         mov     ah, 2                   %@AB@%;   and use Function 2%@AE@%%@NL@%
  3874.         mov     es, dx                  %@AB@%; Point ES to low memory%@AE@%%@NL@%
  3875.         .IF     BYTE PTR es:[496h] & 16 %@AB@%; If extended keyboard installed,%@AE@%%@NL@%
  3876.         inc     dx                      %@AB@%;   Set high word of return code%@AE@%%@NL@%
  3877.         mov     ah, 12h                 %@AB@%;   and use Function 12h%@AE@%%@NL@%
  3878.         .ENDIF%@NL@%
  3879.         int     16h                     %@AB@%; Get Keyboard Flags%@AE@%%@NL@%
  3880.         ret%@NL@%
  3881. %@NL@%
  3882. GetShift ENDP%@NL@%
  3883. %@NL@%
  3884. %@NL@%
  3885. %@AB@%;* GetKeyClock - Waits for keypress while updating time at specified location%@AE@%%@NL@%
  3886. %@AB@%;* on screen.%@AE@%%@NL@%
  3887. %@AB@%;*%@AE@%%@NL@%
  3888. %@AB@%;* Shows:   BIOS Interrupt - 16h, Functions 0 and 10h (Read Character)%@AE@%%@NL@%
  3889. %@AB@%;*                           16h, Functions 1 and 11h (Get Keyboard Status)%@AE@%%@NL@%
  3890. %@AB@%;*          DOS Functions - 2Ah (Get Date)%@AE@%%@NL@%
  3891. %@AB@%;*                          2Ch (Get Time)%@AE@%%@NL@%
  3892. %@AB@%;*%@AE@%%@NL@%
  3893. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  3894. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  3895. %@AB@%;*%@AE@%%@NL@%
  3896. %@AB@%;* Params:  Row - Screen row for clock display%@AE@%%@NL@%
  3897. %@AB@%;*          Col - Screen column for clock display%@AE@%%@NL@%
  3898. %@AB@%;*%@AE@%%@NL@%
  3899. %@AB@%;* Return:  Short integer with key scan code in high byte and ASCII%@AE@%%@NL@%
  3900. %@AB@%;*          character code in low byte. Low byte is 0 for special%@AE@%%@NL@%
  3901. %@AB@%;*          keys (such as the "F" keys) which don't generate characters.%@AE@%%@NL@%
  3902. %@NL@%
  3903.         .DATA%@NL@%
  3904.         PUBLIC  datestr%@NL@%
  3905. datestr BYTE    "  -  -     :  :  ", 0  %@AB@%; Date/time string%@AE@%%@NL@%
  3906.         .CODE%@NL@%
  3907. %@NL@%
  3908. GetKeyClock PROC,%@NL@%
  3909.         Row:WORD, Col:WORD%@NL@%
  3910. %@NL@%
  3911.         LOCAL   service:BYTE%@NL@%
  3912. %@NL@%
  3913.         INVOKE  GetShift                %@AB@%; Check for extended keyboard%@AE@%%@NL@%
  3914.         mov     service, 11h            %@AB@%; Assume Function 11h%@AE@%%@NL@%
  3915.         .IF     dx != 1                 %@AB@%; If no extended keyboard:%@AE@%%@NL@%
  3916.         mov     service, 1              %@AB@%; Use Function 1%@AE@%%@NL@%
  3917.         .ENDIF%@NL@%
  3918. %@NL@%
  3919.         .WHILE  1%@NL@%
  3920.         mov     ah, service%@NL@%
  3921.         int     16h                     %@AB@%; Get Keyboard Status%@AE@%%@NL@%
  3922.         .BREAK  .IF !zero?              %@AB@%; If no key yet, update clock%@AE@%%@NL@%
  3923. %@NL@%
  3924. %@AB@%; If not monochrome, color text, or black and white, skip clock update%@AE@%%@NL@%
  3925. %@AB@%; and poll keyboard again%@AE@%%@NL@%
  3926. %@NL@%
  3927.         .CONTINUE .IF (vconfig.mode != 7) \%@NL@%
  3928.                    && (vconfig.mode != 3) \%@NL@%
  3929.                    && (vconfig.mode != 2)%@NL@%
  3930. %@NL@%
  3931. %@AB@%; If 80-column text, get date and time from DOS before again%@AE@%%@NL@%
  3932. %@AB@%; polling keyboard, and display at upper right corner of screen.%@AE@%%@NL@%
  3933. %@NL@%
  3934.         mov     ah, 2Ch                 %@AB@%; Request time%@AE@%%@NL@%
  3935.         int     21h                     %@AB@%; Get Time%@AE@%%@NL@%
  3936.         mov     dl, dh%@NL@%
  3937.         push    dx                      %@AB@%; Save seconds,%@AE@%%@NL@%
  3938.         push    cx                      %@AB@%;   minutes,%@AE@%%@NL@%
  3939.         mov     cl, ch                  %@AB@%;   and%@AE@%%@NL@%
  3940.         push    cx                      %@AB@%;   hours%@AE@%%@NL@%
  3941.         mov     ah, 2Ah                 %@AB@%; Request date%@AE@%%@NL@%
  3942.         int     21h                     %@AB@%; Get Date%@AE@%%@NL@%
  3943.         sub     cx, 1900                %@AB@%; Subtract century, CL = year%@AE@%%@NL@%
  3944.         push    cx                      %@AB@%; Save year,%@AE@%%@NL@%
  3945.         push    dx                      %@AB@%;   day,%@AE@%%@NL@%
  3946.         mov     dl, dh                  %@AB@%;   and%@AE@%%@NL@%
  3947.         push    dx                      %@AB@%;   month%@AE@%%@NL@%
  3948. %@NL@%
  3949.         mov     cx, 6%@NL@%
  3950.         sub     bx, bx%@NL@%
  3951. %@NL@%
  3952.         .REPEAT%@NL@%
  3953.         pop     ax                      %@AB@%; Recover all 6 numbers in AL%@AE@%%@NL@%
  3954.         aam                             %@AB@%; Convert to unpacked BCD%@AE@%%@NL@%
  3955.         xchg    al, ah                  %@AB@%; Switch bytes for word move%@AE@%%@NL@%
  3956.         or      ax, "00"                %@AB@%; Make ASCII numerals%@AE@%%@NL@%
  3957.         mov     WORD PTR datestr[bx], ax%@AB@%; Copy to string%@AE@%%@NL@%
  3958.         add     bx, 3                   %@AB@%;   at every third byte%@AE@%%@NL@%
  3959.         .UNTILCXZ%@NL@%
  3960. %@NL@%
  3961.         INVOKE  StrWrite, Row, Col, ADDR datestr%@NL@%
  3962.         .ENDW                           %@AB@%; Loop again for keypress%@AE@%%@NL@%
  3963. %@NL@%
  3964.         mov     ah, service             %@AB@%; 1 or 11h, depending on keybd%@AE@%%@NL@%
  3965.         dec     ah                      %@AB@%; Set AH to 0 or 10h%@AE@%%@NL@%
  3966.         int     16h                     %@AB@%; Get key to remove it from%@AE@%%@NL@%
  3967.         ret                             %@AB@%;   keyboard buffer%@AE@%%@NL@%
  3968. %@NL@%
  3969. GetKeyClock ENDP%@NL@%
  3970. %@NL@%
  3971. %@NL@%
  3972. %@AB@%;* GetPSP - Gets address of Program Segment Prefix. For DOS 3.0 or higher.%@AE@%%@NL@%
  3973. %@AB@%;*%@AE@%%@NL@%
  3974. %@AB@%;* Shows:   DOS Function - 62h (Get PSP Address)%@AE@%%@NL@%
  3975. %@AB@%;*          Instruction - call%@AE@%%@NL@%
  3976. %@AB@%;*%@AE@%%@NL@%
  3977. %@AB@%;* Params:  None%@AE@%%@NL@%
  3978. %@AB@%;*%@AE@%%@NL@%
  3979. %@AB@%;* Return:  Short integer with PSP segment address%@AE@%%@NL@%
  3980. %@AB@%;*          or 0 if DOS version below 3.0%@AE@%%@NL@%
  3981. %@NL@%
  3982. GetPSP  PROC%@NL@%
  3983. %@NL@%
  3984.         INVOKE  GetVer                  %@AB@%; Get DOS version number%@AE@%%@NL@%
  3985.         .IF     ax >= 300               %@AB@%; If DOS 3.0 or higher:%@AE@%%@NL@%
  3986.         mov     ah, 62h                 %@AB@%; Query DOS for PSP%@AE@%%@NL@%
  3987.         int     21h                     %@AB@%; Get PSP Address%@AE@%%@NL@%
  3988.         mov     ax, bx                  %@AB@%; Return in AX%@AE@%%@NL@%
  3989.         .ELSE                           %@AB@%; Else 2.0:%@AE@%%@NL@%
  3990.         sub     ax, ax                  %@AB@%; For version 2, return 0%@AE@%%@NL@%
  3991.         .ENDIF%@NL@%
  3992.         ret%@NL@%
  3993. %@NL@%
  3994. GetPSP  ENDP%@NL@%
  3995. %@NL@%
  3996. %@NL@%
  3997. %@AB@%;* GetMem - Gets total size of memory and determines the largest amount of%@AE@%%@NL@%
  3998. %@AB@%;* unallocated memory available. GetMem invokes DOS Function 48h (Allocate%@AE@%%@NL@%
  3999. %@AB@%;* Memory) to request an impossibly large memory block. DOS denies the re-%@AE@%%@NL@%
  4000. %@AB@%;* quest, but returns instead the size of the largest block available. This%@AE@%%@NL@%
  4001. %@AB@%;* is the amount that GetMem returns to the calling program. See the WinOpen%@AE@%%@NL@%
  4002. %@AB@%;* procedure for an example of calling Function 48h to allocate unused memory.%@AE@%%@NL@%
  4003. %@AB@%;*%@AE@%%@NL@%
  4004. %@AB@%;* Shows:   BIOS Interrupt - 12h (Get Conventional Memory Size)%@AE@%%@NL@%
  4005. %@AB@%;*          Instructions - push     pop      ret%@AE@%%@NL@%
  4006. %@AB@%;*%@AE@%%@NL@%
  4007. %@AB@%;* Params:  None%@AE@%%@NL@%
  4008. %@AB@%;*%@AE@%%@NL@%
  4009. %@AB@%;* Return:  Long integer, high word = total memory in kilobytes (KB)%@AE@%%@NL@%
  4010. %@AB@%;*                        low word  = largest block of available memory (KB)%@AE@%%@NL@%
  4011. %@NL@%
  4012. GetMem  PROC%@NL@%
  4013. %@NL@%
  4014.         int     12h                     %@AB@%; Get total memory in K%@AE@%%@NL@%
  4015.         push    ax                      %@AB@%; Save size of memory%@AE@%%@NL@%
  4016.         mov     ah, 48h                 %@AB@%; Request memory allocation%@AE@%%@NL@%
  4017.         mov     bx, 0FFFFh              %@AB@%; Ensure request is denied for%@AE@%%@NL@%
  4018.                                         %@AB@%;   impossibly large block%@AE@%%@NL@%
  4019.         int     21h                     %@AB@%; Get largest available block in BX%@AE@%%@NL@%
  4020.         mov     ax, bx                  %@AB@%; Copy to AX%@AE@%%@NL@%
  4021.         mov     cl, 6                   %@AB@%; Convert paragraphs to kilobytes by%@AE@%%@NL@%
  4022.         shr     ax, cl                  %@AB@%;   dividing by 64%@AE@%%@NL@%
  4023.         pop     dx                      %@AB@%; Recover total in DX%@AE@%%@NL@%
  4024.         ret                             %@AB@%; Return long integer DX:AX%@AE@%%@NL@%
  4025. %@NL@%
  4026. GetMem  ENDP%@NL@%
  4027. %@NL@%
  4028. %@NL@%
  4029. %@AB@%;* VeriPrint - Checks if LPT1 (PRN) is available.%@AE@%%@NL@%
  4030. %@AB@%;*%@AE@%%@NL@%
  4031. %@AB@%;* Shows:   BIOS Interrupt - 17h (Parallel Port Printer Driver)%@AE@%%@NL@%
  4032. %@AB@%;*%@AE@%%@NL@%
  4033. %@AB@%;* Params:  None%@AE@%%@NL@%
  4034. %@AB@%;*%@AE@%%@NL@%
  4035. %@AB@%;* Return:  Short integer, 1 for yes or 0 for no%@AE@%%@NL@%
  4036. %@NL@%
  4037. VeriPrint PROC%@NL@%
  4038. %@NL@%
  4039.         mov     ah, 2                   %@AB@%; Check printer status for%@AE@%%@NL@%
  4040.         sub     dx, dx                  %@AB@%;   parallel printer (port 0)%@AE@%%@NL@%
  4041.         int     17h%@NL@%
  4042.         xchg    dx, ax                  %@AB@%; Put 0 (for error) in AX%@AE@%%@NL@%
  4043. %@NL@%
  4044. %@AB@%; If all error bits are off and both operation bits are on, return 1%@AE@%%@NL@%
  4045. %@NL@%
  4046.         .IF     !(dh & 00101001y) && (dh & 10010000y)%@NL@%
  4047.         inc     ax                      %@AB@%; Return 1%@AE@%%@NL@%
  4048.         .ENDIF%@NL@%
  4049.         ret%@NL@%
  4050. %@NL@%
  4051. VeriPrint ENDP%@NL@%
  4052. %@NL@%
  4053. %@NL@%
  4054. %@AB@%;* IntToAsc - Converts integer to ASCII string. This procedure is useful%@AE@%%@NL@%
  4055. %@AB@%;* only for assembly language, and is not intended to be C-callable.%@AE@%%@NL@%
  4056. %@AB@%;*%@AE@%%@NL@%
  4057. %@AB@%;* Shows:   Instructions - aam     xchg%@AE@%%@NL@%
  4058. %@AB@%;*%@AE@%%@NL@%
  4059. %@AB@%;* Entry:   AX = integer (9999 max)%@AE@%%@NL@%
  4060. %@AB@%;*%@AE@%%@NL@%
  4061. %@AB@%;* Return:  DX:AX = 4-digit ASCII number%@AE@%%@NL@%
  4062. %@NL@%
  4063. IntToAsc PROC%@NL@%
  4064. %@NL@%
  4065.         cwd                             %@AB@%; Zero DX register%@AE@%%@NL@%
  4066.         mov     cx, 100                 %@AB@%; Divide AX by 100, yields%@AE@%%@NL@%
  4067.         div     cx                      %@AB@%;   AX=quotient, DX=remainder%@AE@%%@NL@%
  4068.         aam                             %@AB@%; Make digits unpacked BCD%@AE@%%@NL@%
  4069.         or      ax, "00"                %@AB@%; Convert to ASCII%@AE@%%@NL@%
  4070.         xchg    ax, dx                  %@AB@%; Do same thing for DX%@AE@%%@NL@%
  4071.         aam%@NL@%
  4072.         or      ax, "00"%@NL@%
  4073.         ret                             %@AB@%; Return DX:AX = ASCII number%@AE@%%@NL@%
  4074. %@NL@%
  4075. IntToAsc ENDP%@NL@%
  4076. %@NL@%
  4077. %@NL@%
  4078. %@AB@%;* VeriAnsi - Checks for ANSI driver by writing ANSI sequence to report%@AE@%%@NL@%
  4079. %@AB@%;* cursor position. If report compares with position returned from%@AE@%%@NL@%
  4080. %@AB@%;* GetCurPos procedure, then ANSI driver is operating.%@AE@%%@NL@%
  4081. %@AB@%;*%@AE@%%@NL@%
  4082. %@AB@%;* Shows:   DOS Functions - 06h (Direct Console I/O)%@AE@%%@NL@%
  4083. %@AB@%;*                          0Ch (Flush Input Buffer and then Input)%@AE@%%@NL@%
  4084. %@AB@%;*%@AE@%%@NL@%
  4085. %@AB@%;* Params:  None%@AE@%%@NL@%
  4086. %@AB@%;*%@AE@%%@NL@%
  4087. %@AB@%;* Return:  Short integer, 1 for yes or 0 for no%@AE@%%@NL@%
  4088. %@NL@%
  4089.         .DATA%@NL@%
  4090.         PUBLIC report%@NL@%
  4091. report  DB      ESCAPE, "[6n$"          %@AB@%; ANSI Report Cursor sequence%@AE@%%@NL@%
  4092.         .CODE%@NL@%
  4093. %@NL@%
  4094. VeriAnsi PROC%@NL@%
  4095. %@NL@%
  4096.         %@AB@%; Get cursor position from BIOS%@AE@%%@NL@%
  4097.         INVOKE  GetCurPos%@NL@%
  4098.         mov     cx, ax                  %@AB@%; Save it in CX%@AE@%%@NL@%
  4099.         mov     dx, OFFSET report       %@AB@%; ANSI string to get position%@AE@%%@NL@%
  4100.         mov     ah, 9                   %@AB@%; Request DOS String Output%@AE@%%@NL@%
  4101.         int     21h                     %@AB@%; Write ANSI escape sequence%@AE@%%@NL@%
  4102. %@NL@%
  4103.         mov     ah, 6                   %@AB@%; Skip Esc character in%@AE@%%@NL@%
  4104.         mov     dl, 0FFh                %@AB@%;   keyboard buffer%@AE@%%@NL@%
  4105.         int     21h%@NL@%
  4106.         jz      e_exit                  %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
  4107.         mov     ah, 6                   %@AB@%; Skip '[' character%@AE@%%@NL@%
  4108.         int     21h%@NL@%
  4109.         jz      e_exit                  %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
  4110.         mov     ah, 6                   %@AB@%; Get 1st digit of cursor row%@AE@%%@NL@%
  4111.         int     21h%@NL@%
  4112.         jz      e_exit                  %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
  4113.         mov     bh, al                  %@AB@%; Store in BH%@AE@%%@NL@%
  4114.         mov     ah, 6                   %@AB@%; Get 2nd digit of cursor row%@AE@%%@NL@%
  4115.         int     21h%@NL@%
  4116.         jz      e_exit                  %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
  4117.         mov     bl, al                  %@AB@%; Store in BL%@AE@%%@NL@%
  4118.         mov     al, ch                  %@AB@%; Get original row # in AL%@AE@%%@NL@%
  4119.         cbw                             %@AB@%; AX = row # from GetCurPos%@AE@%%@NL@%
  4120.         inc     ax                      %@AB@%; Add 1 to it%@AE@%%@NL@%
  4121.         call    IntToAsc                %@AB@%; Make ASCII digits%@AE@%%@NL@%
  4122.         cmp     ax, bx                  %@AB@%; ANSI and BIOS reports match?%@AE@%%@NL@%
  4123.         jne     e_exit                  %@AB@%; No?  Then ANSI not loaded%@AE@%%@NL@%
  4124. %@NL@%
  4125.         mov     ax, 0C06h               %@AB@%; Flush remaining ANSI keys%@AE@%%@NL@%
  4126.         mov     dl, 0FFh                %@AB@%;   from buffer%@AE@%%@NL@%
  4127.         int     21h%@NL@%
  4128.         mov     ax, 1                   %@AB@%; Set 1 for true%@AE@%%@NL@%
  4129.         jmp     exit                    %@AB@%;   and exit%@AE@%%@NL@%
  4130. e_exit:%@NL@%
  4131.         sub     ax, ax                  %@AB@%; Set 0 return code if no%@AE@%%@NL@%
  4132. exit:%@NL@%
  4133.         ret                             %@AB@%;   ANSI driver installed%@AE@%%@NL@%
  4134. %@NL@%
  4135. VeriAnsi ENDP%@NL@%
  4136. %@NL@%
  4137. %@NL@%
  4138. %@AB@%;* VeriCop - Checks for coprocessor.%@AE@%%@NL@%
  4139. %@AB@%;*%@AE@%%@NL@%
  4140. %@AB@%;* Shows:   BIOS Interrupt - 11h (Get Equipment Configuration)%@AE@%%@NL@%
  4141. %@AB@%;*%@AE@%%@NL@%
  4142. %@AB@%;* Params:  None%@AE@%%@NL@%
  4143. %@AB@%;*%@AE@%%@NL@%
  4144. %@AB@%;* Return:  Short integer, 1 for yes or 0 for no%@AE@%%@NL@%
  4145. %@NL@%
  4146. VeriCop PROC%@NL@%
  4147. %@NL@%
  4148.         int     11h                     %@AB@%; Check peripherals%@AE@%%@NL@%
  4149.         test    al, 2                   %@AB@%; Coprocessor?%@AE@%%@NL@%
  4150.         mov     ax, 0                   %@AB@%; Assume no, don't alter flags%@AE@%%@NL@%
  4151.         .IF     !zero?%@NL@%
  4152.         inc     ax                      %@AB@%; Set to 1%@AE@%%@NL@%
  4153.         .ENDIF%@NL@%
  4154.         ret%@NL@%
  4155. %@NL@%
  4156. VeriCop ENDP%@NL@%
  4157. %@NL@%
  4158. %@NL@%
  4159. %@AB@%;* SetLineMode - Sets line mode for EGA or VGA.%@AE@%%@NL@%
  4160. %@AB@%;*%@AE@%%@NL@%
  4161. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 11h (Character Generator Interface)%@AE@%%@NL@%
  4162. %@AB@%;*                           10h, Function 12h (Video Subsystem Configuration)%@AE@%%@NL@%
  4163. %@AB@%;*%@AE@%%@NL@%
  4164. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  4165. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  4166. %@AB@%;*%@AE@%%@NL@%
  4167. %@AB@%;* Params:  Line - Requested line mode (25, 43, or 50)%@AE@%%@NL@%
  4168. %@AB@%;*%@AE@%%@NL@%
  4169. %@AB@%;* Return:  Short integer with error code%@AE@%%@NL@%
  4170. %@AB@%;*          0 if successful%@AE@%%@NL@%
  4171. %@AB@%;*          1 if error%@AE@%%@NL@%
  4172. %@NL@%
  4173. SetLineMode PROC,%@NL@%
  4174.         Line:WORD%@NL@%
  4175. %@NL@%
  4176.         .IF     vconfig.adapter >= EGA  %@AB@%; If EGA or VGA:%@AE@%%@NL@%
  4177.         mov     ax, Line                %@AB@%; Check for valid parameter%@AE@%%@NL@%
  4178.         cmp     al, 25%@NL@%
  4179.         je      line25%@NL@%
  4180.         cmp     al, 43%@NL@%
  4181.         je      line43%@NL@%
  4182.         cmp     al, 50%@NL@%
  4183.         je      line50%@NL@%
  4184.         jmp     e_exit                  %@AB@%; If not 25, 43, or 50, exit w/ error%@AE@%%@NL@%
  4185. line25:%@NL@%
  4186.         mov     al, 11h                 %@AB@%; Set for EGA 25-line mode%@AE@%%@NL@%
  4187.         cmp     vconfig.adapter, EGA    %@AB@%; EGA?%@AE@%%@NL@%
  4188.         je      linemode                %@AB@%; Yes?  Continue%@AE@%%@NL@%
  4189.         mov     ax, 1202h               %@AB@%; No?  Function 12h for VGA%@AE@%%@NL@%
  4190.         mov     bl, 30h                 %@AB@%; AL = 2 for 400 scan lines%@AE@%%@NL@%
  4191.         int     10h                     %@AB@%; Reset to 400 scan lines%@AE@%%@NL@%
  4192.         mov     ax, 0003                %@AB@%; Reset mode (Function 0)%@AE@%%@NL@%
  4193.         int     10h                     %@AB@%;   to mode 3 (80-col text)%@AE@%%@NL@%
  4194.         mov     al, 14h                 %@AB@%; Request 8x16 char matrix%@AE@%%@NL@%
  4195.         jmp     linemode%@NL@%
  4196. line43:%@NL@%
  4197.         mov     al, 12h                 %@AB@%; Set for EGA 43-line mode%@AE@%%@NL@%
  4198.         cmp     vconfig.adapter, EGA    %@AB@%; EGA?%@AE@%%@NL@%
  4199.         je      linemode                %@AB@%; Yes?  Continue%@AE@%%@NL@%
  4200.         mov     ax, 1201h               %@AB@%; No?  Function 12h for VGA%@AE@%%@NL@%
  4201.         mov     bl, 30h                 %@AB@%; AL = 1 for 350 scan lines%@AE@%%@NL@%
  4202.         int     10h                     %@AB@%; Reset to 350 scan lines%@AE@%%@NL@%
  4203.         mov     ax, 0003                %@AB@%; Reset mode (Function 0)%@AE@%%@NL@%
  4204.         int     10h                     %@AB@%;   to mode 3 (80-col text)%@AE@%%@NL@%
  4205.         mov     al, 12h                 %@AB@%; Request 8x8 character matrix%@AE@%%@NL@%
  4206.         jmp     linemode%@NL@%
  4207. line50:%@NL@%
  4208.         cmp     vconfig.adapter, VGA    %@AB@%; VGA?%@AE@%%@NL@%
  4209.         jne     e_exit                  %@AB@%; No?  Exit with error%@AE@%%@NL@%
  4210.         mov     ax, 1202h               %@AB@%; Yes?  Function 12h%@AE@%%@NL@%
  4211.         mov     bl, 30h                 %@AB@%; AL = 2 for 400 scan lines%@AE@%%@NL@%
  4212.         int     10h                     %@AB@%; Reset to 400 scan lines%@AE@%%@NL@%
  4213.         mov     ax, 0003                %@AB@%; Reset mode (Function 0)%@AE@%%@NL@%
  4214.         int     10h                     %@AB@%;   to mode 3 (80-col text)%@AE@%%@NL@%
  4215.         mov     al, 12h                 %@AB@%; Request 8x8 character matrix%@AE@%%@NL@%
  4216. linemode:%@NL@%
  4217.         sub     bl, bl                  %@AB@%; Use table 0%@AE@%%@NL@%
  4218.         mov     ah, 11h                 %@AB@%; Request Function 11h%@AE@%%@NL@%
  4219.         int     10h                     %@AB@%; Set new line mode%@AE@%%@NL@%
  4220. %@NL@%
  4221.         mov     ah, 12h                 %@AB@%; Select alternate print%@AE@%%@NL@%
  4222.         mov     bl, 20h                 %@AB@%;    screen for EGA and VGA%@AE@%%@NL@%
  4223.         int     10h%@NL@%
  4224. %@NL@%
  4225.         cmp     vconfig.adapter, VGA    %@AB@%; VGA?%@AE@%%@NL@%
  4226.         je      exit                    %@AB@%; Yes?  Then exit%@AE@%%@NL@%
  4227.         cmp     Line, 12h               %@AB@%; If EGA 43-line mode, set%@AE@%%@NL@%
  4228.         je      port                    %@AB@%;   cursor through port to%@AE@%%@NL@%
  4229.                                         %@AB@%;   avoid cursor emulation bug%@AE@%%@NL@%
  4230. %@NL@%
  4231.         %@AB@%; Set normal cursor size, pass top and bottom scan lines%@AE@%%@NL@%
  4232.         INVOKE  SetCurSize, 6, 7%@NL@%
  4233.         jmp     exit%@NL@%
  4234. port:%@NL@%
  4235.         mov     dx, 03D4h               %@AB@%; Video controller address%@AE@%%@NL@%
  4236.         mov     ax, 060Ah               %@AB@%; Set AH = 06h (cursor start)%@AE@%%@NL@%
  4237.                                         %@AB@%;     AL = 0Ah (register #)%@AE@%%@NL@%
  4238.         out     dx, ax                  %@AB@%; Update port%@AE@%%@NL@%
  4239.         mov     ax, 000Bh               %@AB@%; Set AH = 00h (cursor end)%@AE@%%@NL@%
  4240.                                         %@AB@%;     AL = 0Bh (register #)%@AE@%%@NL@%
  4241.         out     dx, ax                  %@AB@%; Update port%@AE@%%@NL@%
  4242.         jmp     exit                    %@AB@%; Normal exit%@AE@%%@NL@%
  4243.         .ENDIF  %@AB@%; EGA or VGA%@AE@%%@NL@%
  4244. e_exit:%@NL@%
  4245.         mov     ax, 1                   %@AB@%; Set error code%@AE@%%@NL@%
  4246.         jmp     exit2%@NL@%
  4247. exit:%@NL@%
  4248.         sub     ax, ax                  %@AB@%; Clear error code%@AE@%%@NL@%
  4249. exit2:%@NL@%
  4250.         ret%@NL@%
  4251. %@NL@%
  4252. SetLineMode ENDP%@NL@%
  4253. %@NL@%
  4254. %@NL@%
  4255. %@AB@%;* Pause - Waits for specified number of clocks to elapse, then returns.%@AE@%%@NL@%
  4256. %@AB@%;*%@AE@%%@NL@%
  4257. %@AB@%;* Shows:   BIOS Interrupt - 1Ah, Function 0 (Real-Time Clock Driver)%@AE@%%@NL@%
  4258. %@AB@%;*          Operators - LOCAL     []%@AE@%%@NL@%
  4259. %@AB@%;*%@AE@%%@NL@%
  4260. %@AB@%;* Params:  Duration - Desired duration in clocks, where%@AE@%%@NL@%
  4261. %@AB@%;*                     18 clocks = approx 1 second%@AE@%%@NL@%
  4262. %@AB@%;*%@AE@%%@NL@%
  4263. %@AB@%;* Return:  None%@AE@%%@NL@%
  4264. %@NL@%
  4265. Pause   PROC,%@NL@%
  4266.         Duration:WORD%@NL@%
  4267. %@NL@%
  4268.         LOCAL tick:DWORD%@NL@%
  4269. %@NL@%
  4270.         sub     ah, ah%@NL@%
  4271.         int     1Ah                     %@AB@%; Get Clock Count in CX:DX%@AE@%%@NL@%
  4272.         add     dx, Duration            %@AB@%; Add pause time to it%@AE@%%@NL@%
  4273.         adc     cx, 0%@NL@%
  4274.         mov     WORD PTR tick[0], dx    %@AB@%; Result is target time;%@AE@%%@NL@%
  4275.         mov     WORD PTR tick[2], cx    %@AB@%;   keep in local variable%@AE@%%@NL@%
  4276. %@NL@%
  4277.         .REPEAT%@NL@%
  4278.         int     1Ah                     %@AB@%; Poll clock until target time%@AE@%%@NL@%
  4279.         .UNTIL  (dx >= WORD PTR tick[0]) || (cx >= WORD PTR fileinfo.time[2])%@NL@%
  4280.         ret%@NL@%
  4281. %@NL@%
  4282. Pause   ENDP%@NL@%
  4283. %@NL@%
  4284. %@NL@%
  4285. %@AB@%;* Sound - Sounds speaker with specified frequency and duration.%@AE@%%@NL@%
  4286. %@AB@%;*%@AE@%%@NL@%
  4287. %@AB@%;* Shows:   Instructions - in           out%@AE@%%@NL@%
  4288. %@AB@%;*%@AE@%%@NL@%
  4289. %@AB@%;* Params:  Freq - Desired frequency of sound in Hertz%@AE@%%@NL@%
  4290. %@AB@%;*          Duration - Desired duration in clocks, where%@AE@%%@NL@%
  4291. %@AB@%;*                     18 clocks = approx 1 second%@AE@%%@NL@%
  4292. %@AB@%;*%@AE@%%@NL@%
  4293. %@AB@%;* Return:  None%@AE@%%@NL@%
  4294. %@NL@%
  4295. Sound   PROC,%@NL@%
  4296.         Freq:WORD, Duration:WORD%@NL@%
  4297. %@NL@%
  4298.         mov     al, 0B6h                %@AB@%; Initialize channel 2 of%@AE@%%@NL@%
  4299.         out     43h, al                 %@AB@%;   timer chip%@AE@%%@NL@%
  4300.         mov     dx, 12h                 %@AB@%; Divide 1,193,182 Hertz%@AE@%%@NL@%
  4301.         mov     ax, 34DEh               %@AB@%;   (clock frequency) by%@AE@%%@NL@%
  4302.         div     Freq                    %@AB@%;   desired frequency%@AE@%%@NL@%
  4303.                                         %@AB@%; Result is timer clock count%@AE@%%@NL@%
  4304.         out     42h, al                 %@AB@%; Low byte of count to timer%@AE@%%@NL@%
  4305.         mov     al, ah%@NL@%
  4306.         out     42h, al                 %@AB@%; High byte of count to timer%@AE@%%@NL@%
  4307.         in      al, 61h                 %@AB@%; Read value from port 61h%@AE@%%@NL@%
  4308.         or      al, 3                   %@AB@%; Set first two bits%@AE@%%@NL@%
  4309.         out     61h, al                 %@AB@%; Turn speaker on%@AE@%%@NL@%
  4310. %@NL@%
  4311.         %@AB@%; Pause, pass duration of delay%@AE@%%@NL@%
  4312.         INVOKE  Pause, Duration%@NL@%
  4313. %@NL@%
  4314.         in      al, 61h                 %@AB@%; Get port value%@AE@%%@NL@%
  4315.         xor     al, 3                   %@AB@%; Kill bits 0-1 to turn%@AE@%%@NL@%
  4316.         out     61h, al                 %@AB@%;   speaker off%@AE@%%@NL@%
  4317.         ret%@NL@%
  4318. %@NL@%
  4319. Sound   ENDP%@NL@%
  4320. %@NL@%
  4321. %@NL@%
  4322. %@AB@%;* WriteTTY - Displays ASCIIZ string at cursor position, in either text%@AE@%%@NL@%
  4323. %@AB@%;* or graphics mode.%@AE@%%@NL@%
  4324. %@AB@%;*%@AE@%%@NL@%
  4325. %@AB@%;* Shows:   BIOS Interrupt - 10h, Function 0Eh (Write Character in TTY Mode)%@AE@%%@NL@%
  4326. %@AB@%;*%@AE@%%@NL@%
  4327. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  4328. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  4329. %@AB@%;*%@AE@%%@NL@%
  4330. %@AB@%;* Params:  Sptr - Pointer to ASCIIZ string%@AE@%%@NL@%
  4331. %@AB@%;*          icolor - Color index (for graphics mode only)%@AE@%%@NL@%
  4332. %@AB@%;*%@AE@%%@NL@%
  4333. %@AB@%;* Return:  None%@AE@%%@NL@%
  4334. %@NL@%
  4335. WriteTTY PROC USES ds si,%@NL@%
  4336.         Sptr:PBYTE, icolor:WORD%@NL@%
  4337. %@NL@%
  4338.         mov     bx, icolor              %@AB@%; BL = color index%@AE@%%@NL@%
  4339.         mov     bh, vconfig.dpage       %@AB@%; BH = current display page%@AE@%%@NL@%
  4340.         LoadPtr ds, si, Sptr%@NL@%
  4341.         mov     cx, -1                  %@AB@%; Set loop counter to maximum%@AE@%%@NL@%
  4342.         mov     ah, 14                  %@AB@%; Function 14%@AE@%%@NL@%
  4343. %@NL@%
  4344.         .REPEAT%@NL@%
  4345.         lodsb                           %@AB@%; Get character from string%@AE@%%@NL@%
  4346.         .BREAK .IF al == 0              %@AB@%; Exit if NULL string terminator%@AE@%%@NL@%
  4347.         int     10h                     %@AB@%; No?  Display, advance cursor%@AE@%%@NL@%
  4348.         .UNTILCXZ%@NL@%
  4349. %@NL@%
  4350.         ret%@NL@%
  4351. %@NL@%
  4352. WriteTTY ENDP%@NL@%
  4353. %@NL@%
  4354. %@NL@%
  4355. %@AB@%;* Colors - Alters screen colors within a specified area by using bit%@AE@%%@NL@%
  4356. %@AB@%;* or move operations on display attribute bytes in video memory.%@AE@%%@NL@%
  4357. %@AB@%;*%@AE@%%@NL@%
  4358. %@AB@%;* Shows:   Instructions - not     rol     ror     and     xor     or%@AE@%%@NL@%
  4359. %@AB@%;*%@AE@%%@NL@%
  4360. %@AB@%;* Params:  Logic - Code number, 0 = NOT    2 = ROR     4 = XOR    6 = MOV%@AE@%%@NL@%
  4361. %@AB@%;*                               1 = ROL    3 = AND     5 = OR%@AE@%%@NL@%
  4362. %@AB@%;*          Attr - Attribute mask%@AE@%%@NL@%
  4363. %@AB@%;*          Row1 - Row at top of window%@AE@%%@NL@%
  4364. %@AB@%;*          Col1 - Column at left edge of window%@AE@%%@NL@%
  4365. %@AB@%;*          Row2 - Row at bottom of window%@AE@%%@NL@%
  4366. %@AB@%;*          Col2 - Column at right edge of window%@AE@%%@NL@%
  4367. %@AB@%;*%@AE@%%@NL@%
  4368. %@AB@%;* Return:  None%@AE@%%@NL@%
  4369. %@NL@%
  4370. Colors  PROC USES ds si,%@NL@%
  4371.         Logic:WORD, Attr:WORD, Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD%@NL@%
  4372. %@NL@%
  4373.         GetVidOffset Row1, Col1         %@AB@%; Get offset in video segment%@AE@%%@NL@%
  4374.         inc     ax%@NL@%
  4375.         mov     si, ax                  %@AB@%; SI = offset for 1st attr byte%@AE@%%@NL@%
  4376.         mov     bx, Row2%@NL@%
  4377.         sub     bx, Row1%@NL@%
  4378.         inc     bx                      %@AB@%; BX = number of window rows%@AE@%%@NL@%
  4379.         mov     cx, Col2%@NL@%
  4380.         sub     cx, Col1%@NL@%
  4381.         inc     cx                      %@AB@%; CX = number of columns%@AE@%%@NL@%
  4382. %@NL@%
  4383.         mov     ds, vconfig.sgmnt       %@AB@%; DS = video segment%@AE@%%@NL@%
  4384.         mov     ax, Attr                %@AB@%; AL = mask for and, xor, and or%@AE@%%@NL@%
  4385. %@NL@%
  4386.         .REPEAT%@NL@%
  4387.         push    si                      %@AB@%; Save ptr to start of line%@AE@%%@NL@%
  4388.         push    cx                      %@AB@%;   and number of columns%@AE@%%@NL@%
  4389. %@NL@%
  4390. %@AB@%; Disable CGA video prior to memory access to avoid screen snow. (See the%@AE@%%@NL@%
  4391. %@AB@%; WinOpen and StrWrite procedures for further discussions on CGA snow.)%@AE@%%@NL@%
  4392. %@NL@%
  4393.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter:%@AE@%%@NL@%
  4394.         INVOKE  DisableCga              %@AB@%; Yes?  Disable video%@AE@%%@NL@%
  4395.         .ENDIF%@NL@%
  4396. %@NL@%
  4397.         cmp     Logic, 1                %@AB@%; Rotate left?%@AE@%%@NL@%
  4398.         jl      c_not                   %@AB@%; If less, do NOT%@AE@%%@NL@%
  4399.         je      c_rol                   %@AB@%; If equal, do ROL%@AE@%%@NL@%
  4400.         cmp     Logic, 3                %@AB@%; And?%@AE@%%@NL@%
  4401.         jl      c_ror                   %@AB@%; If less, do ROR%@AE@%%@NL@%
  4402.         je      c_and                   %@AB@%; If equal, do AND%@AE@%%@NL@%
  4403.         cmp     Logic, 5                %@AB@%; Or?%@AE@%%@NL@%
  4404.         jl      c_xor                   %@AB@%; If less, do XOR%@AE@%%@NL@%
  4405.         je      c_or                    %@AB@%; If equal, do OR%@AE@%%@NL@%
  4406. c_mov:%@NL@%
  4407.         mov     BYTE PTR [si], al       %@AB@%; MOV attr parameter%@AE@%%@NL@%
  4408.         add     si, 2                   %@AB@%;   into attribute byte%@AE@%%@NL@%
  4409.         loop    c_mov%@NL@%
  4410.         jmp     c_done%@NL@%
  4411. c_or:%@NL@%
  4412.         or      BYTE PTR [si], al       %@AB@%; OR with attr parameter%@AE@%%@NL@%
  4413.         add     si, 2%@NL@%
  4414.         loop    c_or%@NL@%
  4415.         jmp     c_done%@NL@%
  4416. c_xor:%@NL@%
  4417.         xor     BYTE PTR [si], al       %@AB@%; XOR with attr parameter%@AE@%%@NL@%
  4418.         add     si, 2%@NL@%
  4419.         loop    c_xor%@NL@%
  4420.         jmp     c_done%@NL@%
  4421. c_and:%@NL@%
  4422.         and     BYTE PTR [si], al       %@AB@%; AND with attr parameter%@AE@%%@NL@%
  4423.         add     si, 2%@NL@%
  4424.         loop    c_and%@NL@%
  4425.         jmp     c_done%@NL@%
  4426. c_ror:%@NL@%
  4427.         ror     BYTE PTR [si], 1        %@AB@%; Rotate right 1 bit%@AE@%%@NL@%
  4428.         add     si, 2%@NL@%
  4429.         loop    c_ror%@NL@%
  4430.         jmp     c_done%@NL@%
  4431. c_rol:%@NL@%
  4432.         rol     BYTE PTR [si], 1        %@AB@%; Rotate left 1 bit%@AE@%%@NL@%
  4433.         add     si, 2%@NL@%
  4434.         loop    c_rol%@NL@%
  4435.         jmp     c_done%@NL@%
  4436. c_not:%@NL@%
  4437.         not     BYTE PTR [si]           %@AB@%; Flip bits%@AE@%%@NL@%
  4438.         add     si, 2%@NL@%
  4439.         loop    c_not%@NL@%
  4440. c_done:%@NL@%
  4441.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA:%@AE@%%@NL@%
  4442.         INVOKE  EnableCga               %@AB@%; Reenable CGA video%@AE@%%@NL@%
  4443.         .ENDIF%@NL@%
  4444. %@NL@%
  4445.         pop     cx                      %@AB@%; Recover number of columns%@AE@%%@NL@%
  4446.         pop     si                      %@AB@%; Recover offset for start of line%@AE@%%@NL@%
  4447.         add     si, 160                 %@AB@%; Point to start of next line%@AE@%%@NL@%
  4448.         dec     bx                      %@AB@%; Decrement row counter%@AE@%%@NL@%
  4449.         .UNTIL  zero?                   %@AB@%; Loop while rows remain%@AE@%%@NL@%
  4450.         ret%@NL@%
  4451. %@NL@%
  4452. Colors  ENDP%@NL@%
  4453. %@NL@%
  4454. %@NL@%
  4455. %@AB@%;* Exec - Executes a child process.  Exec handles the usual chores associated%@AE@%%@NL@%
  4456. %@AB@%;* with spawning a process:  (1) parsing the command line tail and loading the%@AE@%%@NL@%
  4457. %@AB@%;* FCBs with the first two arguments; (2) setting and restoring the vectors%@AE@%%@NL@%
  4458. %@AB@%;* for Interrupts 1Bh, 23h, and 24h; and (3) querying DOS for the child's%@AE@%%@NL@%
  4459. %@AB@%;* return code.%@AE@%%@NL@%
  4460. %@AB@%;*%@AE@%%@NL@%
  4461. %@AB@%;* Shows:   DOS Functions - 29h (Parse Filename)%@AE@%%@NL@%
  4462. %@AB@%;*                          25h (Set Interrupt Vector)%@AE@%%@NL@%
  4463. %@AB@%;*                          35h (Get Interrupt Vector)%@AE@%%@NL@%
  4464. %@AB@%;*                          4Bh (Execute Program)%@AE@%%@NL@%
  4465. %@AB@%;*                          4Dh (Get Return Code)%@AE@%%@NL@%
  4466. %@AB@%;*%@AE@%%@NL@%
  4467. %@AB@%;* Params:  Spec - Pointer to ASCIIZ specification for program file%@AE@%%@NL@%
  4468. %@AB@%;*                 (must include .COM or .EXE extension)%@AE@%%@NL@%
  4469. %@AB@%;*          Block - Pointer to parameter block structure%@AE@%%@NL@%
  4470. %@AB@%;*          CtrBrk - Pointer to new Ctrl+Break (Interrupt 1Bh) handler%@AE@%%@NL@%
  4471. %@AB@%;*          CtrlC - Pointer to new Ctrl+C (Interrupt 23h) handler%@AE@%%@NL@%
  4472. %@AB@%;*          Criterr - Pointer to new Critical Error (Interrupt 24h) handler%@AE@%%@NL@%
  4473. %@AB@%;*%@AE@%%@NL@%
  4474. %@AB@%;* Return:  Short integer with child return code, or -1 for EXEC error%@AE@%%@NL@%
  4475. %@NL@%
  4476. Exec    PROC USES ds si di,%@NL@%
  4477.         Spec:PBYTE, Block:PPARMBLK, CtrBrk:PTR FAR,%@NL@%
  4478.         CtrlC:PTR FAR, Criterr:PTR FAR%@NL@%
  4479. %@NL@%
  4480.         Vector 1Bh, Old1Bh, CtrBrk      %@AB@%; Save, replace Int 1Bh vector%@AE@%%@NL@%
  4481.         Vector 23h, Old23h, CtrlC       %@AB@%; Save, replace Int 23h vector%@AE@%%@NL@%
  4482.         Vector 24h, Old24h, Criterr     %@AB@%; Save, replace Int 24h vector%@AE@%%@NL@%
  4483. %@NL@%
  4484.         LoadPtr ds, bx, Block           %@AB@%; Point DS:BX to parameter block%@AE@%%@NL@%
  4485.         push    ds                      %@AB@%; Save segment address%@AE@%%@NL@%
  4486.         les     di, (PARMBLK PTR [bx]).fcb1    %@AB@%; Point ES:DI to first FCB%@AE@%%@NL@%
  4487.         lds     si, (PARMBLK PTR [bx]).taddr   %@AB@%; Point DS:SI to command line tail%@AE@%%@NL@%
  4488.         inc     si                      %@AB@%; Skip over count byte%@AE@%%@NL@%
  4489. %@NL@%
  4490.         mov     ax, 2901h               %@AB@%; Set AH to request Function 29h%@AE@%%@NL@%
  4491.                                         %@AB@%; AL = flag to skip leading blanks%@AE@%%@NL@%
  4492.         int     21h                     %@AB@%; Parse command-line into first FCB%@AE@%%@NL@%
  4493.         pop     es                      %@AB@%; Recover seg addr of parameter block%@AE@%%@NL@%
  4494.         les     di, (PARMBLK PTR es:[bx]).fcb2   %@AB@%; Point ES:DI to second FCB%@AE@%%@NL@%
  4495.         mov     ax, 2901h               %@AB@%; Request DOS Function #29h again%@AE@%%@NL@%
  4496.         int     21h                     %@AB@%; Parse command-line into second FCB%@AE@%%@NL@%
  4497. %@NL@%
  4498.         push    bp                      %@AB@%; Save only important register%@AE@%%@NL@%
  4499.         mov     WORD PTR cs:OldStk[0], sp%@NL@%
  4500.         mov     WORD PTR cs:OldStk[2], ss%@NL@%
  4501.         LoadPtr es, bx, Block           %@AB@%; ES:BX points to param block%@AE@%%@NL@%
  4502.         LoadPtr ds, dx, Spec            %@AB@%; DS:DX points to path spec%@AE@%%@NL@%
  4503.         mov     ax, 4B00h               %@AB@%; AH = DOS Function 4Bh%@AE@%%@NL@%
  4504.                                         %@AB@%; AL = 0 for load and execute%@AE@%%@NL@%
  4505.         int     21h                     %@AB@%; Execute Program%@AE@%%@NL@%
  4506.         mov     sp, WORD PTR cs:OldStk[0] %@AB@%; Reset stack pointers%@AE@%%@NL@%
  4507.         mov     ss, WORD PTR cs:OldStk[2]%@NL@%
  4508.         pop     bp                      %@AB@%; Recover saved register%@AE@%%@NL@%
  4509. %@NL@%
  4510. %@AB@%; Restore vectors for Interrupts 1Bh, 23h, and 24h.%@AE@%%@NL@%
  4511. %@NL@%
  4512.         mov     ax, 251Bh               %@AB@%; AH = DOS Function 25h%@AE@%%@NL@%
  4513.                                         %@AB@%; AL = interrupt number%@AE@%%@NL@%
  4514.         lds     dx, cs:Old1Bh           %@AB@%; DS:DX = original vector%@AE@%%@NL@%
  4515.         int     21h                     %@AB@%; Set Interrupt 1Bh Vector%@AE@%%@NL@%
  4516.         mov     al, 23h                 %@AB@%; AL = interrupt number%@AE@%%@NL@%
  4517.         lds     dx, cs:Old23h           %@AB@%; DS:DX = original vector%@AE@%%@NL@%
  4518.         int     21h                     %@AB@%; Set Interrupt 23h Vector%@AE@%%@NL@%
  4519.         mov     al, 24h                 %@AB@%; AL = interrupt number%@AE@%%@NL@%
  4520.         lds     dx, cs:Old24h           %@AB@%; DS:DX = original vector%@AE@%%@NL@%
  4521.         int     21h                     %@AB@%; Set Interrupt 24h Vector%@AE@%%@NL@%
  4522. %@NL@%
  4523.         mov     ax, -1                  %@AB@%; Set error code%@AE@%%@NL@%
  4524.         .IF     !carry?                 %@AB@%; If no EXEC error:%@AE@%%@NL@%
  4525.         mov     ah, 4Dh                 %@AB@%; Request child's code%@AE@%%@NL@%
  4526.         int     21h                     %@AB@%; Get Return Code%@AE@%%@NL@%
  4527.         sub     ah, ah                  %@AB@%; Make short integer%@AE@%%@NL@%
  4528.         .ENDIF%@NL@%
  4529.         ret%@NL@%
  4530. %@NL@%
  4531. Old1Bh  FPVOID  ?                       %@AB@%; Keep vectors for Interrupts%@AE@%%@NL@%
  4532. Old23h  FPVOID  ?                       %@AB@%;   1Bh, 23h, and 24h in code%@AE@%%@NL@%
  4533. Old24h  FPVOID  ?                       %@AB@%;   segment, but non-executable%@AE@%%@NL@%
  4534. OldStk  FPVOID  ?                       %@AB@%; Keep stack pointer%@AE@%%@NL@%
  4535. %@NL@%
  4536. Exec    ENDP%@NL@%
  4537. %@NL@%
  4538. %@NL@%
  4539. %@AB@%;* BinToHex - Converts binary word to 6-byte hexadecimal number in%@AE@%%@NL@%
  4540. %@AB@%;* ASCIIZ string. String is right-justified and includes "h" radix.%@AE@%%@NL@%
  4541. %@AB@%;*%@AE@%%@NL@%
  4542. %@AB@%;* Shows:   Instruction - xlat%@AE@%%@NL@%
  4543. %@AB@%;*%@AE@%%@NL@%
  4544. %@AB@%;* Params:  Num - Number to convert to hex string%@AE@%%@NL@%
  4545. %@AB@%;*          Sptr - Pointer to 6-byte string%@AE@%%@NL@%
  4546. %@AB@%;*%@AE@%%@NL@%
  4547. %@AB@%;* Return:  None%@AE@%%@NL@%
  4548. %@NL@%
  4549.         .DATA%@NL@%
  4550. hex     BYTE    "0123456789ABCDEF"      %@AB@%; String of hex numbers%@AE@%%@NL@%
  4551. %@NL@%
  4552.         .CODE%@NL@%
  4553. BinToHex PROC USES di,%@NL@%
  4554.         Num:WORD, Sptr:PBYTE%@NL@%
  4555. %@NL@%
  4556.         LoadPtr es, di, Sptr            %@AB@%; Point ES:DI to 6-byte string%@AE@%%@NL@%
  4557.         mov     bx, OFFSET hex          %@AB@%; Point DS:BX to hex numbers%@AE@%%@NL@%
  4558.         mov     ax, Num                 %@AB@%; Number in AX%@AE@%%@NL@%
  4559.         mov     cx, 2                   %@AB@%; Loop twice for two bytes%@AE@%%@NL@%
  4560. %@NL@%
  4561.         .REPEAT%@NL@%
  4562.         xchg    ah, al                  %@AB@%; Switch bytes%@AE@%%@NL@%
  4563.         push    ax                      %@AB@%; Save number%@AE@%%@NL@%
  4564.         shr     al, 1                   %@AB@%; Shift high nibble to low%@AE@%%@NL@%
  4565.         shr     al, 1%@NL@%
  4566.         shr     al, 1%@NL@%
  4567.         shr     al, 1%@NL@%
  4568.         xlat                            %@AB@%; Get equivalent ASCII number in AL%@AE@%%@NL@%
  4569.         stosb                           %@AB@%; Copy to 6-byte string, increment DI%@AE@%%@NL@%
  4570.         pop     ax                      %@AB@%; Recover number%@AE@%%@NL@%
  4571.         push    ax                      %@AB@%; Save it again%@AE@%%@NL@%
  4572.         and     al, 00001111y           %@AB@%; Mask out high nibble%@AE@%%@NL@%
  4573.         xlat                            %@AB@%; Get equivalent ASCII number in AL%@AE@%%@NL@%
  4574.         stosb                           %@AB@%; Copy to 6-byte string, increment DI%@AE@%%@NL@%
  4575.         pop     ax                      %@AB@%; Recover number%@AE@%%@NL@%
  4576.         .UNTILCXZ                       %@AB@%; Do next byte%@AE@%%@NL@%
  4577.         mov     ax, 'h'                 %@AB@%; Put null, 'h' radix in AX%@AE@%%@NL@%
  4578.         stosw                           %@AB@%; Copy to last two bytes in string%@AE@%%@NL@%
  4579.         ret%@NL@%
  4580. %@NL@%
  4581. BinToHex ENDP%@NL@%
  4582. %@NL@%
  4583. %@NL@%
  4584. %@AB@%;* NewBlockSize - Adjusts size of allocated memory block.%@AE@%%@NL@%
  4585. %@AB@%;*%@AE@%%@NL@%
  4586. %@AB@%;* Shows:   DOS Function - 4Ah (Resize Memory Block)%@AE@%%@NL@%
  4587. %@AB@%;*%@AE@%%@NL@%
  4588. %@AB@%;* Params:  Adr - Segment address of block%@AE@%%@NL@%
  4589. %@AB@%;*          Resize - Requested block size in paragraphs%@AE@%%@NL@%
  4590. %@AB@%;*%@AE@%%@NL@%
  4591. %@AB@%;* Return:  Short integer error code%@AE@%%@NL@%
  4592. %@AB@%;*          0 if successful%@AE@%%@NL@%
  4593. %@AB@%;*          1 if error%@AE@%%@NL@%
  4594. %@NL@%
  4595. NewBlockSize PROC,%@NL@%
  4596.         Adr:WORD, Resize:WORD%@NL@%
  4597. %@NL@%
  4598.         mov     ax, Adr                 %@AB@%; Get block address%@AE@%%@NL@%
  4599.         mov     es, ax                  %@AB@%; Point ES to block%@AE@%%@NL@%
  4600.         mov     bx, Resize              %@AB@%; New block size%@AE@%%@NL@%
  4601.         mov     ah, 4Ah                 %@AB@%; Function number%@AE@%%@NL@%
  4602.         int     21h                     %@AB@%; Resize Memory Block%@AE@%%@NL@%
  4603.         ret%@NL@%
  4604. %@NL@%
  4605. NewBlockSize ENDP%@NL@%
  4606. %@NL@%
  4607. %@NL@%
  4608. %@AB@%;* Initialize - Initializes global variables _psp and _env, which are defined%@AE@%%@NL@%
  4609. %@AB@%;* in the DEMO.INC include file. If used with a DOS version less than 3.0,%@AE@%%@NL@%
  4610. %@AB@%;* this procedure will not produce valid results unless it is called before%@AE@%%@NL@%
  4611. %@AB@%;* changing the ES register. This is because at program entry ES points to%@AE@%%@NL@%
  4612. %@AB@%;* the Program Segment Prefix (PSP).%@AE@%%@NL@%
  4613. %@AB@%;*%@AE@%%@NL@%
  4614. %@AB@%;* Params:  None%@AE@%%@NL@%
  4615. %@AB@%;*%@AE@%%@NL@%
  4616. %@AB@%;* Return:  None%@AE@%%@NL@%
  4617. %@NL@%
  4618. Initialize PROC%@NL@%
  4619. %@NL@%
  4620.         INVOKE  GetPSP                  %@AB@%; Get segment address of PSP%@AE@%%@NL@%
  4621.         .IF     ax == 0                 %@AB@%; If less than DOS 3.0:%@AE@%%@NL@%
  4622.         mov     es, ax                  %@AB@%; Reload ES with PSP address%@AE@%%@NL@%
  4623.         .ENDIF%@NL@%
  4624. %@NL@%
  4625.         mov     _psp, es                %@AB@%; Initialize variable with PSP address%@AE@%%@NL@%
  4626.         mov     ax, es:[2Ch]            %@AB@%; Get environment seg from PSP%@AE@%%@NL@%
  4627.         mov     _env, ax                %@AB@%; Store it%@AE@%%@NL@%
  4628.         ret%@NL@%
  4629. %@NL@%
  4630. Initialize ENDP%@NL@%
  4631. %@NL@%
  4632.         END%@NL@%
  4633. %@NL@%
  4634. %@NL@%
  4635. %@2@%%@AH@%MISCDEMO.ASM%@AE@%%@EH@%%@NL@%
  4636. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\DEMOS\MISCDEMO.ASM%@AE@%%@NL@%
  4637. %@NL@%
  4638. %@AB@%;* MISCDEMO - Invokes many of the assembly example procedures, most of them%@AE@%%@NL@%
  4639. %@AB@%;* demonstrating assembly language instructions and calls to the system BIOS.%@AE@%%@NL@%
  4640. %@AB@%;* MISCDEMO demonstrates how to:%@AE@%%@NL@%
  4641. %@AB@%;*%@AE@%%@NL@%
  4642. %@AB@%;*         -   determine hardware information%@AE@%%@NL@%
  4643. %@AB@%;*         -   display time and date while waiting for keystrokes%@AE@%%@NL@%
  4644. %@AB@%;*         -   play notes of any frequency on the speaker%@AE@%%@NL@%
  4645. %@AB@%;*         -   change the line mode for EGA or VGA systems%@AE@%%@NL@%
  4646. %@AB@%;*         -   create non-destructive pop-up windows%@AE@%%@NL@%
  4647. %@AB@%;*         -   execute another program as a child process%@AE@%%@NL@%
  4648. %@AB@%;*         -   create primitive handlers for Interrupts 1Bh, 23h, and 24h%@AE@%%@NL@%
  4649. %@AB@%;*         -   use C-callable procedures in assembly programs%@AE@%%@NL@%
  4650. %@AB@%;*         -   use simplified segment directives%@AE@%%@NL@%
  4651. %@AB@%;*         -   write model-independent procedures%@AE@%%@NL@%
  4652. %@AB@%;*         -   declare and initialize data with DUP, BYTE, WORD, and DWORD%@AE@%%@NL@%
  4653. %@AB@%;*         -   create structures with the STRUCT directive%@AE@%%@NL@%
  4654. %@AB@%;*         -   declare macros%@AE@%%@NL@%
  4655. %@AB@%;*         -   set up a dispatch table%@AE@%%@NL@%
  4656. %@AB@%;*%@AE@%%@NL@%
  4657. %@AB@%;* MISCDEMO.EXE is built from the following files:%@AE@%%@NL@%
  4658. %@AB@%;*    MISCDEMO.ASM - Main program%@AE@%%@NL@%
  4659. %@AB@%;*    MISC.ASM     - Assembly procedures for MISCDEMO%@AE@%%@NL@%
  4660. %@AB@%;*    COMMON.ASM   - Assembly procedures shared by other example programs%@AE@%%@NL@%
  4661. %@AB@%;*    DEMO.INC     - Include file with macros, structure declarations%@AE@%%@NL@%
  4662. %@AB@%;*%@AE@%%@NL@%
  4663. %@AB@%;* Procedures:  GetVidConfig    GetCurPos       VeriPrint       GetPSP%@AE@%%@NL@%
  4664. %@AB@%;*              WinOpen         VeriAnsi        VeriCop         GetVer%@AE@%%@NL@%
  4665. %@AB@%;*              WinClose        StrWrite        SetLineMode     NewBlockSize%@AE@%%@NL@%
  4666. %@AB@%;*              SetCurSize      GetKeyClock     BinToHex        IntToAsc%@AE@%%@NL@%
  4667. %@AB@%;*              SetCurPos       GetShift        Sound           Colors%@AE@%%@NL@%
  4668. %@AB@%;*              GetCurSize      GetMem          Pause           Exec%@AE@%%@NL@%
  4669. %@AB@%;*              WriteTTY        Initialize%@AE@%%@NL@%
  4670. %@NL@%
  4671.         .DOSSEG%@NL@%
  4672.         .MODEL  small, pascal, os_dos%@NL@%
  4673.         INCLUDE demo.inc%@NL@%
  4674. %@NL@%
  4675. NewBreak        PROTO   FAR%@NL@%
  4676. NewCtrlC        PROTO   FAR%@NL@%
  4677. NewCritErr      PROTO   FAR%@NL@%
  4678. DispMenu        PROTO   NEAR%@NL@%
  4679. Press           PROTO   NEAR%@NL@%
  4680. GetVidinfo      PROTO   NEAR%@NL@%
  4681. GetMemInfo      PROTO   NEAR%@NL@%
  4682. CheckPrinter    PROTO   NEAR%@NL@%
  4683. CheckAnsi       PROTO   NEAR%@NL@%
  4684. CheckCoproc     PROTO   NEAR%@NL@%
  4685. GetConfig       PROTO   NEAR%@NL@%
  4686. Speaker         PROTO   NEAR%@NL@%
  4687. SetLines        PROTO   NEAR%@NL@%
  4688. PopWindows      PROTO   NEAR%@NL@%
  4689. SetAttrs        PROTO   NEAR%@NL@%
  4690. ExecPgm         PROTO   NEAR%@NL@%
  4691. %@NL@%
  4692.         .STACK%@NL@%
  4693.         .DATA%@NL@%
  4694. %@NL@%
  4695. PGMSIZE EQU     500h                    %@AB@%; Maximum program size in paragraphs%@AE@%%@NL@%
  4696. F1      EQU     59                      %@AB@%; Extended code for first option key%@AE@%%@NL@%
  4697. F7      EQU     65                      %@AB@%; Extended code for last option key%@AE@%%@NL@%
  4698. CLKROW  EQU     0                       %@AB@%; Row for on-screen clock%@AE@%%@NL@%
  4699. CLKCOL  EQU     62                      %@AB@%; Column for on-screen clock%@AE@%%@NL@%
  4700. %@NL@%
  4701. %@AB@%;* Box - Macro to color portion of screen for effect. Not to be confused with%@AE@%%@NL@%
  4702. %@AB@%;* the WinOpen procedure, which is far more capable.%@AE@%%@NL@%
  4703. %@AB@%;*%@AE@%%@NL@%
  4704. %@AB@%;* Params:  Row1 - Screen row at top of box%@AE@%%@NL@%
  4705. %@AB@%;*          Col1 - Screen column at left side of box%@AE@%%@NL@%
  4706. %@AB@%;*          Row2 - Screen row at bottom of box%@AE@%%@NL@%
  4707. %@AB@%;*          Col2 - Screen column at right side of box%@AE@%%@NL@%
  4708. %@NL@%
  4709. Box MACRO Row1, Col1, Row2, Col2%@NL@%
  4710.     LOCAL sk%@NL@%
  4711.     mov ax, 0600h                       %@AB@%;; Scroll service%@AE@%%@NL@%
  4712.     mov bh, Filmono                     %@AB@%;; Fill attribute%@AE@%%@NL@%
  4713.     .IF vconfig.adapter != MDA          %@AB@%;; If color:%@AE@%%@NL@%
  4714.     mov bh, Filcolr                     %@AB@%;; Use color fill attribute%@AE@%%@NL@%
  4715.     .ENDIF%@NL@%
  4716.     mov ch, Row1%@NL@%
  4717.     mov cl, Col1                        %@AB@%;; CX = row/col for upper left%@AE@%%@NL@%
  4718.     mov dh, Row2%@NL@%
  4719.     mov dl, Col2                        %@AB@%;; DX = row/col for lower right%@AE@%%@NL@%
  4720.     int 10h                             %@AB@%;; Blank window area on screen%@AE@%%@NL@%
  4721. ENDM%@NL@%
  4722. %@NL@%
  4723. OldMode BYTE    ?                       %@AB@%; Original video mode%@AE@%%@NL@%
  4724. OldCurs WORD    ?                       %@AB@%; Original cursor coordinates%@AE@%%@NL@%
  4725. KeepSeg PSEG    ?                       %@AB@%; Segment addr, orig screen%@AE@%%@NL@%
  4726. Filcolr BYTE    1Fh, 20h, 3Bh, 4Eh      %@AB@%; Color fill attributes%@AE@%%@NL@%
  4727. Filmono BYTE    70h, 89h, 78h, 1        %@AB@%; Monochrome fill attributes%@AE@%%@NL@%
  4728. Fill    BYTE    7                       %@AB@%; Default attribute for menu%@AE@%%@NL@%
  4729. Filsub  BYTE    ?                       %@AB@%; Fore/background colors in submenu%@AE@%%@NL@%
  4730. %@NL@%
  4731. PresMsg BYTE    ". . . press a key to continue", 0%@NL@%
  4732. yes     BYTE    "yes"%@NL@%
  4733. no      BYTE    "no "%@NL@%
  4734. %@NL@%
  4735. %@AB@%; Main menu text%@AE@%%@NL@%
  4736. %@NL@%
  4737. Menu1   BYTE    "***  MISC Demonstration Program  ***", 0%@NL@%
  4738. Menu2   BYTE    "F1  System Configuration", 0%@NL@%
  4739. Menu3   BYTE    "F2  Speaker Test", 0%@NL@%
  4740. Menu4   BYTE    "F3  Toggle Line Mode", 0%@NL@%
  4741. Menu5   BYTE    "F4  Windows", 0%@NL@%
  4742. Menu6   BYTE    "F5  Screen Colors", 0%@NL@%
  4743. Menu7   BYTE    "F6  Exec Program", 0%@NL@%
  4744. Menu8   BYTE    "Select an option, or press ESC to quit:", 0%@NL@%
  4745. %@NL@%
  4746. %@AB@%; Option F1 - System Configuration%@AE@%%@NL@%
  4747. %@NL@%
  4748. MonoStr BYTE    "monochrome"%@NL@%
  4749. ClrStr  BYTE    "color     "%@NL@%
  4750. AdapStr BYTE    "MDA CGA MCGAEGA VGA "%@NL@%
  4751. VidMsg1 BYTE    "Adapter:                 xxxx", 0%@NL@%
  4752. VidMsg2 BYTE    "Display:                 xxxxxxxxxx", 0%@NL@%
  4753. VidMsg3 BYTE    "Mode:                    xx", 0%@NL@%
  4754. VidMsg4 BYTE    "Rows:                    xx", 0%@NL@%
  4755. MemMsg1 BYTE    "Total memory:            xxxx Kb", 0%@NL@%
  4756. MemMsg2 BYTE    "Available memory:        xxxx Kb", 0%@NL@%
  4757. PrnMsg  BYTE    "Printer ready:           xxx", 0%@NL@%
  4758. AnsiMsg BYTE    "ANSI driver installed:   xxx", 0%@NL@%
  4759. CopMsg  BYTE    "Coprocessor installed:   xxx", 0%@NL@%
  4760. LEN1    EQU     LENGTHOF CopMsg - 4%@NL@%
  4761. %@NL@%
  4762. %@AB@%; Option F3 - Toggle Line Mode%@AE@%%@NL@%
  4763. %@NL@%
  4764. LineMsg BYTE    "Line mode reset available only for EGA or VGA", 0%@NL@%
  4765. %@NL@%
  4766. %@AB@%; Option F4 - Windows%@AE@%%@NL@%
  4767. %@NL@%
  4768. WinMsg  BYTE    "WINDOW x", 0%@NL@%
  4769. LEN3    EQU     LENGTHOF WinMsg - 2%@NL@%
  4770. %@NL@%
  4771. %@AB@%; Option F5  Screen Colors%@AE@%%@NL@%
  4772. %@NL@%
  4773. CMsg1   BYTE    "Toggle                   Step", 0%@NL@%
  4774. CMsg2   BYTE    "────────────────         ──────────────────", 0%@NL@%
  4775. CMsg3   BYTE    "B  blink                 ", 27, 26, "  foreground", 0%@NL@%
  4776. CMsg4   BYTE    "I  intensity             ", 24, 25, "  background", 0%@NL@%
  4777. CMsg5   BYTE    "Foreground:  press F, then color number 0-7", 0%@NL@%
  4778. CMsg6   BYTE    "Background:  press A, then color number 0-7", 0%@NL@%
  4779. CMsg7   BYTE    "Color Numbers", 0%@NL@%
  4780. CMsg8   BYTE    "───────────────────────────────────────────", 0%@NL@%
  4781. CMsg9   BYTE    "0  black                     4  red", 0%@NL@%
  4782. CMsg10  BYTE    "1  blue                      5  magenta", 0%@NL@%
  4783. CMsg11  BYTE    "2  green                     6  brown", 0%@NL@%
  4784. CMsg12  BYTE    "3  cyan                      7  white", 0%@NL@%
  4785. CMsg13  BYTE    "Toggle", 0%@NL@%
  4786. CMsg14  BYTE    "───────────────", 0%@NL@%
  4787. CMsg15  BYTE    "B  blink", 0%@NL@%
  4788. CMsg16  BYTE    "I  intensity", 0%@NL@%
  4789. CMsg17  BYTE    "U  underline", 0%@NL@%
  4790. CMsg18  BYTE    "R  reverse", 0%@NL@%
  4791. %@NL@%
  4792. %@AB@%; Option F6 - Exec Program%@AE@%%@NL@%
  4793. %@NL@%
  4794. RetMsg  BYTE    "Return code:  "%@NL@%
  4795. Recode  BYTE    6 DUP (?)               %@AB@%; ASCII string for return code%@AE@%%@NL@%
  4796. ExecMsg BYTE    "Enter program file spec (including .COM or .EXE):", 0%@NL@%
  4797. TailMsg BYTE    "Enter command-line argument(s):", 0%@NL@%
  4798. Fspec   BYTE    50, 50 DUP (?)          %@AB@%; File specification (max length = 50)%@AE@%%@NL@%
  4799. Tail    BYTE    50, 50 DUP (?)          %@AB@%; Command-line tail (max length = 50)%@AE@%%@NL@%
  4800. Fcblk1  BYTE    0                       %@AB@%; Allocate space for 1st FCB%@AE@%%@NL@%
  4801.         BYTE    11 DUP (0)%@NL@%
  4802.         BYTE    25 DUP (0)%@NL@%
  4803. Fcblk2  BYTE    0                       %@AB@%; Allocate space for 2nd FCB%@AE@%%@NL@%
  4804.         BYTE    11 DUP (0)%@NL@%
  4805.         BYTE    25 DUP (0)%@NL@%
  4806. pb      PARMBLK <>                      %@AB@%; Parameter block structure%@AE@%%@NL@%
  4807. %@NL@%
  4808. %@AB@%; Initialize dispatch table with offsets for internal procedures.%@AE@%%@NL@%
  4809. %@NL@%
  4810. TPROC   TYPEDEF PROTO           %@AB@%; Procedure type%@AE@%%@NL@%
  4811. PPROC   TYPEDEF PTR TPROC       %@AB@%; Pointer to procedure with no arguments%@AE@%%@NL@%
  4812. %@NL@%
  4813. %@AB@%; Table of procedures%@AE@%%@NL@%
  4814. DispTbl PPROC   GetConfig, Speaker, SetLines,%@NL@%
  4815.                 PopWindows, SetAttrs, ExecPgm%@NL@%
  4816. %@NL@%
  4817.         .CODE%@NL@%
  4818.         .STARTUP%@NL@%
  4819. %@NL@%
  4820.         %@AB@%; Initialize _psp and _env variables%@AE@%%@NL@%
  4821.         INVOKE  Initialize%@NL@%
  4822. %@NL@%
  4823.         %@AB@%; Return unused memory to DOS%@AE@%%@NL@%
  4824.         %@AB@%; Pass PSP segment address and memory block allocated to program%@AE@%%@NL@%
  4825.         INVOKE  NewBlockSize, _psp, PGMSIZE%@NL@%
  4826. %@NL@%
  4827.         %@AB@%; Initialize global configuration data%@AE@%%@NL@%
  4828.         INVOKE  GetVidConfig%@NL@%
  4829. %@NL@%
  4830.         mov     al, vconfig.rows%@NL@%
  4831.         mov     OldMode, al             %@AB@%; Preserve original line mode%@AE@%%@NL@%
  4832. %@NL@%
  4833.         %@AB@%; Get current cursor position%@AE@%%@NL@%
  4834.         INVOKE  GetCurPos%@NL@%
  4835. %@NL@%
  4836.         mov     OldCurs, ax             %@AB@%; Store it%@AE@%%@NL@%
  4837. %@NL@%
  4838.         %@AB@%; Preserve original screen and put up window%@AE@%%@NL@%
  4839.         %@AB@%; Pass top, left, bottom, right, and attribute%@AE@%%@NL@%
  4840.         INVOKE  WinOpen, 0, 0, vconfig.rows, 79, 07h%@NL@%
  4841. %@NL@%
  4842.         mov     KeepSeg, ax             %@AB@%; Keep segment address%@AE@%%@NL@%
  4843.         .IF     AX == 0                 %@AB@%; If window not opened successfully:%@AE@%%@NL@%
  4844.         .EXIT   1                       %@AB@%; Exit with return code = 1%@AE@%%@NL@%
  4845.         .ENDIF%@NL@%
  4846. %@NL@%
  4847.         .WHILE 1%@NL@%
  4848. %@NL@%
  4849.         %@AB@%; Display main menu%@AE@%%@NL@%
  4850.         INVOKE  DispMenu%@NL@%
  4851. %@NL@%
  4852.         %@AB@%; Highlight on-screen clock with macro%@AE@%%@NL@%
  4853.         Box CLKROW, CLKCOL-1, CLKROW, CLKCOL + 17%@NL@%
  4854. %@NL@%
  4855.         %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
  4856.         %@AB@%; Pass row and column%@AE@%%@NL@%
  4857.         INVOKE  GetKeyClock, CLKROW, CLKCOL%@NL@%
  4858. %@NL@%
  4859.         .BREAK .IF al == ESCAPE         %@AB@%; Quit loop if Esc key%@AE@%%@NL@%
  4860. %@NL@%
  4861.         .CONTINUE .IF (ah < F1) || (ah > F7) %@AB@%; Ignore if not a function%@AE@%%@NL@%
  4862.                                              %@AB@%;   key between F1 and F7?%@AE@%%@NL@%
  4863. %@NL@%
  4864.         xchg    al, ah                  %@AB@%; Yes?  Make AX = AH%@AE@%%@NL@%
  4865.         sub     al, F1                  %@AB@%; Normalize to 0%@AE@%%@NL@%
  4866.         shl     al, 1                   %@AB@%; Double to make word index%@AE@%%@NL@%
  4867.         mov     bx, ax                  %@AB@%; BX = index to table%@AE@%%@NL@%
  4868. %@NL@%
  4869.         %@AB@%; Call the current procedure from call table%@AE@%%@NL@%
  4870.         INVOKE  DispTbl[bx]%@NL@%
  4871. %@NL@%
  4872.         .ENDW                           %@AB@%; Loop for another key%@AE@%%@NL@%
  4873. %@NL@%
  4874.         mov     al, OldMode             %@AB@%; Get original line mode%@AE@%%@NL@%
  4875.         .IF     al != vconfig.rows      %@AB@%; If not same as current mode:%@AE@%%@NL@%
  4876. %@NL@%
  4877.         inc     ax                      %@AB@%; Increment to 25/43/50%@AE@%%@NL@%
  4878. %@NL@%
  4879.         %@AB@%; Restore line mode, pass lines%@AE@%%@NL@%
  4880.         INVOKE  SetLineMode, ax%@NL@%
  4881. %@NL@%
  4882.         .ENDIF%@NL@%
  4883. %@NL@%
  4884.         %@AB@%; Restore original screen, pass segment of screen contents%@AE@%%@NL@%
  4885.         INVOKE  WinClose, KeepSeg%@NL@%
  4886. %@NL@%
  4887.         mov     ax, OldCurs%@NL@%
  4888. %@NL@%
  4889.         %@AB@%; Restore cursor to original place%@AE@%%@NL@%
  4890.         %@AB@%; Pass row and column%@AE@%%@NL@%
  4891.         INVOKE  SetCurPos, BYTE PTR OldCurs[1], BYTE PTR OldCurs[0]%@NL@%
  4892. %@NL@%
  4893.         .EXIT   0                       %@AB@%; Exit wih return code 0%@AE@%%@NL@%
  4894. %@NL@%
  4895. %@NL@%
  4896. %@AB@%;* DispMenu - Displays main menu.%@AE@%%@NL@%
  4897. %@AB@%;*%@AE@%%@NL@%
  4898. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  4899. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  4900. %@AB@%;*%@AE@%%@NL@%
  4901. %@AB@%;* Return:  None%@AE@%%@NL@%
  4902. %@NL@%
  4903. DispMenu PROC NEAR%@NL@%
  4904. %@NL@%
  4905.         mov     ax, 0600h               %@AB@%; Scroll screen service%@AE@%%@NL@%
  4906.         mov     bh, Fill                %@AB@%; Menu display attribute%@AE@%%@NL@%
  4907.         sub     cx, cx                  %@AB@%; From row 0, col 0%@AE@%%@NL@%
  4908.         mov     dh, vconfig.rows        %@AB@%;   to bottom row,%@AE@%%@NL@%
  4909.         mov     dl, 79                  %@AB@%;   rightmost column%@AE@%%@NL@%
  4910.         int     10h                     %@AB@%; Clear entire screen%@AE@%%@NL@%
  4911. %@NL@%
  4912.         %@AB@%; Display menu%@AE@%%@NL@%
  4913.         %@AB@%; For each line pass row, column, and string address%@AE@%%@NL@%
  4914.         INVOKE StrWrite,  4, 21, ADDR Menu1%@NL@%
  4915.         INVOKE StrWrite,  8, 28, ADDR Menu2%@NL@%
  4916.         INVOKE StrWrite,  9, 28, ADDR Menu3%@NL@%
  4917.         INVOKE StrWrite, 10, 28, ADDR Menu4%@NL@%
  4918.         INVOKE StrWrite, 11, 28, ADDR Menu5%@NL@%
  4919.         INVOKE StrWrite, 12, 28, ADDR Menu6%@NL@%
  4920.         INVOKE StrWrite, 13, 28, ADDR Menu7%@NL@%
  4921.         INVOKE StrWrite, 17, 18, ADDR Menu8%@NL@%
  4922. %@NL@%
  4923.         %@AB@%; Park cursor at prompt, pass row and column%@AE@%%@NL@%
  4924.         INVOKE  SetCurPos, 17, 18 + (LENGTHOF Menu8) + 2%@NL@%
  4925. %@NL@%
  4926.         ret%@NL@%
  4927. %@NL@%
  4928. DispMenu ENDP%@NL@%
  4929. %@NL@%
  4930. %@NL@%
  4931. %@NL@%
  4932. %@AB@%;* Press - Displays a prompt, then waits for a key press.%@AE@%%@NL@%
  4933. %@AB@%;*%@AE@%%@NL@%
  4934. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  4935. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  4936. %@AB@%;*%@AE@%%@NL@%
  4937. %@AB@%;* Return:  None%@AE@%%@NL@%
  4938. %@NL@%
  4939. Press   PROC NEAR%@NL@%
  4940. %@NL@%
  4941.         %@AB@%; Write string, pass row, column, and string address%@AE@%%@NL@%
  4942.         INVOKE StrWrite, vconfig.rows, 50, ADDR PresMsg%@NL@%
  4943. %@NL@%
  4944.         %@AB@%; Park cursor at prompt, pass row and column%@AE@%%@NL@%
  4945.         INVOKE  SetCurPos, vconfig.rows, 48%@NL@%
  4946. %@NL@%
  4947.         %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
  4948.         %@AB@%; Pass row and column%@AE@%%@NL@%
  4949.         INVOKE  GetKeyClock, CLKROW, CLKCOL%@NL@%
  4950. %@NL@%
  4951.         ret%@NL@%
  4952. %@NL@%
  4953. Press   ENDP%@NL@%
  4954. %@NL@%
  4955. %@NL@%
  4956. %@NL@%
  4957. %@AB@%;* GetVidinfo - Initializes video configuration message for display.%@AE@%%@NL@%
  4958. %@AB@%;*%@AE@%%@NL@%
  4959. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  4960. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  4961. %@AB@%;*%@AE@%%@NL@%
  4962. %@AB@%;* Return:  None%@AE@%%@NL@%
  4963. %@NL@%
  4964. GetVidinfo PROC NEAR%@NL@%
  4965. %@NL@%
  4966.         push    ds%@NL@%
  4967.         pop     es                      %@AB@%; Point ES to data segment%@AE@%%@NL@%
  4968.         mov     al, 4                   %@AB@%; Find index to 4-character%@AE@%%@NL@%
  4969.         mul     vconfig.adapter         %@AB@%;   group in string%@AE@%%@NL@%
  4970.         add     ax, OFFSET AdapStr      %@AB@%; Point AX to proper group%@AE@%%@NL@%
  4971.         mov     si, ax                  %@AB@%; Put pointer in SI%@AE@%%@NL@%
  4972.         lea     di, VidMsg1[LEN1]       %@AB@%; Point to 1st line of message%@AE@%%@NL@%
  4973.         mov     cx, 2                   %@AB@%; Copy 4 letters (adapter%@AE@%%@NL@%
  4974.         rep     movsw                   %@AB@%;   designation) to message%@AE@%%@NL@%
  4975. %@NL@%
  4976.         mov     si, OFFSET MonoStr      %@AB@%; Assume display is monochrome%@AE@%%@NL@%
  4977.         .IF     vconfig.display != MONO %@AB@%; I color display:%@AE@%%@NL@%
  4978.         mov     si, OFFSET ClrStr       %@AB@%; Point to "color" string%@AE@%%@NL@%
  4979.         .ENDIF%@NL@%
  4980.         lea     di, VidMsg2[LEN1]       %@AB@%; Point to 2nd line of message%@AE@%%@NL@%
  4981.         mov     cx, 5                   %@AB@%; Copy 10 chars ("monochrome"%@AE@%%@NL@%
  4982.         rep     movsw                   %@AB@%;   or "color     ") to msg%@AE@%%@NL@%
  4983. %@NL@%
  4984.         %@AB@%; Note that IntToAsc can't be invoked because of its%@AE@%%@NL@%
  4985.         %@AB@%; register calling convention%@AE@%%@NL@%
  4986.         mov     al, vconfig.mode%@NL@%
  4987.         cbw                             %@AB@%; AX = video mode%@AE@%%@NL@%
  4988.         call    IntToAsc                %@AB@%; Convert AX to ASCII%@AE@%%@NL@%
  4989.         xchg    ah, al                  %@AB@%; Flip bytes for word write%@AE@%%@NL@%
  4990.         mov     WORD PTR VidMsg3[LEN1], ax  %@AB@%; Insert in message string%@AE@%%@NL@%
  4991. %@NL@%
  4992.         mov     al, vconfig.rows%@NL@%
  4993.         cbw%@NL@%
  4994.         inc     ax                      %@AB@%; AX = number of screen rows%@AE@%%@NL@%
  4995.         call    IntToAsc                %@AB@%; Convert to ASCII%@AE@%%@NL@%
  4996.         xchg    ah, al                  %@AB@%; Flip bytes for word write%@AE@%%@NL@%
  4997.         mov     WORD PTR VidMsg4[LEN1], ax  %@AB@%; Insert in message string%@AE@%%@NL@%
  4998.         ret%@NL@%
  4999. %@NL@%
  5000. GetVidinfo ENDP%@NL@%
  5001. %@NL@%
  5002. %@NL@%
  5003. %@NL@%
  5004. %@AB@%;* GetMemInfo - Initializes memory information message.%@AE@%%@NL@%
  5005. %@AB@%;*%@AE@%%@NL@%
  5006. %@AB@%;* Return:  None%@AE@%%@NL@%
  5007. %@NL@%
  5008. GetMemInfo PROC NEAR%@NL@%
  5009. %@NL@%
  5010.         %@AB@%; Get total memory in DX, available memory in AX%@AE@%%@NL@%
  5011.         INVOKE  GetMem%@NL@%
  5012. %@NL@%
  5013.         push    ax%@NL@%
  5014.         mov     ax, dx%@NL@%
  5015.         call    IntToAsc                %@AB@%; Convert AX to ASCII%@AE@%%@NL@%
  5016.         xchg    dh, dl                  %@AB@%; Flip bytes for word write%@AE@%%@NL@%
  5017.         xchg    ah, al%@NL@%
  5018.         mov     WORD PTR MemMsg1[LEN1], dx      %@AB@%; Insert in message%@AE@%%@NL@%
  5019.         mov     WORD PTR MemMsg1[LEN1+2], ax    %@AB@%;   string%@AE@%%@NL@%
  5020.         pop     ax                              %@AB@%; Recover avail memory #%@AE@%%@NL@%
  5021.         call    IntToAsc                        %@AB@%; Convert to ASCII%@AE@%%@NL@%
  5022.         xchg    dh, dl                          %@AB@%; Flip bytes for word write%@AE@%%@NL@%
  5023.         xchg    ah, al%@NL@%
  5024.         mov     WORD PTR MemMsg2[LEN1], dx      %@AB@%; Insert in message%@AE@%%@NL@%
  5025.         mov     WORD PTR MemMsg2[LEN1+2], ax    %@AB@%;   string%@AE@%%@NL@%
  5026.         ret%@NL@%
  5027. %@NL@%
  5028. GetMemInfo ENDP%@NL@%
  5029. %@NL@%
  5030. %@NL@%
  5031. %@AB@%;* CheckPrinter - Initializes printer status message.%@AE@%%@NL@%
  5032. %@AB@%;*%@AE@%%@NL@%
  5033. %@AB@%;* Shows:   Instruction - movsb%@AE@%%@NL@%
  5034. %@AB@%;*%@AE@%%@NL@%
  5035. %@AB@%;* Return:  None%@AE@%%@NL@%
  5036. %@NL@%
  5037. CheckPrinter PROC NEAR%@NL@%
  5038. %@NL@%
  5039.         push    ds%@NL@%
  5040.         pop     es                      %@AB@%; Point ES to data segment%@AE@%%@NL@%
  5041.         mov     si, OFFSET yes          %@AB@%; Assume answer is "yes"%@AE@%%@NL@%
  5042. %@NL@%
  5043.         %@AB@%; Check if printer ready%@AE@%%@NL@%
  5044.         INVOKE  VeriPrint%@NL@%
  5045. %@NL@%
  5046.         .IF     al == 0                 %@AB@%; If not ready%@AE@%%@NL@%
  5047.         mov     si, OFFSET no           %@AB@%; Point to "no" answer%@AE@%%@NL@%
  5048.         .ENDIF%@NL@%
  5049.         lea     di, PrnMsg[LEN1]        %@AB@%; Point to print message%@AE@%%@NL@%
  5050.         mov     cx, 3                   %@AB@%; Copy 3 letters (either "yes"%@AE@%%@NL@%
  5051.         rep     movsb                   %@AB@%;   or "no ") to message%@AE@%%@NL@%
  5052.         ret%@NL@%
  5053. %@NL@%
  5054. CheckPrinter ENDP%@NL@%
  5055. %@NL@%
  5056. %@NL@%
  5057. %@NL@%
  5058. %@AB@%;* CheckAnsi - Initializes status message for ANSI driver.%@AE@%%@NL@%
  5059. %@AB@%;*%@AE@%%@NL@%
  5060. %@AB@%;* Return:  None%@AE@%%@NL@%
  5061. %@NL@%
  5062. CheckAnsi PROC NEAR%@NL@%
  5063. %@NL@%
  5064.         push    ds%@NL@%
  5065.         pop     es                      %@AB@%; Point ES to data segment%@AE@%%@NL@%
  5066.         mov     si, OFFSET yes          %@AB@%; Assume answer is "yes"%@AE@%%@NL@%
  5067. %@NL@%
  5068.         %@AB@%; Check if ANSI driver is installed%@AE@%%@NL@%
  5069.         INVOKE  VeriAnsi%@NL@%
  5070. %@NL@%
  5071.         .IF     al == 0                 %@AB@%; If not installed:%@AE@%%@NL@%
  5072.         mov     si, OFFSET no           %@AB@%; Point to "no" answer%@AE@%%@NL@%
  5073.         .ENDIF%@NL@%
  5074.         lea     di, AnsiMsg[LEN1]       %@AB@%; Point to ansi message%@AE@%%@NL@%
  5075.         mov     cx, 3                   %@AB@%; Copy 3 letters (either "yes"%@AE@%%@NL@%
  5076.         rep     movsb                   %@AB@%;   or "no ") to message%@AE@%%@NL@%
  5077.         ret%@NL@%
  5078. %@NL@%
  5079. CheckAnsi ENDP%@NL@%
  5080. %@NL@%
  5081. %@NL@%
  5082. %@NL@%
  5083. %@AB@%;* CheckCoproc - Initializes coprocessor status message.%@AE@%%@NL@%
  5084. %@AB@%;*%@AE@%%@NL@%
  5085. %@AB@%;* Return:  None%@AE@%%@NL@%
  5086. %@NL@%
  5087. CheckCoproc PROC NEAR%@NL@%
  5088. %@NL@%
  5089.         push    ds%@NL@%
  5090.         pop     es                      %@AB@%; Point ES to data segment%@AE@%%@NL@%
  5091.         mov     si, OFFSET yes          %@AB@%; Assume answer is "yes"%@AE@%%@NL@%
  5092. %@NL@%
  5093.         %@AB@%; Check for coprocessor%@AE@%%@NL@%
  5094.         INVOKE  VeriCop%@NL@%
  5095. %@NL@%
  5096.         .IF     al == 0                 %@AB@%; If not installed:%@AE@%%@NL@%
  5097.         mov     si, OFFSET no           %@AB@%; Point to "no" answer%@AE@%%@NL@%
  5098.         .ENDIF%@NL@%
  5099.         lea     di, CopMsg[LEN1]        %@AB@%; Point to coprocessor message%@AE@%%@NL@%
  5100.         mov     cx, 3                   %@AB@%; Copy 3 letters (either "yes"%@AE@%%@NL@%
  5101.         rep     movsb                   %@AB@%;   or "no ") to message%@AE@%%@NL@%
  5102.         ret%@NL@%
  5103. %@NL@%
  5104. CheckCoproc ENDP%@NL@%
  5105. %@NL@%
  5106. %@NL@%
  5107. %@AB@%;* GetConfig - Displays system configuration information.%@AE@%%@NL@%
  5108. %@NL@%
  5109. GetConfig PROC NEAR%@NL@%
  5110. %@NL@%
  5111.         INVOKE  GetVidinfo              %@AB@%; Initialize video message%@AE@%%@NL@%
  5112.         INVOKE  GetMemInfo              %@AB@%; Initialize memory message%@AE@%%@NL@%
  5113.         INVOKE  CheckPrinter            %@AB@%; Initialize printer message%@AE@%%@NL@%
  5114.         INVOKE  CheckAnsi               %@AB@%; Initialize ANSI driver msg%@AE@%%@NL@%
  5115.         INVOKE  CheckCoproc             %@AB@%; Initialize coprocessor msg%@AE@%%@NL@%
  5116. %@NL@%
  5117.         Box 4, 13, 20, 67               %@AB@%; Clear screen with box%@AE@%%@NL@%
  5118. %@NL@%
  5119.         %@AB@%; Display configuration information%@AE@%%@NL@%
  5120.         %@AB@%; For each line, pass row, column, and string address%@AE@%%@NL@%
  5121.         INVOKE  StrWrite,  6, 23, ADDR VidMsg1%@NL@%
  5122.         INVOKE  StrWrite,  7, 23, ADDR VidMsg2%@NL@%
  5123.         INVOKE  StrWrite,  8, 23, ADDR VidMsg3%@NL@%
  5124.         INVOKE  StrWrite,  9, 23, ADDR VidMsg4%@NL@%
  5125.         INVOKE  StrWrite, 11, 23, ADDR MemMsg1%@NL@%
  5126.         INVOKE  StrWrite, 12, 23, ADDR MemMsg2%@NL@%
  5127.         INVOKE  StrWrite, 14, 23, ADDR PrnMsg%@NL@%
  5128.         INVOKE  StrWrite, 16, 23, ADDR AnsiMsg%@NL@%
  5129.         INVOKE  StrWrite, 18, 23, ADDR CopMsg%@NL@%
  5130. %@NL@%
  5131.         %@AB@%; Prompt for keypress%@AE@%%@NL@%
  5132.         INVOKE  Press%@NL@%
  5133. %@NL@%
  5134.         ret%@NL@%
  5135. %@NL@%
  5136. GetConfig ENDP%@NL@%
  5137. %@NL@%
  5138. %@NL@%
  5139. %@NL@%
  5140. %@AB@%;* Speaker - Sounds speaker with ascending frequencies.%@AE@%%@NL@%
  5141. %@AB@%;*%@AE@%%@NL@%
  5142. %@AB@%;* Return:  None%@AE@%%@NL@%
  5143. %@NL@%
  5144. Speaker PROC NEAR%@NL@%
  5145. %@NL@%
  5146.         sub     ax, ax%@NL@%
  5147.         .REPEAT%@NL@%
  5148.         add     ax, 100                 %@AB@%; Start with frequency 100%@AE@%%@NL@%
  5149.         push    ax                      %@AB@%; Save frequency%@AE@%%@NL@%
  5150. %@NL@%
  5151.         %@AB@%; Beep speaker, pass frequency and duration%@AE@%%@NL@%
  5152.         INVOKE  Sound, ax, 1%@NL@%
  5153. %@NL@%
  5154.         pop     ax                      %@AB@%; Recover frequency%@AE@%%@NL@%
  5155.         .UNTIL  ax > 3000               %@AB@%; Continue to frequency 3000%@AE@%%@NL@%
  5156.         ret%@NL@%
  5157. %@NL@%
  5158. Speaker ENDP%@NL@%
  5159. %@NL@%
  5160. %@NL@%
  5161. %@NL@%
  5162. %@AB@%;* SetLines - Toggles between 25/43-line mode for EGA or 25/43/50-line mode%@AE@%%@NL@%
  5163. %@AB@%;* for VGA.%@AE@%%@NL@%
  5164. %@AB@%;*%@AE@%%@NL@%
  5165. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  5166. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  5167. %@AB@%;*%@AE@%%@NL@%
  5168. %@AB@%;* Return:  None%@AE@%%@NL@%
  5169. %@NL@%
  5170. SetLines PROC NEAR%@NL@%
  5171. %@NL@%
  5172.         mov     al, 25                  %@AB@%; Assume toggle to 25 line%@AE@%%@NL@%
  5173.         cmp     vconfig.rows, 49        %@AB@%; Current mode 50 lines?%@AE@%%@NL@%
  5174.         je      toggle25                %@AB@%; Yes?  Toggle VGA to 25-line%@AE@%%@NL@%
  5175.         cmp     vconfig.rows, 42        %@AB@%; Current mode 43 lines?%@AE@%%@NL@%
  5176.         jne     toggle43                %@AB@%; No?  Must be 25%@AE@%%@NL@%
  5177.         cmp     vconfig.adapter, EGA    %@AB@%; Yes?  And is adapter EGA?%@AE@%%@NL@%
  5178.         je      toggle25                %@AB@%; Yes?  Then toggle to 25 line%@AE@%%@NL@%
  5179.         mov     al, 50                  %@AB@%; No?  Toggle VGA to 50 line%@AE@%%@NL@%
  5180.         jmp     toggle25%@NL@%
  5181. toggle43:%@NL@%
  5182.         mov     al, 43                  %@AB@%; If currently 25 lines, make%@AE@%%@NL@%
  5183.                                         %@AB@%;   either EGA or VGA 43 lines%@AE@%%@NL@%
  5184. toggle25:%@NL@%
  5185.         %@AB@%; Change line mode, pass lines%@AE@%%@NL@%
  5186.         INVOKE  SetLineMode, ax%@NL@%
  5187. %@NL@%
  5188.         .IF     al == 0                 %@AB@%; If no error:%@AE@%%@NL@%
  5189.         INVOKE  GetVidConfig            %@AB@%; Update configuration structure%@AE@%%@NL@%
  5190.         .ELSE                           %@AB@%; Else:%@AE@%%@NL@%
  5191.         Box 16, 13, 20, 67              %@AB@%; Display error message%@AE@%%@NL@%
  5192. %@NL@%
  5193.         %@AB@%; Write line message, pass row, column, and string address%@AE@%%@NL@%
  5194.         INVOKE  StrWrite, 18, 17, ADDR LineMsg%@NL@%
  5195. %@NL@%
  5196.         INVOKE  Press%@NL@%
  5197.         .ENDIF%@NL@%
  5198. %@NL@%
  5199.         ret%@NL@%
  5200. %@NL@%
  5201. SetLines ENDP%@NL@%
  5202. %@NL@%
  5203. %@NL@%
  5204. %@NL@%
  5205. %@AB@%;* PopWindows - Demonstrates windowing with the WinOpen and WinClose%@AE@%%@NL@%
  5206. %@AB@%;* procedures.%@AE@%%@NL@%
  5207. %@AB@%;*%@AE@%%@NL@%
  5208. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  5209. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  5210. %@AB@%;*%@AE@%%@NL@%
  5211. %@AB@%;* Return:  None%@AE@%%@NL@%
  5212. %@NL@%
  5213. PopWindows PROC NEAR%@NL@%
  5214. %@NL@%
  5215.         LOCAL Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD%@NL@%
  5216.         LOCAL Index:BYTE, Adr[4]:WORD, Csize:WORD%@NL@%
  5217. %@NL@%
  5218.         %@AB@%; Get current cursor size%@AE@%%@NL@%
  5219.         INVOKE  GetCurSize%@NL@%
  5220. %@NL@%
  5221.         mov     Csize, ax               %@AB@%; Store it%@AE@%%@NL@%
  5222.         or      al, 100000y             %@AB@%; Set 5th bit for cursor off%@AE@%%@NL@%
  5223.         mov     bl, al%@NL@%
  5224. %@NL@%
  5225.         %@AB@%; Set cursor size%@AE@%%@NL@%
  5226.         %@AB@%; Pass arbitrary top and bottom lines with visibility bit off%@AE@%%@NL@%
  5227.         INVOKE  SetCurSize, BYTE PTR Csize[1], bl%@NL@%
  5228. %@NL@%
  5229.         mov     WinMsg[LEN3], "0"       %@AB@%; Initialize window message%@AE@%%@NL@%
  5230.         mov     Row1, 4                 %@AB@%; Initialize window coords%@AE@%%@NL@%
  5231.         mov     Col1, 10%@NL@%
  5232.         mov     Row2, 20%@NL@%
  5233.         mov     Col2, 34%@NL@%
  5234.         mov     Index, 0%@NL@%
  5235.         mov     cx, 4                   %@AB@%; Open 4 windows%@AE@%%@NL@%
  5236.         .REPEAT%@NL@%
  5237.         push    cx                      %@AB@%; Save loop counter%@AE@%%@NL@%
  5238.         mov     al, Index%@NL@%
  5239.         mov     bx, OFFSET Filmono      %@AB@%; BX points to fill attributes%@AE@%%@NL@%
  5240.         .IF     vconfig.display != MONO %@AB@%; If not monochrome:%@AE@%%@NL@%
  5241.         mov     bx, OFFSET Filcolr      %@AB@%; Repoint to color attributes%@AE@%%@NL@%
  5242.         .ENDIF%@NL@%
  5243.         xlat                            %@AB@%; Get attributes in succession%@AE@%%@NL@%
  5244. %@NL@%
  5245.         %@AB@%; Save old window and open new%@AE@%%@NL@%
  5246.         %@AB@%; Pass top, left, bottom, right, and attribute in AX%@AE@%%@NL@%
  5247.         INVOKE  WinOpen, Row1, Col1, Row2, Col2, ax%@NL@%
  5248. %@NL@%
  5249.         pop     di                      %@AB@%; Recover counter in DI%@AE@%%@NL@%
  5250.         push    di                      %@AB@%;   and save it again%@AE@%%@NL@%
  5251.         dec     di%@NL@%
  5252.         shl     di, 1                   %@AB@%; Make DI a word index%@AE@%%@NL@%
  5253.         mov     Adr[di], ax             %@AB@%; Save address of allocated%@AE@%%@NL@%
  5254.                                         %@AB@%;   block returned by WinOpen%@AE@%%@NL@%
  5255.         inc     WinMsg[LEN3]            %@AB@%; Increment window number%@AE@%%@NL@%
  5256.         mov     bx, Row1%@NL@%
  5257.         add     bl, 2                   %@AB@%; Message row%@AE@%%@NL@%
  5258.         mov     cx, Col1%@NL@%
  5259.         add     cl, 9                   %@AB@%; Message column%@AE@%%@NL@%
  5260. %@NL@%
  5261.         %@AB@%; Write window message, pass row, column, and string address%@AE@%%@NL@%
  5262.         INVOKE StrWrite, bx, cx, ADDR WinMsg%@NL@%
  5263. %@NL@%
  5264.         %@AB@%; Pause, pass 18 ticks (about 1 second)%@AE@%%@NL@%
  5265.         INVOKE  Pause, 18%@NL@%
  5266. %@NL@%
  5267.         add     Row1, 2                 %@AB@%; Adjust coordinates for%@AE@%%@NL@%
  5268.         add     Col1, 13                %@AB@%;   next window%@AE@%%@NL@%
  5269.         sub     Row2, 2%@NL@%
  5270.         add     Col2, 13%@NL@%
  5271.         inc     Index%@NL@%
  5272.         pop     cx                      %@AB@%; Recover counter%@AE@%%@NL@%
  5273.         .UNTILCXZ%@NL@%
  5274. %@NL@%
  5275.         mov     cx, 4                   %@AB@%; Close 4 windows%@AE@%%@NL@%
  5276.         sub     di, di                  %@AB@%; DI = index to addresses%@AE@%%@NL@%
  5277. %@NL@%
  5278.         .REPEAT%@NL@%
  5279.         push    cx                      %@AB@%; Save loop counter%@AE@%%@NL@%
  5280. %@NL@%
  5281.         %@AB@%; Close a window, pass address of the window%@AE@%%@NL@%
  5282.         INVOKE  WinClose, Adr[di]%@NL@%
  5283. %@NL@%
  5284.         %@AB@%; Pause, pass 18 ticks (about 1 second)%@AE@%%@NL@%
  5285.         INVOKE  Pause, 18%@NL@%
  5286. %@NL@%
  5287.         add     di, 2                   %@AB@%; Point to next address%@AE@%%@NL@%
  5288.         pop     cx                      %@AB@%; Recover counter%@AE@%%@NL@%
  5289.         .UNTILCXZ                       %@AB@%; Close another window%@AE@%%@NL@%
  5290. %@NL@%
  5291.         mov     ax, Csize               %@AB@%; Get original cursor size%@AE@%%@NL@%
  5292. %@NL@%
  5293.         %@AB@%; Set cursor size, pass top and bottom lines%@AE@%%@NL@%
  5294.         INVOKE  SetCurSize, BYTE PTR Csize[1], BYTE PTR Csize[0]%@NL@%
  5295. %@NL@%
  5296.         ret%@NL@%
  5297. %@NL@%
  5298. PopWindows ENDP%@NL@%
  5299. %@NL@%
  5300. %@NL@%
  5301. %@NL@%
  5302. %@AB@%;* SetAttrs - Changes display attributes for the main menu.%@AE@%%@NL@%
  5303. %@AB@%;*%@AE@%%@NL@%
  5304. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  5305. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  5306. %@AB@%;*%@AE@%%@NL@%
  5307. %@AB@%;* Return:  None%@AE@%%@NL@%
  5308. %@NL@%
  5309. SetAttrs PROC NEAR%@NL@%
  5310. %@NL@%
  5311.         Box 3, 12, 23, 68%@NL@%
  5312.         .IF     vconfig.adapter == MDA  %@AB@%; If monochrome?%@AE@%%@NL@%
  5313. %@NL@%
  5314.         %@AB@%; Write monochrome menu%@AE@%%@NL@%
  5315.         %@AB@%; For each line, pass row, column, and string address%@AE@%%@NL@%
  5316.         INVOKE StrWrite,  8, 32, ADDR CMsg13%@NL@%
  5317.         INVOKE StrWrite,  9, 32, ADDR CMsg14%@NL@%
  5318.         INVOKE StrWrite, 10, 36, ADDR CMsg15%@NL@%
  5319.         INVOKE StrWrite, 11, 36, ADDR CMsg16%@NL@%
  5320.         INVOKE StrWrite, 12, 36, ADDR CMsg17%@NL@%
  5321.         INVOKE StrWrite, 13, 36, ADDR CMsg18%@NL@%
  5322. %@NL@%
  5323.         mov     al, Filmono             %@AB@%; Initialize Filsub variable%@AE@%%@NL@%
  5324.         mov     Filsub, al              %@AB@%;   for monochrome%@AE@%%@NL@%
  5325. %@NL@%
  5326.         .ELSE%@NL@%
  5327. %@NL@%
  5328.         %@AB@%; Write color menu%@AE@%%@NL@%
  5329.         %@AB@%; For each line, pass row, column, and string address%@AE@%%@NL@%
  5330.         INVOKE StrWrite,  4, 18, ADDR CMsg1%@NL@%
  5331.         INVOKE StrWrite,  5, 18, ADDR CMsg2%@NL@%
  5332.         INVOKE StrWrite,  6, 22, ADDR CMsg3%@NL@%
  5333.         INVOKE StrWrite,  7, 22, ADDR CMsg4%@NL@%
  5334.         INVOKE StrWrite, 10, 18, ADDR CMsg5%@NL@%
  5335.         INVOKE StrWrite, 11, 18, ADDR CMsg6%@NL@%
  5336.         INVOKE StrWrite, 14, 18, ADDR CMsg7%@NL@%
  5337.         INVOKE StrWrite, 15, 18, ADDR CMsg8%@NL@%
  5338.         INVOKE StrWrite, 16, 22, ADDR CMsg9%@NL@%
  5339.         INVOKE StrWrite, 17, 22, ADDR CMsg10%@NL@%
  5340.         INVOKE StrWrite, 18, 22, ADDR CMsg11%@NL@%
  5341.         INVOKE StrWrite, 19, 22, ADDR CMsg12%@NL@%
  5342. %@NL@%
  5343.         mov     al, Filcolr             %@AB@%; Initialize Filsub variable%@AE@%%@NL@%
  5344.         mov     Filsub, al              %@AB@%;   for color%@AE@%%@NL@%
  5345.         .ENDIF%@NL@%
  5346. %@NL@%
  5347.         %@AB@%; Write menu message%@AE@%%@NL@%
  5348.         INVOKE StrWrite, 22, 15, ADDR Menu8%@NL@%
  5349. %@NL@%
  5350.         %@AB@%; Park cursor at prompt, pass row and column%@AE@%%@NL@%
  5351.         INVOKE  SetCurPos, 22, 56%@NL@%
  5352. %@NL@%
  5353.         .WHILE   1%@NL@%
  5354. %@NL@%
  5355.         %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
  5356.         %@AB@%; Pass row and column%@AE@%%@NL@%
  5357.         INVOKE  GetKeyClock, CLKROW, CLKCOL%@NL@%
  5358. %@NL@%
  5359.         .BREAK .IF al == ESCAPE         %@AB@%; Quit if Esc key%@AE@%%@NL@%
  5360. %@NL@%
  5361.         .IF (al >= 'a') && (al <= 'z')  %@AB@%; Convert letters to uppercase%@AE@%%@NL@%
  5362.         and     al, 5Fh                 %@AB@%;   to make comparisons easier%@AE@%%@NL@%
  5363.         .ENDIF%@NL@%
  5364. %@NL@%
  5365.         cmp     al, 'B'                 %@AB@%; Request blink toggle?%@AE@%%@NL@%
  5366.         je      blink%@NL@%
  5367.         cmp     al, 'I'                 %@AB@%; Request intensity toggle?%@AE@%%@NL@%
  5368.         je      intense%@NL@%
  5369.         mov     bl, Filsub              %@AB@%; Get window display attribute%@AE@%%@NL@%
  5370.         cmp     vconfig.adapter, MDA    %@AB@%; Monochrome?%@AE@%%@NL@%
  5371.         jne     iscolor                 %@AB@%; No?  Jump to color selections%@AE@%%@NL@%
  5372.         cmp     al, 'U'                 %@AB@%; Request underline toggle?%@AE@%%@NL@%
  5373.         je      underline%@NL@%
  5374.         .CONTINUE .IF al != 'R'         %@AB@%; If not reverse toggle:%@AE@%%@NL@%
  5375.                                         %@AB@%; Skip invalid key%@AE@%%@NL@%
  5376. %@NL@%
  5377. %@AB@%; What with cross-toggling between reverse, normal, and underline, three%@AE@%%@NL@%
  5378. %@AB@%; bit settings can exist in monochrome:  x111x000 for reverse, x000x111 for%@AE@%%@NL@%
  5379. %@AB@%; normal, and x000x001 for underline. Changing between the three involves%@AE@%%@NL@%
  5380. %@AB@%; more than simply XOR-ing the current attribute; each condition must check%@AE@%%@NL@%
  5381. %@AB@%; for the other two.%@AE@%%@NL@%
  5382. %@NL@%
  5383. reverse:%@NL@%
  5384.         .IF     bl & 1                  %@AB@%; If reverse video off:%@AE@%%@NL@%
  5385.         or      bl, 00000111y           %@AB@%; Ensure normal bits are on%@AE@%%@NL@%
  5386.         .ENDIF%@NL@%
  5387. %@NL@%
  5388.         xor     bl, 01110111y           %@AB@%; Toggle for reverse/normal%@AE@%%@NL@%
  5389.         mov     cl, 6                   %@AB@%; Set code for MOV%@AE@%%@NL@%
  5390.         jmp     switch%@NL@%
  5391. %@NL@%
  5392. underline:%@NL@%
  5393.         .IF     bl & 1                  %@AB@%; If reverse video on:%@AE@%%@NL@%
  5394.         and     bl, 10001111y           %@AB@%; Clear bits 4-6%@AE@%%@NL@%
  5395.         or      bl, 00000111y           %@AB@%;   and set bits 0-2%@AE@%%@NL@%
  5396.         .ENDIF%@NL@%
  5397. %@NL@%
  5398.         xor     bl, 00000110y           %@AB@%; Toggle bits 1-2 for underline%@AE@%%@NL@%
  5399.         mov     cl, 6                   %@AB@%; Set code for MOV%@AE@%%@NL@%
  5400.         jmp     switch%@NL@%
  5401. %@NL@%
  5402. %@AB@%; Blink and intensity use the same bits for color and monochrome.%@AE@%%@NL@%
  5403. %@NL@%
  5404. blink:%@NL@%
  5405.         mov     bl, 10000000y           %@AB@%; Set bit 7 for blink%@AE@%%@NL@%
  5406.         mov     cl, 4                   %@AB@%; Set code for XOR%@AE@%%@NL@%
  5407.         jmp     switch%@NL@%
  5408. %@NL@%
  5409. intense:%@NL@%
  5410.         mov     bl, 00001000y           %@AB@%; Set bit 3 for intensity%@AE@%%@NL@%
  5411.         mov     cl, 4                   %@AB@%; Set code for XOR%@AE@%%@NL@%
  5412.         jmp     switch%@NL@%
  5413. %@NL@%
  5414. %@AB@%; Enter this section only for color displays. First check for arrow keys,%@AE@%%@NL@%
  5415. %@AB@%; which increment or decrement the foreground or background bits of the%@AE@%%@NL@%
  5416. %@AB@%; current attribute stored in the variable Filsub. If arrow keys are not%@AE@%%@NL@%
  5417. %@AB@%; pressed, check for the F or A keys, which request specific colors for the%@AE@%%@NL@%
  5418. %@AB@%; foreground or background colors.%@AE@%%@NL@%
  5419. %@NL@%
  5420. iscolor:%@NL@%
  5421.         mov     ch, bl                  %@AB@%; Copy current attribute to CH%@AE@%%@NL@%
  5422.         .IF     ah == 72                %@AB@%; If up arrow:%@AE@%%@NL@%
  5423.         mov     cl, 4                   %@AB@%; Increment bits 4-6%@AE@%%@NL@%
  5424.         shr     ch, cl                  %@AB@%;   to next background color%@AE@%%@NL@%
  5425.         inc     ch%@NL@%
  5426.         and     ch, 00000111y%@NL@%
  5427.         shl     ch, cl%@NL@%
  5428.         mov     dl, 10001111y           %@AB@%; Set background mask%@AE@%%@NL@%
  5429.         jmp     step%@NL@%
  5430.         .ENDIF%@NL@%
  5431. %@NL@%
  5432.         .IF     ah == 75                %@AB@%; If left arrow:%@AE@%%@NL@%
  5433.         inc     ch                      %@AB@%; Increment bits 0-2%@AE@%%@NL@%
  5434.         and     ch, 00000111y           %@AB@%;   to next foreground color%@AE@%%@NL@%
  5435.         mov     dl, 11111000y           %@AB@%; Set foreground mask%@AE@%%@NL@%
  5436.         jmp     step%@NL@%
  5437.         .ENDIF%@NL@%
  5438. %@NL@%
  5439.         .IF     ah == 77                %@AB@%; If right arrow%@AE@%%@NL@%
  5440.         dec     ch                      %@AB@%; Decrement bits 0-2%@AE@%%@NL@%
  5441.         and     ch, 00000111y           %@AB@%;   to previous foreground color%@AE@%%@NL@%
  5442.         mov     dl, 11111000y           %@AB@%; Set foreground mask%@AE@%%@NL@%
  5443.         jmp     step%@NL@%
  5444.         .ENDIF%@NL@%
  5445. %@NL@%
  5446.         .IF     ah == 80                %@AB@%; If down arrow:%@AE@%%@NL@%
  5447.         mov     cl, 4                   %@AB@%; Decrement bits 4-6%@AE@%%@NL@%
  5448.         shr     ch, cl                  %@AB@%;   to previous background color%@AE@%%@NL@%
  5449.         dec     ch%@NL@%
  5450.         and     ch, 00000111y%@NL@%
  5451.         shl     ch, cl%@NL@%
  5452.         mov     dl, 10001111y           %@AB@%; Set background mask%@AE@%%@NL@%
  5453. step:%@NL@%
  5454.         and     bl, dl                  %@AB@%; Mask out fore or back bits%@AE@%%@NL@%
  5455.         or      bl, ch                  %@AB@%; Copy into original attribute%@AE@%%@NL@%
  5456.         mov     Filsub, bl              %@AB@%; Store the new submenu color%@AE@%%@NL@%
  5457.         mov     cl, 6                   %@AB@%; Request move operation in%@AE@%%@NL@%
  5458.         jmp     switch                  %@AB@%;   Colors procedure%@AE@%%@NL@%
  5459.         .ENDIF%@NL@%
  5460. %@NL@%
  5461. %@AB@%; This section checks for the F or A keys; if found it checks again for%@AE@%%@NL@%
  5462. %@AB@%; a number key between 0 and 7, then inserts the correct foreground or%@AE@%%@NL@%
  5463. %@AB@%; background bit pattern into the current fill attribute.%@AE@%%@NL@%
  5464. %@NL@%
  5465.         sub     cx, cx                  %@AB@%; Clear flag for foreground request%@AE@%%@NL@%
  5466.         .IF     al == 'A'               %@AB@%; If background request:%@AE@%%@NL@%
  5467.         inc     cx                      %@AB@%; Set flag for background request%@AE@%%@NL@%
  5468.         .CONTINUE .IF al != 'F'         %@AB@%; If not foreground request, continue%@AE@%%@NL@%
  5469.         .ENDIF%@NL@%
  5470. %@NL@%
  5471.         push    ax%@NL@%
  5472. %@NL@%
  5473.         %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
  5474.         %@AB@%; Pass row and column%@AE@%%@NL@%
  5475.         INVOKE  GetKeyClock, CLKROW, CLKCOL%@NL@%
  5476. %@NL@%
  5477.         pop     cx                      %@AB@%; Recover flag%@AE@%%@NL@%
  5478. %@NL@%
  5479.         .CONTINUE .IF (al < '0') && (al > '7') %@AB@%; Ignore invalid key%@AE@%%@NL@%
  5480. %@NL@%
  5481.         xor     al, '0'                 %@AB@%; Convert ASCII numeral into binary%@AE@%%@NL@%
  5482.         mov     dl, 11111000y           %@AB@%; Set foreground mask%@AE@%%@NL@%
  5483.         .IF     cx != 0                 %@AB@%; Skip if foreground request%@AE@%%@NL@%
  5484.         mov     cl, 4                   %@AB@%; Otherwise shift bits 0-2%@AE@%%@NL@%
  5485.         shl     al, cl                  %@AB@%;   to positions 4-6%@AE@%%@NL@%
  5486.         mov     dl, 10001111y           %@AB@%; Set background mask%@AE@%%@NL@%
  5487.         .ENDIF%@NL@%
  5488. %@NL@%
  5489.         mov     bl, Filsub%@NL@%
  5490.         and     bl, dl                  %@AB@%; Mask out fore or back bits%@AE@%%@NL@%
  5491.         or      bl, al                  %@AB@%; Insert number into fore or back bits%@AE@%%@NL@%
  5492.         mov     Filsub, bl              %@AB@%; Store the new submenu color%@AE@%%@NL@%
  5493.         mov     cl, 6                   %@AB@%; Request move%@AE@%%@NL@%
  5494. switch:%@NL@%
  5495. %@NL@%
  5496.         %@AB@%; Set new attributes in a window%@AE@%%@NL@%
  5497.         %@AB@%; Pass logic code (CX), attribute (BX), top, left, bottom, right%@AE@%%@NL@%
  5498.         INVOKE  Colors, cx, bx, 3, 12, 23, 68%@NL@%
  5499. %@NL@%
  5500.         mov     ah, 8                   %@AB@%; Function 8, get char/attribute%@AE@%%@NL@%
  5501.         mov     bh, vconfig.dpage%@NL@%
  5502.         int     10h                     %@AB@%; Get attribute in AH%@AE@%%@NL@%
  5503.         mov     Fill, ah                %@AB@%; New fill variable for main menu%@AE@%%@NL@%
  5504.         mov     Filsub, ah              %@AB@%;   and for submenu%@AE@%%@NL@%
  5505.         .ENDW%@NL@%
  5506.         ret%@NL@%
  5507. %@NL@%
  5508. SetAttrs ENDP%@NL@%
  5509. %@NL@%
  5510. %@NL@%
  5511. %@NL@%
  5512. %@AB@%;* ExecPgm - Executes a specified program as a child process.%@AE@%%@NL@%
  5513. %@AB@%;*%@AE@%%@NL@%
  5514. %@AB@%;* Uses:    vconfig - Video configuration structure (initialized%@AE@%%@NL@%
  5515. %@AB@%;*          by calling the GetVidConfig procedure)%@AE@%%@NL@%
  5516. %@AB@%;*          pb - Parameter block structure, declared in the DEMO.INC file%@AE@%%@NL@%
  5517. %@AB@%;*%@AE@%%@NL@%
  5518. %@AB@%;* Return:  None%@AE@%%@NL@%
  5519. %@NL@%
  5520. ExecPgm PROC NEAR%@NL@%
  5521. %@NL@%
  5522.         Box 16, 13, 20, 67%@NL@%
  5523. %@NL@%
  5524.         %@AB@%; Display prompt for file spec, pass row, column, and string address%@AE@%%@NL@%
  5525.         INVOKE StrWrite, 17, 16, ADDR ExecMsg%@NL@%
  5526. %@NL@%
  5527.         %@AB@%; Set cursor position below prompt, pass row and column%@AE@%%@NL@%
  5528.         INVOKE  SetCurPos, 19, 16%@NL@%
  5529. %@NL@%
  5530.         mov     ah, 0Ah                 %@AB@%; Request DOS to read keyboard%@AE@%%@NL@%
  5531.         mov     dx, OFFSET Fspec        %@AB@%;   input into Fspec string%@AE@%%@NL@%
  5532.         int     21h                     %@AB@%; Read Buffered Keyboard Input%@AE@%%@NL@%
  5533. %@NL@%
  5534.         Box 16, 13, 20, 67%@NL@%
  5535. %@NL@%
  5536.         %@AB@%; Display prompt for command tail%@AE@%%@NL@%
  5537.         INVOKE StrWrite, 17, 16, ADDR TailMsg%@NL@%
  5538. %@NL@%
  5539.         %@AB@%; Set cursor position below prompt, pass row and column%@AE@%%@NL@%
  5540.         INVOKE  SetCurPos, 19, 16%@NL@%
  5541. %@NL@%
  5542.         mov     ah, 0Ah                 %@AB@%; Request DOS to read keyboard%@AE@%%@NL@%
  5543.         mov     dx, OFFSET Tail         %@AB@%;   input into tail string%@AE@%%@NL@%
  5544.         int     21h                     %@AB@%; Read Buffered Keyboard Input%@AE@%%@NL@%
  5545. %@NL@%
  5546.         sub     bh, bh                  %@AB@%; Clear BH%@AE@%%@NL@%
  5547.         mov     si, OFFSET Fspec        %@AB@%; DS:SI points to file spec string%@AE@%%@NL@%
  5548.         mov     bl, [si+1]              %@AB@%; BL = number of chars in spec%@AE@%%@NL@%
  5549.         mov     BYTE PTR [si+bx+2], 0   %@AB@%; Terminate string with 0%@AE@%%@NL@%
  5550. %@NL@%
  5551.         mov     ax, _env                %@AB@%; Get segment address of environment%@AE@%%@NL@%
  5552.         mov     pb.env, ax              %@AB@%; Copy it to parameter block%@AE@%%@NL@%
  5553.         mov     ax, @data               %@AB@%; AX points to data segment%@AE@%%@NL@%
  5554.         lea     bx, Tail[1]             %@AB@%; BX points to command-line tail%@AE@%%@NL@%
  5555.         mov     WORD PTR pb.taddr[0], bx%@AB@%; Copy address of command-line tail%@AE@%%@NL@%
  5556.         mov     WORD PTR pb.taddr[2], ax%@AB@%;   to parameter block%@AE@%%@NL@%
  5557. %@NL@%
  5558.         mov     bx, OFFSET Fcblk1       %@AB@%; BX points to first FCB%@AE@%%@NL@%
  5559.         mov     WORD PTR pb.fcb1[0], bx %@AB@%; Copy address of first FCB%@AE@%%@NL@%
  5560.         mov     WORD PTR pb.fcb1[2], ax %@AB@%;   to parameter block%@AE@%%@NL@%
  5561.         mov     bx, OFFSET Fcblk2       %@AB@%; BX points to second FCB%@AE@%%@NL@%
  5562.         mov     WORD PTR pb.fcb2[0], bx %@AB@%; Copy address of second FCB%@AE@%%@NL@%
  5563.         mov     WORD PTR pb.fcb2[2], ax %@AB@%;   to parameter block%@AE@%%@NL@%
  5564. %@NL@%
  5565. %@AB@%; At this point, the program file is specified, the command line tail is set,%@AE@%%@NL@%
  5566. %@AB@%; and the parameter block is properly initialized. The Exec procedure will%@AE@%%@NL@%
  5567. %@AB@%; take care of loading the FCBs with command-line arguments and resetting%@AE@%%@NL@%
  5568. %@AB@%; interrupt vectors. Now blank the screen in preparation for executing the%@AE@%%@NL@%
  5569. %@AB@%; process and pass the five pointers to the Exec procedure.%@AE@%%@NL@%
  5570. %@NL@%
  5571.         mov     ax, 0600h               %@AB@%; AH = scroll service, AL = 0%@AE@%%@NL@%
  5572.         mov     bh, 7                   %@AB@%; Blank with normal attribute%@AE@%%@NL@%
  5573.         sub     cx, cx                  %@AB@%; From row 0, col 0%@AE@%%@NL@%
  5574.         mov     dh, vconfig.rows        %@AB@%;   to bottom row%@AE@%%@NL@%
  5575.         mov     dl, 79                  %@AB@%;   and rightmost column%@AE@%%@NL@%
  5576.         int     10h                     %@AB@%; Blank screen%@AE@%%@NL@%
  5577. %@NL@%
  5578.         %@AB@%; Set cursor at top of screen, pass row and column%@AE@%%@NL@%
  5579.         INVOKE  SetCurPos, 0, 0%@NL@%
  5580. %@NL@%
  5581. %@NL@%
  5582.         %@AB@%; Exec specified program%@AE@%%@NL@%
  5583.         INVOKE  Exec,%@NL@%
  5584.                 ADDR Fspec[2],          %@AB@%; File spec%@AE@%%@NL@%
  5585.                 ADDR pb,                %@AB@%; Parameter block structure%@AE@%%@NL@%
  5586.                 NewBreak,               %@AB@%; New handlers for CTRL+BREAK,%@AE@%%@NL@%
  5587.                 NewCtrlC,               %@AB@%;   CTRL+C%@AE@%%@NL@%
  5588.                 NewCritErr              %@AB@%;   and Critical Error%@AE@%%@NL@%
  5589. %@NL@%
  5590. %@NL@%
  5591.         .IF     ax != -1                %@AB@%; If successful:%@AE@%%@NL@%
  5592. %@NL@%
  5593.         %@AB@%; Convert return code to string%@AE@%%@NL@%
  5594.         %@AB@%; Pass return code (AX) and address of string buffer%@AE@%%@NL@%
  5595.         INVOKE  BinToHex, ax, ADDR Recode%@NL@%
  5596. %@NL@%
  5597.         %@AB@%; Update video structure%@AE@%%@NL@%
  5598.         INVOKE  GetVidConfig%@NL@%
  5599. %@NL@%
  5600.         Box CLKROW, CLKCOL-1, CLKROW, CLKCOL+17 %@AB@%; Highlight on-screen clock%@AE@%%@NL@%
  5601.         Box vconfig.rows, 0, vconfig.rows, 79   %@AB@%; Highlight bottom row%@AE@%%@NL@%
  5602.         mov     dl, vconfig.rows%@NL@%
  5603. %@NL@%
  5604.         %@AB@%; Display return code at bottom%@AE@%%@NL@%
  5605.         INVOKE StrWrite, dx, 0, ADDR RetMsg%@NL@%
  5606. %@NL@%
  5607.         %@AB@%; Wait for keypress%@AE@%%@NL@%
  5608.         INVOKE  Press%@NL@%
  5609.         .ELSE%@NL@%
  5610.         mov     ax, 0E07h               %@AB@%; Write ASCII 7 character%@AE@%%@NL@%
  5611.         int     10h                     %@AB@%;   (bell) to console%@AE@%%@NL@%
  5612.         .ENDIF%@NL@%
  5613. %@NL@%
  5614.         ret%@NL@%
  5615. %@NL@%
  5616. ExecPgm ENDP%@NL@%
  5617. %@NL@%
  5618. %@NL@%
  5619. %@NL@%
  5620. %@AB@%;* The following three procedures are primitive handlers for Interrupt 1Bh%@AE@%%@NL@%
  5621. %@AB@%;* (Ctrl-Break), Interrupt 23h (Ctrl-C), and Interrupt 24h (Critical Error).%@AE@%%@NL@%
  5622. %@AB@%;* The purpose of an interrupt handler in this context is to prevent termina-%@AE@%%@NL@%
  5623. %@AB@%;* tion of both parent and child processes when the interrupt is invoked.%@AE@%%@NL@%
  5624. %@AB@%;* Such handlers often set flags to signal a process that the interrupt has%@AE@%%@NL@%
  5625. %@AB@%;* been called.%@AE@%%@NL@%
  5626. %@NL@%
  5627. %@AB@%;* NewBreak - Handler for Interrupt 1Bh.%@AE@%%@NL@%
  5628. %@NL@%
  5629. NewBreak PROC   FAR%@NL@%
  5630. %@NL@%
  5631.         sti                             %@AB@%; Reenable interrupts%@AE@%%@NL@%
  5632.         push    ax                      %@AB@%; Preserve AX register%@AE@%%@NL@%
  5633.         mov     al, 20h                 %@AB@%; Send end-of-interrupt signal%@AE@%%@NL@%
  5634.         out     20h, al                 %@AB@%;   to interrupt controller%@AE@%%@NL@%
  5635.         pop     ax                      %@AB@%; Recover AX register%@AE@%%@NL@%
  5636.         iret                            %@AB@%; Return from handler%@AE@%%@NL@%
  5637.                                         %@AB@%;   without taking action%@AE@%%@NL@%
  5638. NewBreak ENDP%@NL@%
  5639. %@NL@%
  5640. %@NL@%
  5641. %@AB@%;* NewCtrlC - Handler for Interrupt 23h.%@AE@%%@NL@%
  5642. %@NL@%
  5643. NewCtrlC PROC   FAR%@NL@%
  5644. %@NL@%
  5645.         iret                            %@AB@%; Return from handler%@AE@%%@NL@%
  5646.                                         %@AB@%;   without taking action%@AE@%%@NL@%
  5647. NewCtrlC ENDP%@NL@%
  5648. %@NL@%
  5649. %@NL@%
  5650. %@AB@%;* NewCritErr - Handler for Interrupt 24h.%@AE@%%@NL@%
  5651. %@NL@%
  5652. NewCritErr PROC FAR%@NL@%
  5653. %@NL@%
  5654.         sub     al, al                  %@AB@%; Tell DOS to ignore error%@AE@%%@NL@%
  5655.         iret                            %@AB@%; Return from handler%@AE@%%@NL@%
  5656.                                         %@AB@%;   without taking action%@AE@%%@NL@%
  5657. NewCritErr ENDP%@NL@%
  5658. %@NL@%
  5659.         END%@NL@%
  5660. %@NL@%
  5661. %@NL@%
  5662. %@NL@%
  5663. %@2@%%@AH@%PAGERP.ASM%@AE@%%@EH@%%@NL@%
  5664. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\SHOW\PAGERP.ASM%@AE@%%@NL@%
  5665. %@NL@%
  5666. %@AB@%;* PAGERP.ASM - Module containing routines for paging through a file and%@AE@%%@NL@%
  5667. %@AB@%;* writing text to the screen buffer. Works with main module SHOWP.ASM.%@AE@%%@NL@%
  5668. %@NL@%
  5669.         TITLE   Pager%@NL@%
  5670.         .MODEL  small, pascal, os_os2%@NL@%
  5671.         .286%@NL@%
  5672. %@NL@%
  5673. INCL_NOCOMMON   EQU 1         %@AB@%; Enable call groups%@AE@%%@NL@%
  5674. INCL_VIO        EQU 1%@NL@%
  5675. %@NL@%
  5676.         INCLUDE os2.inc%@NL@%
  5677.         INCLUDE show.inc%@NL@%
  5678. %@NL@%
  5679.         .CODE%@NL@%
  5680. %@NL@%
  5681. %@AB@%;* Pager - Displays status line and all the text lines for a screen.%@AE@%%@NL@%
  5682. %@AB@%;*%@AE@%%@NL@%
  5683. %@AB@%;* Params: cLines - lines to scroll (negative up, positive down)%@AE@%%@NL@%
  5684. %@AB@%;*%@AE@%%@NL@%
  5685. %@AB@%;* Uses:   Global variables: segBuf, offBuf, yCur%@AE@%%@NL@%
  5686. %@AB@%;*%@AE@%%@NL@%
  5687. %@AB@%;* Return: None%@AE@%%@NL@%
  5688. %@NL@%
  5689. Pager   PROC,%@NL@%
  5690.         cLines:SWORD%@NL@%
  5691. %@NL@%
  5692.         mov     es, segBuf              %@AB@%; Initialize buffer position%@AE@%%@NL@%
  5693.         mov     di, offBuf%@NL@%
  5694. %@NL@%
  5695.         mov     cx, cLines              %@AB@%; Get line count%@AE@%%@NL@%
  5696.         mov     ax, 10                  %@AB@%; Search for linefeed%@AE@%%@NL@%
  5697. %@NL@%
  5698.         or      cx, cx                  %@AB@%; Argument 0?%@AE@%%@NL@%
  5699.         jl      backward                %@AB@%; If below, backward%@AE@%%@NL@%
  5700.         jg      foreward                %@AB@%; If above, forward%@AE@%%@NL@%
  5701.         jmp     showit                  %@AB@%; If equal, done%@AE@%%@NL@%
  5702. %@NL@%
  5703. backward:%@NL@%
  5704.         call    GoBack                  %@AB@%; Adjust backward%@AE@%%@NL@%
  5705.         jmp     showit                  %@AB@%; Show screen%@AE@%%@NL@%
  5706. %@NL@%
  5707. foreward:%@NL@%
  5708.         call    GoForeward              %@AB@%; Adjust forward%@AE@%%@NL@%
  5709. %@NL@%
  5710. %@AB@%; Write line number to status line%@AE@%%@NL@%
  5711. %@NL@%
  5712. showit:%@NL@%
  5713.         cld                             %@AB@%; Forward%@AE@%%@NL@%
  5714.         push    di                      %@AB@%; Save%@AE@%%@NL@%
  5715.         push    ds                      %@AB@%; ES = DS%@AE@%%@NL@%
  5716.         pop     es%@NL@%
  5717. %@NL@%
  5718.         INVOKE  BinToStr,               %@AB@%; Write line number as string%@AE@%%@NL@%
  5719.                 yCur,%@NL@%
  5720.                 ADDR stLine[LINE_POS]%@NL@%
  5721. %@NL@%
  5722. %@AB@%; Fill in status line%@AE@%%@NL@%
  5723. %@NL@%
  5724.         mov     cx, 6                   %@AB@%; Six spaces to fill%@AE@%%@NL@%
  5725.         sub     cx, ax                  %@AB@%; Subtract those already done%@AE@%%@NL@%
  5726.         mov     al, ' '                 %@AB@%; Fill with space%@AE@%%@NL@%
  5727.         rep     stosb%@NL@%
  5728. %@NL@%
  5729.         INVOKE  VioWrtCharStrAtt,       %@AB@%; Write to screen%@AE@%%@NL@%
  5730.                 ADDR stLine,%@NL@%
  5731.                 X_MAX,%@NL@%
  5732.                 0,%@NL@%
  5733.                 0,%@NL@%
  5734.                 ADDR atSta,%@NL@%
  5735.                 0%@NL@%
  5736. %@NL@%
  5737.         pop     di                      %@AB@%; Update position%@AE@%%@NL@%
  5738.         mov     si, di%@NL@%
  5739.         mov     cx, yMax                %@AB@%; Lines per screen%@AE@%%@NL@%
  5740. %@NL@%
  5741.         .REPEAT%@NL@%
  5742.         mov     bx, yMax                %@AB@%; Lines per screen%@AE@%%@NL@%
  5743.         inc     bx                      %@AB@%; Adjust for 0%@AE@%%@NL@%
  5744.         sub     bx, cx                  %@AB@%; Calculate current row%@AE@%%@NL@%
  5745.         push    cx                      %@AB@%; Save line number%@AE@%%@NL@%
  5746.         mov     es, segBuf              %@AB@%; Reload%@AE@%%@NL@%
  5747. %@NL@%
  5748.         INVOKE  ShowLine,               %@AB@%; Write line to screen%@AE@%%@NL@%
  5749.                 es::si,                 %@AB@%; Pointer to current position%@AE@%%@NL@%
  5750.                 bx,                     %@AB@%; Line number%@AE@%%@NL@%
  5751.                 cbBuf,                  %@AB@%; File length (for bounds check)%@AE@%%@NL@%
  5752.                 ADDR atScr              %@AB@%; Attribute%@AE@%%@NL@%
  5753. %@NL@%
  5754.         pop     cx                      %@AB@%; Restore line number%@AE@%%@NL@%
  5755.         mov     si, ax                  %@AB@%; Get returned position%@AE@%%@NL@%
  5756. %@NL@%
  5757.         dec     cx                      %@AB@%; Count the line%@AE@%%@NL@%
  5758.         .UNTIL  (ax >= cbBuf) || !cx    %@AB@%; Continue if more lines and not%@AE@%%@NL@%
  5759.         jcxz    exit                    %@AB@%; Done if more lines,%@AE@%%@NL@%
  5760.                                         %@AB@%;   else fill screen with spaces%@AE@%%@NL@%
  5761.         mov     ax, X_MAX               %@AB@%; Columns times remaining lines%@AE@%%@NL@%
  5762.         mul     cl%@NL@%
  5763.         mov     dx, ax                  %@AB@%; INVOKE uses AX, so use DX%@AE@%%@NL@%
  5764.         sub     cx, yMax                %@AB@%; Calculate starting line%@AE@%%@NL@%
  5765.         neg     cx%@NL@%
  5766.         inc     cx%@NL@%
  5767. %@NL@%
  5768.         INVOKE  VioWrtNCell,            %@AB@%; Write space cells%@AE@%%@NL@%
  5769.                 ADDR celScr,            %@AB@%; Cell of space and attribute%@AE@%%@NL@%
  5770.                 dx,                     %@AB@%; Number of cells to fill%@AE@%%@NL@%
  5771.                 cx,                     %@AB@%; Line to start fill%@AE@%%@NL@%
  5772.                 0,                      %@AB@%; Column 0%@AE@%%@NL@%
  5773.                 0                       %@AB@%; Console handle%@AE@%%@NL@%
  5774. exit:%@NL@%
  5775.         ret%@NL@%
  5776. %@NL@%
  5777. Pager   ENDP%@NL@%
  5778. %@NL@%
  5779. %@NL@%
  5780. %@AB@%;* ShowLine - Writes a line of text to the screen.%@AE@%%@NL@%
  5781. %@AB@%;*%@AE@%%@NL@%
  5782. %@AB@%;* Params: pchIn - Far pointer to input text%@AE@%%@NL@%
  5783. %@AB@%;*         y - Line number%@AE@%%@NL@%
  5784. %@AB@%;*         cbMax - Maximum number of characters (file length)%@AE@%%@NL@%
  5785. %@AB@%;*         pcelAtrib - Far pointer to attribute%@AE@%%@NL@%
  5786. %@AB@%;*%@AE@%%@NL@%
  5787. %@AB@%;* Return: None%@AE@%%@NL@%
  5788. %@NL@%
  5789. ShowLine PROC USES si di,%@NL@%
  5790.         pchIn:PBYTE,%@NL@%
  5791.         y:WORD,%@NL@%
  5792.         cbMax:WORD,%@NL@%
  5793.         pcelAtrib:PBYTE%@NL@%
  5794. %@NL@%
  5795.         LOCAL   achOut[X_MAX]:BYTE%@NL@%
  5796. %@NL@%
  5797.         push    ds                      %@AB@%; Save%@AE@%%@NL@%
  5798.         push    ss                      %@AB@%; ES = SS%@AE@%%@NL@%
  5799.         pop     es%@NL@%
  5800.         lea     di, achOut              %@AB@%; Destination line%@AE@%%@NL@%
  5801.         lds     si, pchIn               %@AB@%; Source line%@AE@%%@NL@%
  5802.         mov     cx, X_MAX               %@AB@%; Cells per row%@AE@%%@NL@%
  5803.         mov     bx, di                  %@AB@%; Save copy of start for tab calc%@AE@%%@NL@%
  5804. loop1:%@NL@%
  5805.         lodsb                           %@AB@%; Get character%@AE@%%@NL@%
  5806.         cmp     al, 9                   %@AB@%; Tab?%@AE@%%@NL@%
  5807.         je      filltab                 %@AB@%; Space out tab%@AE@%%@NL@%
  5808.         cmp     al, 13                  %@AB@%; CR?%@AE@%%@NL@%
  5809.         je      filleol                 %@AB@%; Fill rest of line with spaces%@AE@%%@NL@%
  5810.         stosb                           %@AB@%; Copy out%@AE@%%@NL@%
  5811.         cmp     si, cbMax               %@AB@%; Check for end of file%@AE@%%@NL@%
  5812.         ja      filleol%@NL@%
  5813.         loop    loop1%@NL@%
  5814. loop2:%@NL@%
  5815.         lodsb                           %@AB@%; Throw away rest of line to truncate%@AE@%%@NL@%
  5816.         cmp     si, cbMax               %@AB@%; Check for end of file%@AE@%%@NL@%
  5817.         ja      exit%@NL@%
  5818.         cmp     al, 13                  %@AB@%; Check for end of line%@AE@%%@NL@%
  5819.         jne     loop2%@NL@%
  5820.         inc     si                      %@AB@%; Throw away line feed%@AE@%%@NL@%
  5821. %@NL@%
  5822.         jmp     exit                    %@AB@%; Done%@AE@%%@NL@%
  5823. filltab:%@NL@%
  5824.         push    bx                      %@AB@%; Fill tab with spaces%@AE@%%@NL@%
  5825.         push    cx%@NL@%
  5826. %@NL@%
  5827.         sub     bx, di                  %@AB@%; Get current position in line%@AE@%%@NL@%
  5828.         neg     bx%@NL@%
  5829. %@NL@%
  5830.         mov     cx, 8                   %@AB@%; Default count 8%@AE@%%@NL@%
  5831.         and     bx, 7                   %@AB@%; Get modulus%@AE@%%@NL@%
  5832.         sub     cx, bx                  %@AB@%; Subtract%@AE@%%@NL@%
  5833.         mov     bx, cx                  %@AB@%; Save modulus%@AE@%%@NL@%
  5834. %@NL@%
  5835.         mov     al, ' '                 %@AB@%; Write spaces%@AE@%%@NL@%
  5836.         rep     stosb%@NL@%
  5837. %@NL@%
  5838.         pop     cx%@NL@%
  5839.         sub     cx, bx                  %@AB@%; Adjust count%@AE@%%@NL@%
  5840.         .IF     sign?%@NL@%
  5841.         sub     cx, cx                  %@AB@%; Make negative count 0%@AE@%%@NL@%
  5842.         .ENDIF%@NL@%
  5843. %@NL@%
  5844.         pop     bx%@NL@%
  5845.         jcxz    loop2                   %@AB@%; If beyond limit done%@AE@%%@NL@%
  5846.         jmp     loop1%@NL@%
  5847. filleol:%@NL@%
  5848.         inc     si                      %@AB@%; After CR, throw away LF%@AE@%%@NL@%
  5849.         mov     al, ' '                 %@AB@%; Fill rest of line%@AE@%%@NL@%
  5850.         rep     stosb%@NL@%
  5851. exit:%@NL@%
  5852.         pop     ds%@NL@%
  5853.         INVOKE  VioWrtCharStrAtt,%@NL@%
  5854.                 ADDR achOut,%@NL@%
  5855.                 X_MAX,%@NL@%
  5856.                 y,%@NL@%
  5857.                 0,%@NL@%
  5858.                 pcelAtrib,%@NL@%
  5859.                 0%@NL@%
  5860. %@NL@%
  5861.         mov     ax, si                  %@AB@%; Return position%@AE@%%@NL@%
  5862.         ret%@NL@%
  5863. %@NL@%
  5864. ShowLine ENDP%@NL@%
  5865. %@NL@%
  5866. %@NL@%
  5867.         END%@NL@%
  5868. %@NL@%
  5869. %@NL@%
  5870. %@2@%%@AH@%PAGERR.ASM%@AE@%%@EH@%%@NL@%
  5871. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\SHOW\PAGERR.ASM%@AE@%%@NL@%
  5872. %@NL@%
  5873. %@AB@%;* PAGERR.ASM - Module containing routines for paging through a file and%@AE@%%@NL@%
  5874. %@AB@%;* writing text to the screen buffer. Works with main module SHOWR.ASM.%@AE@%%@NL@%
  5875. %@NL@%
  5876. %@NL@%
  5877.         .MODEL  small, pascal, os_dos   %@AB@%; This code also works in tiny model%@AE@%%@NL@%
  5878. %@NL@%
  5879.         INCLUDE show.inc%@NL@%
  5880. %@NL@%
  5881.         .CODE%@NL@%
  5882. %@NL@%
  5883. %@AB@%;* Pager - Displays status line and all the text lines for a screen.%@AE@%%@NL@%
  5884. %@AB@%;*%@AE@%%@NL@%
  5885. %@AB@%;* Params: cLines - lines to scroll (negative up, positive down)%@AE@%%@NL@%
  5886. %@AB@%;*%@AE@%%@NL@%
  5887. %@AB@%;* Uses:   Global variables: segBuf, offBuf, yCur%@AE@%%@NL@%
  5888. %@AB@%;*%@AE@%%@NL@%
  5889. %@AB@%;* Return: None%@AE@%%@NL@%
  5890. %@NL@%
  5891. Pager   PROC,%@NL@%
  5892.         cLines:SWORD%@NL@%
  5893. %@NL@%
  5894.         mov     es, segBuf              %@AB@%; Initialize buffer position%@AE@%%@NL@%
  5895.         mov     di, offBuf%@NL@%
  5896. %@NL@%
  5897.         mov     cx, cLines              %@AB@%; Get line count%@AE@%%@NL@%
  5898.         mov     ax, 10                  %@AB@%; Search for linefeed%@AE@%%@NL@%
  5899. %@NL@%
  5900.         or      cx, cx                  %@AB@%; Argument 0?%@AE@%%@NL@%
  5901.         jg      forward                 %@AB@%; If above, forward%@AE@%%@NL@%
  5902.         jl      backward                %@AB@%; If below, backward%@AE@%%@NL@%
  5903.         jmp     showit                  %@AB@%; If equal, done%@AE@%%@NL@%
  5904. backward:%@NL@%
  5905.         call    GoBack                  %@AB@%; Adjust backward%@AE@%%@NL@%
  5906.         jmp     showit                  %@AB@%; Show screen%@AE@%%@NL@%
  5907. forward:%@NL@%
  5908.         call    GoForeward              %@AB@%; Adjust forward%@AE@%%@NL@%
  5909. %@NL@%
  5910. %@AB@%; Write        line number to status line%@AE@%%@NL@%
  5911. %@NL@%
  5912. showit:%@NL@%
  5913.         cld                             %@AB@%; Forward%@AE@%%@NL@%
  5914.         push    di                      %@AB@%; Save%@AE@%%@NL@%
  5915.         push    ds                      %@AB@%; ES = DS%@AE@%%@NL@%
  5916.         pop     es%@NL@%
  5917. %@NL@%
  5918.         INVOKE  BinToStr,               %@AB@%; Write line number as string%@AE@%%@NL@%
  5919.                 yCur,%@NL@%
  5920.                 ADDR stLine[LINE_POS]%@NL@%
  5921. %@NL@%
  5922. %@AB@%; Fill in status line%@AE@%%@NL@%
  5923. %@NL@%
  5924.         mov     cx, 6                   %@AB@%; Seven spaces to fill%@AE@%%@NL@%
  5925.         sub     cx, ax                  %@AB@%; Subtract those already done%@AE@%%@NL@%
  5926.         mov     al, ' '                 %@AB@%; Fill with space%@AE@%%@NL@%
  5927.         rep     stosb%@NL@%
  5928. %@NL@%
  5929.         INVOKE  ShowLine,               %@AB@%; Write to screen%@AE@%%@NL@%
  5930.                 ADDR stLine,            %@AB@%; Far pointer to line%@AE@%%@NL@%
  5931.                 0,                      %@AB@%; Line number%@AE@%%@NL@%
  5932.                 atSta                   %@AB@%; Atttribute%@AE@%%@NL@%
  5933. %@NL@%
  5934.         pop     di%@NL@%
  5935.         mov     si, di                  %@AB@%; Update position%@AE@%%@NL@%
  5936.         mov     cx, yMax                %@AB@%; Lines per screen%@AE@%%@NL@%
  5937. %@NL@%
  5938.         .REPEAT%@NL@%
  5939.         mov     bx, yMax                %@AB@%; Lines per screen%@AE@%%@NL@%
  5940.         inc     bx                      %@AB@%; Adjust for 0%@AE@%%@NL@%
  5941.         sub     bx, cx                  %@AB@%; Calculate current row%@AE@%%@NL@%
  5942.         push    cx                      %@AB@%; Save line number%@AE@%%@NL@%
  5943.         mov     es, segBuf              %@AB@%; Reload%@AE@%%@NL@%
  5944. %@NL@%
  5945.         INVOKE  ShowLine,               %@AB@%; Write line to screen%@AE@%%@NL@%
  5946.                 es::si,                 %@AB@%; Far pointer to text%@AE@%%@NL@%
  5947.                 bx,                     %@AB@%; Line number%@AE@%%@NL@%
  5948.                 atScr                   %@AB@%; Attribute%@AE@%%@NL@%
  5949. %@NL@%
  5950.         pop     cx                      %@AB@%; Restore line number%@AE@%%@NL@%
  5951.         mov     si, ax                  %@AB@%; Get returned position%@AE@%%@NL@%
  5952. %@NL@%
  5953.         dec     cx                      %@AB@%; Count the line%@AE@%%@NL@%
  5954.         .UNTIL  (ax >= cbBuf) || !cx    %@AB@%; Continue if more lines and not%@AE@%%@NL@%
  5955.         jcxz    exit                    %@AB@%; Done if more lines,%@AE@%%@NL@%
  5956.                                         %@AB@%;   else fill screen with spaces%@AE@%%@NL@%
  5957.         mov     al, cl                  %@AB@%; Columns * remaining lines%@AE@%%@NL@%
  5958.         mov     dl, X_MAX               %@AB@%;   is count of cells to fill%@AE@%%@NL@%
  5959.         mul     dl%@NL@%
  5960.         mov     dx, ax                  %@AB@%; Save in DX (INVOKE uses AX)%@AE@%%@NL@%
  5961. %@NL@%
  5962.         sub     cx, yMax                %@AB@%; Calculate starting line%@AE@%%@NL@%
  5963.         neg     cx%@NL@%
  5964.         inc     cx%@NL@%
  5965. %@NL@%
  5966.         INVOKE  CellFill,               %@AB@%; Write space cells%@AE@%%@NL@%
  5967.                 cx,                     %@AB@%; Starting line%@AE@%%@NL@%
  5968.                 dx,                     %@AB@%; Cells to write%@AE@%%@NL@%
  5969.                 celScr                  %@AB@%; Cell to write%@AE@%%@NL@%
  5970. exit:%@NL@%
  5971.         ret%@NL@%
  5972. %@NL@%
  5973. Pager   ENDP%@NL@%
  5974. %@NL@%
  5975. %@NL@%
  5976. %@AB@%;* WriteNCell - Macro to write a cell one or more times. For CGA, the%@AE@%%@NL@%
  5977. %@AB@%;* macro writes during horizontal retrace. Note that this is a macro%@AE@%%@NL@%
  5978. %@AB@%;* even though it may result in more code than if it were a procedure.%@AE@%%@NL@%
  5979. %@AB@%;* This is because writes to the screen buffer are a speed bottleneck%@AE@%%@NL@%
  5980. %@AB@%;* that only occurs at a few key points in the program. The extra%@AE@%%@NL@%
  5981. %@AB@%;* size cost is worth paying.%@AE@%%@NL@%
  5982. %@AB@%;*%@AE@%%@NL@%
  5983. %@AB@%;* Uses:   ES:DI has screen buffer position%@AE@%%@NL@%
  5984. %@AB@%;*         AX has cell%@AE@%%@NL@%
  5985. %@AB@%;*         DX should have port number for rescan check if CGA%@AE@%%@NL@%
  5986. %@AB@%;*%@AE@%%@NL@%
  5987. %@AB@%;* Params: isCGA - One of the following:%@AE@%%@NL@%
  5988.                 CGA     EQU     1%@NL@%
  5989.                 NoCGA   EQU     0%@NL@%
  5990. %@AB@%;*%@AE@%%@NL@%
  5991. %@AB@%;*         count - If blank, write cell in AX once. If count given, write%@AE@%%@NL@%
  5992. %@AB@%;*         cell in AX count times. Note that the count is optimized for a%@AE@%%@NL@%
  5993. %@AB@%;*         CX argument. The argument should normally be blank or CX.%@AE@%%@NL@%
  5994. %@NL@%
  5995. WriteNCell MACRO isCGA:REQ, count:=<1>%@NL@%
  5996. %@NL@%
  5997.     IF isCGA EQ 0                       %@AB@%; First handle non-CGA%@AE@%%@NL@%
  5998.         IFIDNI <count>, <1>             %@AB@%; Special case one cell%@AE@%%@NL@%
  5999.             stosw%@NL@%
  6000.         ELSE%@NL@%
  6001.             IFDIFI <count>, <cx>        %@AB@%; Load count if necessary%@AE@%%@NL@%
  6002.                 mov  cx, count%@NL@%
  6003.             ENDIF%@NL@%
  6004.             rep  stosw                  %@AB@%; Do repeated sequence%@AE@%%@NL@%
  6005.         ENDIF%@NL@%
  6006.     ELSE%@NL@%
  6007.         IFIDNI <count>, <1>             %@AB@%; Special case one cell%@AE@%%@NL@%
  6008.             push    ax                  %@AB@%; Save character%@AE@%%@NL@%
  6009.             .REPEAT%@NL@%
  6010.             in      al, dx              %@AB@%; Look in the port%@AE@%%@NL@%
  6011.             shr     al, 1               %@AB@%;   until it goes low%@AE@%%@NL@%
  6012.             .UNTIL  !carry?%@NL@%
  6013.             cli%@NL@%
  6014.             .REPEAT%@NL@%
  6015.             in      al, dx              %@AB@%; Look in the port%@AE@%%@NL@%
  6016.             shr     al, 1               %@AB@%;   until it goes high%@AE@%%@NL@%
  6017.             .UNTIL  carry?%@NL@%
  6018.             pop     ax                  %@AB@%; Restore and write it%@AE@%%@NL@%
  6019.             stosw%@NL@%
  6020.             sti%@NL@%
  6021.         ELSE%@NL@%
  6022.             IFDIFI <count>, <cx>        %@AB@%; Load count if necessary%@AE@%%@NL@%
  6023.                 mov  cx, count%@NL@%
  6024.             ENDIF%@NL@%
  6025.             .REPEAT%@NL@%
  6026.             push    ax                  %@AB@%; Save character%@AE@%%@NL@%
  6027.             .REPEAT%@NL@%
  6028.             in      al, dx              %@AB@%; Look in the port%@AE@%%@NL@%
  6029.             shr     al, 1               %@AB@%;   until it goes low%@AE@%%@NL@%
  6030.             .UNTIL  !carry?%@NL@%
  6031.             cli%@NL@%
  6032.             .REPEAT%@NL@%
  6033.             in      al, dx              %@AB@%; Look in the port%@AE@%%@NL@%
  6034.             shr     al, 1               %@AB@%;   until it goes high%@AE@%%@NL@%
  6035.             .UNTIL  carry?%@NL@%
  6036.             pop     ax                  %@AB@%; Restore and write it%@AE@%%@NL@%
  6037.             stosw%@NL@%
  6038.             sti%@NL@%
  6039.             .UNTILCXZ%@NL@%
  6040.         ENDIF%@NL@%
  6041.     ENDIF%@NL@%
  6042. ENDM%@NL@%
  6043. %@NL@%
  6044. %@AB@%;* ShowLine - Writes a line to the screen buffer.%@AE@%%@NL@%
  6045. %@AB@%;*%@AE@%%@NL@%
  6046. %@AB@%;* Params: fpBuffer - Far pointer to line to write%@AE@%%@NL@%
  6047. %@AB@%;*         y - Line number%@AE@%%@NL@%
  6048. %@AB@%;*         attr - Attribute%@AE@%%@NL@%
  6049. %@AB@%;*%@AE@%%@NL@%
  6050. %@AB@%;* Return: None%@AE@%%@NL@%
  6051. %@NL@%
  6052. ShowLine PROC USES si di ds,%@NL@%
  6053.         fpBuffer:FAR PTR BYTE,%@NL@%
  6054.         y:WORD,%@NL@%
  6055.         attr:BYTE%@NL@%
  6056. %@NL@%
  6057.         sub     dx, dx                  %@AB@%; Zero%@AE@%%@NL@%
  6058.         .IF     fCGA                    %@AB@%; User port number as CGA flag%@AE@%%@NL@%
  6059.         mov     dx, 03DAh               %@AB@%; Load port #%@AE@%%@NL@%
  6060.         .ENDIF%@NL@%
  6061.         mov     es, segVid              %@AB@%; Load screen buffer segment%@AE@%%@NL@%
  6062.         lds     si, fpBuffer            %@AB@%; Buffer segment%@AE@%%@NL@%
  6063.         mov     cx, X_MAX               %@AB@%; Cells per row%@AE@%%@NL@%
  6064.         mov     ax, y                   %@AB@%; Starting row%@AE@%%@NL@%
  6065.         mov     bx, X_MAX * 2           %@AB@%; Bytes per row%@AE@%%@NL@%
  6066.         mul     bl                      %@AB@%; Figure columns per row%@AE@%%@NL@%
  6067.         mov     di, ax                  %@AB@%; Load as destination%@AE@%%@NL@%
  6068.         mov     bx, di                  %@AB@%; Save start for tab calculation%@AE@%%@NL@%
  6069.         mov     ah, attr                %@AB@%; Attribute%@AE@%%@NL@%
  6070. movechar:%@NL@%
  6071.         lodsb                           %@AB@%; Get character%@AE@%%@NL@%
  6072.         cmp     al, 13                  %@AB@%; CR?%@AE@%%@NL@%
  6073.         je      fillspc%@NL@%
  6074.         cmp     al, 9                   %@AB@%; Tab?%@AE@%%@NL@%
  6075.         jne     notab%@NL@%
  6076.         call    FillTab                 %@AB@%; Yes? fill with spaces%@AE@%%@NL@%
  6077.         jcxz    nextline                %@AB@%; If beyond limit done%@AE@%%@NL@%
  6078.         jmp     movechar%@NL@%
  6079. notab:%@NL@%
  6080.         or      dx, dx                  %@AB@%; CGA?%@AE@%%@NL@%
  6081.         je      notab2%@NL@%
  6082.         WriteNCell CGA                  %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
  6083.         loop    movechar                %@AB@%; Duplicate code here and below%@AE@%%@NL@%
  6084.         jmp     nextline                %@AB@%;   is worth cost in tight loop%@AE@%%@NL@%
  6085. notab2:%@NL@%
  6086.         WriteNCell NoCGA                %@AB@%; Write%@AE@%%@NL@%
  6087.         loop    movechar%@NL@%
  6088.         jmp     nextline                %@AB@%; Done%@AE@%%@NL@%
  6089. fillspc:%@NL@%
  6090.         mov     al, ' '                 %@AB@%; Fill with space%@AE@%%@NL@%
  6091. %@NL@%
  6092.         .IF     dx != 0                 %@AB@%; CGA?%@AE@%%@NL@%
  6093.         WriteNCell CGA, cx%@NL@%
  6094.         inc     si                      %@AB@%; Adjust%@AE@%%@NL@%
  6095.         jmp     exit                    %@AB@%; Done%@AE@%%@NL@%
  6096.         .ENDIF%@NL@%
  6097.         WriteNCell NoCGA, cx%@NL@%
  6098.         inc     si                      %@AB@%; Adjust for LF%@AE@%%@NL@%
  6099.         jmp     exit                    %@AB@%; Done%@AE@%%@NL@%
  6100. nextline:%@NL@%
  6101.         mov     ah, 10                  %@AB@%; Search for next line feed%@AE@%%@NL@%
  6102.         .REPEAT%@NL@%
  6103.         lodsb                           %@AB@%; Load and compare%@AE@%%@NL@%
  6104.         .UNTILCXZ al == ah%@NL@%
  6105. exit:%@NL@%
  6106.         mov     ax, si                  %@AB@%; Return position%@AE@%%@NL@%
  6107.         ret%@NL@%
  6108. %@NL@%
  6109. ShowLine ENDP%@NL@%
  6110. %@NL@%
  6111. %@NL@%
  6112. %@AB@%;* CellFill - Fills a portion of the screen with a specified%@AE@%%@NL@%
  6113. %@AB@%;* character/attribute cell.%@AE@%%@NL@%
  6114. %@AB@%;*%@AE@%%@NL@%
  6115. %@AB@%;* Params: yStart - Starting line%@AE@%%@NL@%
  6116. %@AB@%;*         cbCell - Number of cells%@AE@%%@NL@%
  6117. %@AB@%;*         celFill - Attribute and character%@AE@%%@NL@%
  6118. %@AB@%;*%@AE@%%@NL@%
  6119. %@AB@%;* Return: None%@AE@%%@NL@%
  6120. %@NL@%
  6121. CellFill PROC,%@NL@%
  6122.         yStart:WORD,%@NL@%
  6123.         cbCell:WORD,%@NL@%
  6124.         celFill:WORD%@NL@%
  6125. %@NL@%
  6126.         mov     dx, 03DAh               %@AB@%; Load port #%@AE@%%@NL@%
  6127.         mov     cx, yStart              %@AB@%; Starting line%@AE@%%@NL@%
  6128.         mov     al, X_MAX * 2           %@AB@%; Convert line to starting offset%@AE@%%@NL@%
  6129.         mul     cl%@NL@%
  6130.         mov     di, ax                  %@AB@%; Make it the target%@AE@%%@NL@%
  6131.         mov     es, segVid              %@AB@%; Load screen buffer segment%@AE@%%@NL@%
  6132.         mov     cx, cbCell              %@AB@%; Characters to fill%@AE@%%@NL@%
  6133.         mov     ax, celFill             %@AB@%; Attribute%@AE@%%@NL@%
  6134.         .IF     fCGA                    %@AB@%; Write cells%@AE@%%@NL@%
  6135.         WriteNCell CGA, cx%@NL@%
  6136.         .ELSE%@NL@%
  6137.         WriteNCell NoCGA, cx%@NL@%
  6138.         .ENDIF%@NL@%
  6139. %@NL@%
  6140.         ret%@NL@%
  6141. %@NL@%
  6142. CellFill ENDP%@NL@%
  6143. %@NL@%
  6144. %@NL@%
  6145. %@AB@%;* FillTab - Writes spaces for tab to screen.%@AE@%%@NL@%
  6146. %@AB@%;*%@AE@%%@NL@%
  6147. %@AB@%;* Input:  BX points to start of line%@AE@%%@NL@%
  6148. %@AB@%;*         DI points to current position%@AE@%%@NL@%
  6149. %@AB@%;*%@AE@%%@NL@%
  6150. %@AB@%;* Return: None%@AE@%%@NL@%
  6151. %@NL@%
  6152. FillTab PROC%@NL@%
  6153. %@NL@%
  6154.         push    bx%@NL@%
  6155.         push    cx%@NL@%
  6156. %@NL@%
  6157.         sub     bx, di                  %@AB@%; Get current position in line%@AE@%%@NL@%
  6158.         neg     bx%@NL@%
  6159.         shr     bx, 1                   %@AB@%; Divide by 2 bytes per character%@AE@%%@NL@%
  6160. %@NL@%
  6161.         mov     cx, 8                   %@AB@%; Default count 8%@AE@%%@NL@%
  6162.         and     bx, 7                   %@AB@%; Get modulus%@AE@%%@NL@%
  6163.         sub     cx, bx                  %@AB@%; Subtract%@AE@%%@NL@%
  6164.         mov     bx, cx                  %@AB@%; Save modulus%@AE@%%@NL@%
  6165. %@NL@%
  6166.         mov     al, ' '                 %@AB@%; Spaces%@AE@%%@NL@%
  6167.         .IF     dx != 0                 %@AB@%; Write cells%@AE@%%@NL@%
  6168.         WriteNCell CGA, cx%@NL@%
  6169.         .ELSE%@NL@%
  6170.         WriteNCell NoCGA, cx%@NL@%
  6171.         .ENDIF%@NL@%
  6172.         pop     cx%@NL@%
  6173.         sub     cx, bx                  %@AB@%; Adjust count%@AE@%%@NL@%
  6174.         .IF     sign?%@NL@%
  6175.         sub     cx, cx                  %@AB@%; Make negative count 0%@AE@%%@NL@%
  6176.         .ENDIF%@NL@%
  6177.         pop     bx%@NL@%
  6178.         ret%@NL@%
  6179. %@NL@%
  6180. FillTab ENDP%@NL@%
  6181. %@NL@%
  6182. %@NL@%
  6183. %@AB@%;* IsEGA - Determines if the current adapter can handle more than 25%@AE@%%@NL@%
  6184. %@AB@%;* lines per screen (usually an EGA or VGA).%@AE@%%@NL@%
  6185. %@AB@%;*%@AE@%%@NL@%
  6186. %@AB@%;* Params: None%@AE@%%@NL@%
  6187. %@AB@%;*%@AE@%%@NL@%
  6188. %@AB@%;* Return: 0 if no CGA or MONO, lines per screen if EGA/VGA%@AE@%%@NL@%
  6189. %@NL@%
  6190. IsEGA   PROC%@NL@%
  6191. %@NL@%
  6192.         mov     ah, 12h                 %@AB@%; Call EGA status function%@AE@%%@NL@%
  6193.         mov     bl, 10h%@NL@%
  6194.         sub     cx, cx                  %@AB@%; Clear status bits%@AE@%%@NL@%
  6195.         int     10h%@NL@%
  6196.         sub     ax, ax                  %@AB@%; Segment 0 and assume no EGA%@AE@%%@NL@%
  6197.         jcxz    noega                   %@AB@%; If status still clear, no EGA%@AE@%%@NL@%
  6198. %@NL@%
  6199.         mov     es, ax                  %@AB@%; ES=0%@AE@%%@NL@%
  6200.         test    BYTE PTR es:[487h], 1000y%@AB@%; Test active bit%@AE@%%@NL@%
  6201.         jnz     noega                   %@AB@%; If set, not active%@AE@%%@NL@%
  6202.         mov     ax, 1130h               %@AB@%; Get EGA information%@AE@%%@NL@%
  6203.         int     10h%@NL@%
  6204.         mov     al, dl                  %@AB@%; Return lines per screen%@AE@%%@NL@%
  6205.         cbw%@NL@%
  6206. noega:%@NL@%
  6207.         ret%@NL@%
  6208. %@NL@%
  6209. IsEGA   ENDP%@NL@%
  6210. %@NL@%
  6211. %@NL@%
  6212.         END%@NL@%
  6213. %@NL@%
  6214. %@NL@%
  6215. %@2@%%@AH@%PASCAL.ASM%@AE@%%@EH@%%@NL@%
  6216. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\MIXED\PASCAL.ASM%@AE@%%@NL@%
  6217. %@NL@%
  6218. %@AB@%; Assemble with ML /c PASCAL.ASM%@AE@%%@NL@%
  6219. %@AB@%; Called by PASMAIN.PAS%@AE@%%@NL@%
  6220. %@NL@%
  6221.         .MODEL  medium, PASCAL%@NL@%
  6222.         .386%@NL@%
  6223. Power2  PROTO PASCAL  factor:WORD, power:WORD%@NL@%
  6224.         .CODE%@NL@%
  6225. %@NL@%
  6226. Power2  PROC    factor:WORD, power:WORD%@NL@%
  6227. %@NL@%
  6228.         mov     ax, factor    %@AB@%; Load Factor into AX%@AE@%%@NL@%
  6229.         mov     cx, power     %@AB@%; Load Power into CX%@AE@%%@NL@%
  6230.         shl     ax, cl        %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
  6231.         ret                   %@AB@%; Leave return value in AX%@AE@%%@NL@%
  6232. %@NL@%
  6233. Power2  ENDP%@NL@%
  6234.         END%@NL@%
  6235. %@NL@%
  6236. %@NL@%
  6237. %@2@%%@AH@%QPEX.ASM%@AE@%%@EH@%%@NL@%
  6238. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\MIXED\QPEX.ASM%@AE@%%@NL@%
  6239. %@NL@%
  6240. %@AB@%; Assemble with ML /c QPEX.ASM%@AE@%%@NL@%
  6241. %@NL@%
  6242. Power2  PROTO PASCAL  factor:WORD, power:WORD%@NL@%
  6243. %@NL@%
  6244. CODE        SEGMENT WORD PUBLIC%@NL@%
  6245.         ASSUME  CS:CODE%@NL@%
  6246. %@NL@%
  6247. %@NL@%
  6248. Power2  PROC PASCAL   factor:WORD, power:WORD%@NL@%
  6249. %@NL@%
  6250.         mov     ax, factor        %@AB@%; Load factor into AX%@AE@%%@NL@%
  6251.         mov     cx, power         %@AB@%; Load power into CX%@AE@%%@NL@%
  6252.         shl        ax, cl                  %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
  6253.                                   %@AB@%; Leave return value in AX%@AE@%%@NL@%
  6254.         ret%@NL@%
  6255. Power2  ENDP%@NL@%
  6256. %@NL@%
  6257. CODE    ENDS%@NL@%
  6258.         END%@NL@%
  6259. %@NL@%
  6260. %@NL@%
  6261. %@2@%%@AH@%SHOWP.ASM%@AE@%%@EH@%%@NL@%
  6262. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\SHOW\SHOWP.ASM%@AE@%%@NL@%
  6263. %@NL@%
  6264. %@AB@%;* SHOWP.ASM - Text file displayer for OS/2 (protect mode).%@AE@%%@NL@%
  6265. %@NL@%
  6266.         TITLE   Show%@NL@%
  6267.         .MODEL  small, pascal, os_os2%@NL@%
  6268.         .DOSSEG%@NL@%
  6269.         .286%@NL@%
  6270. %@NL@%
  6271. INCL_NOCOMMON   EQU 1         %@AB@%; Enable call groups%@AE@%%@NL@%
  6272. INCL_DOSFILEMGR EQU 1%@NL@%
  6273. INCL_DOSMEMMGR  EQU 1%@NL@%
  6274. INCL_KBD        EQU 1%@NL@%
  6275. INCL_VIO        EQU 1%@NL@%
  6276. %@NL@%
  6277.         INCLUDE os2.inc%@NL@%
  6278.         INCLUDE show.inc%@NL@%
  6279.         INCLUDELIB os2.lib%@NL@%
  6280. %@NL@%
  6281.         .STACK%@NL@%
  6282. %@NL@%
  6283.         .DATA%@NL@%
  6284. %@NL@%
  6285. %@AB@%; Status line%@AE@%%@NL@%
  6286. %@NL@%
  6287. stLine  BYTE    "Line: 12345 "%@NL@%
  6288. stFile  BYTE    "File: 12345678.123  "%@NL@%
  6289.         BYTE    "Quit: Q  Next: ESC  Move:   PGUP PGDN HOME END"%@NL@%
  6290. %@NL@%
  6291. %@AB@%; Variables for screen and cursor handling%@AE@%%@NL@%
  6292. %@NL@%
  6293. yCur    WORD    1               %@AB@%; Current line number%@AE@%%@NL@%
  6294. yMax    WORD    ?               %@AB@%; Lines per screen%@AE@%%@NL@%
  6295. vmiMode VIOMODEINFO < SIZE VIOMODEINFO > %@AB@%; Structure for video data%@AE@%%@NL@%
  6296.                                 %@AB@%; First field initialized to size%@AE@%%@NL@%
  6297. vciCsr  VIOCURSORINFO <>        %@AB@%; Structure for cursor data%@AE@%%@NL@%
  6298. atCsr   WORD    -1              %@AB@%; Cursor attribute (initized to hidden)%@AE@%%@NL@%
  6299. bCsrSta BYTE    0               %@AB@%; 0 = cursor visible, position unchanged%@AE@%%@NL@%
  6300.                                 %@AB@%; 1 = cursor invisible, position unchanged%@AE@%%@NL@%
  6301.                                 %@AB@%; 2 = cursor invisible, position changed%@AE@%%@NL@%
  6302. %@NL@%
  6303. atSta   BYTE    STAT_CLR        %@AB@%; Status line color%@AE@%%@NL@%
  6304. celScr  LABEL   WORD            %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
  6305. chScr   BYTE    " "             %@AB@%; Initialize to space%@AE@%%@NL@%
  6306. atScr   BYTE    SCRN_CLR        %@AB@%; Screen color%@AE@%%@NL@%
  6307. chInit  BYTE    0               %@AB@%; Cell to restore when finished%@AE@%%@NL@%
  6308. atInit  BYTE    0%@NL@%
  6309. %@NL@%
  6310. %@AB@%; Buffer variables%@AE@%%@NL@%
  6311. %@NL@%
  6312. fpBuf   LABEL   PBYTE%@NL@%
  6313. offBuf  WORD    0               %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
  6314. segBuf  SEL     ?               %@AB@%; Base of buffer (segment selector)%@AE@%%@NL@%
  6315. cbBuf   WORD    ?               %@AB@%; Count in bytes of buffer%@AE@%%@NL@%
  6316. %@NL@%
  6317. %@AB@%; File information%@AE@%%@NL@%
  6318. %@NL@%
  6319. hFileIn HFILE   ?               %@AB@%; Holds file handle on open%@AE@%%@NL@%
  6320. usAct   WORD    ?               %@AB@%; Result of open%@AE@%%@NL@%
  6321. usMode  WORD    OPEN_ACCESS_READONLY OR OPEN_SHARE_DENYNONE%@NL@%
  6322. cbRead  WORD    ?               %@AB@%; Bytes read from file%@AE@%%@NL@%
  6323. %@NL@%
  6324. %@AB@%; Directory information for file name search%@AE@%%@NL@%
  6325. %@NL@%
  6326. stFiles BYTE    NAME_MAX DUP ("w")%@NL@%
  6327. hFiles  WORD    HDIR_CREATE     %@AB@%; Directory handle%@AE@%%@NL@%
  6328. fiFiles FILEFINDBUF <>          %@AB@%; Structure for results%@AE@%%@NL@%
  6329. usCount WORD    1               %@AB@%; Find one file at a time%@AE@%%@NL@%
  6330. %@NL@%
  6331. %@AB@%; Buffer for file name%@AE@%%@NL@%
  6332. %@NL@%
  6333. kkiChar KBDKEYINFO <>           %@AB@%; Structure for character input%@AE@%%@NL@%
  6334. sibStr  STRINGINBUF < NAME_MAX >%@AB@%; Structure for string input%@AE@%%@NL@%
  6335. %@NL@%
  6336. %@AB@%; Messages%@AE@%%@NL@%
  6337. %@NL@%
  6338. stMsg1  BYTE    13, 10, "Enter filename: "%@NL@%
  6339. stMsg2  BYTE    13, 10, "File problem. Try again? "%@NL@%
  6340. stMsg3  BYTE    13, 10, "File too large: "%@NL@%
  6341. stMsg4  BYTE    13, 10, "Memory problem.",13,10%@NL@%
  6342. %@NL@%
  6343. %@AB@%; Call table%@AE@%%@NL@%
  6344. %@NL@%
  6345. achKeys BYTE    71, 72, 73, 79, 80, 81, 'q', 'Q'%@AB@%; Key table%@AE@%%@NL@%
  6346. afnKeys WORD    HomeKey                         %@AB@%; Corresponding procedures%@AE@%%@NL@%
  6347.         WORD    UpKey%@NL@%
  6348.         WORD    PgUpKey%@NL@%
  6349.         WORD    EndKey%@NL@%
  6350.         WORD    DownKey%@NL@%
  6351.         WORD    PgDnKey%@NL@%
  6352.         WORD    Quit%@NL@%
  6353.         WORD    Quit%@NL@%
  6354.         WORD    UnknownKey%@NL@%
  6355. %@NL@%
  6356.         .CODE%@NL@%
  6357.         .STARTUP%@NL@%
  6358. %@NL@%
  6359. %@AB@%; Load environment segment%@AE@%%@NL@%
  6360. %@NL@%
  6361.         mov     es, ax                  %@AB@%; AX points to environment segment%@AE@%%@NL@%
  6362.         mov     di, bx                  %@AB@%; BX points to command line offset%@AE@%%@NL@%
  6363. %@NL@%
  6364. %@AB@%; Throw away .EXE name%@AE@%%@NL@%
  6365. %@NL@%
  6366.         sub     ax, ax                  %@AB@%; Find null at end of program name%@AE@%%@NL@%
  6367.         repne   scasb%@NL@%
  6368.         cmp     BYTE PTR es:[di], 0     %@AB@%; If double zero, there's no name%@AE@%%@NL@%
  6369.         je      Prompter                %@AB@%;   so get from prompt%@AE@%%@NL@%
  6370. %@NL@%
  6371.         .IF     BYTE PTR es:[di] == ' '%@NL@%
  6372.         inc     di                      %@AB@%; Skip leading space%@AE@%%@NL@%
  6373.         .ENDIF%@NL@%
  6374. %@NL@%
  6375. %@AB@%; Copy command line to file name buffer%@AE@%%@NL@%
  6376. %@NL@%
  6377.         mov     si, di                  %@AB@%; Filename source%@AE@%%@NL@%
  6378.         mov     di, OFFSET stFiles      %@AB@%; Name buffer destination%@AE@%%@NL@%
  6379.         mov     bx, ds                  %@AB@%; Save segment registers%@AE@%%@NL@%
  6380.         mov     dx, es%@NL@%
  6381.         mov     ds, dx                  %@AB@%; DS = ES%@AE@%%@NL@%
  6382.         mov     es, bx                  %@AB@%; ES = DS%@AE@%%@NL@%
  6383.         mov     cx, NAME_MAX            %@AB@%; Count = max file name allowed%@AE@%%@NL@%
  6384. %@NL@%
  6385.         .REPEAT%@NL@%
  6386.         lodsb                           %@AB@%; Copy characters%@AE@%%@NL@%
  6387.         .BREAK .IF (al == ' ') || (al == 0) %@AB@%; Stop at space or null%@AE@%%@NL@%
  6388.         stosb%@NL@%
  6389.         .UNTILCXZ                       %@AB@%; Until name exceeds max%@AE@%%@NL@%
  6390. %@NL@%
  6391.         mov     ds, bx                  %@AB@%; Restore DS%@AE@%%@NL@%
  6392.         mov     BYTE PTR [di], 0%@NL@%
  6393.         jmp     FindFile%@NL@%
  6394. %@NL@%
  6395. %@AB@%; Prompt for file%@AE@%%@NL@%
  6396. %@NL@%
  6397. NoFile:%@NL@%
  6398.         INVOKE  VioWrtTTy,              %@AB@%; Write message%@AE@%%@NL@%
  6399.                 ADDR stMsg2,%@NL@%
  6400.                 LENGTHOF stMsg2,%@NL@%
  6401.                 0%@NL@%
  6402. %@NL@%
  6403.         INVOKE  KbdCharIn,%@NL@%
  6404.                 ADDR kkiChar,%@NL@%
  6405.                 IO_WAIT,%@NL@%
  6406.                 0%@NL@%
  6407. %@NL@%
  6408.         and     kkiChar.chChar_, 11011111y %@AB@%; Convert to uppercase%@AE@%%@NL@%
  6409.         cmp     kkiChar.chChar_, "Y"%@NL@%
  6410. %@NL@%
  6411.         mov     hFiles, -1%@NL@%
  6412.         mov     usCount, 1%@NL@%
  6413.         .IF     !zero?%@NL@%
  6414.         jmp     Quit                    %@AB@%; Quit if not yes%@AE@%%@NL@%
  6415.         .ENDIF%@NL@%
  6416. Prompter:%@NL@%
  6417.         INVOKE  VioWrtTTy,              %@AB@%; Else prompt for file name%@AE@%%@NL@%
  6418.                 ADDR stMsg1,%@NL@%
  6419.                 LENGTHOF stMsg1,%@NL@%
  6420.                 0%@NL@%
  6421. %@NL@%
  6422.         INVOKE  KbdStringIn,%@NL@%
  6423.                 ADDR stFiles,%@NL@%
  6424.                 ADDR sibStr,%@NL@%
  6425.                 IO_WAIT,%@NL@%
  6426.                 0%@NL@%
  6427. %@NL@%
  6428.         mov     di, sibStr.cchIn_       %@AB@%; Null terminate%@AE@%%@NL@%
  6429.         mov     stFiles[di], 0%@NL@%
  6430. %@NL@%
  6431. %@AB@%; Find first (or only) file in filespec%@AE@%%@NL@%
  6432. %@NL@%
  6433. FindFile:%@NL@%
  6434.         INVOKE  DosFindFirst,%@NL@%
  6435.                 ADDR stFiles,%@NL@%
  6436.                 ADDR hFiles,%@NL@%
  6437.                 0,%@NL@%
  6438.                 ADDR fiFiles,%@NL@%
  6439.                 SIZE fiFiles,%@NL@%
  6440.                 ADDR usCount,%@NL@%
  6441.                 0%@NL@%
  6442. %@NL@%
  6443.         or      ax, ax%@NL@%
  6444.         jnz     NoFile%@NL@%
  6445. %@NL@%
  6446.         INVOKE  GetVid                  %@AB@%; Adjust for current mode and%@AE@%%@NL@%
  6447.                                         %@AB@%;  video adapter and hide cursor%@AE@%%@NL@%
  6448. %@NL@%
  6449. %@AB@%; Main program loop to process files%@AE@%%@NL@%
  6450. %@NL@%
  6451.         .REPEAT%@NL@%
  6452. %@NL@%
  6453. %@AB@%; Copy file name to file spec%@AE@%%@NL@%
  6454. %@NL@%
  6455.         mov     bCsrSta, 2              %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
  6456.         INVOKE  GetNamePos,             %@AB@%; Get file name position in file spec%@AE@%%@NL@%
  6457.                 ADDR stFiles%@NL@%
  6458. %@NL@%
  6459.         mov     si, OFFSET fiFiles.achName_%@AB@%; Load source name%@AE@%%@NL@%
  6460.         mov     di, ax                  %@AB@%; Load adjusted destination address%@AE@%%@NL@%
  6461.                                         %@AB@%;   from return value%@AE@%%@NL@%
  6462.         sub     cx, cx                  %@AB@%; Load file name length%@AE@%%@NL@%
  6463.         mov     cl, fiFiles.cchName_%@NL@%
  6464.         rep     movsb                   %@AB@%; Copy to spec%@AE@%%@NL@%
  6465.         mov     BYTE PTR es:[di], 0     %@AB@%; Null terminate%@AE@%%@NL@%
  6466. %@NL@%
  6467. %@AB@%; Copy file name to status line%@AE@%%@NL@%
  6468. %@NL@%
  6469.         sub     cx, cx                  %@AB@%; Load file length%@AE@%%@NL@%
  6470.         mov     cl, fiFiles.cchName_%@NL@%
  6471.         mov     bx, 12                  %@AB@%; Calculate blank spaces to fill%@AE@%%@NL@%
  6472.         sub     bx, cx%@NL@%
  6473.         push    ds                      %@AB@%; ES=DS%@AE@%%@NL@%
  6474.         pop     es%@NL@%
  6475.         mov     si, OFFSET fiFiles.achName_%@AB@%; File name as source%@AE@%%@NL@%
  6476.         mov     di, OFFSET stFile[FILE_POS]%@AB@%; Status line as destination%@AE@%%@NL@%
  6477.         rep     movsb%@NL@%
  6478.         mov     al, " "                 %@AB@%; Fill rest of name space with blanks%@AE@%%@NL@%
  6479.         mov     cx, bx%@NL@%
  6480.         rep     stosb%@NL@%
  6481. %@NL@%
  6482. %@AB@%; Skip any file that is larger than 64K%@AE@%%@NL@%
  6483. %@NL@%
  6484.         .IF     WORD PTR fiFiles.cbFile_[2] != 0%@NL@%
  6485. %@NL@%
  6486.         INVOKE  VioWrtTTy,%@NL@%
  6487.                 ADDR stMsg3,%@NL@%
  6488.                 LENGTHOF stMsg3,%@NL@%
  6489.                 0%@NL@%
  6490. %@NL@%
  6491.         INVOKE  VioWrtTTy,%@NL@%
  6492.                 ADDR fiFiles.achName_,%@NL@%
  6493.                 fiFiles.cchName_,%@NL@%
  6494.                 0%@NL@%
  6495. %@NL@%
  6496.         .IF     usCount <= 0            %@AB@%; Get key if there's another file%@AE@%%@NL@%
  6497.         INVOKE  KbdCharIn,%@NL@%
  6498.                 ADDR kkiChar,%@NL@%
  6499.                 IO_WAIT,%@NL@%
  6500.                 0%@NL@%
  6501.         .ENDIF%@NL@%
  6502.         .ENDIF%@NL@%
  6503. %@NL@%
  6504. %@AB@%; Allocate file Buffer%@AE@%%@NL@%
  6505. %@NL@%
  6506.         mov     ax, WORD PTR fiFiles.cbFile_[0] %@AB@%; Save size%@AE@%%@NL@%
  6507.         mov     cbBuf, ax%@NL@%
  6508.         mov     offBuf, 0%@NL@%
  6509.         INVOKE  DosAllocSeg,%@NL@%
  6510.                 ax,%@NL@%
  6511.                 ADDR segBuf,%@NL@%
  6512.                 0%@NL@%
  6513. %@NL@%
  6514.         .IF     ax != 0%@NL@%
  6515.         mov     bCsrSta, 1              %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
  6516.         INVOKE  VioWrtTTy,%@NL@%
  6517.                 ADDR stMsg4,%@NL@%
  6518.                 LENGTHOF stMsg4,%@NL@%
  6519.                 0%@NL@%
  6520. %@NL@%
  6521.         jmp     Quit%@NL@%
  6522.         .ENDIF%@NL@%
  6523. %@NL@%
  6524. %@AB@%; Open file and read contents into buffer%@AE@%%@NL@%
  6525. %@NL@%
  6526.         INVOKE  DosOpen,%@NL@%
  6527.                 ADDR stFiles,%@NL@%
  6528.                 ADDR hFileIn,%@NL@%
  6529.                 ADDR usAct,%@NL@%
  6530.                 0,%@NL@%
  6531.                 FILE_NORMAL,%@NL@%
  6532.                 FILE_OPEN,%@NL@%
  6533.                 usMode,%@NL@%
  6534.                 0%@NL@%
  6535. %@NL@%
  6536.         .IF     ax != 0%@NL@%
  6537.         jmp     NoFile%@NL@%
  6538.         .ENDIF%@NL@%
  6539. %@NL@%
  6540.         INVOKE  DosRead,%@NL@%
  6541.                 hFileIn,%@NL@%
  6542.                 fpBuf,%@NL@%
  6543.                 cbBuf,%@NL@%
  6544.                 ADDR cbRead%@NL@%
  6545. %@NL@%
  6546.         .IF     ax != 0%@NL@%
  6547.         jmp     NoFile%@NL@%
  6548.         .ENDIF%@NL@%
  6549. %@NL@%
  6550. %@AB@%; Search back for EOF marker and adjust if necessary%@AE@%%@NL@%
  6551. %@NL@%
  6552.         mov     di, cbRead              %@AB@%; Load file length%@AE@%%@NL@%
  6553.         dec     di                      %@AB@%;   and adjust%@AE@%%@NL@%
  6554.         mov     es, segBuf              %@AB@%; Save ES and load buffer segment%@AE@%%@NL@%
  6555.         std                             %@AB@%; Look backward for 255 characters%@AE@%%@NL@%
  6556.         mov     cx, 0FFh%@NL@%
  6557.         .IF     cx >= di%@NL@%
  6558.         mov     cx, di%@NL@%
  6559.         .ENDIF%@NL@%
  6560. %@NL@%
  6561.         mov     al, 1Ah                 %@AB@%; Search for EOF marker%@AE@%%@NL@%
  6562.         repne   scasb%@NL@%
  6563.         cld%@NL@%
  6564.         .IF     cx != 0                 %@AB@%; If found:%@AE@%%@NL@%
  6565.         inc     di                      %@AB@%; Adjust and save file size%@AE@%%@NL@%
  6566.         mov     cbBuf, di%@NL@%
  6567.         .ENDIF%@NL@%
  6568. %@NL@%
  6569. %@AB@%; Show a screen of text and allow commands%@AE@%%@NL@%
  6570. %@NL@%
  6571.         INVOKE  Show%@NL@%
  6572. %@NL@%
  6573.         INVOKE  DosClose,               %@AB@%; Close file%@AE@%%@NL@%
  6574.                 hFileIn%@NL@%
  6575. %@NL@%
  6576.         INVOKE  DosFreeSeg,             %@AB@%; Free memofy%@AE@%%@NL@%
  6577.                 segBuf%@NL@%
  6578. %@NL@%
  6579.         INVOKE  DosFindNext,            %@AB@%; Get next file%@AE@%%@NL@%
  6580.                 hFiles,%@NL@%
  6581.                 ADDR fiFiles,%@NL@%
  6582.                 SIZE fiFiles,%@NL@%
  6583.                 ADDR usCount%@NL@%
  6584. %@NL@%
  6585.         .UNTIL  ax != 0                 %@AB@%; Fall through to Quit if%@AE@%%@NL@%
  6586.                                         %@AB@%;  this is the last file%@AE@%%@NL@%
  6587. Quit    PROC%@NL@%
  6588. %@NL@%
  6589.         cmp     bCsrSta, 1              %@AB@%; Check cursor status%@AE@%%@NL@%
  6590.         jg      csrvislast              %@AB@%; 2 - Make cursor visible on last line%@AE@%%@NL@%
  6591.         je      csrvis                  %@AB@%; 1 - Make cursor visible%@AE@%%@NL@%
  6592.         jmp     csrasis                 %@AB@%; 0 - Leave cursor as is%@AE@%%@NL@%
  6593. %@NL@%
  6594. csrvislast:%@NL@%
  6595.         INVOKE  VioSetCurPos,           %@AB@%; Restore cursor on last line%@AE@%%@NL@%
  6596.                 yMax,%@NL@%
  6597.                 0,%@NL@%
  6598.                 0%@NL@%
  6599.         INVOKE  VioScrollDn,%@NL@%
  6600.                 yMax,%@NL@%
  6601.                 0,%@NL@%
  6602.                 yMax,%@NL@%
  6603.                 79,%@NL@%
  6604.                 1,%@NL@%
  6605.                 ADDR chInit,%@NL@%
  6606.                 0%@NL@%
  6607. csrvis:                                 %@AB@%; Fall through%@AE@%%@NL@%
  6608.         mov     ax, atCsr               %@AB@%; Restore cursor attribute%@AE@%%@NL@%
  6609.         mov     vciCsr.attr_, ax%@NL@%
  6610.         INVOKE  VioSetCurType,%@NL@%
  6611.                 ADDR vciCsr,%@NL@%
  6612.                 0%@NL@%
  6613. csrasis:                                %@AB@%; Fall through%@AE@%%@NL@%
  6614.         .EXIT   0%@NL@%
  6615. %@NL@%
  6616. Quit    ENDP%@NL@%
  6617. %@NL@%
  6618. %@NL@%
  6619. Show    PROC%@NL@%
  6620. %@NL@%
  6621. %@AB@%; Display first page%@AE@%%@NL@%
  6622. %@NL@%
  6623.         mov     yCur, 1%@NL@%
  6624.         INVOKE  Pager,                  %@AB@%; Start at 0%@AE@%%@NL@%
  6625.                 0%@NL@%
  6626. %@NL@%
  6627. %@AB@%; Handle keys%@AE@%%@NL@%
  6628. %@NL@%
  6629.         .REPEAT%@NL@%
  6630.         INVOKE  KbdCharIn,              %@AB@%; Get a key and load to register%@AE@%%@NL@%
  6631.                 ADDR kkiChar,%@NL@%
  6632.                 IO_WAIT,%@NL@%
  6633.                 0%@NL@%
  6634. %@NL@%
  6635.         mov     al, kkiChar.chChar_%@NL@%
  6636. %@NL@%
  6637.         .BREAK .IF al == 27             %@AB@%; If ESCAPE get out for next file%@AE@%%@NL@%
  6638. %@NL@%
  6639.         %@AB@%; If null or E0 (for extended keyboard), it's an extended key%@AE@%%@NL@%
  6640.         .IF     (al == 0) || (al == 0E0h)%@NL@%
  6641.         mov     al, kkiChar.chScan_      %@AB@%; Load scan code%@AE@%%@NL@%
  6642.         .ENDIF%@NL@%
  6643. %@NL@%
  6644.         push    ds                      %@AB@%; ES = DS%@AE@%%@NL@%
  6645.         pop     es%@NL@%
  6646.         mov     di, OFFSET achKeys      %@AB@%; Load address and length of key list%@AE@%%@NL@%
  6647.         mov     cx, LENGTHOF achKeys + 1%@NL@%
  6648.         repne   scasb                   %@AB@%; Find position and point to key%@AE@%%@NL@%
  6649.         sub     di, OFFSET achKeys + 1%@NL@%
  6650.         shl     di, 1                   %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
  6651.         call    afnKeys[di]             %@AB@%; Call procedure%@AE@%%@NL@%
  6652.         .UNTIL  0%@NL@%
  6653. %@NL@%
  6654.         ret%@NL@%
  6655. Show    ENDP%@NL@%
  6656. %@NL@%
  6657. HomeKey:%@NL@%
  6658.         mov     offBuf, 0               %@AB@%; HOME - set position to 0%@AE@%%@NL@%
  6659.         mov     yCur, 1%@NL@%
  6660.         INVOKE  Pager, offBuf%@NL@%
  6661.         retn%@NL@%
  6662. %@NL@%
  6663. UpKey:%@NL@%
  6664.         INVOKE  Pager, -1               %@AB@%; UP - scroll back 1 line%@AE@%%@NL@%
  6665.         retn%@NL@%
  6666. %@NL@%
  6667. PgUpKey:%@NL@%
  6668.         mov     ax, yMax                %@AB@%; PGUP - Page back%@AE@%%@NL@%
  6669.         neg     ax%@NL@%
  6670.         INVOKE  Pager, ax%@NL@%
  6671.         retn%@NL@%
  6672. %@NL@%
  6673. EndKey:%@NL@%
  6674.         mov     ax, cbBuf               %@AB@%; END - Get last byte of file%@AE@%%@NL@%
  6675.         dec     ax                      %@AB@%; Zero adjust%@AE@%%@NL@%
  6676.         mov     offBuf, ax              %@AB@%; Make it the file position%@AE@%%@NL@%
  6677.         mov     yCur, -1                %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
  6678.         mov     ax, yMax                %@AB@%; Page back%@AE@%%@NL@%
  6679.         neg     ax%@NL@%
  6680.         INVOKE  Pager, ax%@NL@%
  6681.         retn%@NL@%
  6682. %@NL@%
  6683. DownKey:%@NL@%
  6684.         INVOKE  Pager, 1                %@AB@%; DOWN - scroll forward 1 line%@AE@%%@NL@%
  6685.         retn%@NL@%
  6686. %@NL@%
  6687. PgDnKey:%@NL@%
  6688.         INVOKE  Pager, yMax             %@AB@%; PGDN - page forward%@AE@%%@NL@%
  6689.         retn%@NL@%
  6690. %@NL@%
  6691. UnknownKey:%@NL@%
  6692.         retn                            %@AB@%; Ignore unknown key%@AE@%%@NL@%
  6693. %@NL@%
  6694. %@NL@%
  6695. %@AB@%;* GetVid - Gets the video mode and sets related global variables.%@AE@%%@NL@%
  6696. %@AB@%;*%@AE@%%@NL@%
  6697. %@AB@%;* Params: None%@AE@%%@NL@%
  6698. %@AB@%;*%@AE@%%@NL@%
  6699. %@AB@%;* Return: Number of lines in current mode (25, 43, or 50)%@AE@%%@NL@%
  6700. %@NL@%
  6701. GetVid  PROC%@NL@%
  6702. %@NL@%
  6703.         LOCAL   x:USHORT, y:USHORT, cb:USHORT%@NL@%
  6704. %@NL@%
  6705. %@NL@%
  6706.         INVOKE  VioGetMode,             %@AB@%; Get video mode%@AE@%%@NL@%
  6707.                 ADDR vmiMode,%@NL@%
  6708.                 0%@NL@%
  6709. %@NL@%
  6710.         sub     ax, ax                  %@AB@%; Clear AH%@AE@%%@NL@%
  6711.         mov     al, vmiMode.fbType_     %@AB@%; Put type in register%@AE@%%@NL@%
  6712. %@NL@%
  6713.         %@AB@%; If monochrome or color burst off:%@AE@%%@NL@%
  6714.         .IF     (al & VGMT_GRAPHICS) || (al & VGMT_DISABLEBURST)%@NL@%
  6715.         mov     atSta, STAT_BW          %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
  6716.         mov     atScr, SCRN_BW          %@AB@%;   and screen background%@AE@%%@NL@%
  6717.         .ENDIF%@NL@%
  6718. %@NL@%
  6719.         INVOKE  VioGetCurPos,           %@AB@%; Get cursor position (for cell read)%@AE@%%@NL@%
  6720.                 ADDR y,                 %@AB@%; Row%@AE@%%@NL@%
  6721.                 ADDR x,                 %@AB@%; Column%@AE@%%@NL@%
  6722.                 0                       %@AB@%; Console handle%@AE@%%@NL@%
  6723. %@NL@%
  6724.         mov     cb, 1                   %@AB@%; One cell%@AE@%%@NL@%
  6725.         INVOKE  VioReadCellStr,         %@AB@%; Read cell to get current attribute%@AE@%%@NL@%
  6726.                 ADDR chInit,            %@AB@%; Address to receive cell%@AE@%%@NL@%
  6727.                 ADDR cb,                %@AB@%; Address of length%@AE@%%@NL@%
  6728.                 y,                      %@AB@%; Row%@AE@%%@NL@%
  6729.                 x,                      %@AB@%; Column%@AE@%%@NL@%
  6730.                 0                       %@AB@%; Console handle%@AE@%%@NL@%
  6731.         mov     chInit, ' '             %@AB@%; Make sure character is space%@AE@%%@NL@%
  6732. %@NL@%
  6733.         INVOKE  VioGetCurType,          %@AB@%; Get cursor mode%@AE@%%@NL@%
  6734.                 ADDR vciCsr,%@NL@%
  6735.                 0%@NL@%
  6736.         mov     ax, vciCsr.attr_        %@AB@%; Save cursor attribute%@AE@%%@NL@%
  6737.         xchg    atCsr, ax%@NL@%
  6738.         mov     vciCsr.attr_, ax        %@AB@%; Set hidden cursor attribute%@AE@%%@NL@%
  6739.         mov     ax, vmiMode.row_        %@AB@%; Get number of rows and adjust%@AE@%%@NL@%
  6740.         dec     ax%@NL@%
  6741.         mov     yMax, ax%@NL@%
  6742. %@NL@%
  6743.         INVOKE  VioSetCurType,          %@AB@%; Hide cursor%@AE@%%@NL@%
  6744.                 ADDR vciCsr,%@NL@%
  6745.                 0%@NL@%
  6746. %@NL@%
  6747.         ret%@NL@%
  6748. %@NL@%
  6749. GetVid  ENDP%@NL@%
  6750. %@NL@%
  6751. %@NL@%
  6752.         END%@NL@%
  6753. %@NL@%
  6754. %@NL@%
  6755. %@2@%%@AH@%SHOWR.ASM%@AE@%%@EH@%%@NL@%
  6756. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\SHOW\SHOWR.ASM%@AE@%%@NL@%
  6757. %@NL@%
  6758. %@AB@%;* SHOWR.ASM - Text file displayer for DOS (real mode).%@AE@%%@NL@%
  6759. %@NL@%
  6760.         TITLE   Show%@NL@%
  6761.         .MODEL  small, pascal, os_dos   %@AB@%; This code also works in tiny model%@AE@%%@NL@%
  6762.         .DOSSEG%@NL@%
  6763. %@NL@%
  6764.         INCLUDE show.inc%@NL@%
  6765.         INCLUDE dos.inc%@NL@%
  6766.         INCLUDE bios.inc%@NL@%
  6767. %@NL@%
  6768.         .STACK%@NL@%
  6769. %@NL@%
  6770.         .DATA%@NL@%
  6771. %@NL@%
  6772. %@AB@%; Status line%@AE@%%@NL@%
  6773. %@NL@%
  6774. stLine  BYTE    "Line: 12345 "%@NL@%
  6775. stFile  BYTE    "File: 12345678.123  "%@NL@%
  6776.         BYTE    "Quit: Q  Next: ESC  Move:   PGUP PGDN HOME END"%@NL@%
  6777. %@NL@%
  6778. %@AB@%; Variables for        screen handling%@AE@%%@NL@%
  6779. %@NL@%
  6780. yCur    WORD    1%@NL@%
  6781. yMax    WORD    24              %@AB@%; Number of rows - status line takes one more%@AE@%%@NL@%
  6782. iMode   BYTE    0               %@AB@%; Initial mode%@AE@%%@NL@%
  6783. iPage   BYTE    0               %@AB@%; Initial display page%@AE@%%@NL@%
  6784. atInit  BYTE    0               %@AB@%; Initial attribute%@AE@%%@NL@%
  6785. shCsr   WORD    0               %@AB@%; Initial cursor shape%@AE@%%@NL@%
  6786. bCsrSta BYTE    0               %@AB@%; 0 = cursor visible, position unchanged%@AE@%%@NL@%
  6787.                                 %@AB@%; 1 = cursor invisible, position unchanged%@AE@%%@NL@%
  6788.                                 %@AB@%; 2 = cursor invisible, position changed%@AE@%%@NL@%
  6789. %@NL@%
  6790. fNewVid BYTE    0               %@AB@%; Video change flag%@AE@%%@NL@%
  6791. fCGA    BYTE    1               %@AB@%; CGA flag - default yes%@AE@%%@NL@%
  6792. %@NL@%
  6793. segVid  WORD    SEG_CLR         %@AB@%; Video buffer address - default color%@AE@%%@NL@%
  6794. %@NL@%
  6795. atSta   BYTE    STAT_CLR        %@AB@%; Status line color%@AE@%%@NL@%
  6796. celScr  LABEL   WORD            %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
  6797. chScr   BYTE    ' '             %@AB@%; Initialize to space%@AE@%%@NL@%
  6798. atScr   BYTE    SCRN_CLR        %@AB@%; Screen color%@AE@%%@NL@%
  6799. %@NL@%
  6800. %@AB@%; Buffer variables%@AE@%%@NL@%
  6801. %@NL@%
  6802. fpBuf   LABEL   FAR PTR%@NL@%
  6803. offBuf  WORD    0               %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
  6804. segBuf  WORD    0               %@AB@%; Base of buffer (segment)%@AE@%%@NL@%
  6805. cbBuf   WORD    0               %@AB@%; Length of buffer%@AE@%%@NL@%
  6806. %@NL@%
  6807. %@AB@%; File information%@AE@%%@NL@%
  6808. %@NL@%
  6809. hFileIn WORD    0               %@AB@%; Holds file handle on open%@AE@%%@NL@%
  6810. %@NL@%
  6811. %@AB@%; Buffer for file spec and structure for file info%@AE@%%@NL@%
  6812. %@NL@%
  6813. achBuf  BYTE    NAME_MAX, ?     %@AB@%; Buffer format for string input%@AE@%%@NL@%
  6814. stFiles BYTE    NAME_MAX DUP (0)%@AB@%; File spec string%@AE@%%@NL@%
  6815. fiFiles FILE_INFO <>            %@AB@%; Wild card entry structure%@AE@%%@NL@%
  6816. cFiles  WORD    0               %@AB@%; Count of 1 or 0 files remaining%@AE@%%@NL@%
  6817. %@NL@%
  6818. %@AB@%; Messages%@AE@%%@NL@%
  6819. %@NL@%
  6820. stMsg1  BYTE    13, 10, 13, 10, "Enter filename: $"%@NL@%
  6821. stMsg2  BYTE    13, 10, "File problem. Try again? $"%@NL@%
  6822. stMsg3  BYTE    13, 10, "File too large: $"%@NL@%
  6823. stMsg4  BYTE    13, 10, "Memory problem.", 13, 10, "$"%@NL@%
  6824. stMsg5  BYTE    13, 10, "Must have DOS 2.0 or higher", 13, 10, "$"%@NL@%
  6825. %@NL@%
  6826. %@AB@%; Call table%@AE@%%@NL@%
  6827. %@NL@%
  6828. achKeys BYTE    71, 72, 73, 79, 80, 81, 'q', 'Q'%@AB@%; Key table%@AE@%%@NL@%
  6829. afnKeys WORD    HomeKey                         %@AB@%; Corresponding procedures%@AE@%%@NL@%
  6830.         WORD    UpKey%@NL@%
  6831.         WORD    PgUpKey%@NL@%
  6832.         WORD    EndKey%@NL@%
  6833.         WORD    DownKey%@NL@%
  6834.         WORD    PgDnKey%@NL@%
  6835.         WORD    Quit%@NL@%
  6836.         WORD    Quit%@NL@%
  6837.         WORD    UnknownKey%@NL@%
  6838. %@NL@%
  6839.         .CODE%@NL@%
  6840.         .STARTUP%@NL@%
  6841. %@NL@%
  6842. %@AB@%; Adjust memory allocation (works for tiny or small model)%@AE@%%@NL@%
  6843. %@NL@%
  6844.         mov     bx, sp                  %@AB@%; Convert stack pointer to paragraphs%@AE@%%@NL@%
  6845.         mov     cl, 4                   %@AB@%;   to get stack size%@AE@%%@NL@%
  6846.         shr     bx, cl%@NL@%
  6847.         mov     ax, ss                  %@AB@%; Add SS to get end of program%@AE@%%@NL@%
  6848.         add     ax, bx%@NL@%
  6849.         mov     bx, es                  %@AB@%; Get start of program%@AE@%%@NL@%
  6850.         sub     ax, bx                  %@AB@%; Subtract start from end%@AE@%%@NL@%
  6851.         inc     ax%@NL@%
  6852.         @ModBlock ax                    %@AB@%; Release memory after program%@AE@%%@NL@%
  6853. %@NL@%
  6854. %@AB@%; Check DOS%@AE@%%@NL@%
  6855. %@NL@%
  6856.         @GetVer                         %@AB@%; Get DOS version%@AE@%%@NL@%
  6857.         .IF     al < 2                  %@AB@%; Requires DOS 2.0%@AE@%%@NL@%
  6858.         @ShowStr stMsg5                 %@AB@%;   else error and quit%@AE@%%@NL@%
  6859.         int     20h%@NL@%
  6860.         .ENDIF%@NL@%
  6861. %@NL@%
  6862. %@AB@%; Get command line and copy to file name buffer%@AE@%%@NL@%
  6863. %@NL@%
  6864.         mov     di, 80h                 %@AB@%; PSP offset of command line%@AE@%%@NL@%
  6865.         mov     bl, es:[di]             %@AB@%; Get length from first byte%@AE@%%@NL@%
  6866.         sub     bh, bh%@NL@%
  6867.         or      bx, bx%@NL@%
  6868.         je      Prompter%@NL@%
  6869. %@NL@%
  6870.         mov     WORD PTR es:[bx+81h], 0 %@AB@%; Convert to ASCIIZ%@AE@%%@NL@%
  6871.         mov     al, ' '                 %@AB@%; Character to check for%@AE@%%@NL@%
  6872.         inc     di                      %@AB@%; Advance beyond count%@AE@%%@NL@%
  6873.         mov     cx, 0FFFFh              %@AB@%; Don't let count interfere%@AE@%%@NL@%
  6874.         repe    scasb                   %@AB@%; Find first non-space%@AE@%%@NL@%
  6875.         dec     di                      %@AB@%; Adjust%@AE@%%@NL@%
  6876. %@NL@%
  6877.         mov     si, di                  %@AB@%; Filename source%@AE@%%@NL@%
  6878.         mov     di, OFFSET stFiles      %@AB@%; Name buffer destination%@AE@%%@NL@%
  6879.         mov     bx, ds                  %@AB@%; Save segment registers%@AE@%%@NL@%
  6880.         mov     dx, es%@NL@%
  6881.         mov     ds, dx                  %@AB@%; DS = ES%@AE@%%@NL@%
  6882.         mov     es, bx                  %@AB@%; ES = DS%@AE@%%@NL@%
  6883.         mov     cx, NAME_MAX            %@AB@%; Count = max file name allowed%@AE@%%@NL@%
  6884. %@NL@%
  6885.         .REPEAT%@NL@%
  6886.         lodsb                           %@AB@%; Copy characters%@AE@%%@NL@%
  6887.         .BREAK .IF (al == ' ') || (al == 0) %@AB@%; Stop at space or null%@AE@%%@NL@%
  6888.         stosb%@NL@%
  6889.         .UNTILCXZ                       %@AB@%; Until name exceeds max%@AE@%%@NL@%
  6890. %@NL@%
  6891.         mov     ds, bx                  %@AB@%; Restore segments%@AE@%%@NL@%
  6892.         mov     es, dx%@NL@%
  6893.         mov     BYTE PTR [di], 0%@NL@%
  6894.         jmp     FindFile%@NL@%
  6895. NoFile:%@NL@%
  6896. %@NL@%
  6897.         @ShowStr stMsg2                 %@AB@%; Prompt to try again%@AE@%%@NL@%
  6898.         @GetChar 0, 1, 0%@NL@%
  6899.         and     al, 11011111y           %@AB@%; Convert key to uppercase%@AE@%%@NL@%
  6900.         .IF     al != 'Y'               %@AB@%; If not yes,%@AE@%%@NL@%
  6901.         jmp     quit                    %@AB@%;   quit%@AE@%%@NL@%
  6902.         .ENDIF%@NL@%
  6903. %@NL@%
  6904. %@AB@%; Prompt for file%@AE@%%@NL@%
  6905. %@NL@%
  6906. Prompter:%@NL@%
  6907.         @ShowStr stMsg1                 %@AB@%; Prompt for file%@AE@%%@NL@%
  6908.         @GetStr achBuf, 0               %@AB@%; Get response as ASCIIZ%@AE@%%@NL@%
  6909. %@NL@%
  6910. %@AB@%; Find first (or only) file in filespec%@AE@%%@NL@%
  6911. %@NL@%
  6912. FindFile:%@NL@%
  6913. %@NL@%
  6914.         @SetDTA <OFFSET fiFiles>        %@AB@%; Set DTA to file info structure%@AE@%%@NL@%
  6915.                                         %@AB@%; Don't need DTA for anything else,%@AE@%%@NL@%
  6916.                                         %@AB@%;   so no need to restore it%@AE@%%@NL@%
  6917.         @GetFirst stFiles,0             %@AB@%; Find a matching file%@AE@%%@NL@%
  6918. %@NL@%
  6919.         jc      NoFile                  %@AB@%; If not found, prompt for new%@AE@%%@NL@%
  6920.         inc     cFiles                  %@AB@%; Some files remaining%@AE@%%@NL@%
  6921. %@NL@%
  6922.         INVOKE  GetVid%@NL@%
  6923. %@NL@%
  6924. %@AB@%; Main program loop to process files%@AE@%%@NL@%
  6925. %@NL@%
  6926.         .REPEAT%@NL@%
  6927. %@NL@%
  6928. %@AB@%; Copy file name to file spec%@AE@%%@NL@%
  6929. %@NL@%
  6930.         mov     bCsrSta, 2              %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
  6931.         INVOKE  GetNamePos,             %@AB@%; Get file name position in file spec%@AE@%%@NL@%
  6932.                 ADDR stFiles%@NL@%
  6933. %@NL@%
  6934.         mov     si, OFFSET fiFiles.FName%@AB@%; Point to source name%@AE@%%@NL@%
  6935.         push    ds                      %@AB@%; ES = DS%@AE@%%@NL@%
  6936.         pop     es%@NL@%
  6937.         mov     di, ax                  %@AB@%; Load address from return value%@AE@%%@NL@%
  6938. %@NL@%
  6939.         .REPEAT                         %@AB@%; Copy to (and including) null%@AE@%%@NL@%
  6940.         movsb%@NL@%
  6941.         .UNTIL BYTE PTR [si-1] == 0%@NL@%
  6942. %@NL@%
  6943. %@AB@%; Copy file name to status line%@AE@%%@NL@%
  6944. %@NL@%
  6945.         mov     si, OFFSET fiFiles.FName    %@AB@%; Point to source name%@AE@%%@NL@%
  6946.         mov     di, OFFSET stFile[FILE_POS] %@AB@%; Point to status line%@AE@%%@NL@%
  6947. %@NL@%
  6948.         sub     cx, cx                  %@AB@%; Count characters%@AE@%%@NL@%
  6949.         .REPEAT%@NL@%
  6950.         lodsb                           %@AB@%; Copy to (but excluding) null%@AE@%%@NL@%
  6951.         .BREAK .IF al == 0%@NL@%
  6952.         stosb%@NL@%
  6953.         inc     cx%@NL@%
  6954.         .UNTIL  0%@NL@%
  6955. %@NL@%
  6956.         mov     bx, 12                  %@AB@%; Calculate blank spaces to fill%@AE@%%@NL@%
  6957.         sub     bx, cx%@NL@%
  6958.         mov     al, ' '                 %@AB@%; Fill rest of name space with blanks%@AE@%%@NL@%
  6959.         mov     cx, bx%@NL@%
  6960.         rep     stosb%@NL@%
  6961. %@NL@%
  6962. %@AB@%; Skip any file that is larger than 64K%@AE@%%@NL@%
  6963. %@NL@%
  6964.         .IF     WORD PTR fiFiles.len[2] != 0 %@AB@%; Error if high word isn't zero%@AE@%%@NL@%
  6965.         mov     bCsrSta, 1              %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
  6966. %@NL@%
  6967.         @ShowStr stMsg3                 %@AB@%; Display error string and file name%@AE@%%@NL@%
  6968.         @Write   fiFiles.FName, cx, 1%@NL@%
  6969. %@NL@%
  6970.         .IF     cFiles                  %@AB@%; If files remaining,%@AE@%%@NL@%
  6971.         @GetChar 0                      %@AB@%;  get a key%@AE@%%@NL@%
  6972.         .ENDIF%@NL@%
  6973.         .ENDIF%@NL@%
  6974. %@NL@%
  6975. %@AB@%; Allocate dynamic memory for file buffer%@AE@%%@NL@%
  6976. %@NL@%
  6977.         mov     ax, WORD PTR fiFiles.Len[0] %@AB@%; Get length%@AE@%%@NL@%
  6978.         mov     cbBuf, ax               %@AB@%; Save%@AE@%%@NL@%
  6979.         mov     offBuf, 0%@NL@%
  6980.         mov     cl, 4                   %@AB@%; Convert to paragraphs%@AE@%%@NL@%
  6981.         shr     ax, cl%@NL@%
  6982.         inc     ax                      %@AB@%; Zero adjust%@AE@%%@NL@%
  6983. %@NL@%
  6984.         @GetBlock ax                    %@AB@%; Try to allocate 64K%@AE@%%@NL@%
  6985.         .IF     carry?                  %@AB@%; Display error and quit if%@AE@%%@NL@%
  6986.         @ShowStr stMsg4                 %@AB@%;  request failed%@AE@%%@NL@%
  6987.         jmp     Quit%@NL@%
  6988.         .ENDIF%@NL@%
  6989.         mov     segBuf, ax              %@AB@%; Save buffer segment%@AE@%%@NL@%
  6990. %@NL@%
  6991. %@AB@%; Open file and read contents into buffer%@AE@%%@NL@%
  6992. %@NL@%
  6993.         @OpenFile stFiles, 0            %@AB@%; Try to open response%@AE@%%@NL@%
  6994.         jc      NoFile                  %@AB@%; If fail, get a new file%@AE@%%@NL@%
  6995.         mov     hFileIn, ax             %@AB@%; Save handle%@AE@%%@NL@%
  6996. %@NL@%
  6997.         push    ds%@NL@%
  6998.         @Read   fpBuf, cbBuf, hFileIn  %@AB@%; Read file%@AE@%%@NL@%
  6999.         pop     ds%@NL@%
  7000.         .IF     carry?%@NL@%
  7001.         jmp     NoFile                  %@AB@%; If read error try again%@AE@%%@NL@%
  7002.         .ENDIF%@NL@%
  7003. %@NL@%
  7004. %@AB@%; Search back for EOF marker and adjust        if necessary%@AE@%%@NL@%
  7005. %@NL@%
  7006.         mov     di, cbBuf               %@AB@%; Load file length%@AE@%%@NL@%
  7007.         dec     di                      %@AB@%;   and adjust%@AE@%%@NL@%
  7008.         mov     es, segBuf%@NL@%
  7009.         std                             %@AB@%; Look backward for 255 characters%@AE@%%@NL@%
  7010.         mov     cx, 0FFh%@NL@%
  7011.         .IF     cx >= di%@NL@%
  7012.         mov     cx, di%@NL@%
  7013.         .ENDIF%@NL@%
  7014. %@NL@%
  7015.         mov     al, 1Ah                 %@AB@%; Search for EOF marker%@AE@%%@NL@%
  7016.         repne   scasb%@NL@%
  7017.         cld%@NL@%
  7018.         .IF     cx != 0                 %@AB@%; If found:%@AE@%%@NL@%
  7019.         inc     di                      %@AB@%; Adjust and save file size%@AE@%%@NL@%
  7020.         mov     cbBuf, di%@NL@%
  7021.         .ENDIF%@NL@%
  7022. %@NL@%
  7023. %@AB@%; Show a screen of text and allow commands%@AE@%%@NL@%
  7024. %@NL@%
  7025.         INVOKE  Show%@NL@%
  7026. %@NL@%
  7027.         @CloseFile hFileIn              %@AB@%; Yes? Close file%@AE@%%@NL@%
  7028.         @FreeBlock segBuf               %@AB@%; Release buffer%@AE@%%@NL@%
  7029. %@NL@%
  7030.         @GetNext%@NL@%
  7031. %@NL@%
  7032.         .IF     carry?%@NL@%
  7033.         dec     cFiles%@NL@%
  7034.         .ENDIF%@NL@%
  7035.         .UNTIL  !cFiles%@NL@%
  7036. %@NL@%
  7037. %@AB@%; Fall through to Quit%@AE@%%@NL@%
  7038. %@NL@%
  7039. Quit    PROC%@NL@%
  7040. %@NL@%
  7041.         cmp     bCsrSta, 1              %@AB@%; Check cursor status%@AE@%%@NL@%
  7042.         jg      csrvislast              %@AB@%; 2 - Make cursor visible on last line%@AE@%%@NL@%
  7043.         je      csrvis                  %@AB@%; 1 - Make cursor visible%@AE@%%@NL@%
  7044.         jmp     csrasis                 %@AB@%; 0 - Leave cursor as is%@AE@%%@NL@%
  7045. %@NL@%
  7046. csrvislast:%@NL@%
  7047.         mov     dx, yMax                %@AB@%; Load last row and first column%@AE@%%@NL@%
  7048.         xchg    dl, dh%@NL@%
  7049.         mov     cx, dx                  %@AB@%; Make row the same%@AE@%%@NL@%
  7050.         mov     dl, 79%@NL@%
  7051.         @Scroll 0, atInit               %@AB@%; Clear last line to original color%@AE@%%@NL@%
  7052.         sub     dl, dl                  %@AB@%; Column 0%@AE@%%@NL@%
  7053.         @SetCsrPos                      %@AB@%; Set cursor%@AE@%%@NL@%
  7054. csrvis:                                 %@AB@%; Fall through%@AE@%%@NL@%
  7055.                                         %@AB@%; Restore cursor attribute%@AE@%%@NL@%
  7056.         @SetCsrSize <BYTE PTR shCsr[1]>, <BYTE PTR shCsr[0]>%@NL@%
  7057. %@NL@%
  7058. csrasis:%@NL@%
  7059.         .IF     fNewVid == 1%@NL@%
  7060.         @SetMode iMode                  %@AB@%; Restore video mode, page, and cursor%@AE@%%@NL@%
  7061.         @SetPage iPage%@NL@%
  7062.         .ENDIF%@NL@%
  7063. %@NL@%
  7064.         .EXIT   0                       %@AB@%; Quit%@AE@%%@NL@%
  7065. %@NL@%
  7066. Quit    ENDP%@NL@%
  7067. %@NL@%
  7068. %@NL@%
  7069. Show    PROC%@NL@%
  7070. %@NL@%
  7071. %@AB@%; Display first page%@AE@%%@NL@%
  7072. %@NL@%
  7073.         mov     yCur, 1                 %@AB@%; Reinitialize%@AE@%%@NL@%
  7074.         INVOKE  Pager,                  %@AB@%; Start at 0%@AE@%%@NL@%
  7075.                 0%@NL@%
  7076. %@NL@%
  7077. %@AB@%; Handle keys%@AE@%%@NL@%
  7078. %@NL@%
  7079.         .REPEAT%@NL@%
  7080. %@NL@%
  7081.         @GetChar 0, 0, 0                %@AB@%; Get a key%@AE@%%@NL@%
  7082. %@NL@%
  7083.         .BREAK .IF al == 27             %@AB@%; If ESCAPE get out for next file%@AE@%%@NL@%
  7084. %@NL@%
  7085.         %@AB@%; If null or E0 (for extended keyboard), it's an extended key%@AE@%%@NL@%
  7086.         .IF     (al == 0) || (al == 0E0h)%@NL@%
  7087.         @GetChar 0, 0, 0                %@AB@%; Get extended code%@AE@%%@NL@%
  7088.         .ENDIF%@NL@%
  7089. %@NL@%
  7090.         push    ds                      %@AB@%; ES = DS%@AE@%%@NL@%
  7091.         pop     es%@NL@%
  7092.         mov     di, OFFSET achKeys      %@AB@%; Load address and length of key list%@AE@%%@NL@%
  7093.         mov     cx, LENGTHOF achKeys + 1%@NL@%
  7094.         repne   scasb                   %@AB@%; Find position and point to key%@AE@%%@NL@%
  7095.         sub     di, OFFSET achKeys + 1%@NL@%
  7096.         shl     di, 1                   %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
  7097.         call    afnKeys[di]             %@AB@%; Call procedure%@AE@%%@NL@%
  7098.         .UNTIL  0%@NL@%
  7099. %@NL@%
  7100.         ret%@NL@%
  7101. Show    ENDP%@NL@%
  7102. %@NL@%
  7103. HomeKey:%@NL@%
  7104.         mov     offBuf, 0               %@AB@%; HOME - set position to 0%@AE@%%@NL@%
  7105.         mov     yCur, 1%@NL@%
  7106.         INVOKE  Pager, offBuf%@NL@%
  7107.         retn%@NL@%
  7108. %@NL@%
  7109. UpKey:%@NL@%
  7110.         INVOKE  Pager, -1               %@AB@%; UP - scroll backward 1 line%@AE@%%@NL@%
  7111.         retn%@NL@%
  7112. %@NL@%
  7113. PgUpKey:%@NL@%
  7114.         mov     ax, yMax                %@AB@%; PGUP - Page back%@AE@%%@NL@%
  7115.         neg     ax%@NL@%
  7116.         INVOKE  Pager, ax%@NL@%
  7117.         retn%@NL@%
  7118. %@NL@%
  7119. EndKey:%@NL@%
  7120.         mov     ax, cbBuf               %@AB@%; END - Get last byte of file%@AE@%%@NL@%
  7121.         dec     ax                      %@AB@%; Zero adjust%@AE@%%@NL@%
  7122.         mov     offBuf, ax              %@AB@%; Make it the file position%@AE@%%@NL@%
  7123.         mov     yCur, -1                %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
  7124.         mov     ax, yMax                %@AB@%; Page back%@AE@%%@NL@%
  7125.         neg     ax%@NL@%
  7126.         INVOKE  Pager, ax%@NL@%
  7127.         retn%@NL@%
  7128. %@NL@%
  7129. DownKey:%@NL@%
  7130.         INVOKE  Pager, 1                %@AB@%; DOWN - scroll forward 1 line%@AE@%%@NL@%
  7131.         retn%@NL@%
  7132. %@NL@%
  7133. PgDnKey:%@NL@%
  7134.         INVOKE  Pager, yMax             %@AB@%; PGDN - page forward%@AE@%%@NL@%
  7135.         retn%@NL@%
  7136. %@NL@%
  7137. UnknownKey:%@NL@%
  7138.         retn                            %@AB@%; Ignore unknown key%@AE@%%@NL@%
  7139. %@NL@%
  7140. %@NL@%
  7141. %@AB@%;* GetVid - Gets the video mode and sets related global variables.%@AE@%%@NL@%
  7142. %@AB@%;*%@AE@%%@NL@%
  7143. %@AB@%;* Params: None%@AE@%%@NL@%
  7144. %@AB@%;*%@AE@%%@NL@%
  7145. %@AB@%;* Return: Number of lines in current mode (25, 43, or 50)%@AE@%%@NL@%
  7146. %@NL@%
  7147. GetVid  PROC%@NL@%
  7148. %@NL@%
  7149. %@AB@%; Adjust for current mode and and video adapter%@AE@%%@NL@%
  7150. %@NL@%
  7151.         INVOKE  IsEGA                   %@AB@%; EGA (or VGA)?%@AE@%%@NL@%
  7152.         .IF     ax != 0                 %@AB@%; If 0 must be CGA or MA%@AE@%%@NL@%
  7153.         mov     yMax, ax                %@AB@%; Load rows%@AE@%%@NL@%
  7154.         dec     fCGA                    %@AB@%; Not CGA%@AE@%%@NL@%
  7155.         .ENDIF%@NL@%
  7156. %@NL@%
  7157.         @GetMode                        %@AB@%; Get video mode%@AE@%%@NL@%
  7158.         mov     iMode, al               %@AB@%; Save initial mode and page%@AE@%%@NL@%
  7159.         mov     iPage, bh%@NL@%
  7160.         mov     dl, al                  %@AB@%; Work on copy%@AE@%%@NL@%
  7161.         cmp     dl, 7                   %@AB@%; Is it mono 7?%@AE@%%@NL@%
  7162.         je      loadmono                %@AB@%; Yes? Set mono%@AE@%%@NL@%
  7163.         cmp     dl, 15                  %@AB@%; Is it mono 15?%@AE@%%@NL@%
  7164.         jne     graphchk                %@AB@%; No? Check graphics%@AE@%%@NL@%
  7165. loadmono:%@NL@%
  7166.         mov     segVid, SEG_MONO        %@AB@%; Load mono address%@AE@%%@NL@%
  7167.         mov     atSta, STAT_BW          %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
  7168.         mov     atScr, SCRN_BW          %@AB@%;   and screen background%@AE@%%@NL@%
  7169.         dec     fCGA                    %@AB@%; Not CGA%@AE@%%@NL@%
  7170.         cmp     al, 15                  %@AB@%; Is it mono 15?%@AE@%%@NL@%
  7171.         jne     exit                    %@AB@%; No? Done%@AE@%%@NL@%
  7172.         mov     dl, 7                   %@AB@%; Yes? Set standard mono%@AE@%%@NL@%
  7173.         jmp     chmode%@NL@%
  7174. graphchk:%@NL@%
  7175.         cmp     dl, 7                   %@AB@%; 7 or higher?%@AE@%%@NL@%
  7176.         jg      color                   %@AB@%; 8 to 14 are color (7 and 15 done)%@AE@%%@NL@%
  7177.         cmp     dl, 4                   %@AB@%; 4 or higher?%@AE@%%@NL@%
  7178.         jg      bnw                     %@AB@%; 5 and 6 are probably black and white%@AE@%%@NL@%
  7179.         je      color                   %@AB@%; 4 is color%@AE@%%@NL@%
  7180.         test    dl, 1                   %@AB@%; Even?%@AE@%%@NL@%
  7181.         jz      bnw                     %@AB@%; 0 and 2 are black and white%@AE@%%@NL@%
  7182. color:                                  %@AB@%; 1 and 3 are color%@AE@%%@NL@%
  7183.         cmp     dl, 3                   %@AB@%; 3?%@AE@%%@NL@%
  7184.         je      exit                    %@AB@%; Yes? Done%@AE@%%@NL@%
  7185.         mov     dl, 3                   %@AB@%; Change mode to 3%@AE@%%@NL@%
  7186.         jmp     chmode%@NL@%
  7187. bnw:%@NL@%
  7188.         mov     atSta, STAT_BW          %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
  7189.         mov     atScr, SCRN_BW          %@AB@%;   and screen background%@AE@%%@NL@%
  7190.         cmp     dl, 2                   %@AB@%; 2?%@AE@%%@NL@%
  7191.         je      exit                    %@AB@%; Yes? Done%@AE@%%@NL@%
  7192.         mov     dl, 2                   %@AB@%; Make it 2%@AE@%%@NL@%
  7193. chmode:%@NL@%
  7194.         @SetMode dl                     %@AB@%; Set video mode%@AE@%%@NL@%
  7195.         @SetPage 0                      %@AB@%; Set video page%@AE@%%@NL@%
  7196.         mov     fNewVid, 1              %@AB@%; Set flag%@AE@%%@NL@%
  7197. exit:%@NL@%
  7198.         @GetCsr                         %@AB@%; Get cursor shape (ignore position)%@AE@%%@NL@%
  7199.         mov     shCsr, cx               %@AB@%; Save shape%@AE@%%@NL@%
  7200.         @GetCharAtr                     %@AB@%; Read the cell at the cursor%@AE@%%@NL@%
  7201.         mov     atInit, ah              %@AB@%; Save attribute%@AE@%%@NL@%
  7202.         @SetCsrSize 20h, 20h            %@AB@%; Turn off cursor (invisible shape)%@AE@%%@NL@%
  7203. %@NL@%
  7204.         ret%@NL@%
  7205. %@NL@%
  7206. GetVid  ENDP%@NL@%
  7207. %@NL@%
  7208. %@NL@%
  7209.         END%@NL@%
  7210. %@NL@%
  7211. %@NL@%
  7212. %@2@%%@AH@%SHOWUTIL.ASM%@AE@%%@EH@%%@NL@%
  7213. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\SHOW\SHOWUTIL.ASM%@AE@%%@NL@%
  7214. %@NL@%
  7215. %@AB@%;* SHOWUTIL.ASM - Module containing routines used by both the real and%@AE@%%@NL@%
  7216. %@AB@%;* protected mode versions of SHOW. Works with main module SHOWR.ASM or%@AE@%%@NL@%
  7217. %@AB@%;* SHOWP.ASM and with PAGERR.ASM or PAGERP.ASM.%@AE@%%@NL@%
  7218. %@NL@%
  7219.         TITLE   ShowUtil%@NL@%
  7220.         .MODEL  small, pascal%@NL@%
  7221. %@NL@%
  7222.         INCLUDE show.inc%@NL@%
  7223. %@NL@%
  7224.         .CODE%@NL@%
  7225. %@NL@%
  7226. %@AB@%;* GetNamePos - Given a file specification potentially including file name,%@AE@%%@NL@%
  7227. %@AB@%;* directory, and/or drive, return the position of the first character%@AE@%%@NL@%
  7228. %@AB@%;* of the file name.%@AE@%%@NL@%
  7229. %@AB@%;*%@AE@%%@NL@%
  7230. %@AB@%;* Params: pchSpec - address of file spec%@AE@%%@NL@%
  7231. %@AB@%;*%@AE@%%@NL@%
  7232. %@AB@%;* Return: Near pointer to position of name portion of file spec%@AE@%%@NL@%
  7233. %@NL@%
  7234. GetNamePos PROC USES di si,%@NL@%
  7235.         pchSpec:PTR BYTE%@NL@%
  7236. %@NL@%
  7237.         push    ds%@NL@%
  7238.         pop     es%@NL@%
  7239.         mov     di, pchSpec             %@AB@%; Load address of file name%@AE@%%@NL@%
  7240.         mov     si, di                  %@AB@%; Save copy%@AE@%%@NL@%
  7241. %@NL@%
  7242.         sub     cx, cx                  %@AB@%; Use CX as count%@AE@%%@NL@%
  7243.         sub     dx, dx                  %@AB@%; Use DX as found flag%@AE@%%@NL@%
  7244.         sub     ax, ax                  %@AB@%; Search for null%@AE@%%@NL@%
  7245. %@NL@%
  7246.         .REPEAT%@NL@%
  7247.         .IF BYTE PTR es:[di] == '\'     %@AB@%; For each backslash:%@AE@%%@NL@%
  7248.         mov     si, di                  %@AB@%; Save position%@AE@%%@NL@%
  7249.         inc     dx                      %@AB@%; Set flag to true%@AE@%%@NL@%
  7250.         .ENDIF%@NL@%
  7251.         inc     cx                      %@AB@%; Count it%@AE@%%@NL@%
  7252.         scasb                           %@AB@%; Get next character%@AE@%%@NL@%
  7253.         .UNTIL  zero?%@NL@%
  7254. %@NL@%
  7255.         .IF     dx != 0                 %@AB@%; If found backslash:%@AE@%%@NL@%
  7256.         mov     ax, si                  %@AB@%; Return position in AX%@AE@%%@NL@%
  7257.         dec     ax%@NL@%
  7258. %@NL@%
  7259.         .ELSE                           %@AB@%; Else search for colon%@AE@%%@NL@%
  7260.         mov     di, si                  %@AB@%; Restore start of name%@AE@%%@NL@%
  7261.         mov     ax, ":"                 %@AB@%; Search for colon%@AE@%%@NL@%
  7262.         repne   scasb%@NL@%
  7263. %@NL@%
  7264.         .IF     zero?                   %@AB@%; If colon:%@AE@%%@NL@%
  7265.         mov     ax, di                  %@AB@%; Return position in DX:AX%@AE@%%@NL@%
  7266.         .ELSE                           %@AB@%; Else:%@AE@%%@NL@%
  7267.         mov     ax, si                  %@AB@%; Return original address%@AE@%%@NL@%
  7268.         .ENDIF%@NL@%
  7269.         .ENDIF%@NL@%
  7270. %@NL@%
  7271.         ret%@NL@%
  7272. %@NL@%
  7273. GetNamePos ENDP%@NL@%
  7274. %@NL@%
  7275. %@NL@%
  7276. %@AB@%;* GoBack - Purpose   Searches backward through buffer%@AE@%%@NL@%
  7277. %@AB@%;*%@AE@%%@NL@%
  7278. %@AB@%;* Params:   CX has number of lines%@AE@%%@NL@%
  7279. %@AB@%;*           ES:DI has buffer position%@AE@%%@NL@%
  7280. %@AB@%;*           AL has 10 (line feed character)%@AE@%%@NL@%
  7281. %@AB@%;*%@AE@%%@NL@%
  7282. %@AB@%;* Return:   None%@AE@%%@NL@%
  7283. %@AB@%;*%@AE@%%@NL@%
  7284. %@AB@%;* Modifies: Updates yCur and offBuf%@AE@%%@NL@%
  7285. %@NL@%
  7286. GoBack  PROC%@NL@%
  7287. %@NL@%
  7288.         neg     cx                      %@AB@%; Make count positive%@AE@%%@NL@%
  7289.         mov     dx, cx                  %@AB@%; Save a copy%@AE@%%@NL@%
  7290.         inc     cx                      %@AB@%; One extra to go up one%@AE@%%@NL@%
  7291.         .IF     di == 0                 %@AB@%; If start of file, done%@AE@%%@NL@%
  7292.         ret%@NL@%
  7293.         .ENDIF%@NL@%
  7294. %@NL@%
  7295.         .REPEAT%@NL@%
  7296.         push    cx                      %@AB@%; Save count%@AE@%%@NL@%
  7297.         mov     cx, 0FFh                %@AB@%; Load maximum character count%@AE@%%@NL@%
  7298.         .IF     cx >= SWORD PTR di      %@AB@%; If near start of buffer,%@AE@%%@NL@%
  7299.         mov     cx, di                  %@AB@%;   search only to start%@AE@%%@NL@%
  7300.         .ENDIF%@NL@%
  7301.         std                             %@AB@%; Go backward%@AE@%%@NL@%
  7302.         repne   scasb                   %@AB@%; Find last previous LF%@AE@%%@NL@%
  7303.         cld                             %@AB@%; Go foreward%@AE@%%@NL@%
  7304.         jcxz    atstart                 %@AB@%; If not found, must be at start%@AE@%%@NL@%
  7305.         pop     cx%@NL@%
  7306.         .UNTILCXZ%@NL@%
  7307. %@NL@%
  7308.         .IF     yCur == 0FFFFh          %@AB@%; IF end of file flag:%@AE@%%@NL@%
  7309.         add     di, 2                   %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
  7310.         mov     offBuf, di              %@AB@%; Save position%@AE@%%@NL@%
  7311.         call    EndCount                %@AB@%; Count back to get line number%@AE@%%@NL@%
  7312.         mov     yCur, ax                %@AB@%; Store line count%@AE@%%@NL@%
  7313.         ret%@NL@%
  7314.         .ENDIF%@NL@%
  7315. %@NL@%
  7316.         sub     yCur, dx                %@AB@%; Calculate line number%@AE@%%@NL@%
  7317.         jg      positive%@NL@%
  7318.         mov     yCur, 1                 %@AB@%; Set to 1 if negative%@AE@%%@NL@%
  7319. positive:%@NL@%
  7320.         add     di, 2                   %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
  7321.         mov     offBuf, di              %@AB@%; Save position%@AE@%%@NL@%
  7322.         ret%@NL@%
  7323. atstart:%@NL@%
  7324.         pop     cx%@NL@%
  7325.         sub     di, di                  %@AB@%; Load start of file%@AE@%%@NL@%
  7326.         mov     yCur, 1                 %@AB@%; Line 1%@AE@%%@NL@%
  7327.         mov     offBuf, di              %@AB@%; Save position%@AE@%%@NL@%
  7328.         ret%@NL@%
  7329. %@NL@%
  7330. GoBack  ENDP%@NL@%
  7331. %@NL@%
  7332. %@NL@%
  7333. %@AB@%;* GoForeward - Skips forward through a buffer of text a specified%@AE@%%@NL@%
  7334. %@AB@%;* number of lines.%@AE@%%@NL@%
  7335. %@AB@%;*%@AE@%%@NL@%
  7336. %@AB@%;* Params:  CX - number of text lines to skip%@AE@%%@NL@%
  7337. %@AB@%;*          ES:DI - starting buffer position%@AE@%%@NL@%
  7338. %@AB@%;*          AL has 10 (line feed character)%@AE@%%@NL@%
  7339. %@AB@%;*%@AE@%%@NL@%
  7340. %@AB@%;* Return:  None%@AE@%%@NL@%
  7341. %@AB@%;*%@AE@%%@NL@%
  7342. %@AB@%;* Modifes: yCur, offBuf, bx, cx, di%@AE@%%@NL@%
  7343. %@NL@%
  7344. GoForeward PROC%@NL@%
  7345. %@NL@%
  7346.         cld                             %@AB@%; Go forward%@AE@%%@NL@%
  7347.         mov     dx, cx                  %@AB@%; Copy count%@AE@%%@NL@%
  7348. %@NL@%
  7349.         .REPEAT%@NL@%
  7350.         push    cx                      %@AB@%; Save count%@AE@%%@NL@%
  7351.         mov     cx, 0FFh                %@AB@%; Load maximum character count%@AE@%%@NL@%
  7352.         mov     bx, cbBuf               %@AB@%; Get end of file%@AE@%%@NL@%
  7353. %@NL@%
  7354.         sub     bx, di                  %@AB@%; Characters to end of file%@AE@%%@NL@%
  7355.         .IF     cx >= bx                %@AB@%; If less than maximum per line:%@AE@%%@NL@%
  7356.         mov     cx, bx                  %@AB@%; Adjust%@AE@%%@NL@%
  7357.         .ENDIF%@NL@%
  7358. %@NL@%
  7359.         repne   scasb                   %@AB@%; Find next LF%@AE@%%@NL@%
  7360.         pop     cx%@NL@%
  7361. %@NL@%
  7362. %@NL@%
  7363.         .IF     !zero? || (di >= cbBuf) %@AB@%; If LF not found or beyond end:%@AE@%%@NL@%
  7364.         mov     di, offBuf              %@AB@%; Restore original position%@AE@%%@NL@%
  7365.         ret                             %@AB@%;  and quit%@AE@%%@NL@%
  7366.         .ENDIF%@NL@%
  7367.         .UNTILCXZ%@NL@%
  7368. %@NL@%
  7369.         add     yCur, dx                %@AB@%; Calulate line number%@AE@%%@NL@%
  7370.         mov     offBuf, di              %@AB@%; Save position%@AE@%%@NL@%
  7371.         ret%@NL@%
  7372. %@NL@%
  7373. GoForeward ENDP%@NL@%
  7374. %@NL@%
  7375. %@NL@%
  7376. %@AB@%;* EndCount - Skips backward through a buffer of text, counting each%@AE@%%@NL@%
  7377. %@AB@%;* text line.%@AE@%%@NL@%
  7378. %@AB@%;*%@AE@%%@NL@%
  7379. %@AB@%;* Params: ES:DI - buffer position (end of file)%@AE@%%@NL@%
  7380. %@AB@%;*%@AE@%%@NL@%
  7381. %@AB@%;* Return: Number of lines counted%@AE@%%@NL@%
  7382. %@NL@%
  7383. EndCount PROC USES di dx cx%@NL@%
  7384. %@NL@%
  7385.         std                             %@AB@%; Backward%@AE@%%@NL@%
  7386.         mov     al, 13                  %@AB@%; Search for CR%@AE@%%@NL@%
  7387.         mov     dx, -1                  %@AB@%; Initialize (first will inc to 0)%@AE@%%@NL@%
  7388. %@NL@%
  7389.         .REPEAT%@NL@%
  7390.         inc     dx                      %@AB@%; Adjust count%@AE@%%@NL@%
  7391.         mov     cx, 0FFh                %@AB@%; Load maximum character count%@AE@%%@NL@%
  7392. %@NL@%
  7393.         .IF     SWORD PTR cx >= di      %@AB@%; If near start of buffer:%@AE@%%@NL@%
  7394.         mov     cx, di                  %@AB@%; Search only to start%@AE@%%@NL@%
  7395.         .ENDIF%@NL@%
  7396. %@NL@%
  7397.         repne   scasb                   %@AB@%; Find last previous cr%@AE@%%@NL@%
  7398.         .UNTIL  !zero?                  %@AB@%; If not found, must be at start%@AE@%%@NL@%
  7399. %@NL@%
  7400.         mov     ax, dx                  %@AB@%; Return count%@AE@%%@NL@%
  7401.         cld                             %@AB@%; Forward%@AE@%%@NL@%
  7402.         ret%@NL@%
  7403. %@NL@%
  7404. EndCount ENDP%@NL@%
  7405. %@NL@%
  7406. %@NL@%
  7407. %@AB@%;* BinToStr - Converts an unsigned integer to a string. User is%@AE@%%@NL@%
  7408. %@AB@%;* responsible for providing a large enough buffer. The string is%@AE@%%@NL@%
  7409. %@AB@%;* not null-terminated.%@AE@%%@NL@%
  7410. %@AB@%;*%@AE@%%@NL@%
  7411. %@AB@%;* Params: i - Integer to be converted%@AE@%%@NL@%
  7412. %@AB@%;*         pch - Pointer to character buffer to receive string%@AE@%%@NL@%
  7413. %@AB@%;*%@AE@%%@NL@%
  7414. %@AB@%;* Return: Number of character in string.%@AE@%%@NL@%
  7415. %@NL@%
  7416. BinToStr PROC,%@NL@%
  7417.         i:WORD,%@NL@%
  7418.         pch:PTR BYTE%@NL@%
  7419. %@NL@%
  7420.         mov     ax, i%@NL@%
  7421.         mov     di, pch%@NL@%
  7422. %@NL@%
  7423.         sub     cx, cx                  %@AB@%; Clear counter%@AE@%%@NL@%
  7424.         mov     bx, 10                  %@AB@%; Divide by 10%@AE@%%@NL@%
  7425. %@NL@%
  7426. %@AB@%; Convert and save on stack backwards%@AE@%%@NL@%
  7427. %@NL@%
  7428.         .REPEAT%@NL@%
  7429.         sub     dx, dx                  %@AB@%; Clear top%@AE@%%@NL@%
  7430.         div     bx                      %@AB@%; Divide to get last digit as remainder%@AE@%%@NL@%
  7431.         add     dl, "0"                 %@AB@%; Convert to ASCII%@AE@%%@NL@%
  7432.         push    dx                      %@AB@%; Save on stack%@AE@%%@NL@%
  7433.         .UNTILCXZ ax == 0               %@AB@%; Until quotient is 0%@AE@%%@NL@%
  7434. %@NL@%
  7435. %@AB@%; Take off the stack and store forward%@AE@%%@NL@%
  7436. %@NL@%
  7437.         neg     cx                      %@AB@%; Negate and save count%@AE@%%@NL@%
  7438.         mov     dx, cx%@NL@%
  7439. %@NL@%
  7440.         .REPEAT%@NL@%
  7441.         pop     ax                      %@AB@%; Get character%@AE@%%@NL@%
  7442.         stosb                           %@AB@%; Store it%@AE@%%@NL@%
  7443.         .UNTILCXZ%@NL@%
  7444.         mov     ax, dx                  %@AB@%; Return digit count%@AE@%%@NL@%
  7445. %@NL@%
  7446.         ret%@NL@%
  7447. %@NL@%
  7448. BinToStr ENDP%@NL@%
  7449. %@NL@%
  7450. %@NL@%
  7451.         END%@NL@%
  7452. %@NL@%
  7453. %@NL@%
  7454. %@2@%%@AH@%SNAP.ASM%@AE@%%@EH@%%@NL@%
  7455. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM6\TSR\SNAP.ASM%@AE@%%@NL@%
  7456. %@NL@%
  7457.         .MODEL  small, pascal, os_dos%@NL@%
  7458.         .DOSSEG%@NL@%
  7459.         INCLUDE demo.inc%@NL@%
  7460.         INCLUDE tsr.inc%@NL@%
  7461. %@NL@%
  7462. OpenBox         PROTO%@NL@%
  7463. CloseBox        PROTO%@NL@%
  7464. %@NL@%
  7465.         .STACK%@NL@%
  7466.         .DATA%@NL@%
  7467. %@NL@%
  7468. DEFAULT_COLR    EQU     1Eh             %@AB@%; Default = white on blue (color)%@AE@%%@NL@%
  7469. DEFAULT_MONO    EQU     70h             %@AB@%; Default = reverse video (mono)%@AE@%%@NL@%
  7470. %@NL@%
  7471. %@AB@%; Set ALT + LEFT SHIFT + S as hot key combination. To set multiple shift%@AE@%%@NL@%
  7472. %@AB@%; keys, OR the appropriate values together for the shift value (HOT_SHIFT).%@AE@%%@NL@%
  7473. %@NL@%
  7474. HOT_SCAN        EQU     1Fh             %@AB@%; Hot key scan code (S)%@AE@%%@NL@%
  7475. HOT_SHIFT       EQU     shAlt OR shLeft %@AB@%; Shift value (ALT + LEFT SHIFT)%@AE@%%@NL@%
  7476. HOT_MASK        EQU     (shIns OR shCaps OR shNum OR shScroll) XOR 0FFh%@NL@%
  7477. %@NL@%
  7478. ROW1            EQU     9               %@AB@%; Query box begins on row 9%@AE@%%@NL@%
  7479. ROW2            EQU     14              %@AB@%;  and ends on row 14%@AE@%%@NL@%
  7480. HEIGHT          EQU     ROW2 - ROW1 + 1 %@AB@%; Number of rows in query box%@AE@%%@NL@%
  7481. %@NL@%
  7482. Box     BYTE    '┌──────────────────────────────────────┐', 0%@NL@%
  7483.         BYTE    '│  Enter file name                     │', 0%@NL@%
  7484.         BYTE    '│  (press Esc to cancel):              │', 0%@NL@%
  7485.         BYTE    '│                                      │', 0%@NL@%
  7486.         BYTE    '│                                      │', 0%@NL@%
  7487. boxend  BYTE    '└──────────────────────────────────────┘', 0%@NL@%
  7488. LEN     EQU     (LENGTHOF boxend) - 1%@NL@%
  7489. %@NL@%
  7490. OldPos  WORD    ?                       %@AB@%; Original cursor position%@AE@%%@NL@%
  7491. Handle  WORD    ?                       %@AB@%; File handle number%@AE@%%@NL@%
  7492. FilSpec BYTE    (LEN - 3) DUP(0)        %@AB@%; ASCIIZ string for file spec%@AE@%%@NL@%
  7493. %@NL@%
  7494. %@AB@%; Fill attribute for prompt box. This is changed by running SNAP with%@AE@%%@NL@%
  7495. %@AB@%; the /Cx switch, where x = new display attribute in hexadecimal. For%@AE@%%@NL@%
  7496. %@AB@%; example, to change the color to yellow on brown for a color monitor,%@AE@%%@NL@%
  7497. %@AB@%; enter%@AE@%%@NL@%
  7498. %@AB@%;         SNAP /C6E%@AE@%%@NL@%
  7499. %@AB@%; where the first digit specifies the background color and the second%@AE@%%@NL@%
  7500. %@AB@%; digit the foreground color. Typical values for x on a monochrome%@AE@%%@NL@%
  7501. %@AB@%; system are%@AE@%%@NL@%
  7502. %@AB@%;       07 normal                 70 reverse video%@AE@%%@NL@%
  7503. %@AB@%;       0F high intensity         78 reverse video, high intensity%@AE@%%@NL@%
  7504. %@NL@%
  7505. BoxFill BYTE    DEFAULT_MONO            %@AB@%; Assume monochrome%@AE@%%@NL@%
  7506. %@NL@%
  7507. %@AB@%; Hold contains the screen text and attributes replaced by the query box.%@AE@%%@NL@%
  7508. %@AB@%; Buffer holds text captured from the screen, with room for 50 rows of 82%@AE@%%@NL@%
  7509. %@AB@%; characters, including carriage return/linefeed. To change Buffer's%@AE@%%@NL@%
  7510. %@AB@%; capacity, replace the dimensions with r * (c + 2) DUP(?), where r and%@AE@%%@NL@%
  7511. %@AB@%; c are row and column count respectively.%@AE@%%@NL@%
  7512. %@NL@%
  7513. Hold    BYTE    (HEIGHT * LEN) + 3 DUP(?)%@NL@%
  7514. Buffer  BYTE    50 * 82 DUP(?)%@NL@%
  7515. %@NL@%
  7516. %@NL@%
  7517.         .CODE%@NL@%
  7518. %@NL@%
  7519. %@AB@%;* Snap - Main procedure for resident program. Called from the Activate%@AE@%%@NL@%
  7520. %@AB@%;* procedure when TSR is invoked by the proper key combination.%@AE@%%@NL@%
  7521. %@AB@%;*%@AE@%%@NL@%
  7522. %@AB@%;* Params:  DS, ES = @data%@AE@%%@NL@%
  7523. %@AB@%;*%@AE@%%@NL@%
  7524. %@AB@%;* Return:  None%@AE@%%@NL@%
  7525. %@NL@%
  7526. Snap    PROC    FAR%@NL@%
  7527. %@NL@%
  7528.         INVOKE  GetVidConfig            %@AB@%; Get video information%@AE@%%@NL@%
  7529. %@NL@%
  7530.         mov     al, vconfig.mode        %@AB@%; AL = video mode%@AE@%%@NL@%
  7531.         .IF     (al <= 3) || (al == 7)  %@AB@%; If text mode:%@AE@%%@NL@%
  7532. %@NL@%
  7533.         INVOKE  GetCurPos               %@AB@%; Get original cursor coordinates%@AE@%%@NL@%
  7534.         mov     OldPos, ax              %@AB@%;   and store them%@AE@%%@NL@%
  7535. %@NL@%
  7536.         INVOKE  OpenBox                 %@AB@%; Display query box%@AE@%%@NL@%
  7537. %@NL@%
  7538.         mov     bl, vconfig.cols        %@AB@%; Calculate column%@AE@%%@NL@%
  7539.         sub     bl, LEN%@NL@%
  7540.         shr     bl, 1%@NL@%
  7541.         add     bl, 3%@NL@%
  7542. %@NL@%
  7543.         INVOKE  StrInput,               %@AB@%; Request input%@AE@%%@NL@%
  7544.                 ROW1 + 4,               %@AB@%; Row%@AE@%%@NL@%
  7545.                 bl,                     %@AB@%; Column%@AE@%%@NL@%
  7546.                 LEN - 4,                %@AB@%; Maximum string%@AE@%%@NL@%
  7547.                 ADDR FilSpec            %@AB@%; Address of string buffer%@AE@%%@NL@%
  7548. %@NL@%
  7549.         push    ax                      %@AB@%; Save terminating keypress%@AE@%%@NL@%
  7550.         call    CloseBox                %@AB@%; Restore screen to original state%@AE@%%@NL@%
  7551.         pop     ax                      %@AB@%; Recover key%@AE@%%@NL@%
  7552.         .IF     al != ESCAPE            %@AB@%; If Esc key not pressed:%@AE@%%@NL@%
  7553.         call    OpenFile                %@AB@%; Open (or create) file%@AE@%%@NL@%
  7554. %@NL@%
  7555.         .IF     !carry?                 %@AB@%; If okay:%@AE@%%@NL@%
  7556.         call    Capture                 %@AB@%; Write screen to file%@AE@%%@NL@%
  7557.         .ELSE%@NL@%
  7558.         mov     ax, 0E07h               %@AB@%; Write bell character%@AE@%%@NL@%
  7559.         int     10h                     %@AB@%;   (ASCII 7) to console%@AE@%%@NL@%
  7560.         .ENDIF                          %@AB@%; End file-okay test%@AE@%%@NL@%
  7561.         .ENDIF                          %@AB@%; End ESCAPE test%@AE@%%@NL@%
  7562. %@NL@%
  7563.         mov     ax, OldPos              %@AB@%; Recover original cursor position%@AE@%%@NL@%
  7564.         mov     bl, ah%@NL@%
  7565. %@NL@%
  7566.         INVOKE  SetCurPos,              %@AB@%; Restore cursor%@AE@%%@NL@%
  7567.                 bx, ax                  %@AB@%; Pass cursor row and column%@AE@%%@NL@%
  7568. %@NL@%
  7569.         .ENDIF                          %@AB@%; End text mode test%@AE@%%@NL@%
  7570. %@NL@%
  7571.         retf                            %@AB@%; Far return to Activate procedure%@AE@%%@NL@%
  7572. %@NL@%
  7573. Snap    ENDP%@NL@%
  7574. %@NL@%
  7575. %@NL@%
  7576. %@AB@%;* OpenBox - Saves portion of screen to Hold buffer, then opens a box.%@AE@%%@NL@%
  7577. %@AB@%;*%@AE@%%@NL@%
  7578. %@AB@%;* Uses:    vconfig - Video configuration structure%@AE@%%@NL@%
  7579. %@AB@%;*%@AE@%%@NL@%
  7580. %@AB@%;* Params:  None%@AE@%%@NL@%
  7581. %@AB@%;*%@AE@%%@NL@%
  7582. %@AB@%;* Return:  None%@AE@%%@NL@%
  7583. %@NL@%
  7584. OpenBox PROC%@NL@%
  7585. %@NL@%
  7586.         mov     dh, ROW1                %@AB@%; DH = top screen row for box%@AE@%%@NL@%
  7587.         mov     dl, vconfig.cols%@NL@%
  7588.         sub     dl, LEN%@NL@%
  7589.         shr     dl, 1                   %@AB@%; DL = left col for centered box%@AE@%%@NL@%
  7590.         push    dx                      %@AB@%; Save coords%@AE@%%@NL@%
  7591.         sub     ch, ch%@NL@%
  7592.         mov     cl, dh                  %@AB@%; CX = row%@AE@%%@NL@%
  7593.         sub     dh, dh                  %@AB@%; DX = column%@AE@%%@NL@%
  7594.         GetVidOffset cx, dx%@NL@%
  7595.         mov     si, ax                  %@AB@%; Get video offset in SI%@AE@%%@NL@%
  7596.         mov     bx, HEIGHT              %@AB@%; BX = number of window rows%@AE@%%@NL@%
  7597.         mov     cx, LEN                 %@AB@%; CX = number of columns%@AE@%%@NL@%
  7598. %@NL@%
  7599.         push    ds%@NL@%
  7600.         pop     es%@NL@%
  7601.         mov     di, OFFSET Hold         %@AB@%; Point ES:DI to hold buffer%@AE@%%@NL@%
  7602.         mov     ax, si%@NL@%
  7603.         stosw                           %@AB@%; Copy video offset to buffer%@AE@%%@NL@%
  7604.         mov     ax, bx%@NL@%
  7605.         stosw                           %@AB@%; Number of rows to buffer%@AE@%%@NL@%
  7606.         mov     ax, cx%@NL@%
  7607.         stosw                           %@AB@%; Number of cols to buffer%@AE@%%@NL@%
  7608.         mov     al, vconfig.cols%@NL@%
  7609.         shl     ax, 1                   %@AB@%; AX = number of video cells/row%@AE@%%@NL@%
  7610.         mov     ds, vconfig.sgmnt       %@AB@%; DS = video segment%@AE@%%@NL@%
  7611. %@NL@%
  7612.         .REPEAT%@NL@%
  7613.         push    si                      %@AB@%; Save ptr to start of line%@AE@%%@NL@%
  7614.         push    cx                      %@AB@%;   and number of columns%@AE@%%@NL@%
  7615.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter:%@AE@%%@NL@%
  7616.         INVOKE  DisableCga              %@AB@%; Disable video%@AE@%%@NL@%
  7617.         .ENDIF%@NL@%
  7618.         rep     movsw                   %@AB@%; Copy one row to buffer%@AE@%%@NL@%
  7619.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter:%@AE@%%@NL@%
  7620.         INVOKE  EnableCga               %@AB@%; Reenable CGA video%@AE@%%@NL@%
  7621.         .ENDIF%@NL@%
  7622.         pop     cx                      %@AB@%; Recover number of columns%@AE@%%@NL@%
  7623.         pop     si                      %@AB@%;   and start of line%@AE@%%@NL@%
  7624.         add     si, ax                  %@AB@%; Point to start of next line%@AE@%%@NL@%
  7625.         dec     bx                      %@AB@%; Decrement row counter%@AE@%%@NL@%
  7626.         .UNTIL  zero?                   %@AB@%; Loop while rows remain%@AE@%%@NL@%
  7627. %@NL@%
  7628. %@AB@%; Screen contents (including display attributes) are now copied to buffer.%@AE@%%@NL@%
  7629. %@AB@%; Next open window, overwriting the screen portion just saved.%@AE@%%@NL@%
  7630. %@NL@%
  7631.         push    es%@NL@%
  7632.         pop     ds                      %@AB@%; Restore DS%@AE@%%@NL@%
  7633. %@NL@%
  7634.         mov     ax, 0600h               %@AB@%; Scroll service%@AE@%%@NL@%
  7635.         mov     bh, BoxFill             %@AB@%; BH = fill attribute%@AE@%%@NL@%
  7636.         pop     cx                      %@AB@%; CX = row/col for upper left%@AE@%%@NL@%
  7637.         mov     dh, ROW2%@NL@%
  7638.         mov     dl, cl%@NL@%
  7639.         add     dl, LEN%@NL@%
  7640.         dec     dl                      %@AB@%; DX = row/col for lower right%@AE@%%@NL@%
  7641.         int     10h                     %@AB@%; Blank window area on screen%@AE@%%@NL@%
  7642. %@NL@%
  7643. %@AB@%; Write box frame and text to screen%@AE@%%@NL@%
  7644. %@NL@%
  7645.         mov     dx, cx                  %@AB@%; DX = row/col for upper left%@AE@%%@NL@%
  7646.         mov     si, OFFSET Box          %@AB@%; Point to text%@AE@%%@NL@%
  7647.         mov     cx, HEIGHT              %@AB@%; Number of rows in box%@AE@%%@NL@%
  7648. %@NL@%
  7649.         .REPEAT%@NL@%
  7650.         push    dx                      %@AB@%; Save coordinates%@AE@%%@NL@%
  7651.         sub     bh, bh%@NL@%
  7652.         mov     bl, dh                  %@AB@%; BX = row%@AE@%%@NL@%
  7653.         sub     dh, dh                  %@AB@%; DX = column%@AE@%%@NL@%
  7654.         INVOKE  StrWrite, bx, dx, si    %@AB@%; Display one line of box%@AE@%%@NL@%
  7655.         pop     dx                      %@AB@%; Recover coordinates%@AE@%%@NL@%
  7656.         inc     dh                      %@AB@%; Next screen row%@AE@%%@NL@%
  7657.         add     si, LEN                 %@AB@%; Point to next line in box%@AE@%%@NL@%
  7658.         inc     si%@NL@%
  7659.         .UNTILCXZ%@NL@%
  7660. %@NL@%
  7661.         ret%@NL@%
  7662. %@NL@%
  7663. OpenBox ENDP%@NL@%
  7664. %@NL@%
  7665. %@NL@%
  7666. %@AB@%;* CloseBox - Restores the original screen text to close the window%@AE@%%@NL@%
  7667. %@AB@%;* previously opened by the OpenBox procedure%@AE@%%@NL@%
  7668. %@AB@%;*%@AE@%%@NL@%
  7669. %@AB@%;* Uses:    vconfig - Video configuration structure%@AE@%%@NL@%
  7670. %@AB@%;*%@AE@%%@NL@%
  7671. %@AB@%;* Params:  None%@AE@%%@NL@%
  7672. %@AB@%;*%@AE@%%@NL@%
  7673. %@AB@%;* Return:  None%@AE@%%@NL@%
  7674. %@NL@%
  7675. CloseBox PROC%@NL@%
  7676. %@NL@%
  7677.         mov     si, OFFSET Hold%@NL@%
  7678.         lodsw%@NL@%
  7679.         mov     di, ax                  %@AB@%; DI = video offset of window%@AE@%%@NL@%
  7680.         lodsw%@NL@%
  7681.         mov     bx, ax                  %@AB@%; BX = number of window rows%@AE@%%@NL@%
  7682.         lodsw%@NL@%
  7683.         mov     cx, ax                  %@AB@%; CX = number of columns%@AE@%%@NL@%
  7684. %@NL@%
  7685.         mov     al, vconfig.cols%@NL@%
  7686.         shl     ax, 1                   %@AB@%; AX = number of video cells/row%@AE@%%@NL@%
  7687. %@NL@%
  7688.         .REPEAT%@NL@%
  7689.         push    di                      %@AB@%; Save ptr to start of line%@AE@%%@NL@%
  7690.         push    cx                      %@AB@%;   and number of columns%@AE@%%@NL@%
  7691.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter:%@AE@%%@NL@%
  7692.         INVOKE  DisableCga              %@AB@%; Disable video%@AE@%%@NL@%
  7693.         .ENDIF%@NL@%
  7694.         rep     movsw                   %@AB@%; Copy one row to buffer%@AE@%%@NL@%
  7695.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA adapter:%@AE@%%@NL@%
  7696.         INVOKE  EnableCga               %@AB@%; Reenable CGA video%@AE@%%@NL@%
  7697.         .ENDIF%@NL@%
  7698.         pop     cx                      %@AB@%; Recover number of columns%@AE@%%@NL@%
  7699.         pop     di                      %@AB@%;   and start of line%@AE@%%@NL@%
  7700.         add     di, ax                  %@AB@%; Point to start of next line%@AE@%%@NL@%
  7701.         dec     bx                      %@AB@%; Decrement row counter%@AE@%%@NL@%
  7702.         .UNTIL  zero?                   %@AB@%; Loop while rows remain%@AE@%%@NL@%
  7703. %@NL@%
  7704.         ret%@NL@%
  7705. %@NL@%
  7706. CloseBox ENDP%@NL@%
  7707. %@NL@%
  7708. %@NL@%
  7709. %@AB@%;* OpenFile - Opens or creates specified file. Resets file pointer to%@AE@%%@NL@%
  7710. %@AB@%;* end of file so that subsequent text is appended to bottom of file.%@AE@%%@NL@%
  7711. %@AB@%;*%@AE@%%@NL@%
  7712. %@AB@%;* Params:  DS:SI = Pointer to file spec%@AE@%%@NL@%
  7713. %@AB@%;*%@AE@%%@NL@%
  7714. %@AB@%;* Return:  None%@AE@%%@NL@%
  7715. %@NL@%
  7716. OpenFile PROC%@NL@%
  7717. %@NL@%
  7718.         mov     ax, 3D01h               %@AB@%; Request DOS to open file%@AE@%%@NL@%
  7719.         mov     dx, OFFSET FilSpec      %@AB@%; DS:DX points to file specification%@AE@%%@NL@%
  7720.         int     21h                     %@AB@%; Open File%@AE@%%@NL@%
  7721.         .IF     carry?                  %@AB@%; If it doesn't exist:%@AE@%%@NL@%
  7722.         mov     ah, 3Ch                 %@AB@%; Request create file%@AE@%%@NL@%
  7723.         sub     cx, cx                  %@AB@%;   with normal attributes%@AE@%%@NL@%
  7724.         int     21h                     %@AB@%; Create File%@AE@%%@NL@%
  7725.         .ENDIF%@NL@%
  7726. %@NL@%
  7727.         .IF     !carry?                 %@AB@%; If no error:%@AE@%%@NL@%
  7728.         mov     Handle, ax              %@AB@%; Store file handle%@AE@%%@NL@%
  7729.         mov     bx, ax%@NL@%
  7730.         mov     ax, 4202h               %@AB@%; Request DOS to reset file pointer%@AE@%%@NL@%
  7731.         sub     cx, cx                  %@AB@%;   to end of file%@AE@%%@NL@%
  7732.         sub     dx, dx%@NL@%
  7733.         int     21h                     %@AB@%; Set File Pointer%@AE@%%@NL@%
  7734.         .ENDIF%@NL@%
  7735.         ret%@NL@%
  7736. %@NL@%
  7737. OpenFile ENDP%@NL@%
  7738. %@NL@%
  7739. %@NL@%
  7740. %@AB@%;* Capture - Copies screen text to Buffer, then writes Buffer to file.%@AE@%%@NL@%
  7741. %@AB@%;*%@AE@%%@NL@%
  7742. %@AB@%;* Uses:    vconfig - Video configuration structure%@AE@%%@NL@%
  7743. %@AB@%;*%@AE@%%@NL@%
  7744. %@AB@%;* Params:  None%@AE@%%@NL@%
  7745. %@AB@%;*%@AE@%%@NL@%
  7746. %@AB@%;* Return:  None%@AE@%%@NL@%
  7747. %@NL@%
  7748. Capture PROC%@NL@%
  7749. %@NL@%
  7750.         mov     es, vconfig.sgmnt       %@AB@%; ES points to video segment address%@AE@%%@NL@%
  7751.         sub     si, si                  %@AB@%; ES:SI points to 1st video byte%@AE@%%@NL@%
  7752.         sub     bx, bx                  %@AB@%; BX = index to capture buffer%@AE@%%@NL@%
  7753.         mov     dx, 3DAh                %@AB@%; DX = address of CGA status register%@AE@%%@NL@%
  7754. %@NL@%
  7755.         .REPEAT%@NL@%
  7756.         sub     ch, ch%@NL@%
  7757.         mov     cl, vconfig.cols        %@AB@%; CX = number of columns in line%@AE@%%@NL@%
  7758.         mov     di, cx%@NL@%
  7759.         dec     di%@NL@%
  7760.         shl     di, 1                   %@AB@%; ES:DI points to video byte for%@AE@%%@NL@%
  7761.         add     di, si                  %@AB@%;   last column in line%@AE@%%@NL@%
  7762. %@NL@%
  7763.         .REPEAT%@NL@%
  7764.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA:%@AE@%%@NL@%
  7765.         cli                             %@AB@%; Disallow interruptions%@AE@%%@NL@%
  7766.         .REPEAT%@NL@%
  7767.         in      al, dx                  %@AB@%; Read current video status%@AE@%%@NL@%
  7768.         .UNTIL  !(al & 1)               %@AB@%;   until horizontal retrace done%@AE@%%@NL@%
  7769.         .REPEAT%@NL@%
  7770.         in      al, dx                  %@AB@%; Read video status%@AE@%%@NL@%
  7771.         .UNTIL  al & 1                  %@AB@%;   until horizontal retrace starts%@AE@%%@NL@%
  7772.         .ENDIF                          %@AB@%; End CGA retrace check%@AE@%%@NL@%
  7773. %@NL@%
  7774.         mov     al, es:[di]             %@AB@%; Get screen char, working backward%@AE@%%@NL@%
  7775.         sti                             %@AB@%; Reenable interrupts in case CGA%@AE@%%@NL@%
  7776.         sub     di, 2                   %@AB@%; DI points to next character%@AE@%%@NL@%
  7777.         .UNTILCXZ (al != ' ')           %@AB@%; Scan for last non-blank character%@AE@%%@NL@%
  7778. %@NL@%
  7779.         .IF     !zero?                  %@AB@%; If non-blank char found:%@AE@%%@NL@%
  7780.         inc     cx                      %@AB@%; Adjust column counter%@AE@%%@NL@%
  7781.         mov     di, si                  %@AB@%; ES:DI points to start of line%@AE@%%@NL@%
  7782. %@NL@%
  7783.         .REPEAT%@NL@%
  7784.         .IF     vconfig.adapter == CGA  %@AB@%; If CGA:%@AE@%%@NL@%
  7785.         cli                             %@AB@%; Disallow interruptions%@AE@%%@NL@%
  7786.         .REPEAT%@NL@%
  7787.         in      al, dx                  %@AB@%; Read current video status%@AE@%%@NL@%
  7788.         .UNTIL  !(al & 1)               %@AB@%;   until horizontal retrace done%@AE@%%@NL@%
  7789.         .REPEAT%@NL@%
  7790.         in      al, dx                  %@AB@%; Read video status%@AE@%%@NL@%
  7791.         .UNTIL  al & 1                  %@AB@%;   until horizontal retrace starts%@AE@%%@NL@%
  7792.         .ENDIF                          %@AB@%; End CGA retrace check%@AE@%%@NL@%
  7793. %@NL@%
  7794.         mov     al, es:[di]             %@AB@%; Get character, working forward%@AE@%%@NL@%
  7795.         sti%@NL@%
  7796.         add     di, 2                   %@AB@%; DI points to next character%@AE@%%@NL@%
  7797.         mov     Buffer[bx], al          %@AB@%; Copy to buffer%@AE@%%@NL@%
  7798.         inc     bx%@NL@%
  7799.         .UNTILCXZ%@NL@%
  7800.         .ENDIF                          %@AB@%; End check for non-blank char%@AE@%%@NL@%
  7801. %@NL@%
  7802.         mov     WORD PTR Buffer[bx], CRLF%@AB@%; Finish line with return/line feed%@AE@%%@NL@%
  7803.         add     bx, 2%@NL@%
  7804.         mov     al, vconfig.cols%@NL@%
  7805.         sub     ah, ah%@NL@%
  7806.         shl     ax, 1%@NL@%
  7807.         add     si, ax                  %@AB@%; SI points to start of next line%@AE@%%@NL@%
  7808.         dec     vconfig.rows            %@AB@%; Decrement row count%@AE@%%@NL@%
  7809.         .UNTIL  sign?                   %@AB@%; Repeat for next screen row%@AE@%%@NL@%
  7810. %@NL@%
  7811.         mov     ah, 40h                 %@AB@%; Request DOS Function 40h%@AE@%%@NL@%
  7812.         mov     cx, bx                  %@AB@%; CX = number of bytes to write%@AE@%%@NL@%
  7813.         mov     bx, Handle              %@AB@%; BX = file handle%@AE@%%@NL@%
  7814.         mov     dx, OFFSET Buffer       %@AB@%; DS:DX points to buffer%@AE@%%@NL@%
  7815.         int     21h                     %@AB@%; Write to File%@AE@%%@NL@%
  7816.         .IF     (ax != cx)              %@AB@%; If number of bytes written !=%@AE@%%@NL@%
  7817.         stc                             %@AB@%;   number requested, set carry%@AE@%%@NL@%
  7818.         .ENDIF                          %@AB@%;   flag to indicate failure%@AE@%%@NL@%
  7819. %@NL@%
  7820.         pushf                           %@AB@%; Save carry flag%@AE@%%@NL@%
  7821.         mov     ah, 3Eh                 %@AB@%; Request DOS Function 3Eh%@AE@%%@NL@%
  7822.         int     21h                     %@AB@%; Close File%@AE@%%@NL@%
  7823.         popf                            %@AB@%; Recover carry%@AE@%%@NL@%
  7824.         ret%@NL@%
  7825. %@NL@%
  7826. Capture ENDP%@NL@%
  7827. %@NL@%
  7828. %@NL@%
  7829. @CurSeg ENDS%@NL@%
  7830. %@NL@%
  7831. %@AB@%;* INSTALLATION SECTION - The following code and data are used only%@AE@%%@NL@%
  7832. %@AB@%;* during SNAP's installation phase. When the program terminates%@AE@%%@NL@%
  7833. %@AB@%;* through Function 31h, the above code and data remain resident;%@AE@%%@NL@%
  7834. %@AB@%;* memory occupied by the following code and data segments is returned%@AE@%%@NL@%
  7835. %@AB@%;* to the operating system.%@AE@%%@NL@%
  7836. %@NL@%
  7837. DGROUP  GROUP INSTALLCODE, INSTALLDATA%@NL@%
  7838. %@NL@%
  7839. INSTALLDATA SEGMENT WORD PUBLIC 'DATA2'%@NL@%
  7840. %@NL@%
  7841. IDstr   BYTE    'SNAP DEMO TSR', 0      %@AB@%; Multiplex identifier string%@AE@%%@NL@%
  7842. %@NL@%
  7843. INSTALLDATA ENDS%@NL@%
  7844. %@NL@%
  7845. INSTALLCODE SEGMENT PARA PUBLIC 'CODE2'%@NL@%
  7846.         ASSUME  ds:@data%@NL@%
  7847. %@NL@%
  7848. Begin   PROC    NEAR%@NL@%
  7849. %@NL@%
  7850.         mov     ax, DGROUP%@NL@%
  7851.         mov     ds, ax                  %@AB@%; Initialize DS%@AE@%%@NL@%
  7852.         mov     ah, 15%@NL@%
  7853.         int     10h                     %@AB@%; Get Video Mode%@AE@%%@NL@%
  7854.         .IF     al != 7                 %@AB@%; If not default monochrome:%@AE@%%@NL@%
  7855.         mov     BoxFill, DEFAULT_COLR   %@AB@%; Reset to default color value%@AE@%%@NL@%
  7856.         .ENDIF%@NL@%
  7857. %@NL@%
  7858. %@AB@%; Before calling any of the TSR procedures, initialize global data%@AE@%%@NL@%
  7859. %@NL@%
  7860.         INVOKE  InitTsr,                %@AB@%; Initialize data%@AE@%%@NL@%
  7861.                 es,                     %@AB@%; Segment of PSP%@AE@%%@NL@%
  7862.                 ADDR IDstr,             %@AB@%; Far address of multiplex ID string%@AE@%%@NL@%
  7863.                 ADDR BoxFill            %@AB@%; Far address of memory shared%@AE@%%@NL@%
  7864.                                         %@AB@%;  with multiplex handler%@AE@%%@NL@%
  7865.         .IF     ax == WRONG_DOS         %@AB@%; If DOS version less than 2.0:%@AE@%%@NL@%
  7866.         jmp     exit                    %@AB@%; Exit with message%@AE@%%@NL@%
  7867.         .ENDIF%@NL@%
  7868. %@NL@%
  7869. %@AB@%; This section gets the command line argument to determine task:%@AE@%%@NL@%
  7870. %@AB@%;    No argument   = install%@AE@%%@NL@%
  7871. %@AB@%;    /D or -D      = deinstall%@AE@%%@NL@%
  7872. %@AB@%;    /Cx or -Cx    = change box fill attribute to value x%@AE@%%@NL@%
  7873. %@NL@%
  7874.         mov     al, 'd'                 %@AB@%; Search command line for%@AE@%%@NL@%
  7875.         call    GetOptions              %@AB@%;   /D or -D argument%@AE@%%@NL@%
  7876.         cmp     ax, NO_ARGUMENT         %@AB@%; No argument?%@AE@%%@NL@%
  7877.         je      installtsr              %@AB@%; If so, try to install%@AE@%%@NL@%
  7878.         cmp     ax, OK_ARGUMENT         %@AB@%; /D argument found?%@AE@%%@NL@%
  7879.         je      deinstalltsr            %@AB@%; If so, try to deinstall%@AE@%%@NL@%
  7880.         mov     al, 'c'                 %@AB@%; Else search command line for%@AE@%%@NL@%
  7881.         call    GetOptions              %@AB@%;   /C or -C argument%@AE@%%@NL@%
  7882.         cmp     ax, BAD_ARGUMENT        %@AB@%; If neither /D or /C arguments,%@AE@%%@NL@%
  7883.         je      exit                    %@AB@%;   quit with error message%@AE@%%@NL@%
  7884. %@NL@%
  7885. %@AB@%; This section changes the fill attribute of SNAP's prompt box. It converts%@AE@%%@NL@%
  7886. %@AB@%; to binary the two-digit hex number following the /C argument, calls the%@AE@%%@NL@%
  7887. %@AB@%; multiplex handler to find the address of the attribute variable stored in%@AE@%%@NL@%
  7888. %@AB@%; shared memory, then resets the attribute to the new value. It does not%@AE@%%@NL@%
  7889. %@AB@%; verify that the value specified in the command line is a valid two-digit%@AE@%%@NL@%
  7890. %@AB@%; hex number.%@AE@%%@NL@%
  7891. %@NL@%
  7892.         mov     ax, es:[di+1]           %@AB@%; AH = low digit, AL = high digit%@AE@%%@NL@%
  7893.         mov     cx, 2                   %@AB@%; Process two digits%@AE@%%@NL@%
  7894. %@NL@%
  7895.         .REPEAT%@NL@%
  7896.         sub     al, '0'                 %@AB@%; Convert digit to binary%@AE@%%@NL@%
  7897.         .IF     (al > 9)                %@AB@%; If not digit 0-9:%@AE@%%@NL@%
  7898.         and     al, 00011111y           %@AB@%; Mask out lower-case bit%@AE@%%@NL@%
  7899.         sub     al, 7                   %@AB@%; Convert A to 10, B to 11, etc%@AE@%%@NL@%
  7900.         .ENDIF%@NL@%
  7901.         xchg    ah, al                  %@AB@%; Get next digit in AL%@AE@%%@NL@%
  7902.         .UNTILCXZ%@NL@%
  7903. %@NL@%
  7904.         mov     cl, 4%@NL@%
  7905.         shl     al, cl                  %@AB@%; Multiply high digit by 16%@AE@%%@NL@%
  7906.         or      al, ah                  %@AB@%; AL = binary value of attribute%@AE@%%@NL@%
  7907.         push    ax                      %@AB@%; Save new attribute%@AE@%%@NL@%
  7908. %@NL@%
  7909.         mov     al, 2                   %@AB@%; Request function 2%@AE@%%@NL@%
  7910.         call    CallMultiplex           %@AB@%; Get shared memory addr in ES:DI%@AE@%%@NL@%
  7911.         .IF     ax != IS_INSTALLED      %@AB@%; If TSR is not installed:%@AE@%%@NL@%
  7912.         pop     ax                      %@AB@%; Clean stack and%@AE@%%@NL@%
  7913.         mov     ax, CANT_ACCESS         %@AB@%;   quit with error message%@AE@%%@NL@%
  7914.         jmp     exit%@NL@%
  7915.         .ELSE                           %@AB@%; If TSR is installed:%@AE@%%@NL@%
  7916.         pop     ax                      %@AB@%; Recover new fill attribute in AL%@AE@%%@NL@%
  7917.         mov     es:[di], al             %@AB@%; Write it to resident shared memory%@AE@%%@NL@%
  7918.         mov     ax, OK_ACCESS           %@AB@%; Signal successful completion%@AE@%%@NL@%
  7919.         jmp     exit%@NL@%
  7920.         .ENDIF%@NL@%
  7921. %@NL@%
  7922. %@AB@%; This section sets up the TSR's interrupt handlers and%@AE@%%@NL@%
  7923. %@AB@%; makes the program memory-resident%@AE@%%@NL@%
  7924. %@NL@%
  7925. installtsr:%@NL@%
  7926.         push    es                      %@AB@%; Preserve PSP address%@AE@%%@NL@%
  7927. %@NL@%
  7928.         mov     ax, @code%@NL@%
  7929.         mov     es, ax%@NL@%
  7930.         mov     bx, OFFSET Snap         %@AB@%; ES:BX points to Snap%@AE@%%@NL@%
  7931.         INVOKE  Install,                %@AB@%; Install handlers%@AE@%%@NL@%
  7932.                 HOT_SCAN,               %@AB@%; Scan code of hot key%@AE@%%@NL@%
  7933.                 HOT_SHIFT,              %@AB@%; Bit value of hot key%@AE@%%@NL@%
  7934.                 HOT_MASK,               %@AB@%; Bit mask for shift hot key%@AE@%%@NL@%
  7935.                 es::bx                   %@AB@%; Far address of Snap procedure%@AE@%%@NL@%
  7936. %@NL@%
  7937.         pop     bx                      %@AB@%; Recover PSP address%@AE@%%@NL@%
  7938.         or      ax, ax                  %@AB@%; If non-zero return code,%@AE@%%@NL@%
  7939.         jnz     exit                    %@AB@%;   exit with appropriate message%@AE@%%@NL@%
  7940.         mov     ax, INSTALLCODE         %@AB@%; Bottom of resident section%@AE@%%@NL@%
  7941.         sub     ax, bx                  %@AB@%; AX = number of paragraphs in%@AE@%%@NL@%
  7942.                                         %@AB@%;   block to be made resident%@AE@%%@NL@%
  7943.         INVOKE  KeepTsr,                %@AB@%; Make TSR memory-resident%@AE@%%@NL@%
  7944.                 ax                      %@AB@%; Resident paragraphs%@AE@%%@NL@%
  7945. %@NL@%
  7946. %@AB@%; This section deinstalls the resident TSR from memory%@AE@%%@NL@%
  7947. %@NL@%
  7948. deinstalltsr:%@NL@%
  7949. %@NL@%
  7950.         INVOKE  Deinstall               %@AB@%; Unchain interrupt handlers%@AE@%%@NL@%
  7951. %@NL@%
  7952.         .IF     ax > OK_ARGUMENT        %@AB@%; If successful:%@AE@%%@NL@%
  7953.         INVOKE  FreeTsr,                %@AB@%; Deinstall TSR by freeing memory%@AE@%%@NL@%
  7954.                 ax                      %@AB@%; Address of resident seg%@AE@%%@NL@%
  7955.         .ENDIF                          %@AB@%; Else exit with message%@AE@%%@NL@%
  7956. exit:%@NL@%
  7957.         INVOKE  FatalError,             %@AB@%; Exit to DOS with message%@AE@%%@NL@%
  7958.                 ax                      %@AB@%; Error number%@AE@%%@NL@%
  7959. %@NL@%
  7960. Begin   ENDP%@NL@%
  7961. %@NL@%
  7962. INSTALLCODE ENDS%@NL@%
  7963. %@NL@%
  7964.         END     Begin%@NL@%
  7965. %@1@%%@AH@%Microsoft MASM: Sample Code from Version 5.x%@EH@%%@AE@%
  7966. %@NL@%
  7967. %@NL@%
  7968. %@2@%%@AH@%BA.ASM%@AE@%%@EH@%%@NL@%
  7969. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\MIXED\BA.ASM%@AE@%%@NL@%
  7970. %@NL@%
  7971. %@NL@%
  7972. .MODEL medium%@NL@%
  7973. .CODE%@NL@%
  7974. %@NL@%
  7975. %@AB@%; BASIC        function for QuickBASIC, Version 4 and future versions%@AE@%%@NL@%
  7976. %@AB@%;   of Microsoft and IBM BASIC Compilers%@AE@%%@NL@%
  7977. %@NL@%
  7978.         PUBLIC        Power2%@NL@%
  7979. Power2        PROC%@NL@%
  7980.         push        bp                %@AB@%; Entry        sequence - save        old BP%@AE@%%@NL@%
  7981.         mov        bp,sp                %@AB@%; Set stack framepointer%@AE@%%@NL@%
  7982. %@NL@%
  7983.         mov        bx,[bp+8]        %@AB@%; Load Arg1 into%@AE@%%@NL@%
  7984.         mov        ax,[bx]                %@AB@%;   AX%@AE@%%@NL@%
  7985.         mov        bx,[bp+6]        %@AB@%; Load Arg2 into%@AE@%%@NL@%
  7986.         mov        cx,[bx]                %@AB@%;   CX%@AE@%%@NL@%
  7987.         shl        ax,cl                %@AB@%; AX = AX * (2 to power        of CX)%@AE@%%@NL@%
  7988.                                 %@AB@%; Leave        return value in        AX%@AE@%%@NL@%
  7989. %@NL@%
  7990.         pop        bp                %@AB@%; Restore old framepointer%@AE@%%@NL@%
  7991.         ret        4                %@AB@%; Exit,        and restore 4 bytes of args%@AE@%%@NL@%
  7992. Power2        ENDP%@NL@%
  7993. %@NL@%
  7994. %@AB@%; BASIC        subprogram for QuickBASIC, Versions 1, 2, and 3;%@AE@%%@NL@%
  7995. %@AB@%;     for the Microsoft        BASIC Compiler through Version 5.36%@AE@%%@NL@%
  7996. %@AB@%;     for the IBM BASIC        Compiler through Version 2.02%@AE@%%@NL@%
  7997. %@NL@%
  7998.         PUBLIC        Power2S%@NL@%
  7999. Power2S        PROC%@NL@%
  8000.         push        bp                %@AB@%; Entry        sequence - save        old BP%@AE@%%@NL@%
  8001.         mov        bp,sp                %@AB@%; Set stack framepointer%@AE@%%@NL@%
  8002. %@NL@%
  8003.         mov        bx,[bp+10]        %@AB@%; Load Arg1 into%@AE@%%@NL@%
  8004.         mov        ax,[bx]                %@AB@%;   AX%@AE@%%@NL@%
  8005.         mov        bx,[bp+8]        %@AB@%; Load Arg2 into%@AE@%%@NL@%
  8006.         mov        cx,[bx]                %@AB@%;   CX%@AE@%%@NL@%
  8007.         shl        ax,cl                %@AB@%; AX = AX * (2 to power        of CX)%@AE@%%@NL@%
  8008.         mov        bx,[bp+6]        %@AB@%; Store        result in%@AE@%%@NL@%
  8009.         mov        [bx],ax                %@AB@%;   Arg3%@AE@%%@NL@%
  8010. %@NL@%
  8011.         pop        bp                %@AB@%; Restore old framepointer%@AE@%%@NL@%
  8012.         ret        4                %@AB@%; Exit,        and restore 4 bytes of args%@AE@%%@NL@%
  8013. Power2S        ENDP%@NL@%
  8014.         END%@NL@%
  8015. %@NL@%
  8016. %@NL@%
  8017. %@NL@%
  8018. %@2@%%@AH@%CA.ASM%@AE@%%@EH@%%@NL@%
  8019. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\MIXED\CA.ASM%@AE@%%@NL@%
  8020. %@NL@%
  8021. %@NL@%
  8022. .MODEL SMALL%@NL@%
  8023. .CODE%@NL@%
  8024.         PUBLIC        _Power2%@NL@%
  8025. _Power2 PROC%@NL@%
  8026.         push        bp        %@AB@%;Entry sequence%@AE@%%@NL@%
  8027.         mov        bp,sp%@NL@%
  8028. %@NL@%
  8029.         mov        ax,[bp+4]        %@AB@%; Load Arg1 into AX%@AE@%%@NL@%
  8030.         mov        cx,[bp+6]        %@AB@%; Load Arg2 into CX%@AE@%%@NL@%
  8031.         shl        ax,cl                %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
  8032.                                 %@AB@%; Leave return value in AX%@AE@%%@NL@%
  8033. %@NL@%
  8034.         pop        bp                %@AB@%; Exit sequence%@AE@%%@NL@%
  8035.         ret%@NL@%
  8036. _Power2 ENDP%@NL@%
  8037.         END%@NL@%
  8038. %@NL@%
  8039. %@NL@%
  8040. %@NL@%
  8041. %@2@%%@AH@%FA.ASM%@AE@%%@EH@%%@NL@%
  8042. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\MIXED\FA.ASM%@AE@%%@NL@%
  8043. %@NL@%
  8044. %@NL@%
  8045. .MODEL large%@NL@%
  8046. .CODE%@NL@%
  8047.         PUBLIC        Power2%@NL@%
  8048. Power2        PROC%@NL@%
  8049.         push        bp                %@AB@%; Entry sequence - save old BP%@AE@%%@NL@%
  8050.         mov         bp,sp                %@AB@%; Set stack framepointer%@AE@%%@NL@%
  8051. %@NL@%
  8052.         les        bx,[bp+10]        %@AB@%; Load Arg1 into%@AE@%%@NL@%
  8053.         mov        ax,[bx]                %@AB@%;   AX%@AE@%%@NL@%
  8054.         les        bx,[bp+6]        %@AB@%; Load Arg2 into%@AE@%%@NL@%
  8055.         mov        cx,[bx]                %@AB@%;   CX%@AE@%%@NL@%
  8056.         shl        ax,cl                %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
  8057.                                 %@AB@%; Leave return value in AX%@AE@%%@NL@%
  8058. %@NL@%
  8059.         pop        bp                %@AB@%; Restore old framepointer%@AE@%%@NL@%
  8060.         ret        4                %@AB@%; Exit, and restore 4 bytes of args%@AE@%%@NL@%
  8061. Power2  ENDP%@NL@%
  8062.         END%@NL@%
  8063. %@NL@%
  8064. %@NL@%
  8065. %@2@%%@AH@%PA.ASM%@AE@%%@EH@%%@NL@%
  8066. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\MIXED\PA.ASM%@AE@%%@NL@%
  8067. %@NL@%
  8068. %@NL@%
  8069. .MODEL medium%@NL@%
  8070. .CODE%@NL@%
  8071.         PUBLIC        Power2%@NL@%
  8072. Power2        PROC%@NL@%
  8073.         push        bp                %@AB@%; Entry sequence - save old BP%@AE@%%@NL@%
  8074.         mov         bp,sp                %@AB@%; Set stack framepointer%@AE@%%@NL@%
  8075. %@NL@%
  8076.         mov        ax,[bp+8]        %@AB@%; Load Arg1 into AX%@AE@%%@NL@%
  8077.         mov        cx,[bp+6]        %@AB@%; Load Arg2 into CX%@AE@%%@NL@%
  8078.         shl        ax,cl                %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
  8079.                                 %@AB@%; Leave return value in AX%@AE@%%@NL@%
  8080. %@NL@%
  8081.         pop        bp                %@AB@%; Restore old framepointer%@AE@%%@NL@%
  8082.         ret        4                %@AB@%; Exit, and restore 4 bytes of args%@AE@%%@NL@%
  8083. Power2  ENDP%@NL@%
  8084.         END%@NL@%
  8085. %@NL@%
  8086. %@NL@%
  8087. %@2@%%@AH@%PAGERP.ASM%@AE@%%@EH@%%@NL@%
  8088. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\PAGERP.ASM%@AE@%%@NL@%
  8089. %@NL@%
  8090.           TITLE   Pager%@NL@%
  8091.           .MODEL  small, pascal%@NL@%
  8092. %@NL@%
  8093. INCL_VIO  EQU 1%@NL@%
  8094. %@NL@%
  8095.           INCLUDE os2.inc%@NL@%
  8096.           .DATA%@NL@%
  8097.           EXTRN   stAtrib:BYTE, scAtrib:BYTE, Cell:WORD, stLine:BYTE%@NL@%
  8098.           EXTRN   sBuffer:WORD, oBuffer:WORD, Buffer:DWORD, lBuffer:WORD%@NL@%
  8099.           EXTRN   nLines:WORD, curLine:WORD%@NL@%
  8100. %@NL@%
  8101.           .CODE%@NL@%
  8102.           PUBLIC  Pager%@NL@%
  8103. %@NL@%
  8104. %@AB@%; Procedure Pager%@AE@%%@NL@%
  8105. %@AB@%; Purpose   Displays status and text lines%@AE@%%@NL@%
  8106. %@AB@%; Input     Stack variable: lines to scroll (negative up, positive down)%@AE@%%@NL@%
  8107. %@AB@%;           Global variables: "sbuffer", "oBuffer", "curLine"%@AE@%%@NL@%
  8108. %@AB@%; Output    To screen%@AE@%%@NL@%
  8109. %@NL@%
  8110. Pager     PROC    count%@NL@%
  8111. %@NL@%
  8112.           mov     es, sBuffer           %@AB@%; Initialize buffer position%@AE@%%@NL@%
  8113.           mov     di, oBuffer%@NL@%
  8114. %@NL@%
  8115.           mov     cx, count             %@AB@%; Get count argument%@AE@%%@NL@%
  8116.           mov     ax, 10                %@AB@%; Search for linefeed%@AE@%%@NL@%
  8117. %@NL@%
  8118.           or      cx, cx                %@AB@%; Argument 0?%@AE@%%@NL@%
  8119.           jl      skip1                 %@AB@%; If below, backward%@AE@%%@NL@%
  8120.           jg      skip2                 %@AB@%; If above, forward%@AE@%%@NL@%
  8121.           jmp     SHORT skip3           %@AB@%; If equal, done%@AE@%%@NL@%
  8122. %@NL@%
  8123. skip1:    call    GoBack                %@AB@%; Adjust backward%@AE@%%@NL@%
  8124.           jmp     SHORT skip3           %@AB@%; Show screen%@AE@%%@NL@%
  8125. skip2:    call    GoForwd               %@AB@%; Adjust forward%@AE@%%@NL@%
  8126. %@NL@%
  8127. %@AB@%; Write line number to status line%@AE@%%@NL@%
  8128. %@NL@%
  8129. skip3:    cld                           %@AB@%; Go forward%@AE@%%@NL@%
  8130.           push    di                    %@AB@%; Save%@AE@%%@NL@%
  8131.           push    ds                    %@AB@%; ES = DS%@AE@%%@NL@%
  8132.           pop     es%@NL@%
  8133. %@NL@%
  8134. %@AB@%; BinToStr (curLine, OFFSET stLine[6])%@AE@%%@NL@%
  8135. %@NL@%
  8136.           push    curLine               %@AB@%; Arg 1%@AE@%%@NL@%
  8137.           @Pushc  <OFFSET stLine[6]>    %@AB@%; Arg 2%@AE@%%@NL@%
  8138.           call    BinToStr              %@AB@%; Convert to string%@AE@%%@NL@%
  8139. %@NL@%
  8140. %@AB@%; Fill in status line%@AE@%%@NL@%
  8141. %@NL@%
  8142.           mov     cx, 6                 %@AB@%; Six spaces to fill%@AE@%%@NL@%
  8143.           sub     cx, ax                %@AB@%; Subtract those already done%@AE@%%@NL@%
  8144.           mov     al, " "               %@AB@%; Fill with space%@AE@%%@NL@%
  8145.           rep     stosb%@NL@%
  8146. %@NL@%
  8147.           @VioWrtCharStrAtt stLine, 80, 0, 0, stAtrib, 0 %@AB@%; Write to screen%@AE@%%@NL@%
  8148. %@NL@%
  8149.           pop     di                    %@AB@%; Update position%@AE@%%@NL@%
  8150.           mov     si, di%@NL@%
  8151.           mov     cx, nLines            %@AB@%; Lines per screen%@AE@%%@NL@%
  8152. %@NL@%
  8153. loop1:    mov     bx, nLines            %@AB@%; Lines of text%@AE@%%@NL@%
  8154.           inc     bx                    %@AB@%; Adjust for 0%@AE@%%@NL@%
  8155.           sub     bx, cx                %@AB@%; Calculate current row%@AE@%%@NL@%
  8156.           push    cx                    %@AB@%; Save line number%@AE@%%@NL@%
  8157. %@NL@%
  8158. %@AB@%; ShowLine (position, line, maxlength, &scAtrib)%@AE@%%@NL@%
  8159. %@NL@%
  8160.           push    sBuffer               %@AB@%; Arg 1%@AE@%%@NL@%
  8161.           push    si%@NL@%
  8162.           push    bx                    %@AB@%; Arg 2%@AE@%%@NL@%
  8163.           push    lBuffer               %@AB@%; Arg 3%@AE@%%@NL@%
  8164.           push    ds                    %@AB@%; Arg r4%@AE@%%@NL@%
  8165.           @Pushc  <OFFSET scAtrib>%@NL@%
  8166.           call    ShowLine              %@AB@%; Write line%@AE@%%@NL@%
  8167. %@NL@%
  8168.           pop     cx                    %@AB@%; Restore line number%@AE@%%@NL@%
  8169.           mov     si, ax                %@AB@%; Get returned position%@AE@%%@NL@%
  8170. %@NL@%
  8171.           cmp     ax, lBuffer           %@AB@%; If beyond end of file,%@AE@%%@NL@%
  8172.           jae     skip4                 %@AB@%;   fill screen with spaces%@AE@%%@NL@%
  8173.           loop    loop1                 %@AB@%; else next line%@AE@%%@NL@%
  8174.           jmp     SHORT exit            %@AB@%; Exit if done%@AE@%%@NL@%
  8175. %@NL@%
  8176. %@AB@%; Fill the rest with spaces%@AE@%%@NL@%
  8177. %@NL@%
  8178. skip4:    dec     cx%@NL@%
  8179.           jcxz    exit%@NL@%
  8180.           mov     ax, 80                %@AB@%; Columns times remaining lines%@AE@%%@NL@%
  8181.           mul     cl%@NL@%
  8182.           mov     dx, ax                %@AB@%; Macros use AX, so use DX%@AE@%%@NL@%
  8183.           sub     cx, nLines            %@AB@%; Calculate starting line%@AE@%%@NL@%
  8184.           neg     cx%@NL@%
  8185.           inc     cx%@NL@%
  8186. %@NL@%
  8187.           @VioWrtNCell Cell, dx, cx, 0, 0 %@AB@%; Write space cells%@AE@%%@NL@%
  8188. %@NL@%
  8189. exit:     ret%@NL@%
  8190. Pager     ENDP%@NL@%
  8191. %@NL@%
  8192. %@AB@%; Procedure ShowLine (inLine, sRow, &pAtrib)%@AE@%%@NL@%
  8193. %@AB@%; Purpose   Writes a line to screen%@AE@%%@NL@%
  8194. %@AB@%; Input     Stack variables: 1 - FAR PTR to input line%@AE@%%@NL@%
  8195. %@AB@%;                            2 - line number%@AE@%%@NL@%
  8196. %@AB@%;                            3 - maximum number of characters (file length)%@AE@%%@NL@%
  8197. %@AB@%;                            4 - FAR PTR to attribute%@AE@%%@NL@%
  8198. %@AB@%; Output    Line to screen%@AE@%%@NL@%
  8199. %@NL@%
  8200. ShowLine  PROC    USES si di, inLine:FAR PTR BYTE, srow, max, pAtrib:FAR PTR BYTE%@NL@%
  8201.           LOCAL   outLine[80]:BYTE%@NL@%
  8202. %@NL@%
  8203.           push    ds                    %@AB@%; Save%@AE@%%@NL@%
  8204.           push    ss                    %@AB@%; ES = SS%@AE@%%@NL@%
  8205.           pop     es%@NL@%
  8206.           lea     di, outLine           %@AB@%; Destination line%@AE@%%@NL@%
  8207.           lds     si, inLine            %@AB@%; Source line%@AE@%%@NL@%
  8208.           mov     cx, 80                %@AB@%; Cells per row%@AE@%%@NL@%
  8209.           mov     bx, di                %@AB@%; Save copy of start for tab calc%@AE@%%@NL@%
  8210. loop1:    lodsb                         %@AB@%; Get character%@AE@%%@NL@%
  8211.           cmp     al, 9                 %@AB@%; Tab?%@AE@%%@NL@%
  8212.           je      skip1                 %@AB@%; Space out tab%@AE@%%@NL@%
  8213.           cmp     al, 13                %@AB@%; CR?%@AE@%%@NL@%
  8214.           je      skip3                 %@AB@%; Fill rest of line with spaces%@AE@%%@NL@%
  8215.           stosb                         %@AB@%; Copy out%@AE@%%@NL@%
  8216.           cmp     si, max               %@AB@%; Check for end of file%@AE@%%@NL@%
  8217.           ja      skip3%@NL@%
  8218.           loop    loop1%@NL@%
  8219. %@NL@%
  8220. loop2:    lodsb                         %@AB@%; Throw away rest of line to truncate%@AE@%%@NL@%
  8221.           cmp     si, max               %@AB@%; Check for end of file%@AE@%%@NL@%
  8222.           ja      exit%@NL@%
  8223.           cmp     al, 13                %@AB@%; Check for end of line%@AE@%%@NL@%
  8224.           jne     loop2%@NL@%
  8225.           inc     si                    %@AB@%; Throw away line feed%@AE@%%@NL@%
  8226. %@NL@%
  8227.           jmp     SHORT exit            %@AB@%; Done%@AE@%%@NL@%
  8228. %@NL@%
  8229. skip1:    push    bx                    %@AB@%; Fill tab with spaces%@AE@%%@NL@%
  8230.           push    cx%@NL@%
  8231. %@NL@%
  8232.           sub     bx, di                %@AB@%; Get current position in line%@AE@%%@NL@%
  8233.           neg     bx%@NL@%
  8234. %@NL@%
  8235.           mov     cx, 8                 %@AB@%; Default count 8%@AE@%%@NL@%
  8236.           and     bx, 7                 %@AB@%; Get modulus%@AE@%%@NL@%
  8237.           sub     cx, bx                %@AB@%; Subtract%@AE@%%@NL@%
  8238.           mov     bx, cx                %@AB@%; Save modulus%@AE@%%@NL@%
  8239. %@NL@%
  8240.           mov     al, " "               %@AB@%; Write spaces%@AE@%%@NL@%
  8241.           rep     stosb%@NL@%
  8242. %@NL@%
  8243.           pop     cx%@NL@%
  8244.           sub     cx, bx                %@AB@%; Adjust count%@AE@%%@NL@%
  8245.           jns     skip2                 %@AB@%; Make negative count 0%@AE@%%@NL@%
  8246.           sub     cx, cx%@NL@%
  8247. skip2:    pop     bx%@NL@%
  8248.           jcxz    loop2                 %@AB@%; If beyond limit done%@AE@%%@NL@%
  8249.           jmp     SHORT loop1%@NL@%
  8250. %@NL@%
  8251. skip3:    inc     si                    %@AB@%; After CR, throw away LF%@AE@%%@NL@%
  8252.           mov     al, ' '               %@AB@%; Fill rest of line%@AE@%%@NL@%
  8253.           rep     stosb%@NL@%
  8254. %@NL@%
  8255. exit:     pop     ds%@NL@%
  8256.           @VioWrtCharStrAtt outLine, 80, [srow], 0, [pAtrib], 0%@NL@%
  8257. %@NL@%
  8258.           mov     ax, si                %@AB@%; Return position%@AE@%%@NL@%
  8259.           ret%@NL@%
  8260. ShowLine  ENDP%@NL@%
  8261. %@NL@%
  8262. %@AB@%; Procedure GoBack%@AE@%%@NL@%
  8263. %@AB@%; Purpose   Searches backward through buffer%@AE@%%@NL@%
  8264. %@AB@%; Input     CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
  8265. %@AB@%; Output    Updates "curLine" and "oBuffer"%@AE@%%@NL@%
  8266. %@NL@%
  8267. GoBack    PROC%@NL@%
  8268.           std                           %@AB@%; Go backward%@AE@%%@NL@%
  8269.           neg     cx                    %@AB@%; Make count positive%@AE@%%@NL@%
  8270.           mov     dx, cx                %@AB@%; Save a copy%@AE@%%@NL@%
  8271.           inc     cx                    %@AB@%; One extra to go up one%@AE@%%@NL@%
  8272.           or      di, di                %@AB@%; Start of file?%@AE@%%@NL@%
  8273.           je      exit                  %@AB@%; If so, ignore%@AE@%%@NL@%
  8274. loop1:    push    cx                    %@AB@%;   else save count%@AE@%%@NL@%
  8275.           mov     cx, 0FFh              %@AB@%; Load maximum character count%@AE@%%@NL@%
  8276.           cmp     cx, di                %@AB@%; Near start of buffer?%@AE@%%@NL@%
  8277.           jl      skip1                 %@AB@%; No? Continue%@AE@%%@NL@%
  8278.           mov     cx, di                %@AB@%;   else search only to start%@AE@%%@NL@%
  8279. skip1:    repne   scasb                 %@AB@%; Find last previous LF%@AE@%%@NL@%
  8280.           jcxz    skip4                 %@AB@%; If not found, must be at start%@AE@%%@NL@%
  8281.           pop     cx%@NL@%
  8282.           loop    loop1%@NL@%
  8283.           cmp     curLine, -1           %@AB@%; End of file flag?%@AE@%%@NL@%
  8284.           jne     skip2                 %@AB@%; No? Continue%@AE@%%@NL@%
  8285.           add     di, 2                 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
  8286.           mov     oBuffer, di           %@AB@%; Save position%@AE@%%@NL@%
  8287.           call    EndCount              %@AB@%; Count back to get line number%@AE@%%@NL@%
  8288.           ret%@NL@%
  8289. %@NL@%
  8290. skip2:    sub     curLine, dx           %@AB@%; Calculate line number%@AE@%%@NL@%
  8291.           jg      skip3%@NL@%
  8292.           mov     curLine, 1            %@AB@%; Set to 1 if negative%@AE@%%@NL@%
  8293. skip3:    add     di, 2                 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
  8294.           mov     oBuffer, di           %@AB@%; Save position%@AE@%%@NL@%
  8295.           ret%@NL@%
  8296. %@NL@%
  8297. skip4:    pop     cx%@NL@%
  8298.           sub     di, di                %@AB@%; Load start of file%@AE@%%@NL@%
  8299.           mov     curLine, 1            %@AB@%; Line 1%@AE@%%@NL@%
  8300.           mov     oBuffer, di           %@AB@%; Save position%@AE@%%@NL@%
  8301. exit:     ret%@NL@%
  8302. GoBack    ENDP%@NL@%
  8303. %@NL@%
  8304. %@AB@%; Procedure GoForwd%@AE@%%@NL@%
  8305. %@AB@%; Purpose   Searches forward through a buffer%@AE@%%@NL@%
  8306. %@AB@%; Input     CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
  8307. %@AB@%; Output    Updates "curLine" and "oBuffer"%@AE@%%@NL@%
  8308. %@NL@%
  8309. GoForwd   PROC%@NL@%
  8310.           cld                           %@AB@%; Go forward%@AE@%%@NL@%
  8311.           mov     dx, cx                %@AB@%; Copy count%@AE@%%@NL@%
  8312. loop1:    push    cx                    %@AB@%; Save count%@AE@%%@NL@%
  8313.           mov     cx, 0FFh              %@AB@%; Load maximum character count%@AE@%%@NL@%
  8314.           mov     bx, lBuffer           %@AB@%; Get end of file%@AE@%%@NL@%
  8315. %@NL@%
  8316.           sub     bx, di                %@AB@%; Characters to end of file%@AE@%%@NL@%
  8317.           cmp     cx, bx                %@AB@%; Less than maximum per line?%@AE@%%@NL@%
  8318.           jb      skip1%@NL@%
  8319.           mov     cx, bx%@NL@%
  8320. skip1:    repne   scasb                 %@AB@%; Find next LF%@AE@%%@NL@%
  8321.           jcxz    exit                  %@AB@%; If not found, must be at end%@AE@%%@NL@%
  8322.           cmp     di, lBuffer           %@AB@%; Beyond end?%@AE@%%@NL@%
  8323.           jae     exit%@NL@%
  8324.           pop     cx%@NL@%
  8325.           loop    loop1%@NL@%
  8326.           add     curLine, dx           %@AB@%; Calulate line number%@AE@%%@NL@%
  8327.           mov     oBuffer, di           %@AB@%; Save position%@AE@%%@NL@%
  8328.           ret%@NL@%
  8329. %@NL@%
  8330. exit:     pop     cx%@NL@%
  8331.           mov     di, oBuffer           %@AB@%; Restore position%@AE@%%@NL@%
  8332.           ret%@NL@%
  8333. GoForwd   ENDP%@NL@%
  8334. %@NL@%
  8335. %@AB@%; Procedure EndCount%@AE@%%@NL@%
  8336. %@AB@%; Purpose   Counts backward to count lines in file%@AE@%%@NL@%
  8337. %@AB@%; Input     ES:DI has buffer position%@AE@%%@NL@%
  8338. %@AB@%; Output    Modifies "curLine"%@AE@%%@NL@%
  8339. %@NL@%
  8340. EndCount  PROC%@NL@%
  8341.           push    di%@NL@%
  8342. %@NL@%
  8343.           mov     al, 13                %@AB@%; Search for CR%@AE@%%@NL@%
  8344.           mov     curLine, 0            %@AB@%; Initialize%@AE@%%@NL@%
  8345. %@NL@%
  8346. loop1:    inc     curLine               %@AB@%; Adjust count%@AE@%%@NL@%
  8347.           mov     cx, 0FFh              %@AB@%; Load maximum character count%@AE@%%@NL@%
  8348.           cmp     cx, di                %@AB@%; Near start of buffer?%@AE@%%@NL@%
  8349.           jl      skip1                 %@AB@%; No? Continue%@AE@%%@NL@%
  8350.           mov     cx, di                %@AB@%;   else search only to start%@AE@%%@NL@%
  8351. skip1:    repne   scasb                 %@AB@%; Find last previous cr%@AE@%%@NL@%
  8352.           jcxz    exit                  %@AB@%; If not found, must be at start%@AE@%%@NL@%
  8353.           jmp     SHORT loop1%@NL@%
  8354. %@NL@%
  8355. exit:     pop     di%@NL@%
  8356.           ret%@NL@%
  8357. EndCount  ENDP%@NL@%
  8358. %@NL@%
  8359. %@AB@%; Procedure BinToStr (number, string)%@AE@%%@NL@%
  8360. %@AB@%; Purpose   Converts integer to string%@AE@%%@NL@%
  8361. %@AB@%; Input     Stack arguments: 1 - Number to convert; 2 - Near address for write%@AE@%%@NL@%
  8362. %@AB@%; Output    AX has characters written%@AE@%%@NL@%
  8363. %@NL@%
  8364. BinToStr  PROC    number, string:PTR BYTE%@NL@%
  8365. %@NL@%
  8366.           mov     ax,number%@NL@%
  8367.           mov     di,string%@NL@%
  8368. %@NL@%
  8369.           sub     cx, cx                %@AB@%; Clear counter%@AE@%%@NL@%
  8370.           mov     bx, 10                %@AB@%; Divide by 10%@AE@%%@NL@%
  8371. %@NL@%
  8372. %@AB@%; Convert and save on stack backwards%@AE@%%@NL@%
  8373. %@NL@%
  8374. loop1:    sub     dx, dx                %@AB@%; Clear top%@AE@%%@NL@%
  8375.           div     bx                    %@AB@%; Divide to get last digit as remainder%@AE@%%@NL@%
  8376.           add     dl, "0"               %@AB@%; Convert to ASCII%@AE@%%@NL@%
  8377.           push    dx                    %@AB@%; Save on stack%@AE@%%@NL@%
  8378.           or      ax, ax                %@AB@%; Quotient 0?%@AE@%%@NL@%
  8379.           loopnz  loop1                 %@AB@%; No? Get another%@AE@%%@NL@%
  8380. %@NL@%
  8381. %@AB@%; Take off the stack and store forward%@AE@%%@NL@%
  8382. %@NL@%
  8383.           neg     cx                    %@AB@%; Negate and save count%@AE@%%@NL@%
  8384.           mov     dx, cx%@NL@%
  8385. loop2:    pop     ax                    %@AB@%; Get character%@AE@%%@NL@%
  8386.           stosb                         %@AB@%; Store it%@AE@%%@NL@%
  8387.           loop    loop2%@NL@%
  8388.           mov     ax, dx                %@AB@%; Return digit count%@AE@%%@NL@%
  8389. %@NL@%
  8390.           ret%@NL@%
  8391. BinToStr  ENDP%@NL@%
  8392. %@NL@%
  8393.           END%@NL@%
  8394. %@NL@%
  8395. %@NL@%
  8396. %@2@%%@AH@%PAGERR.ASM%@AE@%%@EH@%%@NL@%
  8397. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\PAGERR.ASM%@AE@%%@NL@%
  8398. %@NL@%
  8399.           PAGE          60,132%@NL@%
  8400.           .MODEL  small%@NL@%
  8401.           .DATA%@NL@%
  8402.           EXTRN          statatr:BYTE,scrnatr:BYTE,sbuffer:WORD,pbuffer:WORD%@NL@%
  8403.           EXTRN          fsize:WORD,cell:WORD,statline:BYTE,linenum:WORD%@NL@%
  8404.           EXTRN          rows:WORD,vidadr:WORD,cga:BYTE%@NL@%
  8405. %@NL@%
  8406.           .CODE%@NL@%
  8407.           PUBLIC  Pager,isEGA%@NL@%
  8408. %@NL@%
  8409. %@AB@%; Procedure Pager%@AE@%%@NL@%
  8410. %@AB@%; Purpose   Displays status and        text lines%@AE@%%@NL@%
  8411. %@AB@%; Input            Stack variable: lines to scroll (negative up, positive down)%@AE@%%@NL@%
  8412. %@AB@%;            Global variables: "sbuffer", "pbuffer", "linenum"%@AE@%%@NL@%
  8413. %@AB@%; Output    To screen%@AE@%%@NL@%
  8414. %@NL@%
  8415. Pager          PROC%@NL@%
  8416.           push          bp%@NL@%
  8417.           mov          bp,sp%@NL@%
  8418. %@NL@%
  8419.           mov          es,sbuffer                %@AB@%; Initialize buffer position%@AE@%%@NL@%
  8420.           mov          di,pbuffer%@NL@%
  8421. %@NL@%
  8422.           mov          cx,[bp+4]                %@AB@%; Get count argument%@AE@%%@NL@%
  8423.           mov          ax,10                        %@AB@%; Search for linefeed%@AE@%%@NL@%
  8424. %@NL@%
  8425.           or          cx,cx                        %@AB@%; Argument 0?%@AE@%%@NL@%
  8426.           jg          forward                %@AB@%; If above, forward%@AE@%%@NL@%
  8427.           jl          backward                %@AB@%; If below, backward%@AE@%%@NL@%
  8428.           jmp          SHORT        show                %@AB@%; If equal, done%@AE@%%@NL@%
  8429. %@NL@%
  8430. backward: call          GoBack                %@AB@%; Adjust backward%@AE@%%@NL@%
  8431.           jmp          SHORT        show                %@AB@%; Show screen%@AE@%%@NL@%
  8432. forward:  call          GoForwd                %@AB@%; Adjust forward%@AE@%%@NL@%
  8433. %@NL@%
  8434. %@AB@%; Write        line number to status line%@AE@%%@NL@%
  8435. %@NL@%
  8436. show:          cld                                %@AB@%; Go forward%@AE@%%@NL@%
  8437.           push          di%@NL@%
  8438.           push          es%@NL@%
  8439.           push          ds                        %@AB@%; Load DS to ES%@AE@%%@NL@%
  8440.           pop          es%@NL@%
  8441. %@NL@%
  8442. %@AB@%; BinToStr (linenum,OFFSET statline[7])%@AE@%%@NL@%
  8443. %@NL@%
  8444.           push          linenum                %@AB@%; Arg 1%@AE@%%@NL@%
  8445.           mov          ax,OFFSET statline[7]%@NL@%
  8446.           push          ax                        %@AB@%; Arg 2%@AE@%%@NL@%
  8447.           call          BinToStr                %@AB@%; Convert to string%@AE@%%@NL@%
  8448. %@NL@%
  8449. %@AB@%; Fill in status line%@AE@%%@NL@%
  8450. %@NL@%
  8451.           mov          cx,7                        %@AB@%; Seven        spaces to fill%@AE@%%@NL@%
  8452.           sub          cx,ax                        %@AB@%; Subtract those already done%@AE@%%@NL@%
  8453.           mov          al," "                %@AB@%; Fill with space%@AE@%%@NL@%
  8454.           rep          stosb%@NL@%
  8455.           pop          es%@NL@%
  8456. %@NL@%
  8457.           mov          bl,statatr                %@AB@%; Load status attribute%@AE@%%@NL@%
  8458.           mov          BYTE PTR cell[1],bl%@NL@%
  8459. %@NL@%
  8460. %@AB@%; CellWrt (DS,OFFSET statline,0,cell)%@AE@%%@NL@%
  8461. %@NL@%
  8462.           push          ds                        %@AB@%; Arg 1%@AE@%%@NL@%
  8463.           mov          ax,OFFSET statline        %@AB@%; Arg 2%@AE@%%@NL@%
  8464.           push          ax%@NL@%
  8465.           sub          ax,ax                        %@AB@%; Arg 3%@AE@%%@NL@%
  8466.           push          ax%@NL@%
  8467.           push          cell                        %@AB@%; Arg 4%@AE@%%@NL@%
  8468.           call          CellWrt                %@AB@%; Write        status line%@AE@%%@NL@%
  8469. %@NL@%
  8470.           pop          di%@NL@%
  8471.           mov          bl,scrnatr                %@AB@%; Load screen attribute%@AE@%%@NL@%
  8472.           mov          BYTE PTR cell[1],bl%@NL@%
  8473.           mov          si,di                        %@AB@%; Update position%@AE@%%@NL@%
  8474.           mov          cx,rows                %@AB@%; Lines        per screen%@AE@%%@NL@%
  8475. %@NL@%
  8476. show1:          mov          bx,rows                %@AB@%; Lines        of text%@AE@%%@NL@%
  8477.           inc          bx                        %@AB@%; Adjust for 0%@AE@%%@NL@%
  8478.           sub          bx,cx                        %@AB@%; Calculate current row%@AE@%%@NL@%
  8479.           push          cx                        %@AB@%; Save line number%@AE@%%@NL@%
  8480. %@NL@%
  8481. %@AB@%; CellWrt (sbuffer,position,line,cell)%@AE@%%@NL@%
  8482. %@NL@%
  8483.           push          sbuffer                %@AB@%; Arg 1%@AE@%%@NL@%
  8484.           push          si                        %@AB@%; Arg 2%@AE@%%@NL@%
  8485.           push          bx                        %@AB@%; Arg 3%@AE@%%@NL@%
  8486.           push          cell                        %@AB@%; Arg 4%@AE@%%@NL@%
  8487.           call          cellwrt                %@AB@%; Write        line%@AE@%%@NL@%
  8488. %@NL@%
  8489.           push          ss                        %@AB@%; Restore DS from SS%@AE@%%@NL@%
  8490.           pop          ds%@NL@%
  8491. %@NL@%
  8492.           pop          cx                        %@AB@%; Restore line number%@AE@%%@NL@%
  8493.           mov          si,ax                        %@AB@%; Get returned position%@AE@%%@NL@%
  8494. %@NL@%
  8495.           cmp          ax,fsize                %@AB@%; Beyond end of        file?%@AE@%%@NL@%
  8496.           jae          fillout                %@AB@%; Yes? Fill screen with        spaces%@AE@%%@NL@%
  8497.           loop          show1                        %@AB@%;    else next line%@AE@%%@NL@%
  8498.           jmp          SHORT        pagedone        %@AB@%; Get out if done%@AE@%%@NL@%
  8499. %@NL@%
  8500. %@AB@%; Fill the rest        with spaces%@AE@%%@NL@%
  8501. %@NL@%
  8502. fillout:  dec          cx                        %@AB@%; Adjust%@AE@%%@NL@%
  8503.           jcxz          pagedone%@NL@%
  8504.           mov          al,80                        %@AB@%; Columns times        remaining lines%@AE@%%@NL@%
  8505.           mul          cl%@NL@%
  8506. %@NL@%
  8507. %@AB@%; CellFil (sbuffer,count,cell)%@AE@%%@NL@%
  8508. %@NL@%
  8509.           push          sbuffer                %@AB@%; Arg 1%@AE@%%@NL@%
  8510.           push          ax                        %@AB@%; Arg 2%@AE@%%@NL@%
  8511.           push          cell                        %@AB@%; Arg 3%@AE@%%@NL@%
  8512.           call          CellFil                %@AB@%; Fill screen with spaces%@AE@%%@NL@%
  8513. %@NL@%
  8514.           push          ss                        %@AB@%; Restore DS from SS%@AE@%%@NL@%
  8515.           pop          ds%@NL@%
  8516. %@NL@%
  8517. pagedone: pop          bp%@NL@%
  8518.           ret          2%@NL@%
  8519. Pager          ENDP%@NL@%
  8520. %@NL@%
  8521. %@AB@%; Procedure CellWrt (segment,offset,line,cell)%@AE@%%@NL@%
  8522. %@AB@%; Purpose   Writes a line to screen buffer%@AE@%%@NL@%
  8523. %@AB@%; Input            Stack variables: 1 - segment of line%@AE@%%@NL@%
  8524. %@AB@%;                             2 - offset%@AE@%%@NL@%
  8525. %@AB@%;                             3 - line number%@AE@%%@NL@%
  8526. %@AB@%;                             4 - attribute%@AE@%%@NL@%
  8527. %@AB@%; Output    Line to screen buffer%@AE@%%@NL@%
  8528. %@NL@%
  8529. CellWrt          PROC%@NL@%
  8530.           push          bp%@NL@%
  8531.           mov          bp,sp%@NL@%
  8532.           sub          dx,dx                        %@AB@%; Clear        as flag        for scan%@AE@%%@NL@%
  8533.           cmp          cga,1                        %@AB@%; CGA?%@AE@%%@NL@%
  8534.           jne          noscan%@NL@%
  8535.           mov          dx,03DAh                %@AB@%; Load port #%@AE@%%@NL@%
  8536. %@NL@%
  8537. noscan:          mov          es,vidadr                %@AB@%; Load screen buffer segment%@AE@%%@NL@%
  8538.           mov          ds,[bp+10]                %@AB@%; Buffer segment%@AE@%%@NL@%
  8539.           mov          si,[bp+8]                %@AB@%; Buffer position%@AE@%%@NL@%
  8540.           mov          cx,80                        %@AB@%; Cells        per row%@AE@%%@NL@%
  8541.           mov          ax,[bp+6]                %@AB@%; Starting row%@AE@%%@NL@%
  8542.           mov          bx,80*2                %@AB@%; Bytes        per row%@AE@%%@NL@%
  8543.           mul          bl                        %@AB@%; Figure columns per row%@AE@%%@NL@%
  8544.           mov          di,ax                        %@AB@%; Load as destination%@AE@%%@NL@%
  8545.           mov          bx,di                        %@AB@%; Save start for tab calculation%@AE@%%@NL@%
  8546.           mov          ax,[bp+4]                %@AB@%; Attribute%@AE@%%@NL@%
  8547. movechar: lodsb                                %@AB@%; Get character%@AE@%%@NL@%
  8548.           cmp          al,13                        %@AB@%; CR?%@AE@%%@NL@%
  8549.           je          fillspc%@NL@%
  8550.           cmp          al,9                        %@AB@%; Tab?%@AE@%%@NL@%
  8551.           jne          notab%@NL@%
  8552.           call          filltab                %@AB@%; Yes? fill with spaces%@AE@%%@NL@%
  8553.           jcxz          nextline                %@AB@%; If beyond limit done%@AE@%%@NL@%
  8554.           jmp          SHORT        movechar%@NL@%
  8555. %@NL@%
  8556. notab:          or          dx,dx                        %@AB@%; CGA?%@AE@%%@NL@%
  8557.           je          notab2%@NL@%
  8558.           call          Retrace                %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
  8559.           loop          movechar%@NL@%
  8560.           jmp          SHORT        nextline%@NL@%
  8561. %@NL@%
  8562. notab2:          stosw                                %@AB@%; Write%@AE@%%@NL@%
  8563.           loop          movechar%@NL@%
  8564.           jmp          SHORT        nextline        %@AB@%; Done%@AE@%%@NL@%
  8565. %@NL@%
  8566. fillspc:  mov          al," "                %@AB@%; Fill with space%@AE@%%@NL@%
  8567. %@NL@%
  8568.           or          dx,dx                        %@AB@%; CGA?%@AE@%%@NL@%
  8569.           je          space2%@NL@%
  8570. space1:          call          Retrace                %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
  8571.           loop          space1%@NL@%
  8572.           inc          si                        %@AB@%; Adjust%@AE@%%@NL@%
  8573.           jmp          SHORT        exit                %@AB@%; Done%@AE@%%@NL@%
  8574. %@NL@%
  8575. space2:          rep          stosw                        %@AB@%; Write%@AE@%%@NL@%
  8576.           inc          si                        %@AB@%; Adjust for LF%@AE@%%@NL@%
  8577.           jmp          SHORT        exit                %@AB@%; Done%@AE@%%@NL@%
  8578. %@NL@%
  8579. nextline: mov          ah,10                        %@AB@%; Search for next line feed%@AE@%%@NL@%
  8580. chklf:          lodsb                                %@AB@%; Load and compare%@AE@%%@NL@%
  8581.           cmp          al,ah%@NL@%
  8582.           loopne  chklf%@NL@%
  8583. %@NL@%
  8584. exit:          mov          ax,si                        %@AB@%; Return position%@AE@%%@NL@%
  8585.           pop          bp%@NL@%
  8586.           ret          8%@NL@%
  8587. CellWrt          ENDP%@NL@%
  8588. %@NL@%
  8589. %@AB@%; Procedure CellFil (segment,count,cell)%@AE@%%@NL@%
  8590. %@AB@%; Purpose   Fills screen with character%@AE@%%@NL@%
  8591. %@AB@%; Input            Stack variables: 1 - segment of text (offset 0)%@AE@%%@NL@%
  8592. %@AB@%;                             2 - number        of characters%@AE@%%@NL@%
  8593. %@AB@%;                             3 - attribute and character%@AE@%%@NL@%
  8594. %@AB@%; Output    Characters to screen buffer%@AE@%%@NL@%
  8595. %@NL@%
  8596. CellFil          PROC%@NL@%
  8597.           push          bp%@NL@%
  8598.           mov          bp,sp%@NL@%
  8599.           sub          dx,dx                        %@AB@%; Clear        as flag        for scan%@AE@%%@NL@%
  8600.           cmp          cga,1                        %@AB@%; CGA?%@AE@%%@NL@%
  8601.           jne          noscan2%@NL@%
  8602.           mov          dx,03DAh                %@AB@%; Load port #%@AE@%%@NL@%
  8603. %@NL@%
  8604. noscan2:  mov          es,vidadr                %@AB@%; Load screen buffer segment%@AE@%%@NL@%
  8605.           mov          ds,[bp+8]                %@AB@%; Buffer segment (position 0)%@AE@%%@NL@%
  8606.           mov          cx,[bp+6]                %@AB@%; Characters to        fill%@AE@%%@NL@%
  8607.           mov          ax,[bp+4]                %@AB@%; Attribute%@AE@%%@NL@%
  8608.           or          dx,dx                        %@AB@%; CGA?%@AE@%%@NL@%
  8609.           je          fillem2%@NL@%
  8610. fillem1:  call          Retrace                %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
  8611.           loop          fillem1%@NL@%
  8612.           jmp          SHORT        filled                %@AB@%; Done%@AE@%%@NL@%
  8613. fillem2:  rep          stosw                        %@AB@%; Write%@AE@%%@NL@%
  8614. %@NL@%
  8615. filled:          pop          bp%@NL@%
  8616.           ret          6%@NL@%
  8617. CellFil          ENDP%@NL@%
  8618. %@NL@%
  8619. %@AB@%; Procedure FillTab%@AE@%%@NL@%
  8620. %@AB@%; Purpose   Writes spaces for tab to screen%@AE@%%@NL@%
  8621. %@AB@%; Input            BX points to start of line,        DI points to current position%@AE@%%@NL@%
  8622. %@AB@%; Output    Spaces to screen buffer%@AE@%%@NL@%
  8623. %@NL@%
  8624. FillTab          PROC%@NL@%
  8625.           push          bx%@NL@%
  8626.           push          cx%@NL@%
  8627. %@NL@%
  8628.           sub          bx,di                        %@AB@%; Get current position in line%@AE@%%@NL@%
  8629.           neg          bx%@NL@%
  8630.           shr          bx,1                        %@AB@%; Divide by 2 bytes per        character%@AE@%%@NL@%
  8631. %@NL@%
  8632.           mov          cx,8                        %@AB@%; Default count        8%@AE@%%@NL@%
  8633.           and          bx,7                        %@AB@%; Get modulus%@AE@%%@NL@%
  8634.           sub          cx,bx                        %@AB@%; Subtract%@AE@%%@NL@%
  8635.           mov          bx,cx                        %@AB@%; Save modulus%@AE@%%@NL@%
  8636. %@NL@%
  8637.           mov          al," "                %@AB@%; Spaces%@AE@%%@NL@%
  8638.           or          dx,dx                        %@AB@%; CGA?%@AE@%%@NL@%
  8639.           je          tabem2%@NL@%
  8640. %@NL@%
  8641. tabem1:          call          Retrace                %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
  8642.           loop          tabem1%@NL@%
  8643.           jmp          SHORT        tabbed%@NL@%
  8644. tabem2:          rep          stosw                        %@AB@%; Write%@AE@%%@NL@%
  8645. %@NL@%
  8646. tabbed:          pop          cx%@NL@%
  8647.           sub          cx,bx                        %@AB@%; Adjust count%@AE@%%@NL@%
  8648.           jns          nomore                %@AB@%; Make negative        count 0%@AE@%%@NL@%
  8649.           sub          cx,cx%@NL@%
  8650. nomore:          pop          bx%@NL@%
  8651.           ret%@NL@%
  8652. FillTab          ENDP%@NL@%
  8653. %@NL@%
  8654. %@AB@%; Procedure GoBack%@AE@%%@NL@%
  8655. %@AB@%; Purpose   Searches backward through buffer%@AE@%%@NL@%
  8656. %@AB@%; Input            CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
  8657. %@AB@%; Output    Updates "linenum" and "pbuffer"%@AE@%%@NL@%
  8658. %@NL@%
  8659. GoBack          PROC%@NL@%
  8660.           std                                %@AB@%; Go backward%@AE@%%@NL@%
  8661.           neg          cx                        %@AB@%; Make count positive%@AE@%%@NL@%
  8662.           mov          dx,cx                        %@AB@%; Save a copy%@AE@%%@NL@%
  8663.           inc          cx                        %@AB@%; One extra to go up one%@AE@%%@NL@%
  8664.           or          di,di                        %@AB@%; Start        of file?%@AE@%%@NL@%
  8665.           je          exback                %@AB@%; If so, ignore%@AE@%%@NL@%
  8666. findb:          push          cx                        %@AB@%;   else save count%@AE@%%@NL@%
  8667.           mov          cx,0FFh                %@AB@%; Load maximum character count%@AE@%%@NL@%
  8668.           cmp          cx,di                        %@AB@%; Near start of        buffer?%@AE@%%@NL@%
  8669.           jl          notnear                %@AB@%; No? Continue%@AE@%%@NL@%
  8670.           mov          cx,di                        %@AB@%;   else search        only to        start%@AE@%%@NL@%
  8671. notnear:  repne          scasb                        %@AB@%; Find last previous LF%@AE@%%@NL@%
  8672.           jcxz          atstart                %@AB@%; If not found,        must be        at start%@AE@%%@NL@%
  8673.           pop          cx%@NL@%
  8674.           loop          findb%@NL@%
  8675.           cmp          linenum,0FFFFh        %@AB@%; End of file flag?%@AE@%%@NL@%
  8676.           jne          notend                %@AB@%; No? Continue%@AE@%%@NL@%
  8677.           add          di,2                        %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
  8678.           mov          pbuffer,di                %@AB@%; Save position%@AE@%%@NL@%
  8679.           call          EndCount                %@AB@%; Count        back to        get line number%@AE@%%@NL@%
  8680.           ret%@NL@%
  8681. %@NL@%
  8682. notend:          sub          linenum,dx                %@AB@%; Calculate line number%@AE@%%@NL@%
  8683.           jg          positive%@NL@%
  8684.           mov          linenum,1                %@AB@%; Set to 1 if negative%@AE@%%@NL@%
  8685. positive: add          di,2                        %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
  8686.           mov          pbuffer,di                %@AB@%; Save position%@AE@%%@NL@%
  8687.           ret%@NL@%
  8688. %@NL@%
  8689. atstart:  pop          cx%@NL@%
  8690.           sub          di,di                        %@AB@%; Load start of        file%@AE@%%@NL@%
  8691.           mov          linenum,1                %@AB@%; Line 1%@AE@%%@NL@%
  8692.           mov          pbuffer,di                %@AB@%; Save position%@AE@%%@NL@%
  8693. exback:          ret%@NL@%
  8694. GoBack          ENDP%@NL@%
  8695. %@NL@%
  8696. %@AB@%; Procedure GoForwd%@AE@%%@NL@%
  8697. %@AB@%; Purpose   Searches forward through a buffer%@AE@%%@NL@%
  8698. %@AB@%; Input            CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
  8699. %@AB@%; Output    Updates "linenum" and "pbuffer"%@AE@%%@NL@%
  8700. %@NL@%
  8701. GoForwd          PROC%@NL@%
  8702.           cld                                %@AB@%; Go forward%@AE@%%@NL@%
  8703.           mov          dx,cx                        %@AB@%; Copy count%@AE@%%@NL@%
  8704. findf:          push          cx                        %@AB@%; Save count%@AE@%%@NL@%
  8705.           mov          cx,0FFh                %@AB@%; Load maximum character count%@AE@%%@NL@%
  8706.           repne          scasb                        %@AB@%; Find next LF%@AE@%%@NL@%
  8707.           jcxz          atend                        %@AB@%; If not found,        must be        at end%@AE@%%@NL@%
  8708.           cmp          di,fsize                %@AB@%; Beyond end?%@AE@%%@NL@%
  8709.           jae          atend%@NL@%
  8710.           pop          cx%@NL@%
  8711.           loop          findf%@NL@%
  8712.           add          linenum,dx                %@AB@%; Calulate line        number%@AE@%%@NL@%
  8713.           mov          pbuffer,di                %@AB@%; Save position%@AE@%%@NL@%
  8714.           ret%@NL@%
  8715. %@NL@%
  8716. atend:          pop          cx%@NL@%
  8717.           mov          di,pbuffer                %@AB@%; Restore position%@AE@%%@NL@%
  8718.           ret%@NL@%
  8719. GoForwd          ENDP%@NL@%
  8720. %@NL@%
  8721. %@AB@%; Procedure EndCount%@AE@%%@NL@%
  8722. %@AB@%; Purpose   Counts backward to count lines in file%@AE@%%@NL@%
  8723. %@AB@%; Input            ES:DI has buffer position%@AE@%%@NL@%
  8724. %@AB@%; Output    Modifies "linenum"%@AE@%%@NL@%
  8725. %@NL@%
  8726. EndCount  PROC%@NL@%
  8727.           push          di%@NL@%
  8728. %@NL@%
  8729.           mov          al,13                        %@AB@%; Search for CR%@AE@%%@NL@%
  8730.           mov          linenum,0                %@AB@%; Initialize%@AE@%%@NL@%
  8731. %@NL@%
  8732. findstrt: inc          linenum                %@AB@%; Adjust count%@AE@%%@NL@%
  8733.           mov          cx,0FFh                %@AB@%; Load maximum character count%@AE@%%@NL@%
  8734.           cmp          cx,di                        %@AB@%; Near start of        buffer?%@AE@%%@NL@%
  8735.           jl          notnear2                %@AB@%; No? Continue%@AE@%%@NL@%
  8736.           mov          cx,di                        %@AB@%;   else search        only to        start%@AE@%%@NL@%
  8737. notnear2: repne          scasb                        %@AB@%; Find last previous cr%@AE@%%@NL@%
  8738.           jcxz          found                        %@AB@%; If not found,        must be        at start%@AE@%%@NL@%
  8739.           jmp          SHORT        findstrt%@NL@%
  8740. %@NL@%
  8741. found:          pop          di%@NL@%
  8742.           ret%@NL@%
  8743. EndCount  ENDP%@NL@%
  8744. %@NL@%
  8745. %@AB@%; Procedure isEGA%@AE@%%@NL@%
  8746. %@AB@%; Purpose   Determines if an EGA is active%@AE@%%@NL@%
  8747. %@AB@%; Input            None%@AE@%%@NL@%
  8748. %@AB@%; Output    0 if no; lines per screen if yes%@AE@%%@NL@%
  8749. %@NL@%
  8750. isEGA          PROC%@NL@%
  8751.           push          bp%@NL@%
  8752.           push          es%@NL@%
  8753.           mov          ah,12h                %@AB@%; Call EGA status function%@AE@%%@NL@%
  8754.           mov          bl,10h%@NL@%
  8755.           sub          cx,cx                        %@AB@%; Clear        status bits%@AE@%%@NL@%
  8756.           int          10h%@NL@%
  8757.           sub          ax,ax                        %@AB@%; Segment 0 and        assume no EGA%@AE@%%@NL@%
  8758.           jcxz          noega                        %@AB@%; If status still clear, no EGA%@AE@%%@NL@%
  8759. %@NL@%
  8760.           mov          es,ax                        %@AB@%; ES=0%@AE@%%@NL@%
  8761.           test          BYTE PTR es:[487h],1000b %@AB@%; Test active bit%@AE@%%@NL@%
  8762.           jnz          noega                        %@AB@%; If set, not active%@AE@%%@NL@%
  8763.           mov          ax,1130h                %@AB@%; Get EGA information%@AE@%%@NL@%
  8764.           int          10h%@NL@%
  8765.           mov          al,dl                        %@AB@%; Return lines per screen%@AE@%%@NL@%
  8766.           cbw%@NL@%
  8767. %@NL@%
  8768. noega:          pop          es%@NL@%
  8769.           pop          bp%@NL@%
  8770.           ret%@NL@%
  8771. isEGA          ENDP%@NL@%
  8772. %@NL@%
  8773. %@AB@%; Procedure BinToStr (number,address)%@AE@%%@NL@%
  8774. %@AB@%; Purpose   Converts integer to        string%@AE@%%@NL@%
  8775. %@AB@%; Input            Stack arguments: 1 - Number        to convert; 2 -        Near address for write%@AE@%%@NL@%
  8776. %@AB@%; Output    AX has characters written%@AE@%%@NL@%
  8777. %@NL@%
  8778. BinToStr  PROC%@NL@%
  8779.           push          bp%@NL@%
  8780.           mov          bp,sp%@NL@%
  8781.           mov          ax,[bp+6]                %@AB@%; Arg 1%@AE@%%@NL@%
  8782.           mov          di,[bp+4]                %@AB@%; Arg 2%@AE@%%@NL@%
  8783. %@NL@%
  8784.           sub          cx,cx                        %@AB@%; Clear        counter%@AE@%%@NL@%
  8785.           mov          bx,10                        %@AB@%; Divide by 10%@AE@%%@NL@%
  8786. %@NL@%
  8787. %@AB@%; Convert and save on stack backwards%@AE@%%@NL@%
  8788. %@NL@%
  8789. getdigit: sub          dx,dx                        %@AB@%; Clear        top%@AE@%%@NL@%
  8790.           div          bx                        %@AB@%; Divide to get        last digit as remainder%@AE@%%@NL@%
  8791.           add          dl,"0"                %@AB@%; Convert to ASCII%@AE@%%@NL@%
  8792.           push          dx                        %@AB@%; Save on stack%@AE@%%@NL@%
  8793.           or          ax,ax                        %@AB@%; Quotient 0?%@AE@%%@NL@%
  8794.           loopnz  getdigit                %@AB@%; No? Get another%@AE@%%@NL@%
  8795. %@NL@%
  8796. %@AB@%; Take off the stack and store forward%@AE@%%@NL@%
  8797. %@NL@%
  8798.           neg          cx                        %@AB@%; Negate and save count%@AE@%%@NL@%
  8799.           mov          dx,cx%@NL@%
  8800. putdigit: pop          ax                        %@AB@%; Get character%@AE@%%@NL@%
  8801.           stosb                                %@AB@%; Store        it%@AE@%%@NL@%
  8802.           loop          putdigit%@NL@%
  8803.           mov          ax,dx                        %@AB@%; Return digit count%@AE@%%@NL@%
  8804. %@NL@%
  8805.           pop          bp%@NL@%
  8806.           ret          4%@NL@%
  8807. BinToStr  ENDP%@NL@%
  8808. %@NL@%
  8809. %@AB@%; Procedure Retrace%@AE@%%@NL@%
  8810. %@AB@%; Purpose   Writes cell        during horizontal retrace (CGA)%@AE@%%@NL@%
  8811. %@AB@%; Input            ES:DI has screen buffer position, AX has cell%@AE@%%@NL@%
  8812. %@AB@%; Output    Character to screen        buffer%@AE@%%@NL@%
  8813. %@NL@%
  8814. Retrace          PROC%@NL@%
  8815.           push          bx%@NL@%
  8816.           mov          bx,ax                        %@AB@%; Save character%@AE@%%@NL@%
  8817. lscan2:          in          al,dx                        %@AB@%; Look in the port%@AE@%%@NL@%
  8818.           shr          al,1                        %@AB@%;   until it goes low%@AE@%%@NL@%
  8819.           jc          lscan2%@NL@%
  8820.           cli%@NL@%
  8821. hscan2:          in          al,dx                        %@AB@%; Look in the port%@AE@%%@NL@%
  8822.           shr          al,1                        %@AB@%;   until it goes high%@AE@%%@NL@%
  8823.           jnc          hscan2%@NL@%
  8824.           mov          ax,bx                        %@AB@%; Restore and write it%@AE@%%@NL@%
  8825.           stosw%@NL@%
  8826.           sti%@NL@%
  8827.           pop          bx%@NL@%
  8828.           ret%@NL@%
  8829. Retrace          ENDP%@NL@%
  8830. %@NL@%
  8831.           END%@NL@%
  8832. %@NL@%
  8833. %@NL@%
  8834. %@2@%%@AH@%POWER2.ASM%@AE@%%@EH@%%@NL@%
  8835. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\MIXED\POWER2.ASM%@AE@%%@NL@%
  8836. %@NL@%
  8837. %@AB@%; Default command line for BASIC:    MASM /Dmodel=medium /Dlang=BASIC power2;%@AE@%%@NL@%
  8838. %@AB@%; Default command line for C:        MASM /MX /Dmodel=small /Dlang=C power2;%@AE@%%@NL@%
  8839. %@AB@%; Default command line for FORTRAN:  MASM /Dmodel=large /Dlang=FORTRAN power2;%@AE@%%@NL@%
  8840. %@AB@%; Default command line for Pascal:   MASM /Dmodel=large /Dlang=Pascal power2;%@AE@%%@NL@%
  8841. %@NL@%
  8842. %         .MODEL  model,lang%@NL@%
  8843.           INCLUDE mixed.inc%@NL@%
  8844. %@NL@%
  8845. %         IFIDNI  <lang>,<BASIC>%@NL@%
  8846. reference EQU     1%@NL@%
  8847. %         ELSEIFIDNI <lang>,<FORTRAN>%@NL@%
  8848. reference EQU     1%@NL@%
  8849.           ENDIF%@NL@%
  8850. %@NL@%
  8851.           .CODE%@NL@%
  8852. %@NL@%
  8853. %@AB@%; Function for C, FORTRAN, Pascal, Version 4 of QuickBASIC, and%@AE@%%@NL@%
  8854. %@AB@%;   future versions of Microsoft and IBM BASIC Compilers%@AE@%%@NL@%
  8855. %@NL@%
  8856.           IFDEF   reference          %@AB@%; Pass by reference for BASIC or FORTRAN%@AE@%%@NL@%
  8857. Power2    PROC    Value:PTR WORD, Count:PTR WORD%@NL@%
  8858. %@NL@%
  8859.           pLes    bx,Value           %@AB@%; Load arguments passed by reference%@AE@%%@NL@%
  8860.           mov     ax,FP[bx]%@NL@%
  8861.           pLes    bx,Count%@NL@%
  8862.           mov     cx,FP[bx]%@NL@%
  8863. %@NL@%
  8864.           ELSE                       %@AB@%; Pass by value for C or Pascal%@AE@%%@NL@%
  8865. Power2    PROC    Value, Count%@NL@%
  8866. %@NL@%
  8867.           mov     ax,Value           %@AB@%; Load arguments passed by value%@AE@%%@NL@%
  8868.           mov     cx,Count%@NL@%
  8869.           ENDIF%@NL@%
  8870. %@NL@%
  8871.           shl     ax,cl              %@AB@%; AX = AX * (2 to power of CL)%@AE@%%@NL@%
  8872.                                      %@AB@%; Return result in AX%@AE@%%@NL@%
  8873.           ret%@NL@%
  8874. Power2    ENDP%@NL@%
  8875. %@NL@%
  8876.           IFIDNI  <lang>,<BASIC>%@NL@%
  8877. %@NL@%
  8878. %@AB@%; Subprogram for QuickBASIC, Versions 1, 2, and 3;%@AE@%%@NL@%
  8879. %@AB@%;     for the Microsoft BASIC Compiler through Version 5.36%@AE@%%@NL@%
  8880. %@AB@%;     for the IBM BASIC Compiler through Version 2.02%@AE@%%@NL@%
  8881. %@NL@%
  8882. Power2S   PROC    Value:PTR WORD, Count:PTR WORD, RetVal:PTR WORD%@NL@%
  8883. %@NL@%
  8884.           pLes    bx,Value           %@AB@%; Load BASIC arguments%@AE@%%@NL@%
  8885.           mov     ax,FP[bx]          %@AB@%;   passed by reference%@AE@%%@NL@%
  8886.           pLes    bx,Count%@NL@%
  8887.           mov     cx,FP[bx]%@NL@%
  8888. %@NL@%
  8889.           shl     ax,cl              %@AB@%; AX = AX * (2 to power of CL)%@AE@%%@NL@%
  8890. %@NL@%
  8891.           pLes    bx,RetVal          %@AB@%; Load return address%@AE@%%@NL@%
  8892.           mov     FP[bx],ax          %@AB@%;   and store result in it%@AE@%%@NL@%
  8893. %@NL@%
  8894.           ret%@NL@%
  8895. Power2S   ENDP%@NL@%
  8896.           ENDIF   %@AB@%; BASIC%@AE@%%@NL@%
  8897.           END%@NL@%
  8898. %@NL@%
  8899. %@NL@%
  8900. %@NL@%
  8901. %@2@%%@AH@%SHOWP.ASM%@AE@%%@EH@%%@NL@%
  8902. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\SHOWP.ASM%@AE@%%@NL@%
  8903. %@NL@%
  8904.           TITLE   Show%@NL@%
  8905. %@NL@%
  8906. %@AB@%; Program SHOW.ASM%@AE@%%@NL@%
  8907. %@AB@%; Purpose Text file displayer%@AE@%%@NL@%
  8908. %@AB@%; Input   File name from command line or prompt%@AE@%%@NL@%
  8909. %@AB@%; Output  Display file to screen%@AE@%%@NL@%
  8910. %@NL@%
  8911.           DOSSEG%@NL@%
  8912.           .MODEL  small, pascal%@NL@%
  8913. %@NL@%
  8914. INCL_DOSFILEMGR   EQU 1         %@AB@%; Enable call groups%@AE@%%@NL@%
  8915. INCL_DOSMEMMGR    EQU 1%@NL@%
  8916. INCL_KBD          EQU 1%@NL@%
  8917. INCL_VIO          EQU 1%@NL@%
  8918. %@NL@%
  8919.           INCLUDE os2.inc%@NL@%
  8920.           INCLUDELIB doscalls.lib%@NL@%
  8921. %@NL@%
  8922.           .STACK  800h%@NL@%
  8923. %@NL@%
  8924.           .DATA%@NL@%
  8925. %@NL@%
  8926. %@AB@%; Status line%@AE@%%@NL@%
  8927. %@NL@%
  8928.           PUBLIC  stLine, nLines, curLine%@NL@%
  8929. curLine   DW      1             %@AB@%; Current line number%@AE@%%@NL@%
  8930. nLines    DW      ?             %@AB@%; Lines per screen%@AE@%%@NL@%
  8931. stLine    DB      "Line: 12345 "%@NL@%
  8932. stFile    DB      "File: 12345678.123  "%@NL@%
  8933.           DB      "Quit: Q  Next: ESC  Move:   PGUP PGDN HOME END"%@NL@%
  8934. %@NL@%
  8935. %@AB@%; Variables for screen and cursor handling%@AE@%%@NL@%
  8936. %@NL@%
  8937.           PUBLIC  vMode, Cell, stAtrib, scAtrib%@NL@%
  8938. vMode     VIOMODEINFO <>        %@AB@%; Structures for video and cursor data%@AE@%%@NL@%
  8939. lvMode    EQU     $ - vMode     %@AB@%; Length of structure%@AE@%%@NL@%
  8940. vType     DW      0             %@AB@%; Video type - 0 flag for no change%@AE@%%@NL@%
  8941. %@NL@%
  8942. cMode     VIOCURSORINFO <>%@NL@%
  8943. cAtrib    DW      -1            %@AB@%; Cursor attribute (initized to hidden)%@AE@%%@NL@%
  8944. cStatus   DB      0             %@AB@%; 0 = cursor visible, position unchanged%@AE@%%@NL@%
  8945.                                 %@AB@%; 1 = cursor invisible, position unchanged%@AE@%%@NL@%
  8946.                                 %@AB@%; 2 = cursor invisible, position changed%@AE@%%@NL@%
  8947. %@NL@%
  8948. stAtrib   DB      030h          %@AB@%; Status line color default - black on cyan%@AE@%%@NL@%
  8949. stBW      EQU     070h          %@AB@%; B&W default - black on white%@AE@%%@NL@%
  8950. Cell      LABEL   WORD          %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
  8951. scChar    DB      " "           %@AB@%; Initialize to space%@AE@%%@NL@%
  8952. scAtrib   DB      017h          %@AB@%; Screen color default - white on blue%@AE@%%@NL@%
  8953. scBW      EQU     007h          %@AB@%; B&W default - white on black%@AE@%%@NL@%
  8954. %@NL@%
  8955. %@AB@%; Variables for buffer and file handling%@AE@%%@NL@%
  8956. %@NL@%
  8957.           PUBLIC  Buffer, oBuffer, sBuffer, lBuffer%@NL@%
  8958. Buffer    LABEL   DWORD%@NL@%
  8959. oBuffer   DW      0             %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
  8960. sBuffer   DW      ?             %@AB@%; Base of buffer (segment)%@AE@%%@NL@%
  8961. lBuffer   DW      ?             %@AB@%; Length of buffer%@AE@%%@NL@%
  8962. %@NL@%
  8963. %@AB@%; File information%@AE@%%@NL@%
  8964. %@NL@%
  8965. lfName    EQU     66%@NL@%
  8966. fName     DB      lfName DUP (" ")%@NL@%
  8967. fHandle   DW      ?             %@AB@%; Holds file handle on open%@AE@%%@NL@%
  8968. fAction   DW      ?             %@AB@%; Result of open%@AE@%%@NL@%
  8969. fAtrib    EQU     0             %@AB@%; Normal file%@AE@%%@NL@%
  8970. fFlag     EQU     1             %@AB@%; Open file if exist, fail if not exist%@AE@%%@NL@%
  8971. %@AB@%; Read only, deny none, private, error codes, use cache, normal file%@AE@%%@NL@%
  8972. fModeRec  RECORD  DA:1=0,WT:1=0,FE:1=0,R1:5=0,INF:1=1,SM:3=2,R2:1=0,AM:3=0%@NL@%
  8973. fMode     fModeRec <>%@NL@%
  8974. fRead     DW      ?             %@AB@%; Bytes read from file%@AE@%%@NL@%
  8975. %@NL@%
  8976. %@AB@%; Directory information for file name search%@AE@%%@NL@%
  8977. %@NL@%
  8978. dHandle   DW      -1            %@AB@%; Directory handle%@AE@%%@NL@%
  8979. dResult   FILEFINDBUF <>        %@AB@%; Structure for results%@AE@%%@NL@%
  8980. dlResult  EQU     $ - dResult   %@AB@%;   length of result%@AE@%%@NL@%
  8981. dCount    DW      1             %@AB@%; Find one file at a time%@AE@%%@NL@%
  8982. %@NL@%
  8983. Prompt    DB      13,10,"Enter filename: "%@NL@%
  8984. lPrompt   EQU     $ - Prompt%@NL@%
  8985. Prompt2   DB      13,10,"No such file. Try again? "%@NL@%
  8986. lPrompt2  EQU     $ - Prompt2%@NL@%
  8987. Prompt3   DB      13,10,"File too large: "%@NL@%
  8988. lPrompt3  EQU     $ - Prompt3%@NL@%
  8989. Prompt4   DB      13,10,"Memory problem.",13,10%@NL@%
  8990. lPrompt4  EQU     $ - Prompt4%@NL@%
  8991. %@NL@%
  8992. %@AB@%; Keyboard data%@AE@%%@NL@%
  8993. %@NL@%
  8994. kChar     KBDKEYINFO <>         %@AB@%; Structures for character and string input%@AE@%%@NL@%
  8995. kStr      STRINGINBUF <>%@NL@%
  8996. kWait     EQU     0             %@AB@%; Wait flag%@AE@%%@NL@%
  8997. %@NL@%
  8998. %@AB@%; Call table%@AE@%%@NL@%
  8999. %@NL@%
  9000. kTable    DB      71,72,73,79,80,81,'q','Q'%@AB@%; Key codes%@AE@%%@NL@%
  9001. lkTable   EQU     $-kTable%@NL@%
  9002. procTable DW      homek                    %@AB@%; Table of keys and procedures%@AE@%%@NL@%
  9003.           DW      upk%@NL@%
  9004.           DW      pgupk%@NL@%
  9005.           DW      endk%@NL@%
  9006.           DW      downk%@NL@%
  9007.           DW      pgdnk%@NL@%
  9008.           DW      Quit%@NL@%
  9009.           DW      Quit%@NL@%
  9010.           DW      nonek%@NL@%
  9011. %@NL@%
  9012.           .CODE%@NL@%
  9013.           EXTRN   Pager:PROC         %@AB@%; Routine in other module%@AE@%%@NL@%
  9014. %@NL@%
  9015. start     PROC%@NL@%
  9016.           mov     es, ax             %@AB@%; Load environment segment%@AE@%%@NL@%
  9017.           mov     di, bx%@NL@%
  9018. %@NL@%
  9019. %@AB@%; Throw away .EXE name%@AE@%%@NL@%
  9020. %@NL@%
  9021.           sub     ax, ax             %@AB@%; Find null at end of program name%@AE@%%@NL@%
  9022.           repne   scasb%@NL@%
  9023.           cmp     BYTE PTR es:[di], 0%@AB@%; If double zero, there's no name%@AE@%%@NL@%
  9024.           je      Prompter           %@AB@%;   so get from prompt%@AE@%%@NL@%
  9025. %@NL@%
  9026.           cmp          BYTE PTR es:[di], ' '%@NL@%
  9027.           jne     skip1%@NL@%
  9028.           inc     di                 %@AB@%; Skip leading space%@AE@%%@NL@%
  9029. skip1:%@NL@%
  9030. %@AB@%; Copy command line to file name buffer%@AE@%%@NL@%
  9031. %@NL@%
  9032.           mov     si, di             %@AB@%; Filename source%@AE@%%@NL@%
  9033.           mov     di, OFFSET fName   %@AB@%; Name buffer destination%@AE@%%@NL@%
  9034.           mov     bx, ds             %@AB@%; Save segment registers%@AE@%%@NL@%
  9035.           mov     dx, es%@NL@%
  9036.           mov     ds, dx             %@AB@%; DS = ES%@AE@%%@NL@%
  9037.           mov     es, bx             %@AB@%; ES = DS%@AE@%%@NL@%
  9038.           mov          cx, lfName             %@AB@%; Count = max file name allowed%@AE@%%@NL@%
  9039. loop1:          lodsb                      %@AB@%; Copy first character%@AE@%%@NL@%
  9040.           stosb%@NL@%
  9041.           cmp     al,' '             %@AB@%; Terminate on space too%@AE@%%@NL@%
  9042.           je      skip2%@NL@%
  9043.           or          al,al%@NL@%
  9044.           loopnz  loop1              %@AB@%; If not null, copy another%@AE@%%@NL@%
  9045. skip2:%@NL@%
  9046.           mov     ds, bx             %@AB@%; Restore DS%@AE@%%@NL@%
  9047.           mov          BYTE PTR [di-1], 0%@NL@%
  9048.           jmp     FindFile%@NL@%
  9049. %@NL@%
  9050. NoFile:   @VioWrtTTy Prompt2, lPrompt2, 0%@NL@%
  9051.           @KbdCharIn kChar, kWait, 0%@NL@%
  9052.           and     kChar.kbci_chChar, 11011111b %@AB@%; Convert to uppercase%@AE@%%@NL@%
  9053.           cmp     kChar.kbci_chChar, "Y"%@NL@%
  9054.           mov     dHandle, -1%@NL@%
  9055.           mov     dCount, 1%@NL@%
  9056.           je      Prompter           %@AB@%; If yes, try again%@AE@%%@NL@%
  9057.           jmp     Quit               %@AB@%;   else quit%@AE@%%@NL@%
  9058. %@NL@%
  9059. Prompter: @VioWrtTTy Prompt, lPrompt, 0 %@AB@%; Else prompt for file name%@AE@%%@NL@%
  9060. %@NL@%
  9061.           mov     kStr.kbsi_cb, lfName%@NL@%
  9062. %@NL@%
  9063.           @KbdStringIn fName, kStr, kWait, 0%@NL@%
  9064.           mov     di, kStr.kbsi_cchIn %@AB@%; Null terminate%@AE@%%@NL@%
  9065.           mov     fName[di], 0%@NL@%
  9066. %@NL@%
  9067. %@AB@%; Find first (or only) file in filespec%@AE@%%@NL@%
  9068. %@NL@%
  9069. FindFile: @DosFindFirst fName, dHandle, 0, dResult, dlResult, dCount, 0%@NL@%
  9070.           or      ax, ax%@NL@%
  9071.           jz      skip3%@NL@%
  9072.           jmp     NoFile%@NL@%
  9073. %@NL@%
  9074. %@AB@%; Adjust for current mode and video adapter and hide cursor%@AE@%%@NL@%
  9075. skip3:    call    GetVid%@NL@%
  9076. %@NL@%
  9077. FileLoop:%@NL@%
  9078.           mov     cStatus, 2         %@AB@%; Cursor invisible, position unchanged%@AE@%%@NL@%
  9079. %@NL@%
  9080. %@AB@%; Copy file name to file spec%@AE@%%@NL@%
  9081. %@NL@%
  9082.           push    ds                 %@AB@%; Get file name position in file spec%@AE@%%@NL@%
  9083.           @Pushc  <OFFSET fName>%@NL@%
  9084.           call    GetNamPos%@NL@%
  9085.           mov     si, OFFSET dResult.findbuf_achName %@AB@%; Load source name%@AE@%%@NL@%
  9086.           mov     es, dx             %@AB@%; Load adjusted destination address%@AE@%%@NL@%
  9087.           mov     di, ax             %@AB@%;   from return value%@AE@%%@NL@%
  9088.           sub     cx, cx             %@AB@%; Load file length%@AE@%%@NL@%
  9089.           mov     cl, dResult.findbuf_cchName%@NL@%
  9090.           rep     movsb              %@AB@%; Copy to spec%@AE@%%@NL@%
  9091.           mov     BYTE PTR es:[di], 0%@AB@%; Null terminate%@AE@%%@NL@%
  9092. %@NL@%
  9093. %@AB@%; Copy file name to status line%@AE@%%@NL@%
  9094. %@NL@%
  9095.           sub     cx, cx             %@AB@%; Load file length%@AE@%%@NL@%
  9096.           mov     cl, dResult.findbuf_cchName%@NL@%
  9097.           mov     bx, 12             %@AB@%; Calculate blank spaces to fill%@AE@%%@NL@%
  9098.           sub     bx, cx%@NL@%
  9099.           push    ds                 %@AB@%; ES=DS%@AE@%%@NL@%
  9100.           pop     es%@NL@%
  9101.           mov     si, OFFSET dResult.findbuf_achName %@AB@%; File name as source%@AE@%%@NL@%
  9102.           mov     di, OFFSET stFile[6] %@AB@%; Status line as destination%@AE@%%@NL@%
  9103.           rep     movsb%@NL@%
  9104.           mov     al, " "            %@AB@%; Fill rest of name space with blanks%@AE@%%@NL@%
  9105.           mov     cx, bx%@NL@%
  9106.           rep     stosb%@NL@%
  9107. %@NL@%
  9108. %@AB@%; Open file%@AE@%%@NL@%
  9109. %@NL@%
  9110.           @DosOpen fName, fHandle, fAction, 0, fAtrib, fFlag, [fMode], 0%@NL@%
  9111.           or      ax, ax%@NL@%
  9112.           jz      skip4%@NL@%
  9113.           jmp     NoFile%@NL@%
  9114. %@NL@%
  9115. skip4:    cmp     WORD PTR dResult.findbuf_cbFile[2], 0%@NL@%
  9116.           jz      skip6              %@AB@%; Make sure file is less than a segment%@AE@%%@NL@%
  9117.           mov     cStatus, 1         %@AB@%; Cursor invisible, position unchanged%@AE@%%@NL@%
  9118.           @VioWrtTTy Prompt3, lPrompt3, 0%@NL@%
  9119.           @VioWrtTTy <stFile + 6>, 12, 0%@NL@%
  9120.           cmp     [dCount], 0        %@AB@%; Get key if there's another file%@AE@%%@NL@%
  9121.           je      skip5%@NL@%
  9122.           @KbdCharIn kChar, kWait, 0%@NL@%
  9123. skip5:    jmp     skip11%@NL@%
  9124. %@NL@%
  9125. %@AB@%; Allocate file buffer%@AE@%%@NL@%
  9126. %@NL@%
  9127. skip6:    mov     ax, WORD PTR dResult.findbuf_cbFile[0] %@AB@%; Save size%@AE@%%@NL@%
  9128.           mov     lBuffer, ax%@NL@%
  9129.           mov     oBuffer, 0%@NL@%
  9130.           @DosAllocSeg ax, sBuffer, 0%@NL@%
  9131.           or      ax, ax%@NL@%
  9132.           jz      skip7%@NL@%
  9133.           mov     cStatus, 1         %@AB@%; Cursor invisible, position unchanged%@AE@%%@NL@%
  9134.           @VioWrtTTy Prompt4, lPrompt4, 0%@NL@%
  9135.           jmp     Quit%@NL@%
  9136. %@NL@%
  9137. %@AB@%; Read the file into the buffer%@AE@%%@NL@%
  9138. %@NL@%
  9139. skip7:    @DosRead [fHandle], [Buffer], [lBuffer], fRead%@NL@%
  9140.           or      ax, ax%@NL@%
  9141.           jz      skip8%@NL@%
  9142.           jmp     NoFile%@NL@%
  9143. %@NL@%
  9144. %@AB@%; Search back for EOF marker and adjust if necessary%@AE@%%@NL@%
  9145. %@NL@%
  9146. skip8:    mov     di, [fRead]        %@AB@%; Load file length%@AE@%%@NL@%
  9147.           dec     di                 %@AB@%;   and adjust%@AE@%%@NL@%
  9148.           mov     es, [sBuffer]      %@AB@%; Save ES and load buffer segment%@AE@%%@NL@%
  9149.           std                        %@AB@%; Look backward for 255 characters%@AE@%%@NL@%
  9150.           mov     cx, 0FFh%@NL@%
  9151.           cmp     cx, di%@NL@%
  9152.           jb      skip9%@NL@%
  9153.           mov     cx, di%@NL@%
  9154. skip9:    mov     al, 1Ah            %@AB@%; Search for EOF marker%@AE@%%@NL@%
  9155.           repe    scasb%@NL@%
  9156.           cld%@NL@%
  9157.           jcxz    skip10             %@AB@%; If none, we're OK%@AE@%%@NL@%
  9158.           inc     di                 %@AB@%;   else adjust and save file size%@AE@%%@NL@%
  9159.           mov     [lBuffer], di%@NL@%
  9160. %@NL@%
  9161. %@AB@%; Show a screen of text and allow commands%@AE@%%@NL@%
  9162. %@NL@%
  9163. skip10:   call    Show%@NL@%
  9164. %@NL@%
  9165. %@NL@%
  9166. skip11:   @DosClose [fHandle]        %@AB@%; Close file%@AE@%%@NL@%
  9167. %@NL@%
  9168.           @DosFreeSeg [sBuffer]      %@AB@%; Free memofy%@AE@%%@NL@%
  9169. %@NL@%
  9170.           @DosFindNext [dHandle], dResult, dlResult, dCount %@AB@%; Get next file%@AE@%%@NL@%
  9171. %@NL@%
  9172.           cmp     [dCount], 0        %@AB@%; Quit if no next file%@AE@%%@NL@%
  9173.           jz      exit%@NL@%
  9174.           jmp     FileLoop%@NL@%
  9175. %@NL@%
  9176. exit:     jmp     Quit%@NL@%
  9177. start     ENDP%@NL@%
  9178. %@NL@%
  9179. Show      PROC%@NL@%
  9180. %@NL@%
  9181. %@AB@%; Display first page%@AE@%%@NL@%
  9182. %@NL@%
  9183.           @Pushc  0                  %@AB@%; Start at 0%@AE@%%@NL@%
  9184.           call    Pager%@NL@%
  9185. %@NL@%
  9186. %@AB@%; Handle keys%@AE@%%@NL@%
  9187. %@NL@%
  9188. nextkey:  @KbdCharIn kChar, kWait, 0 %@AB@%; Get a key and load to register%@AE@%%@NL@%
  9189.           mov     al, kChar.kbci_chChar%@NL@%
  9190.           or      al, al             %@AB@%; Is ascii code null?%@AE@%%@NL@%
  9191.           jz      skip1              %@AB@%; Yes? Load scan%@AE@%%@NL@%
  9192.           cmp     al, 0E0h           %@AB@%; Extended key on extended keyboard?%@AE@%%@NL@%
  9193.           jne     skip2              %@AB@%; No? Got code%@AE@%%@NL@%
  9194. skip1:    mov     al, kChar.kbci_chScan%@NL@%
  9195. skip2:%@NL@%
  9196.           cmp     al, 27             %@AB@%; Is it ESCAPE?%@AE@%%@NL@%
  9197.           je      Exit               %@AB@%; Yes? Get out for next file%@AE@%%@NL@%
  9198. %@NL@%
  9199.           push    ds                 %@AB@%; ES = DS%@AE@%%@NL@%
  9200.           pop     es%@NL@%
  9201.           mov     di, OFFSET kTable  %@AB@%; Load address and length of key list%@AE@%%@NL@%
  9202.           mov     cx, lkTable + 1%@NL@%
  9203.           repne   scasb              %@AB@%; Find position and point to key%@AE@%%@NL@%
  9204.           sub     di, (OFFSET kTable) + 1%@NL@%
  9205.           shl     di, 1              %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
  9206.           call    procTable[di]      %@AB@%; Call procedure%@AE@%%@NL@%
  9207.           jmp     nextkey%@NL@%
  9208. %@NL@%
  9209. exit:     ret%@NL@%
  9210. Show      ENDP%@NL@%
  9211. %@NL@%
  9212. homek:    mov     oBuffer, 0         %@AB@%; HOME - set position to 0%@AE@%%@NL@%
  9213.           push    oBuffer%@NL@%
  9214.           mov     curLine, 1%@NL@%
  9215.           call    Pager%@NL@%
  9216.           retn%@NL@%
  9217. %@NL@%
  9218. upk:      @Pushc  -1                 %@AB@%; UP - scroll back 1 line%@AE@%%@NL@%
  9219.           call    Pager%@NL@%
  9220.           retn%@NL@%
  9221. %@NL@%
  9222. pgupk:    mov     ax, nLines         %@AB@%; PGUP - Page back%@AE@%%@NL@%
  9223.           neg     ax%@NL@%
  9224.           push    ax%@NL@%
  9225.           call    Pager%@NL@%
  9226.           retn%@NL@%
  9227. %@NL@%
  9228. endk:     mov     ax, lBuffer        %@AB@%; END - Get last byte of file%@AE@%%@NL@%
  9229.           mov     oBuffer, ax        %@AB@%; Make it the file position%@AE@%%@NL@%
  9230.           mov     curLine, -1        %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
  9231.           mov     ax, nLines         %@AB@%; Page back%@AE@%%@NL@%
  9232.           neg     ax%@NL@%
  9233.           push    ax%@NL@%
  9234.           call    Pager%@NL@%
  9235.           retn%@NL@%
  9236. %@NL@%
  9237. downk:    @Pushc  1                  %@AB@%; DOWN - scroll forward 1 line%@AE@%%@NL@%
  9238.           call    Pager%@NL@%
  9239.           retn%@NL@%
  9240. %@NL@%
  9241. pgdnk:    push    nLines             %@AB@%; PGDN - page forward%@AE@%%@NL@%
  9242.           call    Pager%@NL@%
  9243.           retn%@NL@%
  9244. %@NL@%
  9245. nonek:    retn                       %@AB@%; Ignore unknown key%@AE@%%@NL@%
  9246. %@NL@%
  9247. GetVid    PROC%@NL@%
  9248. %@NL@%
  9249.           mov     vMode.viomi_cb, lvMode%@NL@%
  9250.           @VioGetMode vMode, 0       %@AB@%; Get video mode%@AE@%%@NL@%
  9251. %@NL@%
  9252.           sub     ax, ax             %@AB@%; Clear AH%@AE@%%@NL@%
  9253.           mov     al, vMode.viomi_fbType %@AB@%; Put type in register%@AE@%%@NL@%
  9254.           mov     vType, ax          %@AB@%;   and save%@AE@%%@NL@%
  9255.           test    al, 1              %@AB@%; Test for color%@AE@%%@NL@%
  9256.           jz      skip1              %@AB@%; No? Mono%@AE@%%@NL@%
  9257.           test    al, 100b           %@AB@%; Test for color burst on%@AE@%%@NL@%
  9258.           jz      skip2              %@AB@%; Yes? Color%@AE@%%@NL@%
  9259. skip1:    mov     stAtrib, stBW      %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
  9260.           mov     scAtrib, scBW      %@AB@%;   and screen background%@AE@%%@NL@%
  9261. %@NL@%
  9262. skip2:    @VioGetCurType cMode, 0    %@AB@%; Get cursor mode%@AE@%%@NL@%
  9263.           mov     ax, cMode.vioci_attr %@AB@%; Save attribute%@AE@%%@NL@%
  9264.           xchg    cAtrib, ax%@NL@%
  9265.           mov     cMode.vioci_attr, ax %@AB@%; Set hidden cursor attribute%@AE@%%@NL@%
  9266.           mov     ax, vMode.viomi_row%@AB@%; Get number of rows and adjust%@AE@%%@NL@%
  9267.           dec     ax%@NL@%
  9268.           mov     nLines, ax%@NL@%
  9269. %@NL@%
  9270.           @VioSetCurType cMode, 0    %@AB@%; Hide cursor%@AE@%%@NL@%
  9271. %@NL@%
  9272.           ret%@NL@%
  9273. GetVid    ENDP%@NL@%
  9274. %@NL@%
  9275. GetNamPos PROC    USES di si, argline:FAR PTR BYTE%@NL@%
  9276. %@NL@%
  9277.           les     di, argline        %@AB@%; Load address of file name%@AE@%%@NL@%
  9278.           mov     si, di             %@AB@%; Save copy%@AE@%%@NL@%
  9279. %@NL@%
  9280.           sub     cx, cx             %@AB@%; Ignore count%@AE@%%@NL@%
  9281.           sub     dx, dx             %@AB@%; Use DX as found flag%@AE@%%@NL@%
  9282.           dec     di                 %@AB@%; Adjust%@AE@%%@NL@%
  9283.           mov     ax, "\"            %@AB@%; Search for backslash%@AE@%%@NL@%
  9284. loop1:    scasb                      %@AB@%; Get next character%@AE@%%@NL@%
  9285.           jz      skip1              %@AB@%; If backslash, set flag and save%@AE@%%@NL@%
  9286.           cmp     BYTE PTR es:[di], 0%@AB@%; If end of name, done%@AE@%%@NL@%
  9287.           je      skip2%@NL@%
  9288.           loop    loop1              %@AB@%; If neither, continue%@AE@%%@NL@%
  9289. skip1:    mov     si, di             %@AB@%; Save position%@AE@%%@NL@%
  9290.           inc     dx                 %@AB@%; Set flag to true%@AE@%%@NL@%
  9291.           loop    loop1%@NL@%
  9292. %@NL@%
  9293. skip2:    or      dx, dx             %@AB@%; Found backslash?%@AE@%%@NL@%
  9294.           je      skip3              %@AB@%; If none, search for colon%@AE@%%@NL@%
  9295.           mov     ax, si             %@AB@%;   else return position in DX:AX%@AE@%%@NL@%
  9296.           jmp     SHORT exit%@NL@%
  9297. %@NL@%
  9298. skip3:    neg     cx                 %@AB@%; Adjust count%@AE@%%@NL@%
  9299.           mov     di, si             %@AB@%; Restore start of name%@AE@%%@NL@%
  9300.           mov     ax, ":"            %@AB@%; Search for colon%@AE@%%@NL@%
  9301.           repne   scasb%@NL@%
  9302.           jnz     skip4              %@AB@%; If no colon, restore original%@AE@%%@NL@%
  9303.           mov     ax, di             %@AB@%;   else return position in DX:AX%@AE@%%@NL@%
  9304.           jmp     SHORT exit%@NL@%
  9305. %@NL@%
  9306. skip4:    mov     ax, si             %@AB@%; Return original address%@AE@%%@NL@%
  9307. %@NL@%
  9308. exit:     mov     dx, es%@NL@%
  9309.           ret%@NL@%
  9310. GetNamPos ENDP%@NL@%
  9311. %@NL@%
  9312. Quit      PROC%@NL@%
  9313. %@NL@%
  9314.           mov     scAtrib, 7         %@AB@%; Restore cell attribute for clear screen%@AE@%%@NL@%
  9315. %@NL@%
  9316.           cmp     cStatus, 1         %@AB@%; Check cursor status%@AE@%%@NL@%
  9317.           jg      skip1              %@AB@%; 2 - Make cursor visible on last line%@AE@%%@NL@%
  9318.           je      skip1              %@AB@%; 1 - Make cursor visible%@AE@%%@NL@%
  9319.           jmp     SHORT skip3        %@AB@%; 0 - Leave cursor as is%@AE@%%@NL@%
  9320. %@NL@%
  9321. skip1:    @VioSetCurPos [nLines], 0, 0 %@AB@%; Restore cursor on last line%@AE@%%@NL@%
  9322.           @VioScrollDn [nLines], 0, [nLines], 79, 1, Cell, 0%@NL@%
  9323. %@NL@%
  9324. %@NL@%
  9325. skip2:    mov     ax, cAtrib         %@AB@%; Restore cursor attribute%@AE@%%@NL@%
  9326.           mov     cMode.vioci_attr, ax%@NL@%
  9327.           @VioSetCurType cMode, 0%@NL@%
  9328. %@NL@%
  9329. skip3:    @DosExit 1, 0              %@AB@%; Quit%@AE@%%@NL@%
  9330. %@NL@%
  9331. Quit      ENDP%@NL@%
  9332. %@NL@%
  9333.           END    start%@NL@%
  9334. %@NL@%
  9335. %@NL@%
  9336. %@2@%%@AH@%SHOWR.ASM%@AE@%%@EH@%%@NL@%
  9337. %@AS@%CD-ROM Disc Path:   \SAMPCODE\MASM\MASM5\SHOWR.ASM%@AE@%%@NL@%
  9338. %@NL@%
  9339.           PAGE          60,132%@NL@%
  9340.           TITLE          SHOW%@NL@%
  9341. %@NL@%
  9342. %@AB@%; Program SHOW.ASM%@AE@%%@NL@%
  9343. %@AB@%; Purpose Text file displayer%@AE@%%@NL@%
  9344. %@AB@%; Input          File name from command line or prompt%@AE@%%@NL@%
  9345. %@AB@%; Output  Display file to screen%@AE@%%@NL@%
  9346. %@NL@%
  9347.           DOSSEG%@NL@%
  9348.           .MODEL  small%@NL@%
  9349. %@NL@%
  9350.           INCLUDE dos.inc%@NL@%
  9351.           INCLUDE bios.inc%@NL@%
  9352. %@NL@%
  9353.           .STACK  100h%@NL@%
  9354. %@NL@%
  9355.           .DATA%@NL@%
  9356. %@NL@%
  9357. %@AB@%; Status line%@AE@%%@NL@%
  9358. %@NL@%
  9359.           PUBLIC  statline,linenum%@NL@%
  9360. statline  DB          " Line:         "%@NL@%
  9361. statfile  DB          " File:                "%@NL@%
  9362. stathelp  DB          " Quit: ESC    Move:   PGUP PGDN HOME END "%@NL@%
  9363. linenum          DW          1%@NL@%
  9364. %@NL@%
  9365. %@AB@%; Variables for        screen handling%@AE@%%@NL@%
  9366. %@NL@%
  9367.           PUBLIC  cell,rows,columns,vidadr,statatr,scrnatr,cga%@NL@%
  9368. cell          LABEL          WORD                %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
  9369. char          DB          " "                %@AB@%; Initialize to        space%@AE@%%@NL@%
  9370. attr          DB          ?                %@AB@%; Attribute%@AE@%%@NL@%
  9371. %@NL@%
  9372. columns          EQU          80                %@AB@%; Number of columns%@AE@%%@NL@%
  9373. rows          DW          24                %@AB@%; Number of rows - status line takes one more%@AE@%%@NL@%
  9374. mode          DB          ?                %@AB@%; Initial mode%@AE@%%@NL@%
  9375. pag          DB          ?                %@AB@%; Initial display page%@AE@%%@NL@%
  9376. newvid          DB          0                %@AB@%; Video        change flag%@AE@%%@NL@%
  9377. cga          DB          1                %@AB@%; CGA flag - default yes%@AE@%%@NL@%
  9378. %@NL@%
  9379. vidadr          DW          0B800h        %@AB@%; Video        buffer address - default CGA%@AE@%%@NL@%
  9380. mono          EQU          0B000h        %@AB@%; Monochrome address%@AE@%%@NL@%
  9381. statatr          DB          030h                %@AB@%; Color        default        - black        on cyan%@AE@%%@NL@%
  9382. bwstat          EQU          070h                %@AB@%; B&W default -        black on white%@AE@%%@NL@%
  9383. scrnatr          DB          017h                %@AB@%; Color        default        - white        on blue%@AE@%%@NL@%
  9384. bwscrn          EQU          007h                %@AB@%; B&W default -        white on black%@AE@%%@NL@%
  9385. %@NL@%
  9386. %@AB@%; Variables for        buffer and file        handling%@AE@%%@NL@%
  9387. %@NL@%
  9388.           PUBLIC  buffer,pbuffer,sbuffer,fsize,namebuf%@NL@%
  9389. buffer          LABEL          DWORD%@NL@%
  9390. pbuffer          DW          0                %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
  9391. sbuffer          DW          ?                %@AB@%; Base of buffer (segment)%@AE@%%@NL@%
  9392. lbuffer          DW          ?                %@AB@%; Length of buffer%@AE@%%@NL@%
  9393. fhandle          DW          ?                %@AB@%; Holds        file handle on open%@AE@%%@NL@%
  9394. fsize          DW          ?                %@AB@%; File size after dosopen%@AE@%%@NL@%
  9395. %@NL@%
  9396. prompt          DB          13,10,13,10,"Enter filename: $"%@NL@%
  9397. prompt2          DB          13,10,"File problem. Try again? $"%@NL@%
  9398. namebuf          DB          66,?%@NL@%
  9399. filename  DB          66 DUP (0)                %@AB@%; Buffer for file name%@AE@%%@NL@%
  9400. %@NL@%
  9401. err1          DB          13,10,"Must have DOS 2.0 or higher",13,10,"$"%@NL@%
  9402. err2          DB          13,10,"File too big",13,10,"$"%@NL@%
  9403. %@NL@%
  9404. %@AB@%; Call table%@AE@%%@NL@%
  9405. %@NL@%
  9406. exkeys          DB          71,72,73,79,80,81        %@AB@%; Extended key codes%@AE@%%@NL@%
  9407. lexkeys          EQU          $-exkeys                %@AB@%; Table        of keys%@AE@%%@NL@%
  9408. extable          DW          homek%@NL@%
  9409.           DW          upk%@NL@%
  9410.           DW          pgupk%@NL@%
  9411.           DW          endk%@NL@%
  9412.           DW          downk%@NL@%
  9413.           DW          pgdnk%@NL@%
  9414.           DW          nonek%@NL@%
  9415. %@NL@%
  9416.           .CODE%@NL@%
  9417.           EXTRN          pager:PROC,isEGA:PROC        %@AB@%; Routines in other module%@AE@%%@NL@%
  9418. start:          mov          ax,@DATA                %@AB@%; Initialize data segment%@AE@%%@NL@%
  9419.           mov          ds,ax%@NL@%
  9420. %@NL@%
  9421.           cli                                %@AB@%; Turn off interrupts%@AE@%%@NL@%
  9422.           mov          ss,ax                        %@AB@%; Make SS and%@AE@%%@NL@%
  9423.           mov          sp,OFFSET STACK        %@AB@%;   SP relative        to DGROUP%@AE@%%@NL@%
  9424.           sti%@NL@%
  9425. %@NL@%
  9426. %@AB@%; Adjust memory        allocation%@AE@%%@NL@%
  9427. %@NL@%
  9428.           mov          bx,sp                        %@AB@%; Convert stack        pointer        to paragraphs%@AE@%%@NL@%
  9429.           mov          cl,4                        %@AB@%;   to get stack size%@AE@%%@NL@%
  9430.           shr          bx,cl%@NL@%
  9431.           add          ax,bx                        %@AB@%; Add SS to get        end of program%@AE@%%@NL@%
  9432.           mov          bx,es                        %@AB@%; Get start of program%@AE@%%@NL@%
  9433.           sub          ax,bx                        %@AB@%; Subtract start from end%@AE@%%@NL@%
  9434.           @ModBlok ax                        %@AB@%; Release memory after program%@AE@%%@NL@%
  9435. %@NL@%
  9436. %@AB@%; Allocate dynamic memory for file buffer%@AE@%%@NL@%
  9437. %@NL@%
  9438.           @GetBlok 0FFFh                %@AB@%; Try to allocate 64K%@AE@%%@NL@%
  9439.           mov          sbuffer,ax                %@AB@%; Save buffer segment%@AE@%%@NL@%
  9440.           mov          lbuffer,bx                %@AB@%; Save actual length allocated%@AE@%%@NL@%
  9441. %@NL@%
  9442. %@AB@%; Check        DOS%@AE@%%@NL@%
  9443. %@NL@%
  9444.           @GetVer                        %@AB@%; Get DOS version%@AE@%%@NL@%
  9445.           cmp          al,2                        %@AB@%; Requires DOS 2.0%@AE@%%@NL@%
  9446.           jge          video%@NL@%
  9447.           @DispStr err1                        %@AB@%;   else error and quit%@AE@%%@NL@%
  9448.           int          20h%@NL@%
  9449. %@NL@%
  9450. %@AB@%; Adjust for current mode and and video        adapter%@AE@%%@NL@%
  9451. %@NL@%
  9452. video:          call          isEGA                        %@AB@%; EGA (or VGA)?%@AE@%%@NL@%
  9453.           or          ax,ax                        %@AB@%; If 0 must be CGA or MA%@AE@%%@NL@%
  9454.           je          modechk                %@AB@%; Leave        default%@AE@%%@NL@%
  9455.           mov          rows,ax                %@AB@%; Load rows%@AE@%%@NL@%
  9456.           dec          cga                        %@AB@%; Not CGA%@AE@%%@NL@%
  9457. %@NL@%
  9458. modechk:  @GetMode                        %@AB@%; Get video mode%@AE@%%@NL@%
  9459.           mov          mode,al                %@AB@%; Save initial mode and        page%@AE@%%@NL@%
  9460.           mov          pag,bh%@NL@%
  9461.           mov          dl,al                        %@AB@%; Work on copy%@AE@%%@NL@%
  9462.           cmp          dl,7                        %@AB@%; Is it        mono 7?%@AE@%%@NL@%
  9463.           je          loadmono                %@AB@%; Yes? Set mono%@AE@%%@NL@%
  9464.           cmp          dl,15                        %@AB@%; Is it        mono 15?%@AE@%%@NL@%
  9465.           jne          graphchk                %@AB@%; No? Check graphics%@AE@%%@NL@%
  9466. loadmono: mov          vidadr,mono                %@AB@%; Load mono address%@AE@%%@NL@%
  9467.           mov          statatr,bwstat        %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
  9468.           mov          scrnatr,bwscrn        %@AB@%;   and        screen background%@AE@%%@NL@%
  9469.           dec          cga                        %@AB@%; Not CGA%@AE@%%@NL@%
  9470.           cmp          al,15                        %@AB@%; Is it        mono 15?%@AE@%%@NL@%
  9471.           jne          cmdchk                %@AB@%; No? Done%@AE@%%@NL@%
  9472.           mov          dl,7                        %@AB@%; Yes? Set standard mono%@AE@%%@NL@%
  9473.           jmp          SHORT        chmode%@NL@%
  9474. %@NL@%
  9475. graphchk: cmp          dl,7                        %@AB@%; 7 or higher?%@AE@%%@NL@%
  9476.           jg          color                        %@AB@%; 8 to 14 are color (7 and 15 done)%@AE@%%@NL@%
  9477.           cmp          dl,4                        %@AB@%; 4 or higher?%@AE@%%@NL@%
  9478.           jg          bnw                        %@AB@%; 5 and        6 are probably black and white%@AE@%%@NL@%
  9479.           je          color                        %@AB@%; 4 is color%@AE@%%@NL@%
  9480.           test          dl,1                        %@AB@%; Even?%@AE@%%@NL@%
  9481.           jz          bnw                        %@AB@%; 0 and        2 are black and        white%@AE@%%@NL@%
  9482. color:                                        %@AB@%; 1 and        3 are color%@AE@%%@NL@%
  9483.           cmp          dl,3                        %@AB@%; 3?%@AE@%%@NL@%
  9484.           je          cmdchk                %@AB@%; Yes? Done%@AE@%%@NL@%
  9485.           mov          dl,3                        %@AB@%; Change mode to 3%@AE@%%@NL@%
  9486.           jmp          SHORT        chmode%@NL@%
  9487. %@NL@%
  9488. bnw:          mov          statatr,bwstat        %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
  9489.           mov          scrnatr,bwscrn        %@AB@%;   and        screen background%@AE@%%@NL@%
  9490.           cmp          dl,2                        %@AB@%; 2?%@AE@%%@NL@%
  9491.           je          cmdchk                %@AB@%; Yes? Done%@AE@%%@NL@%
  9492.           mov          dl,2                        %@AB@%; Make it 2%@AE@%%@NL@%
  9493. %@NL@%
  9494. chmode:          @SetMode dl                        %@AB@%; Set video mode%@AE@%%@NL@%
  9495.           @SetPage 0                        %@AB@%; Set video page%@AE@%%@NL@%
  9496.           mov          newvid,1                %@AB@%; Set flag%@AE@%%@NL@%
  9497. %@NL@%
  9498. %@AB@%; Try to open command line file%@AE@%%@NL@%
  9499. %@NL@%
  9500. cmdchk:          mov          bl,es:[80h]                %@AB@%; Get length%@AE@%%@NL@%
  9501.           sub          bh,bh%@NL@%
  9502.           mov          WORD PTR es:[bx+81h],0%@AB@%; Convert to ASCIIZ%@AE@%%@NL@%
  9503.           push          ds%@NL@%
  9504.           @OpenFil 82h,0,es                %@AB@%; Open argument%@AE@%%@NL@%
  9505.           pop          ds%@NL@%
  9506.           jc          getname                %@AB@%; If error, get        from prompt%@AE@%%@NL@%
  9507.           mov          fhandle,ax                %@AB@%;   else save handle%@AE@%%@NL@%
  9508.           push          ds%@NL@%
  9509.           @GetFirst 82h,,es                %@AB@%; Let DOS convert to file name%@AE@%%@NL@%
  9510.           pop          ds%@NL@%
  9511.           jnc          opened                %@AB@%; If OK        file is        open%@AE@%%@NL@%
  9512. %@NL@%
  9513. %@AB@%; Prompt for file%@AE@%%@NL@%
  9514. %@NL@%
  9515. getname:  @DispStr prompt                %@AB@%; Prompt for file%@AE@%%@NL@%
  9516.           @GetStr namebuf,0                %@AB@%; Get response as ASCIIZ%@AE@%%@NL@%
  9517.           @OpenFil filename,0                %@AB@%; Try to open response%@AE@%%@NL@%
  9518.           jc          badfile                %@AB@%; If successful, continue%@AE@%%@NL@%
  9519.           mov          fhandle,ax                %@AB@%; Save handle%@AE@%%@NL@%
  9520.           @GetFirst filename                %@AB@%; Let DOS convert to file name%@AE@%%@NL@%
  9521.           jnc          opened                %@AB@%; If OK, file is opened%@AE@%%@NL@%
  9522. %@NL@%
  9523. badfile:  @DispStr prompt2                %@AB@%;    else prompt to try        again%@AE@%%@NL@%
  9524.           @GetKey 0,1,0%@NL@%
  9525.           and          al,11011111b                %@AB@%; Convert key to uppercase%@AE@%%@NL@%
  9526.           cmp          al,"Y"                %@AB@%; If yes,%@AE@%%@NL@%
  9527.           je          getname                %@AB@%;   try        again%@AE@%%@NL@%
  9528.           jmp          quit                        %@AB@%;   else quit%@AE@%%@NL@%
  9529. %@NL@%
  9530. %@AB@%; Copy file name to status line%@AE@%%@NL@%
  9531. %@NL@%
  9532. opened:          mov          si,9Eh                %@AB@%; Load FCB as as source%@AE@%%@NL@%
  9533.           mov          di,OFFSET statfile[7]        %@AB@%; Load status line as destination%@AE@%%@NL@%
  9534.           mov          al,es:[si]                %@AB@%; Load first byte%@AE@%%@NL@%
  9535.           inc          si%@NL@%
  9536. copy:          mov          [di],al                %@AB@%; Save and load        bytes until 0%@AE@%%@NL@%
  9537.           inc          di%@NL@%
  9538.           mov          al,es:[si]%@NL@%
  9539.           inc          si%@NL@%
  9540.           or          al,al                        %@AB@%; Check        for 0%@AE@%%@NL@%
  9541.           loopne  copy%@NL@%
  9542. %@NL@%
  9543. %@AB@%; Check        file size%@AE@%%@NL@%
  9544. %@NL@%
  9545.           @GetFilSz fhandle                %@AB@%; Get file size%@AE@%%@NL@%
  9546. %@NL@%
  9547.           or          dx,dx                        %@AB@%; Larger than 64K?%@AE@%%@NL@%
  9548.           jne          big                        %@AB@%; Yes? Too big%@AE@%%@NL@%
  9549.           mov          fsize,ax                %@AB@%; Save file size%@AE@%%@NL@%
  9550.           mov          cx,4                        %@AB@%; Convert to paragraphs%@AE@%%@NL@%
  9551.           shr          ax,cl%@NL@%
  9552.           cmp          ax,lbuffer                %@AB@%; Is it        larger than buffer%@AE@%%@NL@%
  9553.           jle          fileread                %@AB@%; No? Continue%@AE@%%@NL@%
  9554. %@NL@%
  9555. big:          @DispStr err2                        %@AB@%;   else error%@AE@%%@NL@%
  9556.           @Exit          2%@NL@%
  9557. %@NL@%
  9558. fileread: push          ds%@NL@%
  9559.           @Read          buffer,fsize,fhandle        %@AB@%; Read file%@AE@%%@NL@%
  9560.           pop          ds%@NL@%
  9561.           jnc          readok                %@AB@%; If no        read error continue%@AE@%%@NL@%
  9562.           jmp          getname                %@AB@%;   else try again%@AE@%%@NL@%
  9563. %@NL@%
  9564. %@AB@%; Search back for EOF marker and adjust        if necessary%@AE@%%@NL@%
  9565. %@NL@%
  9566. readok:          mov          di,ax                        %@AB@%; Load file length%@AE@%%@NL@%
  9567.           push          es                        %@AB@%; Save ES and load buffer segment%@AE@%%@NL@%
  9568.           mov          es,sbuffer%@NL@%
  9569.           std                                %@AB@%; Look backward        for 255        characters%@AE@%%@NL@%
  9570.           mov          cx,0FFh%@NL@%
  9571.           mov          al,1Ah                %@AB@%; Search for EOF marker%@AE@%%@NL@%
  9572.           repne          scasb%@NL@%
  9573.           cld%@NL@%
  9574.           jcxz          noeof                        %@AB@%; If none, we're OK%@AE@%%@NL@%
  9575.           inc          di                        %@AB@%;   else adjust        and save file size%@AE@%%@NL@%
  9576.           mov          fsize,di%@NL@%
  9577. %@NL@%
  9578. noeof:          pop          es%@NL@%
  9579.           @SetCurPos 0,43                %@AB@%; Turn off cursor by moving off        screen%@AE@%%@NL@%
  9580. %@NL@%
  9581. %@AB@%; Display first        page%@AE@%%@NL@%
  9582. %@NL@%
  9583.           xor          ax,ax                        %@AB@%; Start        at 0%@AE@%%@NL@%
  9584.           push          ax%@NL@%
  9585. firstpg:  call          pager%@NL@%
  9586. %@NL@%
  9587. %@AB@%; Handle keys%@AE@%%@NL@%
  9588. %@NL@%
  9589. nextkey:  @GetKey 0,0,0                        %@AB@%; Get a        key%@AE@%%@NL@%
  9590. nextkey2: cmp          al,0                        %@AB@%; Is it        a null?%@AE@%%@NL@%
  9591.           je          extended                %@AB@%; Yes? Must be extended        code%@AE@%%@NL@%
  9592. %@NL@%
  9593.           cmp          al,27                        %@AB@%; Is it        ESCAPE?%@AE@%%@NL@%
  9594.           jne          nextkey                %@AB@%; No? Ignore unknown command%@AE@%%@NL@%
  9595. %@NL@%
  9596. quit:          @ClosFil fhandle                %@AB@%; Yes? Close file%@AE@%%@NL@%
  9597.           @FreeBlok sbuffer                %@AB@%; Release buffer%@AE@%%@NL@%
  9598.           cmp          newvid,1                %@AB@%; Restore video?%@AE@%%@NL@%
  9599.           jne          thatsall                %@AB@%; No?%@AE@%%@NL@%
  9600.           @SetMode mode                        %@AB@%; Restore video        mode, page, and        cursor%@AE@%%@NL@%
  9601.           @SetPage pag%@NL@%
  9602. thatsall: mov          dx,rows                %@AB@%; Load last row        and first column%@AE@%%@NL@%
  9603.           xchg          dl,dh%@NL@%
  9604.           mov          cx,dx                        %@AB@%; Make row the same%@AE@%%@NL@%
  9605.           mov          dl,79%@NL@%
  9606.           @Scroll 0                        %@AB@%; Clear        last line%@AE@%%@NL@%
  9607.           sub          dl,dl%@NL@%
  9608.           @SetCurPos                        %@AB@%; Set cursor%@AE@%%@NL@%
  9609. %@NL@%
  9610.           @Exit          0                        %@AB@%; Quit%@AE@%%@NL@%
  9611. %@NL@%
  9612. extended: @GetKey 0,0,0                        %@AB@%; Get extended code%@AE@%%@NL@%
  9613.           push          es%@NL@%
  9614.           push          ds                        %@AB@%; Load DS into ES%@AE@%%@NL@%
  9615.           pop          es%@NL@%
  9616.           mov          di,OFFSET exkeys        %@AB@%; Load address and length of key list%@AE@%%@NL@%
  9617.           mov          cx,lexkeys+1%@NL@%
  9618.           repne          scasb                        %@AB@%; Find position%@AE@%%@NL@%
  9619.           pop          es%@NL@%
  9620.           sub          di,(OFFSET exkeys)+1        %@AB@%; Point        to key%@AE@%%@NL@%
  9621.           shl          di,1                        %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
  9622.           call          extable[di]                %@AB@%; Call procedure%@AE@%%@NL@%
  9623.           jmp          nextkey%@NL@%
  9624. %@NL@%
  9625. homek:          mov          pbuffer,0                %@AB@%; HOME - set position to 0%@AE@%%@NL@%
  9626.           push          pbuffer%@NL@%
  9627.           mov          linenum,1%@NL@%
  9628.           call          pager%@NL@%
  9629.           retn%@NL@%
  9630. %@NL@%
  9631. upk:          mov          ax,-1                        %@AB@%; UP - scroll back 1 line%@AE@%%@NL@%
  9632.           push          ax%@NL@%
  9633.           call          pager%@NL@%
  9634.           retn%@NL@%
  9635. %@NL@%
  9636. pgupk:          mov          ax,rows                %@AB@%; PGUP - Page back%@AE@%%@NL@%
  9637.           neg          ax%@NL@%
  9638.           push          ax%@NL@%
  9639.           call          pager%@NL@%
  9640.           retn%@NL@%
  9641. %@NL@%
  9642. endk:          mov          ax,fsize                %@AB@%; END -        Get last byte of file%@AE@%%@NL@%
  9643.           mov          pbuffer,ax                %@AB@%; Make it the file position%@AE@%%@NL@%
  9644.           mov          linenum,-1                %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
  9645.           mov          ax,rows                %@AB@%; Page back%@AE@%%@NL@%
  9646.           neg          ax%@NL@%
  9647.           push          ax%@NL@%
  9648.           call          pager%@NL@%
  9649.           retn%@NL@%
  9650. %@NL@%
  9651. downk:          mov          ax,1                        %@AB@%; DOWN - scroll        forward        1 line%@AE@%%@NL@%
  9652.           push          ax%@NL@%
  9653.           call          pager%@NL@%
  9654.           retn%@NL@%
  9655. %@NL@%
  9656. pgdnk:          push          rows                        %@AB@%; PGDN - page forward%@AE@%%@NL@%
  9657.           call          pager%@NL@%
  9658.           retn%@NL@%
  9659. %@NL@%
  9660. nonek:          retn                                %@AB@%; Ignore unknown key%@AE@%%@NL@%
  9661. %@NL@%
  9662.           END         start%@NL@%
  9663. %@NL@%
  9664.