home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-03-01 | 463.4 KB | 9,664 lines |
- %@1@%%@AH@%Microsoft MASM: Sample Code from v6.0%@EH@%%@AE@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%ALARM.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\TSR\ALARM.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* ALARM.ASM - A simple memory-resident program that beeps the speaker%@AE@%%@NL@%
- %@AB@%;* at a prearranged time. Can be loaded more than once for multiple%@AE@%%@NL@%
- %@AB@%;* alarm settings. During installation, ALARM establishes a handler%@AE@%%@NL@%
- %@AB@%;* for the timer interrupt (interrupt 08). It then terminates through%@AE@%%@NL@%
- %@AB@%;* the Terminate-and-Stay-Resident function (function 31h). After the%@AE@%%@NL@%
- %@AB@%;* alarm sounds, the resident portion of the program retires by setting%@AE@%%@NL@%
- %@AB@%;* a flag that prevents further processing in the handler.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* NOTE: You must assemble this program as a .COM file, either as a PWB%@AE@%%@NL@%
- %@AB@%;* build option or with the ML /AT switch.%@AE@%%@NL@%
- %@NL@%
- .MODEL tiny, pascal, os_dos%@NL@%
- .STACK%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- ORG 5Dh %@AB@%; Location of time argument in PSP,%@AE@%%@NL@%
- CountDown LABEL WORD %@AB@%; converted to number of 5-second%@AE@%%@NL@%
- %@AB@%; intervals to elapse%@AE@%%@NL@%
- .STARTUP%@NL@%
- jmp Install %@AB@%; Jump over data and resident code%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Data must be in code segment so it won't be thrown away with Install code.%@AE@%%@NL@%
- %@NL@%
- OldTimer DWORD ? %@AB@%; Address of original timer routine%@AE@%%@NL@%
- tick_91 BYTE 91 %@AB@%; Counts 91 clock ticks (5 seconds)%@AE@%%@NL@%
- TimerActiveFlag BYTE 0 %@AB@%; Active flag for timer handler%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* NewTimer - Handler routine for timer interrupt (interrupt 08).%@AE@%%@NL@%
- %@AB@%;* Decrements CountDown every 5 seconds. No other action is taken%@AE@%%@NL@%
- %@AB@%;* until CountDown reaches 0, at which time the speaker sounds.%@AE@%%@NL@%
- %@NL@%
- NewTimer PROC FAR%@NL@%
- %@NL@%
- .IF cs:TimerActiveFlag != 0 %@AB@%; If timer busy or retired:%@AE@%%@NL@%
- jmp cs:OldTimer %@AB@%; Jump to original timer routine%@AE@%%@NL@%
- .ENDIF%@NL@%
- inc cs:TimerActiveFlag %@AB@%; Set active flag%@AE@%%@NL@%
- pushf %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
- call cs:OldTimer %@AB@%; then far-calling original routine%@AE@%%@NL@%
- sti %@AB@%; Enable interrupts%@AE@%%@NL@%
- push ds %@AB@%; Preserve DS register%@AE@%%@NL@%
- push cs %@AB@%; Point DS to current segment for%@AE@%%@NL@%
- pop ds %@AB@%; further memory access%@AE@%%@NL@%
- dec tick_91 %@AB@%; Count down for 91 ticks%@AE@%%@NL@%
- .IF zero? %@AB@%; If 91 ticks have elapsed:%@AE@%%@NL@%
- mov tick_91, 91 %@AB@%; Reset secondary counter and%@AE@%%@NL@%
- dec CountDown %@AB@%; subtract one 5-second interval%@AE@%%@NL@%
- .IF zero? %@AB@%; If CountDown drained:%@AE@%%@NL@%
- call Sound %@AB@%; Sound speaker%@AE@%%@NL@%
- inc TimerActiveFlag %@AB@%; Alarm has sounded, set flag%@AE@%%@NL@%
- .ENDIF%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- dec TimerActiveFlag %@AB@%; Decrement active flag%@AE@%%@NL@%
- pop ds %@AB@%; Recover DS%@AE@%%@NL@%
- iret %@AB@%; Return from interrupt handler%@AE@%%@NL@%
- %@NL@%
- NewTimer ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Sound - Sounds speaker with the following tone and duration:%@AE@%%@NL@%
- %@NL@%
- BEEP_TONE EQU 440 %@AB@%; Beep tone in hertz%@AE@%%@NL@%
- BEEP_DURATION EQU 6 %@AB@%; Number of clocks during beep,%@AE@%%@NL@%
- %@AB@%; where 18 clocks = approx 1 second%@AE@%%@NL@%
- %@NL@%
- Sound PROC USES ax bx cx dx es %@AB@%; Save registers used in this routine%@AE@%%@NL@%
- mov al, 0B6h %@AB@%; Initialize channel 2 of%@AE@%%@NL@%
- out 43h, al %@AB@%; timer chip%@AE@%%@NL@%
- mov dx, 12h %@AB@%; Divide 1,193,180 hertz%@AE@%%@NL@%
- mov ax, 34DCh %@AB@%; (clock frequency) by%@AE@%%@NL@%
- mov bx, BEEP_TONE %@AB@%; desired frequency%@AE@%%@NL@%
- div bx %@AB@%; Result is timer clock count%@AE@%%@NL@%
- out 42h, al %@AB@%; Low byte of count to timer%@AE@%%@NL@%
- mov al, ah%@NL@%
- out 42h, al %@AB@%; High byte of count to timer%@AE@%%@NL@%
- in al, 61h %@AB@%; Read value from port 61h%@AE@%%@NL@%
- or al, 3 %@AB@%; Set first two bits%@AE@%%@NL@%
- out 61h, al %@AB@%; Turn speaker on%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Pause for specified number of clock ticks%@AE@%%@NL@%
- %@NL@%
- mov dx, BEEP_DURATION %@AB@%; Beep duration in clock ticks%@AE@%%@NL@%
- sub cx, cx %@AB@%; CX:DX = tick count for pause%@AE@%%@NL@%
- mov es, cx %@AB@%; Point ES to low memory data%@AE@%%@NL@%
- add dx, es:[46Ch] %@AB@%; Add current tick count to CX:DX%@AE@%%@NL@%
- adc cx, es:[46Eh] %@AB@%; Result is target count in CX:DX%@AE@%%@NL@%
- .REPEAT%@NL@%
- mov bx, es:[46Ch] %@AB@%; Now repeatedly poll clock%@AE@%%@NL@%
- mov ax, es:[46Eh] %@AB@%; count until the target%@AE@%%@NL@%
- sub bx, dx %@AB@%; time is reached%@AE@%%@NL@%
- sbb ax, cx%@NL@%
- .UNTIL !carry?%@NL@%
- %@NL@%
- in al, 61h %@AB@%; When time elapses, get port value%@AE@%%@NL@%
- xor al, 3 %@AB@%; Kill bits 0-1 to turn%@AE@%%@NL@%
- out 61h, al %@AB@%; speaker off%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- Sound ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Install - Converts ASCII argument to valid binary number, replaces%@AE@%%@NL@%
- %@AB@%;* NewTimer as the interrupt handler for the timer, then makes program%@AE@%%@NL@%
- %@AB@%;* memory-resident by exiting through function 31h.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* This procedure marks the end of the TSR's resident section and the%@AE@%%@NL@%
- %@AB@%;* beginning of the installation section. When ALARM terminates through%@AE@%%@NL@%
- %@AB@%;* function 31h, the above code and data remain resident in memory. The%@AE@%%@NL@%
- %@AB@%;* memory occupied by the following code is returned to DOS.%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- Install PROC%@NL@%
- %@NL@%
- %@AB@%; Time argument is in hhmm military format. Convert ASCII digits to%@AE@%%@NL@%
- %@AB@%; number of minutes since midnight, then convert current time to number%@AE@%%@NL@%
- %@AB@%; of minutes since midnight. Difference is number of minutes to elapse%@AE@%%@NL@%
- %@AB@%; until alarm sounds. Convert to seconds-to-elapse, divide by 5 seconds,%@AE@%%@NL@%
- %@AB@%; and store result in word CountDown.%@AE@%%@NL@%
- %@NL@%
- DEFAULT_TIME EQU 3600 %@AB@%; Default alarm setting = 1 hour%@AE@%%@NL@%
- %@AB@%; (in seconds) from present time%@AE@%%@NL@%
- mov ax, DEFAULT_TIME%@NL@%
- cwd %@AB@%; DX:AX = default time in seconds%@AE@%%@NL@%
- .IF BYTE PTR CountDown != ' '%@AB@%;If not blank argument:%@AE@%%@NL@%
- xor CountDown[0], '00' %@AB@%; Convert 4 bytes of ASCII%@AE@%%@NL@%
- xor CountDown[2], '00' %@AB@%; argument to binary%@AE@%%@NL@%
- %@NL@%
- mov al, 10 %@AB@%; Multiply 1st hour digit by 10%@AE@%%@NL@%
- mul BYTE PTR CountDown[0] %@AB@%; and add to 2nd hour digit%@AE@%%@NL@%
- add al, BYTE PTR CountDown[1]%@NL@%
- mov bh, al %@AB@%; BH = hour for alarm to go off%@AE@%%@NL@%
- mov al, 10 %@AB@%; Repeat procedure for minutes%@AE@%%@NL@%
- mul BYTE PTR CountDown[2] %@AB@%; Multiply 1st minute digit by 10%@AE@%%@NL@%
- add al, BYTE PTR CountDown[3] %@AB@%; and add to 2nd minute digit%@AE@%%@NL@%
- mov bl, al %@AB@%; BL = minute for alarm to go off%@AE@%%@NL@%
- mov ah, 2Ch %@AB@%; Request function 2Ch%@AE@%%@NL@%
- int 21h %@AB@%; Get Time (CX = current hour/min)%@AE@%%@NL@%
- mov dl, dh%@NL@%
- sub dh, dh%@NL@%
- push dx %@AB@%; Save DX = current seconds%@AE@%%@NL@%
- %@NL@%
- mov al, 60 %@AB@%; Multiply current hour by 60%@AE@%%@NL@%
- mul ch %@AB@%; to convert to minutes%@AE@%%@NL@%
- sub ch, ch%@NL@%
- add cx, ax %@AB@%; Add current minutes to result%@AE@%%@NL@%
- %@AB@%; CX = minutes since midnight%@AE@%%@NL@%
- mov al, 60 %@AB@%; Multiply alarm hour by 60%@AE@%%@NL@%
- mul bh %@AB@%; to convert to minutes%@AE@%%@NL@%
- sub bh, bh%@NL@%
- add ax, bx %@AB@%; AX = number of minutes since%@AE@%%@NL@%
- %@AB@%; midnight for alarm setting%@AE@%%@NL@%
- sub ax, cx %@AB@%; AX = time in minutes to elapse%@AE@%%@NL@%
- %@AB@%; before alarm sounds%@AE@%%@NL@%
- .IF carry? %@AB@%; If alarm time is tomorrow:%@AE@%%@NL@%
- add ax, 24 * 60 %@AB@%; Add minutes in a day%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov bx, 60%@NL@%
- mul bx %@AB@%; DX:AX = minutes-to-elapse-times-60%@AE@%%@NL@%
- pop bx %@AB@%; Recover current seconds%@AE@%%@NL@%
- sub ax, bx %@AB@%; DX:AX = seconds to elapse before%@AE@%%@NL@%
- sbb dx, 0 %@AB@%; alarm activates%@AE@%%@NL@%
- .IF carry? %@AB@%; If negative:%@AE@%%@NL@%
- mov ax, 5 %@AB@%; Assume 5 seconds%@AE@%%@NL@%
- cwd%@NL@%
- .ENDIF%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov bx, 5 %@AB@%; Divide result by 5 seconds%@AE@%%@NL@%
- div bx %@AB@%; AX = number of 5-second intervals%@AE@%%@NL@%
- mov CountDown, ax %@AB@%; to elapse before alarm sounds%@AE@%%@NL@%
- %@NL@%
- mov ax, 3508h %@AB@%; Request function 35h%@AE@%%@NL@%
- int 21h %@AB@%; Get Vector for timer (interrupt 08)%@AE@%%@NL@%
- mov WORD PTR OldTimer[0], bx%@AB@%; Store address of original%@AE@%%@NL@%
- mov WORD PTR OldTimer[2], es%@AB@%; timer interrupt%@AE@%%@NL@%
- mov ax, 2508h %@AB@%; Request function 25h%@AE@%%@NL@%
- mov dx, OFFSET NewTimer %@AB@%; DS:DX points to new timer handler%@AE@%%@NL@%
- int 21h %@AB@%; Set Vector with address of NewTimer%@AE@%%@NL@%
- %@NL@%
- mov dx, OFFSET Install %@AB@%; DX = bytes in resident section%@AE@%%@NL@%
- mov cl, 4%@NL@%
- shr dx, cl %@AB@%; Convert to number of paragraphs%@AE@%%@NL@%
- inc dx %@AB@%; plus one%@AE@%%@NL@%
- mov ax, 3100h %@AB@%; Request function 31h, error code=0%@AE@%%@NL@%
- int 21h %@AB@%; Terminate-and-Stay-Resident%@AE@%%@NL@%
- %@NL@%
- Install ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%BASIC.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\MIXED\BASIC.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Called by BASMAIN.BAS%@AE@%%@NL@%
- %@AB@%; Assemble with ML /c BASIC.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL medium%@NL@%
- %@NL@%
- Power2 PROTO PASCAL, Factor:PTR WORD, Power:PTR WORD%@NL@%
- .CODE%@NL@%
- Power2 PROC PASCAL, Factor:PTR WORD, Power:PTR WORD%@NL@%
- %@NL@%
- mov bx, WORD PTR Factor %@AB@%; Load Factor into%@AE@%%@NL@%
- mov ax, [bx] %@AB@%; AX%@AE@%%@NL@%
- mov bx, WORD PTR Power %@AB@%; Load Power into%@AE@%%@NL@%
- mov cx, [bx] %@AB@%; CX%@AE@%%@NL@%
- shl ax, cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- Power2 ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%C.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\MIXED\C.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Called from main program in CMAIN.C%@AE@%%@NL@%
- %@AB@%; Assemble with ML /c C.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL small, c%@NL@%
- %@NL@%
- Power2 PROTO C factor:SWORD, power:SWORD%@NL@%
- .CODE%@NL@%
- %@NL@%
- Power2 PROC C factor:SWORD, power:SWORD%@NL@%
- mov ax, factor %@AB@%; Load Arg1 into AX%@AE@%%@NL@%
- mov cx, power %@AB@%; Load Arg2 into CX%@AE@%%@NL@%
- shl ax, cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- %@AB@%; Leave return value in AX%@AE@%%@NL@%
- ret%@NL@%
- Power2 ENDP%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%COMMON.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\DEMOS\COMMON.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL small, pascal, os_dos%@NL@%
- INCLUDE demo.inc%@NL@%
- %@NL@%
- .DATA%@NL@%
- vconfig VIDCONFIG <> %@AB@%; Global video configuration structure%@AE@%%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* GetVidConfig - Determines current video configuration and initializes%@AE@%%@NL@%
- %@AB@%;* the vconfig structure.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 0 (Set Video Mode)%@AE@%%@NL@%
- %@AB@%;* 10h, Function 0Fh (Get Current Video Mode)%@AE@%%@NL@%
- %@AB@%;* 10h, Function 1Ah (Video Display Combination)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure, declared in the%@AE@%%@NL@%
- %@AB@%;* DEMO.INC include file.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- GetVidConfig PROC%@NL@%
- %@NL@%
- mov ax, 1A00h %@AB@%; Get video info for VGA%@AE@%%@NL@%
- int 10h%@NL@%
- chkVGA:%@NL@%
- cmp al, 1Ah %@AB@%; Is VGA or MCGA present?%@AE@%%@NL@%
- jne chkEGA %@AB@%; No? Then check for EGA%@AE@%%@NL@%
- %@NL@%
- cmp bl, 2 %@AB@%; If VGA exists as secondary adapter,%@AE@%%@NL@%
- je isCGA %@AB@%; check for CGA and mono as primary%@AE@%%@NL@%
- jb isMONO%@NL@%
- cmp bl, 5 %@AB@%; If EGA is primary, do normal%@AE@%%@NL@%
- jbe chkEGA %@AB@%; EGA checking%@AE@%%@NL@%
- chkMCGA:%@NL@%
- mov vconfig.adapter, MCGA %@AB@%; Yes? Assume MCGA%@AE@%%@NL@%
- mov vconfig.display, COLOR%@NL@%
- cmp bl, 8 %@AB@%; Correct assumption?%@AE@%%@NL@%
- ja gotmode %@AB@%; Yes? Continue%@AE@%%@NL@%
- isVGA:%@NL@%
- mov vconfig.adapter, VGA %@AB@%; Assume it's VGA color%@AE@%%@NL@%
- je gotmode %@AB@%; Yes? Continue%@AE@%%@NL@%
- mov vconfig.display, MONO %@AB@%; No? Must be VGA mono%@AE@%%@NL@%
- jmp gotmode %@AB@%; Finished with VGA, so jump%@AE@%%@NL@%
- chkEGA:%@NL@%
- mov ah, 12h %@AB@%; Call EGA status function%@AE@%%@NL@%
- mov bl, 10h%@NL@%
- sub cx, cx %@AB@%; Clear status bits%@AE@%%@NL@%
- int 10h%@NL@%
- jcxz chkCGA %@AB@%; If CX is unchanged, not EGA%@AE@%%@NL@%
- isEGA:%@NL@%
- mov vconfig.adapter, EGA %@AB@%; Set structure fields for EGA%@AE@%%@NL@%
- mov vconfig.display, MONO %@AB@%; Assume EGA mono%@AE@%%@NL@%
- or bh, bh %@AB@%; Correct assumption?%@AE@%%@NL@%
- jnz gotmode %@AB@%; Yes? Continue%@AE@%%@NL@%
- mov vconfig.display, COLOR %@AB@%; No? Must be EGA color%@AE@%%@NL@%
- jmp gotmode %@AB@%; Finished with EGA, so jump%@AE@%%@NL@%
- chkCGA:%@NL@%
- int 11h %@AB@%; Get equipment list%@AE@%%@NL@%
- and al, 30h %@AB@%; If bits 4-5 set, monochrome%@AE@%%@NL@%
- cmp al, 30h %@AB@%; Monochrome text mode?%@AE@%%@NL@%
- je isMONO %@AB@%; Yes? Continue%@AE@%%@NL@%
- isCGA:%@NL@%
- mov vconfig.adapter, CGA %@AB@%; No? Must be CGA%@AE@%%@NL@%
- mov vconfig.display, COLOR%@NL@%
- jmp gotmode%@NL@%
- isMONO:%@NL@%
- mov vconfig.adapter, MDA %@AB@%; Set MONO%@AE@%%@NL@%
- mov vconfig.display, MONO%@NL@%
- gotmode:%@NL@%
- mov ah, 0Fh%@NL@%
- int 10h %@AB@%; Get current mode%@AE@%%@NL@%
- mov vconfig.mode, al %@AB@%; Record mode%@AE@%%@NL@%
- mov vconfig.dpage, bh %@AB@%; and current page%@AE@%%@NL@%
- mov al, vconfig.display %@AB@%; Multiply display value%@AE@%%@NL@%
- cbw %@AB@%; (which is either 0 or 1)%@AE@%%@NL@%
- mov bx, 800h %@AB@%; by 800h, then add to B000h%@AE@%%@NL@%
- mul bx %@AB@%; for segment address of%@AE@%%@NL@%
- add ax, 0B000h %@AB@%; video buffer%@AE@%%@NL@%
- add ah, vconfig.dpage %@AB@%; Adding display page gives%@AE@%%@NL@%
- mov vconfig.sgmnt, ax %@AB@%; address of current page%@AE@%%@NL@%
- %@NL@%
- sub ax, ax%@NL@%
- mov es, ax%@NL@%
- mov al, es:[44Ah] %@AB@%; Get number of display cols%@AE@%%@NL@%
- mov vconfig.cols, al %@AB@%; Store in structure%@AE@%%@NL@%
- mov vconfig.rows, 24 %@AB@%; Assume bottom row # = 24%@AE@%%@NL@%
- cmp vconfig.adapter, EGA %@AB@%; EGA or VGA?%@AE@%%@NL@%
- jl exit %@AB@%; No? Exit%@AE@%%@NL@%
- mov ax, 1130h %@AB@%; Yes? Request character info%@AE@%%@NL@%
- sub bh, bh %@AB@%; Set BH to valid value%@AE@%%@NL@%
- push bp %@AB@%; BP will change, so save it%@AE@%%@NL@%
- int 10h %@AB@%; Get number of rows/screen%@AE@%%@NL@%
- mov vconfig.rows, dl %@AB@%; Keep in structure%@AE@%%@NL@%
- pop bp %@AB@%; Restore BP%@AE@%%@NL@%
- exit:%@NL@%
- ret%@NL@%
- %@NL@%
- GetVidConfig ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetCurPos - Gets current cursor position.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with high byte = row, low byte = column%@AE@%%@NL@%
- %@NL@%
- GetCurPos PROC USES bx dx%@NL@%
- %@NL@%
- mov ah, 3 %@AB@%; Function 3%@AE@%%@NL@%
- mov bh, vconfig.dpage%@NL@%
- int 10h %@AB@%; Get cursor position%@AE@%%@NL@%
- mov ax, dx%@NL@%
- ret%@NL@%
- %@NL@%
- GetCurPos ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* SetCurPos - Sets cursor position.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 2 (Set Cursor Position)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Row - Target row%@AE@%%@NL@%
- %@AB@%;* Col - Target column%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- SetCurPos PROC USES bx dx,%@NL@%
- Row:WORD,%@NL@%
- Col:WORD%@NL@%
- %@NL@%
- mov dh, BYTE PTR Row %@AB@%; DH = row%@AE@%%@NL@%
- mov dl, BYTE ptr Col %@AB@%; DL = column%@AE@%%@NL@%
- mov ah, 2 %@AB@%; Function 2%@AE@%%@NL@%
- mov bh, vconfig.dpage %@AB@%; Current page%@AE@%%@NL@%
- int 10h %@AB@%; Set cursor position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- SetCurPos ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* StrWrite - Writes ASCIIZ string to video memory at specified row/column.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - lodsb stosb%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Row - Row coordinate%@AE@%%@NL@%
- %@AB@%;* Col - Column coordinate%@AE@%%@NL@%
- %@AB@%;* Sptr - Pointer to string%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- StrWrite PROC USES ds si di,%@NL@%
- Row:WORD,%@NL@%
- Col:WORD,%@NL@%
- Sptr:PTR BYTE%@NL@%
- %@NL@%
- GetVidOffset Row, Col %@AB@%; Get video offset for these coords%@AE@%%@NL@%
- mov di, ax %@AB@%; Copy to DI%@AE@%%@NL@%
- LoadPtr ds, si, Sptr %@AB@%; DS:SI points to string%@AE@%%@NL@%
- mov es, vconfig.sgmnt %@AB@%; ES:DI points to video RAM%@AE@%%@NL@%
- .WHILE 1 %@AB@%; Loop forever (or until break)%@AE@%%@NL@%
- lodsb %@AB@%; Get 1 character from string%@AE@%%@NL@%
- .BREAK .IF al == 0 %@AB@%; Quit if null terminator%@AE@%%@NL@%
- %@NL@%
- %@AB@%; For CGA systems, StrWrite waits for the video to begin a horizontal%@AE@%%@NL@%
- %@AB@%; retrace before writing a character to memory. This avoids the problem%@AE@%%@NL@%
- %@AB@%; of video snow inherent with some (though not all) color/graphics adapters.%@AE@%%@NL@%
- %@AB@%; It also demonstrates a somewhat different approach to the problem than the%@AE@%%@NL@%
- %@AB@%; one taken in the WinOpen and WinClose procedures.%@AE@%%@NL@%
- %@NL@%
- .IF vconfig.adapter != CGA %@AB@%; If not CGA, skip this step%@AE@%%@NL@%
- push ax %@AB@%; Save character%@AE@%%@NL@%
- mov dx, 3DAh %@AB@%; Address of status register%@AE@%%@NL@%
- cli %@AB@%; Disallow interruptions%@AE@%%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Read current video status%@AE@%%@NL@%
- .UNTIL !(al & 1) %@AB@%; Until horizontal retrace done%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; No? Read status again%@AE@%%@NL@%
- .UNTIL al & 1 %@AB@%; Until retrace starts%@AE@%%@NL@%
- pop ax %@AB@%; Recover character%@AE@%%@NL@%
- .ENDIF %@AB@%; CGA only%@AE@%%@NL@%
- %@NL@%
- stosb %@AB@%; Write char to video buffer%@AE@%%@NL@%
- sti %@AB@%; Reenable interrupts in case CGA%@AE@%%@NL@%
- inc di %@AB@%; Skip attribute byte%@AE@%%@NL@%
- .ENDW%@NL@%
- ret%@NL@%
- %@NL@%
- StrWrite ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* StrInput - Gets input string from keyboard using BIOS. Signals idle%@AE@%%@NL@%
- %@AB@%;* state by calling interrupt 28h while polling for keypress, making%@AE@%%@NL@%
- %@AB@%;* the procedure useful in TSR programs. Terminates when Enter or Esc%@AE@%%@NL@%
- %@AB@%;* keys pressed.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS interrupt - Interrupt 28h (DOS Idle Interrupt)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Row - Row coordinate%@AE@%%@NL@%
- %@AB@%;* Col - Column coordinate%@AE@%%@NL@%
- %@AB@%;* Max - Maximum allowable string length%@AE@%%@NL@%
- %@AB@%;* Sptr - Pointer to string%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with terminating char%@AE@%%@NL@%
- %@NL@%
- StrInput PROC USES ds si,%@NL@%
- Row:WORD,%@NL@%
- Col:WORD,%@NL@%
- Max:WORD,%@NL@%
- Sptr:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, si, Sptr %@AB@%; DS:SI points to string%@AE@%%@NL@%
- add Max, si%@NL@%
- dec Max %@AB@%; MAX now points to string limit%@AE@%%@NL@%
- %@NL@%
- .WHILE 1 %@AB@%; Get key until break or continue%@AE@%%@NL@%
- loop1:%@NL@%
- INVOKE StrWrite, %@AB@%; Display input string%@AE@%%@NL@%
- Row,%@NL@%
- Col,%@NL@%
- si%@NL@%
- %@NL@%
- mov bx, si%@NL@%
- mov dx, Col %@AB@%; DL = cursor column%@AE@%%@NL@%
- %@NL@%
- .WHILE (BYTE PTR [bx] != 0) %@AB@%; Scan string for null terminator%@AE@%%@NL@%
- inc bx %@AB@%; Else try next character%@AE@%%@NL@%
- inc dx %@AB@%; and increment cursor column%@AE@%%@NL@%
- .ENDW%@NL@%
- %@NL@%
- %@AB@%; Set cursor position, pass row and column (DX)%@AE@%%@NL@%
- INVOKE SetCurPos,%@NL@%
- Row,%@NL@%
- dx%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- int 28h %@AB@%; Signal idle state%@AE@%%@NL@%
- mov ah, 1%@NL@%
- int 16h %@AB@%; Key waiting?%@AE@%%@NL@%
- .CONTINUE .IF zero?%@NL@%
- sub ah, ah%@NL@%
- int 16h %@AB@%; Yes? Get key%@AE@%%@NL@%
- %@NL@%
- cmp ah, LEFT %@AB@%; Left arrow key?%@AE@%%@NL@%
- je backspace %@AB@%; Treat like backspace%@AE@%%@NL@%
- .UNTIL al != 0 %@AB@%; Ignore all other special keys%@AE@%%@NL@%
- %@NL@%
- .BREAK .IF al == ESCAPE %@AB@%; Exit if Esc key%@AE@%%@NL@%
- .BREAK .IF al == CR %@AB@%; Exit if Return key%@AE@%%@NL@%
- %@NL@%
- .IF al == BACKSP %@AB@%; If backspace or left, handle it%@AE@%%@NL@%
- backspace:%@NL@%
- cmp bx, si %@AB@%; At first letter?%@AE@%%@NL@%
- jbe loop1 %@AB@%; Yes? Ignore backspace%@AE@%%@NL@%
- dec bx %@AB@%; No? Point to preceding char%@AE@%%@NL@%
- dec dx %@AB@%; Decrement column%@AE@%%@NL@%
- mov BYTE PTR [bx], ' ' %@AB@%; Blank char%@AE@%%@NL@%
- push bx %@AB@%; Preserve pointer%@AE@%%@NL@%
- INVOKE StrWrite, %@AB@%; Overwrite last char with blank%@AE@%%@NL@%
- Row,%@NL@%
- dx,%@NL@%
- bx%@NL@%
- %@NL@%
- pop bx%@NL@%
- mov BYTE PTR [bx], 0 %@AB@%; Make last char the new terminator%@AE@%%@NL@%
- .CONTINUE%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .CONTINUE .IF bx > Max %@AB@%; Ignore key if too many letters%@AE@%%@NL@%
- sub ah, ah%@NL@%
- mov [bx], ax %@AB@%; Store letter and null terminator%@AE@%%@NL@%
- .ENDW%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- StrInput ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* ClearBox - Clears portion of screen with specified fill attribute.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 6 (Scroll Up)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Attr - Fill attribute%@AE@%%@NL@%
- %@AB@%;* Row1 - Top screen row of cleared section%@AE@%%@NL@%
- %@AB@%;* Col1 - Left column of cleared section%@AE@%%@NL@%
- %@AB@%;* Row2 - Bottom screen row of cleared section%@AE@%%@NL@%
- %@AB@%;* Col2 - Right column of cleared section%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- ClearBox PROC,%@NL@%
- Attr:WORD,%@NL@%
- Row1:WORD,%@NL@%
- Col1:WORD,%@NL@%
- Row2:WORD,%@NL@%
- Col2:WORD%@NL@%
- %@NL@%
- mov ax, 0600h %@AB@%; Scroll service%@AE@%%@NL@%
- mov bh, BYTE PTR Attr %@AB@%; BH = fill attribute%@AE@%%@NL@%
- mov ch, BYTE PTR Row1 %@AB@%; CH = top row of clear area%@AE@%%@NL@%
- mov cl, BYTE PTR Col1 %@AB@%; CL = left column%@AE@%%@NL@%
- mov dh, BYTE PTR Row2 %@AB@%; DH = bottom row of clear area%@AE@%%@NL@%
- mov dl, BYTE PTR Col2 %@AB@%; DL = right column%@AE@%%@NL@%
- int 10h %@AB@%; Clear screen by scrolling up%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- ClearBox ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* DisableCga - Disables CGA video by reprogramming the control register.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - cli sti%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- DisableCga PROC USES ax cx dx %@AB@%; Preserve registers%@AE@%%@NL@%
- %@NL@%
- mov cx, -1 %@AB@%; Set maximum loop count%@AE@%%@NL@%
- mov dx, 03DAh %@AB@%; Address of status register%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Get video status%@AE@%%@NL@%
- .UNTILCXZ !(al & 8) %@AB@%; Until retrace end/timeout%@AE@%%@NL@%
- cli %@AB@%; Disallow interruptions%@AE@%%@NL@%
- mov cx, -1 %@AB@%; Reset loop count%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Get video status%@AE@%%@NL@%
- .UNTILCXZ al & 8 %@AB@%; Until retrace start/timeout%@AE@%%@NL@%
- %@NL@%
- sub dx, 2 %@AB@%; DX = address of control reg%@AE@%%@NL@%
- mov al, 1 %@AB@%; Value to disable CGA video%@AE@%%@NL@%
- out dx, al %@AB@%; Disable video%@AE@%%@NL@%
- sti %@AB@%; Reenable interrupts%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- DisableCga ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* EnableCga - Enables CGA video by reprogramming the control register.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- EnableCga PROC USES ax dx es %@AB@%; Preserve registers%@AE@%%@NL@%
- %@NL@%
- sub ax, ax%@NL@%
- mov es, ax %@AB@%; Point ES to low memory%@AE@%%@NL@%
- mov al, es:[0465h] %@AB@%; Get former mode setting%@AE@%%@NL@%
- mov dx, 03D8h %@AB@%; Address of control register%@AE@%%@NL@%
- out dx, al %@AB@%; Enable video%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- EnableCga ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetVer - Gets DOS version.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 30h (Get MS-DOS Version Number)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer of form (M*100)+m, where M is major%@AE@%%@NL@%
- %@AB@%;* version number and m is minor version, or 0 if%@AE@%%@NL@%
- %@AB@%;* DOS version earlier than 2.0%@AE@%%@NL@%
- %@NL@%
- GetVer PROC%@NL@%
- %@NL@%
- mov ah, 30h %@AB@%; DOS Function 30h%@AE@%%@NL@%
- int 21h %@AB@%; Get MS-DOS Version Number%@AE@%%@NL@%
- .IF al == 0 %@AB@%; If version, version 1%@AE@%%@NL@%
- sub ax, ax %@AB@%; Set AX to 0%@AE@%%@NL@%
- .ELSE %@AB@%; Version 2.0 or higher%@AE@%%@NL@%
- sub ch, ch %@AB@%; Zero CH and move minor%@AE@%%@NL@%
- mov cl, ah %@AB@%; version number into CX%@AE@%%@NL@%
- mov bl, 100%@NL@%
- mul bl %@AB@%; Multiply major by 10%@AE@%%@NL@%
- add ax, cx %@AB@%; Add minor to major*10%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret %@AB@%; Return result in AX%@AE@%%@NL@%
- %@NL@%
- GetVer ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%FILE.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\DEMOS\FILE.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL small, pascal, os_dos%@NL@%
- INCLUDE demo.inc%@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* ReadCharAttr - Reads character and display attribute at cursor location.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 8 (Read Character and Attribute%@AE@%%@NL@%
- %@AB@%;* at Cursor)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Attr - Pointer to short integer for display attribute%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with ASCII value of character%@AE@%%@NL@%
- %@NL@%
- ReadCharAttr PROC USES di,%@NL@%
- Attr:PWORD%@NL@%
- %@NL@%
- mov ah, 8 %@AB@%; Function 8%@AE@%%@NL@%
- mov bh, vconfig.dpage %@AB@%; Current page%@AE@%%@NL@%
- int 10h %@AB@%; Read Character and Attribute%@AE@%%@NL@%
- sub bh, bh%@NL@%
- mov bl, ah %@AB@%; BX = attribute%@AE@%%@NL@%
- cbw %@AB@%; AX = character%@AE@%%@NL@%
- LoadPtr es, di, Attr %@AB@%; ES:DI = pointer to int%@AE@%%@NL@%
- mov es:[di], bx %@AB@%; Copy attribute%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- ReadCharAttr ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CopyFile - Copies a file from a specified directory to another. Allows%@AE@%%@NL@%
- %@AB@%;* two different copy methods. See the OpenFile, CloseFile, ReadFile, and%@AE@%%@NL@%
- %@AB@%;* WriteFile procedures for specific examples on opening, closing, reading%@AE@%%@NL@%
- %@AB@%;* from, and writing to files.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Functions - 3Ch (Create File)%@AE@%%@NL@%
- %@AB@%;* 5Bh (Create New File)%@AE@%%@NL@%
- %@AB@%;* Instruction - clc%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Imode - 0 = Create new target file or overwrite existing file%@AE@%%@NL@%
- %@AB@%;* 1 = Abort and return error code if target file already%@AE@%%@NL@%
- %@AB@%;* exists (only for DOS versions 3.0 and higher)%@AE@%%@NL@%
- %@AB@%;* Fspec1 - Pointer to ASCIIZ source file specification%@AE@%%@NL@%
- %@AB@%;* Fspec2 - Pointer to ASCIIZ target file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if error%@AE@%%@NL@%
- %@NL@%
- .DATA%@NL@%
- Buffer BYTE BUFFERSIZE DUP (?) %@AB@%; Buffer for diskette read%@AE@%%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- CopyFile PROC USES ds si di,%@NL@%
- Imode:WORD,%@NL@%
- Fspec1:PBYTE,%@NL@%
- Fspec2:PBYTE%@NL@%
- %@NL@%
- LOCAL eof_flag:BYTE%@NL@%
- %@NL@%
- %@AB@%; Open source file for read only%@AE@%%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec1 %@AB@%; Point DS:DX to source file%@AE@%%@NL@%
- mov ax, 3D00h %@AB@%; AH = function #, AL = access code%@AE@%%@NL@%
- int 21h %@AB@%; Open File (for read only)%@AE@%%@NL@%
- jc e_exit%@NL@%
- mov si, ax %@AB@%; SI = file handle for source%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Open target file according to copy mode%@AE@%%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec2 %@AB@%; Point DS:DX to target file%@AE@%%@NL@%
- .IF Imode != 1 %@AB@%; If Imode (DOS function) is not 1%@AE@%%@NL@%
- mov ah, 3Ch %@AB@%; Request Create File%@AE@%%@NL@%
- .ELSE%@NL@%
- %@NL@%
- %@AB@%; Check DOS version%@AE@%%@NL@%
- INVOKE GetVer%@NL@%
- %@NL@%
- cmp ax, 300 %@AB@%; 3.0 or higher?%@AE@%%@NL@%
- jb close %@AB@%; No? Abort with error code%@AE@%%@NL@%
- mov ah, 5Bh %@AB@%; Request Create New File%@AE@%%@NL@%
- .ENDIF%@NL@%
- sub cx, cx %@AB@%; Normal attribute for target%@AE@%%@NL@%
- int 21h %@AB@%; DOS function for target file%@AE@%%@NL@%
- jc close %@AB@%; If open error, abort%@AE@%%@NL@%
- mov di, ax %@AB@%; DI = file handle for target%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Both files successfully opened. Now read from source and copy to target.%@AE@%%@NL@%
- %@NL@%
- mov ax, @data%@NL@%
- mov ds, ax %@AB@%; DS:DX = buffer. Read/write%@AE@%%@NL@%
- mov dx, OFFSET Buffer %@AB@%; to and from here.%@AE@%%@NL@%
- mov eof_flag, 0 %@AB@%; Initialize end-of-file flag%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov bx, si %@AB@%; Handle for source file%@AE@%%@NL@%
- mov cx, BUFFERSIZE %@AB@%; CX = number of bytes to read%@AE@%%@NL@%
- mov ah, 3Fh %@AB@%; Request DOS read%@AE@%%@NL@%
- int 21h %@AB@%; Read from File%@AE@%%@NL@%
- jc close %@AB@%; If error, exit%@AE@%%@NL@%
- .IF ax != cx %@AB@%; If bytes not read successfully:%@AE@%%@NL@%
- inc eof_flag %@AB@%; Raise flag%@AE@%%@NL@%
- .ENDIF%@NL@%
- mov bx, di %@AB@%; Handle for target file%@AE@%%@NL@%
- mov cx, ax %@AB@%; Write number of bytes read%@AE@%%@NL@%
- mov ah, 40h %@AB@%; Request DOS write%@AE@%%@NL@%
- int 21h %@AB@%; Write from buffer to target file%@AE@%%@NL@%
- jc close %@AB@%; If error, exit%@AE@%%@NL@%
- .UNTIL eof_flag != 0 %@AB@%; Loop to read next block%@AE@%%@NL@%
- clc %@AB@%; Clear CY to indicate%@AE@%%@NL@%
- close:%@NL@%
- pushf %@AB@%; Preserve flags while closing%@AE@%%@NL@%
- mov bx, di %@AB@%; Handle for target file%@AE@%%@NL@%
- mov ah, 3Eh %@AB@%; Request DOS Function 3Eh%@AE@%%@NL@%
- int 21h %@AB@%; Close File%@AE@%%@NL@%
- sub ax, ax %@AB@%; Clear error code%@AE@%%@NL@%
- popf %@AB@%; Recover flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- e_exit:%@NL@%
- mov ax, 1 %@AB@%; Else set error code%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- CopyFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* ChangeDrive - Changes default drive.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 0Eh (Select Disk)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Drive - Uppercase letter designation for new drive%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- ChangeDrive PROC,%@NL@%
- Drive:WORD%@NL@%
- %@NL@%
- mov ah, 0Eh %@AB@%; DOS Function 0Eh%@AE@%%@NL@%
- mov dx, Drive %@AB@%; Drive designation in DL,%@AE@%%@NL@%
- sub dl, 'A' %@AB@%; 0=A, 1=B, 2=C, etc%@AE@%%@NL@%
- int 21h %@AB@%; Select Disk%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- ChangeDrive ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetCurDrive - Gets designation of current drive.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 19h (Get Current Disk)%@AE@%%@NL@%
- %@AB@%;* Instruction - cbw%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with drive designation%@AE@%%@NL@%
- %@AB@%;* 0 = A, 1 = B, 2 = C, etc.%@AE@%%@NL@%
- %@NL@%
- GetCurDrive PROC%@NL@%
- %@NL@%
- mov ah, 19h %@AB@%; DOS Function 19h%@AE@%%@NL@%
- int 21h %@AB@%; Get Current Disk%@AE@%%@NL@%
- cbw %@AB@%; AX = drive designation%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetCurDrive ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* SetDTA - Sets address for new Disk Transfer Area.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 1Ah (Set DTA Address)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Dta - Far pointer to new transfer address%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- SetDTA PROC USES ds,%@NL@%
- Dta:FPBYTE%@NL@%
- %@NL@%
- lds dx, [Dta] %@AB@%; Point DS:DX to DTA%@AE@%%@NL@%
- mov ah, 1Ah %@AB@%; DOS Function 1Ah%@AE@%%@NL@%
- int 21h %@AB@%; Set DTA Address%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- SetDTA ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetDTA - Gets address of current Disk Transfer Area.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 2Fh (Get DTA Address)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Dta - Far pointer to receive transfer address%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- GetDTA PROC,%@NL@%
- Dta:FPBYTE%@NL@%
- %@NL@%
- mov ah, 2Fh %@AB@%; DOS Function 2Fh%@AE@%%@NL@%
- int 21h %@AB@%; Get DTA Address in ES:BX%@AE@%%@NL@%
- mov ax, es %@AB@%; Save DTA segment%@AE@%%@NL@%
- mov dx, bx %@AB@%; Save DTA offset%@AE@%%@NL@%
- les bx, Dta %@AB@%; Now ES:BX points to variable%@AE@%%@NL@%
- mov es:[bx], dx %@AB@%; Copy DTA address to%@AE@%%@NL@%
- mov es:[bx+2], ax %@AB@%; dta variable%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetDTA ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CreateFile - Creates file with specified attribute.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 3Ch (Create File)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Attr - Attribute code: 0 = normal 8 = volume label%@AE@%%@NL@%
- %@AB@%;* 1 = read only 16 = subdirectory%@AE@%%@NL@%
- %@AB@%;* 2 = hidden 32 = archive%@AE@%%@NL@%
- %@AB@%;* 4 = system%@AE@%%@NL@%
- %@AB@%;* Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with file handle or -1 for error%@AE@%%@NL@%
- %@NL@%
- CreateFile PROC USES ds,%@NL@%
- Attr:WORD, Fspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
- mov cx, Attr %@AB@%; CX = attribute%@AE@%%@NL@%
- mov ah, 3Ch %@AB@%; AH = function number%@AE@%%@NL@%
- int 21h %@AB@%; Create file%@AE@%%@NL@%
- .IF carry?%@NL@%
- mov ax, -1 %@AB@%; Set error code%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- CreateFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* OpenFile - Opens specified file for reading or writing. See the CopyFile%@AE@%%@NL@%
- %@AB@%;* procedure for another example of using DOS Function 3Dh to open files.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 3Dh (Open File)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Access - Access code: 0 = read 1 = write 2 = read/write%@AE@%%@NL@%
- %@AB@%;* Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with file handle or -1 for error%@AE@%%@NL@%
- %@NL@%
- OpenFile PROC USES ds,%@NL@%
- Access:WORD, Fspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
- mov ax, Access %@AB@%; AL = access code%@AE@%%@NL@%
- mov ah, 3Dh %@AB@%; AH = function number%@AE@%%@NL@%
- int 21h %@AB@%; Open file%@AE@%%@NL@%
- .IF carry?%@NL@%
- mov ax, -1 %@AB@%; Set error code%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- OpenFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CloseFile - Closes an open file, specified by handle. See the CopyFile%@AE@%%@NL@%
- %@AB@%;* procedure for another example of using DOS Function 3Eh to close files.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 3EH (Close File)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Handle - File handle%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CloseFile PROC,%@NL@%
- Handle:WORD%@NL@%
- %@NL@%
- mov bx, Handle %@AB@%; BX = file handle%@AE@%%@NL@%
- mov ah, 3Eh %@AB@%; DOS Function 3Eh%@AE@%%@NL@%
- int 21h %@AB@%; Close file%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- CloseFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* ReadFile - Read from open file to specified buffer. See the CopyFile%@AE@%%@NL@%
- %@AB@%;* procedure for another example of using DOS Function 3Fh to read files.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 3Fh (Read File or Device)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Handle - File handle%@AE@%%@NL@%
- %@AB@%;* Len - Number of bytes to read%@AE@%%@NL@%
- %@AB@%;* Pbuff - Pointer to buffer%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with number of bytes read, or 0 if read error%@AE@%%@NL@%
- %@NL@%
- ReadFile PROC USES ds di,%@NL@%
- Handle:WORD, Len:WORD, Pbuff:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Pbuff %@AB@%; Point DS:DX to buffer%@AE@%%@NL@%
- mov di, dx %@AB@%; Keep string offset in DI%@AE@%%@NL@%
- mov bx, Handle %@AB@%; BX = handle%@AE@%%@NL@%
- mov cx, Len %@AB@%; CX = number of bytes to read%@AE@%%@NL@%
- mov ah, 3Fh %@AB@%; Request DOS read%@AE@%%@NL@%
- int 21h %@AB@%; Read File%@AE@%%@NL@%
- .IF carry?%@NL@%
- sub ax, ax %@AB@%; Set error code%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- ReadFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* WriteFile - Write ASCIIZ string to file. If Handle = 0, the string is%@AE@%%@NL@%
- %@AB@%;* written to STDOUT (console). See the CopyFile procedure for another%@AE@%%@NL@%
- %@AB@%;* example of using DOS Function 40h to write to files.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 40h (Write File or Device)%@AE@%%@NL@%
- %@AB@%;* Instructions - inc dec%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Handle - File handle%@AE@%%@NL@%
- %@AB@%;* SPtr - Pointer to ASCIIZ string%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if write error%@AE@%%@NL@%
- %@AB@%;* 2 if number of bytes written not equal to string length%@AE@%%@NL@%
- %@NL@%
- WriteFile PROC USES ds di,%@NL@%
- Handle:WORD, Sptr:PBYTE%@NL@%
- %@NL@%
- LoadPtr es, di, Sptr %@AB@%; Point ES:DI to string%@AE@%%@NL@%
- push di %@AB@%; Hold on to string pointer%@AE@%%@NL@%
- mov cx, -1 %@AB@%; Set CX to maximum%@AE@%%@NL@%
- sub al, al %@AB@%; AL = 0%@AE@%%@NL@%
- repne scasb %@AB@%; Scan string for NULL%@AE@%%@NL@%
- pop dx %@AB@%; Recover string pointer%@AE@%%@NL@%
- dec di%@NL@%
- sub di, dx %@AB@%; Get string length (w/o NULL)%@AE@%%@NL@%
- mov cx, di %@AB@%; Put it into CX%@AE@%%@NL@%
- mov bx, Handle %@AB@%; Load BX with handle%@AE@%%@NL@%
- push es %@AB@%; Set DS to ES to ensure%@AE@%%@NL@%
- pop ds %@AB@%; DS:DX points to string%@AE@%%@NL@%
- mov ah, 40h %@AB@%; Request DOS write%@AE@%%@NL@%
- int 21h %@AB@%; Write File or Device%@AE@%%@NL@%
- mov bx, ax %@AB@%; Get number of bytes written%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Set error code, preserve carry%@AE@%%@NL@%
- .IF carry? %@AB@%; If carry:%@AE@%%@NL@%
- inc ax %@AB@%; Increment once for write error%@AE@%%@NL@%
- .ENDIF %@AB@%; carry%@AE@%%@NL@%
- .IF bx != cx %@AB@%; If bytes not all written:%@AE@%%@NL@%
- inc ax %@AB@%; Increment twice%@AE@%%@NL@%
- .ENDIF %@AB@%; bx ! cx%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- WriteFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetDiskSize - Gets size information from specified disk.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 36h (Get Drive Allocation Information)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Drive - Drive code (0 = default, 1 = A, 2 = B, etc.)%@AE@%%@NL@%
- %@AB@%;* Disk - Pointer to a structure with 4 short integer members:%@AE@%%@NL@%
- %@AB@%;* Member 1 - Total clusters on disk%@AE@%%@NL@%
- %@AB@%;* Member 2 - Number of available clusters%@AE@%%@NL@%
- %@AB@%;* Member 3 - Sectors/cluster (-1 if invalid drive)%@AE@%%@NL@%
- %@AB@%;* Member 4 - Bytes/sector%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- GetDiskSize PROC USES di,%@NL@%
- Drive:WORD, Disk:PDISKSTAT%@NL@%
- %@NL@%
- mov dx, Drive %@AB@%; DL = drive code%@AE@%%@NL@%
- mov ah, 36h %@AB@%; DOS Function 36h%@AE@%%@NL@%
- int 21h %@AB@%; Get Drive Allocation Information%@AE@%%@NL@%
- LoadPtr es, di, Disk %@AB@%; ES:DI = disk structure%@AE@%%@NL@%
- mov (DISKSTAT PTR es:[di]).\%@NL@%
- total, dx %@AB@%; DX = total clusters%@AE@%%@NL@%
- mov (DISKSTAT PTR es:[di]).\%@NL@%
- avail, bx %@AB@%; BX = number of free clusters%@AE@%%@NL@%
- mov (DISKSTAT PTR es:[di]).\%@NL@%
- sects, ax %@AB@%; AX = sectors/cluster%@AE@%%@NL@%
- mov (DISKSTAT PTR es:[di]).\%@NL@%
- bytes, cx %@AB@%; CX = bytes/sector%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetDiskSize ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* MakeDir - Creates a specified subdirectory.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 39h (Create Directory)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Pspec - Pointer to ASCIIZ pathname of new subdirectory%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if create error%@AE@%%@NL@%
- %@NL@%
- MakeDir PROC USES ds,%@NL@%
- Pspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Pspec %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
- mov ah, 39h %@AB@%; DOS Function 39h%@AE@%%@NL@%
- int 21h %@AB@%; Create Directory%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Set error code, keep flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- MakeDir ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* RemoveDir - Removes a specified subdirectory.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 3Ah (Delete Directory)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Pspec - Pointer to ASCIIZ pathname of subdirectory%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if delete error or subdirectory not empty%@AE@%%@NL@%
- %@NL@%
- RemoveDir PROC USES ds,%@NL@%
- Pspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Pspec %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
- mov ah, 3Ah %@AB@%; DOS Function 3Ah%@AE@%%@NL@%
- int 21h %@AB@%; Delete Directory%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Set error code, keep flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- RemoveDir ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* ChangeDir - Changes current (default) directory.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 3Bh (Set Current Directory)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Pspec - Pointer to ASCIIZ pathname of target subdirectory%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if delete error or subdirectory not empty%@AE@%%@NL@%
- %@NL@%
- ChangeDir PROC USES ds,%@NL@%
- Pspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Pspec %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
- mov ah, 3Bh %@AB@%; DOS Function 3Bh%@AE@%%@NL@%
- int 21h %@AB@%; Set Current Directory%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Set error code, keep flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- ChangeDir ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* DelFile - Deletes a specified file.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 41h (Delete File)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if delete error%@AE@%%@NL@%
- %@NL@%
- DelFile PROC USES ds,%@NL@%
- Fspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
- mov ah, 41h %@AB@%; DOS Function 41h%@AE@%%@NL@%
- int 21h %@AB@%; Delete File%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Set error code, keep flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- DelFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Rewind - Rewinds an open file, specified by handle. See the GetFileSize%@AE@%%@NL@%
- %@AB@%;* procedure for an example of using Function 42h to determine file size.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 42h (Set File Pointer)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Handle - File handle%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Rewind PROC,%@NL@%
- Handle:WORD%@NL@%
- %@NL@%
- mov bx, Handle %@AB@%; BX = file handle%@AE@%%@NL@%
- mov ax, 4200h %@AB@%; AH = function #,%@AE@%%@NL@%
- %@AB@%; AL = move to beginning of%@AE@%%@NL@%
- sub cx, cx %@AB@%; file plus offset%@AE@%%@NL@%
- sub dx, dx %@AB@%; CX:DX = offset (zero)%@AE@%%@NL@%
- int 21h %@AB@%; Set File Pointer%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- Rewind ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetFileSize - Gets the size of an open file, specified by handle.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 42h (Set File Pointer)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Handle - File handle%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Long integer with file size in bytes%@AE@%%@NL@%
- %@NL@%
- GetFileSize PROC,%@NL@%
- Handle:WORD%@NL@%
- %@NL@%
- mov bx, Handle %@AB@%; BX = file handle%@AE@%%@NL@%
- mov ax, 4202h %@AB@%; AH = function #,%@AE@%%@NL@%
- %@AB@%; AL = move to end of%@AE@%%@NL@%
- sub cx, cx %@AB@%; file plus offset%@AE@%%@NL@%
- sub dx, dx %@AB@%; CX:DX = offset (zero)%@AE@%%@NL@%
- int 21h %@AB@%; Set File Pointer%@AE@%%@NL@%
- mov ax, dx %@AB@%; Set DX:AX = file size in%@AE@%%@NL@%
- mov dx, cx %@AB@%; bytes, return long int%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetFileSize ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetAttribute - Gets the attribute(s) of a specified file.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 43h (Get or Set File Attributes)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with file attribute bits set as follows:%@AE@%%@NL@%
- %@AB@%;* bit 0 = read-only bit 3 = volume label%@AE@%%@NL@%
- %@AB@%;* bit 1 = hidden bit 4 = subdirectory%@AE@%%@NL@%
- %@AB@%;* bit 2 = system bit 5 = archive%@AE@%%@NL@%
- %@AB@%;* 0 indicates normal data file%@AE@%%@NL@%
- %@AB@%;* -1 indicates error%@AE@%%@NL@%
- %@NL@%
- GetAttribute PROC USES ds,%@NL@%
- Fspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec %@AB@%; DS:DX = file specification%@AE@%%@NL@%
- mov ax, 4300h %@AB@%; AH = function #%@AE@%%@NL@%
- %@AB@%; AL = 0 (return attribute)%@AE@%%@NL@%
- int 21h %@AB@%; Get File Attributes%@AE@%%@NL@%
- mov ax, -1 %@AB@%; Set code, keep flags%@AE@%%@NL@%
- .IF !carry?%@NL@%
- mov ax, cx %@AB@%; Return with file attribute bits%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- GetAttribute ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* SetAttribute - Sets the attribute(s) of a specified file.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 43h (Get or Set File Attributes)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Attr - Attribute bits set as follows:%@AE@%%@NL@%
- %@AB@%;* bit 0 = read-only bit 3 = volume label%@AE@%%@NL@%
- %@AB@%;* bit 1 = hidden bit 4 = subdirectory%@AE@%%@NL@%
- %@AB@%;* bit 2 = system bit 5 = archive%@AE@%%@NL@%
- %@AB@%;* (Attr = 0 for normal data file)%@AE@%%@NL@%
- %@AB@%;* Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if delete error%@AE@%%@NL@%
- %@NL@%
- SetAttribute PROC USES ds,%@NL@%
- Attr:WORD,%@NL@%
- Fspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec %@AB@%; DS:DX = file specification%@AE@%%@NL@%
- mov cx, Attr %@AB@%; Put attribute code in CX%@AE@%%@NL@%
- mov ax, 4301h %@AB@%; AH = function #%@AE@%%@NL@%
- %@AB@%; AL = 1 (set attribute)%@AE@%%@NL@%
- int 21h %@AB@%; Set File Attributes%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Clear code, keep flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- SetAttribute ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetCurDir - Gets the current directory of default drive.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 47h (Get Current Directory)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Spec - Pointer to 64-byte buffer to receive directory%@AE@%%@NL@%
- %@AB@%;* path. Path terminates with 0 but does not include%@AE@%%@NL@%
- %@AB@%;* drive and does not begin with backslash.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if delete error or subdirectory not empty%@AE@%%@NL@%
- %@NL@%
- GetCurDir PROC USES ds si,%@NL@%
- Spec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, si, Spec %@AB@%; DS:SI = spec address%@AE@%%@NL@%
- mov ah, 47h %@AB@%; AH = function number%@AE@%%@NL@%
- sub dl, dl %@AB@%; DL = current drive (0)%@AE@%%@NL@%
- int 21h %@AB@%; Get Current Directory%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Set error code, keep flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- GetCurDir ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* FindFirst - Finds first entry in given directory matching specification.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 4Eh (Find First File)%@AE@%%@NL@%
- %@AB@%;* Instructions - pushf popf%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Attr - Attribute code (see header comments for CreateFile)%@AE@%%@NL@%
- %@AB@%;* Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;* Finfo - Pointer to 43-byte buffer to receive%@AE@%%@NL@%
- %@AB@%;* data from matched entry%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if no match found%@AE@%%@NL@%
- %@NL@%
- .DATA%@NL@%
- OldDta FPVOID ? %@AB@%; Storage for old DTA address%@AE@%%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- FindFirst PROC USES ds,%@NL@%
- Attr:WORD,%@NL@%
- Fspec:PBYTE,%@NL@%
- Finfo:PFILEINFO%@NL@%
- %@NL@%
- %@AB@%; Get current DTA address, pass address of pointer to hold value%@AE@%%@NL@%
- INVOKE GetDTA,%@NL@%
- ADDR OldDta%@NL@%
- %@NL@%
- mov cx, Attr %@AB@%; Load CX with file attribute%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Set DTA address, pass pointer to structure%@AE@%%@NL@%
- INVOKE SetDTA,%@NL@%
- Finfo%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
- mov ah, 4Eh %@AB@%; AH = function number%@AE@%%@NL@%
- int 21h %@AB@%; Find First File%@AE@%%@NL@%
- %@NL@%
- pushf %@AB@%; Preserve flags%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Restore DTA address, pass pointer%@AE@%%@NL@%
- INVOKE SetDTA,%@NL@%
- OldDta%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Set error code%@AE@%%@NL@%
- popf %@AB@%; Recover flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- FindFirst ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* FindNext - Finds next entry in given directory matching specification.%@AE@%%@NL@%
- %@AB@%;* (Should be called only after successfully calling the FindFirst procedure.)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 4Fh (Find Next File)%@AE@%%@NL@%
- %@AB@%;* Operator - OFFSET%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Finfo - Pointer to 43-byte buffer. This must be the same buffer%@AE@%%@NL@%
- %@AB@%;* (or a duplicate) returned from the FindFirst procedure.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if no more matches found%@AE@%%@NL@%
- %@NL@%
- FindNext PROC USES ds,%@NL@%
- Finfo:PFILEINFO%@NL@%
- %@NL@%
- %@AB@%; Get current DTA address, pass address of pointer to hold value%@AE@%%@NL@%
- INVOKE GetDTA,%@NL@%
- ADDR OldDta%@NL@%
- %@NL@%
- %@AB@%; Set DTA address, pass pointer to structure%@AE@%%@NL@%
- INVOKE SetDTA,%@NL@%
- Finfo%@NL@%
- %@NL@%
- mov ah, 4Fh %@AB@%; AH = function number%@AE@%%@NL@%
- int 21h %@AB@%; Find Next File%@AE@%%@NL@%
- %@NL@%
- pushf %@AB@%; Preserve flags%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Restore DTA address, pass pointer%@AE@%%@NL@%
- INVOKE SetDTA,%@NL@%
- OldDta%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Set error code%@AE@%%@NL@%
- popf %@AB@%; Recover flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- FindNext ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* RenameFile - Renames specified file.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 56h (Rename File)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Fspec1 - Pointer to old ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;* Fspec2 - Pointer to new ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* The drive must be the same for both arguments, but the path%@AE@%%@NL@%
- %@AB@%;* does not. This allows files to be moved between directories.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if error%@AE@%%@NL@%
- %@NL@%
- RenameFile PROC USES ds di,%@NL@%
- Fspec1:PBYTE,%@NL@%
- Fspec2:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec1 %@AB@%; Point DS:DX to old file spec%@AE@%%@NL@%
- LoadPtr es, di, Fspec2 %@AB@%; Point ES:DI to new file spec%@AE@%%@NL@%
- mov ah, 56h %@AB@%; AH = function number%@AE@%%@NL@%
- int 21h %@AB@%; Rename File%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Clear error code, keep flags%@AE@%%@NL@%
- .IF carry?%@NL@%
- inc ax %@AB@%; Set error code to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- RenameFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetFileTime - Gets date/time for open file specified by handle.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 57h (Get or Set File Date and Time)%@AE@%%@NL@%
- %@AB@%;* Instructions - shl shr%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Handle - Handle of open file%@AE@%%@NL@%
- %@AB@%;* Sptr - Pointer to 18-byte buffer to receive date/time%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if error%@AE@%%@NL@%
- %@NL@%
- GetFileTime PROC USES di,%@NL@%
- Handle:WORD,%@NL@%
- Sptr:PBYTE%@NL@%
- %@NL@%
- mov ax, 5700h %@AB@%; AH = function number%@AE@%%@NL@%
- %@AB@%; AL = get request%@AE@%%@NL@%
- mov bx, Handle %@AB@%; BX = file handle%@AE@%%@NL@%
- int 21h %@AB@%; Get File Date and Time%@AE@%%@NL@%
- mov ax, 1 %@AB@%; Set error code, keep flags%@AE@%%@NL@%
- .IF !carry? %@AB@%; If not carry, continue%@AE@%%@NL@%
- mov bx, cx %@AB@%; Else save time in BX%@AE@%%@NL@%
- mov al, bl %@AB@%; Get low byte of time%@AE@%%@NL@%
- and al, 00011111y %@AB@%; Mask to get 2-second incrs,%@AE@%%@NL@%
- shl al, 1 %@AB@%; convert to seconds%@AE@%%@NL@%
- push ax %@AB@%; Save seconds%@AE@%%@NL@%
- mov cl, 5%@NL@%
- shr bx, cl %@AB@%; Shift minutes into low byte%@AE@%%@NL@%
- mov al, bl %@AB@%; Get new low byte%@AE@%%@NL@%
- and al, 00111111y %@AB@%; Mask to get minutes%@AE@%%@NL@%
- push ax %@AB@%; Save minutes%@AE@%%@NL@%
- mov cl, 6%@NL@%
- shr bx, cl %@AB@%; Shift hours into low byte%@AE@%%@NL@%
- push bx %@AB@%; Save hours%@AE@%%@NL@%
- %@NL@%
- mov bl, dl %@AB@%; Get low byte of date%@AE@%%@NL@%
- and bl, 00011111y %@AB@%; Mask to get day in BX%@AE@%%@NL@%
- mov cl, 5%@NL@%
- shr dx, cl %@AB@%; Shift month into low byte%@AE@%%@NL@%
- mov al, dl %@AB@%; Get new low byte%@AE@%%@NL@%
- and al, 00001111y %@AB@%; Mask to get month%@AE@%%@NL@%
- mov cl, 4%@NL@%
- shr dx, cl %@AB@%; Shift year into low byte%@AE@%%@NL@%
- add dx, 80 %@AB@%; Year is relative to 1980%@AE@%%@NL@%
- push dx %@AB@%; Save year%@AE@%%@NL@%
- push bx %@AB@%; Save day%@AE@%%@NL@%
- push ax %@AB@%; Save month%@AE@%%@NL@%
- %@NL@%
- LoadPtr es, di, Sptr %@AB@%; Point ES:DI to 18-byte%@AE@%%@NL@%
- mov cx, 6 %@AB@%; string%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- pop ax %@AB@%; Get 6 numbers sequentially in AL%@AE@%%@NL@%
- aam %@AB@%; Convert to unpacked BCD%@AE@%%@NL@%
- xchg al, ah %@AB@%; Switch bytes for word move%@AE@%%@NL@%
- or ax, '00' %@AB@%; Make ASCII numerals%@AE@%%@NL@%
- stosw %@AB@%; Copy to string%@AE@%%@NL@%
- mov al, '-' %@AB@%; Separator for date text%@AE@%%@NL@%
- cmp cl, 4 %@AB@%; First 3 iters are for date%@AE@%%@NL@%
- jg @F %@AB@%; If CX=6 or 5, insert hyphen%@AE@%%@NL@%
- mov al, ' ' %@AB@%; Separator date and time%@AE@%%@NL@%
- je @F %@AB@%; If CX = 4, insert hyphen%@AE@%%@NL@%
- mov al, ':' %@AB@%; Separator for time text%@AE@%%@NL@%
- .IF cl != 1%@NL@%
- @@: stosb %@AB@%; Copy separator to string%@AE@%%@NL@%
- .ENDIF%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Clear return code%@AE@%%@NL@%
- stosb %@AB@%; Terminate string with null%@AE@%%@NL@%
- .ENDIF %@AB@%; to make ASCIIZ%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetFileTime ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* UniqueFile - Creates and opens a new file with a name unique to the%@AE@%%@NL@%
- %@AB@%;* specified directory. The name is manufactured from the current time,%@AE@%%@NL@%
- %@AB@%;* making it useful for temporary files. For DOS versions 3.0 and higher.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 5Ah (Create Temporary File)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Attr - Attribute code (see header comments for CreateFile)%@AE@%%@NL@%
- %@AB@%;* Pspec - Pointer to ASCIIZ path specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with file handle or -1 for error%@AE@%%@NL@%
- %@NL@%
- UniqueFile PROC USES ds,%@NL@%
- Attr:WORD,%@NL@%
- Pspec:PBYTE%@NL@%
- %@NL@%
- %@AB@%; Get DOS version%@AE@%%@NL@%
- INVOKE GetVer%@NL@%
- %@NL@%
- cmp ax, 300 %@AB@%; 3.0 or higher?%@AE@%%@NL@%
- jb e_exit %@AB@%; No? Quit with error%@AE@%%@NL@%
- LoadPtr ds, dx, Pspec %@AB@%; Point DS:DX to path spec%@AE@%%@NL@%
- mov cx, Attr %@AB@%; CX = attribute%@AE@%%@NL@%
- mov ah, 5Ah %@AB@%; AH = function number%@AE@%%@NL@%
- int 21h %@AB@%; Create Temporary File%@AE@%%@NL@%
- .IF carry?%@NL@%
- e_exit: mov ax, -1 %@AB@%; Set error code%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- UniqueFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CreateNewFile - Creates a new file with specified attribute. Differs%@AE@%%@NL@%
- %@AB@%;* from the CreateFile procedure in that it returns an error if file%@AE@%%@NL@%
- %@AB@%;* already exists. For DOS versions 3.0 and higher.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 5Bh (Create New File)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Attr - Attribute code (see header comments for CreateFile)%@AE@%%@NL@%
- %@AB@%;* Fspec - Pointer to ASCIIZ file specification%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with file handle or -1 for error%@AE@%%@NL@%
- %@NL@%
- CreateNewFile PROC USES ds,%@NL@%
- Attr:WORD,%@NL@%
- Fspec:PBYTE%@NL@%
- %@NL@%
- LoadPtr ds, dx, Fspec %@AB@%; Point DS:DX to file spec%@AE@%%@NL@%
- mov cx, Attr %@AB@%; CX = attribute%@AE@%%@NL@%
- mov ah, 5Bh %@AB@%; AH = function number%@AE@%%@NL@%
- int 21h %@AB@%; Create New File%@AE@%%@NL@%
- .IF carry?%@NL@%
- mov ax, -1 %@AB@%; Set error code%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- CreateNewFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* StrCompare - Compares two strings for equality. See StrWrite, StrFindChar,%@AE@%%@NL@%
- %@AB@%;* WinOpen, and WinClose procedures for other examples of string instructions.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - cmpsb cmpsw repe jcxz%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Sptr1 - Pointer to first string%@AE@%%@NL@%
- %@AB@%;* Sptr2 - Pointer to second string%@AE@%%@NL@%
- %@AB@%;* Len - Length in bytes for comparison. Strings need not be of%@AE@%%@NL@%
- %@AB@%;* equal length; however if len is an even number, comparison%@AE@%%@NL@%
- %@AB@%;* is made on a word-by-word basis and thus is more efficient.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Null pointer if strings match; else pointer to string #1 where%@AE@%%@NL@%
- %@AB@%;* match failed.%@AE@%%@NL@%
- %@NL@%
- StrCompare PROC USES ds di si,%@NL@%
- Sptr1:PBYTE,%@NL@%
- Sptr2:PBYTE,%@NL@%
- Len:WORD%@NL@%
- %@NL@%
- LoadPtr es, di, Sptr1 %@AB@%; ES:DI points to string #1%@AE@%%@NL@%
- LoadPtr ds, si, Sptr2 %@AB@%; DS:SI points to string #2%@AE@%%@NL@%
- mov cx, Len %@AB@%; Length of search in bytes%@AE@%%@NL@%
- and al, 0 %@AB@%; Set ZR flag in case CX = 0%@AE@%%@NL@%
- .IF cx != 0 %@AB@%; If length is not 0:%@AE@%%@NL@%
- .IF !(cl & 1) %@AB@%; If not even number:%@AE@%%@NL@%
- repe cmpsb %@AB@%; Compare byte-by-byte%@AE@%%@NL@%
- .ELSE %@AB@%; Else compare word-by-word%@AE@%%@NL@%
- shr cx, 1 %@AB@%; Decrease count by half%@AE@%%@NL@%
- repe cmpsw %@AB@%; Compare word-by-word%@AE@%%@NL@%
- sub di, 2 %@AB@%; Back up 2 characters%@AE@%%@NL@%
- sub si, 2%@NL@%
- cmpsb %@AB@%; Match?%@AE@%%@NL@%
- .IF zero? %@AB@%; No? Then failure%@AE@%%@NL@%
- cmpsb %@AB@%; Compare last characters%@AE@%%@NL@%
- .ENDIF %@AB@%; zero%@AE@%%@NL@%
- .ENDIF %@AB@%; cl & 1%@AE@%%@NL@%
- .ENDIF %@AB@%; cx != 0%@AE@%%@NL@%
- %@NL@%
- mov ax, 0 %@AB@%; Set null pointer without%@AE@%%@NL@%
- mov dx, 0 %@AB@%; disturbing flags%@AE@%%@NL@%
- .IF !zero? %@AB@%; If no match:%@AE@%%@NL@%
- dec di %@AB@%; Point to failure%@AE@%%@NL@%
- mov ax, di%@NL@%
- mov dx, es%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- StrCompare ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* StrFindChar - Finds first occurence of character in given ASCIIZ string,%@AE@%%@NL@%
- %@AB@%;* searching either from beginning or end of string. See StrWrite, WinOpen,%@AE@%%@NL@%
- %@AB@%;* WinClose, and StrCompare procedures for other examples of string%@AE@%%@NL@%
- %@AB@%;* instructions.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - repne scasb cld std%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Ichar - Character to search for%@AE@%%@NL@%
- %@AB@%;* Sptr - Pointer to ASCIIZ string in which to search%@AE@%%@NL@%
- %@AB@%;* Direct - Direction flag:%@AE@%%@NL@%
- %@AB@%;* 0 = search from start to end%@AE@%%@NL@%
- %@AB@%;* 1 = search from end to start%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Null pointer if character not found, else pointer to string where%@AE@%%@NL@%
- %@AB@%;* character first encountered%@AE@%%@NL@%
- %@NL@%
- StrFindChar PROC USES ds di si,%@NL@%
- IChar:SBYTE,%@NL@%
- Sptr:PBYTE,%@NL@%
- Direct:WORD%@NL@%
- %@NL@%
- LoadPtr es, di, Sptr %@AB@%; ES:DI points to string%@AE@%%@NL@%
- LoadPtr ds, si, Sptr %@AB@%; as does DS:SI%@AE@%%@NL@%
- mov cx, -1 %@AB@%; Set scan counter to maximum%@AE@%%@NL@%
- mov bx, cx %@AB@%; BX = max string tail%@AE@%%@NL@%
- cld %@AB@%; Assume head-to-tail search%@AE@%%@NL@%
- %@NL@%
- .IF Direct != 0 %@AB@%; If assumption correct:%@AE@%%@NL@%
- mov bx, di %@AB@%; Set BX to byte before%@AE@%%@NL@%
- dec bx %@AB@%; string head and scan%@AE@%%@NL@%
- sub al, al %@AB@%; string for null terminator%@AE@%%@NL@%
- push cx %@AB@%; to find string tail%@AE@%%@NL@%
- repne scasb%@NL@%
- pop cx %@AB@%; Recover scan counter%@AE@%%@NL@%
- dec di %@AB@%; Backup pointer to last%@AE@%%@NL@%
- dec di %@AB@%; character in string and%@AE@%%@NL@%
- mov si, di %@AB@%; begin search from there%@AE@%%@NL@%
- std %@AB@%; Set direction flag%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- lodsb %@AB@%; Get first char from string%@AE@%%@NL@%
- .IF (si == bx) || (al == 0) %@AB@%; If at head or tail limit:%@AE@%%@NL@%
- sub ax, ax %@AB@%; No match%@AE@%%@NL@%
- sub dx, dx %@AB@%; Set null pointer%@AE@%%@NL@%
- jmp exit%@NL@%
- .ENDIF%@NL@%
- .UNTILCXZ al == IChar%@NL@%
- %@NL@%
- mov ax, si %@AB@%; Match, so point to first%@AE@%%@NL@%
- dec ax %@AB@%; occurence%@AE@%%@NL@%
- .IF Direct != 0 %@AB@%; If head-to-tail search:%@AE@%%@NL@%
- inc ax %@AB@%; Adjust pointer forward%@AE@%%@NL@%
- inc ax%@NL@%
- mov dx, ds %@AB@%; Pointer segment%@AE@%%@NL@%
- .ENDIF%@NL@%
- exit:%@NL@%
- ret%@NL@%
- %@NL@%
- StrFindChar ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetStr - Gets a string of up to 128 characters from the user. Since%@AE@%%@NL@%
- %@AB@%;* this function uses the DOS input mechanism, it can use the DOS editing%@AE@%%@NL@%
- %@AB@%;* keys or the keys of a DOS command-line editor if one is loaded.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 0Ah (Buffered Keyboard Input)%@AE@%%@NL@%
- %@AB@%;* Directive - EQU%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Strbuf - Pointer to area where input string will be placed%@AE@%%@NL@%
- %@AB@%;* Maxlen - Maximum length (up to 128 characters) of string%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: 0 if successful, 1 if error (Maxlen is too long)%@AE@%%@NL@%
- %@NL@%
- .DATA%@NL@%
- MAXSTR EQU 128%@NL@%
- max BYTE MAXSTR%@NL@%
- actual BYTE ?%@NL@%
- string BYTE MAXSTR DUP (?)%@NL@%
- %@NL@%
- .CODE%@NL@%
- GetStr PROC USES si di,%@NL@%
- Strbuf:PBYTE,%@NL@%
- Maxlen:WORD%@NL@%
- %@NL@%
- mov ax, 1 %@AB@%; Assume error%@AE@%%@NL@%
- mov cx, Maxlen %@AB@%; Copy length to register%@AE@%%@NL@%
- %@NL@%
- .IF (cx != 0) && (cx <= MAXSTR) %@AB@%; Error if 0 or too long%@AE@%%@NL@%
- mov max, cl %@AB@%; Load maximum length%@AE@%%@NL@%
- mov ah, 0Ah %@AB@%; Request DOS Function 0Ah%@AE@%%@NL@%
- mov dx, OFFSET max %@AB@%; Load offset of string%@AE@%%@NL@%
- int 21h %@AB@%; Buffered Keyboard Input%@AE@%%@NL@%
- %@NL@%
- mov bl, actual %@AB@%; Put number of characters read%@AE@%%@NL@%
- sub bh, bh %@AB@%; in BX%@AE@%%@NL@%
- mov string[bx], 0 %@AB@%; Null-terminate string%@AE@%%@NL@%
- mov cx, bx %@AB@%; Put count in CX%@AE@%%@NL@%
- inc cx %@AB@%; Plus one for the null terminator%@AE@%%@NL@%
- %@NL@%
- LoadPtr es, di, Strbuf %@AB@%; ES:DI points to destination buffer%@AE@%%@NL@%
- mov si, OFFSET string %@AB@%; DS:SI points to source string%@AE@%%@NL@%
- rep movsb %@AB@%; Copy source to destination%@AE@%%@NL@%
- sub ax, ax %@AB@%; Return 0 for success%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- GetStr ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%FORTRAN.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\MIXED\FORTRAN.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Power2 routine called by FMAIN.FOR%@AE@%%@NL@%
- %@AB@%; Assemble with ML /c FORTRAN.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL LARGE, FORTRAN%@NL@%
- %@NL@%
- Power2 PROTO FORTRAN, factor:FAR PTR SWORD, power:FAR PTR SWORD%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- Power2 PROC FORTRAN, factor:FAR PTR SWORD, power:FAR PTR SWORD%@NL@%
- %@NL@%
- les bx, factor%@NL@%
- mov ax, ES:[bx]%@NL@%
- les bx, power%@NL@%
- mov cx, ES:[bx]%@NL@%
- shl ax, cl%@NL@%
- ret%@NL@%
- Power2 ENDP%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%HANDLERS.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\TSR\HANDLERS.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL small, pascal, os_dos%@NL@%
- %@NL@%
- %@AB@%; Prototypes for internal procedures%@AE@%%@NL@%
- Activate PROTO NEAR%@NL@%
- CheckRequest PROTO NEAR%@NL@%
- CheckDos PROTO NEAR%@NL@%
- CheckHardware PROTO NEAR%@NL@%
- GetDosFlags PROTO NEAR%@NL@%
- %@NL@%
- INCLUDE tsr.inc%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%; Stack buffer used by TSR. Size is determined by constant STACK_SIZ,%@AE@%%@NL@%
- %@AB@%; declared in TSR.INC file. NewStack points to top of stack.%@AE@%%@NL@%
- %@NL@%
- EVEN%@NL@%
- BYTE STACK_SIZ DUP(?) %@AB@%; Stack buffer%@AE@%%@NL@%
- NewStack LABEL BYTE %@AB@%; Pointer to top of stack%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Structures for interrupt handlers or "interrupt service routines".%@AE@%%@NL@%
- %@AB@%; The following handlers are replaced during installation. Such routines%@AE@%%@NL@%
- %@AB@%; usually set a flag to indicate they are active, optionally do some%@AE@%%@NL@%
- %@AB@%; processing (such as detecting a hot key), call the old system interrupt%@AE@%%@NL@%
- %@AB@%; routine, and when finished clear the active flag.%@AE@%%@NL@%
- %@NL@%
- HandArray LABEL BYTE %@AB@%; Array of handler structures%@AE@%%@NL@%
- %@AB@%; Num Flag OldHand NewHand%@AE@%%@NL@%
- intClock INTR < 8h, FALSE, NULL, Clock>%@NL@%
- intKeybrd INTR < 9h, FALSE, NULL, Keybrd>%@NL@%
- intVideo INTR <10h, FALSE, NULL, Video>%@NL@%
- intDiskIO INTR <13h, FALSE, NULL, DiskIO>%@NL@%
- intMisc INTR <15h, FALSE, NULL, SkipMiscServ>%@NL@%
- intIdle INTR <28h, FALSE, NULL, Idle>%@NL@%
- intMultex INTR <2Fh, FALSE, NULL, Multiplex>%@NL@%
- %@NL@%
- CHAND EQU ($ - HandArray) / (SIZEOF INTR) %@AB@%; Number of handlers in array%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Interrupt trap routines. These interrupt routines are set up%@AE@%%@NL@%
- %@AB@%; temporarily to trap keyboard break errors and critical errors%@AE@%%@NL@%
- %@AB@%; while the TSR is active. When the TSR finishes its tasks, it%@AE@%%@NL@%
- %@AB@%; restores the old interrupts before returning.%@AE@%%@NL@%
- %@NL@%
- TrapArray LABEL BYTE %@AB@%; Array of trap structures%@AE@%%@NL@%
- %@AB@%; Num Flag OldHand NewHand%@AE@%%@NL@%
- intCtrlBk INTR <1Bh, FALSE, NULL, CtrlBreak>%@NL@%
- intCtrlC INTR <23h, FALSE, NULL, CtrlC>%@NL@%
- intCritEr INTR <24h, FALSE, NULL, CritError>%@NL@%
- %@NL@%
- CTRAP EQU ($ - TrapArray) / (SIZEOF INTR) %@AB@%; Number of traps in array%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Address of application's stack. Before calling the main body of the TSR,%@AE@%%@NL@%
- %@AB@%; the Activate procedure stores the application's stack address, then resets%@AE@%%@NL@%
- %@AB@%; SS:SP to point to LABEL NewStack (see above). This gives the TSR its own%@AE@%%@NL@%
- %@AB@%; stack space without making demands on the current stack. Activate restores%@AE@%%@NL@%
- %@AB@%; the application's stack before returning.%@AE@%%@NL@%
- %@NL@%
- OldStackAddr FPVOID ? %@AB@%; SS:SP pointer to application stack%@AE@%%@NL@%
- %@NL@%
- %@AB@%; The TSR must set up its own disk transfer area if it calls DOS functions%@AE@%%@NL@%
- %@AB@%; that use the DTA (see Section 17.5.3 of the Programmer's Guide). DTA_SIZ%@AE@%%@NL@%
- %@AB@%; is defined in the TSR.INC include file.%@AE@%%@NL@%
- %@NL@%
- IFDEF DTA_SIZ%@NL@%
- OldDtaAddr FPVOID ? %@AB@%; Address of application's DTA%@AE@%%@NL@%
- DtaBuff BYTE DTA_SIZ DUP(?) %@AB@%; DTA buffer%@AE@%%@NL@%
- ENDIF%@NL@%
- %@NL@%
- %@AB@%; Multiplex data. STR_LEN is defined in the TSR.INC include file%@AE@%%@NL@%
- %@NL@%
- IDnumber BYTE 0 %@AB@%; TSR's identity number%@AE@%%@NL@%
- IDstring BYTE STR_LEN DUP (0) %@AB@%; Copy of identifier string%@AE@%%@NL@%
- IDstrlen WORD ? %@AB@%; Length of identifier string%@AE@%%@NL@%
- ShareAddr FPVOID ? %@AB@%; Address of shared memory%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Miscellaneous data%@AE@%%@NL@%
- %@NL@%
- TsrRequestFlag BYTE FALSE %@AB@%; Flag set when hot key is pressed%@AE@%%@NL@%
- TsrActiveFlag BYTE FALSE %@AB@%; Flag set when TSR executes%@AE@%%@NL@%
- BreakCheckFlag BYTE ? %@AB@%; Break-checking status of application%@AE@%%@NL@%
- TsrPspSeg WORD ? %@AB@%; Segment address of PSP%@AE@%%@NL@%
- TsrAddr FPVOID ? %@AB@%; Pointer to main part of TSR%@AE@%%@NL@%
- CritErrAddr FPVOID ? %@AB@%; Pointer to MS-DOS critical error flag%@AE@%%@NL@%
- InDosAddr FPVOID ? %@AB@%; Pointer to MS-DOS InDos flag%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Scan and shift codes for hot key. Install procedure initializes%@AE@%%@NL@%
- %@AB@%; HotScan, HotShift, and HotMask during installation.%@AE@%%@NL@%
- %@NL@%
- HotScan BYTE ? %@AB@%; Scan code hot key%@AE@%%@NL@%
- HotShift BYTE ? %@AB@%; Shift value of hot key%@AE@%%@NL@%
- HotMask BYTE ? %@AB@%; Mask unwanted shift values%@AE@%%@NL@%
- %@NL@%
- Version LABEL WORD %@AB@%; DOS version number%@AE@%%@NL@%
- minor BYTE ?%@NL@%
- major BYTE ?%@NL@%
- %@NL@%
- %@AB@%; Timer data, used when the TSR is activated at a preset time instead%@AE@%%@NL@%
- %@AB@%; of activated from the keyboard. The following variables serve the%@AE@%%@NL@%
- %@AB@%; same purposes as the counter variables used in the ALARM.ASM program%@AE@%%@NL@%
- %@AB@%; presented in Section 17.3 of the Programmer's Guide. Refer to the%@AE@%%@NL@%
- %@AB@%; header comments in the Install procedure for an explanation of how%@AE@%%@NL@%
- %@AB@%; to set up a time-activated TSR.%@AE@%%@NL@%
- %@NL@%
- Tick91 BYTE 91 %@AB@%; Measures 91 timer ticks (5 seconds)%@AE@%%@NL@%
- CountDown WORD 0 %@AB@%; Counts 5-second intervals%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Clock - Interrupt handler for Interrupt 08 (timer). Executes at each%@AE@%%@NL@%
- %@AB@%;* timer interrupt, which occur an average of 18.2 times per second. Clock%@AE@%%@NL@%
- %@AB@%;* first allows the original timer service routine to execute. It then%@AE@%%@NL@%
- %@AB@%;* checks the flag TsrRequestFlag maintained either by the keyboard handler%@AE@%%@NL@%
- %@AB@%;* (if keyboard-activated) or by this procedure (if time-activated). If%@AE@%%@NL@%
- %@AB@%;* TsrRequestFlag = TRUE and system is okay, Clock invokes the TSR by%@AE@%%@NL@%
- %@AB@%;* calling the Activate procedure. Uses an active flag to prevent the%@AE@%%@NL@%
- %@AB@%;* Clock procedure from being reentered while executing.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: intClock, TsrActiveFlag, CountDown%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Clock PROC FAR%@NL@%
- %@NL@%
- pushf %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
- call cs:intClock.OldHand %@AB@%; far-calling orig Int 08 routine%@AE@%%@NL@%
- %@NL@%
- .IF cs:intClock.Flag == FALSE %@AB@%; If not already in this handler:%@AE@%%@NL@%
- mov cs:intClock.Flag, TRUE %@AB@%; Set active flag%@AE@%%@NL@%
- %@NL@%
- sti %@AB@%; Interrupts are okay%@AE@%%@NL@%
- push ds %@AB@%; Save application's DS%@AE@%%@NL@%
- push cs%@NL@%
- pop ds %@AB@%; Set DS to resident code segment%@AE@%%@NL@%
- ASSUME ds:@code%@NL@%
- %@NL@%
- INVOKE CheckRequest %@AB@%; Check conditions%@AE@%%@NL@%
- .IF !carry? %@AB@%; If TSR requested and safe:%@AE@%%@NL@%
- mov TsrActiveFlag, TRUE %@AB@%; Activate TSR%@AE@%%@NL@%
- INVOKE Activate%@NL@%
- mov TsrActiveFlag, FALSE%@NL@%
- .ENDIF %@AB@%; End carry flag check%@AE@%%@NL@%
- %@NL@%
- cmp CountDown, 0 %@AB@%; If CountDown = 0, TSR is not time-%@AE@%%@NL@%
- je ticked %@AB@%; activated or has already executed%@AE@%%@NL@%
- dec Tick91 %@AB@%; Else count down 91 timer ticks%@AE@%%@NL@%
- jnz ticked %@AB@%; If 91 ticks have not elapsed, exit%@AE@%%@NL@%
- mov Tick91, 91 %@AB@%; Else reset secondary counter and%@AE@%%@NL@%
- dec CountDown %@AB@%; subract one 5-second interval%@AE@%%@NL@%
- ja ticked %@AB@%; If counter not yet drained, exit%@AE@%%@NL@%
- mov TsrRequestFlag, TRUE %@AB@%; Else raise request flag%@AE@%%@NL@%
- ticked:%@NL@%
- mov intClock.Flag, FALSE %@AB@%; Clear active flag%@AE@%%@NL@%
- pop ds %@AB@%; Recover application's DS%@AE@%%@NL@%
- ASSUME ds:NOTHING%@NL@%
- %@NL@%
- .ENDIF %@AB@%; End in-handler check%@AE@%%@NL@%
- iret%@NL@%
- %@NL@%
- Clock ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Keybrd - Interrupt handler for Interrupt 09 (keyboard).%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* IBM PC/AT and compatibles:%@AE@%%@NL@%
- %@AB@%;* Gets the scan code of the current keystroke from port 60h. Then%@AE@%%@NL@%
- %@AB@%;* compares the scan code and shift state to the hot key. If they%@AE@%%@NL@%
- %@AB@%;* match, sets TsrRequestFlag to signal the handlers Clock and Idle%@AE@%%@NL@%
- %@AB@%;* that the TSR is requested.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* IBM PS/2 series:%@AE@%%@NL@%
- %@AB@%;* Only the instructions at KeybrdMonitor (see below) are installed%@AE@%%@NL@%
- %@AB@%;* as Interrupt 09 handler, since above method should not be used to%@AE@%%@NL@%
- %@AB@%;* determine current keystroke in IBM PS/2 series. In this case, the%@AE@%%@NL@%
- %@AB@%;* Interrupt 15h handler MiscServ takes care of checking the scan codes%@AE@%%@NL@%
- %@AB@%;* and setting the request flag when the hot key is pressed.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Time-activated TSRs:%@AE@%%@NL@%
- %@AB@%;* If the TSR is activated by time instead of by a hotkey, KeybrdMonitor%@AE@%%@NL@%
- %@AB@%;* serves as the Interrupt 09 handler for both PC/AT and PS/2 systems.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: intKeybrd, TsrRequestFlag%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Keybrd PROC FAR%@NL@%
- %@NL@%
- sti %@AB@%; Interrupts are okay%@AE@%%@NL@%
- push ax %@AB@%; Save AX register%@AE@%%@NL@%
- in al, 60h %@AB@%; AL = scan code of current key%@AE@%%@NL@%
- call CheckHotKey %@AB@%; Check for hot key%@AE@%%@NL@%
- .IF !carry? %@AB@%; If not hot key:%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Hot key pressed. Reset the keyboard to throw away keystroke.%@AE@%%@NL@%
- %@NL@%
- cli %@AB@%; Disable interrupts while resetting%@AE@%%@NL@%
- in al, 61h %@AB@%; Get current port 61h state%@AE@%%@NL@%
- or al, 10000000y %@AB@%; Turn on bit 7 to signal clear keybrd%@AE@%%@NL@%
- out 61h, al %@AB@%; Send to port%@AE@%%@NL@%
- and al, 01111111y %@AB@%; Turn off bit 7 to signal break%@AE@%%@NL@%
- out 61h, al %@AB@%; Send to port%@AE@%%@NL@%
- mov al, 20h %@AB@%; Reset interrupt controller%@AE@%%@NL@%
- out 20h, al%@NL@%
- sti %@AB@%; Reenable interrupts%@AE@%%@NL@%
- %@NL@%
- pop ax %@AB@%; Recover AX%@AE@%%@NL@%
- mov cs:TsrRequestFlag, TRUE %@AB@%; Raise request flag%@AE@%%@NL@%
- iret %@AB@%; Exit interrupt handler%@AE@%%@NL@%
- .ENDIF %@AB@%; End hot-key check%@AE@%%@NL@%
- %@NL@%
- %@AB@%; No hot key was pressed, so let normal Int 09 service routine take over%@AE@%%@NL@%
- %@NL@%
- pop ax %@AB@%; Recover AX and fall through%@AE@%%@NL@%
- cli %@AB@%; Interrupts cleared for service%@AE@%%@NL@%
- %@NL@%
- KeybrdMonitor LABEL FAR %@AB@%; Installed as Int 09 handler for%@AE@%%@NL@%
- %@AB@%; PS/2 or for time-activated TSR%@AE@%%@NL@%
- mov cs:intKeybrd.Flag, TRUE %@AB@%; Signal that interrupt is busy%@AE@%%@NL@%
- pushf %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
- call cs:intKeybrd.OldHand %@AB@%; far-calling old Int 09 routine%@AE@%%@NL@%
- mov cs:intKeybrd.Flag, FALSE%@NL@%
- iret%@NL@%
- %@NL@%
- Keybrd ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Video - Interrupt handler for Interrupt 10h (video). Allows the original%@AE@%%@NL@%
- %@AB@%;* video service routine to execute. Maintains an active flag to prevent%@AE@%%@NL@%
- %@AB@%;* the TSR from being called while Interrupt 10h is executing.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: intVideo%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Registers passed to Interrupt 10h%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Registers returned by Interrupt 10h%@AE@%%@NL@%
- %@NL@%
- Video PROC FAR%@NL@%
- %@NL@%
- mov cs:intVideo.Flag, TRUE %@AB@%; Set active flag%@AE@%%@NL@%
- pushf %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
- call cs:intVideo.OldHand %@AB@%; far-calling old Int 10h routine%@AE@%%@NL@%
- mov cs:intVideo.Flag, FALSE %@AB@%; Clear active flag%@AE@%%@NL@%
- iret%@NL@%
- %@NL@%
- Video ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* DiskIO - Interrupt handler for Interrupt 13h (disk I/O). Allows the%@AE@%%@NL@%
- %@AB@%;* original disk I/O service routine to execute. Maintains an active flag%@AE@%%@NL@%
- %@AB@%;* to prevent the TSR from being called while Interrupt 13h is executing.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: intDiskIO%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Registers passed to Interrupt 13h%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Registers and the carry flag returned by Interrupt 13h%@AE@%%@NL@%
- %@NL@%
- DiskIO PROC FAR%@NL@%
- %@NL@%
- mov cs:intDiskIO.Flag, TRUE %@AB@%; Set active flag%@AE@%%@NL@%
- pushf %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
- call cs:intDiskIO.OldHand %@AB@%; far-calling old Int 13h routine%@AE@%%@NL@%
- mov cs:intDiskIO.Flag, FALSE%@AB@%; Clear active flag without%@AE@%%@NL@%
- %@AB@%; disturbing flags register%@AE@%%@NL@%
- sti %@AB@%; Enable interrupts%@AE@%%@NL@%
- ret 2 %@AB@%; Simulate IRET without popping flags%@AE@%%@NL@%
- %@AB@%; (since services use carry flag)%@AE@%%@NL@%
- DiskIO ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* MiscServ - Interrupt handler for Interrupt 15h (Miscellaneous System%@AE@%%@NL@%
- %@AB@%;* Services).%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* IBM PC/AT and compatibles:%@AE@%%@NL@%
- %@AB@%;* Stub at SkipMiscServ is used as handler, bypassing all calls to%@AE@%%@NL@%
- %@AB@%;* Interrupt 15h. Keypresses are checked by Keybrd (Int 09 handler).%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* IBM PS/2 series:%@AE@%%@NL@%
- %@AB@%;* This procedure handles calls to Interrupt 15h, searching for%@AE@%%@NL@%
- %@AB@%;* Function 4Fh (Keyboard Intercept Service). When AH = 4Fh, gets%@AE@%%@NL@%
- %@AB@%;* scan code of current keystroke in AL register. Then compares the%@AE@%%@NL@%
- %@AB@%;* scan code and shift state to the hot key. If they match, sets%@AE@%%@NL@%
- %@AB@%;* TsrRequestFlag to signal the handlers Clock and Idle that the%@AE@%%@NL@%
- %@AB@%;* TSR is requested.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: intMisc, TsrRequestFlag%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Registers passed to Interrupt 15h%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Registers returned by Interrupt 15h%@AE@%%@NL@%
- %@NL@%
- MiscServ PROC FAR%@NL@%
- %@NL@%
- sti %@AB@%; Interrupts okay%@AE@%%@NL@%
- .IF ah == 4Fh %@AB@%; If Keyboard Intercept Service:%@AE@%%@NL@%
- push ax %@AB@%; Preserve AX%@AE@%%@NL@%
- call CheckHotKey %@AB@%; Check for hot key%@AE@%%@NL@%
- pop ax%@NL@%
- .IF !carry? %@AB@%; If hot key:%@AE@%%@NL@%
- mov cs:TsrRequestFlag, TRUE %@AB@%; Raise request flag%@AE@%%@NL@%
- clc %@AB@%; Signal BIOS not to process the key%@AE@%%@NL@%
- ret 2 %@AB@%; Simulate IRET without popping flags%@AE@%%@NL@%
- .ENDIF %@AB@%; End carry flag check%@AE@%%@NL@%
- .ENDIF %@AB@%; End Keyboard Intercept check%@AE@%%@NL@%
- %@NL@%
- cli %@AB@%; Disable interrupts and fall through%@AE@%%@NL@%
- %@NL@%
- SkipMiscServ LABEL FAR %@AB@%; Interrupt 15h handler if PC/AT%@AE@%%@NL@%
- %@NL@%
- jmp cs:intMisc.OldHand%@NL@%
- %@NL@%
- MiscServ ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CtrlBreak - Interrupt trap for Interrupt 1Bh (CTRL+BREAK Handler).%@AE@%%@NL@%
- %@AB@%;* Disables CTRL+BREAK processing.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CtrlBreak PROC FAR%@NL@%
- %@NL@%
- iret%@NL@%
- %@NL@%
- CtrlBreak ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CtrlC - Interrupt trap for Interrupt 23h (CTRL+C Handler).%@AE@%%@NL@%
- %@AB@%;* Disables CTRL+C processing.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CtrlC PROC FAR%@NL@%
- %@NL@%
- iret%@NL@%
- %@NL@%
- CtrlC ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CritError - Interrupt trap for Interrupt 24h (Critical Error Handler).%@AE@%%@NL@%
- %@AB@%;* Disables critical error processing.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AL = Stop code 0 or 3%@AE@%%@NL@%
- %@NL@%
- CritError PROC FAR%@NL@%
- %@NL@%
- sti%@NL@%
- sub al, al %@AB@%; Assume DOS 2.x%@AE@%%@NL@%
- %@AB@%; Set AL = 0 for ignore error%@AE@%%@NL@%
- .IF cs:major != 2 %@AB@%; If DOS 3.x, set AL = 3%@AE@%%@NL@%
- mov al, 3 %@AB@%; DOS call fails%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- iret%@NL@%
- %@NL@%
- CritError ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Idle - Interrupt handler for Interrupt 28h (DOS Idle). Allows the%@AE@%%@NL@%
- %@AB@%;* original Interrupt 28h service routine to execute. Then checks the%@AE@%%@NL@%
- %@AB@%;* request flag TsrRequestFlag maintained either by the keyboard handler%@AE@%%@NL@%
- %@AB@%;* (keyboard-activated TSR) or by the timer handler (time-activated TSR).%@AE@%%@NL@%
- %@AB@%;* See header comments above for Clock, Keybrd, and MiscServ procedures.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* If TsrRequestFlag = TRUE and system is in interruptable state, Idle%@AE@%%@NL@%
- %@AB@%;* invokes the TSR by calling the Activate procedure. Uses an active flag%@AE@%%@NL@%
- %@AB@%;* to prevent the Idle procedure from being reentered while executing.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: intIdle and TsrActiveFlag%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Idle PROC FAR%@NL@%
- %@NL@%
- pushf %@AB@%; Simulate interrupt by pushing flags,%@AE@%%@NL@%
- call cs:intIdle.OldHand %@AB@%; far-calling old Int 28h routine%@AE@%%@NL@%
- %@NL@%
- .IF cs:intIdle.Flag == FALSE%@AB@%; If not already in this handler:%@AE@%%@NL@%
- mov cs:intIdle.Flag, TRUE %@AB@%; Set active flag%@AE@%%@NL@%
- %@NL@%
- sti %@AB@%; Interrupts are okay%@AE@%%@NL@%
- push ds %@AB@%; Save application's DS%@AE@%%@NL@%
- push cs%@NL@%
- pop ds %@AB@%; Set DS to resident code segment%@AE@%%@NL@%
- ASSUME ds:@code%@NL@%
- %@NL@%
- INVOKE CheckRequest %@AB@%; Check conditions%@AE@%%@NL@%
- .IF !carry? %@AB@%; If TSR requested and safe:%@AE@%%@NL@%
- mov TsrActiveFlag, TRUE %@AB@%; Activate TSR%@AE@%%@NL@%
- INVOKE Activate%@NL@%
- mov TsrActiveFlag, FALSE%@NL@%
- .ENDIF %@AB@%; End carry flag check%@AE@%%@NL@%
- %@NL@%
- mov intIdle.Flag, FALSE %@AB@%; Clear active flag%@AE@%%@NL@%
- pop ds %@AB@%; Recover application's DS%@AE@%%@NL@%
- .ENDIF %@AB@%; End in-handler check%@AE@%%@NL@%
- %@NL@%
- iret%@NL@%
- %@NL@%
- Idle ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Multiplex - Handler for Interrupt 2Fh (Multiplex Interrupt). Checks%@AE@%%@NL@%
- %@AB@%;* AH for this TSR's identity number. If no match (indicating call is%@AE@%%@NL@%
- %@AB@%;* not intended for this TSR), Multiplex passes control to the previous%@AE@%%@NL@%
- %@AB@%;* Interrupt 2Fh handler.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: AH = Handler identity number%@AE@%%@NL@%
- %@AB@%;* AL = Function number 0-2%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AL = 0FFh (function 0)%@AE@%%@NL@%
- %@AB@%;* ES:DI = Pointer to identifier string (function 0)%@AE@%%@NL@%
- %@AB@%;* ES:DI = Pointer to resident PSP segment (function 1)%@AE@%%@NL@%
- %@AB@%;* ES:DI = Pointer to shared memory (function 2)%@AE@%%@NL@%
- %@NL@%
- Multiplex PROC FAR%@NL@%
- %@NL@%
- .IF ah != cs:IDnumber %@AB@%; If this handler not reqested:%@AE@%%@NL@%
- jmp cs:intMultex.OldHand %@AB@%; Pass control to old Int 2Fh handler%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .IF al == 0 %@AB@%; If function 0 (verify presence):%@AE@%%@NL@%
- mov al, 0FFh %@AB@%; AL = 0FFh,%@AE@%%@NL@%
- push cs %@AB@%; ES = resident code segment%@AE@%%@NL@%
- pop es%@NL@%
- mov di, OFFSET IDstring %@AB@%; DI = offset of identifier string%@AE@%%@NL@%
- %@NL@%
- .ELSEIF al == 1 %@AB@%; If function 1 (get PSP address):%@AE@%%@NL@%
- mov es, cs:TsrPspSeg %@AB@%; ES:DI = far address of resident PSP%@AE@%%@NL@%
- sub di, di%@NL@%
- %@NL@%
- .ELSE%@NL@%
- les di, cs:ShareAddr %@AB@%; If function 2 (get shared memory):%@AE@%%@NL@%
- .ENDIF %@AB@%; set ES:DI = far address%@AE@%%@NL@%
- %@NL@%
- NoMultiplex LABEL FAR %@AB@%; Secondary entry for null Multiplex%@AE@%%@NL@%
- %@NL@%
- iret%@NL@%
- %@NL@%
- Multiplex ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CheckHotKey - Checks current keystroke for hot key. Called from Keybrd%@AE@%%@NL@%
- %@AB@%;* handler if IBM PC/AT or compatible, or from MiscServ handler if PS/2.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: HotScan, HotShift, HotMask, and SHFT_STAT%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: AL = Scan code%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Carry flag set = FALSE; carry flag clear = TRUE%@AE@%%@NL@%
- %@NL@%
- CheckHotKey PROC NEAR%@NL@%
- %@NL@%
- cmp al, cs:HotScan %@AB@%; If current scan code isn't code%@AE@%%@NL@%
- jne e_exit %@AB@%; for hot key, exit with carry set%@AE@%%@NL@%
- %@NL@%
- push es %@AB@%; Else look into BIOS data area%@AE@%%@NL@%
- sub ax, ax %@AB@%; (segment 0) to check shift state%@AE@%%@NL@%
- mov es, ax%@NL@%
- mov al, es:[SHFT_STAT] %@AB@%; Get shift-key flags%@AE@%%@NL@%
- and al, cs:HotMask %@AB@%; AND with "don't care" mask%@AE@%%@NL@%
- cmp al, cs:HotShift %@AB@%; Compare result with hot shift key%@AE@%%@NL@%
- pop es%@NL@%
- je exit %@AB@%; If match, exit with carry clear%@AE@%%@NL@%
- %@NL@%
- e_exit: stc %@AB@%; Set carry if not hot key%@AE@%%@NL@%
- exit: ret%@NL@%
- %@NL@%
- CheckHotKey ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CheckRequest - Checks request flag and system status using the%@AE@%%@NL@%
- %@AB@%;* following logic:%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* IF (TsrRequestFlag AND (NOT TsrActiveFlag)%@AE@%%@NL@%
- %@AB@%;* AND DosStatus AND HardwareStatus)%@AE@%%@NL@%
- %@AB@%;* return TRUE%@AE@%%@NL@%
- %@AB@%;* ELSE%@AE@%%@NL@%
- %@AB@%;* return FALSE%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: TsrRequestFlag and TsrActiveFlag%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Carry flag set = TRUE; carry flag clear = FALSE%@AE@%%@NL@%
- %@NL@%
- CheckRequest PROC NEAR%@NL@%
- %@NL@%
- rol TsrRequestFlag, 1 %@AB@%; Rotate high bit into carry - set%@AE@%%@NL@%
- %@AB@%; if TRUE (-1), clear if FALSE (0)%@AE@%%@NL@%
- cmc %@AB@%; NOT carry%@AE@%%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If TsrRequestFlag = TRUE:%@AE@%%@NL@%
- ror TsrActiveFlag, 1 %@AB@%; Rotate low bit into carry - set%@AE@%%@NL@%
- %@AB@%; if TRUE (-1), clear if FALSE (0)%@AE@%%@NL@%
- .IF !carry? %@AB@%; If TsrActiveFlag = FALSE:%@AE@%%@NL@%
- INVOKE CheckDos %@AB@%; Is DOS in interruptable state?%@AE@%%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If so:%@AE@%%@NL@%
- INVOKE CheckHardware %@AB@%; If hardware or BIOS unstable,%@AE@%%@NL@%
- .ENDIF %@AB@%; set carry and exit%@AE@%%@NL@%
- .ENDIF%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- CheckRequest ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CheckDos - Checks status of MS-DOS using the following logic:%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* IF (NOT CritErr) AND ((NOT InDos) OR (Idle AND InDos))%@AE@%%@NL@%
- %@AB@%;* return DosStatus = TRUE%@AE@%%@NL@%
- %@AB@%;* ELSE%@AE@%%@NL@%
- %@AB@%;* return DosStatus = FALSE%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: CritErrAddr, InDosAddr, and intIdle%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Carry flag set if MS-DOS is busy%@AE@%%@NL@%
- %@NL@%
- CheckDos PROC NEAR USES es bx ax%@NL@%
- %@NL@%
- les bx, CritErrAddr%@NL@%
- mov ah, es:[bx] %@AB@%; AH = value of CritErr flag%@AE@%%@NL@%
- %@NL@%
- les bx, InDosAddr%@NL@%
- mov al, es:[bx] %@AB@%; AL = value of InDos flag%@AE@%%@NL@%
- %@NL@%
- sub bx, bx %@AB@%; BH = 0, BL = 0%@AE@%%@NL@%
- cmp bl, intIdle.Flag %@AB@%; Carry flag set if call is from%@AE@%%@NL@%
- %@AB@%; Interrupt 28h handler%@AE@%%@NL@%
- rcl bl, 1 %@AB@%; Rotate carry into BL: TRUE if Idle%@AE@%%@NL@%
- cmp bx, ax %@AB@%; Carry flag clear if CritErr = 0%@AE@%%@NL@%
- %@AB@%; and InDos <= BL%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- CheckDos ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CheckHardware - Checks status of BIOS and hardware using the%@AE@%%@NL@%
- %@AB@%;* following logic:%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* IF HardwareActive OR KeybrdActive OR VideoActive OR DiskIOActive%@AE@%%@NL@%
- %@AB@%;* return HardwareStatus = FALSE%@AE@%%@NL@%
- %@AB@%;* ELSE%@AE@%%@NL@%
- %@AB@%;* return HardwareStatus = TRUE%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: intKeybrd, intVideo, and intDiskIO%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Carry flag set if hardware or BIOS is busy%@AE@%%@NL@%
- %@NL@%
- CheckHardware PROC NEAR USES ax%@NL@%
- %@NL@%
- %@AB@%; Verify hardware interrupt status by interrogating Intel 8259A%@AE@%%@NL@%
- %@AB@%; Programmable Interrupt Controller%@AE@%%@NL@%
- %@NL@%
- mov ax, 00001011y %@AB@%; AL = 0CW3 for Intel 8259A%@AE@%%@NL@%
- %@AB@%; (RR = 1, RIS = 1)%@AE@%%@NL@%
- out 20h, al %@AB@%; Request 8259A in-service register%@AE@%%@NL@%
- jmp delay %@AB@%; Wait a few cycles%@AE@%%@NL@%
- delay:%@NL@%
- in al, 20h %@AB@%; AL = hardware interrupts being%@AE@%%@NL@%
- cmp ah, al %@AB@%; serviced (bit = 1 if in service)%@AE@%%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If no hard interrupts in service:%@AE@%%@NL@%
- sub al, al %@AB@%; Verify BIOS interrupts not active%@AE@%%@NL@%
- cmp al, intKeybrd.Flag %@AB@%; Check Interrupt 09 handler%@AE@%%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If Int 09 not active:%@AE@%%@NL@%
- cmp al, intVideo.Flag %@AB@%; Check Interrupt 10h handler%@AE@%%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If Int 10h not active:%@AE@%%@NL@%
- cmp al, intDiskIO.Flag %@AB@%; Check Interrupt 13h handler%@AE@%%@NL@%
- .ENDIF %@AB@%; Return with carry set if%@AE@%%@NL@%
- .ENDIF %@AB@%; Interrupt 09, 10h, or 13h%@AE@%%@NL@%
- .ENDIF %@AB@%; is active%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- CheckHardware ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Activate - Sets up for far call to TSR with the following steps:%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* 1. Stores stack pointer SS:SP and switches to new stack%@AE@%%@NL@%
- %@AB@%;* 2. Pushes registers onto new stack%@AE@%%@NL@%
- %@AB@%;* 3. Stores vectors for Interrupts 1Bh, 23h, and 23h, and%@AE@%%@NL@%
- %@AB@%;* replaces them with addresses of error-trapping handlers%@AE@%%@NL@%
- %@AB@%;* 4. Stores DOS Ctrl+C checking flag, then turns off checking%@AE@%%@NL@%
- %@AB@%;* 5. If required, stores DTA address and switches to new DTA%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* When TSR returns, restores all the above.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: Reads or writes the following globals:%@AE@%%@NL@%
- %@AB@%;* OldStackAddr, TrapArray, BreakCheckFlag, TsrRequestFlag%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Activate PROC NEAR%@NL@%
- %@NL@%
- %@AB@%; Step 1. Set up a new stack%@AE@%%@NL@%
- %@NL@%
- mov WORD PTR OldStackAddr[0], sp %@AB@%; Save current%@AE@%%@NL@%
- mov WORD PTR OldStackAddr[2], ss %@AB@%; stack pointer%@AE@%%@NL@%
- %@NL@%
- cli %@AB@%; Turn off interrupts while%@AE@%%@NL@%
- push cs %@AB@%; changing stack%@AE@%%@NL@%
- pop ss %@AB@%; New stack begins%@AE@%%@NL@%
- mov sp, OFFSET NewStack %@AB@%; at LABEL NewStack%@AE@%%@NL@%
- sti%@NL@%
- %@NL@%
- %@AB@%; Step 2. Preserve registers (DS already saved in Clock or Idle)%@AE@%%@NL@%
- %@NL@%
- push ax%@NL@%
- push bx%@NL@%
- push cx%@NL@%
- push dx%@NL@%
- push si%@NL@%
- push di%@NL@%
- push bp%@NL@%
- push es%@NL@%
- %@NL@%
- cld %@AB@%; Clear direction flag%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Step 3. Set up trapping handlers for keyboard breaks and DOS%@AE@%%@NL@%
- %@AB@%; critical errors (Interrupts 1Bh, 23h, and 24h)%@AE@%%@NL@%
- %@NL@%
- mov cx, CTRAP %@AB@%; CX = number of handlers%@AE@%%@NL@%
- mov si, OFFSET TrapArray %@AB@%; DS:SI points to trap array%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov al, [si] %@AB@%; AL = interrupt number%@AE@%%@NL@%
- mov ah, 35h %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
- int 21h %@AB@%; Get Interrupt Vector (ES:BX)%@AE@%%@NL@%
- mov WORD PTR [si].INTR.OldHand[0], bx %@AB@%; Save far address of%@AE@%%@NL@%
- mov WORD PTR [si].INTR.OldHand[2], es %@AB@%; application's handler%@AE@%%@NL@%
- mov dx, WORD PTR [si].INTR.NewHand[0] %@AB@%; DS:DX points to TSR's hand%@AE@%%@NL@%
- mov ah, 25h %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt Vector%@AE@%%@NL@%
- add si, SIZEOF INTR %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- %@AB@%; Step 4. Disable MS-DOS break checking during disk I/O%@AE@%%@NL@%
- %@NL@%
- mov ax, 3300h %@AB@%; Request DOS Function 33h%@AE@%%@NL@%
- int 21h %@AB@%; Get Ctrl-Break Flag in DL%@AE@%%@NL@%
- mov BreakCheckFlag, dl %@AB@%; Preserve it%@AE@%%@NL@%
- %@NL@%
- sub dl, dl %@AB@%; DL = 0 to disable I/O break checking%@AE@%%@NL@%
- mov ax, 3301h %@AB@%; Request DOS Function 33h%@AE@%%@NL@%
- int 21h %@AB@%; Set Ctrl-Break Flag from DL%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Step 5. If TSR requires a disk transfer area, store address of current%@AE@%%@NL@%
- %@AB@%; DTA and switch buffer address to this segment. See Section 17.5.3 of%@AE@%%@NL@%
- %@AB@%; Programmer's Guide for more information about the DTA.%@AE@%%@NL@%
- %@NL@%
- IFDEF DTA_SIZ%@NL@%
- mov ah, 2Fh %@AB@%; Request DOS Function 2Fh%@AE@%%@NL@%
- int 21h %@AB@%; Get DTA Address into ES:BX%@AE@%%@NL@%
- mov WORD PTR OldDtaAddr[0], bx %@AB@%; Store address%@AE@%%@NL@%
- mov WORD PTR OldDtaAddr[2], es%@NL@%
- %@NL@%
- mov dx, OFFSET DtaBuff %@AB@%; DS:DX points to new DTA%@AE@%%@NL@%
- mov ah, 1Ah %@AB@%; Request DOS Function 1Ah%@AE@%%@NL@%
- int 21h %@AB@%; Set DTA Address%@AE@%%@NL@%
- ENDIF%@NL@%
- %@NL@%
- %@AB@%; Call main body of TSR.%@AE@%%@NL@%
- %@NL@%
- mov ax, @data%@NL@%
- mov ds, ax %@AB@%; Initialize DS and ES%@AE@%%@NL@%
- mov es, ax %@AB@%; to data segment%@AE@%%@NL@%
- %@NL@%
- call cs:TsrAddr %@AB@%; Call main part of TSR%@AE@%%@NL@%
- %@NL@%
- push cs%@NL@%
- pop ds %@AB@%; Reset DS to this segment%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Undo step 5. Restore previous DTA (if required)%@AE@%%@NL@%
- %@NL@%
- IFDEF DTA_SIZ%@NL@%
- push ds %@AB@%; Preserve DS%@AE@%%@NL@%
- lds dx, OldDtaAddr %@AB@%; DS:DX points to application's DTA%@AE@%%@NL@%
- mov ah, 1Ah %@AB@%; Request DOS Function 1Ah%@AE@%%@NL@%
- int 21h %@AB@%; Set DTA Address%@AE@%%@NL@%
- pop ds%@NL@%
- ENDIF%@NL@%
- %@NL@%
- %@AB@%; Undo step 4. Restore previous MS-DOS break checking%@AE@%%@NL@%
- %@NL@%
- mov dl, BreakCheckFlag %@AB@%; DL = previous break state%@AE@%%@NL@%
- mov ax, 3301h %@AB@%; Request DOS Function 33h%@AE@%%@NL@%
- int 21h %@AB@%; Set Ctrl-Break Flag from DL%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Undo step 3. Restore previous vectors for error-trapping handlers%@AE@%%@NL@%
- %@NL@%
- mov cx, CTRAP%@NL@%
- mov di, OFFSET TrapArray%@NL@%
- push ds %@AB@%; Preserve DS%@AE@%%@NL@%
- push ds %@AB@%; ES = resident code segment%@AE@%%@NL@%
- pop es%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov al, es:[di] %@AB@%; AL = interrupt number%@AE@%%@NL@%
- lds dx, es:[di].INTR.OldHand%@AB@%; DS:DX points to application's handler%@AE@%%@NL@%
- mov ah, 25h %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt Vector from DS:DX%@AE@%%@NL@%
- add di, SIZEOF INTR %@AB@%; ES:DI points to next in list%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- pop ds%@NL@%
- %@NL@%
- %@AB@%; Undo step 2. Restore registers from stack%@AE@%%@NL@%
- %@NL@%
- pop es%@NL@%
- pop bp%@NL@%
- pop di%@NL@%
- pop si%@NL@%
- pop dx%@NL@%
- pop cx%@NL@%
- pop bx%@NL@%
- pop ax%@NL@%
- %@NL@%
- %@AB@%; Undo step 1. Restore address of original stack to SS:SP%@AE@%%@NL@%
- %@NL@%
- cli%@NL@%
- mov sp, WORD PTR OldStackAddr[0]%@NL@%
- mov ss, WORD PTR OldStackAddr[2]%@NL@%
- sti%@NL@%
- %@NL@%
- %@AB@%; Clear request flag and return to caller (Clock or Idle procedure)%@AE@%%@NL@%
- %@NL@%
- mov TsrRequestFlag, FALSE%@NL@%
- ret%@NL@%
- %@NL@%
- Activate ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* INSTALLATION SECTION - The following code is executed only during%@AE@%%@NL@%
- %@AB@%;* the TSR's installation phase. When the program terminates through%@AE@%%@NL@%
- %@AB@%;* Function 31h, the above code and data remain resident; memory%@AE@%%@NL@%
- %@AB@%;* occupied by the following code segment is returned to the operating%@AE@%%@NL@%
- %@AB@%;* system.%@AE@%%@NL@%
- %@NL@%
- DGROUP GROUP INSTALLCODE%@NL@%
- %@NL@%
- INSTALLCODE SEGMENT PARA PUBLIC 'CODE2'%@NL@%
- ASSUME ds:@code%@NL@%
- %@NL@%
- %@AB@%;* Install - Prepares for installation of a TSR by chaining interrupt%@AE@%%@NL@%
- %@AB@%;* handlers and initializing pointers to DOS flags. Install does not%@AE@%%@NL@%
- %@AB@%;* call the Terminate-and-Stay-Resident function.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* This library of routines accomodates both keyboard-activated and%@AE@%%@NL@%
- %@AB@%;* time-activated TSRs. The latter are TSRs that activate at a preset%@AE@%%@NL@%
- %@AB@%;* time. If the first parameter (Param1) is a valid scan code, Install%@AE@%%@NL@%
- %@AB@%;* assumes the TSR is activated from the keyboard and sets up a keyboard%@AE@%%@NL@%
- %@AB@%;* handler to search for the hotkey. If Param1 is null, Install assumes%@AE@%%@NL@%
- %@AB@%;* the next two parameters (Param2 and Param3) are respectively the hour%@AE@%%@NL@%
- %@AB@%;* and minute at which the TSR is to activate. In this case, Install%@AE@%%@NL@%
- %@AB@%;* calls GetTimeToElapse to initialize the variable CountDown and sets%@AE@%%@NL@%
- %@AB@%;* up KeybrdMonitor as the keyboard handler. CountDown and the secondary%@AE@%%@NL@%
- %@AB@%;* counter Tick91 serve here the same functions as they do for the%@AE@%%@NL@%
- %@AB@%;* ALARM.ASM program presented in Section 17.3 of the Programmer's Guide.%@AE@%%@NL@%
- %@AB@%;* Install is callable from a high-level language.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: InDosAddr, CritErrAddr, CHAND,%@AE@%%@NL@%
- %@AB@%;* HandArray, CTRAP, TrapArray%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Keyboard-activated Time-activated%@AE@%%@NL@%
- %@AB@%;* ------------------ --------------%@AE@%%@NL@%
- %@AB@%;* Params: Param1 - Scan code for hotkey 0%@AE@%%@NL@%
- %@AB@%;* Param2 - Bit value for shift hotkey Hour to activate%@AE@%%@NL@%
- %@AB@%;* Param3 - Bit mask for shift hotkey Minute to activate%@AE@%%@NL@%
- %@AB@%;* Param4 - Far address of main TSR procedure (same)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = 0 if successful, or one of the following codes:%@AE@%%@NL@%
- %@AB@%;* IS_INSTALLED FLAGS_NOT_FOUND NO_IDNUM%@AE@%%@NL@%
- %@AB@%;* ALREADY_INSTALLED WRONG_DOS%@AE@%%@NL@%
- %@NL@%
- Install PROC FAR USES ds si di,%@NL@%
- Param1:WORD, Param2:WORD, Param3:WORD, Param4:FAR PTR FAR%@NL@%
- %@NL@%
- mov ax, @code%@NL@%
- mov ds, ax %@AB@%; Point DS to code segment%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Get and store parameters passed from main program module%@AE@%%@NL@%
- %@NL@%
- mov al, BYTE PTR Param1%@NL@%
- mov HotScan, al %@AB@%; Store hot key scan code%@AE@%%@NL@%
- mov al, BYTE PTR Param2 %@AB@%; or flag for time-activate%@AE@%%@NL@%
- mov HotShift, al %@AB@%; Store hot key shift value%@AE@%%@NL@%
- mov al, BYTE PTR Param3 %@AB@%; or hour value%@AE@%%@NL@%
- mov HotMask, al %@AB@%; Store hot key shift mask%@AE@%%@NL@%
- %@AB@%; or minute value%@AE@%%@NL@%
- mov ax, WORD PTR Param4[0]%@NL@%
- mov bx, WORD PTR Param4[2]%@NL@%
- mov WORD PTR TsrAddr[0], ax %@AB@%; Store segment:offset of%@AE@%%@NL@%
- mov WORD PTR TsrAddr[2], bx %@AB@%; TSR's main code%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Get addresses of DOS flags, then check for prior installation%@AE@%%@NL@%
- %@NL@%
- INVOKE GetDosFlags %@AB@%; Find DOS service flags%@AE@%%@NL@%
- or ax, ax%@NL@%
- jnz exit %@AB@%; If flags not found, quit%@AE@%%@NL@%
- %@NL@%
- sub al, al %@AB@%; Request multiplex function 0%@AE@%%@NL@%
- call CallMultiplex %@AB@%; Invoke Interrupt 2Fh%@AE@%%@NL@%
- cmp ax, NOT_INSTALLED %@AB@%; Check for presence of resident TSR%@AE@%%@NL@%
- %@NL@%
- .IF !zero? %@AB@%; If TSR is installed:%@AE@%%@NL@%
- cmp ax, IS_INSTALLED %@AB@%; Return with appropriate%@AE@%%@NL@%
- jne exit %@AB@%; error code%@AE@%%@NL@%
- mov ax, ALREADY_INSTALLED%@NL@%
- jmp exit%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Check if TSR is to activate at the hour:minute specified by Param2:Param3.%@AE@%%@NL@%
- %@AB@%; If so, determine the number of 5-second intervals that must elapse before%@AE@%%@NL@%
- %@AB@%; activation, then set up the code at the far LABEL KeybrdMonitor to serve%@AE@%%@NL@%
- %@AB@%; as the keyboard handler.%@AE@%%@NL@%
- %@NL@%
- .IF HotScan == 0 %@AB@%; If valid scan code given:%@AE@%%@NL@%
- mov ah, HotShift %@AB@%; AH = hour to activate%@AE@%%@NL@%
- mov al, HotMask %@AB@%; AL = minute to activate%@AE@%%@NL@%
- call GetTimeToElapse %@AB@%; Get number of 5-second intervals%@AE@%%@NL@%
- mov CountDown, ax %@AB@%; to elapse before activation%@AE@%%@NL@%
- %@NL@%
- .ELSE %@AB@%; Force use of KeybrdMonitor as%@AE@%%@NL@%
- %@AB@%; keyboard handler%@AE@%%@NL@%
- cmp Version, 031Eh %@AB@%; DOS Version 3.3 or higher?%@AE@%%@NL@%
- jb setup %@AB@%; No? Skip next step%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Test for IBM PS/2 series. If not PS/2, use Keybrd and SkipMiscServ as%@AE@%%@NL@%
- %@AB@%; handlers for Interrupts 09 and 15h respectively. If PS/2 system, set up%@AE@%%@NL@%
- %@AB@%; KeybrdMonitor as the Interrupt 09 handler. Audit keystrokes with MiscServ%@AE@%%@NL@%
- %@AB@%; handler, which searches for the hot key by handling calls to Interrupt 15h%@AE@%%@NL@%
- %@AB@%; (Miscellaneous System Services). Refer to Section 17.2.1 of the Programmer's%@AE@%%@NL@%
- %@AB@%; Guide for more information about keyboard handlers.%@AE@%%@NL@%
- %@NL@%
- mov ax, 0C00h %@AB@%; Function 0Ch (Get System%@AE@%%@NL@%
- int 15h %@AB@%; Configuration Parameters)%@AE@%%@NL@%
- sti %@AB@%; Compaq ROM may leave disabled%@AE@%%@NL@%
- %@NL@%
- jc setup %@AB@%; If carry set,%@AE@%%@NL@%
- or ah, ah %@AB@%; or if AH not 0,%@AE@%%@NL@%
- jnz setup %@AB@%; services are not supported%@AE@%%@NL@%
- %@NL@%
- test BYTE PTR es:[bx+5], 00010000y %@AB@%; Test byte 4 to see if%@AE@%%@NL@%
- jz setup %@AB@%; intercept is implemented%@AE@%%@NL@%
- %@NL@%
- mov ax, OFFSET MiscServ %@AB@%; If so, set up MiscServ as%@AE@%%@NL@%
- mov WORD PTR intMisc.NewHand, ax %@AB@%; Interrupt 15h handler%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov ax, OFFSET KeybrdMonitor %@AB@%; Set up KeybrdMonitor as%@AE@%%@NL@%
- mov WORD PTR intKeybrd.NewHand, ax %@AB@%; Interrupt 09 handler%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Interrupt structure is now initialized for either PC/AT or PS/2 system.%@AE@%%@NL@%
- %@AB@%; Get existing handler addresses from interrupt vector table, store in%@AE@%%@NL@%
- %@AB@%; OldHand member, and replace with addresses of new handlers.%@AE@%%@NL@%
- %@NL@%
- setup:%@NL@%
- mov cx, CHAND %@AB@%; CX = count of handlers%@AE@%%@NL@%
- mov si, OFFSET HandArray %@AB@%; SI = offset of handler structures%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov ah, 35h %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
- mov al, [si] %@AB@%; AL = interrupt number%@AE@%%@NL@%
- int 21h %@AB@%; Get Interrupt Vector in ES:BX%@AE@%%@NL@%
- mov WORD PTR [si].INTR.OldHand[0], bx %@AB@%; Save far address%@AE@%%@NL@%
- mov WORD PTR [si].INTR.OldHand[2], es %@AB@%; of current handler%@AE@%%@NL@%
- mov dx, WORD PTR [si].INTR.NewHand[0] %@AB@%; DS:DX points to TSR handler%@AE@%%@NL@%
- mov ah, 25h %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt Vector from DS:DX%@AE@%%@NL@%
- add si, SIZEOF INTR %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Clear return code%@AE@%%@NL@%
- exit:%@NL@%
- ret %@AB@%; Return to caller%@AE@%%@NL@%
- %@NL@%
- Install ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Deinstall - Prepares for deinstallation of a TSR. Deinstall is the%@AE@%%@NL@%
- %@AB@%;* complement of the Install procedure. It restores to the vector table%@AE@%%@NL@%
- %@AB@%;* the original addresses replaced during installation, thus unhooking%@AE@%%@NL@%
- %@AB@%;* the TSR's handlers. Checks to see if another TSR has installed handlers%@AE@%%@NL@%
- %@AB@%;* for the interrupts in array HandArray. If so, the procedure fails with%@AE@%%@NL@%
- %@AB@%;* an appropriate error code. Callable from a high-level language.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = Segment address of resident portion's PSP or%@AE@%%@NL@%
- %@AB@%;* one of the following error codes:%@AE@%%@NL@%
- %@AB@%;* CANT_DEINSTALL WRONG_DOS%@AE@%%@NL@%
- %@NL@%
- Deinstall PROC FAR USES ds si di%@NL@%
- %@NL@%
- mov ax, @code%@NL@%
- mov ds, ax %@AB@%; Point DS to code segment%@AE@%%@NL@%
- %@NL@%
- sub al, al %@AB@%; Request multiplex function 0%@AE@%%@NL@%
- call CallMultiplex %@AB@%; Get resident code segment in ES%@AE@%%@NL@%
- %@NL@%
- cmp ax, IS_INSTALLED %@AB@%; If not resident,%@AE@%%@NL@%
- jne exit %@AB@%; exit with error%@AE@%%@NL@%
- push es %@AB@%; Else point DS to%@AE@%%@NL@%
- pop ds %@AB@%; resident code segment%@AE@%%@NL@%
- mov cx, CHAND %@AB@%; Count of handlers%@AE@%%@NL@%
- mov si, OFFSET HandArray %@AB@%; SI points to handler structures%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Read current vectors for TSR's interrupt handlers and compare with far%@AE@%%@NL@%
- %@AB@%; addresses. If mismatch, another TSR has installed new handlers and ours%@AE@%%@NL@%
- %@AB@%; cannot be safely deinstalled.%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov al, [si] %@AB@%; AL = interrupt number%@AE@%%@NL@%
- mov ah, 35h %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
- int 21h %@AB@%; Get Interrupt Vector in ES:BX%@AE@%%@NL@%
- cmp bx, WORD PTR [si].INTR.NewHand[0] %@AB@%; If offset different,%@AE@%%@NL@%
- jne e_exit %@AB@%; error%@AE@%%@NL@%
- mov ax, es%@NL@%
- cmp ax, WORD PTR [si].INTR.NewHand[2] %@AB@%; If segment different,%@AE@%%@NL@%
- jne e_exit %@AB@%; error%@AE@%%@NL@%
- add si, SIZEOF INTR %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- %@AB@%; If no interrupts replaced, call TSR's multiplex handler to locate%@AE@%%@NL@%
- %@AB@%; address of resident portion's PSP. Although the PSP is not required%@AE@%%@NL@%
- %@AB@%; until memory is returned to DOS, the call must be done now before%@AE@%%@NL@%
- %@AB@%; unhooking the multiplex handler.%@AE@%%@NL@%
- %@NL@%
- mov al, 1 %@AB@%; Request multiplex function 1%@AE@%%@NL@%
- call CallMultiplex %@AB@%; Get resident code's PSP in ES%@AE@%%@NL@%
- push es %@AB@%; Save it%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Unhook all handlers by restoring the original vectors to vector table.%@AE@%%@NL@%
- %@NL@%
- mov cx, CHAND %@AB@%; Count of installed handlers%@AE@%%@NL@%
- mov si, OFFSET HandArray %@AB@%; SI points to handler structures%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov al, [si] %@AB@%; AL = interrupt number%@AE@%%@NL@%
- push ds %@AB@%; Preserve DS segment%@AE@%%@NL@%
- lds dx, [si].INTR.OldHand %@AB@%; Put vector in DS:DX%@AE@%%@NL@%
- mov ah, 25h %@AB@%; Request DOS Function 25h%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt Vector from DS:DX%@AE@%%@NL@%
- pop ds%@NL@%
- add si, SIZEOF INTR %@AB@%; DS:SI points to next in list%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- pop ax %@AB@%; Return address of resident PSP%@AE@%%@NL@%
- jmp exit %@AB@%; to signal success%@AE@%%@NL@%
- e_exit:%@NL@%
- mov ax, CANT_DEINSTALL%@NL@%
- exit:%@NL@%
- ret%@NL@%
- %@NL@%
- Deinstall ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetVersion - Gets the DOS version and stores it in a global variable as%@AE@%%@NL@%
- %@AB@%;* well as returning it in AX.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: Version%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AH = Major version%@AE@%%@NL@%
- %@AB@%;* AL = Minor version%@AE@%%@NL@%
- %@NL@%
- GetVersion PROC NEAR%@NL@%
- %@NL@%
- mov ax, 3000h %@AB@%; Request DOS Function 30h%@AE@%%@NL@%
- int 21h %@AB@%; Get MS-DOS Version Number%@AE@%%@NL@%
- .IF al < 2 %@AB@%; If Version 1.x:%@AE@%%@NL@%
- mov ax, WRONG_DOS %@AB@%; Abort with WRONG_DOS as error code%@AE@%%@NL@%
- .ELSE%@NL@%
- xchg ah, al %@AB@%; AH = major, AL = minor version%@AE@%%@NL@%
- mov Version, ax %@AB@%; Save in global%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- GetVersion ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetDosFlags - Gets pointers to DOS's InDos and Critical Error flags.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS = Resident code segment%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: 0 if successful, or the following error code:%@AE@%%@NL@%
- %@AB@%;* FLAGS_NOT_FOUND%@AE@%%@NL@%
- %@NL@%
- GetDosFlags PROC NEAR%@NL@%
- %@NL@%
- %@AB@%; Get InDOS address from MS-DOS%@AE@%%@NL@%
- %@NL@%
- mov ah, 34h %@AB@%; Request DOS Function 34h%@AE@%%@NL@%
- int 21h %@AB@%; Get Address of InDos Flag%@AE@%%@NL@%
- mov WORD PTR InDosAddr[0], bx %@AB@%; Store address (ES:BX)%@AE@%%@NL@%
- mov WORD PTR InDosAddr[2], es %@AB@%; for later access%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Determine address of Critical Error Flag%@AE@%%@NL@%
- %@NL@%
- mov ax, Version %@AB@%; AX = DOS version number%@AE@%%@NL@%
- %@NL@%
- %@AB@%; If DOS 3.1 or greater and not OS/2 compatibility mode, Critical Error%@AE@%%@NL@%
- %@AB@%; flag is in byte preceding InDOS flag%@AE@%%@NL@%
- .IF (ah < 10) && (ah >= 3) && (al >= 10)%@NL@%
- dec bx %@AB@%; BX points to byte before InDos flag%@AE@%%@NL@%
- %@NL@%
- .ELSE%@NL@%
- %@AB@%; For earlier versions, the only reliable method is to scan through%@AE@%%@NL@%
- %@AB@%; DOS to find an INT 28h instruction in a specific context.%@AE@%%@NL@%
- %@NL@%
- mov cx, 0FFFFh %@AB@%; Maximum bytes to scan%@AE@%%@NL@%
- sub di, di %@AB@%; ES:DI = start of DOS segment%@AE@%%@NL@%
- %@NL@%
- INT_28 EQU 028CDh%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov ax, INT_28 %@AB@%; Load opcode for INT 28h%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- repne scasb %@AB@%; Scan for first byte of opcode%@AE@%%@NL@%
- %@NL@%
- .IF !zero?%@NL@%
- mov ax, FLAGS_NOT_FOUND %@AB@%; Return error if not found%@AE@%%@NL@%
- jmp exit%@NL@%
- .ENDIF%@NL@%
- .UNTIL ah == es:[di] %@AB@%; For each matching first byte,%@AE@%%@NL@%
- %@AB@%; check the second byte until match%@AE@%%@NL@%
- %@NL@%
- %@AB@%; See if INT 28h is in this context:%@AE@%%@NL@%
- %@AB@%; ; (-7) (-5)%@AE@%%@NL@%
- %@AB@%; CMP ss:[CritErrFlag], 0 ; 36, 80, 3E, ?, ?, 0%@AE@%%@NL@%
- %@AB@%; JNE NearLabel ; 75, ?%@AE@%%@NL@%
- int 28h %@AB@%; CD, 28%@AE@%%@NL@%
- %@AB@%; ; (0) (1)%@AE@%%@NL@%
- CMP_SS EQU 3E80h%@NL@%
- P_CMP_SS EQU 8%@NL@%
- P_CMP_OP EQU 6%@NL@%
- %@NL@%
- mov ax, CMP_SS %@AB@%; Load and compare opcode to CMP%@AE@%%@NL@%
- .IF ax == es:[di-P_CMP_SS] %@AB@%; If match:%@AE@%%@NL@%
- mov bx, es:[di-P_CMP_OP] %@AB@%; BX = offset of%@AE@%%@NL@%
- jmp exit %@AB@%; Critical Error Flag%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; See if INT 28h is in this context:%@AE@%%@NL@%
- %@AB@%; ; (-12) (-10)%@AE@%%@NL@%
- %@AB@%; TEST ?s:[CritErr], 0FFh ; ?6 F6, 06, ?, ?, FF%@AE@%%@NL@%
- %@AB@%; JNE NearLabel ; 75, ?%@AE@%%@NL@%
- %@AB@%; PUSH ss:[CritErrFlag] ; 36, FF, 36, ?, ?%@AE@%%@NL@%
- int 28h %@AB@%; CD, 28%@AE@%%@NL@%
- %@AB@%; ; (0) (1)%@AE@%%@NL@%
- TEST_SS EQU 06F6h%@NL@%
- P_TEST_SS EQU 13%@NL@%
- P_TEST_OP EQU 11%@NL@%
- %@NL@%
- mov ax, TEST_SS %@AB@%; Load AX = opcode for TEST%@AE@%%@NL@%
- .UNTIL ax == es:[di-P_TEST_SS] %@AB@%; If not TEST, continue scan%@AE@%%@NL@%
- %@NL@%
- mov bx, es:[di-P_TEST_OP] %@AB@%; Else load BX with offset of%@AE@%%@NL@%
- .ENDIF %@AB@%; Critical Error flag%@AE@%%@NL@%
- exit:%@NL@%
- mov WORD PTR CritErrAddr[0], bx %@AB@%; Store address of%@AE@%%@NL@%
- mov WORD PTR CritErrAddr[2], es %@AB@%; Critical Error Flag%@AE@%%@NL@%
- sub ax, ax %@AB@%; Clear error code%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetDosFlags ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetTimeToElapse - Determines number of 5-second intervals that%@AE@%%@NL@%
- %@AB@%;* must elapse between specified hour:minute and current time.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: AH = Hour%@AE@%%@NL@%
- %@AB@%;* AL = Minute%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = Number of 5-second intervals%@AE@%%@NL@%
- %@NL@%
- GetTimeToElapse PROC NEAR%@NL@%
- %@NL@%
- push ax %@AB@%; Save hour:minute%@AE@%%@NL@%
- mov ah, 2Ch %@AB@%; Request DOS Function 2Ch%@AE@%%@NL@%
- int 21h %@AB@%; Get Time (CH:CL = hour:minute)%@AE@%%@NL@%
- pop bx %@AB@%; Recover hour:minute%@AE@%%@NL@%
- mov dl, dh%@NL@%
- sub dh, dh%@NL@%
- push dx %@AB@%; Save DX = current seconds%@AE@%%@NL@%
- %@NL@%
- mov al, 60 %@AB@%; 60 minutes/hour%@AE@%%@NL@%
- mul bh %@AB@%; Mutiply by specified hour%@AE@%%@NL@%
- sub bh, bh%@NL@%
- add bx, ax %@AB@%; BX = minutes from midnight%@AE@%%@NL@%
- %@AB@%; to activation time%@AE@%%@NL@%
- mov al, 60 %@AB@%; 60 minutes/hour%@AE@%%@NL@%
- mul ch %@AB@%; Multiply by current hour%@AE@%%@NL@%
- sub ch, ch%@NL@%
- add ax, cx %@AB@%; AX = minutes from midnight%@AE@%%@NL@%
- %@AB@%; to current time%@AE@%%@NL@%
- sub bx, ax %@AB@%; BX = minutes to elapse before%@AE@%%@NL@%
- .IF carry? %@AB@%; If activation is tomorrow:%@AE@%%@NL@%
- add bx, 24 * 60 %@AB@%; add number of minutes per day%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov ax, 60%@NL@%
- mul bx %@AB@%; DX:AX = minutes-to-elapse-times-60%@AE@%%@NL@%
- pop bx %@AB@%; Recover current seconds%@AE@%%@NL@%
- sub ax, bx %@AB@%; DX:AX = seconds to elapse before%@AE@%%@NL@%
- sbb dx, 0 %@AB@%; activation%@AE@%%@NL@%
- .IF carry? %@AB@%; If negative:%@AE@%%@NL@%
- mov ax, 5 %@AB@%; Assume 5 seconds%@AE@%%@NL@%
- cwd%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov bx, 5 %@AB@%; Divide result by 5 seconds%@AE@%%@NL@%
- div bx %@AB@%; AX = number of 5-second intervals%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetTimeToElapse ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CallMultiplex - Calls the Multiplex Interrupt (Interrupt 2Fh).%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: IDstring%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: AL = Function number for multiplex handler%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = One of the following return codes:%@AE@%%@NL@%
- %@AB@%;* NOT_INSTALLED IS_INSTALLED NO_IDNUM%@AE@%%@NL@%
- %@AB@%;* ES:DI = Resident code segment:identifier string (function 0)%@AE@%%@NL@%
- %@AB@%;* ES:DI = Resident PSP segment address (function 1)%@AE@%%@NL@%
- %@AB@%;* ES:DI = Far address of shared memory (function 2)%@AE@%%@NL@%
- %@NL@%
- CallMultiplex PROC FAR USES ds%@NL@%
- %@NL@%
- push ax %@AB@%; Save function number%@AE@%%@NL@%
- mov ax, @code%@NL@%
- mov ds, ax %@AB@%; Point DS to code segment%@AE@%%@NL@%
- %@NL@%
- %@AB@%; First, check 2Fh vector. DOS Version 2.x may leave the vector null%@AE@%%@NL@%
- %@AB@%; if PRINT.COM is not installed. If vector is null, point it to IRET%@AE@%%@NL@%
- %@AB@%; instruction at LABEL NoMultiplex. This allows the new multiplex%@AE@%%@NL@%
- %@AB@%; handler to pass control, if necessary, to a proper existing routine.%@AE@%%@NL@%
- %@NL@%
- mov ax, 352Fh %@AB@%; Request DOS Function 35h%@AE@%%@NL@%
- int 21h %@AB@%; Get Interrupt Vector in ES:BX%@AE@%%@NL@%
- mov ax, es%@NL@%
- or ax, bx%@NL@%
- .IF zero? %@AB@%; If Null vector:%@AE@%%@NL@%
- mov dx, OFFSET NoMultiplex %@AB@%; Set vector to IRET instruction%@AE@%%@NL@%
- mov ax, 252Fh %@AB@%; at LABEL NoMultiplex%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt Vector%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Second, call Interrupt 2Fh with function 0 (presence request). Cycle%@AE@%%@NL@%
- %@AB@%; through allowable identity numbers (192 to 255) until TSR's multiplex%@AE@%%@NL@%
- %@AB@%; handler returns ES:DI = IDstring to verify its presence or until call%@AE@%%@NL@%
- %@AB@%; returns AL = 0, indicating the TSR is not installed.%@AE@%%@NL@%
- %@NL@%
- mov dh, 192 %@AB@%; Start with identity number = 192%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov ah, dh %@AB@%; Call Multiplex with AH = trial ID%@AE@%%@NL@%
- sub al, al %@AB@%; and AL = function 0%@AE@%%@NL@%
- push dx %@AB@%; Save DH and DS in case call%@AE@%%@NL@%
- push ds %@AB@%; destroys them%@AE@%%@NL@%
- int 2Fh %@AB@%; Multiplex%@AE@%%@NL@%
- pop ds %@AB@%; Recover DS and%@AE@%%@NL@%
- pop dx %@AB@%; current ID number in DH%@AE@%%@NL@%
- or al, al %@AB@%; Does a handler claim this ID number?%@AE@%%@NL@%
- jz no %@AB@%; If not, stop search%@AE@%%@NL@%
- %@NL@%
- .IF al == 0FFh %@AB@%; If handler ready to process calls:%@AE@%%@NL@%
- mov si, OFFSET IDstring %@AB@%; Point DS:SI to ID string, compare%@AE@%%@NL@%
- mov cx, IDstrlen %@AB@%; with string at ES:DI returned%@AE@%%@NL@%
- repe cmpsb %@AB@%; by multiplex handler%@AE@%%@NL@%
- je yes %@AB@%; If equal, TSR's handler is found%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- inc dh %@AB@%; This handler is not the one%@AE@%%@NL@%
- .UNTIL zero? %@AB@%; Try next identity number up to 255%@AE@%%@NL@%
- %@NL@%
- mov ax, NO_IDNUM %@AB@%; In the unlikely event that numbers%@AE@%%@NL@%
- jmp e_exit %@AB@%; 192-255 are all taken, quit%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Third, assuming handler is found and verified, process the multiplex%@AE@%%@NL@%
- %@AB@%; call with the requested function number.%@AE@%%@NL@%
- %@NL@%
- yes:%@NL@%
- pop ax %@AB@%; AL = original function number%@AE@%%@NL@%
- mov ah, dh %@AB@%; AH = identity number%@AE@%%@NL@%
- int 2Fh %@AB@%; Multiplex%@AE@%%@NL@%
- mov ax, IS_INSTALLED %@AB@%; Signal that handler has been found%@AE@%%@NL@%
- jmp exit %@AB@%; and quit%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Reaching this section means multiplex handler (and TSR) not installed.%@AE@%%@NL@%
- %@AB@%; Since the value in DH is not claimed by any handler, it will be used as%@AE@%%@NL@%
- %@AB@%; the resident TSR's identity number. Save the number in resident code%@AE@%%@NL@%
- %@AB@%; segment so multiplex handler can find it.%@AE@%%@NL@%
- %@NL@%
- no:%@NL@%
- mov IDnumber, dh %@AB@%; Save multiplex identity number%@AE@%%@NL@%
- mov ax, NOT_INSTALLED %@AB@%; Signal handler is not installed%@AE@%%@NL@%
- e_exit:%@NL@%
- pop bx %@AB@%; Remove function number from stack%@AE@%%@NL@%
- exit:%@NL@%
- ret%@NL@%
- %@NL@%
- CallMultiplex ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* InitTsr - Initializes DOS version variables and multiplex data with%@AE@%%@NL@%
- %@AB@%;* following parameters. This procedure must execute before calling%@AE@%%@NL@%
- %@AB@%;* either the Install, Deinstall, or CallMultiplex procedures. Callable%@AE@%%@NL@%
- %@AB@%;* from a high-level language.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: IDstring%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: PspParam - Segment address of PSP%@AE@%%@NL@%
- %@AB@%;* StrParam - Far address of TSR's identifier string%@AE@%%@NL@%
- %@AB@%;* ShrParam - Far address of shared memory%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = WRONG_DOS if not DOS Version 2.0 or higher%@AE@%%@NL@%
- %@NL@%
- InitTsr PROC FAR USES ds es si di,%@NL@%
- PspParam:WORD, StrParam:FPVOID, ShrParam:FPVOID%@NL@%
- %@NL@%
- mov ax, @code%@NL@%
- mov ds, ax %@AB@%; Point DS and ES%@AE@%%@NL@%
- mov es, ax %@AB@%; to code segment%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Get and store parameters passed from main program module%@AE@%%@NL@%
- %@NL@%
- mov ax, PspParam%@NL@%
- mov TsrPspSeg, ax %@AB@%; Store PSP segment address%@AE@%%@NL@%
- %@NL@%
- mov ax, WORD PTR ShrParam[0]%@NL@%
- mov bx, WORD PTR ShrParam[2]%@NL@%
- mov WORD PTR ShareAddr[0], ax %@AB@%; Store far address of%@AE@%%@NL@%
- mov WORD PTR ShareAddr[2], bx %@AB@%; shared memory%@AE@%%@NL@%
- %@NL@%
- push ds%@NL@%
- mov si, WORD PTR StrParam[0] %@AB@%; DS:SI points to multiplex%@AE@%%@NL@%
- mov ax, WORD PTR StrParam[2] %@AB@%; identifier string%@AE@%%@NL@%
- mov ds, ax%@NL@%
- mov di, OFFSET IDstring %@AB@%; Copy string to IDstring%@AE@%%@NL@%
- mov cx, STR_LEN %@AB@%; at ES:DI so multiplex%@AE@%%@NL@%
- %@AB@%; handler has a copy%@AE@%%@NL@%
- .REPEAT%@NL@%
- lodsb %@AB@%; Copy STR_LEN characters%@AE@%%@NL@%
- .BREAK .IF al == 0 %@AB@%; or until null-terminator%@AE@%%@NL@%
- stosb %@AB@%; found%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- pop ds %@AB@%; Recover DS = code segment%@AE@%%@NL@%
- mov ax, STR_LEN%@NL@%
- sub ax, cx%@NL@%
- mov IDstrlen, ax %@AB@%; Store string length%@AE@%%@NL@%
- %@NL@%
- INVOKE GetVersion %@AB@%; Return AX = version number%@AE@%%@NL@%
- ret %@AB@%; or WRONG_DOS%@AE@%%@NL@%
- %@NL@%
- InitTsr ENDP%@NL@%
- %@NL@%
- %@NL@%
- INSTALLCODE ENDS%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%INSTALL.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\TSR\INSTALL.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL small, pascal, os_dos%@NL@%
- INCLUDE tsr.inc%@NL@%
- %@NL@%
- %@AB@%;* INSTALLATION SECTION - The following code and data are used only%@AE@%%@NL@%
- %@AB@%;* during the TSR's installation phase. When the program terminates%@AE@%%@NL@%
- %@AB@%;* through Function 31h, memory occupied by the following code and%@AE@%%@NL@%
- %@AB@%;* data segments is returned to the operating system.%@AE@%%@NL@%
- %@NL@%
- DGROUP GROUP INSTALLCODE, INSTALLDATA%@NL@%
- %@NL@%
- INSTALLDATA SEGMENT WORD PUBLIC 'DATA2' %@AB@%; Data segment for installation phase%@AE@%%@NL@%
- %@NL@%
- PUBLIC _MsgTbl%@NL@%
- %@NL@%
- _MsgTbl WORD Msg0 %@AB@%; Deinstalled okay%@AE@%%@NL@%
- WORD Msg1 %@AB@%; Installed okay%@AE@%%@NL@%
- WORD Msg2 %@AB@%; Already installed%@AE@%%@NL@%
- WORD Msg3 %@AB@%; Can't install%@AE@%%@NL@%
- WORD Msg4 %@AB@%; Can't find flag%@AE@%%@NL@%
- WORD Msg5 %@AB@%; Can't deinstall%@AE@%%@NL@%
- WORD Msg6 %@AB@%; Requires DOS 2+%@AE@%%@NL@%
- WORD Msg7 %@AB@%; MCB damaged%@AE@%%@NL@%
- WORD Msg8 %@AB@%; Invalid ID%@AE@%%@NL@%
- WORD Msg9 %@AB@%; Invalid memory block address%@AE@%%@NL@%
- WORD Msg10 %@AB@%; Successful access%@AE@%%@NL@%
- WORD Msg11 %@AB@%; Can't access%@AE@%%@NL@%
- WORD Msg12 %@AB@%; Unrecognized option%@AE@%%@NL@%
- %@NL@%
- Msg0 BYTE CR, LF, "TSR deinstalled", CR, LF, 0%@NL@%
- Msg1 BYTE CR, LF, "TSR installed", CR, LF, 0%@NL@%
- Msg2 BYTE CR, LF, "TSR already installed", CR, LF, 0%@NL@%
- Msg3 BYTE CR, LF, "Can't install TSR", CR, LF, 0%@NL@%
- Msg4 BYTE CR, LF, "Can't find MS-DOS Critical Error Flag", CR, LF, 0%@NL@%
- Msg5 BYTE CR, LF, "Can't deinstall TSR", CR, LF, 0%@NL@%
- Msg6 BYTE CR, LF, "Requires MS-DOS 2.0 or later", CR, LF, 0%@NL@%
- Msg7 BYTE CR, LF, "Memory Control Block damaged", CR, LF, 0%@NL@%
- Msg8 BYTE CR, LF, "No ID numbers available", CR, LF, 0%@NL@%
- Msg9 BYTE CR, LF, "Can't free memory block: invalid address", CR, LF,0%@NL@%
- Msg10 BYTE CR, LF, "TSR successfully accessed", CR, LF, 0%@NL@%
- Msg11 BYTE CR, LF, "Can't access: TSR not installed", CR, LF, 0%@NL@%
- Msg12 BYTE CR, LF, "Unrecognized option", CR, LF, 0%@NL@%
- %@NL@%
- INSTALLDATA ENDS%@NL@%
- %@NL@%
- %@NL@%
- INSTALLCODE SEGMENT PARA PUBLIC 'CODE2'%@NL@%
- %@NL@%
- ASSUME ds:@data%@NL@%
- %@NL@%
- %@AB@%;* GetOptions - Scans command line for argument of form /X or -X%@AE@%%@NL@%
- %@AB@%;* where X = specified ASCII character. Presumes that argument is%@AE@%%@NL@%
- %@AB@%;* preceded by either '/' or '-'. Comparisons are case-insensitive.%@AE@%%@NL@%
- %@AB@%;* Designed to be callable only from an assembly language program.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: ES = Segment address of Program Segment Prefix%@AE@%%@NL@%
- %@AB@%;* AL = Argument character for which to scan%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = One of the following codes:%@AE@%%@NL@%
- %@AB@%;* NO_ARGUMENT if empty command line%@AE@%%@NL@%
- %@AB@%;* OK_ARGUMENT if argument found%@AE@%%@NL@%
- %@AB@%;* BAD_ARGUMENT if argument not as specified%@AE@%%@NL@%
- %@AB@%;* ES:DI = Pointer to found argument%@AE@%%@NL@%
- %@NL@%
- GetOptions PROC NEAR%@NL@%
- %@NL@%
- and al, 11011111y %@AB@%; Make character upper-case%@AE@%%@NL@%
- mov ah, NO_ARGUMENT %@AB@%; Assume no argument%@AE@%%@NL@%
- mov di, 80h %@AB@%; Point to command line%@AE@%%@NL@%
- sub ch, ch%@NL@%
- mov cl, BYTE PTR es:[di] %@AB@%; Command-line count%@AE@%%@NL@%
- jcxz exit %@AB@%; If none, quit%@AE@%%@NL@%
- sub bx, bx %@AB@%; Initialize flag%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Find start of argument%@AE@%%@NL@%
- %@NL@%
- loop1:%@NL@%
- inc di %@AB@%; Point to next character%@AE@%%@NL@%
- mov dl, es:[di] %@AB@%; Get character from argument list%@AE@%%@NL@%
- cmp dl, '/' %@AB@%; Find option prefix '/'%@AE@%%@NL@%
- je analyze%@NL@%
- cmp dl, '-' %@AB@%; or option prefix '-'%@AE@%%@NL@%
- je analyze%@NL@%
- .IF (dl != ' ') && (dl != TAB ) %@AB@%; If not white space:%@AE@%%@NL@%
- inc bx %@AB@%; Set flag if command line not empty%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- loop loop1%@NL@%
- %@NL@%
- or bx, bx %@AB@%; Empty command line?%@AE@%%@NL@%
- jz exit %@AB@%; Yes? Normal exit%@AE@%%@NL@%
- jmp SHORT e_exit %@AB@%; Error if no argument is preceded%@AE@%%@NL@%
- %@AB@%; by '-' or '/' prefixes%@AE@%%@NL@%
- %@NL@%
- %@AB@%; '/' or '-' prefix found. Compare command-line character%@AE@%%@NL@%
- %@AB@%; with character specified in AL.%@AE@%%@NL@%
- analyze:%@NL@%
- mov ah, OK_ARGUMENT %@AB@%; Assume argument is okay%@AE@%%@NL@%
- inc di%@NL@%
- mov dl, es:[di]%@NL@%
- and dl, 11011111y %@AB@%; Convert to upper-case%@AE@%%@NL@%
- cmp dl, al %@AB@%; Argument as specified?%@AE@%%@NL@%
- je exit %@AB@%; If so, normal exit%@AE@%%@NL@%
- mov ah, BAD_ARGUMENT %@AB@%; Else signal bad argument,%@AE@%%@NL@%
- inc bx %@AB@%; raise flag, and%@AE@%%@NL@%
- jmp loop1 %@AB@%; continue scan%@AE@%%@NL@%
- %@NL@%
- e_exit:%@NL@%
- mov ah, BAD_ARGUMENT%@NL@%
- exit:%@NL@%
- mov al, ah%@NL@%
- cbw %@AB@%; AX = return code%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetOptions ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* FatalError - Displays an error message and exits to DOS.%@AE@%%@NL@%
- %@AB@%;* Callable from a high-level language.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Err = Error number%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AL = Error number returned to DOS (except DOS 1.x)%@AE@%%@NL@%
- %@NL@%
- FatalError PROC FAR,%@NL@%
- Err:WORD%@NL@%
- %@NL@%
- mov ax, Err%@NL@%
- push ax%@NL@%
- mov bx, @data%@NL@%
- mov ds, bx %@AB@%; DS points to DGROUP%@AE@%%@NL@%
- mov bx, OFFSET _MsgTbl%@NL@%
- shl ax, 1 %@AB@%; Double to get offset into _MsgTbl%@AE@%%@NL@%
- add bx, ax %@AB@%; BX = table index%@AE@%%@NL@%
- mov si, [bx] %@AB@%; DS:SI points to message%@AE@%%@NL@%
- sub bx, bx %@AB@%; BH = page 0%@AE@%%@NL@%
- mov ah, 0Eh %@AB@%; Request video Function 0Eh%@AE@%%@NL@%
- %@NL@%
- .WHILE 1%@NL@%
- lodsb %@AB@%; Get character from ASCIIZ string%@AE@%%@NL@%
- .BREAK .IF al == 0 %@AB@%; Break if null terminator%@AE@%%@NL@%
- int 10h %@AB@%; Display text, advance cursor%@AE@%%@NL@%
- .ENDW%@NL@%
- %@NL@%
- pop ax %@AB@%; Recover original error code%@AE@%%@NL@%
- %@NL@%
- .IF ax == WRONG_DOS %@AB@%; If DOS error:%@AE@%%@NL@%
- int 20h %@AB@%; Terminate Program (Version 1.x)%@AE@%%@NL@%
- .ELSE %@AB@%; Else:%@AE@%%@NL@%
- mov ah, 4Ch %@AB@%; Request DOS Function 4Ch%@AE@%%@NL@%
- int 21h %@AB@%; Terminate Program (2.x and later)%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- FatalError ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* KeepTsr - Calls Terminate-and-Stay-Resident function to%@AE@%%@NL@%
- %@AB@%;* make TSR resident. Callable from a high-level language.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: ParaNum - Number of paragraphs in resident block%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: DOS return code = 0%@AE@%%@NL@%
- %@NL@%
- KeepTsr PROC FAR,%@NL@%
- ParaNum:WORD%@NL@%
- %@NL@%
- mov ax, @data%@NL@%
- mov ds, ax %@AB@%; DS:SI points to "Program%@AE@%%@NL@%
- mov si, OFFSET Msg1 %@AB@%; installed" message%@AE@%%@NL@%
- sub bx, bx %@AB@%; BH = page 0%@AE@%%@NL@%
- mov ah, 0Eh %@AB@%; Request video Function 0Eh%@AE@%%@NL@%
- %@NL@%
- .WHILE 1%@NL@%
- lodsb %@AB@%; Get character from ASCIIZ string%@AE@%%@NL@%
- .BREAK .IF al == 0 %@AB@%; Break if null terminator%@AE@%%@NL@%
- int 10h %@AB@%; Display text, advance cursor%@AE@%%@NL@%
- .ENDW%@NL@%
- %@NL@%
- mov dx, ParaNum %@AB@%; DX = number of paragraphs%@AE@%%@NL@%
- mov ax, 3100h %@AB@%; Request Function 31h, err code = 0%@AE@%%@NL@%
- int 21h %@AB@%; Terminate-and-Stay-Resident%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- KeepTsr ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* FreeTsr - Deinstalls TSR by freeing its two memory blocks: program%@AE@%%@NL@%
- %@AB@%;* block (located at PSP) and environment block (located from address%@AE@%%@NL@%
- %@AB@%;* at offset 2Ch of PSP). Callable from a high-level language.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: PspSeg - Segment address of TSR's Program Segment Prefix%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = 0 if successful, or one of the following error codes:%@AE@%%@NL@%
- %@AB@%;* MCB_DESTROYED if Memory Control Block damaged%@AE@%%@NL@%
- %@AB@%;* INVALID_ADDR if invalid block address%@AE@%%@NL@%
- %@NL@%
- FreeTsr PROC FAR,%@NL@%
- PspSeg:WORD%@NL@%
- %@NL@%
- mov es, PspSeg %@AB@%; ES = address of resident PSP%@AE@%%@NL@%
- mov ah, 49h %@AB@%; Request DOS Function 49h%@AE@%%@NL@%
- int 21h %@AB@%; Release Memory in program block%@AE@%%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If no error:%@AE@%%@NL@%
- mov es, es:[2Ch] %@AB@%; ES = address of environment block%@AE@%%@NL@%
- mov ah, 49h %@AB@%; Request DOS Function 49h%@AE@%%@NL@%
- int 21h %@AB@%; Release Memory in environment block%@AE@%%@NL@%
- .IF !carry? %@AB@%; If no error:%@AE@%%@NL@%
- sub ax, ax %@AB@%; Return AX = 0%@AE@%%@NL@%
- .ENDIF %@AB@%; Else exit with AX = error code%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- FreeTsr ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CallMultiplexC - Interface for CallMultiplex procedure to make it%@AE@%%@NL@%
- %@AB@%;* callable from a high-level language. Separating this ability from%@AE@%%@NL@%
- %@AB@%;* the original CallMultiplex procedure keeps assembly-language calls%@AE@%%@NL@%
- %@AB@%;* to CallMultiplex neater and more concise.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: FuncNum - Function number for multiplex handler%@AE@%%@NL@%
- %@AB@%;* RecvPtr - Far address to recieve ES:DI pointer%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: One of the following return codes:%@AE@%%@NL@%
- %@AB@%;* NOT_INSTALLED IS_INSTALLED NO_IDNUM%@AE@%%@NL@%
- %@AB@%;* ES:DI pointer written to address in RecvPtr%@AE@%%@NL@%
- %@NL@%
- CallMultiplexC PROC FAR USES ds si di,%@NL@%
- FuncNum:WORD, RecvPtr:FPVOID%@NL@%
- %@NL@%
- mov al, BYTE PTR FuncNum %@AB@%; AL = function number%@AE@%%@NL@%
- call CallMultiplex %@AB@%; Multiplex%@AE@%%@NL@%
- %@NL@%
- lds si, RecvPtr %@AB@%; DS:SI = far address of pointer%@AE@%%@NL@%
- mov [si], di %@AB@%; Return ES:DI pointer for the%@AE@%%@NL@%
- mov [si+2], es %@AB@%; benefit of high-level callers%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- CallMultiplexC ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetResidentSize - Returns the number of paragraphs between Program%@AE@%%@NL@%
- %@AB@%;* Segment Prefix and beginning of INSTALLCODE. This routine allows%@AE@%%@NL@%
- %@AB@%;* TSRs written in a high-level language to determine the size in%@AE@%%@NL@%
- %@AB@%;* paragraphs required to make the program resident.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: PspSeg - PSP segment address%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: AX = Number of paragraphs%@AE@%%@NL@%
- %@NL@%
- GetResidentSize PROC FAR,%@NL@%
- PspSeg:WORD%@NL@%
- %@NL@%
- mov ax, INSTALLCODE %@AB@%; Bottom of resident section%@AE@%%@NL@%
- sub ax, PspSeg %@AB@%; AX = number of paragraphs in%@AE@%%@NL@%
- ret %@AB@%; block to be made resident%@AE@%%@NL@%
- %@NL@%
- GetResidentSize ENDP%@NL@%
- %@NL@%
- %@NL@%
- INSTALLCODE ENDS%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%MATH.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\DEMOS\MATH.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL small, pascal, os_dos%@NL@%
- INCLUDE demo.inc%@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* AddLong - Adds two double-word (long) integers.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - add adc%@AE@%%@NL@%
- %@AB@%;* Operator - PTR%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Long1 - First integer%@AE@%%@NL@%
- %@AB@%;* Long2 - Second integer%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Sum as long integer%@AE@%%@NL@%
- %@NL@%
- AddLong PROC,%@NL@%
- Long1:SDWORD, Long2:SDWORD%@NL@%
- %@NL@%
- mov ax, WORD PTR Long1[0] %@AB@%; AX = low word, long1%@AE@%%@NL@%
- mov dx, WORD PTR Long1[2] %@AB@%; DX = high word, long1%@AE@%%@NL@%
- add ax, WORD PTR Long2[0] %@AB@%; Add low word, long2%@AE@%%@NL@%
- adc dx, WORD PTR Long2[2] %@AB@%; Add high word, long2%@AE@%%@NL@%
- ret %@AB@%; Result returned as DX:AX%@AE@%%@NL@%
- %@NL@%
- AddLong ENDP%@NL@%
- %@NL@%
- %@AB@%;* SubLong - Subtracts a double-word (long) integer from another.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - sub sbb%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Long1 - First integer%@AE@%%@NL@%
- %@AB@%;* Long2 - Second integer%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Difference as long integer%@AE@%%@NL@%
- %@NL@%
- SubLong PROC,%@NL@%
- Long1:SDWORD, Long2:SDWORD%@NL@%
- %@NL@%
- mov ax, WORD PTR Long1[0] %@AB@%; AX = low word, long1%@AE@%%@NL@%
- mov dx, WORD PTR Long1[2] %@AB@%; DX = high word, long1%@AE@%%@NL@%
- sub ax, WORD PTR Long2[0] %@AB@%; Subtract low word, long2%@AE@%%@NL@%
- sbb dx, WORD PTR Long2[2] %@AB@%; Subtract high word, long2%@AE@%%@NL@%
- ret %@AB@%; Result returned as DX:AX%@AE@%%@NL@%
- %@NL@%
- SubLong ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* MulLong - Multiplies two unsigned double-word (long) integers. The%@AE@%%@NL@%
- %@AB@%;* procedure allows for a product of twice the length of the multipliers,%@AE@%%@NL@%
- %@AB@%;* thus preventing overflows. The result is copied into a 4-word data area%@AE@%%@NL@%
- %@AB@%;* and a pointer to the data area is returned.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instruction - mul%@AE@%%@NL@%
- %@AB@%;* Predefined equate - @data%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Long1 - First integer (multiplicand)%@AE@%%@NL@%
- %@AB@%;* Long2 - Second integer (multiplier)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Pointer to quadword result%@AE@%%@NL@%
- %@NL@%
- .DATA%@NL@%
- PUBLIC result%@NL@%
- result QWORD WORD PTR ? %@AB@%; Result from MulLong%@AE@%%@NL@%
- %@NL@%
- .CODE%@NL@%
- MulLong PROC,%@NL@%
- Long1:DWORD, Long2:DWORD%@NL@%
- %@NL@%
- mov ax, WORD PTR Long2[2] %@AB@%; Multiply long2 high word%@AE@%%@NL@%
- mul WORD PTR Long1[2] %@AB@%; by long1 high word%@AE@%%@NL@%
- mov WORD PTR result[4], ax%@NL@%
- mov WORD PTR result[6], dx%@NL@%
- %@NL@%
- mov ax, WORD PTR Long2[2] %@AB@%; Multiply long2 high word%@AE@%%@NL@%
- mul WORD PTR Long1[0] %@AB@%; by long1 low word%@AE@%%@NL@%
- mov WORD PTR result[2], ax%@NL@%
- add WORD PTR result[4], dx%@NL@%
- adc WORD PTR result[6], 0 %@AB@%; Add any remnant carry%@AE@%%@NL@%
- %@NL@%
- mov ax, WORD PTR Long2[0] %@AB@%; Multiply long2 low word%@AE@%%@NL@%
- mul WORD PTR Long1[2] %@AB@%; by long1 high word%@AE@%%@NL@%
- add WORD PTR result[2], ax%@NL@%
- adc WORD PTR result[4], dx%@NL@%
- adc WORD PTR result[6], 0 %@AB@%; Add any remnant carry%@AE@%%@NL@%
- %@NL@%
- mov ax, WORD PTR Long2[0] %@AB@%; Multiply long2 low word%@AE@%%@NL@%
- mul WORD PTR Long1[0] %@AB@%; by long1 low word%@AE@%%@NL@%
- mov WORD PTR result[0], ax%@NL@%
- add WORD PTR result[2], dx%@NL@%
- adc WORD PTR result[4], 0 %@AB@%; Add any remnant carry%@AE@%%@NL@%
- %@NL@%
- mov ax, OFFSET result %@AB@%; Return pointer%@AE@%%@NL@%
- mov dx, @data %@AB@%; to result%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- MulLong ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* ImulLong - Multiplies two signed double-word integers. Because the imul%@AE@%%@NL@%
- %@AB@%;* instruction (illustrated here) treats each word as a signed number, its%@AE@%%@NL@%
- %@AB@%;* use is impractical when multiplying multi-word values. Thus the technique%@AE@%%@NL@%
- %@AB@%;* used in the MulLong procedure can't be adopted here. Instead, ImulLong%@AE@%%@NL@%
- %@AB@%;* is broken into three sections arranged in ascending order of computational%@AE@%%@NL@%
- %@AB@%;* overhead. The procedure tests the values of the two integers and selects%@AE@%%@NL@%
- %@AB@%;* the section that involves the minimum required effort to multiply them.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instruction - imul%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Long1 - First integer (multiplicand)%@AE@%%@NL@%
- %@AB@%;* Long2 - Second integer (multiplier)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Result as long integer%@AE@%%@NL@%
- %@NL@%
- ImulLong PROC USES si,%@NL@%
- Long1:SDWORD, Long2:SDWORD%@NL@%
- %@NL@%
- %@AB@%; Section 1 tests for integers in the range of 0 to 65,535. If both%@AE@%%@NL@%
- %@AB@%; numbers are within these limits, they're treated as unsigned short%@AE@%%@NL@%
- %@AB@%; integers.%@AE@%%@NL@%
- %@NL@%
- mov ax, WORD PTR Long2[0] %@AB@%; AX = low word of long2%@AE@%%@NL@%
- mov dx, WORD PTR Long2[2] %@AB@%; DX = high word of long2%@AE@%%@NL@%
- mov bx, WORD PTR Long1[0] %@AB@%; BX = low word of long1%@AE@%%@NL@%
- mov cx, WORD PTR Long1[2] %@AB@%; CX = high word of long1%@AE@%%@NL@%
- .IF (dx == 0) && (cx == 0) %@AB@%; If both high words are zero:%@AE@%%@NL@%
- mul bx %@AB@%; Multiply the low words%@AE@%%@NL@%
- jmp exit %@AB@%; and exit section 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Section 2 tests for integers in the range of -32,768 to 32,767. If%@AE@%%@NL@%
- %@AB@%; both numbers are within these limits, they're treated as signed short%@AE@%%@NL@%
- %@AB@%; integers.%@AE@%%@NL@%
- %@NL@%
- push ax %@AB@%; Save long2 low word%@AE@%%@NL@%
- push bx %@AB@%; Save long1 low word%@AE@%%@NL@%
- or dx, dx %@AB@%; High word of long2 = 0?%@AE@%%@NL@%
- jnz notzhi2 %@AB@%; No? Test for negative%@AE@%%@NL@%
- test ah, 80h %@AB@%; Low word of long2 in range?%@AE@%%@NL@%
- jz notnlo2 %@AB@%; Yes? long2 ok, so test long1%@AE@%%@NL@%
- jmp sect3 %@AB@%; No? Go to section 3%@AE@%%@NL@%
- notzhi2:%@NL@%
- cmp dx, 0FFFFh %@AB@%; Empty with sign flag set?%@AE@%%@NL@%
- jne sect3 %@AB@%; No? Go to section 3%@AE@%%@NL@%
- test ah, 80h %@AB@%; High bit set in low word?%@AE@%%@NL@%
- jz sect3 %@AB@%; No? Low word is too high%@AE@%%@NL@%
- notnlo2:%@NL@%
- or cx, cx %@AB@%; High word of long1 = 0?%@AE@%%@NL@%
- jnz notzhi1 %@AB@%; No? Test for negative%@AE@%%@NL@%
- test bh, 80h %@AB@%; Low word of long1 in range?%@AE@%%@NL@%
- jz notnlo1 %@AB@%; Yes? long1 ok, so use sect 2%@AE@%%@NL@%
- jmp sect3 %@AB@%; No? Go to section 3%@AE@%%@NL@%
- notzhi1:%@NL@%
- cmp cx, 0FFFFh %@AB@%; Empty with sign flag set?%@AE@%%@NL@%
- jne sect3 %@AB@%; No? Go to section 3%@AE@%%@NL@%
- test bh, 80h %@AB@%; High bit set in low word?%@AE@%%@NL@%
- jz sect3 %@AB@%; No? Low word is too high%@AE@%%@NL@%
- notnlo1:%@NL@%
- imul bx %@AB@%; Multiply low words%@AE@%%@NL@%
- pop bx %@AB@%; Clean stack%@AE@%%@NL@%
- pop bx%@NL@%
- jmp exit %@AB@%; Exit section 2%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Section 3 involves the most computational overhead. It treats the two%@AE@%%@NL@%
- %@AB@%; numbers as signed long (double-word) integers.%@AE@%%@NL@%
- %@NL@%
- sect3:%@NL@%
- pop bx %@AB@%; Recover long1 low word%@AE@%%@NL@%
- pop ax %@AB@%; Recover long2 low word%@AE@%%@NL@%
- mov si, dx %@AB@%; SI = long2 high word%@AE@%%@NL@%
- push ax %@AB@%; Save long2 low word%@AE@%%@NL@%
- mul cx %@AB@%; long1 high word x long2 low word%@AE@%%@NL@%
- mov cx, ax %@AB@%; Accumulate products in CX%@AE@%%@NL@%
- mov ax, bx %@AB@%; AX = low word of long1%@AE@%%@NL@%
- mul si %@AB@%; Multiply by long2 high word%@AE@%%@NL@%
- add cx, ax %@AB@%; Add to previous product%@AE@%%@NL@%
- pop ax %@AB@%; Recover long2 low word%@AE@%%@NL@%
- mul bx %@AB@%; Multiply by long1 low word%@AE@%%@NL@%
- add dx, cx %@AB@%; Add to product high word%@AE@%%@NL@%
- exit:%@NL@%
- ret %@AB@%; Return result as DX:AX%@AE@%%@NL@%
- %@NL@%
- ImulLong ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* DivLong - Divides an unsigned long integer by an unsigned short integer.%@AE@%%@NL@%
- %@AB@%;* The procedure does not check for overflow or divide-by-zero.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instruction - div%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Long1 - First integer (dividend)%@AE@%%@NL@%
- %@AB@%;* Short2 - Second integer (divisor)%@AE@%%@NL@%
- %@AB@%;* Remn - Pointer to remainder%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Quotient as short integer%@AE@%%@NL@%
- %@NL@%
- DivLong PROC USES di,%@NL@%
- Long1:DWORD, Short2:WORD, Remn:PWORD%@NL@%
- %@NL@%
- mov ax, WORD PTR Long1[0] %@AB@%; AX = low word of dividend%@AE@%%@NL@%
- mov dx, WORD PTR Long1[2] %@AB@%; DX = high word of dividend%@AE@%%@NL@%
- div Short2 %@AB@%; Divide by short integer%@AE@%%@NL@%
- LoadPtr es, di, Remn %@AB@%; Point ES:DI to remainder%@AE@%%@NL@%
- mov es:[di], dx %@AB@%; Copy remainder%@AE@%%@NL@%
- ret %@AB@%; Return with AX = quotient%@AE@%%@NL@%
- %@NL@%
- DivLong ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* IdivLong - Divides a signed long integer by a signed short integer.%@AE@%%@NL@%
- %@AB@%;* The procedure does not check for overflow or divide-by-zero.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instruction - idiv%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Long1 - First integer (dividend)%@AE@%%@NL@%
- %@AB@%;* Short2 - Second integer (divisor)%@AE@%%@NL@%
- %@AB@%;* Remn - Pointer to remainder%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Quotient as short integer%@AE@%%@NL@%
- %@NL@%
- IdivLong PROC USES di,%@NL@%
- Long1:SDWORD, Short2:SWORD, Remn:PSWORD%@NL@%
- %@NL@%
- mov ax, WORD PTR Long1[0] %@AB@%; AX = low word of dividend%@AE@%%@NL@%
- mov dx, WORD PTR Long1[2] %@AB@%; DX = high word of dividend%@AE@%%@NL@%
- idiv Short2 %@AB@%; Divide by short integer%@AE@%%@NL@%
- LoadPtr es, di, Remn %@AB@%; ES:DI = remainder%@AE@%%@NL@%
- mov es:[di], dx %@AB@%; Copy remainder%@AE@%%@NL@%
- ret %@AB@%; Return with AX = quotient%@AE@%%@NL@%
- %@NL@%
- IdivLong ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Quadratic - Solves for the roots of a quadratic equation of form%@AE@%%@NL@%
- %@AB@%;* A*x*x + B*x + C = 0%@AE@%%@NL@%
- %@AB@%;* using floating-point instructions. This procedure requires either a math%@AE@%%@NL@%
- %@AB@%;* coprocessor or emulation code.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - sahf fld1 fld fadd fmul%@AE@%%@NL@%
- %@AB@%;* fxch fsubr fchs fsubp fstp%@AE@%%@NL@%
- %@AB@%;* fst fstsw fdivr fwait ftst%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: a - Constant for 2nd-order term%@AE@%%@NL@%
- %@AB@%;* b - Constant for 1st-order term%@AE@%%@NL@%
- %@AB@%;* c - Equation constant%@AE@%%@NL@%
- %@AB@%;* R1 - Pointer to 1st root%@AE@%%@NL@%
- %@AB@%;* R2 - Pointer to 2nd root%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with return code%@AE@%%@NL@%
- %@AB@%;* 0 if both roots found%@AE@%%@NL@%
- %@AB@%;* 1 if single root (placed in R1)%@AE@%%@NL@%
- %@AB@%;* 2 if indeterminate%@AE@%%@NL@%
- %@NL@%
- Quadratic PROC USES ds di si,%@NL@%
- aa:DWORD, bb:DWORD, cc:DWORD, r1:PDWORD, r2:PDWORD%@NL@%
- %@NL@%
- LOCAL status:WORD %@AB@%; Intermediate status%@AE@%%@NL@%
- %@NL@%
- LoadPtr es, di, r1 %@AB@%; ES:DI points to 1st root%@AE@%%@NL@%
- LoadPtr ds, si, r2 %@AB@%; DS:SI points to 2nd root%@AE@%%@NL@%
- sub bx, bx %@AB@%; Clear error code%@AE@%%@NL@%
- fld1 %@AB@%; Load top of stack with 1%@AE@%%@NL@%
- fadd st, st %@AB@%; Double it to make 2%@AE@%%@NL@%
- fld st %@AB@%; Copy to next register%@AE@%%@NL@%
- fmul aa %@AB@%; ST register = 2a%@AE@%%@NL@%
- ftst %@AB@%; Test current ST value%@AE@%%@NL@%
- fstsw status %@AB@%; Copy status to local word%@AE@%%@NL@%
- fwait %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
- mov ax, status %@AB@%; Copy status into AX%@AE@%%@NL@%
- sahf %@AB@%; Load flag register%@AE@%%@NL@%
- jnz notzero %@AB@%; If C3 set, a = 0, in which case%@AE@%%@NL@%
- %@AB@%; solution is x = -c / b%@AE@%%@NL@%
- fld cc %@AB@%; Load c parameter%@AE@%%@NL@%
- fchs %@AB@%; Reverse sign%@AE@%%@NL@%
- fld bb %@AB@%; Load b parameter%@AE@%%@NL@%
- ftst %@AB@%; Test current ST value%@AE@%%@NL@%
- fstsw status %@AB@%; Copy status to local word%@AE@%%@NL@%
- fwait %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
- mov ax, status %@AB@%; Copy status into AX%@AE@%%@NL@%
- sahf %@AB@%; Load flag register%@AE@%%@NL@%
- jz exit2 %@AB@%; If C3 set, b = 0, in which case%@AE@%%@NL@%
- %@AB@%; division by zero%@AE@%%@NL@%
- fdiv %@AB@%; Divide by B%@AE@%%@NL@%
- fstp DWORD PTR es:[di] %@AB@%; Copy result and pop stack%@AE@%%@NL@%
- fstp st %@AB@%; Clean up stack%@AE@%%@NL@%
- jmp exit1 %@AB@%; Return with code = 1%@AE@%%@NL@%
- notzero:%@NL@%
- fmul st(1), st %@AB@%; ST(1) register = 4a%@AE@%%@NL@%
- fxch %@AB@%; Exchange ST and ST(1)%@AE@%%@NL@%
- fmul cc %@AB@%; ST register = 4ac%@AE@%%@NL@%
- ftst %@AB@%; Test current ST value%@AE@%%@NL@%
- fstsw status %@AB@%; Copy status to local word%@AE@%%@NL@%
- fwait %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
- mov ax, status %@AB@%; Copy status into AX%@AE@%%@NL@%
- sahf %@AB@%; Load flag register%@AE@%%@NL@%
- jp exit2 %@AB@%; If C2 set, 4*a*c is infinite%@AE@%%@NL@%
- %@NL@%
- fld bb %@AB@%; Else load b parameter%@AE@%%@NL@%
- fmul st, st %@AB@%; Square it; ST register = b*b%@AE@%%@NL@%
- fsubr %@AB@%; ST register = b*b - 4*a*c%@AE@%%@NL@%
- ftst %@AB@%; Test current ST value%@AE@%%@NL@%
- fstsw status %@AB@%; Copy status to local word%@AE@%%@NL@%
- fwait %@AB@%; Ensure coprocessor is done%@AE@%%@NL@%
- mov ax, status %@AB@%; Copy status into AX%@AE@%%@NL@%
- sahf %@AB@%; Load flag register%@AE@%%@NL@%
- jc exit2 %@AB@%; If C0 set, b*b < 4ac%@AE@%%@NL@%
- jnz tworoot %@AB@%; If C3 set, b*b = 4ac, in which%@AE@%%@NL@%
- inc bx %@AB@%; case only 1 root so set flag%@AE@%%@NL@%
- tworoot:%@NL@%
- fsqrt %@AB@%; Get square root%@AE@%%@NL@%
- fld bb %@AB@%; Load b parameter%@AE@%%@NL@%
- fchs %@AB@%; Reverse sign%@AE@%%@NL@%
- fxch %@AB@%; Exchange ST and ST1%@AE@%%@NL@%
- fld st %@AB@%; Copy square root to next reg%@AE@%%@NL@%
- fadd st, st(2) %@AB@%; ST = -b + sqrt(b*b - 4*a*c)%@AE@%%@NL@%
- fxch %@AB@%; Exchange ST and ST1%@AE@%%@NL@%
- fsubp st(2), st %@AB@%; ST = -b - sqrt(b*b - 4*a*c)%@AE@%%@NL@%
- %@NL@%
- fdiv st, st(2) %@AB@%; Divide 1st dividend by 2*a%@AE@%%@NL@%
- fstp DWORD PTR es:[di] %@AB@%; Copy result, pop stack%@AE@%%@NL@%
- fdivr %@AB@%; Divide 2nd dividend by 2*a%@AE@%%@NL@%
- fstp DWORD PTR ds:[si] %@AB@%; Copy result, pop stack%@AE@%%@NL@%
- jmp exit %@AB@%; Return with code%@AE@%%@NL@%
- exit2:%@NL@%
- inc bx %@AB@%; Error code = 2 for indeterminancy%@AE@%%@NL@%
- fstp st %@AB@%; Clean stack%@AE@%%@NL@%
- exit1:%@NL@%
- inc bx %@AB@%; Error code = 1 for single root%@AE@%%@NL@%
- fstp st %@AB@%; Clean stack%@AE@%%@NL@%
- exit:%@NL@%
- mov ax, bx%@NL@%
- ret%@NL@%
- %@NL@%
- Quadratic ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%MISC.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\DEMOS\MISC.ASM%@AE@%%@NL@%
- %@NL@%
- .modeL small, pascal, os_dos%@NL@%
- INCLUDE demo.inc%@NL@%
- %@NL@%
- .DATA%@NL@%
- _psp PSEG ? %@AB@%; Segment of PSP%@AE@%%@NL@%
- _env PSEG ? %@AB@%; Segment of environment%@AE@%%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* WinOpen - Saves portion of screen to allocated memory, then opens a window%@AE@%%@NL@%
- %@AB@%;* with specified fill attribute. See also the WinClose procedure.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 48h (Allocate Memory Block)%@AE@%%@NL@%
- %@AB@%;* Instructions - movsw stosw rep%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Row1 - Row at top of window%@AE@%%@NL@%
- %@AB@%;* Col1 - Column at left edge of window%@AE@%%@NL@%
- %@AB@%;* Row2 - Row at bottom of window%@AE@%%@NL@%
- %@AB@%;* Col2 - Column at right edge of window%@AE@%%@NL@%
- %@AB@%;* Attr - Fill attribute for window%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with segment address of allocated buffer, or%@AE@%%@NL@%
- %@AB@%;* 0 if unable to allocate memory%@AE@%%@NL@%
- %@NL@%
- WinOpen PROC USES ds di si,%@NL@%
- Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD, Attr:WORD%@NL@%
- %@NL@%
- GetVidOffset Row1, Col1 %@AB@%; Get offset in video segment%@AE@%%@NL@%
- mov si, ax %@AB@%; SI = video offset for window%@AE@%%@NL@%
- mov bx, Row2%@NL@%
- sub bx, Row1%@NL@%
- inc bx %@AB@%; BX = number of window rows%@AE@%%@NL@%
- mov cx, Col2%@NL@%
- sub cx, Col1%@NL@%
- inc cx %@AB@%; CX = number of columns%@AE@%%@NL@%
- %@NL@%
- mov ax, cx %@AB@%; Compute number of video%@AE@%%@NL@%
- mul bl %@AB@%; cells in window%@AE@%%@NL@%
- add ax, 3 %@AB@%; Plus 3 additional entries%@AE@%%@NL@%
- shr ax, 1 %@AB@%; Shift right 3 times to%@AE@%%@NL@%
- shr ax, 1 %@AB@%; multiply by 2 bytes/cell,%@AE@%%@NL@%
- shr ax, 1 %@AB@%; divide by 16 bytes/para%@AE@%%@NL@%
- inc ax %@AB@%; Add a paragraph%@AE@%%@NL@%
- push bx %@AB@%; Save number of rows%@AE@%%@NL@%
- mov bx, ax %@AB@%; BX = number of paragraphs%@AE@%%@NL@%
- mov ah, 48h %@AB@%; Request DOS Function 48h%@AE@%%@NL@%
- int 21h %@AB@%; Allocate Memory Block%@AE@%%@NL@%
- pop bx%@NL@%
- %@NL@%
- .IF carry? %@AB@%; If unsuccessful:%@AE@%%@NL@%
- sub ax, ax %@AB@%; Return null pointer%@AE@%%@NL@%
- .ELSE%@NL@%
- mov es, ax %@AB@%; Point ES:DI to allocated%@AE@%%@NL@%
- sub di, di %@AB@%; buffer%@AE@%%@NL@%
- mov ax, si%@NL@%
- stosw %@AB@%; Copy video offset to buffer%@AE@%%@NL@%
- mov ax, bx%@NL@%
- stosw %@AB@%; Number of rows to buffer%@AE@%%@NL@%
- mov ax, cx%@NL@%
- stosw %@AB@%; Number of cols to buffer%@AE@%%@NL@%
- mov ax, 160 %@AB@%; Number of video cells/row%@AE@%%@NL@%
- mov ds, vconfig.sgmnt %@AB@%; DS = video segment%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push si %@AB@%; Save ptr to start of line%@AE@%%@NL@%
- push cx %@AB@%; and number of columns%@AE@%%@NL@%
- %@NL@%
- %@AB@%; For CGA adapters, WinOpen avoids screen "snow" by disabling the video prior%@AE@%%@NL@%
- %@AB@%; to block memory moves, then reenabling it. Although this technique can%@AE@%%@NL@%
- %@AB@%; result in brief flickering, it demonstrates the fastest way to access a%@AE@%%@NL@%
- %@AB@%; block in the CGA video buffer without causing display snow. See also the%@AE@%%@NL@%
- %@AB@%; StrWrite procedure for another solution to the problem of CGA snow.%@AE@%%@NL@%
- %@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If not CGA adapter,%@AE@%%@NL@%
- INVOKE DisableCga %@AB@%; disable video%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- rep movsw %@AB@%; Copy one row to buffer%@AE@%%@NL@%
- %@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter,%@AE@%%@NL@%
- INVOKE EnableCga %@AB@%; reenable CGA video%@AE@%%@NL@%
- .ENDIF%@NL@%
- pop cx %@AB@%; Recover number of columns%@AE@%%@NL@%
- pop si %@AB@%; and start of line%@AE@%%@NL@%
- add si, ax %@AB@%; Point to start of next line%@AE@%%@NL@%
- dec bx %@AB@%; Decrement row counter%@AE@%%@NL@%
- .UNTIL zero? %@AB@%; Until no rows remain%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Screen contents (including display attributes) are now copied to buffer.%@AE@%%@NL@%
- %@AB@%; Next open window, overwriting the screen portion just saved.%@AE@%%@NL@%
- %@NL@%
- mov ax, 0600h %@AB@%; Scroll service%@AE@%%@NL@%
- mov bh, BYTE PTR Attr %@AB@%; Fill attribute%@AE@%%@NL@%
- mov cx, Col1 %@AB@%; CX = row/col for upper left%@AE@%%@NL@%
- mov ch, BYTE PTR Row1%@NL@%
- mov dx, Col2 %@AB@%; DX = row/col for lower right%@AE@%%@NL@%
- mov dh, BYTE PTR Row2%@NL@%
- int 10h %@AB@%; Blank window area on screen%@AE@%%@NL@%
- mov ax, es %@AB@%; Return address of allocated%@AE@%%@NL@%
- .ENDIF %@AB@%; segment%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- WinOpen ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* WinClose - "Closes" a window previously opened by the WinOpen procedure.%@AE@%%@NL@%
- %@AB@%;* See also the WinOpen procedure.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 49h (Release Memory Block)%@AE@%%@NL@%
- %@AB@%;* Instructions - lodsw%@AE@%%@NL@%
- %@AB@%;* Operators - : (segment override) SEG%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Adr - Segment address of buffer that holds screen contents%@AE@%%@NL@%
- %@AB@%;* saved in WinOpen procedure%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- WinClose PROC USES ds di si,%@NL@%
- Adr:WORD%@NL@%
- %@NL@%
- mov ds, Adr %@AB@%; DS:SI points to buffer%@AE@%%@NL@%
- sub si, si%@NL@%
- lodsw%@NL@%
- mov di, ax %@AB@%; DI = video offset of window%@AE@%%@NL@%
- lodsw%@NL@%
- mov bx, ax %@AB@%; BX = number of window rows%@AE@%%@NL@%
- lodsw%@NL@%
- mov cx, ax %@AB@%; CX = number of columns%@AE@%%@NL@%
- %@NL@%
- mov ax, SEG vconfig.sgmnt%@NL@%
- mov es, ax %@AB@%; Point ES to data segment%@AE@%%@NL@%
- push es:vconfig.sgmnt%@NL@%
- pop es %@AB@%; ES = video segment%@AE@%%@NL@%
- mov ax, 160 %@AB@%; Number of video cells/row%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push di %@AB@%; Save ptr to start of line%@AE@%%@NL@%
- push cx %@AB@%; and number of columns%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Disable CGA video prior to memory move to avoid screen snow. (See the%@AE@%%@NL@%
- %@AB@%; WinOpen and StrWrite procedures for further discussions on CGA snow.)%@AE@%%@NL@%
- %@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter,%@AE@%%@NL@%
- INVOKE DisableCga %@AB@%; disable video%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- rep movsw %@AB@%; Copy one row to buffer%@AE@%%@NL@%
- %@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter,%@AE@%%@NL@%
- INVOKE EnableCga %@AB@%; reenable CGA video%@AE@%%@NL@%
- .ENDIF%@NL@%
- pop cx %@AB@%; Recover number of columns%@AE@%%@NL@%
- pop di %@AB@%; and start of line%@AE@%%@NL@%
- add di, ax %@AB@%; Point to start of next line%@AE@%%@NL@%
- dec bx %@AB@%; Decrement row counter%@AE@%%@NL@%
- .UNTIL zero? %@AB@%; until no rows remain%@AE@%%@NL@%
- %@NL@%
- mov ah, 49h %@AB@%; Request DOS Function 49h%@AE@%%@NL@%
- mov es, Adr%@NL@%
- int 21h %@AB@%; Release Memory Block%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- WinClose ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* SetCurSize - Sets cursor size.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 1 (Set Cursor Type)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Scan1 - Starting scan line%@AE@%%@NL@%
- %@AB@%;* Scan2 - Ending scan line%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- SetCurSize PROC,%@NL@%
- Scan1:WORD, Scan2:WORD%@NL@%
- %@NL@%
- mov cx, Scan2 %@AB@%; CL = ending scan line%@AE@%%@NL@%
- mov ch, BYTE PTR Scan1 %@AB@%; CH = starting scan line%@AE@%%@NL@%
- mov ah, 1 %@AB@%; Function 1%@AE@%%@NL@%
- int 10h %@AB@%; Set Cursor Type%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- SetCurSize ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetCurSize - Gets current cursor size.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 3 (Get Cursor Position)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with high byte = top scan line,%@AE@%%@NL@%
- %@AB@%;* low byte = bottom scan line%@AE@%%@NL@%
- %@NL@%
- GetCurSize PROC%@NL@%
- %@NL@%
- mov ah, 3 %@AB@%; Function 3%@AE@%%@NL@%
- mov bh, vconfig.dpage%@NL@%
- int 10h %@AB@%; Get Cursor Position%@AE@%%@NL@%
- mov ax, cx %@AB@%; Return cursor size%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetCurSize ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetShift - Gets current shift status. Checks for extended keyboard,%@AE@%%@NL@%
- %@AB@%;* and if available returns additional shift information.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 16h, Functions 2 and 12h (Get Keyboard Flags)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Long integer%@AE@%%@NL@%
- %@AB@%;* high word = 0 for non-extended keyboard%@AE@%%@NL@%
- %@AB@%;* 1 for extended keyboard%@AE@%%@NL@%
- %@AB@%;* low word has following bits set when indicated keys are pressed:%@AE@%%@NL@%
- %@AB@%;* 0 - Right shift 8 - Left Ctrl%@AE@%%@NL@%
- %@AB@%;* 1 - Left shift 9 - Left Alt%@AE@%%@NL@%
- %@AB@%;* 2 - Ctrl 10 - Right Ctrl%@AE@%%@NL@%
- %@AB@%;* 3 - Alt 11 - Right Alt%@AE@%%@NL@%
- %@AB@%;* 4 - Scroll Lock active 12 - Scroll Lock pressed%@AE@%%@NL@%
- %@AB@%;* 5 - Num Lock active 13 - Num Lock pressed%@AE@%%@NL@%
- %@AB@%;* 6 - Caps Lock active 14 - Caps Lock pressed%@AE@%%@NL@%
- %@AB@%;* 7 - Insert toggled 15 - Sys Req pressed%@AE@%%@NL@%
- %@NL@%
- GetShift PROC%@NL@%
- %@NL@%
- sub dx, dx %@AB@%; Assume non-extended keyboard%@AE@%%@NL@%
- mov ah, 2 %@AB@%; and use Function 2%@AE@%%@NL@%
- mov es, dx %@AB@%; Point ES to low memory%@AE@%%@NL@%
- .IF BYTE PTR es:[496h] & 16 %@AB@%; If extended keyboard installed,%@AE@%%@NL@%
- inc dx %@AB@%; Set high word of return code%@AE@%%@NL@%
- mov ah, 12h %@AB@%; and use Function 12h%@AE@%%@NL@%
- .ENDIF%@NL@%
- int 16h %@AB@%; Get Keyboard Flags%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetShift ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetKeyClock - Waits for keypress while updating time at specified location%@AE@%%@NL@%
- %@AB@%;* on screen.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 16h, Functions 0 and 10h (Read Character)%@AE@%%@NL@%
- %@AB@%;* 16h, Functions 1 and 11h (Get Keyboard Status)%@AE@%%@NL@%
- %@AB@%;* DOS Functions - 2Ah (Get Date)%@AE@%%@NL@%
- %@AB@%;* 2Ch (Get Time)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Row - Screen row for clock display%@AE@%%@NL@%
- %@AB@%;* Col - Screen column for clock display%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with key scan code in high byte and ASCII%@AE@%%@NL@%
- %@AB@%;* character code in low byte. Low byte is 0 for special%@AE@%%@NL@%
- %@AB@%;* keys (such as the "F" keys) which don't generate characters.%@AE@%%@NL@%
- %@NL@%
- .DATA%@NL@%
- PUBLIC datestr%@NL@%
- datestr BYTE " - - : : ", 0 %@AB@%; Date/time string%@AE@%%@NL@%
- .CODE%@NL@%
- %@NL@%
- GetKeyClock PROC,%@NL@%
- Row:WORD, Col:WORD%@NL@%
- %@NL@%
- LOCAL service:BYTE%@NL@%
- %@NL@%
- INVOKE GetShift %@AB@%; Check for extended keyboard%@AE@%%@NL@%
- mov service, 11h %@AB@%; Assume Function 11h%@AE@%%@NL@%
- .IF dx != 1 %@AB@%; If no extended keyboard:%@AE@%%@NL@%
- mov service, 1 %@AB@%; Use Function 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .WHILE 1%@NL@%
- mov ah, service%@NL@%
- int 16h %@AB@%; Get Keyboard Status%@AE@%%@NL@%
- .BREAK .IF !zero? %@AB@%; If no key yet, update clock%@AE@%%@NL@%
- %@NL@%
- %@AB@%; If not monochrome, color text, or black and white, skip clock update%@AE@%%@NL@%
- %@AB@%; and poll keyboard again%@AE@%%@NL@%
- %@NL@%
- .CONTINUE .IF (vconfig.mode != 7) \%@NL@%
- && (vconfig.mode != 3) \%@NL@%
- && (vconfig.mode != 2)%@NL@%
- %@NL@%
- %@AB@%; If 80-column text, get date and time from DOS before again%@AE@%%@NL@%
- %@AB@%; polling keyboard, and display at upper right corner of screen.%@AE@%%@NL@%
- %@NL@%
- mov ah, 2Ch %@AB@%; Request time%@AE@%%@NL@%
- int 21h %@AB@%; Get Time%@AE@%%@NL@%
- mov dl, dh%@NL@%
- push dx %@AB@%; Save seconds,%@AE@%%@NL@%
- push cx %@AB@%; minutes,%@AE@%%@NL@%
- mov cl, ch %@AB@%; and%@AE@%%@NL@%
- push cx %@AB@%; hours%@AE@%%@NL@%
- mov ah, 2Ah %@AB@%; Request date%@AE@%%@NL@%
- int 21h %@AB@%; Get Date%@AE@%%@NL@%
- sub cx, 1900 %@AB@%; Subtract century, CL = year%@AE@%%@NL@%
- push cx %@AB@%; Save year,%@AE@%%@NL@%
- push dx %@AB@%; day,%@AE@%%@NL@%
- mov dl, dh %@AB@%; and%@AE@%%@NL@%
- push dx %@AB@%; month%@AE@%%@NL@%
- %@NL@%
- mov cx, 6%@NL@%
- sub bx, bx%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- pop ax %@AB@%; Recover all 6 numbers in AL%@AE@%%@NL@%
- aam %@AB@%; Convert to unpacked BCD%@AE@%%@NL@%
- xchg al, ah %@AB@%; Switch bytes for word move%@AE@%%@NL@%
- or ax, "00" %@AB@%; Make ASCII numerals%@AE@%%@NL@%
- mov WORD PTR datestr[bx], ax%@AB@%; Copy to string%@AE@%%@NL@%
- add bx, 3 %@AB@%; at every third byte%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- INVOKE StrWrite, Row, Col, ADDR datestr%@NL@%
- .ENDW %@AB@%; Loop again for keypress%@AE@%%@NL@%
- %@NL@%
- mov ah, service %@AB@%; 1 or 11h, depending on keybd%@AE@%%@NL@%
- dec ah %@AB@%; Set AH to 0 or 10h%@AE@%%@NL@%
- int 16h %@AB@%; Get key to remove it from%@AE@%%@NL@%
- ret %@AB@%; keyboard buffer%@AE@%%@NL@%
- %@NL@%
- GetKeyClock ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetPSP - Gets address of Program Segment Prefix. For DOS 3.0 or higher.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 62h (Get PSP Address)%@AE@%%@NL@%
- %@AB@%;* Instruction - call%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with PSP segment address%@AE@%%@NL@%
- %@AB@%;* or 0 if DOS version below 3.0%@AE@%%@NL@%
- %@NL@%
- GetPSP PROC%@NL@%
- %@NL@%
- INVOKE GetVer %@AB@%; Get DOS version number%@AE@%%@NL@%
- .IF ax >= 300 %@AB@%; If DOS 3.0 or higher:%@AE@%%@NL@%
- mov ah, 62h %@AB@%; Query DOS for PSP%@AE@%%@NL@%
- int 21h %@AB@%; Get PSP Address%@AE@%%@NL@%
- mov ax, bx %@AB@%; Return in AX%@AE@%%@NL@%
- .ELSE %@AB@%; Else 2.0:%@AE@%%@NL@%
- sub ax, ax %@AB@%; For version 2, return 0%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- GetPSP ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetMem - Gets total size of memory and determines the largest amount of%@AE@%%@NL@%
- %@AB@%;* unallocated memory available. GetMem invokes DOS Function 48h (Allocate%@AE@%%@NL@%
- %@AB@%;* Memory) to request an impossibly large memory block. DOS denies the re-%@AE@%%@NL@%
- %@AB@%;* quest, but returns instead the size of the largest block available. This%@AE@%%@NL@%
- %@AB@%;* is the amount that GetMem returns to the calling program. See the WinOpen%@AE@%%@NL@%
- %@AB@%;* procedure for an example of calling Function 48h to allocate unused memory.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 12h (Get Conventional Memory Size)%@AE@%%@NL@%
- %@AB@%;* Instructions - push pop ret%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Long integer, high word = total memory in kilobytes (KB)%@AE@%%@NL@%
- %@AB@%;* low word = largest block of available memory (KB)%@AE@%%@NL@%
- %@NL@%
- GetMem PROC%@NL@%
- %@NL@%
- int 12h %@AB@%; Get total memory in K%@AE@%%@NL@%
- push ax %@AB@%; Save size of memory%@AE@%%@NL@%
- mov ah, 48h %@AB@%; Request memory allocation%@AE@%%@NL@%
- mov bx, 0FFFFh %@AB@%; Ensure request is denied for%@AE@%%@NL@%
- %@AB@%; impossibly large block%@AE@%%@NL@%
- int 21h %@AB@%; Get largest available block in BX%@AE@%%@NL@%
- mov ax, bx %@AB@%; Copy to AX%@AE@%%@NL@%
- mov cl, 6 %@AB@%; Convert paragraphs to kilobytes by%@AE@%%@NL@%
- shr ax, cl %@AB@%; dividing by 64%@AE@%%@NL@%
- pop dx %@AB@%; Recover total in DX%@AE@%%@NL@%
- ret %@AB@%; Return long integer DX:AX%@AE@%%@NL@%
- %@NL@%
- GetMem ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* VeriPrint - Checks if LPT1 (PRN) is available.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 17h (Parallel Port Printer Driver)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer, 1 for yes or 0 for no%@AE@%%@NL@%
- %@NL@%
- VeriPrint PROC%@NL@%
- %@NL@%
- mov ah, 2 %@AB@%; Check printer status for%@AE@%%@NL@%
- sub dx, dx %@AB@%; parallel printer (port 0)%@AE@%%@NL@%
- int 17h%@NL@%
- xchg dx, ax %@AB@%; Put 0 (for error) in AX%@AE@%%@NL@%
- %@NL@%
- %@AB@%; If all error bits are off and both operation bits are on, return 1%@AE@%%@NL@%
- %@NL@%
- .IF !(dh & 00101001y) && (dh & 10010000y)%@NL@%
- inc ax %@AB@%; Return 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- VeriPrint ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* IntToAsc - Converts integer to ASCII string. This procedure is useful%@AE@%%@NL@%
- %@AB@%;* only for assembly language, and is not intended to be C-callable.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - aam xchg%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Entry: AX = integer (9999 max)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: DX:AX = 4-digit ASCII number%@AE@%%@NL@%
- %@NL@%
- IntToAsc PROC%@NL@%
- %@NL@%
- cwd %@AB@%; Zero DX register%@AE@%%@NL@%
- mov cx, 100 %@AB@%; Divide AX by 100, yields%@AE@%%@NL@%
- div cx %@AB@%; AX=quotient, DX=remainder%@AE@%%@NL@%
- aam %@AB@%; Make digits unpacked BCD%@AE@%%@NL@%
- or ax, "00" %@AB@%; Convert to ASCII%@AE@%%@NL@%
- xchg ax, dx %@AB@%; Do same thing for DX%@AE@%%@NL@%
- aam%@NL@%
- or ax, "00"%@NL@%
- ret %@AB@%; Return DX:AX = ASCII number%@AE@%%@NL@%
- %@NL@%
- IntToAsc ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* VeriAnsi - Checks for ANSI driver by writing ANSI sequence to report%@AE@%%@NL@%
- %@AB@%;* cursor position. If report compares with position returned from%@AE@%%@NL@%
- %@AB@%;* GetCurPos procedure, then ANSI driver is operating.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Functions - 06h (Direct Console I/O)%@AE@%%@NL@%
- %@AB@%;* 0Ch (Flush Input Buffer and then Input)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer, 1 for yes or 0 for no%@AE@%%@NL@%
- %@NL@%
- .DATA%@NL@%
- PUBLIC report%@NL@%
- report DB ESCAPE, "[6n$" %@AB@%; ANSI Report Cursor sequence%@AE@%%@NL@%
- .CODE%@NL@%
- %@NL@%
- VeriAnsi PROC%@NL@%
- %@NL@%
- %@AB@%; Get cursor position from BIOS%@AE@%%@NL@%
- INVOKE GetCurPos%@NL@%
- mov cx, ax %@AB@%; Save it in CX%@AE@%%@NL@%
- mov dx, OFFSET report %@AB@%; ANSI string to get position%@AE@%%@NL@%
- mov ah, 9 %@AB@%; Request DOS String Output%@AE@%%@NL@%
- int 21h %@AB@%; Write ANSI escape sequence%@AE@%%@NL@%
- %@NL@%
- mov ah, 6 %@AB@%; Skip Esc character in%@AE@%%@NL@%
- mov dl, 0FFh %@AB@%; keyboard buffer%@AE@%%@NL@%
- int 21h%@NL@%
- jz e_exit %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
- mov ah, 6 %@AB@%; Skip '[' character%@AE@%%@NL@%
- int 21h%@NL@%
- jz e_exit %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
- mov ah, 6 %@AB@%; Get 1st digit of cursor row%@AE@%%@NL@%
- int 21h%@NL@%
- jz e_exit %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
- mov bh, al %@AB@%; Store in BH%@AE@%%@NL@%
- mov ah, 6 %@AB@%; Get 2nd digit of cursor row%@AE@%%@NL@%
- int 21h%@NL@%
- jz e_exit %@AB@%; If no key, ANSI not loaded%@AE@%%@NL@%
- mov bl, al %@AB@%; Store in BL%@AE@%%@NL@%
- mov al, ch %@AB@%; Get original row # in AL%@AE@%%@NL@%
- cbw %@AB@%; AX = row # from GetCurPos%@AE@%%@NL@%
- inc ax %@AB@%; Add 1 to it%@AE@%%@NL@%
- call IntToAsc %@AB@%; Make ASCII digits%@AE@%%@NL@%
- cmp ax, bx %@AB@%; ANSI and BIOS reports match?%@AE@%%@NL@%
- jne e_exit %@AB@%; No? Then ANSI not loaded%@AE@%%@NL@%
- %@NL@%
- mov ax, 0C06h %@AB@%; Flush remaining ANSI keys%@AE@%%@NL@%
- mov dl, 0FFh %@AB@%; from buffer%@AE@%%@NL@%
- int 21h%@NL@%
- mov ax, 1 %@AB@%; Set 1 for true%@AE@%%@NL@%
- jmp exit %@AB@%; and exit%@AE@%%@NL@%
- e_exit:%@NL@%
- sub ax, ax %@AB@%; Set 0 return code if no%@AE@%%@NL@%
- exit:%@NL@%
- ret %@AB@%; ANSI driver installed%@AE@%%@NL@%
- %@NL@%
- VeriAnsi ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* VeriCop - Checks for coprocessor.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 11h (Get Equipment Configuration)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer, 1 for yes or 0 for no%@AE@%%@NL@%
- %@NL@%
- VeriCop PROC%@NL@%
- %@NL@%
- int 11h %@AB@%; Check peripherals%@AE@%%@NL@%
- test al, 2 %@AB@%; Coprocessor?%@AE@%%@NL@%
- mov ax, 0 %@AB@%; Assume no, don't alter flags%@AE@%%@NL@%
- .IF !zero?%@NL@%
- inc ax %@AB@%; Set to 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- VeriCop ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* SetLineMode - Sets line mode for EGA or VGA.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 11h (Character Generator Interface)%@AE@%%@NL@%
- %@AB@%;* 10h, Function 12h (Video Subsystem Configuration)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Line - Requested line mode (25, 43, or 50)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if error%@AE@%%@NL@%
- %@NL@%
- SetLineMode PROC,%@NL@%
- Line:WORD%@NL@%
- %@NL@%
- .IF vconfig.adapter >= EGA %@AB@%; If EGA or VGA:%@AE@%%@NL@%
- mov ax, Line %@AB@%; Check for valid parameter%@AE@%%@NL@%
- cmp al, 25%@NL@%
- je line25%@NL@%
- cmp al, 43%@NL@%
- je line43%@NL@%
- cmp al, 50%@NL@%
- je line50%@NL@%
- jmp e_exit %@AB@%; If not 25, 43, or 50, exit w/ error%@AE@%%@NL@%
- line25:%@NL@%
- mov al, 11h %@AB@%; Set for EGA 25-line mode%@AE@%%@NL@%
- cmp vconfig.adapter, EGA %@AB@%; EGA?%@AE@%%@NL@%
- je linemode %@AB@%; Yes? Continue%@AE@%%@NL@%
- mov ax, 1202h %@AB@%; No? Function 12h for VGA%@AE@%%@NL@%
- mov bl, 30h %@AB@%; AL = 2 for 400 scan lines%@AE@%%@NL@%
- int 10h %@AB@%; Reset to 400 scan lines%@AE@%%@NL@%
- mov ax, 0003 %@AB@%; Reset mode (Function 0)%@AE@%%@NL@%
- int 10h %@AB@%; to mode 3 (80-col text)%@AE@%%@NL@%
- mov al, 14h %@AB@%; Request 8x16 char matrix%@AE@%%@NL@%
- jmp linemode%@NL@%
- line43:%@NL@%
- mov al, 12h %@AB@%; Set for EGA 43-line mode%@AE@%%@NL@%
- cmp vconfig.adapter, EGA %@AB@%; EGA?%@AE@%%@NL@%
- je linemode %@AB@%; Yes? Continue%@AE@%%@NL@%
- mov ax, 1201h %@AB@%; No? Function 12h for VGA%@AE@%%@NL@%
- mov bl, 30h %@AB@%; AL = 1 for 350 scan lines%@AE@%%@NL@%
- int 10h %@AB@%; Reset to 350 scan lines%@AE@%%@NL@%
- mov ax, 0003 %@AB@%; Reset mode (Function 0)%@AE@%%@NL@%
- int 10h %@AB@%; to mode 3 (80-col text)%@AE@%%@NL@%
- mov al, 12h %@AB@%; Request 8x8 character matrix%@AE@%%@NL@%
- jmp linemode%@NL@%
- line50:%@NL@%
- cmp vconfig.adapter, VGA %@AB@%; VGA?%@AE@%%@NL@%
- jne e_exit %@AB@%; No? Exit with error%@AE@%%@NL@%
- mov ax, 1202h %@AB@%; Yes? Function 12h%@AE@%%@NL@%
- mov bl, 30h %@AB@%; AL = 2 for 400 scan lines%@AE@%%@NL@%
- int 10h %@AB@%; Reset to 400 scan lines%@AE@%%@NL@%
- mov ax, 0003 %@AB@%; Reset mode (Function 0)%@AE@%%@NL@%
- int 10h %@AB@%; to mode 3 (80-col text)%@AE@%%@NL@%
- mov al, 12h %@AB@%; Request 8x8 character matrix%@AE@%%@NL@%
- linemode:%@NL@%
- sub bl, bl %@AB@%; Use table 0%@AE@%%@NL@%
- mov ah, 11h %@AB@%; Request Function 11h%@AE@%%@NL@%
- int 10h %@AB@%; Set new line mode%@AE@%%@NL@%
- %@NL@%
- mov ah, 12h %@AB@%; Select alternate print%@AE@%%@NL@%
- mov bl, 20h %@AB@%; screen for EGA and VGA%@AE@%%@NL@%
- int 10h%@NL@%
- %@NL@%
- cmp vconfig.adapter, VGA %@AB@%; VGA?%@AE@%%@NL@%
- je exit %@AB@%; Yes? Then exit%@AE@%%@NL@%
- cmp Line, 12h %@AB@%; If EGA 43-line mode, set%@AE@%%@NL@%
- je port %@AB@%; cursor through port to%@AE@%%@NL@%
- %@AB@%; avoid cursor emulation bug%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Set normal cursor size, pass top and bottom scan lines%@AE@%%@NL@%
- INVOKE SetCurSize, 6, 7%@NL@%
- jmp exit%@NL@%
- port:%@NL@%
- mov dx, 03D4h %@AB@%; Video controller address%@AE@%%@NL@%
- mov ax, 060Ah %@AB@%; Set AH = 06h (cursor start)%@AE@%%@NL@%
- %@AB@%; AL = 0Ah (register #)%@AE@%%@NL@%
- out dx, ax %@AB@%; Update port%@AE@%%@NL@%
- mov ax, 000Bh %@AB@%; Set AH = 00h (cursor end)%@AE@%%@NL@%
- %@AB@%; AL = 0Bh (register #)%@AE@%%@NL@%
- out dx, ax %@AB@%; Update port%@AE@%%@NL@%
- jmp exit %@AB@%; Normal exit%@AE@%%@NL@%
- .ENDIF %@AB@%; EGA or VGA%@AE@%%@NL@%
- e_exit:%@NL@%
- mov ax, 1 %@AB@%; Set error code%@AE@%%@NL@%
- jmp exit2%@NL@%
- exit:%@NL@%
- sub ax, ax %@AB@%; Clear error code%@AE@%%@NL@%
- exit2:%@NL@%
- ret%@NL@%
- %@NL@%
- SetLineMode ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Pause - Waits for specified number of clocks to elapse, then returns.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 1Ah, Function 0 (Real-Time Clock Driver)%@AE@%%@NL@%
- %@AB@%;* Operators - LOCAL []%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Duration - Desired duration in clocks, where%@AE@%%@NL@%
- %@AB@%;* 18 clocks = approx 1 second%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Pause PROC,%@NL@%
- Duration:WORD%@NL@%
- %@NL@%
- LOCAL tick:DWORD%@NL@%
- %@NL@%
- sub ah, ah%@NL@%
- int 1Ah %@AB@%; Get Clock Count in CX:DX%@AE@%%@NL@%
- add dx, Duration %@AB@%; Add pause time to it%@AE@%%@NL@%
- adc cx, 0%@NL@%
- mov WORD PTR tick[0], dx %@AB@%; Result is target time;%@AE@%%@NL@%
- mov WORD PTR tick[2], cx %@AB@%; keep in local variable%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- int 1Ah %@AB@%; Poll clock until target time%@AE@%%@NL@%
- .UNTIL (dx >= WORD PTR tick[0]) || (cx >= WORD PTR fileinfo.time[2])%@NL@%
- ret%@NL@%
- %@NL@%
- Pause ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Sound - Sounds speaker with specified frequency and duration.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - in out%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Freq - Desired frequency of sound in Hertz%@AE@%%@NL@%
- %@AB@%;* Duration - Desired duration in clocks, where%@AE@%%@NL@%
- %@AB@%;* 18 clocks = approx 1 second%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Sound PROC,%@NL@%
- Freq:WORD, Duration:WORD%@NL@%
- %@NL@%
- mov al, 0B6h %@AB@%; Initialize channel 2 of%@AE@%%@NL@%
- out 43h, al %@AB@%; timer chip%@AE@%%@NL@%
- mov dx, 12h %@AB@%; Divide 1,193,182 Hertz%@AE@%%@NL@%
- mov ax, 34DEh %@AB@%; (clock frequency) by%@AE@%%@NL@%
- div Freq %@AB@%; desired frequency%@AE@%%@NL@%
- %@AB@%; Result is timer clock count%@AE@%%@NL@%
- out 42h, al %@AB@%; Low byte of count to timer%@AE@%%@NL@%
- mov al, ah%@NL@%
- out 42h, al %@AB@%; High byte of count to timer%@AE@%%@NL@%
- in al, 61h %@AB@%; Read value from port 61h%@AE@%%@NL@%
- or al, 3 %@AB@%; Set first two bits%@AE@%%@NL@%
- out 61h, al %@AB@%; Turn speaker on%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Pause, pass duration of delay%@AE@%%@NL@%
- INVOKE Pause, Duration%@NL@%
- %@NL@%
- in al, 61h %@AB@%; Get port value%@AE@%%@NL@%
- xor al, 3 %@AB@%; Kill bits 0-1 to turn%@AE@%%@NL@%
- out 61h, al %@AB@%; speaker off%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- Sound ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* WriteTTY - Displays ASCIIZ string at cursor position, in either text%@AE@%%@NL@%
- %@AB@%;* or graphics mode.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: BIOS Interrupt - 10h, Function 0Eh (Write Character in TTY Mode)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Sptr - Pointer to ASCIIZ string%@AE@%%@NL@%
- %@AB@%;* icolor - Color index (for graphics mode only)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- WriteTTY PROC USES ds si,%@NL@%
- Sptr:PBYTE, icolor:WORD%@NL@%
- %@NL@%
- mov bx, icolor %@AB@%; BL = color index%@AE@%%@NL@%
- mov bh, vconfig.dpage %@AB@%; BH = current display page%@AE@%%@NL@%
- LoadPtr ds, si, Sptr%@NL@%
- mov cx, -1 %@AB@%; Set loop counter to maximum%@AE@%%@NL@%
- mov ah, 14 %@AB@%; Function 14%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- lodsb %@AB@%; Get character from string%@AE@%%@NL@%
- .BREAK .IF al == 0 %@AB@%; Exit if NULL string terminator%@AE@%%@NL@%
- int 10h %@AB@%; No? Display, advance cursor%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- WriteTTY ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Colors - Alters screen colors within a specified area by using bit%@AE@%%@NL@%
- %@AB@%;* or move operations on display attribute bytes in video memory.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instructions - not rol ror and xor or%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Logic - Code number, 0 = NOT 2 = ROR 4 = XOR 6 = MOV%@AE@%%@NL@%
- %@AB@%;* 1 = ROL 3 = AND 5 = OR%@AE@%%@NL@%
- %@AB@%;* Attr - Attribute mask%@AE@%%@NL@%
- %@AB@%;* Row1 - Row at top of window%@AE@%%@NL@%
- %@AB@%;* Col1 - Column at left edge of window%@AE@%%@NL@%
- %@AB@%;* Row2 - Row at bottom of window%@AE@%%@NL@%
- %@AB@%;* Col2 - Column at right edge of window%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Colors PROC USES ds si,%@NL@%
- Logic:WORD, Attr:WORD, Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD%@NL@%
- %@NL@%
- GetVidOffset Row1, Col1 %@AB@%; Get offset in video segment%@AE@%%@NL@%
- inc ax%@NL@%
- mov si, ax %@AB@%; SI = offset for 1st attr byte%@AE@%%@NL@%
- mov bx, Row2%@NL@%
- sub bx, Row1%@NL@%
- inc bx %@AB@%; BX = number of window rows%@AE@%%@NL@%
- mov cx, Col2%@NL@%
- sub cx, Col1%@NL@%
- inc cx %@AB@%; CX = number of columns%@AE@%%@NL@%
- %@NL@%
- mov ds, vconfig.sgmnt %@AB@%; DS = video segment%@AE@%%@NL@%
- mov ax, Attr %@AB@%; AL = mask for and, xor, and or%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push si %@AB@%; Save ptr to start of line%@AE@%%@NL@%
- push cx %@AB@%; and number of columns%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Disable CGA video prior to memory access to avoid screen snow. (See the%@AE@%%@NL@%
- %@AB@%; WinOpen and StrWrite procedures for further discussions on CGA snow.)%@AE@%%@NL@%
- %@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter:%@AE@%%@NL@%
- INVOKE DisableCga %@AB@%; Yes? Disable video%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- cmp Logic, 1 %@AB@%; Rotate left?%@AE@%%@NL@%
- jl c_not %@AB@%; If less, do NOT%@AE@%%@NL@%
- je c_rol %@AB@%; If equal, do ROL%@AE@%%@NL@%
- cmp Logic, 3 %@AB@%; And?%@AE@%%@NL@%
- jl c_ror %@AB@%; If less, do ROR%@AE@%%@NL@%
- je c_and %@AB@%; If equal, do AND%@AE@%%@NL@%
- cmp Logic, 5 %@AB@%; Or?%@AE@%%@NL@%
- jl c_xor %@AB@%; If less, do XOR%@AE@%%@NL@%
- je c_or %@AB@%; If equal, do OR%@AE@%%@NL@%
- c_mov:%@NL@%
- mov BYTE PTR [si], al %@AB@%; MOV attr parameter%@AE@%%@NL@%
- add si, 2 %@AB@%; into attribute byte%@AE@%%@NL@%
- loop c_mov%@NL@%
- jmp c_done%@NL@%
- c_or:%@NL@%
- or BYTE PTR [si], al %@AB@%; OR with attr parameter%@AE@%%@NL@%
- add si, 2%@NL@%
- loop c_or%@NL@%
- jmp c_done%@NL@%
- c_xor:%@NL@%
- xor BYTE PTR [si], al %@AB@%; XOR with attr parameter%@AE@%%@NL@%
- add si, 2%@NL@%
- loop c_xor%@NL@%
- jmp c_done%@NL@%
- c_and:%@NL@%
- and BYTE PTR [si], al %@AB@%; AND with attr parameter%@AE@%%@NL@%
- add si, 2%@NL@%
- loop c_and%@NL@%
- jmp c_done%@NL@%
- c_ror:%@NL@%
- ror BYTE PTR [si], 1 %@AB@%; Rotate right 1 bit%@AE@%%@NL@%
- add si, 2%@NL@%
- loop c_ror%@NL@%
- jmp c_done%@NL@%
- c_rol:%@NL@%
- rol BYTE PTR [si], 1 %@AB@%; Rotate left 1 bit%@AE@%%@NL@%
- add si, 2%@NL@%
- loop c_rol%@NL@%
- jmp c_done%@NL@%
- c_not:%@NL@%
- not BYTE PTR [si] %@AB@%; Flip bits%@AE@%%@NL@%
- add si, 2%@NL@%
- loop c_not%@NL@%
- c_done:%@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA:%@AE@%%@NL@%
- INVOKE EnableCga %@AB@%; Reenable CGA video%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- pop cx %@AB@%; Recover number of columns%@AE@%%@NL@%
- pop si %@AB@%; Recover offset for start of line%@AE@%%@NL@%
- add si, 160 %@AB@%; Point to start of next line%@AE@%%@NL@%
- dec bx %@AB@%; Decrement row counter%@AE@%%@NL@%
- .UNTIL zero? %@AB@%; Loop while rows remain%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- Colors ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Exec - Executes a child process. Exec handles the usual chores associated%@AE@%%@NL@%
- %@AB@%;* with spawning a process: (1) parsing the command line tail and loading the%@AE@%%@NL@%
- %@AB@%;* FCBs with the first two arguments; (2) setting and restoring the vectors%@AE@%%@NL@%
- %@AB@%;* for Interrupts 1Bh, 23h, and 24h; and (3) querying DOS for the child's%@AE@%%@NL@%
- %@AB@%;* return code.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Functions - 29h (Parse Filename)%@AE@%%@NL@%
- %@AB@%;* 25h (Set Interrupt Vector)%@AE@%%@NL@%
- %@AB@%;* 35h (Get Interrupt Vector)%@AE@%%@NL@%
- %@AB@%;* 4Bh (Execute Program)%@AE@%%@NL@%
- %@AB@%;* 4Dh (Get Return Code)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Spec - Pointer to ASCIIZ specification for program file%@AE@%%@NL@%
- %@AB@%;* (must include .COM or .EXE extension)%@AE@%%@NL@%
- %@AB@%;* Block - Pointer to parameter block structure%@AE@%%@NL@%
- %@AB@%;* CtrBrk - Pointer to new Ctrl+Break (Interrupt 1Bh) handler%@AE@%%@NL@%
- %@AB@%;* CtrlC - Pointer to new Ctrl+C (Interrupt 23h) handler%@AE@%%@NL@%
- %@AB@%;* Criterr - Pointer to new Critical Error (Interrupt 24h) handler%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer with child return code, or -1 for EXEC error%@AE@%%@NL@%
- %@NL@%
- Exec PROC USES ds si di,%@NL@%
- Spec:PBYTE, Block:PPARMBLK, CtrBrk:PTR FAR,%@NL@%
- CtrlC:PTR FAR, Criterr:PTR FAR%@NL@%
- %@NL@%
- Vector 1Bh, Old1Bh, CtrBrk %@AB@%; Save, replace Int 1Bh vector%@AE@%%@NL@%
- Vector 23h, Old23h, CtrlC %@AB@%; Save, replace Int 23h vector%@AE@%%@NL@%
- Vector 24h, Old24h, Criterr %@AB@%; Save, replace Int 24h vector%@AE@%%@NL@%
- %@NL@%
- LoadPtr ds, bx, Block %@AB@%; Point DS:BX to parameter block%@AE@%%@NL@%
- push ds %@AB@%; Save segment address%@AE@%%@NL@%
- les di, (PARMBLK PTR [bx]).fcb1 %@AB@%; Point ES:DI to first FCB%@AE@%%@NL@%
- lds si, (PARMBLK PTR [bx]).taddr %@AB@%; Point DS:SI to command line tail%@AE@%%@NL@%
- inc si %@AB@%; Skip over count byte%@AE@%%@NL@%
- %@NL@%
- mov ax, 2901h %@AB@%; Set AH to request Function 29h%@AE@%%@NL@%
- %@AB@%; AL = flag to skip leading blanks%@AE@%%@NL@%
- int 21h %@AB@%; Parse command-line into first FCB%@AE@%%@NL@%
- pop es %@AB@%; Recover seg addr of parameter block%@AE@%%@NL@%
- les di, (PARMBLK PTR es:[bx]).fcb2 %@AB@%; Point ES:DI to second FCB%@AE@%%@NL@%
- mov ax, 2901h %@AB@%; Request DOS Function #29h again%@AE@%%@NL@%
- int 21h %@AB@%; Parse command-line into second FCB%@AE@%%@NL@%
- %@NL@%
- push bp %@AB@%; Save only important register%@AE@%%@NL@%
- mov WORD PTR cs:OldStk[0], sp%@NL@%
- mov WORD PTR cs:OldStk[2], ss%@NL@%
- LoadPtr es, bx, Block %@AB@%; ES:BX points to param block%@AE@%%@NL@%
- LoadPtr ds, dx, Spec %@AB@%; DS:DX points to path spec%@AE@%%@NL@%
- mov ax, 4B00h %@AB@%; AH = DOS Function 4Bh%@AE@%%@NL@%
- %@AB@%; AL = 0 for load and execute%@AE@%%@NL@%
- int 21h %@AB@%; Execute Program%@AE@%%@NL@%
- mov sp, WORD PTR cs:OldStk[0] %@AB@%; Reset stack pointers%@AE@%%@NL@%
- mov ss, WORD PTR cs:OldStk[2]%@NL@%
- pop bp %@AB@%; Recover saved register%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Restore vectors for Interrupts 1Bh, 23h, and 24h.%@AE@%%@NL@%
- %@NL@%
- mov ax, 251Bh %@AB@%; AH = DOS Function 25h%@AE@%%@NL@%
- %@AB@%; AL = interrupt number%@AE@%%@NL@%
- lds dx, cs:Old1Bh %@AB@%; DS:DX = original vector%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt 1Bh Vector%@AE@%%@NL@%
- mov al, 23h %@AB@%; AL = interrupt number%@AE@%%@NL@%
- lds dx, cs:Old23h %@AB@%; DS:DX = original vector%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt 23h Vector%@AE@%%@NL@%
- mov al, 24h %@AB@%; AL = interrupt number%@AE@%%@NL@%
- lds dx, cs:Old24h %@AB@%; DS:DX = original vector%@AE@%%@NL@%
- int 21h %@AB@%; Set Interrupt 24h Vector%@AE@%%@NL@%
- %@NL@%
- mov ax, -1 %@AB@%; Set error code%@AE@%%@NL@%
- .IF !carry? %@AB@%; If no EXEC error:%@AE@%%@NL@%
- mov ah, 4Dh %@AB@%; Request child's code%@AE@%%@NL@%
- int 21h %@AB@%; Get Return Code%@AE@%%@NL@%
- sub ah, ah %@AB@%; Make short integer%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- Old1Bh FPVOID ? %@AB@%; Keep vectors for Interrupts%@AE@%%@NL@%
- Old23h FPVOID ? %@AB@%; 1Bh, 23h, and 24h in code%@AE@%%@NL@%
- Old24h FPVOID ? %@AB@%; segment, but non-executable%@AE@%%@NL@%
- OldStk FPVOID ? %@AB@%; Keep stack pointer%@AE@%%@NL@%
- %@NL@%
- Exec ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* BinToHex - Converts binary word to 6-byte hexadecimal number in%@AE@%%@NL@%
- %@AB@%;* ASCIIZ string. String is right-justified and includes "h" radix.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instruction - xlat%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Num - Number to convert to hex string%@AE@%%@NL@%
- %@AB@%;* Sptr - Pointer to 6-byte string%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- .DATA%@NL@%
- hex BYTE "0123456789ABCDEF" %@AB@%; String of hex numbers%@AE@%%@NL@%
- %@NL@%
- .CODE%@NL@%
- BinToHex PROC USES di,%@NL@%
- Num:WORD, Sptr:PBYTE%@NL@%
- %@NL@%
- LoadPtr es, di, Sptr %@AB@%; Point ES:DI to 6-byte string%@AE@%%@NL@%
- mov bx, OFFSET hex %@AB@%; Point DS:BX to hex numbers%@AE@%%@NL@%
- mov ax, Num %@AB@%; Number in AX%@AE@%%@NL@%
- mov cx, 2 %@AB@%; Loop twice for two bytes%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- xchg ah, al %@AB@%; Switch bytes%@AE@%%@NL@%
- push ax %@AB@%; Save number%@AE@%%@NL@%
- shr al, 1 %@AB@%; Shift high nibble to low%@AE@%%@NL@%
- shr al, 1%@NL@%
- shr al, 1%@NL@%
- shr al, 1%@NL@%
- xlat %@AB@%; Get equivalent ASCII number in AL%@AE@%%@NL@%
- stosb %@AB@%; Copy to 6-byte string, increment DI%@AE@%%@NL@%
- pop ax %@AB@%; Recover number%@AE@%%@NL@%
- push ax %@AB@%; Save it again%@AE@%%@NL@%
- and al, 00001111y %@AB@%; Mask out high nibble%@AE@%%@NL@%
- xlat %@AB@%; Get equivalent ASCII number in AL%@AE@%%@NL@%
- stosb %@AB@%; Copy to 6-byte string, increment DI%@AE@%%@NL@%
- pop ax %@AB@%; Recover number%@AE@%%@NL@%
- .UNTILCXZ %@AB@%; Do next byte%@AE@%%@NL@%
- mov ax, 'h' %@AB@%; Put null, 'h' radix in AX%@AE@%%@NL@%
- stosw %@AB@%; Copy to last two bytes in string%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- BinToHex ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* NewBlockSize - Adjusts size of allocated memory block.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: DOS Function - 4Ah (Resize Memory Block)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Adr - Segment address of block%@AE@%%@NL@%
- %@AB@%;* Resize - Requested block size in paragraphs%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Short integer error code%@AE@%%@NL@%
- %@AB@%;* 0 if successful%@AE@%%@NL@%
- %@AB@%;* 1 if error%@AE@%%@NL@%
- %@NL@%
- NewBlockSize PROC,%@NL@%
- Adr:WORD, Resize:WORD%@NL@%
- %@NL@%
- mov ax, Adr %@AB@%; Get block address%@AE@%%@NL@%
- mov es, ax %@AB@%; Point ES to block%@AE@%%@NL@%
- mov bx, Resize %@AB@%; New block size%@AE@%%@NL@%
- mov ah, 4Ah %@AB@%; Function number%@AE@%%@NL@%
- int 21h %@AB@%; Resize Memory Block%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- NewBlockSize ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Initialize - Initializes global variables _psp and _env, which are defined%@AE@%%@NL@%
- %@AB@%;* in the DEMO.INC include file. If used with a DOS version less than 3.0,%@AE@%%@NL@%
- %@AB@%;* this procedure will not produce valid results unless it is called before%@AE@%%@NL@%
- %@AB@%;* changing the ES register. This is because at program entry ES points to%@AE@%%@NL@%
- %@AB@%;* the Program Segment Prefix (PSP).%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Initialize PROC%@NL@%
- %@NL@%
- INVOKE GetPSP %@AB@%; Get segment address of PSP%@AE@%%@NL@%
- .IF ax == 0 %@AB@%; If less than DOS 3.0:%@AE@%%@NL@%
- mov es, ax %@AB@%; Reload ES with PSP address%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov _psp, es %@AB@%; Initialize variable with PSP address%@AE@%%@NL@%
- mov ax, es:[2Ch] %@AB@%; Get environment seg from PSP%@AE@%%@NL@%
- mov _env, ax %@AB@%; Store it%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- Initialize ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%MISCDEMO.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\DEMOS\MISCDEMO.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* MISCDEMO - Invokes many of the assembly example procedures, most of them%@AE@%%@NL@%
- %@AB@%;* demonstrating assembly language instructions and calls to the system BIOS.%@AE@%%@NL@%
- %@AB@%;* MISCDEMO demonstrates how to:%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* - determine hardware information%@AE@%%@NL@%
- %@AB@%;* - display time and date while waiting for keystrokes%@AE@%%@NL@%
- %@AB@%;* - play notes of any frequency on the speaker%@AE@%%@NL@%
- %@AB@%;* - change the line mode for EGA or VGA systems%@AE@%%@NL@%
- %@AB@%;* - create non-destructive pop-up windows%@AE@%%@NL@%
- %@AB@%;* - execute another program as a child process%@AE@%%@NL@%
- %@AB@%;* - create primitive handlers for Interrupts 1Bh, 23h, and 24h%@AE@%%@NL@%
- %@AB@%;* - use C-callable procedures in assembly programs%@AE@%%@NL@%
- %@AB@%;* - use simplified segment directives%@AE@%%@NL@%
- %@AB@%;* - write model-independent procedures%@AE@%%@NL@%
- %@AB@%;* - declare and initialize data with DUP, BYTE, WORD, and DWORD%@AE@%%@NL@%
- %@AB@%;* - create structures with the STRUCT directive%@AE@%%@NL@%
- %@AB@%;* - declare macros%@AE@%%@NL@%
- %@AB@%;* - set up a dispatch table%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* MISCDEMO.EXE is built from the following files:%@AE@%%@NL@%
- %@AB@%;* MISCDEMO.ASM - Main program%@AE@%%@NL@%
- %@AB@%;* MISC.ASM - Assembly procedures for MISCDEMO%@AE@%%@NL@%
- %@AB@%;* COMMON.ASM - Assembly procedures shared by other example programs%@AE@%%@NL@%
- %@AB@%;* DEMO.INC - Include file with macros, structure declarations%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Procedures: GetVidConfig GetCurPos VeriPrint GetPSP%@AE@%%@NL@%
- %@AB@%;* WinOpen VeriAnsi VeriCop GetVer%@AE@%%@NL@%
- %@AB@%;* WinClose StrWrite SetLineMode NewBlockSize%@AE@%%@NL@%
- %@AB@%;* SetCurSize GetKeyClock BinToHex IntToAsc%@AE@%%@NL@%
- %@AB@%;* SetCurPos GetShift Sound Colors%@AE@%%@NL@%
- %@AB@%;* GetCurSize GetMem Pause Exec%@AE@%%@NL@%
- %@AB@%;* WriteTTY Initialize%@AE@%%@NL@%
- %@NL@%
- .DOSSEG%@NL@%
- .MODEL small, pascal, os_dos%@NL@%
- INCLUDE demo.inc%@NL@%
- %@NL@%
- NewBreak PROTO FAR%@NL@%
- NewCtrlC PROTO FAR%@NL@%
- NewCritErr PROTO FAR%@NL@%
- DispMenu PROTO NEAR%@NL@%
- Press PROTO NEAR%@NL@%
- GetVidinfo PROTO NEAR%@NL@%
- GetMemInfo PROTO NEAR%@NL@%
- CheckPrinter PROTO NEAR%@NL@%
- CheckAnsi PROTO NEAR%@NL@%
- CheckCoproc PROTO NEAR%@NL@%
- GetConfig PROTO NEAR%@NL@%
- Speaker PROTO NEAR%@NL@%
- SetLines PROTO NEAR%@NL@%
- PopWindows PROTO NEAR%@NL@%
- SetAttrs PROTO NEAR%@NL@%
- ExecPgm PROTO NEAR%@NL@%
- %@NL@%
- .STACK%@NL@%
- .DATA%@NL@%
- %@NL@%
- PGMSIZE EQU 500h %@AB@%; Maximum program size in paragraphs%@AE@%%@NL@%
- F1 EQU 59 %@AB@%; Extended code for first option key%@AE@%%@NL@%
- F7 EQU 65 %@AB@%; Extended code for last option key%@AE@%%@NL@%
- CLKROW EQU 0 %@AB@%; Row for on-screen clock%@AE@%%@NL@%
- CLKCOL EQU 62 %@AB@%; Column for on-screen clock%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* Box - Macro to color portion of screen for effect. Not to be confused with%@AE@%%@NL@%
- %@AB@%;* the WinOpen procedure, which is far more capable.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: Row1 - Screen row at top of box%@AE@%%@NL@%
- %@AB@%;* Col1 - Screen column at left side of box%@AE@%%@NL@%
- %@AB@%;* Row2 - Screen row at bottom of box%@AE@%%@NL@%
- %@AB@%;* Col2 - Screen column at right side of box%@AE@%%@NL@%
- %@NL@%
- Box MACRO Row1, Col1, Row2, Col2%@NL@%
- LOCAL sk%@NL@%
- mov ax, 0600h %@AB@%;; Scroll service%@AE@%%@NL@%
- mov bh, Filmono %@AB@%;; Fill attribute%@AE@%%@NL@%
- .IF vconfig.adapter != MDA %@AB@%;; If color:%@AE@%%@NL@%
- mov bh, Filcolr %@AB@%;; Use color fill attribute%@AE@%%@NL@%
- .ENDIF%@NL@%
- mov ch, Row1%@NL@%
- mov cl, Col1 %@AB@%;; CX = row/col for upper left%@AE@%%@NL@%
- mov dh, Row2%@NL@%
- mov dl, Col2 %@AB@%;; DX = row/col for lower right%@AE@%%@NL@%
- int 10h %@AB@%;; Blank window area on screen%@AE@%%@NL@%
- ENDM%@NL@%
- %@NL@%
- OldMode BYTE ? %@AB@%; Original video mode%@AE@%%@NL@%
- OldCurs WORD ? %@AB@%; Original cursor coordinates%@AE@%%@NL@%
- KeepSeg PSEG ? %@AB@%; Segment addr, orig screen%@AE@%%@NL@%
- Filcolr BYTE 1Fh, 20h, 3Bh, 4Eh %@AB@%; Color fill attributes%@AE@%%@NL@%
- Filmono BYTE 70h, 89h, 78h, 1 %@AB@%; Monochrome fill attributes%@AE@%%@NL@%
- Fill BYTE 7 %@AB@%; Default attribute for menu%@AE@%%@NL@%
- Filsub BYTE ? %@AB@%; Fore/background colors in submenu%@AE@%%@NL@%
- %@NL@%
- PresMsg BYTE ". . . press a key to continue", 0%@NL@%
- yes BYTE "yes"%@NL@%
- no BYTE "no "%@NL@%
- %@NL@%
- %@AB@%; Main menu text%@AE@%%@NL@%
- %@NL@%
- Menu1 BYTE "*** MISC Demonstration Program ***", 0%@NL@%
- Menu2 BYTE "F1 System Configuration", 0%@NL@%
- Menu3 BYTE "F2 Speaker Test", 0%@NL@%
- Menu4 BYTE "F3 Toggle Line Mode", 0%@NL@%
- Menu5 BYTE "F4 Windows", 0%@NL@%
- Menu6 BYTE "F5 Screen Colors", 0%@NL@%
- Menu7 BYTE "F6 Exec Program", 0%@NL@%
- Menu8 BYTE "Select an option, or press ESC to quit:", 0%@NL@%
- %@NL@%
- %@AB@%; Option F1 - System Configuration%@AE@%%@NL@%
- %@NL@%
- MonoStr BYTE "monochrome"%@NL@%
- ClrStr BYTE "color "%@NL@%
- AdapStr BYTE "MDA CGA MCGAEGA VGA "%@NL@%
- VidMsg1 BYTE "Adapter: xxxx", 0%@NL@%
- VidMsg2 BYTE "Display: xxxxxxxxxx", 0%@NL@%
- VidMsg3 BYTE "Mode: xx", 0%@NL@%
- VidMsg4 BYTE "Rows: xx", 0%@NL@%
- MemMsg1 BYTE "Total memory: xxxx Kb", 0%@NL@%
- MemMsg2 BYTE "Available memory: xxxx Kb", 0%@NL@%
- PrnMsg BYTE "Printer ready: xxx", 0%@NL@%
- AnsiMsg BYTE "ANSI driver installed: xxx", 0%@NL@%
- CopMsg BYTE "Coprocessor installed: xxx", 0%@NL@%
- LEN1 EQU LENGTHOF CopMsg - 4%@NL@%
- %@NL@%
- %@AB@%; Option F3 - Toggle Line Mode%@AE@%%@NL@%
- %@NL@%
- LineMsg BYTE "Line mode reset available only for EGA or VGA", 0%@NL@%
- %@NL@%
- %@AB@%; Option F4 - Windows%@AE@%%@NL@%
- %@NL@%
- WinMsg BYTE "WINDOW x", 0%@NL@%
- LEN3 EQU LENGTHOF WinMsg - 2%@NL@%
- %@NL@%
- %@AB@%; Option F5 Screen Colors%@AE@%%@NL@%
- %@NL@%
- CMsg1 BYTE "Toggle Step", 0%@NL@%
- CMsg2 BYTE "──────────────── ──────────────────", 0%@NL@%
- CMsg3 BYTE "B blink ", 27, 26, " foreground", 0%@NL@%
- CMsg4 BYTE "I intensity ", 24, 25, " background", 0%@NL@%
- CMsg5 BYTE "Foreground: press F, then color number 0-7", 0%@NL@%
- CMsg6 BYTE "Background: press A, then color number 0-7", 0%@NL@%
- CMsg7 BYTE "Color Numbers", 0%@NL@%
- CMsg8 BYTE "───────────────────────────────────────────", 0%@NL@%
- CMsg9 BYTE "0 black 4 red", 0%@NL@%
- CMsg10 BYTE "1 blue 5 magenta", 0%@NL@%
- CMsg11 BYTE "2 green 6 brown", 0%@NL@%
- CMsg12 BYTE "3 cyan 7 white", 0%@NL@%
- CMsg13 BYTE "Toggle", 0%@NL@%
- CMsg14 BYTE "───────────────", 0%@NL@%
- CMsg15 BYTE "B blink", 0%@NL@%
- CMsg16 BYTE "I intensity", 0%@NL@%
- CMsg17 BYTE "U underline", 0%@NL@%
- CMsg18 BYTE "R reverse", 0%@NL@%
- %@NL@%
- %@AB@%; Option F6 - Exec Program%@AE@%%@NL@%
- %@NL@%
- RetMsg BYTE "Return code: "%@NL@%
- Recode BYTE 6 DUP (?) %@AB@%; ASCII string for return code%@AE@%%@NL@%
- ExecMsg BYTE "Enter program file spec (including .COM or .EXE):", 0%@NL@%
- TailMsg BYTE "Enter command-line argument(s):", 0%@NL@%
- Fspec BYTE 50, 50 DUP (?) %@AB@%; File specification (max length = 50)%@AE@%%@NL@%
- Tail BYTE 50, 50 DUP (?) %@AB@%; Command-line tail (max length = 50)%@AE@%%@NL@%
- Fcblk1 BYTE 0 %@AB@%; Allocate space for 1st FCB%@AE@%%@NL@%
- BYTE 11 DUP (0)%@NL@%
- BYTE 25 DUP (0)%@NL@%
- Fcblk2 BYTE 0 %@AB@%; Allocate space for 2nd FCB%@AE@%%@NL@%
- BYTE 11 DUP (0)%@NL@%
- BYTE 25 DUP (0)%@NL@%
- pb PARMBLK <> %@AB@%; Parameter block structure%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Initialize dispatch table with offsets for internal procedures.%@AE@%%@NL@%
- %@NL@%
- TPROC TYPEDEF PROTO %@AB@%; Procedure type%@AE@%%@NL@%
- PPROC TYPEDEF PTR TPROC %@AB@%; Pointer to procedure with no arguments%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Table of procedures%@AE@%%@NL@%
- DispTbl PPROC GetConfig, Speaker, SetLines,%@NL@%
- PopWindows, SetAttrs, ExecPgm%@NL@%
- %@NL@%
- .CODE%@NL@%
- .STARTUP%@NL@%
- %@NL@%
- %@AB@%; Initialize _psp and _env variables%@AE@%%@NL@%
- INVOKE Initialize%@NL@%
- %@NL@%
- %@AB@%; Return unused memory to DOS%@AE@%%@NL@%
- %@AB@%; Pass PSP segment address and memory block allocated to program%@AE@%%@NL@%
- INVOKE NewBlockSize, _psp, PGMSIZE%@NL@%
- %@NL@%
- %@AB@%; Initialize global configuration data%@AE@%%@NL@%
- INVOKE GetVidConfig%@NL@%
- %@NL@%
- mov al, vconfig.rows%@NL@%
- mov OldMode, al %@AB@%; Preserve original line mode%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Get current cursor position%@AE@%%@NL@%
- INVOKE GetCurPos%@NL@%
- %@NL@%
- mov OldCurs, ax %@AB@%; Store it%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Preserve original screen and put up window%@AE@%%@NL@%
- %@AB@%; Pass top, left, bottom, right, and attribute%@AE@%%@NL@%
- INVOKE WinOpen, 0, 0, vconfig.rows, 79, 07h%@NL@%
- %@NL@%
- mov KeepSeg, ax %@AB@%; Keep segment address%@AE@%%@NL@%
- .IF AX == 0 %@AB@%; If window not opened successfully:%@AE@%%@NL@%
- .EXIT 1 %@AB@%; Exit with return code = 1%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .WHILE 1%@NL@%
- %@NL@%
- %@AB@%; Display main menu%@AE@%%@NL@%
- INVOKE DispMenu%@NL@%
- %@NL@%
- %@AB@%; Highlight on-screen clock with macro%@AE@%%@NL@%
- Box CLKROW, CLKCOL-1, CLKROW, CLKCOL + 17%@NL@%
- %@NL@%
- %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
- %@AB@%; Pass row and column%@AE@%%@NL@%
- INVOKE GetKeyClock, CLKROW, CLKCOL%@NL@%
- %@NL@%
- .BREAK .IF al == ESCAPE %@AB@%; Quit loop if Esc key%@AE@%%@NL@%
- %@NL@%
- .CONTINUE .IF (ah < F1) || (ah > F7) %@AB@%; Ignore if not a function%@AE@%%@NL@%
- %@AB@%; key between F1 and F7?%@AE@%%@NL@%
- %@NL@%
- xchg al, ah %@AB@%; Yes? Make AX = AH%@AE@%%@NL@%
- sub al, F1 %@AB@%; Normalize to 0%@AE@%%@NL@%
- shl al, 1 %@AB@%; Double to make word index%@AE@%%@NL@%
- mov bx, ax %@AB@%; BX = index to table%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Call the current procedure from call table%@AE@%%@NL@%
- INVOKE DispTbl[bx]%@NL@%
- %@NL@%
- .ENDW %@AB@%; Loop for another key%@AE@%%@NL@%
- %@NL@%
- mov al, OldMode %@AB@%; Get original line mode%@AE@%%@NL@%
- .IF al != vconfig.rows %@AB@%; If not same as current mode:%@AE@%%@NL@%
- %@NL@%
- inc ax %@AB@%; Increment to 25/43/50%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Restore line mode, pass lines%@AE@%%@NL@%
- INVOKE SetLineMode, ax%@NL@%
- %@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Restore original screen, pass segment of screen contents%@AE@%%@NL@%
- INVOKE WinClose, KeepSeg%@NL@%
- %@NL@%
- mov ax, OldCurs%@NL@%
- %@NL@%
- %@AB@%; Restore cursor to original place%@AE@%%@NL@%
- %@AB@%; Pass row and column%@AE@%%@NL@%
- INVOKE SetCurPos, BYTE PTR OldCurs[1], BYTE PTR OldCurs[0]%@NL@%
- %@NL@%
- .EXIT 0 %@AB@%; Exit wih return code 0%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* DispMenu - Displays main menu.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- DispMenu PROC NEAR%@NL@%
- %@NL@%
- mov ax, 0600h %@AB@%; Scroll screen service%@AE@%%@NL@%
- mov bh, Fill %@AB@%; Menu display attribute%@AE@%%@NL@%
- sub cx, cx %@AB@%; From row 0, col 0%@AE@%%@NL@%
- mov dh, vconfig.rows %@AB@%; to bottom row,%@AE@%%@NL@%
- mov dl, 79 %@AB@%; rightmost column%@AE@%%@NL@%
- int 10h %@AB@%; Clear entire screen%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Display menu%@AE@%%@NL@%
- %@AB@%; For each line pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, 4, 21, ADDR Menu1%@NL@%
- INVOKE StrWrite, 8, 28, ADDR Menu2%@NL@%
- INVOKE StrWrite, 9, 28, ADDR Menu3%@NL@%
- INVOKE StrWrite, 10, 28, ADDR Menu4%@NL@%
- INVOKE StrWrite, 11, 28, ADDR Menu5%@NL@%
- INVOKE StrWrite, 12, 28, ADDR Menu6%@NL@%
- INVOKE StrWrite, 13, 28, ADDR Menu7%@NL@%
- INVOKE StrWrite, 17, 18, ADDR Menu8%@NL@%
- %@NL@%
- %@AB@%; Park cursor at prompt, pass row and column%@AE@%%@NL@%
- INVOKE SetCurPos, 17, 18 + (LENGTHOF Menu8) + 2%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- DispMenu ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Press - Displays a prompt, then waits for a key press.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Press PROC NEAR%@NL@%
- %@NL@%
- %@AB@%; Write string, pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, vconfig.rows, 50, ADDR PresMsg%@NL@%
- %@NL@%
- %@AB@%; Park cursor at prompt, pass row and column%@AE@%%@NL@%
- INVOKE SetCurPos, vconfig.rows, 48%@NL@%
- %@NL@%
- %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
- %@AB@%; Pass row and column%@AE@%%@NL@%
- INVOKE GetKeyClock, CLKROW, CLKCOL%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- Press ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetVidinfo - Initializes video configuration message for display.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- GetVidinfo PROC NEAR%@NL@%
- %@NL@%
- push ds%@NL@%
- pop es %@AB@%; Point ES to data segment%@AE@%%@NL@%
- mov al, 4 %@AB@%; Find index to 4-character%@AE@%%@NL@%
- mul vconfig.adapter %@AB@%; group in string%@AE@%%@NL@%
- add ax, OFFSET AdapStr %@AB@%; Point AX to proper group%@AE@%%@NL@%
- mov si, ax %@AB@%; Put pointer in SI%@AE@%%@NL@%
- lea di, VidMsg1[LEN1] %@AB@%; Point to 1st line of message%@AE@%%@NL@%
- mov cx, 2 %@AB@%; Copy 4 letters (adapter%@AE@%%@NL@%
- rep movsw %@AB@%; designation) to message%@AE@%%@NL@%
- %@NL@%
- mov si, OFFSET MonoStr %@AB@%; Assume display is monochrome%@AE@%%@NL@%
- .IF vconfig.display != MONO %@AB@%; I color display:%@AE@%%@NL@%
- mov si, OFFSET ClrStr %@AB@%; Point to "color" string%@AE@%%@NL@%
- .ENDIF%@NL@%
- lea di, VidMsg2[LEN1] %@AB@%; Point to 2nd line of message%@AE@%%@NL@%
- mov cx, 5 %@AB@%; Copy 10 chars ("monochrome"%@AE@%%@NL@%
- rep movsw %@AB@%; or "color ") to msg%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Note that IntToAsc can't be invoked because of its%@AE@%%@NL@%
- %@AB@%; register calling convention%@AE@%%@NL@%
- mov al, vconfig.mode%@NL@%
- cbw %@AB@%; AX = video mode%@AE@%%@NL@%
- call IntToAsc %@AB@%; Convert AX to ASCII%@AE@%%@NL@%
- xchg ah, al %@AB@%; Flip bytes for word write%@AE@%%@NL@%
- mov WORD PTR VidMsg3[LEN1], ax %@AB@%; Insert in message string%@AE@%%@NL@%
- %@NL@%
- mov al, vconfig.rows%@NL@%
- cbw%@NL@%
- inc ax %@AB@%; AX = number of screen rows%@AE@%%@NL@%
- call IntToAsc %@AB@%; Convert to ASCII%@AE@%%@NL@%
- xchg ah, al %@AB@%; Flip bytes for word write%@AE@%%@NL@%
- mov WORD PTR VidMsg4[LEN1], ax %@AB@%; Insert in message string%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetVidinfo ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetMemInfo - Initializes memory information message.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- GetMemInfo PROC NEAR%@NL@%
- %@NL@%
- %@AB@%; Get total memory in DX, available memory in AX%@AE@%%@NL@%
- INVOKE GetMem%@NL@%
- %@NL@%
- push ax%@NL@%
- mov ax, dx%@NL@%
- call IntToAsc %@AB@%; Convert AX to ASCII%@AE@%%@NL@%
- xchg dh, dl %@AB@%; Flip bytes for word write%@AE@%%@NL@%
- xchg ah, al%@NL@%
- mov WORD PTR MemMsg1[LEN1], dx %@AB@%; Insert in message%@AE@%%@NL@%
- mov WORD PTR MemMsg1[LEN1+2], ax %@AB@%; string%@AE@%%@NL@%
- pop ax %@AB@%; Recover avail memory #%@AE@%%@NL@%
- call IntToAsc %@AB@%; Convert to ASCII%@AE@%%@NL@%
- xchg dh, dl %@AB@%; Flip bytes for word write%@AE@%%@NL@%
- xchg ah, al%@NL@%
- mov WORD PTR MemMsg2[LEN1], dx %@AB@%; Insert in message%@AE@%%@NL@%
- mov WORD PTR MemMsg2[LEN1+2], ax %@AB@%; string%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GetMemInfo ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CheckPrinter - Initializes printer status message.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Shows: Instruction - movsb%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CheckPrinter PROC NEAR%@NL@%
- %@NL@%
- push ds%@NL@%
- pop es %@AB@%; Point ES to data segment%@AE@%%@NL@%
- mov si, OFFSET yes %@AB@%; Assume answer is "yes"%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Check if printer ready%@AE@%%@NL@%
- INVOKE VeriPrint%@NL@%
- %@NL@%
- .IF al == 0 %@AB@%; If not ready%@AE@%%@NL@%
- mov si, OFFSET no %@AB@%; Point to "no" answer%@AE@%%@NL@%
- .ENDIF%@NL@%
- lea di, PrnMsg[LEN1] %@AB@%; Point to print message%@AE@%%@NL@%
- mov cx, 3 %@AB@%; Copy 3 letters (either "yes"%@AE@%%@NL@%
- rep movsb %@AB@%; or "no ") to message%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- CheckPrinter ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CheckAnsi - Initializes status message for ANSI driver.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CheckAnsi PROC NEAR%@NL@%
- %@NL@%
- push ds%@NL@%
- pop es %@AB@%; Point ES to data segment%@AE@%%@NL@%
- mov si, OFFSET yes %@AB@%; Assume answer is "yes"%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Check if ANSI driver is installed%@AE@%%@NL@%
- INVOKE VeriAnsi%@NL@%
- %@NL@%
- .IF al == 0 %@AB@%; If not installed:%@AE@%%@NL@%
- mov si, OFFSET no %@AB@%; Point to "no" answer%@AE@%%@NL@%
- .ENDIF%@NL@%
- lea di, AnsiMsg[LEN1] %@AB@%; Point to ansi message%@AE@%%@NL@%
- mov cx, 3 %@AB@%; Copy 3 letters (either "yes"%@AE@%%@NL@%
- rep movsb %@AB@%; or "no ") to message%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- CheckAnsi ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CheckCoproc - Initializes coprocessor status message.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CheckCoproc PROC NEAR%@NL@%
- %@NL@%
- push ds%@NL@%
- pop es %@AB@%; Point ES to data segment%@AE@%%@NL@%
- mov si, OFFSET yes %@AB@%; Assume answer is "yes"%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Check for coprocessor%@AE@%%@NL@%
- INVOKE VeriCop%@NL@%
- %@NL@%
- .IF al == 0 %@AB@%; If not installed:%@AE@%%@NL@%
- mov si, OFFSET no %@AB@%; Point to "no" answer%@AE@%%@NL@%
- .ENDIF%@NL@%
- lea di, CopMsg[LEN1] %@AB@%; Point to coprocessor message%@AE@%%@NL@%
- mov cx, 3 %@AB@%; Copy 3 letters (either "yes"%@AE@%%@NL@%
- rep movsb %@AB@%; or "no ") to message%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- CheckCoproc ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetConfig - Displays system configuration information.%@AE@%%@NL@%
- %@NL@%
- GetConfig PROC NEAR%@NL@%
- %@NL@%
- INVOKE GetVidinfo %@AB@%; Initialize video message%@AE@%%@NL@%
- INVOKE GetMemInfo %@AB@%; Initialize memory message%@AE@%%@NL@%
- INVOKE CheckPrinter %@AB@%; Initialize printer message%@AE@%%@NL@%
- INVOKE CheckAnsi %@AB@%; Initialize ANSI driver msg%@AE@%%@NL@%
- INVOKE CheckCoproc %@AB@%; Initialize coprocessor msg%@AE@%%@NL@%
- %@NL@%
- Box 4, 13, 20, 67 %@AB@%; Clear screen with box%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Display configuration information%@AE@%%@NL@%
- %@AB@%; For each line, pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, 6, 23, ADDR VidMsg1%@NL@%
- INVOKE StrWrite, 7, 23, ADDR VidMsg2%@NL@%
- INVOKE StrWrite, 8, 23, ADDR VidMsg3%@NL@%
- INVOKE StrWrite, 9, 23, ADDR VidMsg4%@NL@%
- INVOKE StrWrite, 11, 23, ADDR MemMsg1%@NL@%
- INVOKE StrWrite, 12, 23, ADDR MemMsg2%@NL@%
- INVOKE StrWrite, 14, 23, ADDR PrnMsg%@NL@%
- INVOKE StrWrite, 16, 23, ADDR AnsiMsg%@NL@%
- INVOKE StrWrite, 18, 23, ADDR CopMsg%@NL@%
- %@NL@%
- %@AB@%; Prompt for keypress%@AE@%%@NL@%
- INVOKE Press%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- GetConfig ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Speaker - Sounds speaker with ascending frequencies.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Speaker PROC NEAR%@NL@%
- %@NL@%
- sub ax, ax%@NL@%
- .REPEAT%@NL@%
- add ax, 100 %@AB@%; Start with frequency 100%@AE@%%@NL@%
- push ax %@AB@%; Save frequency%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Beep speaker, pass frequency and duration%@AE@%%@NL@%
- INVOKE Sound, ax, 1%@NL@%
- %@NL@%
- pop ax %@AB@%; Recover frequency%@AE@%%@NL@%
- .UNTIL ax > 3000 %@AB@%; Continue to frequency 3000%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- Speaker ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* SetLines - Toggles between 25/43-line mode for EGA or 25/43/50-line mode%@AE@%%@NL@%
- %@AB@%;* for VGA.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- SetLines PROC NEAR%@NL@%
- %@NL@%
- mov al, 25 %@AB@%; Assume toggle to 25 line%@AE@%%@NL@%
- cmp vconfig.rows, 49 %@AB@%; Current mode 50 lines?%@AE@%%@NL@%
- je toggle25 %@AB@%; Yes? Toggle VGA to 25-line%@AE@%%@NL@%
- cmp vconfig.rows, 42 %@AB@%; Current mode 43 lines?%@AE@%%@NL@%
- jne toggle43 %@AB@%; No? Must be 25%@AE@%%@NL@%
- cmp vconfig.adapter, EGA %@AB@%; Yes? And is adapter EGA?%@AE@%%@NL@%
- je toggle25 %@AB@%; Yes? Then toggle to 25 line%@AE@%%@NL@%
- mov al, 50 %@AB@%; No? Toggle VGA to 50 line%@AE@%%@NL@%
- jmp toggle25%@NL@%
- toggle43:%@NL@%
- mov al, 43 %@AB@%; If currently 25 lines, make%@AE@%%@NL@%
- %@AB@%; either EGA or VGA 43 lines%@AE@%%@NL@%
- toggle25:%@NL@%
- %@AB@%; Change line mode, pass lines%@AE@%%@NL@%
- INVOKE SetLineMode, ax%@NL@%
- %@NL@%
- .IF al == 0 %@AB@%; If no error:%@AE@%%@NL@%
- INVOKE GetVidConfig %@AB@%; Update configuration structure%@AE@%%@NL@%
- .ELSE %@AB@%; Else:%@AE@%%@NL@%
- Box 16, 13, 20, 67 %@AB@%; Display error message%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write line message, pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, 18, 17, ADDR LineMsg%@NL@%
- %@NL@%
- INVOKE Press%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- SetLines ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* PopWindows - Demonstrates windowing with the WinOpen and WinClose%@AE@%%@NL@%
- %@AB@%;* procedures.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- PopWindows PROC NEAR%@NL@%
- %@NL@%
- LOCAL Row1:WORD, Col1:WORD, Row2:WORD, Col2:WORD%@NL@%
- LOCAL Index:BYTE, Adr[4]:WORD, Csize:WORD%@NL@%
- %@NL@%
- %@AB@%; Get current cursor size%@AE@%%@NL@%
- INVOKE GetCurSize%@NL@%
- %@NL@%
- mov Csize, ax %@AB@%; Store it%@AE@%%@NL@%
- or al, 100000y %@AB@%; Set 5th bit for cursor off%@AE@%%@NL@%
- mov bl, al%@NL@%
- %@NL@%
- %@AB@%; Set cursor size%@AE@%%@NL@%
- %@AB@%; Pass arbitrary top and bottom lines with visibility bit off%@AE@%%@NL@%
- INVOKE SetCurSize, BYTE PTR Csize[1], bl%@NL@%
- %@NL@%
- mov WinMsg[LEN3], "0" %@AB@%; Initialize window message%@AE@%%@NL@%
- mov Row1, 4 %@AB@%; Initialize window coords%@AE@%%@NL@%
- mov Col1, 10%@NL@%
- mov Row2, 20%@NL@%
- mov Col2, 34%@NL@%
- mov Index, 0%@NL@%
- mov cx, 4 %@AB@%; Open 4 windows%@AE@%%@NL@%
- .REPEAT%@NL@%
- push cx %@AB@%; Save loop counter%@AE@%%@NL@%
- mov al, Index%@NL@%
- mov bx, OFFSET Filmono %@AB@%; BX points to fill attributes%@AE@%%@NL@%
- .IF vconfig.display != MONO %@AB@%; If not monochrome:%@AE@%%@NL@%
- mov bx, OFFSET Filcolr %@AB@%; Repoint to color attributes%@AE@%%@NL@%
- .ENDIF%@NL@%
- xlat %@AB@%; Get attributes in succession%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Save old window and open new%@AE@%%@NL@%
- %@AB@%; Pass top, left, bottom, right, and attribute in AX%@AE@%%@NL@%
- INVOKE WinOpen, Row1, Col1, Row2, Col2, ax%@NL@%
- %@NL@%
- pop di %@AB@%; Recover counter in DI%@AE@%%@NL@%
- push di %@AB@%; and save it again%@AE@%%@NL@%
- dec di%@NL@%
- shl di, 1 %@AB@%; Make DI a word index%@AE@%%@NL@%
- mov Adr[di], ax %@AB@%; Save address of allocated%@AE@%%@NL@%
- %@AB@%; block returned by WinOpen%@AE@%%@NL@%
- inc WinMsg[LEN3] %@AB@%; Increment window number%@AE@%%@NL@%
- mov bx, Row1%@NL@%
- add bl, 2 %@AB@%; Message row%@AE@%%@NL@%
- mov cx, Col1%@NL@%
- add cl, 9 %@AB@%; Message column%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write window message, pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, bx, cx, ADDR WinMsg%@NL@%
- %@NL@%
- %@AB@%; Pause, pass 18 ticks (about 1 second)%@AE@%%@NL@%
- INVOKE Pause, 18%@NL@%
- %@NL@%
- add Row1, 2 %@AB@%; Adjust coordinates for%@AE@%%@NL@%
- add Col1, 13 %@AB@%; next window%@AE@%%@NL@%
- sub Row2, 2%@NL@%
- add Col2, 13%@NL@%
- inc Index%@NL@%
- pop cx %@AB@%; Recover counter%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- mov cx, 4 %@AB@%; Close 4 windows%@AE@%%@NL@%
- sub di, di %@AB@%; DI = index to addresses%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push cx %@AB@%; Save loop counter%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Close a window, pass address of the window%@AE@%%@NL@%
- INVOKE WinClose, Adr[di]%@NL@%
- %@NL@%
- %@AB@%; Pause, pass 18 ticks (about 1 second)%@AE@%%@NL@%
- INVOKE Pause, 18%@NL@%
- %@NL@%
- add di, 2 %@AB@%; Point to next address%@AE@%%@NL@%
- pop cx %@AB@%; Recover counter%@AE@%%@NL@%
- .UNTILCXZ %@AB@%; Close another window%@AE@%%@NL@%
- %@NL@%
- mov ax, Csize %@AB@%; Get original cursor size%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Set cursor size, pass top and bottom lines%@AE@%%@NL@%
- INVOKE SetCurSize, BYTE PTR Csize[1], BYTE PTR Csize[0]%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- PopWindows ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* SetAttrs - Changes display attributes for the main menu.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- SetAttrs PROC NEAR%@NL@%
- %@NL@%
- Box 3, 12, 23, 68%@NL@%
- .IF vconfig.adapter == MDA %@AB@%; If monochrome?%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write monochrome menu%@AE@%%@NL@%
- %@AB@%; For each line, pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, 8, 32, ADDR CMsg13%@NL@%
- INVOKE StrWrite, 9, 32, ADDR CMsg14%@NL@%
- INVOKE StrWrite, 10, 36, ADDR CMsg15%@NL@%
- INVOKE StrWrite, 11, 36, ADDR CMsg16%@NL@%
- INVOKE StrWrite, 12, 36, ADDR CMsg17%@NL@%
- INVOKE StrWrite, 13, 36, ADDR CMsg18%@NL@%
- %@NL@%
- mov al, Filmono %@AB@%; Initialize Filsub variable%@AE@%%@NL@%
- mov Filsub, al %@AB@%; for monochrome%@AE@%%@NL@%
- %@NL@%
- .ELSE%@NL@%
- %@NL@%
- %@AB@%; Write color menu%@AE@%%@NL@%
- %@AB@%; For each line, pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, 4, 18, ADDR CMsg1%@NL@%
- INVOKE StrWrite, 5, 18, ADDR CMsg2%@NL@%
- INVOKE StrWrite, 6, 22, ADDR CMsg3%@NL@%
- INVOKE StrWrite, 7, 22, ADDR CMsg4%@NL@%
- INVOKE StrWrite, 10, 18, ADDR CMsg5%@NL@%
- INVOKE StrWrite, 11, 18, ADDR CMsg6%@NL@%
- INVOKE StrWrite, 14, 18, ADDR CMsg7%@NL@%
- INVOKE StrWrite, 15, 18, ADDR CMsg8%@NL@%
- INVOKE StrWrite, 16, 22, ADDR CMsg9%@NL@%
- INVOKE StrWrite, 17, 22, ADDR CMsg10%@NL@%
- INVOKE StrWrite, 18, 22, ADDR CMsg11%@NL@%
- INVOKE StrWrite, 19, 22, ADDR CMsg12%@NL@%
- %@NL@%
- mov al, Filcolr %@AB@%; Initialize Filsub variable%@AE@%%@NL@%
- mov Filsub, al %@AB@%; for color%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Write menu message%@AE@%%@NL@%
- INVOKE StrWrite, 22, 15, ADDR Menu8%@NL@%
- %@NL@%
- %@AB@%; Park cursor at prompt, pass row and column%@AE@%%@NL@%
- INVOKE SetCurPos, 22, 56%@NL@%
- %@NL@%
- .WHILE 1%@NL@%
- %@NL@%
- %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
- %@AB@%; Pass row and column%@AE@%%@NL@%
- INVOKE GetKeyClock, CLKROW, CLKCOL%@NL@%
- %@NL@%
- .BREAK .IF al == ESCAPE %@AB@%; Quit if Esc key%@AE@%%@NL@%
- %@NL@%
- .IF (al >= 'a') && (al <= 'z') %@AB@%; Convert letters to uppercase%@AE@%%@NL@%
- and al, 5Fh %@AB@%; to make comparisons easier%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- cmp al, 'B' %@AB@%; Request blink toggle?%@AE@%%@NL@%
- je blink%@NL@%
- cmp al, 'I' %@AB@%; Request intensity toggle?%@AE@%%@NL@%
- je intense%@NL@%
- mov bl, Filsub %@AB@%; Get window display attribute%@AE@%%@NL@%
- cmp vconfig.adapter, MDA %@AB@%; Monochrome?%@AE@%%@NL@%
- jne iscolor %@AB@%; No? Jump to color selections%@AE@%%@NL@%
- cmp al, 'U' %@AB@%; Request underline toggle?%@AE@%%@NL@%
- je underline%@NL@%
- .CONTINUE .IF al != 'R' %@AB@%; If not reverse toggle:%@AE@%%@NL@%
- %@AB@%; Skip invalid key%@AE@%%@NL@%
- %@NL@%
- %@AB@%; What with cross-toggling between reverse, normal, and underline, three%@AE@%%@NL@%
- %@AB@%; bit settings can exist in monochrome: x111x000 for reverse, x000x111 for%@AE@%%@NL@%
- %@AB@%; normal, and x000x001 for underline. Changing between the three involves%@AE@%%@NL@%
- %@AB@%; more than simply XOR-ing the current attribute; each condition must check%@AE@%%@NL@%
- %@AB@%; for the other two.%@AE@%%@NL@%
- %@NL@%
- reverse:%@NL@%
- .IF bl & 1 %@AB@%; If reverse video off:%@AE@%%@NL@%
- or bl, 00000111y %@AB@%; Ensure normal bits are on%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- xor bl, 01110111y %@AB@%; Toggle for reverse/normal%@AE@%%@NL@%
- mov cl, 6 %@AB@%; Set code for MOV%@AE@%%@NL@%
- jmp switch%@NL@%
- %@NL@%
- underline:%@NL@%
- .IF bl & 1 %@AB@%; If reverse video on:%@AE@%%@NL@%
- and bl, 10001111y %@AB@%; Clear bits 4-6%@AE@%%@NL@%
- or bl, 00000111y %@AB@%; and set bits 0-2%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- xor bl, 00000110y %@AB@%; Toggle bits 1-2 for underline%@AE@%%@NL@%
- mov cl, 6 %@AB@%; Set code for MOV%@AE@%%@NL@%
- jmp switch%@NL@%
- %@NL@%
- %@AB@%; Blink and intensity use the same bits for color and monochrome.%@AE@%%@NL@%
- %@NL@%
- blink:%@NL@%
- mov bl, 10000000y %@AB@%; Set bit 7 for blink%@AE@%%@NL@%
- mov cl, 4 %@AB@%; Set code for XOR%@AE@%%@NL@%
- jmp switch%@NL@%
- %@NL@%
- intense:%@NL@%
- mov bl, 00001000y %@AB@%; Set bit 3 for intensity%@AE@%%@NL@%
- mov cl, 4 %@AB@%; Set code for XOR%@AE@%%@NL@%
- jmp switch%@NL@%
- %@NL@%
- %@AB@%; Enter this section only for color displays. First check for arrow keys,%@AE@%%@NL@%
- %@AB@%; which increment or decrement the foreground or background bits of the%@AE@%%@NL@%
- %@AB@%; current attribute stored in the variable Filsub. If arrow keys are not%@AE@%%@NL@%
- %@AB@%; pressed, check for the F or A keys, which request specific colors for the%@AE@%%@NL@%
- %@AB@%; foreground or background colors.%@AE@%%@NL@%
- %@NL@%
- iscolor:%@NL@%
- mov ch, bl %@AB@%; Copy current attribute to CH%@AE@%%@NL@%
- .IF ah == 72 %@AB@%; If up arrow:%@AE@%%@NL@%
- mov cl, 4 %@AB@%; Increment bits 4-6%@AE@%%@NL@%
- shr ch, cl %@AB@%; to next background color%@AE@%%@NL@%
- inc ch%@NL@%
- and ch, 00000111y%@NL@%
- shl ch, cl%@NL@%
- mov dl, 10001111y %@AB@%; Set background mask%@AE@%%@NL@%
- jmp step%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .IF ah == 75 %@AB@%; If left arrow:%@AE@%%@NL@%
- inc ch %@AB@%; Increment bits 0-2%@AE@%%@NL@%
- and ch, 00000111y %@AB@%; to next foreground color%@AE@%%@NL@%
- mov dl, 11111000y %@AB@%; Set foreground mask%@AE@%%@NL@%
- jmp step%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .IF ah == 77 %@AB@%; If right arrow%@AE@%%@NL@%
- dec ch %@AB@%; Decrement bits 0-2%@AE@%%@NL@%
- and ch, 00000111y %@AB@%; to previous foreground color%@AE@%%@NL@%
- mov dl, 11111000y %@AB@%; Set foreground mask%@AE@%%@NL@%
- jmp step%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .IF ah == 80 %@AB@%; If down arrow:%@AE@%%@NL@%
- mov cl, 4 %@AB@%; Decrement bits 4-6%@AE@%%@NL@%
- shr ch, cl %@AB@%; to previous background color%@AE@%%@NL@%
- dec ch%@NL@%
- and ch, 00000111y%@NL@%
- shl ch, cl%@NL@%
- mov dl, 10001111y %@AB@%; Set background mask%@AE@%%@NL@%
- step:%@NL@%
- and bl, dl %@AB@%; Mask out fore or back bits%@AE@%%@NL@%
- or bl, ch %@AB@%; Copy into original attribute%@AE@%%@NL@%
- mov Filsub, bl %@AB@%; Store the new submenu color%@AE@%%@NL@%
- mov cl, 6 %@AB@%; Request move operation in%@AE@%%@NL@%
- jmp switch %@AB@%; Colors procedure%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; This section checks for the F or A keys; if found it checks again for%@AE@%%@NL@%
- %@AB@%; a number key between 0 and 7, then inserts the correct foreground or%@AE@%%@NL@%
- %@AB@%; background bit pattern into the current fill attribute.%@AE@%%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Clear flag for foreground request%@AE@%%@NL@%
- .IF al == 'A' %@AB@%; If background request:%@AE@%%@NL@%
- inc cx %@AB@%; Set flag for background request%@AE@%%@NL@%
- .CONTINUE .IF al != 'F' %@AB@%; If not foreground request, continue%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- push ax%@NL@%
- %@NL@%
- %@AB@%; Poll for keyboard selection while updating time%@AE@%%@NL@%
- %@AB@%; Pass row and column%@AE@%%@NL@%
- INVOKE GetKeyClock, CLKROW, CLKCOL%@NL@%
- %@NL@%
- pop cx %@AB@%; Recover flag%@AE@%%@NL@%
- %@NL@%
- .CONTINUE .IF (al < '0') && (al > '7') %@AB@%; Ignore invalid key%@AE@%%@NL@%
- %@NL@%
- xor al, '0' %@AB@%; Convert ASCII numeral into binary%@AE@%%@NL@%
- mov dl, 11111000y %@AB@%; Set foreground mask%@AE@%%@NL@%
- .IF cx != 0 %@AB@%; Skip if foreground request%@AE@%%@NL@%
- mov cl, 4 %@AB@%; Otherwise shift bits 0-2%@AE@%%@NL@%
- shl al, cl %@AB@%; to positions 4-6%@AE@%%@NL@%
- mov dl, 10001111y %@AB@%; Set background mask%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov bl, Filsub%@NL@%
- and bl, dl %@AB@%; Mask out fore or back bits%@AE@%%@NL@%
- or bl, al %@AB@%; Insert number into fore or back bits%@AE@%%@NL@%
- mov Filsub, bl %@AB@%; Store the new submenu color%@AE@%%@NL@%
- mov cl, 6 %@AB@%; Request move%@AE@%%@NL@%
- switch:%@NL@%
- %@NL@%
- %@AB@%; Set new attributes in a window%@AE@%%@NL@%
- %@AB@%; Pass logic code (CX), attribute (BX), top, left, bottom, right%@AE@%%@NL@%
- INVOKE Colors, cx, bx, 3, 12, 23, 68%@NL@%
- %@NL@%
- mov ah, 8 %@AB@%; Function 8, get char/attribute%@AE@%%@NL@%
- mov bh, vconfig.dpage%@NL@%
- int 10h %@AB@%; Get attribute in AH%@AE@%%@NL@%
- mov Fill, ah %@AB@%; New fill variable for main menu%@AE@%%@NL@%
- mov Filsub, ah %@AB@%; and for submenu%@AE@%%@NL@%
- .ENDW%@NL@%
- ret%@NL@%
- %@NL@%
- SetAttrs ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* ExecPgm - Executes a specified program as a child process.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure (initialized%@AE@%%@NL@%
- %@AB@%;* by calling the GetVidConfig procedure)%@AE@%%@NL@%
- %@AB@%;* pb - Parameter block structure, declared in the DEMO.INC file%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- ExecPgm PROC NEAR%@NL@%
- %@NL@%
- Box 16, 13, 20, 67%@NL@%
- %@NL@%
- %@AB@%; Display prompt for file spec, pass row, column, and string address%@AE@%%@NL@%
- INVOKE StrWrite, 17, 16, ADDR ExecMsg%@NL@%
- %@NL@%
- %@AB@%; Set cursor position below prompt, pass row and column%@AE@%%@NL@%
- INVOKE SetCurPos, 19, 16%@NL@%
- %@NL@%
- mov ah, 0Ah %@AB@%; Request DOS to read keyboard%@AE@%%@NL@%
- mov dx, OFFSET Fspec %@AB@%; input into Fspec string%@AE@%%@NL@%
- int 21h %@AB@%; Read Buffered Keyboard Input%@AE@%%@NL@%
- %@NL@%
- Box 16, 13, 20, 67%@NL@%
- %@NL@%
- %@AB@%; Display prompt for command tail%@AE@%%@NL@%
- INVOKE StrWrite, 17, 16, ADDR TailMsg%@NL@%
- %@NL@%
- %@AB@%; Set cursor position below prompt, pass row and column%@AE@%%@NL@%
- INVOKE SetCurPos, 19, 16%@NL@%
- %@NL@%
- mov ah, 0Ah %@AB@%; Request DOS to read keyboard%@AE@%%@NL@%
- mov dx, OFFSET Tail %@AB@%; input into tail string%@AE@%%@NL@%
- int 21h %@AB@%; Read Buffered Keyboard Input%@AE@%%@NL@%
- %@NL@%
- sub bh, bh %@AB@%; Clear BH%@AE@%%@NL@%
- mov si, OFFSET Fspec %@AB@%; DS:SI points to file spec string%@AE@%%@NL@%
- mov bl, [si+1] %@AB@%; BL = number of chars in spec%@AE@%%@NL@%
- mov BYTE PTR [si+bx+2], 0 %@AB@%; Terminate string with 0%@AE@%%@NL@%
- %@NL@%
- mov ax, _env %@AB@%; Get segment address of environment%@AE@%%@NL@%
- mov pb.env, ax %@AB@%; Copy it to parameter block%@AE@%%@NL@%
- mov ax, @data %@AB@%; AX points to data segment%@AE@%%@NL@%
- lea bx, Tail[1] %@AB@%; BX points to command-line tail%@AE@%%@NL@%
- mov WORD PTR pb.taddr[0], bx%@AB@%; Copy address of command-line tail%@AE@%%@NL@%
- mov WORD PTR pb.taddr[2], ax%@AB@%; to parameter block%@AE@%%@NL@%
- %@NL@%
- mov bx, OFFSET Fcblk1 %@AB@%; BX points to first FCB%@AE@%%@NL@%
- mov WORD PTR pb.fcb1[0], bx %@AB@%; Copy address of first FCB%@AE@%%@NL@%
- mov WORD PTR pb.fcb1[2], ax %@AB@%; to parameter block%@AE@%%@NL@%
- mov bx, OFFSET Fcblk2 %@AB@%; BX points to second FCB%@AE@%%@NL@%
- mov WORD PTR pb.fcb2[0], bx %@AB@%; Copy address of second FCB%@AE@%%@NL@%
- mov WORD PTR pb.fcb2[2], ax %@AB@%; to parameter block%@AE@%%@NL@%
- %@NL@%
- %@AB@%; At this point, the program file is specified, the command line tail is set,%@AE@%%@NL@%
- %@AB@%; and the parameter block is properly initialized. The Exec procedure will%@AE@%%@NL@%
- %@AB@%; take care of loading the FCBs with command-line arguments and resetting%@AE@%%@NL@%
- %@AB@%; interrupt vectors. Now blank the screen in preparation for executing the%@AE@%%@NL@%
- %@AB@%; process and pass the five pointers to the Exec procedure.%@AE@%%@NL@%
- %@NL@%
- mov ax, 0600h %@AB@%; AH = scroll service, AL = 0%@AE@%%@NL@%
- mov bh, 7 %@AB@%; Blank with normal attribute%@AE@%%@NL@%
- sub cx, cx %@AB@%; From row 0, col 0%@AE@%%@NL@%
- mov dh, vconfig.rows %@AB@%; to bottom row%@AE@%%@NL@%
- mov dl, 79 %@AB@%; and rightmost column%@AE@%%@NL@%
- int 10h %@AB@%; Blank screen%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Set cursor at top of screen, pass row and column%@AE@%%@NL@%
- INVOKE SetCurPos, 0, 0%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%; Exec specified program%@AE@%%@NL@%
- INVOKE Exec,%@NL@%
- ADDR Fspec[2], %@AB@%; File spec%@AE@%%@NL@%
- ADDR pb, %@AB@%; Parameter block structure%@AE@%%@NL@%
- NewBreak, %@AB@%; New handlers for CTRL+BREAK,%@AE@%%@NL@%
- NewCtrlC, %@AB@%; CTRL+C%@AE@%%@NL@%
- NewCritErr %@AB@%; and Critical Error%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- .IF ax != -1 %@AB@%; If successful:%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Convert return code to string%@AE@%%@NL@%
- %@AB@%; Pass return code (AX) and address of string buffer%@AE@%%@NL@%
- INVOKE BinToHex, ax, ADDR Recode%@NL@%
- %@NL@%
- %@AB@%; Update video structure%@AE@%%@NL@%
- INVOKE GetVidConfig%@NL@%
- %@NL@%
- Box CLKROW, CLKCOL-1, CLKROW, CLKCOL+17 %@AB@%; Highlight on-screen clock%@AE@%%@NL@%
- Box vconfig.rows, 0, vconfig.rows, 79 %@AB@%; Highlight bottom row%@AE@%%@NL@%
- mov dl, vconfig.rows%@NL@%
- %@NL@%
- %@AB@%; Display return code at bottom%@AE@%%@NL@%
- INVOKE StrWrite, dx, 0, ADDR RetMsg%@NL@%
- %@NL@%
- %@AB@%; Wait for keypress%@AE@%%@NL@%
- INVOKE Press%@NL@%
- .ELSE%@NL@%
- mov ax, 0E07h %@AB@%; Write ASCII 7 character%@AE@%%@NL@%
- int 10h %@AB@%; (bell) to console%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- ExecPgm ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* The following three procedures are primitive handlers for Interrupt 1Bh%@AE@%%@NL@%
- %@AB@%;* (Ctrl-Break), Interrupt 23h (Ctrl-C), and Interrupt 24h (Critical Error).%@AE@%%@NL@%
- %@AB@%;* The purpose of an interrupt handler in this context is to prevent termina-%@AE@%%@NL@%
- %@AB@%;* tion of both parent and child processes when the interrupt is invoked.%@AE@%%@NL@%
- %@AB@%;* Such handlers often set flags to signal a process that the interrupt has%@AE@%%@NL@%
- %@AB@%;* been called.%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* NewBreak - Handler for Interrupt 1Bh.%@AE@%%@NL@%
- %@NL@%
- NewBreak PROC FAR%@NL@%
- %@NL@%
- sti %@AB@%; Reenable interrupts%@AE@%%@NL@%
- push ax %@AB@%; Preserve AX register%@AE@%%@NL@%
- mov al, 20h %@AB@%; Send end-of-interrupt signal%@AE@%%@NL@%
- out 20h, al %@AB@%; to interrupt controller%@AE@%%@NL@%
- pop ax %@AB@%; Recover AX register%@AE@%%@NL@%
- iret %@AB@%; Return from handler%@AE@%%@NL@%
- %@AB@%; without taking action%@AE@%%@NL@%
- NewBreak ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* NewCtrlC - Handler for Interrupt 23h.%@AE@%%@NL@%
- %@NL@%
- NewCtrlC PROC FAR%@NL@%
- %@NL@%
- iret %@AB@%; Return from handler%@AE@%%@NL@%
- %@AB@%; without taking action%@AE@%%@NL@%
- NewCtrlC ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* NewCritErr - Handler for Interrupt 24h.%@AE@%%@NL@%
- %@NL@%
- NewCritErr PROC FAR%@NL@%
- %@NL@%
- sub al, al %@AB@%; Tell DOS to ignore error%@AE@%%@NL@%
- iret %@AB@%; Return from handler%@AE@%%@NL@%
- %@AB@%; without taking action%@AE@%%@NL@%
- NewCritErr ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%PAGERP.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\SHOW\PAGERP.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* PAGERP.ASM - Module containing routines for paging through a file and%@AE@%%@NL@%
- %@AB@%;* writing text to the screen buffer. Works with main module SHOWP.ASM.%@AE@%%@NL@%
- %@NL@%
- TITLE Pager%@NL@%
- .MODEL small, pascal, os_os2%@NL@%
- .286%@NL@%
- %@NL@%
- INCL_NOCOMMON EQU 1 %@AB@%; Enable call groups%@AE@%%@NL@%
- INCL_VIO EQU 1%@NL@%
- %@NL@%
- INCLUDE os2.inc%@NL@%
- INCLUDE show.inc%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* Pager - Displays status line and all the text lines for a screen.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: cLines - lines to scroll (negative up, positive down)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: Global variables: segBuf, offBuf, yCur%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Pager PROC,%@NL@%
- cLines:SWORD%@NL@%
- %@NL@%
- mov es, segBuf %@AB@%; Initialize buffer position%@AE@%%@NL@%
- mov di, offBuf%@NL@%
- %@NL@%
- mov cx, cLines %@AB@%; Get line count%@AE@%%@NL@%
- mov ax, 10 %@AB@%; Search for linefeed%@AE@%%@NL@%
- %@NL@%
- or cx, cx %@AB@%; Argument 0?%@AE@%%@NL@%
- jl backward %@AB@%; If below, backward%@AE@%%@NL@%
- jg foreward %@AB@%; If above, forward%@AE@%%@NL@%
- jmp showit %@AB@%; If equal, done%@AE@%%@NL@%
- %@NL@%
- backward:%@NL@%
- call GoBack %@AB@%; Adjust backward%@AE@%%@NL@%
- jmp showit %@AB@%; Show screen%@AE@%%@NL@%
- %@NL@%
- foreward:%@NL@%
- call GoForeward %@AB@%; Adjust forward%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write line number to status line%@AE@%%@NL@%
- %@NL@%
- showit:%@NL@%
- cld %@AB@%; Forward%@AE@%%@NL@%
- push di %@AB@%; Save%@AE@%%@NL@%
- push ds %@AB@%; ES = DS%@AE@%%@NL@%
- pop es%@NL@%
- %@NL@%
- INVOKE BinToStr, %@AB@%; Write line number as string%@AE@%%@NL@%
- yCur,%@NL@%
- ADDR stLine[LINE_POS]%@NL@%
- %@NL@%
- %@AB@%; Fill in status line%@AE@%%@NL@%
- %@NL@%
- mov cx, 6 %@AB@%; Six spaces to fill%@AE@%%@NL@%
- sub cx, ax %@AB@%; Subtract those already done%@AE@%%@NL@%
- mov al, ' ' %@AB@%; Fill with space%@AE@%%@NL@%
- rep stosb%@NL@%
- %@NL@%
- INVOKE VioWrtCharStrAtt, %@AB@%; Write to screen%@AE@%%@NL@%
- ADDR stLine,%@NL@%
- X_MAX,%@NL@%
- 0,%@NL@%
- 0,%@NL@%
- ADDR atSta,%@NL@%
- 0%@NL@%
- %@NL@%
- pop di %@AB@%; Update position%@AE@%%@NL@%
- mov si, di%@NL@%
- mov cx, yMax %@AB@%; Lines per screen%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov bx, yMax %@AB@%; Lines per screen%@AE@%%@NL@%
- inc bx %@AB@%; Adjust for 0%@AE@%%@NL@%
- sub bx, cx %@AB@%; Calculate current row%@AE@%%@NL@%
- push cx %@AB@%; Save line number%@AE@%%@NL@%
- mov es, segBuf %@AB@%; Reload%@AE@%%@NL@%
- %@NL@%
- INVOKE ShowLine, %@AB@%; Write line to screen%@AE@%%@NL@%
- es::si, %@AB@%; Pointer to current position%@AE@%%@NL@%
- bx, %@AB@%; Line number%@AE@%%@NL@%
- cbBuf, %@AB@%; File length (for bounds check)%@AE@%%@NL@%
- ADDR atScr %@AB@%; Attribute%@AE@%%@NL@%
- %@NL@%
- pop cx %@AB@%; Restore line number%@AE@%%@NL@%
- mov si, ax %@AB@%; Get returned position%@AE@%%@NL@%
- %@NL@%
- dec cx %@AB@%; Count the line%@AE@%%@NL@%
- .UNTIL (ax >= cbBuf) || !cx %@AB@%; Continue if more lines and not%@AE@%%@NL@%
- jcxz exit %@AB@%; Done if more lines,%@AE@%%@NL@%
- %@AB@%; else fill screen with spaces%@AE@%%@NL@%
- mov ax, X_MAX %@AB@%; Columns times remaining lines%@AE@%%@NL@%
- mul cl%@NL@%
- mov dx, ax %@AB@%; INVOKE uses AX, so use DX%@AE@%%@NL@%
- sub cx, yMax %@AB@%; Calculate starting line%@AE@%%@NL@%
- neg cx%@NL@%
- inc cx%@NL@%
- %@NL@%
- INVOKE VioWrtNCell, %@AB@%; Write space cells%@AE@%%@NL@%
- ADDR celScr, %@AB@%; Cell of space and attribute%@AE@%%@NL@%
- dx, %@AB@%; Number of cells to fill%@AE@%%@NL@%
- cx, %@AB@%; Line to start fill%@AE@%%@NL@%
- 0, %@AB@%; Column 0%@AE@%%@NL@%
- 0 %@AB@%; Console handle%@AE@%%@NL@%
- exit:%@NL@%
- ret%@NL@%
- %@NL@%
- Pager ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* ShowLine - Writes a line of text to the screen.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: pchIn - Far pointer to input text%@AE@%%@NL@%
- %@AB@%;* y - Line number%@AE@%%@NL@%
- %@AB@%;* cbMax - Maximum number of characters (file length)%@AE@%%@NL@%
- %@AB@%;* pcelAtrib - Far pointer to attribute%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- ShowLine PROC USES si di,%@NL@%
- pchIn:PBYTE,%@NL@%
- y:WORD,%@NL@%
- cbMax:WORD,%@NL@%
- pcelAtrib:PBYTE%@NL@%
- %@NL@%
- LOCAL achOut[X_MAX]:BYTE%@NL@%
- %@NL@%
- push ds %@AB@%; Save%@AE@%%@NL@%
- push ss %@AB@%; ES = SS%@AE@%%@NL@%
- pop es%@NL@%
- lea di, achOut %@AB@%; Destination line%@AE@%%@NL@%
- lds si, pchIn %@AB@%; Source line%@AE@%%@NL@%
- mov cx, X_MAX %@AB@%; Cells per row%@AE@%%@NL@%
- mov bx, di %@AB@%; Save copy of start for tab calc%@AE@%%@NL@%
- loop1:%@NL@%
- lodsb %@AB@%; Get character%@AE@%%@NL@%
- cmp al, 9 %@AB@%; Tab?%@AE@%%@NL@%
- je filltab %@AB@%; Space out tab%@AE@%%@NL@%
- cmp al, 13 %@AB@%; CR?%@AE@%%@NL@%
- je filleol %@AB@%; Fill rest of line with spaces%@AE@%%@NL@%
- stosb %@AB@%; Copy out%@AE@%%@NL@%
- cmp si, cbMax %@AB@%; Check for end of file%@AE@%%@NL@%
- ja filleol%@NL@%
- loop loop1%@NL@%
- loop2:%@NL@%
- lodsb %@AB@%; Throw away rest of line to truncate%@AE@%%@NL@%
- cmp si, cbMax %@AB@%; Check for end of file%@AE@%%@NL@%
- ja exit%@NL@%
- cmp al, 13 %@AB@%; Check for end of line%@AE@%%@NL@%
- jne loop2%@NL@%
- inc si %@AB@%; Throw away line feed%@AE@%%@NL@%
- %@NL@%
- jmp exit %@AB@%; Done%@AE@%%@NL@%
- filltab:%@NL@%
- push bx %@AB@%; Fill tab with spaces%@AE@%%@NL@%
- push cx%@NL@%
- %@NL@%
- sub bx, di %@AB@%; Get current position in line%@AE@%%@NL@%
- neg bx%@NL@%
- %@NL@%
- mov cx, 8 %@AB@%; Default count 8%@AE@%%@NL@%
- and bx, 7 %@AB@%; Get modulus%@AE@%%@NL@%
- sub cx, bx %@AB@%; Subtract%@AE@%%@NL@%
- mov bx, cx %@AB@%; Save modulus%@AE@%%@NL@%
- %@NL@%
- mov al, ' ' %@AB@%; Write spaces%@AE@%%@NL@%
- rep stosb%@NL@%
- %@NL@%
- pop cx%@NL@%
- sub cx, bx %@AB@%; Adjust count%@AE@%%@NL@%
- .IF sign?%@NL@%
- sub cx, cx %@AB@%; Make negative count 0%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- pop bx%@NL@%
- jcxz loop2 %@AB@%; If beyond limit done%@AE@%%@NL@%
- jmp loop1%@NL@%
- filleol:%@NL@%
- inc si %@AB@%; After CR, throw away LF%@AE@%%@NL@%
- mov al, ' ' %@AB@%; Fill rest of line%@AE@%%@NL@%
- rep stosb%@NL@%
- exit:%@NL@%
- pop ds%@NL@%
- INVOKE VioWrtCharStrAtt,%@NL@%
- ADDR achOut,%@NL@%
- X_MAX,%@NL@%
- y,%@NL@%
- 0,%@NL@%
- pcelAtrib,%@NL@%
- 0%@NL@%
- %@NL@%
- mov ax, si %@AB@%; Return position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- ShowLine ENDP%@NL@%
- %@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%PAGERR.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\SHOW\PAGERR.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* PAGERR.ASM - Module containing routines for paging through a file and%@AE@%%@NL@%
- %@AB@%;* writing text to the screen buffer. Works with main module SHOWR.ASM.%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- .MODEL small, pascal, os_dos %@AB@%; This code also works in tiny model%@AE@%%@NL@%
- %@NL@%
- INCLUDE show.inc%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* Pager - Displays status line and all the text lines for a screen.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: cLines - lines to scroll (negative up, positive down)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: Global variables: segBuf, offBuf, yCur%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Pager PROC,%@NL@%
- cLines:SWORD%@NL@%
- %@NL@%
- mov es, segBuf %@AB@%; Initialize buffer position%@AE@%%@NL@%
- mov di, offBuf%@NL@%
- %@NL@%
- mov cx, cLines %@AB@%; Get line count%@AE@%%@NL@%
- mov ax, 10 %@AB@%; Search for linefeed%@AE@%%@NL@%
- %@NL@%
- or cx, cx %@AB@%; Argument 0?%@AE@%%@NL@%
- jg forward %@AB@%; If above, forward%@AE@%%@NL@%
- jl backward %@AB@%; If below, backward%@AE@%%@NL@%
- jmp showit %@AB@%; If equal, done%@AE@%%@NL@%
- backward:%@NL@%
- call GoBack %@AB@%; Adjust backward%@AE@%%@NL@%
- jmp showit %@AB@%; Show screen%@AE@%%@NL@%
- forward:%@NL@%
- call GoForeward %@AB@%; Adjust forward%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write line number to status line%@AE@%%@NL@%
- %@NL@%
- showit:%@NL@%
- cld %@AB@%; Forward%@AE@%%@NL@%
- push di %@AB@%; Save%@AE@%%@NL@%
- push ds %@AB@%; ES = DS%@AE@%%@NL@%
- pop es%@NL@%
- %@NL@%
- INVOKE BinToStr, %@AB@%; Write line number as string%@AE@%%@NL@%
- yCur,%@NL@%
- ADDR stLine[LINE_POS]%@NL@%
- %@NL@%
- %@AB@%; Fill in status line%@AE@%%@NL@%
- %@NL@%
- mov cx, 6 %@AB@%; Seven spaces to fill%@AE@%%@NL@%
- sub cx, ax %@AB@%; Subtract those already done%@AE@%%@NL@%
- mov al, ' ' %@AB@%; Fill with space%@AE@%%@NL@%
- rep stosb%@NL@%
- %@NL@%
- INVOKE ShowLine, %@AB@%; Write to screen%@AE@%%@NL@%
- ADDR stLine, %@AB@%; Far pointer to line%@AE@%%@NL@%
- 0, %@AB@%; Line number%@AE@%%@NL@%
- atSta %@AB@%; Atttribute%@AE@%%@NL@%
- %@NL@%
- pop di%@NL@%
- mov si, di %@AB@%; Update position%@AE@%%@NL@%
- mov cx, yMax %@AB@%; Lines per screen%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- mov bx, yMax %@AB@%; Lines per screen%@AE@%%@NL@%
- inc bx %@AB@%; Adjust for 0%@AE@%%@NL@%
- sub bx, cx %@AB@%; Calculate current row%@AE@%%@NL@%
- push cx %@AB@%; Save line number%@AE@%%@NL@%
- mov es, segBuf %@AB@%; Reload%@AE@%%@NL@%
- %@NL@%
- INVOKE ShowLine, %@AB@%; Write line to screen%@AE@%%@NL@%
- es::si, %@AB@%; Far pointer to text%@AE@%%@NL@%
- bx, %@AB@%; Line number%@AE@%%@NL@%
- atScr %@AB@%; Attribute%@AE@%%@NL@%
- %@NL@%
- pop cx %@AB@%; Restore line number%@AE@%%@NL@%
- mov si, ax %@AB@%; Get returned position%@AE@%%@NL@%
- %@NL@%
- dec cx %@AB@%; Count the line%@AE@%%@NL@%
- .UNTIL (ax >= cbBuf) || !cx %@AB@%; Continue if more lines and not%@AE@%%@NL@%
- jcxz exit %@AB@%; Done if more lines,%@AE@%%@NL@%
- %@AB@%; else fill screen with spaces%@AE@%%@NL@%
- mov al, cl %@AB@%; Columns * remaining lines%@AE@%%@NL@%
- mov dl, X_MAX %@AB@%; is count of cells to fill%@AE@%%@NL@%
- mul dl%@NL@%
- mov dx, ax %@AB@%; Save in DX (INVOKE uses AX)%@AE@%%@NL@%
- %@NL@%
- sub cx, yMax %@AB@%; Calculate starting line%@AE@%%@NL@%
- neg cx%@NL@%
- inc cx%@NL@%
- %@NL@%
- INVOKE CellFill, %@AB@%; Write space cells%@AE@%%@NL@%
- cx, %@AB@%; Starting line%@AE@%%@NL@%
- dx, %@AB@%; Cells to write%@AE@%%@NL@%
- celScr %@AB@%; Cell to write%@AE@%%@NL@%
- exit:%@NL@%
- ret%@NL@%
- %@NL@%
- Pager ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* WriteNCell - Macro to write a cell one or more times. For CGA, the%@AE@%%@NL@%
- %@AB@%;* macro writes during horizontal retrace. Note that this is a macro%@AE@%%@NL@%
- %@AB@%;* even though it may result in more code than if it were a procedure.%@AE@%%@NL@%
- %@AB@%;* This is because writes to the screen buffer are a speed bottleneck%@AE@%%@NL@%
- %@AB@%;* that only occurs at a few key points in the program. The extra%@AE@%%@NL@%
- %@AB@%;* size cost is worth paying.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: ES:DI has screen buffer position%@AE@%%@NL@%
- %@AB@%;* AX has cell%@AE@%%@NL@%
- %@AB@%;* DX should have port number for rescan check if CGA%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: isCGA - One of the following:%@AE@%%@NL@%
- CGA EQU 1%@NL@%
- NoCGA EQU 0%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* count - If blank, write cell in AX once. If count given, write%@AE@%%@NL@%
- %@AB@%;* cell in AX count times. Note that the count is optimized for a%@AE@%%@NL@%
- %@AB@%;* CX argument. The argument should normally be blank or CX.%@AE@%%@NL@%
- %@NL@%
- WriteNCell MACRO isCGA:REQ, count:=<1>%@NL@%
- %@NL@%
- IF isCGA EQ 0 %@AB@%; First handle non-CGA%@AE@%%@NL@%
- IFIDNI <count>, <1> %@AB@%; Special case one cell%@AE@%%@NL@%
- stosw%@NL@%
- ELSE%@NL@%
- IFDIFI <count>, <cx> %@AB@%; Load count if necessary%@AE@%%@NL@%
- mov cx, count%@NL@%
- ENDIF%@NL@%
- rep stosw %@AB@%; Do repeated sequence%@AE@%%@NL@%
- ENDIF%@NL@%
- ELSE%@NL@%
- IFIDNI <count>, <1> %@AB@%; Special case one cell%@AE@%%@NL@%
- push ax %@AB@%; Save character%@AE@%%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Look in the port%@AE@%%@NL@%
- shr al, 1 %@AB@%; until it goes low%@AE@%%@NL@%
- .UNTIL !carry?%@NL@%
- cli%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Look in the port%@AE@%%@NL@%
- shr al, 1 %@AB@%; until it goes high%@AE@%%@NL@%
- .UNTIL carry?%@NL@%
- pop ax %@AB@%; Restore and write it%@AE@%%@NL@%
- stosw%@NL@%
- sti%@NL@%
- ELSE%@NL@%
- IFDIFI <count>, <cx> %@AB@%; Load count if necessary%@AE@%%@NL@%
- mov cx, count%@NL@%
- ENDIF%@NL@%
- .REPEAT%@NL@%
- push ax %@AB@%; Save character%@AE@%%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Look in the port%@AE@%%@NL@%
- shr al, 1 %@AB@%; until it goes low%@AE@%%@NL@%
- .UNTIL !carry?%@NL@%
- cli%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Look in the port%@AE@%%@NL@%
- shr al, 1 %@AB@%; until it goes high%@AE@%%@NL@%
- .UNTIL carry?%@NL@%
- pop ax %@AB@%; Restore and write it%@AE@%%@NL@%
- stosw%@NL@%
- sti%@NL@%
- .UNTILCXZ%@NL@%
- ENDIF%@NL@%
- ENDIF%@NL@%
- ENDM%@NL@%
- %@NL@%
- %@AB@%;* ShowLine - Writes a line to the screen buffer.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: fpBuffer - Far pointer to line to write%@AE@%%@NL@%
- %@AB@%;* y - Line number%@AE@%%@NL@%
- %@AB@%;* attr - Attribute%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- ShowLine PROC USES si di ds,%@NL@%
- fpBuffer:FAR PTR BYTE,%@NL@%
- y:WORD,%@NL@%
- attr:BYTE%@NL@%
- %@NL@%
- sub dx, dx %@AB@%; Zero%@AE@%%@NL@%
- .IF fCGA %@AB@%; User port number as CGA flag%@AE@%%@NL@%
- mov dx, 03DAh %@AB@%; Load port #%@AE@%%@NL@%
- .ENDIF%@NL@%
- mov es, segVid %@AB@%; Load screen buffer segment%@AE@%%@NL@%
- lds si, fpBuffer %@AB@%; Buffer segment%@AE@%%@NL@%
- mov cx, X_MAX %@AB@%; Cells per row%@AE@%%@NL@%
- mov ax, y %@AB@%; Starting row%@AE@%%@NL@%
- mov bx, X_MAX * 2 %@AB@%; Bytes per row%@AE@%%@NL@%
- mul bl %@AB@%; Figure columns per row%@AE@%%@NL@%
- mov di, ax %@AB@%; Load as destination%@AE@%%@NL@%
- mov bx, di %@AB@%; Save start for tab calculation%@AE@%%@NL@%
- mov ah, attr %@AB@%; Attribute%@AE@%%@NL@%
- movechar:%@NL@%
- lodsb %@AB@%; Get character%@AE@%%@NL@%
- cmp al, 13 %@AB@%; CR?%@AE@%%@NL@%
- je fillspc%@NL@%
- cmp al, 9 %@AB@%; Tab?%@AE@%%@NL@%
- jne notab%@NL@%
- call FillTab %@AB@%; Yes? fill with spaces%@AE@%%@NL@%
- jcxz nextline %@AB@%; If beyond limit done%@AE@%%@NL@%
- jmp movechar%@NL@%
- notab:%@NL@%
- or dx, dx %@AB@%; CGA?%@AE@%%@NL@%
- je notab2%@NL@%
- WriteNCell CGA %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
- loop movechar %@AB@%; Duplicate code here and below%@AE@%%@NL@%
- jmp nextline %@AB@%; is worth cost in tight loop%@AE@%%@NL@%
- notab2:%@NL@%
- WriteNCell NoCGA %@AB@%; Write%@AE@%%@NL@%
- loop movechar%@NL@%
- jmp nextline %@AB@%; Done%@AE@%%@NL@%
- fillspc:%@NL@%
- mov al, ' ' %@AB@%; Fill with space%@AE@%%@NL@%
- %@NL@%
- .IF dx != 0 %@AB@%; CGA?%@AE@%%@NL@%
- WriteNCell CGA, cx%@NL@%
- inc si %@AB@%; Adjust%@AE@%%@NL@%
- jmp exit %@AB@%; Done%@AE@%%@NL@%
- .ENDIF%@NL@%
- WriteNCell NoCGA, cx%@NL@%
- inc si %@AB@%; Adjust for LF%@AE@%%@NL@%
- jmp exit %@AB@%; Done%@AE@%%@NL@%
- nextline:%@NL@%
- mov ah, 10 %@AB@%; Search for next line feed%@AE@%%@NL@%
- .REPEAT%@NL@%
- lodsb %@AB@%; Load and compare%@AE@%%@NL@%
- .UNTILCXZ al == ah%@NL@%
- exit:%@NL@%
- mov ax, si %@AB@%; Return position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- ShowLine ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CellFill - Fills a portion of the screen with a specified%@AE@%%@NL@%
- %@AB@%;* character/attribute cell.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: yStart - Starting line%@AE@%%@NL@%
- %@AB@%;* cbCell - Number of cells%@AE@%%@NL@%
- %@AB@%;* celFill - Attribute and character%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CellFill PROC,%@NL@%
- yStart:WORD,%@NL@%
- cbCell:WORD,%@NL@%
- celFill:WORD%@NL@%
- %@NL@%
- mov dx, 03DAh %@AB@%; Load port #%@AE@%%@NL@%
- mov cx, yStart %@AB@%; Starting line%@AE@%%@NL@%
- mov al, X_MAX * 2 %@AB@%; Convert line to starting offset%@AE@%%@NL@%
- mul cl%@NL@%
- mov di, ax %@AB@%; Make it the target%@AE@%%@NL@%
- mov es, segVid %@AB@%; Load screen buffer segment%@AE@%%@NL@%
- mov cx, cbCell %@AB@%; Characters to fill%@AE@%%@NL@%
- mov ax, celFill %@AB@%; Attribute%@AE@%%@NL@%
- .IF fCGA %@AB@%; Write cells%@AE@%%@NL@%
- WriteNCell CGA, cx%@NL@%
- .ELSE%@NL@%
- WriteNCell NoCGA, cx%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- CellFill ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* FillTab - Writes spaces for tab to screen.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Input: BX points to start of line%@AE@%%@NL@%
- %@AB@%;* DI points to current position%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- FillTab PROC%@NL@%
- %@NL@%
- push bx%@NL@%
- push cx%@NL@%
- %@NL@%
- sub bx, di %@AB@%; Get current position in line%@AE@%%@NL@%
- neg bx%@NL@%
- shr bx, 1 %@AB@%; Divide by 2 bytes per character%@AE@%%@NL@%
- %@NL@%
- mov cx, 8 %@AB@%; Default count 8%@AE@%%@NL@%
- and bx, 7 %@AB@%; Get modulus%@AE@%%@NL@%
- sub cx, bx %@AB@%; Subtract%@AE@%%@NL@%
- mov bx, cx %@AB@%; Save modulus%@AE@%%@NL@%
- %@NL@%
- mov al, ' ' %@AB@%; Spaces%@AE@%%@NL@%
- .IF dx != 0 %@AB@%; Write cells%@AE@%%@NL@%
- WriteNCell CGA, cx%@NL@%
- .ELSE%@NL@%
- WriteNCell NoCGA, cx%@NL@%
- .ENDIF%@NL@%
- pop cx%@NL@%
- sub cx, bx %@AB@%; Adjust count%@AE@%%@NL@%
- .IF sign?%@NL@%
- sub cx, cx %@AB@%; Make negative count 0%@AE@%%@NL@%
- .ENDIF%@NL@%
- pop bx%@NL@%
- ret%@NL@%
- %@NL@%
- FillTab ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* IsEGA - Determines if the current adapter can handle more than 25%@AE@%%@NL@%
- %@AB@%;* lines per screen (usually an EGA or VGA).%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: 0 if no CGA or MONO, lines per screen if EGA/VGA%@AE@%%@NL@%
- %@NL@%
- IsEGA PROC%@NL@%
- %@NL@%
- mov ah, 12h %@AB@%; Call EGA status function%@AE@%%@NL@%
- mov bl, 10h%@NL@%
- sub cx, cx %@AB@%; Clear status bits%@AE@%%@NL@%
- int 10h%@NL@%
- sub ax, ax %@AB@%; Segment 0 and assume no EGA%@AE@%%@NL@%
- jcxz noega %@AB@%; If status still clear, no EGA%@AE@%%@NL@%
- %@NL@%
- mov es, ax %@AB@%; ES=0%@AE@%%@NL@%
- test BYTE PTR es:[487h], 1000y%@AB@%; Test active bit%@AE@%%@NL@%
- jnz noega %@AB@%; If set, not active%@AE@%%@NL@%
- mov ax, 1130h %@AB@%; Get EGA information%@AE@%%@NL@%
- int 10h%@NL@%
- mov al, dl %@AB@%; Return lines per screen%@AE@%%@NL@%
- cbw%@NL@%
- noega:%@NL@%
- ret%@NL@%
- %@NL@%
- IsEGA ENDP%@NL@%
- %@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%PASCAL.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\MIXED\PASCAL.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Assemble with ML /c PASCAL.ASM%@AE@%%@NL@%
- %@AB@%; Called by PASMAIN.PAS%@AE@%%@NL@%
- %@NL@%
- .MODEL medium, PASCAL%@NL@%
- .386%@NL@%
- Power2 PROTO PASCAL factor:WORD, power:WORD%@NL@%
- .CODE%@NL@%
- %@NL@%
- Power2 PROC factor:WORD, power:WORD%@NL@%
- %@NL@%
- mov ax, factor %@AB@%; Load Factor into AX%@AE@%%@NL@%
- mov cx, power %@AB@%; Load Power into CX%@AE@%%@NL@%
- shl ax, cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- ret %@AB@%; Leave return value in AX%@AE@%%@NL@%
- %@NL@%
- Power2 ENDP%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%QPEX.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\MIXED\QPEX.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Assemble with ML /c QPEX.ASM%@AE@%%@NL@%
- %@NL@%
- Power2 PROTO PASCAL factor:WORD, power:WORD%@NL@%
- %@NL@%
- CODE SEGMENT WORD PUBLIC%@NL@%
- ASSUME CS:CODE%@NL@%
- %@NL@%
- %@NL@%
- Power2 PROC PASCAL factor:WORD, power:WORD%@NL@%
- %@NL@%
- mov ax, factor %@AB@%; Load factor into AX%@AE@%%@NL@%
- mov cx, power %@AB@%; Load power into CX%@AE@%%@NL@%
- shl ax, cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- %@AB@%; Leave return value in AX%@AE@%%@NL@%
- ret%@NL@%
- Power2 ENDP%@NL@%
- %@NL@%
- CODE ENDS%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%SHOWP.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\SHOW\SHOWP.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* SHOWP.ASM - Text file displayer for OS/2 (protect mode).%@AE@%%@NL@%
- %@NL@%
- TITLE Show%@NL@%
- .MODEL small, pascal, os_os2%@NL@%
- .DOSSEG%@NL@%
- .286%@NL@%
- %@NL@%
- INCL_NOCOMMON EQU 1 %@AB@%; Enable call groups%@AE@%%@NL@%
- INCL_DOSFILEMGR EQU 1%@NL@%
- INCL_DOSMEMMGR EQU 1%@NL@%
- INCL_KBD EQU 1%@NL@%
- INCL_VIO EQU 1%@NL@%
- %@NL@%
- INCLUDE os2.inc%@NL@%
- INCLUDE show.inc%@NL@%
- INCLUDELIB os2.lib%@NL@%
- %@NL@%
- .STACK%@NL@%
- %@NL@%
- .DATA%@NL@%
- %@NL@%
- %@AB@%; Status line%@AE@%%@NL@%
- %@NL@%
- stLine BYTE "Line: 12345 "%@NL@%
- stFile BYTE "File: 12345678.123 "%@NL@%
- BYTE "Quit: Q Next: ESC Move: PGUP PGDN HOME END"%@NL@%
- %@NL@%
- %@AB@%; Variables for screen and cursor handling%@AE@%%@NL@%
- %@NL@%
- yCur WORD 1 %@AB@%; Current line number%@AE@%%@NL@%
- yMax WORD ? %@AB@%; Lines per screen%@AE@%%@NL@%
- vmiMode VIOMODEINFO < SIZE VIOMODEINFO > %@AB@%; Structure for video data%@AE@%%@NL@%
- %@AB@%; First field initialized to size%@AE@%%@NL@%
- vciCsr VIOCURSORINFO <> %@AB@%; Structure for cursor data%@AE@%%@NL@%
- atCsr WORD -1 %@AB@%; Cursor attribute (initized to hidden)%@AE@%%@NL@%
- bCsrSta BYTE 0 %@AB@%; 0 = cursor visible, position unchanged%@AE@%%@NL@%
- %@AB@%; 1 = cursor invisible, position unchanged%@AE@%%@NL@%
- %@AB@%; 2 = cursor invisible, position changed%@AE@%%@NL@%
- %@NL@%
- atSta BYTE STAT_CLR %@AB@%; Status line color%@AE@%%@NL@%
- celScr LABEL WORD %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
- chScr BYTE " " %@AB@%; Initialize to space%@AE@%%@NL@%
- atScr BYTE SCRN_CLR %@AB@%; Screen color%@AE@%%@NL@%
- chInit BYTE 0 %@AB@%; Cell to restore when finished%@AE@%%@NL@%
- atInit BYTE 0%@NL@%
- %@NL@%
- %@AB@%; Buffer variables%@AE@%%@NL@%
- %@NL@%
- fpBuf LABEL PBYTE%@NL@%
- offBuf WORD 0 %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
- segBuf SEL ? %@AB@%; Base of buffer (segment selector)%@AE@%%@NL@%
- cbBuf WORD ? %@AB@%; Count in bytes of buffer%@AE@%%@NL@%
- %@NL@%
- %@AB@%; File information%@AE@%%@NL@%
- %@NL@%
- hFileIn HFILE ? %@AB@%; Holds file handle on open%@AE@%%@NL@%
- usAct WORD ? %@AB@%; Result of open%@AE@%%@NL@%
- usMode WORD OPEN_ACCESS_READONLY OR OPEN_SHARE_DENYNONE%@NL@%
- cbRead WORD ? %@AB@%; Bytes read from file%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Directory information for file name search%@AE@%%@NL@%
- %@NL@%
- stFiles BYTE NAME_MAX DUP ("w")%@NL@%
- hFiles WORD HDIR_CREATE %@AB@%; Directory handle%@AE@%%@NL@%
- fiFiles FILEFINDBUF <> %@AB@%; Structure for results%@AE@%%@NL@%
- usCount WORD 1 %@AB@%; Find one file at a time%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Buffer for file name%@AE@%%@NL@%
- %@NL@%
- kkiChar KBDKEYINFO <> %@AB@%; Structure for character input%@AE@%%@NL@%
- sibStr STRINGINBUF < NAME_MAX >%@AB@%; Structure for string input%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Messages%@AE@%%@NL@%
- %@NL@%
- stMsg1 BYTE 13, 10, "Enter filename: "%@NL@%
- stMsg2 BYTE 13, 10, "File problem. Try again? "%@NL@%
- stMsg3 BYTE 13, 10, "File too large: "%@NL@%
- stMsg4 BYTE 13, 10, "Memory problem.",13,10%@NL@%
- %@NL@%
- %@AB@%; Call table%@AE@%%@NL@%
- %@NL@%
- achKeys BYTE 71, 72, 73, 79, 80, 81, 'q', 'Q'%@AB@%; Key table%@AE@%%@NL@%
- afnKeys WORD HomeKey %@AB@%; Corresponding procedures%@AE@%%@NL@%
- WORD UpKey%@NL@%
- WORD PgUpKey%@NL@%
- WORD EndKey%@NL@%
- WORD DownKey%@NL@%
- WORD PgDnKey%@NL@%
- WORD Quit%@NL@%
- WORD Quit%@NL@%
- WORD UnknownKey%@NL@%
- %@NL@%
- .CODE%@NL@%
- .STARTUP%@NL@%
- %@NL@%
- %@AB@%; Load environment segment%@AE@%%@NL@%
- %@NL@%
- mov es, ax %@AB@%; AX points to environment segment%@AE@%%@NL@%
- mov di, bx %@AB@%; BX points to command line offset%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Throw away .EXE name%@AE@%%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Find null at end of program name%@AE@%%@NL@%
- repne scasb%@NL@%
- cmp BYTE PTR es:[di], 0 %@AB@%; If double zero, there's no name%@AE@%%@NL@%
- je Prompter %@AB@%; so get from prompt%@AE@%%@NL@%
- %@NL@%
- .IF BYTE PTR es:[di] == ' '%@NL@%
- inc di %@AB@%; Skip leading space%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Copy command line to file name buffer%@AE@%%@NL@%
- %@NL@%
- mov si, di %@AB@%; Filename source%@AE@%%@NL@%
- mov di, OFFSET stFiles %@AB@%; Name buffer destination%@AE@%%@NL@%
- mov bx, ds %@AB@%; Save segment registers%@AE@%%@NL@%
- mov dx, es%@NL@%
- mov ds, dx %@AB@%; DS = ES%@AE@%%@NL@%
- mov es, bx %@AB@%; ES = DS%@AE@%%@NL@%
- mov cx, NAME_MAX %@AB@%; Count = max file name allowed%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- lodsb %@AB@%; Copy characters%@AE@%%@NL@%
- .BREAK .IF (al == ' ') || (al == 0) %@AB@%; Stop at space or null%@AE@%%@NL@%
- stosb%@NL@%
- .UNTILCXZ %@AB@%; Until name exceeds max%@AE@%%@NL@%
- %@NL@%
- mov ds, bx %@AB@%; Restore DS%@AE@%%@NL@%
- mov BYTE PTR [di], 0%@NL@%
- jmp FindFile%@NL@%
- %@NL@%
- %@AB@%; Prompt for file%@AE@%%@NL@%
- %@NL@%
- NoFile:%@NL@%
- INVOKE VioWrtTTy, %@AB@%; Write message%@AE@%%@NL@%
- ADDR stMsg2,%@NL@%
- LENGTHOF stMsg2,%@NL@%
- 0%@NL@%
- %@NL@%
- INVOKE KbdCharIn,%@NL@%
- ADDR kkiChar,%@NL@%
- IO_WAIT,%@NL@%
- 0%@NL@%
- %@NL@%
- and kkiChar.chChar_, 11011111y %@AB@%; Convert to uppercase%@AE@%%@NL@%
- cmp kkiChar.chChar_, "Y"%@NL@%
- %@NL@%
- mov hFiles, -1%@NL@%
- mov usCount, 1%@NL@%
- .IF !zero?%@NL@%
- jmp Quit %@AB@%; Quit if not yes%@AE@%%@NL@%
- .ENDIF%@NL@%
- Prompter:%@NL@%
- INVOKE VioWrtTTy, %@AB@%; Else prompt for file name%@AE@%%@NL@%
- ADDR stMsg1,%@NL@%
- LENGTHOF stMsg1,%@NL@%
- 0%@NL@%
- %@NL@%
- INVOKE KbdStringIn,%@NL@%
- ADDR stFiles,%@NL@%
- ADDR sibStr,%@NL@%
- IO_WAIT,%@NL@%
- 0%@NL@%
- %@NL@%
- mov di, sibStr.cchIn_ %@AB@%; Null terminate%@AE@%%@NL@%
- mov stFiles[di], 0%@NL@%
- %@NL@%
- %@AB@%; Find first (or only) file in filespec%@AE@%%@NL@%
- %@NL@%
- FindFile:%@NL@%
- INVOKE DosFindFirst,%@NL@%
- ADDR stFiles,%@NL@%
- ADDR hFiles,%@NL@%
- 0,%@NL@%
- ADDR fiFiles,%@NL@%
- SIZE fiFiles,%@NL@%
- ADDR usCount,%@NL@%
- 0%@NL@%
- %@NL@%
- or ax, ax%@NL@%
- jnz NoFile%@NL@%
- %@NL@%
- INVOKE GetVid %@AB@%; Adjust for current mode and%@AE@%%@NL@%
- %@AB@%; video adapter and hide cursor%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Main program loop to process files%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- %@NL@%
- %@AB@%; Copy file name to file spec%@AE@%%@NL@%
- %@NL@%
- mov bCsrSta, 2 %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
- INVOKE GetNamePos, %@AB@%; Get file name position in file spec%@AE@%%@NL@%
- ADDR stFiles%@NL@%
- %@NL@%
- mov si, OFFSET fiFiles.achName_%@AB@%; Load source name%@AE@%%@NL@%
- mov di, ax %@AB@%; Load adjusted destination address%@AE@%%@NL@%
- %@AB@%; from return value%@AE@%%@NL@%
- sub cx, cx %@AB@%; Load file name length%@AE@%%@NL@%
- mov cl, fiFiles.cchName_%@NL@%
- rep movsb %@AB@%; Copy to spec%@AE@%%@NL@%
- mov BYTE PTR es:[di], 0 %@AB@%; Null terminate%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Copy file name to status line%@AE@%%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Load file length%@AE@%%@NL@%
- mov cl, fiFiles.cchName_%@NL@%
- mov bx, 12 %@AB@%; Calculate blank spaces to fill%@AE@%%@NL@%
- sub bx, cx%@NL@%
- push ds %@AB@%; ES=DS%@AE@%%@NL@%
- pop es%@NL@%
- mov si, OFFSET fiFiles.achName_%@AB@%; File name as source%@AE@%%@NL@%
- mov di, OFFSET stFile[FILE_POS]%@AB@%; Status line as destination%@AE@%%@NL@%
- rep movsb%@NL@%
- mov al, " " %@AB@%; Fill rest of name space with blanks%@AE@%%@NL@%
- mov cx, bx%@NL@%
- rep stosb%@NL@%
- %@NL@%
- %@AB@%; Skip any file that is larger than 64K%@AE@%%@NL@%
- %@NL@%
- .IF WORD PTR fiFiles.cbFile_[2] != 0%@NL@%
- %@NL@%
- INVOKE VioWrtTTy,%@NL@%
- ADDR stMsg3,%@NL@%
- LENGTHOF stMsg3,%@NL@%
- 0%@NL@%
- %@NL@%
- INVOKE VioWrtTTy,%@NL@%
- ADDR fiFiles.achName_,%@NL@%
- fiFiles.cchName_,%@NL@%
- 0%@NL@%
- %@NL@%
- .IF usCount <= 0 %@AB@%; Get key if there's another file%@AE@%%@NL@%
- INVOKE KbdCharIn,%@NL@%
- ADDR kkiChar,%@NL@%
- IO_WAIT,%@NL@%
- 0%@NL@%
- .ENDIF%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Allocate file Buffer%@AE@%%@NL@%
- %@NL@%
- mov ax, WORD PTR fiFiles.cbFile_[0] %@AB@%; Save size%@AE@%%@NL@%
- mov cbBuf, ax%@NL@%
- mov offBuf, 0%@NL@%
- INVOKE DosAllocSeg,%@NL@%
- ax,%@NL@%
- ADDR segBuf,%@NL@%
- 0%@NL@%
- %@NL@%
- .IF ax != 0%@NL@%
- mov bCsrSta, 1 %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
- INVOKE VioWrtTTy,%@NL@%
- ADDR stMsg4,%@NL@%
- LENGTHOF stMsg4,%@NL@%
- 0%@NL@%
- %@NL@%
- jmp Quit%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Open file and read contents into buffer%@AE@%%@NL@%
- %@NL@%
- INVOKE DosOpen,%@NL@%
- ADDR stFiles,%@NL@%
- ADDR hFileIn,%@NL@%
- ADDR usAct,%@NL@%
- 0,%@NL@%
- FILE_NORMAL,%@NL@%
- FILE_OPEN,%@NL@%
- usMode,%@NL@%
- 0%@NL@%
- %@NL@%
- .IF ax != 0%@NL@%
- jmp NoFile%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- INVOKE DosRead,%@NL@%
- hFileIn,%@NL@%
- fpBuf,%@NL@%
- cbBuf,%@NL@%
- ADDR cbRead%@NL@%
- %@NL@%
- .IF ax != 0%@NL@%
- jmp NoFile%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Search back for EOF marker and adjust if necessary%@AE@%%@NL@%
- %@NL@%
- mov di, cbRead %@AB@%; Load file length%@AE@%%@NL@%
- dec di %@AB@%; and adjust%@AE@%%@NL@%
- mov es, segBuf %@AB@%; Save ES and load buffer segment%@AE@%%@NL@%
- std %@AB@%; Look backward for 255 characters%@AE@%%@NL@%
- mov cx, 0FFh%@NL@%
- .IF cx >= di%@NL@%
- mov cx, di%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov al, 1Ah %@AB@%; Search for EOF marker%@AE@%%@NL@%
- repne scasb%@NL@%
- cld%@NL@%
- .IF cx != 0 %@AB@%; If found:%@AE@%%@NL@%
- inc di %@AB@%; Adjust and save file size%@AE@%%@NL@%
- mov cbBuf, di%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Show a screen of text and allow commands%@AE@%%@NL@%
- %@NL@%
- INVOKE Show%@NL@%
- %@NL@%
- INVOKE DosClose, %@AB@%; Close file%@AE@%%@NL@%
- hFileIn%@NL@%
- %@NL@%
- INVOKE DosFreeSeg, %@AB@%; Free memofy%@AE@%%@NL@%
- segBuf%@NL@%
- %@NL@%
- INVOKE DosFindNext, %@AB@%; Get next file%@AE@%%@NL@%
- hFiles,%@NL@%
- ADDR fiFiles,%@NL@%
- SIZE fiFiles,%@NL@%
- ADDR usCount%@NL@%
- %@NL@%
- .UNTIL ax != 0 %@AB@%; Fall through to Quit if%@AE@%%@NL@%
- %@AB@%; this is the last file%@AE@%%@NL@%
- Quit PROC%@NL@%
- %@NL@%
- cmp bCsrSta, 1 %@AB@%; Check cursor status%@AE@%%@NL@%
- jg csrvislast %@AB@%; 2 - Make cursor visible on last line%@AE@%%@NL@%
- je csrvis %@AB@%; 1 - Make cursor visible%@AE@%%@NL@%
- jmp csrasis %@AB@%; 0 - Leave cursor as is%@AE@%%@NL@%
- %@NL@%
- csrvislast:%@NL@%
- INVOKE VioSetCurPos, %@AB@%; Restore cursor on last line%@AE@%%@NL@%
- yMax,%@NL@%
- 0,%@NL@%
- 0%@NL@%
- INVOKE VioScrollDn,%@NL@%
- yMax,%@NL@%
- 0,%@NL@%
- yMax,%@NL@%
- 79,%@NL@%
- 1,%@NL@%
- ADDR chInit,%@NL@%
- 0%@NL@%
- csrvis: %@AB@%; Fall through%@AE@%%@NL@%
- mov ax, atCsr %@AB@%; Restore cursor attribute%@AE@%%@NL@%
- mov vciCsr.attr_, ax%@NL@%
- INVOKE VioSetCurType,%@NL@%
- ADDR vciCsr,%@NL@%
- 0%@NL@%
- csrasis: %@AB@%; Fall through%@AE@%%@NL@%
- .EXIT 0%@NL@%
- %@NL@%
- Quit ENDP%@NL@%
- %@NL@%
- %@NL@%
- Show PROC%@NL@%
- %@NL@%
- %@AB@%; Display first page%@AE@%%@NL@%
- %@NL@%
- mov yCur, 1%@NL@%
- INVOKE Pager, %@AB@%; Start at 0%@AE@%%@NL@%
- 0%@NL@%
- %@NL@%
- %@AB@%; Handle keys%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- INVOKE KbdCharIn, %@AB@%; Get a key and load to register%@AE@%%@NL@%
- ADDR kkiChar,%@NL@%
- IO_WAIT,%@NL@%
- 0%@NL@%
- %@NL@%
- mov al, kkiChar.chChar_%@NL@%
- %@NL@%
- .BREAK .IF al == 27 %@AB@%; If ESCAPE get out for next file%@AE@%%@NL@%
- %@NL@%
- %@AB@%; If null or E0 (for extended keyboard), it's an extended key%@AE@%%@NL@%
- .IF (al == 0) || (al == 0E0h)%@NL@%
- mov al, kkiChar.chScan_ %@AB@%; Load scan code%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- push ds %@AB@%; ES = DS%@AE@%%@NL@%
- pop es%@NL@%
- mov di, OFFSET achKeys %@AB@%; Load address and length of key list%@AE@%%@NL@%
- mov cx, LENGTHOF achKeys + 1%@NL@%
- repne scasb %@AB@%; Find position and point to key%@AE@%%@NL@%
- sub di, OFFSET achKeys + 1%@NL@%
- shl di, 1 %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
- call afnKeys[di] %@AB@%; Call procedure%@AE@%%@NL@%
- .UNTIL 0%@NL@%
- %@NL@%
- ret%@NL@%
- Show ENDP%@NL@%
- %@NL@%
- HomeKey:%@NL@%
- mov offBuf, 0 %@AB@%; HOME - set position to 0%@AE@%%@NL@%
- mov yCur, 1%@NL@%
- INVOKE Pager, offBuf%@NL@%
- retn%@NL@%
- %@NL@%
- UpKey:%@NL@%
- INVOKE Pager, -1 %@AB@%; UP - scroll back 1 line%@AE@%%@NL@%
- retn%@NL@%
- %@NL@%
- PgUpKey:%@NL@%
- mov ax, yMax %@AB@%; PGUP - Page back%@AE@%%@NL@%
- neg ax%@NL@%
- INVOKE Pager, ax%@NL@%
- retn%@NL@%
- %@NL@%
- EndKey:%@NL@%
- mov ax, cbBuf %@AB@%; END - Get last byte of file%@AE@%%@NL@%
- dec ax %@AB@%; Zero adjust%@AE@%%@NL@%
- mov offBuf, ax %@AB@%; Make it the file position%@AE@%%@NL@%
- mov yCur, -1 %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
- mov ax, yMax %@AB@%; Page back%@AE@%%@NL@%
- neg ax%@NL@%
- INVOKE Pager, ax%@NL@%
- retn%@NL@%
- %@NL@%
- DownKey:%@NL@%
- INVOKE Pager, 1 %@AB@%; DOWN - scroll forward 1 line%@AE@%%@NL@%
- retn%@NL@%
- %@NL@%
- PgDnKey:%@NL@%
- INVOKE Pager, yMax %@AB@%; PGDN - page forward%@AE@%%@NL@%
- retn%@NL@%
- %@NL@%
- UnknownKey:%@NL@%
- retn %@AB@%; Ignore unknown key%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetVid - Gets the video mode and sets related global variables.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Number of lines in current mode (25, 43, or 50)%@AE@%%@NL@%
- %@NL@%
- GetVid PROC%@NL@%
- %@NL@%
- LOCAL x:USHORT, y:USHORT, cb:USHORT%@NL@%
- %@NL@%
- %@NL@%
- INVOKE VioGetMode, %@AB@%; Get video mode%@AE@%%@NL@%
- ADDR vmiMode,%@NL@%
- 0%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Clear AH%@AE@%%@NL@%
- mov al, vmiMode.fbType_ %@AB@%; Put type in register%@AE@%%@NL@%
- %@NL@%
- %@AB@%; If monochrome or color burst off:%@AE@%%@NL@%
- .IF (al & VGMT_GRAPHICS) || (al & VGMT_DISABLEBURST)%@NL@%
- mov atSta, STAT_BW %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
- mov atScr, SCRN_BW %@AB@%; and screen background%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- INVOKE VioGetCurPos, %@AB@%; Get cursor position (for cell read)%@AE@%%@NL@%
- ADDR y, %@AB@%; Row%@AE@%%@NL@%
- ADDR x, %@AB@%; Column%@AE@%%@NL@%
- 0 %@AB@%; Console handle%@AE@%%@NL@%
- %@NL@%
- mov cb, 1 %@AB@%; One cell%@AE@%%@NL@%
- INVOKE VioReadCellStr, %@AB@%; Read cell to get current attribute%@AE@%%@NL@%
- ADDR chInit, %@AB@%; Address to receive cell%@AE@%%@NL@%
- ADDR cb, %@AB@%; Address of length%@AE@%%@NL@%
- y, %@AB@%; Row%@AE@%%@NL@%
- x, %@AB@%; Column%@AE@%%@NL@%
- 0 %@AB@%; Console handle%@AE@%%@NL@%
- mov chInit, ' ' %@AB@%; Make sure character is space%@AE@%%@NL@%
- %@NL@%
- INVOKE VioGetCurType, %@AB@%; Get cursor mode%@AE@%%@NL@%
- ADDR vciCsr,%@NL@%
- 0%@NL@%
- mov ax, vciCsr.attr_ %@AB@%; Save cursor attribute%@AE@%%@NL@%
- xchg atCsr, ax%@NL@%
- mov vciCsr.attr_, ax %@AB@%; Set hidden cursor attribute%@AE@%%@NL@%
- mov ax, vmiMode.row_ %@AB@%; Get number of rows and adjust%@AE@%%@NL@%
- dec ax%@NL@%
- mov yMax, ax%@NL@%
- %@NL@%
- INVOKE VioSetCurType, %@AB@%; Hide cursor%@AE@%%@NL@%
- ADDR vciCsr,%@NL@%
- 0%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- GetVid ENDP%@NL@%
- %@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%SHOWR.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\SHOW\SHOWR.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* SHOWR.ASM - Text file displayer for DOS (real mode).%@AE@%%@NL@%
- %@NL@%
- TITLE Show%@NL@%
- .MODEL small, pascal, os_dos %@AB@%; This code also works in tiny model%@AE@%%@NL@%
- .DOSSEG%@NL@%
- %@NL@%
- INCLUDE show.inc%@NL@%
- INCLUDE dos.inc%@NL@%
- INCLUDE bios.inc%@NL@%
- %@NL@%
- .STACK%@NL@%
- %@NL@%
- .DATA%@NL@%
- %@NL@%
- %@AB@%; Status line%@AE@%%@NL@%
- %@NL@%
- stLine BYTE "Line: 12345 "%@NL@%
- stFile BYTE "File: 12345678.123 "%@NL@%
- BYTE "Quit: Q Next: ESC Move: PGUP PGDN HOME END"%@NL@%
- %@NL@%
- %@AB@%; Variables for screen handling%@AE@%%@NL@%
- %@NL@%
- yCur WORD 1%@NL@%
- yMax WORD 24 %@AB@%; Number of rows - status line takes one more%@AE@%%@NL@%
- iMode BYTE 0 %@AB@%; Initial mode%@AE@%%@NL@%
- iPage BYTE 0 %@AB@%; Initial display page%@AE@%%@NL@%
- atInit BYTE 0 %@AB@%; Initial attribute%@AE@%%@NL@%
- shCsr WORD 0 %@AB@%; Initial cursor shape%@AE@%%@NL@%
- bCsrSta BYTE 0 %@AB@%; 0 = cursor visible, position unchanged%@AE@%%@NL@%
- %@AB@%; 1 = cursor invisible, position unchanged%@AE@%%@NL@%
- %@AB@%; 2 = cursor invisible, position changed%@AE@%%@NL@%
- %@NL@%
- fNewVid BYTE 0 %@AB@%; Video change flag%@AE@%%@NL@%
- fCGA BYTE 1 %@AB@%; CGA flag - default yes%@AE@%%@NL@%
- %@NL@%
- segVid WORD SEG_CLR %@AB@%; Video buffer address - default color%@AE@%%@NL@%
- %@NL@%
- atSta BYTE STAT_CLR %@AB@%; Status line color%@AE@%%@NL@%
- celScr LABEL WORD %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
- chScr BYTE ' ' %@AB@%; Initialize to space%@AE@%%@NL@%
- atScr BYTE SCRN_CLR %@AB@%; Screen color%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Buffer variables%@AE@%%@NL@%
- %@NL@%
- fpBuf LABEL FAR PTR%@NL@%
- offBuf WORD 0 %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
- segBuf WORD 0 %@AB@%; Base of buffer (segment)%@AE@%%@NL@%
- cbBuf WORD 0 %@AB@%; Length of buffer%@AE@%%@NL@%
- %@NL@%
- %@AB@%; File information%@AE@%%@NL@%
- %@NL@%
- hFileIn WORD 0 %@AB@%; Holds file handle on open%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Buffer for file spec and structure for file info%@AE@%%@NL@%
- %@NL@%
- achBuf BYTE NAME_MAX, ? %@AB@%; Buffer format for string input%@AE@%%@NL@%
- stFiles BYTE NAME_MAX DUP (0)%@AB@%; File spec string%@AE@%%@NL@%
- fiFiles FILE_INFO <> %@AB@%; Wild card entry structure%@AE@%%@NL@%
- cFiles WORD 0 %@AB@%; Count of 1 or 0 files remaining%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Messages%@AE@%%@NL@%
- %@NL@%
- stMsg1 BYTE 13, 10, 13, 10, "Enter filename: $"%@NL@%
- stMsg2 BYTE 13, 10, "File problem. Try again? $"%@NL@%
- stMsg3 BYTE 13, 10, "File too large: $"%@NL@%
- stMsg4 BYTE 13, 10, "Memory problem.", 13, 10, "$"%@NL@%
- stMsg5 BYTE 13, 10, "Must have DOS 2.0 or higher", 13, 10, "$"%@NL@%
- %@NL@%
- %@AB@%; Call table%@AE@%%@NL@%
- %@NL@%
- achKeys BYTE 71, 72, 73, 79, 80, 81, 'q', 'Q'%@AB@%; Key table%@AE@%%@NL@%
- afnKeys WORD HomeKey %@AB@%; Corresponding procedures%@AE@%%@NL@%
- WORD UpKey%@NL@%
- WORD PgUpKey%@NL@%
- WORD EndKey%@NL@%
- WORD DownKey%@NL@%
- WORD PgDnKey%@NL@%
- WORD Quit%@NL@%
- WORD Quit%@NL@%
- WORD UnknownKey%@NL@%
- %@NL@%
- .CODE%@NL@%
- .STARTUP%@NL@%
- %@NL@%
- %@AB@%; Adjust memory allocation (works for tiny or small model)%@AE@%%@NL@%
- %@NL@%
- mov bx, sp %@AB@%; Convert stack pointer to paragraphs%@AE@%%@NL@%
- mov cl, 4 %@AB@%; to get stack size%@AE@%%@NL@%
- shr bx, cl%@NL@%
- mov ax, ss %@AB@%; Add SS to get end of program%@AE@%%@NL@%
- add ax, bx%@NL@%
- mov bx, es %@AB@%; Get start of program%@AE@%%@NL@%
- sub ax, bx %@AB@%; Subtract start from end%@AE@%%@NL@%
- inc ax%@NL@%
- @ModBlock ax %@AB@%; Release memory after program%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Check DOS%@AE@%%@NL@%
- %@NL@%
- @GetVer %@AB@%; Get DOS version%@AE@%%@NL@%
- .IF al < 2 %@AB@%; Requires DOS 2.0%@AE@%%@NL@%
- @ShowStr stMsg5 %@AB@%; else error and quit%@AE@%%@NL@%
- int 20h%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Get command line and copy to file name buffer%@AE@%%@NL@%
- %@NL@%
- mov di, 80h %@AB@%; PSP offset of command line%@AE@%%@NL@%
- mov bl, es:[di] %@AB@%; Get length from first byte%@AE@%%@NL@%
- sub bh, bh%@NL@%
- or bx, bx%@NL@%
- je Prompter%@NL@%
- %@NL@%
- mov WORD PTR es:[bx+81h], 0 %@AB@%; Convert to ASCIIZ%@AE@%%@NL@%
- mov al, ' ' %@AB@%; Character to check for%@AE@%%@NL@%
- inc di %@AB@%; Advance beyond count%@AE@%%@NL@%
- mov cx, 0FFFFh %@AB@%; Don't let count interfere%@AE@%%@NL@%
- repe scasb %@AB@%; Find first non-space%@AE@%%@NL@%
- dec di %@AB@%; Adjust%@AE@%%@NL@%
- %@NL@%
- mov si, di %@AB@%; Filename source%@AE@%%@NL@%
- mov di, OFFSET stFiles %@AB@%; Name buffer destination%@AE@%%@NL@%
- mov bx, ds %@AB@%; Save segment registers%@AE@%%@NL@%
- mov dx, es%@NL@%
- mov ds, dx %@AB@%; DS = ES%@AE@%%@NL@%
- mov es, bx %@AB@%; ES = DS%@AE@%%@NL@%
- mov cx, NAME_MAX %@AB@%; Count = max file name allowed%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- lodsb %@AB@%; Copy characters%@AE@%%@NL@%
- .BREAK .IF (al == ' ') || (al == 0) %@AB@%; Stop at space or null%@AE@%%@NL@%
- stosb%@NL@%
- .UNTILCXZ %@AB@%; Until name exceeds max%@AE@%%@NL@%
- %@NL@%
- mov ds, bx %@AB@%; Restore segments%@AE@%%@NL@%
- mov es, dx%@NL@%
- mov BYTE PTR [di], 0%@NL@%
- jmp FindFile%@NL@%
- NoFile:%@NL@%
- %@NL@%
- @ShowStr stMsg2 %@AB@%; Prompt to try again%@AE@%%@NL@%
- @GetChar 0, 1, 0%@NL@%
- and al, 11011111y %@AB@%; Convert key to uppercase%@AE@%%@NL@%
- .IF al != 'Y' %@AB@%; If not yes,%@AE@%%@NL@%
- jmp quit %@AB@%; quit%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Prompt for file%@AE@%%@NL@%
- %@NL@%
- Prompter:%@NL@%
- @ShowStr stMsg1 %@AB@%; Prompt for file%@AE@%%@NL@%
- @GetStr achBuf, 0 %@AB@%; Get response as ASCIIZ%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Find first (or only) file in filespec%@AE@%%@NL@%
- %@NL@%
- FindFile:%@NL@%
- %@NL@%
- @SetDTA <OFFSET fiFiles> %@AB@%; Set DTA to file info structure%@AE@%%@NL@%
- %@AB@%; Don't need DTA for anything else,%@AE@%%@NL@%
- %@AB@%; so no need to restore it%@AE@%%@NL@%
- @GetFirst stFiles,0 %@AB@%; Find a matching file%@AE@%%@NL@%
- %@NL@%
- jc NoFile %@AB@%; If not found, prompt for new%@AE@%%@NL@%
- inc cFiles %@AB@%; Some files remaining%@AE@%%@NL@%
- %@NL@%
- INVOKE GetVid%@NL@%
- %@NL@%
- %@AB@%; Main program loop to process files%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- %@NL@%
- %@AB@%; Copy file name to file spec%@AE@%%@NL@%
- %@NL@%
- mov bCsrSta, 2 %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
- INVOKE GetNamePos, %@AB@%; Get file name position in file spec%@AE@%%@NL@%
- ADDR stFiles%@NL@%
- %@NL@%
- mov si, OFFSET fiFiles.FName%@AB@%; Point to source name%@AE@%%@NL@%
- push ds %@AB@%; ES = DS%@AE@%%@NL@%
- pop es%@NL@%
- mov di, ax %@AB@%; Load address from return value%@AE@%%@NL@%
- %@NL@%
- .REPEAT %@AB@%; Copy to (and including) null%@AE@%%@NL@%
- movsb%@NL@%
- .UNTIL BYTE PTR [si-1] == 0%@NL@%
- %@NL@%
- %@AB@%; Copy file name to status line%@AE@%%@NL@%
- %@NL@%
- mov si, OFFSET fiFiles.FName %@AB@%; Point to source name%@AE@%%@NL@%
- mov di, OFFSET stFile[FILE_POS] %@AB@%; Point to status line%@AE@%%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Count characters%@AE@%%@NL@%
- .REPEAT%@NL@%
- lodsb %@AB@%; Copy to (but excluding) null%@AE@%%@NL@%
- .BREAK .IF al == 0%@NL@%
- stosb%@NL@%
- inc cx%@NL@%
- .UNTIL 0%@NL@%
- %@NL@%
- mov bx, 12 %@AB@%; Calculate blank spaces to fill%@AE@%%@NL@%
- sub bx, cx%@NL@%
- mov al, ' ' %@AB@%; Fill rest of name space with blanks%@AE@%%@NL@%
- mov cx, bx%@NL@%
- rep stosb%@NL@%
- %@NL@%
- %@AB@%; Skip any file that is larger than 64K%@AE@%%@NL@%
- %@NL@%
- .IF WORD PTR fiFiles.len[2] != 0 %@AB@%; Error if high word isn't zero%@AE@%%@NL@%
- mov bCsrSta, 1 %@AB@%; Cursor hidden, position unchanged%@AE@%%@NL@%
- %@NL@%
- @ShowStr stMsg3 %@AB@%; Display error string and file name%@AE@%%@NL@%
- @Write fiFiles.FName, cx, 1%@NL@%
- %@NL@%
- .IF cFiles %@AB@%; If files remaining,%@AE@%%@NL@%
- @GetChar 0 %@AB@%; get a key%@AE@%%@NL@%
- .ENDIF%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Allocate dynamic memory for file buffer%@AE@%%@NL@%
- %@NL@%
- mov ax, WORD PTR fiFiles.Len[0] %@AB@%; Get length%@AE@%%@NL@%
- mov cbBuf, ax %@AB@%; Save%@AE@%%@NL@%
- mov offBuf, 0%@NL@%
- mov cl, 4 %@AB@%; Convert to paragraphs%@AE@%%@NL@%
- shr ax, cl%@NL@%
- inc ax %@AB@%; Zero adjust%@AE@%%@NL@%
- %@NL@%
- @GetBlock ax %@AB@%; Try to allocate 64K%@AE@%%@NL@%
- .IF carry? %@AB@%; Display error and quit if%@AE@%%@NL@%
- @ShowStr stMsg4 %@AB@%; request failed%@AE@%%@NL@%
- jmp Quit%@NL@%
- .ENDIF%@NL@%
- mov segBuf, ax %@AB@%; Save buffer segment%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Open file and read contents into buffer%@AE@%%@NL@%
- %@NL@%
- @OpenFile stFiles, 0 %@AB@%; Try to open response%@AE@%%@NL@%
- jc NoFile %@AB@%; If fail, get a new file%@AE@%%@NL@%
- mov hFileIn, ax %@AB@%; Save handle%@AE@%%@NL@%
- %@NL@%
- push ds%@NL@%
- @Read fpBuf, cbBuf, hFileIn %@AB@%; Read file%@AE@%%@NL@%
- pop ds%@NL@%
- .IF carry?%@NL@%
- jmp NoFile %@AB@%; If read error try again%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Search back for EOF marker and adjust if necessary%@AE@%%@NL@%
- %@NL@%
- mov di, cbBuf %@AB@%; Load file length%@AE@%%@NL@%
- dec di %@AB@%; and adjust%@AE@%%@NL@%
- mov es, segBuf%@NL@%
- std %@AB@%; Look backward for 255 characters%@AE@%%@NL@%
- mov cx, 0FFh%@NL@%
- .IF cx >= di%@NL@%
- mov cx, di%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- mov al, 1Ah %@AB@%; Search for EOF marker%@AE@%%@NL@%
- repne scasb%@NL@%
- cld%@NL@%
- .IF cx != 0 %@AB@%; If found:%@AE@%%@NL@%
- inc di %@AB@%; Adjust and save file size%@AE@%%@NL@%
- mov cbBuf, di%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Show a screen of text and allow commands%@AE@%%@NL@%
- %@NL@%
- INVOKE Show%@NL@%
- %@NL@%
- @CloseFile hFileIn %@AB@%; Yes? Close file%@AE@%%@NL@%
- @FreeBlock segBuf %@AB@%; Release buffer%@AE@%%@NL@%
- %@NL@%
- @GetNext%@NL@%
- %@NL@%
- .IF carry?%@NL@%
- dec cFiles%@NL@%
- .ENDIF%@NL@%
- .UNTIL !cFiles%@NL@%
- %@NL@%
- %@AB@%; Fall through to Quit%@AE@%%@NL@%
- %@NL@%
- Quit PROC%@NL@%
- %@NL@%
- cmp bCsrSta, 1 %@AB@%; Check cursor status%@AE@%%@NL@%
- jg csrvislast %@AB@%; 2 - Make cursor visible on last line%@AE@%%@NL@%
- je csrvis %@AB@%; 1 - Make cursor visible%@AE@%%@NL@%
- jmp csrasis %@AB@%; 0 - Leave cursor as is%@AE@%%@NL@%
- %@NL@%
- csrvislast:%@NL@%
- mov dx, yMax %@AB@%; Load last row and first column%@AE@%%@NL@%
- xchg dl, dh%@NL@%
- mov cx, dx %@AB@%; Make row the same%@AE@%%@NL@%
- mov dl, 79%@NL@%
- @Scroll 0, atInit %@AB@%; Clear last line to original color%@AE@%%@NL@%
- sub dl, dl %@AB@%; Column 0%@AE@%%@NL@%
- @SetCsrPos %@AB@%; Set cursor%@AE@%%@NL@%
- csrvis: %@AB@%; Fall through%@AE@%%@NL@%
- %@AB@%; Restore cursor attribute%@AE@%%@NL@%
- @SetCsrSize <BYTE PTR shCsr[1]>, <BYTE PTR shCsr[0]>%@NL@%
- %@NL@%
- csrasis:%@NL@%
- .IF fNewVid == 1%@NL@%
- @SetMode iMode %@AB@%; Restore video mode, page, and cursor%@AE@%%@NL@%
- @SetPage iPage%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .EXIT 0 %@AB@%; Quit%@AE@%%@NL@%
- %@NL@%
- Quit ENDP%@NL@%
- %@NL@%
- %@NL@%
- Show PROC%@NL@%
- %@NL@%
- %@AB@%; Display first page%@AE@%%@NL@%
- %@NL@%
- mov yCur, 1 %@AB@%; Reinitialize%@AE@%%@NL@%
- INVOKE Pager, %@AB@%; Start at 0%@AE@%%@NL@%
- 0%@NL@%
- %@NL@%
- %@AB@%; Handle keys%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- %@NL@%
- @GetChar 0, 0, 0 %@AB@%; Get a key%@AE@%%@NL@%
- %@NL@%
- .BREAK .IF al == 27 %@AB@%; If ESCAPE get out for next file%@AE@%%@NL@%
- %@NL@%
- %@AB@%; If null or E0 (for extended keyboard), it's an extended key%@AE@%%@NL@%
- .IF (al == 0) || (al == 0E0h)%@NL@%
- @GetChar 0, 0, 0 %@AB@%; Get extended code%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- push ds %@AB@%; ES = DS%@AE@%%@NL@%
- pop es%@NL@%
- mov di, OFFSET achKeys %@AB@%; Load address and length of key list%@AE@%%@NL@%
- mov cx, LENGTHOF achKeys + 1%@NL@%
- repne scasb %@AB@%; Find position and point to key%@AE@%%@NL@%
- sub di, OFFSET achKeys + 1%@NL@%
- shl di, 1 %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
- call afnKeys[di] %@AB@%; Call procedure%@AE@%%@NL@%
- .UNTIL 0%@NL@%
- %@NL@%
- ret%@NL@%
- Show ENDP%@NL@%
- %@NL@%
- HomeKey:%@NL@%
- mov offBuf, 0 %@AB@%; HOME - set position to 0%@AE@%%@NL@%
- mov yCur, 1%@NL@%
- INVOKE Pager, offBuf%@NL@%
- retn%@NL@%
- %@NL@%
- UpKey:%@NL@%
- INVOKE Pager, -1 %@AB@%; UP - scroll backward 1 line%@AE@%%@NL@%
- retn%@NL@%
- %@NL@%
- PgUpKey:%@NL@%
- mov ax, yMax %@AB@%; PGUP - Page back%@AE@%%@NL@%
- neg ax%@NL@%
- INVOKE Pager, ax%@NL@%
- retn%@NL@%
- %@NL@%
- EndKey:%@NL@%
- mov ax, cbBuf %@AB@%; END - Get last byte of file%@AE@%%@NL@%
- dec ax %@AB@%; Zero adjust%@AE@%%@NL@%
- mov offBuf, ax %@AB@%; Make it the file position%@AE@%%@NL@%
- mov yCur, -1 %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
- mov ax, yMax %@AB@%; Page back%@AE@%%@NL@%
- neg ax%@NL@%
- INVOKE Pager, ax%@NL@%
- retn%@NL@%
- %@NL@%
- DownKey:%@NL@%
- INVOKE Pager, 1 %@AB@%; DOWN - scroll forward 1 line%@AE@%%@NL@%
- retn%@NL@%
- %@NL@%
- PgDnKey:%@NL@%
- INVOKE Pager, yMax %@AB@%; PGDN - page forward%@AE@%%@NL@%
- retn%@NL@%
- %@NL@%
- UnknownKey:%@NL@%
- retn %@AB@%; Ignore unknown key%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GetVid - Gets the video mode and sets related global variables.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Number of lines in current mode (25, 43, or 50)%@AE@%%@NL@%
- %@NL@%
- GetVid PROC%@NL@%
- %@NL@%
- %@AB@%; Adjust for current mode and and video adapter%@AE@%%@NL@%
- %@NL@%
- INVOKE IsEGA %@AB@%; EGA (or VGA)?%@AE@%%@NL@%
- .IF ax != 0 %@AB@%; If 0 must be CGA or MA%@AE@%%@NL@%
- mov yMax, ax %@AB@%; Load rows%@AE@%%@NL@%
- dec fCGA %@AB@%; Not CGA%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- @GetMode %@AB@%; Get video mode%@AE@%%@NL@%
- mov iMode, al %@AB@%; Save initial mode and page%@AE@%%@NL@%
- mov iPage, bh%@NL@%
- mov dl, al %@AB@%; Work on copy%@AE@%%@NL@%
- cmp dl, 7 %@AB@%; Is it mono 7?%@AE@%%@NL@%
- je loadmono %@AB@%; Yes? Set mono%@AE@%%@NL@%
- cmp dl, 15 %@AB@%; Is it mono 15?%@AE@%%@NL@%
- jne graphchk %@AB@%; No? Check graphics%@AE@%%@NL@%
- loadmono:%@NL@%
- mov segVid, SEG_MONO %@AB@%; Load mono address%@AE@%%@NL@%
- mov atSta, STAT_BW %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
- mov atScr, SCRN_BW %@AB@%; and screen background%@AE@%%@NL@%
- dec fCGA %@AB@%; Not CGA%@AE@%%@NL@%
- cmp al, 15 %@AB@%; Is it mono 15?%@AE@%%@NL@%
- jne exit %@AB@%; No? Done%@AE@%%@NL@%
- mov dl, 7 %@AB@%; Yes? Set standard mono%@AE@%%@NL@%
- jmp chmode%@NL@%
- graphchk:%@NL@%
- cmp dl, 7 %@AB@%; 7 or higher?%@AE@%%@NL@%
- jg color %@AB@%; 8 to 14 are color (7 and 15 done)%@AE@%%@NL@%
- cmp dl, 4 %@AB@%; 4 or higher?%@AE@%%@NL@%
- jg bnw %@AB@%; 5 and 6 are probably black and white%@AE@%%@NL@%
- je color %@AB@%; 4 is color%@AE@%%@NL@%
- test dl, 1 %@AB@%; Even?%@AE@%%@NL@%
- jz bnw %@AB@%; 0 and 2 are black and white%@AE@%%@NL@%
- color: %@AB@%; 1 and 3 are color%@AE@%%@NL@%
- cmp dl, 3 %@AB@%; 3?%@AE@%%@NL@%
- je exit %@AB@%; Yes? Done%@AE@%%@NL@%
- mov dl, 3 %@AB@%; Change mode to 3%@AE@%%@NL@%
- jmp chmode%@NL@%
- bnw:%@NL@%
- mov atSta, STAT_BW %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
- mov atScr, SCRN_BW %@AB@%; and screen background%@AE@%%@NL@%
- cmp dl, 2 %@AB@%; 2?%@AE@%%@NL@%
- je exit %@AB@%; Yes? Done%@AE@%%@NL@%
- mov dl, 2 %@AB@%; Make it 2%@AE@%%@NL@%
- chmode:%@NL@%
- @SetMode dl %@AB@%; Set video mode%@AE@%%@NL@%
- @SetPage 0 %@AB@%; Set video page%@AE@%%@NL@%
- mov fNewVid, 1 %@AB@%; Set flag%@AE@%%@NL@%
- exit:%@NL@%
- @GetCsr %@AB@%; Get cursor shape (ignore position)%@AE@%%@NL@%
- mov shCsr, cx %@AB@%; Save shape%@AE@%%@NL@%
- @GetCharAtr %@AB@%; Read the cell at the cursor%@AE@%%@NL@%
- mov atInit, ah %@AB@%; Save attribute%@AE@%%@NL@%
- @SetCsrSize 20h, 20h %@AB@%; Turn off cursor (invisible shape)%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- GetVid ENDP%@NL@%
- %@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%SHOWUTIL.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\SHOW\SHOWUTIL.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%;* SHOWUTIL.ASM - Module containing routines used by both the real and%@AE@%%@NL@%
- %@AB@%;* protected mode versions of SHOW. Works with main module SHOWR.ASM or%@AE@%%@NL@%
- %@AB@%;* SHOWP.ASM and with PAGERR.ASM or PAGERP.ASM.%@AE@%%@NL@%
- %@NL@%
- TITLE ShowUtil%@NL@%
- .MODEL small, pascal%@NL@%
- %@NL@%
- INCLUDE show.inc%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* GetNamePos - Given a file specification potentially including file name,%@AE@%%@NL@%
- %@AB@%;* directory, and/or drive, return the position of the first character%@AE@%%@NL@%
- %@AB@%;* of the file name.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: pchSpec - address of file spec%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Near pointer to position of name portion of file spec%@AE@%%@NL@%
- %@NL@%
- GetNamePos PROC USES di si,%@NL@%
- pchSpec:PTR BYTE%@NL@%
- %@NL@%
- push ds%@NL@%
- pop es%@NL@%
- mov di, pchSpec %@AB@%; Load address of file name%@AE@%%@NL@%
- mov si, di %@AB@%; Save copy%@AE@%%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Use CX as count%@AE@%%@NL@%
- sub dx, dx %@AB@%; Use DX as found flag%@AE@%%@NL@%
- sub ax, ax %@AB@%; Search for null%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- .IF BYTE PTR es:[di] == '\' %@AB@%; For each backslash:%@AE@%%@NL@%
- mov si, di %@AB@%; Save position%@AE@%%@NL@%
- inc dx %@AB@%; Set flag to true%@AE@%%@NL@%
- .ENDIF%@NL@%
- inc cx %@AB@%; Count it%@AE@%%@NL@%
- scasb %@AB@%; Get next character%@AE@%%@NL@%
- .UNTIL zero?%@NL@%
- %@NL@%
- .IF dx != 0 %@AB@%; If found backslash:%@AE@%%@NL@%
- mov ax, si %@AB@%; Return position in AX%@AE@%%@NL@%
- dec ax%@NL@%
- %@NL@%
- .ELSE %@AB@%; Else search for colon%@AE@%%@NL@%
- mov di, si %@AB@%; Restore start of name%@AE@%%@NL@%
- mov ax, ":" %@AB@%; Search for colon%@AE@%%@NL@%
- repne scasb%@NL@%
- %@NL@%
- .IF zero? %@AB@%; If colon:%@AE@%%@NL@%
- mov ax, di %@AB@%; Return position in DX:AX%@AE@%%@NL@%
- .ELSE %@AB@%; Else:%@AE@%%@NL@%
- mov ax, si %@AB@%; Return original address%@AE@%%@NL@%
- .ENDIF%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- GetNamePos ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GoBack - Purpose Searches backward through buffer%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: CX has number of lines%@AE@%%@NL@%
- %@AB@%;* ES:DI has buffer position%@AE@%%@NL@%
- %@AB@%;* AL has 10 (line feed character)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Modifies: Updates yCur and offBuf%@AE@%%@NL@%
- %@NL@%
- GoBack PROC%@NL@%
- %@NL@%
- neg cx %@AB@%; Make count positive%@AE@%%@NL@%
- mov dx, cx %@AB@%; Save a copy%@AE@%%@NL@%
- inc cx %@AB@%; One extra to go up one%@AE@%%@NL@%
- .IF di == 0 %@AB@%; If start of file, done%@AE@%%@NL@%
- ret%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push cx %@AB@%; Save count%@AE@%%@NL@%
- mov cx, 0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- .IF cx >= SWORD PTR di %@AB@%; If near start of buffer,%@AE@%%@NL@%
- mov cx, di %@AB@%; search only to start%@AE@%%@NL@%
- .ENDIF%@NL@%
- std %@AB@%; Go backward%@AE@%%@NL@%
- repne scasb %@AB@%; Find last previous LF%@AE@%%@NL@%
- cld %@AB@%; Go foreward%@AE@%%@NL@%
- jcxz atstart %@AB@%; If not found, must be at start%@AE@%%@NL@%
- pop cx%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- .IF yCur == 0FFFFh %@AB@%; IF end of file flag:%@AE@%%@NL@%
- add di, 2 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
- mov offBuf, di %@AB@%; Save position%@AE@%%@NL@%
- call EndCount %@AB@%; Count back to get line number%@AE@%%@NL@%
- mov yCur, ax %@AB@%; Store line count%@AE@%%@NL@%
- ret%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- sub yCur, dx %@AB@%; Calculate line number%@AE@%%@NL@%
- jg positive%@NL@%
- mov yCur, 1 %@AB@%; Set to 1 if negative%@AE@%%@NL@%
- positive:%@NL@%
- add di, 2 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
- mov offBuf, di %@AB@%; Save position%@AE@%%@NL@%
- ret%@NL@%
- atstart:%@NL@%
- pop cx%@NL@%
- sub di, di %@AB@%; Load start of file%@AE@%%@NL@%
- mov yCur, 1 %@AB@%; Line 1%@AE@%%@NL@%
- mov offBuf, di %@AB@%; Save position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GoBack ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* GoForeward - Skips forward through a buffer of text a specified%@AE@%%@NL@%
- %@AB@%;* number of lines.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: CX - number of text lines to skip%@AE@%%@NL@%
- %@AB@%;* ES:DI - starting buffer position%@AE@%%@NL@%
- %@AB@%;* AL has 10 (line feed character)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Modifes: yCur, offBuf, bx, cx, di%@AE@%%@NL@%
- %@NL@%
- GoForeward PROC%@NL@%
- %@NL@%
- cld %@AB@%; Go forward%@AE@%%@NL@%
- mov dx, cx %@AB@%; Copy count%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push cx %@AB@%; Save count%@AE@%%@NL@%
- mov cx, 0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- mov bx, cbBuf %@AB@%; Get end of file%@AE@%%@NL@%
- %@NL@%
- sub bx, di %@AB@%; Characters to end of file%@AE@%%@NL@%
- .IF cx >= bx %@AB@%; If less than maximum per line:%@AE@%%@NL@%
- mov cx, bx %@AB@%; Adjust%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- repne scasb %@AB@%; Find next LF%@AE@%%@NL@%
- pop cx%@NL@%
- %@NL@%
- %@NL@%
- .IF !zero? || (di >= cbBuf) %@AB@%; If LF not found or beyond end:%@AE@%%@NL@%
- mov di, offBuf %@AB@%; Restore original position%@AE@%%@NL@%
- ret %@AB@%; and quit%@AE@%%@NL@%
- .ENDIF%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- add yCur, dx %@AB@%; Calulate line number%@AE@%%@NL@%
- mov offBuf, di %@AB@%; Save position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- GoForeward ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* EndCount - Skips backward through a buffer of text, counting each%@AE@%%@NL@%
- %@AB@%;* text line.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: ES:DI - buffer position (end of file)%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Number of lines counted%@AE@%%@NL@%
- %@NL@%
- EndCount PROC USES di dx cx%@NL@%
- %@NL@%
- std %@AB@%; Backward%@AE@%%@NL@%
- mov al, 13 %@AB@%; Search for CR%@AE@%%@NL@%
- mov dx, -1 %@AB@%; Initialize (first will inc to 0)%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- inc dx %@AB@%; Adjust count%@AE@%%@NL@%
- mov cx, 0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- %@NL@%
- .IF SWORD PTR cx >= di %@AB@%; If near start of buffer:%@AE@%%@NL@%
- mov cx, di %@AB@%; Search only to start%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- repne scasb %@AB@%; Find last previous cr%@AE@%%@NL@%
- .UNTIL !zero? %@AB@%; If not found, must be at start%@AE@%%@NL@%
- %@NL@%
- mov ax, dx %@AB@%; Return count%@AE@%%@NL@%
- cld %@AB@%; Forward%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- EndCount ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* BinToStr - Converts an unsigned integer to a string. User is%@AE@%%@NL@%
- %@AB@%;* responsible for providing a large enough buffer. The string is%@AE@%%@NL@%
- %@AB@%;* not null-terminated.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: i - Integer to be converted%@AE@%%@NL@%
- %@AB@%;* pch - Pointer to character buffer to receive string%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: Number of character in string.%@AE@%%@NL@%
- %@NL@%
- BinToStr PROC,%@NL@%
- i:WORD,%@NL@%
- pch:PTR BYTE%@NL@%
- %@NL@%
- mov ax, i%@NL@%
- mov di, pch%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Clear counter%@AE@%%@NL@%
- mov bx, 10 %@AB@%; Divide by 10%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Convert and save on stack backwards%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- sub dx, dx %@AB@%; Clear top%@AE@%%@NL@%
- div bx %@AB@%; Divide to get last digit as remainder%@AE@%%@NL@%
- add dl, "0" %@AB@%; Convert to ASCII%@AE@%%@NL@%
- push dx %@AB@%; Save on stack%@AE@%%@NL@%
- .UNTILCXZ ax == 0 %@AB@%; Until quotient is 0%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Take off the stack and store forward%@AE@%%@NL@%
- %@NL@%
- neg cx %@AB@%; Negate and save count%@AE@%%@NL@%
- mov dx, cx%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- pop ax %@AB@%; Get character%@AE@%%@NL@%
- stosb %@AB@%; Store it%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- mov ax, dx %@AB@%; Return digit count%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- BinToStr ENDP%@NL@%
- %@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%SNAP.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM6\TSR\SNAP.ASM%@AE@%%@NL@%
- %@NL@%
- .MODEL small, pascal, os_dos%@NL@%
- .DOSSEG%@NL@%
- INCLUDE demo.inc%@NL@%
- INCLUDE tsr.inc%@NL@%
- %@NL@%
- OpenBox PROTO%@NL@%
- CloseBox PROTO%@NL@%
- %@NL@%
- .STACK%@NL@%
- .DATA%@NL@%
- %@NL@%
- DEFAULT_COLR EQU 1Eh %@AB@%; Default = white on blue (color)%@AE@%%@NL@%
- DEFAULT_MONO EQU 70h %@AB@%; Default = reverse video (mono)%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Set ALT + LEFT SHIFT + S as hot key combination. To set multiple shift%@AE@%%@NL@%
- %@AB@%; keys, OR the appropriate values together for the shift value (HOT_SHIFT).%@AE@%%@NL@%
- %@NL@%
- HOT_SCAN EQU 1Fh %@AB@%; Hot key scan code (S)%@AE@%%@NL@%
- HOT_SHIFT EQU shAlt OR shLeft %@AB@%; Shift value (ALT + LEFT SHIFT)%@AE@%%@NL@%
- HOT_MASK EQU (shIns OR shCaps OR shNum OR shScroll) XOR 0FFh%@NL@%
- %@NL@%
- ROW1 EQU 9 %@AB@%; Query box begins on row 9%@AE@%%@NL@%
- ROW2 EQU 14 %@AB@%; and ends on row 14%@AE@%%@NL@%
- HEIGHT EQU ROW2 - ROW1 + 1 %@AB@%; Number of rows in query box%@AE@%%@NL@%
- %@NL@%
- Box BYTE '┌──────────────────────────────────────┐', 0%@NL@%
- BYTE '│ Enter file name │', 0%@NL@%
- BYTE '│ (press Esc to cancel): │', 0%@NL@%
- BYTE '│ │', 0%@NL@%
- BYTE '│ │', 0%@NL@%
- boxend BYTE '└──────────────────────────────────────┘', 0%@NL@%
- LEN EQU (LENGTHOF boxend) - 1%@NL@%
- %@NL@%
- OldPos WORD ? %@AB@%; Original cursor position%@AE@%%@NL@%
- Handle WORD ? %@AB@%; File handle number%@AE@%%@NL@%
- FilSpec BYTE (LEN - 3) DUP(0) %@AB@%; ASCIIZ string for file spec%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Fill attribute for prompt box. This is changed by running SNAP with%@AE@%%@NL@%
- %@AB@%; the /Cx switch, where x = new display attribute in hexadecimal. For%@AE@%%@NL@%
- %@AB@%; example, to change the color to yellow on brown for a color monitor,%@AE@%%@NL@%
- %@AB@%; enter%@AE@%%@NL@%
- %@AB@%; SNAP /C6E%@AE@%%@NL@%
- %@AB@%; where the first digit specifies the background color and the second%@AE@%%@NL@%
- %@AB@%; digit the foreground color. Typical values for x on a monochrome%@AE@%%@NL@%
- %@AB@%; system are%@AE@%%@NL@%
- %@AB@%; 07 normal 70 reverse video%@AE@%%@NL@%
- %@AB@%; 0F high intensity 78 reverse video, high intensity%@AE@%%@NL@%
- %@NL@%
- BoxFill BYTE DEFAULT_MONO %@AB@%; Assume monochrome%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Hold contains the screen text and attributes replaced by the query box.%@AE@%%@NL@%
- %@AB@%; Buffer holds text captured from the screen, with room for 50 rows of 82%@AE@%%@NL@%
- %@AB@%; characters, including carriage return/linefeed. To change Buffer's%@AE@%%@NL@%
- %@AB@%; capacity, replace the dimensions with r * (c + 2) DUP(?), where r and%@AE@%%@NL@%
- %@AB@%; c are row and column count respectively.%@AE@%%@NL@%
- %@NL@%
- Hold BYTE (HEIGHT * LEN) + 3 DUP(?)%@NL@%
- Buffer BYTE 50 * 82 DUP(?)%@NL@%
- %@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%;* Snap - Main procedure for resident program. Called from the Activate%@AE@%%@NL@%
- %@AB@%;* procedure when TSR is invoked by the proper key combination.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS, ES = @data%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Snap PROC FAR%@NL@%
- %@NL@%
- INVOKE GetVidConfig %@AB@%; Get video information%@AE@%%@NL@%
- %@NL@%
- mov al, vconfig.mode %@AB@%; AL = video mode%@AE@%%@NL@%
- .IF (al <= 3) || (al == 7) %@AB@%; If text mode:%@AE@%%@NL@%
- %@NL@%
- INVOKE GetCurPos %@AB@%; Get original cursor coordinates%@AE@%%@NL@%
- mov OldPos, ax %@AB@%; and store them%@AE@%%@NL@%
- %@NL@%
- INVOKE OpenBox %@AB@%; Display query box%@AE@%%@NL@%
- %@NL@%
- mov bl, vconfig.cols %@AB@%; Calculate column%@AE@%%@NL@%
- sub bl, LEN%@NL@%
- shr bl, 1%@NL@%
- add bl, 3%@NL@%
- %@NL@%
- INVOKE StrInput, %@AB@%; Request input%@AE@%%@NL@%
- ROW1 + 4, %@AB@%; Row%@AE@%%@NL@%
- bl, %@AB@%; Column%@AE@%%@NL@%
- LEN - 4, %@AB@%; Maximum string%@AE@%%@NL@%
- ADDR FilSpec %@AB@%; Address of string buffer%@AE@%%@NL@%
- %@NL@%
- push ax %@AB@%; Save terminating keypress%@AE@%%@NL@%
- call CloseBox %@AB@%; Restore screen to original state%@AE@%%@NL@%
- pop ax %@AB@%; Recover key%@AE@%%@NL@%
- .IF al != ESCAPE %@AB@%; If Esc key not pressed:%@AE@%%@NL@%
- call OpenFile %@AB@%; Open (or create) file%@AE@%%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If okay:%@AE@%%@NL@%
- call Capture %@AB@%; Write screen to file%@AE@%%@NL@%
- .ELSE%@NL@%
- mov ax, 0E07h %@AB@%; Write bell character%@AE@%%@NL@%
- int 10h %@AB@%; (ASCII 7) to console%@AE@%%@NL@%
- .ENDIF %@AB@%; End file-okay test%@AE@%%@NL@%
- .ENDIF %@AB@%; End ESCAPE test%@AE@%%@NL@%
- %@NL@%
- mov ax, OldPos %@AB@%; Recover original cursor position%@AE@%%@NL@%
- mov bl, ah%@NL@%
- %@NL@%
- INVOKE SetCurPos, %@AB@%; Restore cursor%@AE@%%@NL@%
- bx, ax %@AB@%; Pass cursor row and column%@AE@%%@NL@%
- %@NL@%
- .ENDIF %@AB@%; End text mode test%@AE@%%@NL@%
- %@NL@%
- retf %@AB@%; Far return to Activate procedure%@AE@%%@NL@%
- %@NL@%
- Snap ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* OpenBox - Saves portion of screen to Hold buffer, then opens a box.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- OpenBox PROC%@NL@%
- %@NL@%
- mov dh, ROW1 %@AB@%; DH = top screen row for box%@AE@%%@NL@%
- mov dl, vconfig.cols%@NL@%
- sub dl, LEN%@NL@%
- shr dl, 1 %@AB@%; DL = left col for centered box%@AE@%%@NL@%
- push dx %@AB@%; Save coords%@AE@%%@NL@%
- sub ch, ch%@NL@%
- mov cl, dh %@AB@%; CX = row%@AE@%%@NL@%
- sub dh, dh %@AB@%; DX = column%@AE@%%@NL@%
- GetVidOffset cx, dx%@NL@%
- mov si, ax %@AB@%; Get video offset in SI%@AE@%%@NL@%
- mov bx, HEIGHT %@AB@%; BX = number of window rows%@AE@%%@NL@%
- mov cx, LEN %@AB@%; CX = number of columns%@AE@%%@NL@%
- %@NL@%
- push ds%@NL@%
- pop es%@NL@%
- mov di, OFFSET Hold %@AB@%; Point ES:DI to hold buffer%@AE@%%@NL@%
- mov ax, si%@NL@%
- stosw %@AB@%; Copy video offset to buffer%@AE@%%@NL@%
- mov ax, bx%@NL@%
- stosw %@AB@%; Number of rows to buffer%@AE@%%@NL@%
- mov ax, cx%@NL@%
- stosw %@AB@%; Number of cols to buffer%@AE@%%@NL@%
- mov al, vconfig.cols%@NL@%
- shl ax, 1 %@AB@%; AX = number of video cells/row%@AE@%%@NL@%
- mov ds, vconfig.sgmnt %@AB@%; DS = video segment%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push si %@AB@%; Save ptr to start of line%@AE@%%@NL@%
- push cx %@AB@%; and number of columns%@AE@%%@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter:%@AE@%%@NL@%
- INVOKE DisableCga %@AB@%; Disable video%@AE@%%@NL@%
- .ENDIF%@NL@%
- rep movsw %@AB@%; Copy one row to buffer%@AE@%%@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter:%@AE@%%@NL@%
- INVOKE EnableCga %@AB@%; Reenable CGA video%@AE@%%@NL@%
- .ENDIF%@NL@%
- pop cx %@AB@%; Recover number of columns%@AE@%%@NL@%
- pop si %@AB@%; and start of line%@AE@%%@NL@%
- add si, ax %@AB@%; Point to start of next line%@AE@%%@NL@%
- dec bx %@AB@%; Decrement row counter%@AE@%%@NL@%
- .UNTIL zero? %@AB@%; Loop while rows remain%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Screen contents (including display attributes) are now copied to buffer.%@AE@%%@NL@%
- %@AB@%; Next open window, overwriting the screen portion just saved.%@AE@%%@NL@%
- %@NL@%
- push es%@NL@%
- pop ds %@AB@%; Restore DS%@AE@%%@NL@%
- %@NL@%
- mov ax, 0600h %@AB@%; Scroll service%@AE@%%@NL@%
- mov bh, BoxFill %@AB@%; BH = fill attribute%@AE@%%@NL@%
- pop cx %@AB@%; CX = row/col for upper left%@AE@%%@NL@%
- mov dh, ROW2%@NL@%
- mov dl, cl%@NL@%
- add dl, LEN%@NL@%
- dec dl %@AB@%; DX = row/col for lower right%@AE@%%@NL@%
- int 10h %@AB@%; Blank window area on screen%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write box frame and text to screen%@AE@%%@NL@%
- %@NL@%
- mov dx, cx %@AB@%; DX = row/col for upper left%@AE@%%@NL@%
- mov si, OFFSET Box %@AB@%; Point to text%@AE@%%@NL@%
- mov cx, HEIGHT %@AB@%; Number of rows in box%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push dx %@AB@%; Save coordinates%@AE@%%@NL@%
- sub bh, bh%@NL@%
- mov bl, dh %@AB@%; BX = row%@AE@%%@NL@%
- sub dh, dh %@AB@%; DX = column%@AE@%%@NL@%
- INVOKE StrWrite, bx, dx, si %@AB@%; Display one line of box%@AE@%%@NL@%
- pop dx %@AB@%; Recover coordinates%@AE@%%@NL@%
- inc dh %@AB@%; Next screen row%@AE@%%@NL@%
- add si, LEN %@AB@%; Point to next line in box%@AE@%%@NL@%
- inc si%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- OpenBox ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* CloseBox - Restores the original screen text to close the window%@AE@%%@NL@%
- %@AB@%;* previously opened by the OpenBox procedure%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- CloseBox PROC%@NL@%
- %@NL@%
- mov si, OFFSET Hold%@NL@%
- lodsw%@NL@%
- mov di, ax %@AB@%; DI = video offset of window%@AE@%%@NL@%
- lodsw%@NL@%
- mov bx, ax %@AB@%; BX = number of window rows%@AE@%%@NL@%
- lodsw%@NL@%
- mov cx, ax %@AB@%; CX = number of columns%@AE@%%@NL@%
- %@NL@%
- mov al, vconfig.cols%@NL@%
- shl ax, 1 %@AB@%; AX = number of video cells/row%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- push di %@AB@%; Save ptr to start of line%@AE@%%@NL@%
- push cx %@AB@%; and number of columns%@AE@%%@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter:%@AE@%%@NL@%
- INVOKE DisableCga %@AB@%; Disable video%@AE@%%@NL@%
- .ENDIF%@NL@%
- rep movsw %@AB@%; Copy one row to buffer%@AE@%%@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA adapter:%@AE@%%@NL@%
- INVOKE EnableCga %@AB@%; Reenable CGA video%@AE@%%@NL@%
- .ENDIF%@NL@%
- pop cx %@AB@%; Recover number of columns%@AE@%%@NL@%
- pop di %@AB@%; and start of line%@AE@%%@NL@%
- add di, ax %@AB@%; Point to start of next line%@AE@%%@NL@%
- dec bx %@AB@%; Decrement row counter%@AE@%%@NL@%
- .UNTIL zero? %@AB@%; Loop while rows remain%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- %@NL@%
- CloseBox ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* OpenFile - Opens or creates specified file. Resets file pointer to%@AE@%%@NL@%
- %@AB@%;* end of file so that subsequent text is appended to bottom of file.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: DS:SI = Pointer to file spec%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- OpenFile PROC%@NL@%
- %@NL@%
- mov ax, 3D01h %@AB@%; Request DOS to open file%@AE@%%@NL@%
- mov dx, OFFSET FilSpec %@AB@%; DS:DX points to file specification%@AE@%%@NL@%
- int 21h %@AB@%; Open File%@AE@%%@NL@%
- .IF carry? %@AB@%; If it doesn't exist:%@AE@%%@NL@%
- mov ah, 3Ch %@AB@%; Request create file%@AE@%%@NL@%
- sub cx, cx %@AB@%; with normal attributes%@AE@%%@NL@%
- int 21h %@AB@%; Create File%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- .IF !carry? %@AB@%; If no error:%@AE@%%@NL@%
- mov Handle, ax %@AB@%; Store file handle%@AE@%%@NL@%
- mov bx, ax%@NL@%
- mov ax, 4202h %@AB@%; Request DOS to reset file pointer%@AE@%%@NL@%
- sub cx, cx %@AB@%; to end of file%@AE@%%@NL@%
- sub dx, dx%@NL@%
- int 21h %@AB@%; Set File Pointer%@AE@%%@NL@%
- .ENDIF%@NL@%
- ret%@NL@%
- %@NL@%
- OpenFile ENDP%@NL@%
- %@NL@%
- %@NL@%
- %@AB@%;* Capture - Copies screen text to Buffer, then writes Buffer to file.%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Uses: vconfig - Video configuration structure%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Params: None%@AE@%%@NL@%
- %@AB@%;*%@AE@%%@NL@%
- %@AB@%;* Return: None%@AE@%%@NL@%
- %@NL@%
- Capture PROC%@NL@%
- %@NL@%
- mov es, vconfig.sgmnt %@AB@%; ES points to video segment address%@AE@%%@NL@%
- sub si, si %@AB@%; ES:SI points to 1st video byte%@AE@%%@NL@%
- sub bx, bx %@AB@%; BX = index to capture buffer%@AE@%%@NL@%
- mov dx, 3DAh %@AB@%; DX = address of CGA status register%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- sub ch, ch%@NL@%
- mov cl, vconfig.cols %@AB@%; CX = number of columns in line%@AE@%%@NL@%
- mov di, cx%@NL@%
- dec di%@NL@%
- shl di, 1 %@AB@%; ES:DI points to video byte for%@AE@%%@NL@%
- add di, si %@AB@%; last column in line%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA:%@AE@%%@NL@%
- cli %@AB@%; Disallow interruptions%@AE@%%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Read current video status%@AE@%%@NL@%
- .UNTIL !(al & 1) %@AB@%; until horizontal retrace done%@AE@%%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Read video status%@AE@%%@NL@%
- .UNTIL al & 1 %@AB@%; until horizontal retrace starts%@AE@%%@NL@%
- .ENDIF %@AB@%; End CGA retrace check%@AE@%%@NL@%
- %@NL@%
- mov al, es:[di] %@AB@%; Get screen char, working backward%@AE@%%@NL@%
- sti %@AB@%; Reenable interrupts in case CGA%@AE@%%@NL@%
- sub di, 2 %@AB@%; DI points to next character%@AE@%%@NL@%
- .UNTILCXZ (al != ' ') %@AB@%; Scan for last non-blank character%@AE@%%@NL@%
- %@NL@%
- .IF !zero? %@AB@%; If non-blank char found:%@AE@%%@NL@%
- inc cx %@AB@%; Adjust column counter%@AE@%%@NL@%
- mov di, si %@AB@%; ES:DI points to start of line%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- .IF vconfig.adapter == CGA %@AB@%; If CGA:%@AE@%%@NL@%
- cli %@AB@%; Disallow interruptions%@AE@%%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Read current video status%@AE@%%@NL@%
- .UNTIL !(al & 1) %@AB@%; until horizontal retrace done%@AE@%%@NL@%
- .REPEAT%@NL@%
- in al, dx %@AB@%; Read video status%@AE@%%@NL@%
- .UNTIL al & 1 %@AB@%; until horizontal retrace starts%@AE@%%@NL@%
- .ENDIF %@AB@%; End CGA retrace check%@AE@%%@NL@%
- %@NL@%
- mov al, es:[di] %@AB@%; Get character, working forward%@AE@%%@NL@%
- sti%@NL@%
- add di, 2 %@AB@%; DI points to next character%@AE@%%@NL@%
- mov Buffer[bx], al %@AB@%; Copy to buffer%@AE@%%@NL@%
- inc bx%@NL@%
- .UNTILCXZ%@NL@%
- .ENDIF %@AB@%; End check for non-blank char%@AE@%%@NL@%
- %@NL@%
- mov WORD PTR Buffer[bx], CRLF%@AB@%; Finish line with return/line feed%@AE@%%@NL@%
- add bx, 2%@NL@%
- mov al, vconfig.cols%@NL@%
- sub ah, ah%@NL@%
- shl ax, 1%@NL@%
- add si, ax %@AB@%; SI points to start of next line%@AE@%%@NL@%
- dec vconfig.rows %@AB@%; Decrement row count%@AE@%%@NL@%
- .UNTIL sign? %@AB@%; Repeat for next screen row%@AE@%%@NL@%
- %@NL@%
- mov ah, 40h %@AB@%; Request DOS Function 40h%@AE@%%@NL@%
- mov cx, bx %@AB@%; CX = number of bytes to write%@AE@%%@NL@%
- mov bx, Handle %@AB@%; BX = file handle%@AE@%%@NL@%
- mov dx, OFFSET Buffer %@AB@%; DS:DX points to buffer%@AE@%%@NL@%
- int 21h %@AB@%; Write to File%@AE@%%@NL@%
- .IF (ax != cx) %@AB@%; If number of bytes written !=%@AE@%%@NL@%
- stc %@AB@%; number requested, set carry%@AE@%%@NL@%
- .ENDIF %@AB@%; flag to indicate failure%@AE@%%@NL@%
- %@NL@%
- pushf %@AB@%; Save carry flag%@AE@%%@NL@%
- mov ah, 3Eh %@AB@%; Request DOS Function 3Eh%@AE@%%@NL@%
- int 21h %@AB@%; Close File%@AE@%%@NL@%
- popf %@AB@%; Recover carry%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- Capture ENDP%@NL@%
- %@NL@%
- %@NL@%
- @CurSeg ENDS%@NL@%
- %@NL@%
- %@AB@%;* INSTALLATION SECTION - The following code and data are used only%@AE@%%@NL@%
- %@AB@%;* during SNAP's installation phase. When the program terminates%@AE@%%@NL@%
- %@AB@%;* through Function 31h, the above code and data remain resident;%@AE@%%@NL@%
- %@AB@%;* memory occupied by the following code and data segments is returned%@AE@%%@NL@%
- %@AB@%;* to the operating system.%@AE@%%@NL@%
- %@NL@%
- DGROUP GROUP INSTALLCODE, INSTALLDATA%@NL@%
- %@NL@%
- INSTALLDATA SEGMENT WORD PUBLIC 'DATA2'%@NL@%
- %@NL@%
- IDstr BYTE 'SNAP DEMO TSR', 0 %@AB@%; Multiplex identifier string%@AE@%%@NL@%
- %@NL@%
- INSTALLDATA ENDS%@NL@%
- %@NL@%
- INSTALLCODE SEGMENT PARA PUBLIC 'CODE2'%@NL@%
- ASSUME ds:@data%@NL@%
- %@NL@%
- Begin PROC NEAR%@NL@%
- %@NL@%
- mov ax, DGROUP%@NL@%
- mov ds, ax %@AB@%; Initialize DS%@AE@%%@NL@%
- mov ah, 15%@NL@%
- int 10h %@AB@%; Get Video Mode%@AE@%%@NL@%
- .IF al != 7 %@AB@%; If not default monochrome:%@AE@%%@NL@%
- mov BoxFill, DEFAULT_COLR %@AB@%; Reset to default color value%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; Before calling any of the TSR procedures, initialize global data%@AE@%%@NL@%
- %@NL@%
- INVOKE InitTsr, %@AB@%; Initialize data%@AE@%%@NL@%
- es, %@AB@%; Segment of PSP%@AE@%%@NL@%
- ADDR IDstr, %@AB@%; Far address of multiplex ID string%@AE@%%@NL@%
- ADDR BoxFill %@AB@%; Far address of memory shared%@AE@%%@NL@%
- %@AB@%; with multiplex handler%@AE@%%@NL@%
- .IF ax == WRONG_DOS %@AB@%; If DOS version less than 2.0:%@AE@%%@NL@%
- jmp exit %@AB@%; Exit with message%@AE@%%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; This section gets the command line argument to determine task:%@AE@%%@NL@%
- %@AB@%; No argument = install%@AE@%%@NL@%
- %@AB@%; /D or -D = deinstall%@AE@%%@NL@%
- %@AB@%; /Cx or -Cx = change box fill attribute to value x%@AE@%%@NL@%
- %@NL@%
- mov al, 'd' %@AB@%; Search command line for%@AE@%%@NL@%
- call GetOptions %@AB@%; /D or -D argument%@AE@%%@NL@%
- cmp ax, NO_ARGUMENT %@AB@%; No argument?%@AE@%%@NL@%
- je installtsr %@AB@%; If so, try to install%@AE@%%@NL@%
- cmp ax, OK_ARGUMENT %@AB@%; /D argument found?%@AE@%%@NL@%
- je deinstalltsr %@AB@%; If so, try to deinstall%@AE@%%@NL@%
- mov al, 'c' %@AB@%; Else search command line for%@AE@%%@NL@%
- call GetOptions %@AB@%; /C or -C argument%@AE@%%@NL@%
- cmp ax, BAD_ARGUMENT %@AB@%; If neither /D or /C arguments,%@AE@%%@NL@%
- je exit %@AB@%; quit with error message%@AE@%%@NL@%
- %@NL@%
- %@AB@%; This section changes the fill attribute of SNAP's prompt box. It converts%@AE@%%@NL@%
- %@AB@%; to binary the two-digit hex number following the /C argument, calls the%@AE@%%@NL@%
- %@AB@%; multiplex handler to find the address of the attribute variable stored in%@AE@%%@NL@%
- %@AB@%; shared memory, then resets the attribute to the new value. It does not%@AE@%%@NL@%
- %@AB@%; verify that the value specified in the command line is a valid two-digit%@AE@%%@NL@%
- %@AB@%; hex number.%@AE@%%@NL@%
- %@NL@%
- mov ax, es:[di+1] %@AB@%; AH = low digit, AL = high digit%@AE@%%@NL@%
- mov cx, 2 %@AB@%; Process two digits%@AE@%%@NL@%
- %@NL@%
- .REPEAT%@NL@%
- sub al, '0' %@AB@%; Convert digit to binary%@AE@%%@NL@%
- .IF (al > 9) %@AB@%; If not digit 0-9:%@AE@%%@NL@%
- and al, 00011111y %@AB@%; Mask out lower-case bit%@AE@%%@NL@%
- sub al, 7 %@AB@%; Convert A to 10, B to 11, etc%@AE@%%@NL@%
- .ENDIF%@NL@%
- xchg ah, al %@AB@%; Get next digit in AL%@AE@%%@NL@%
- .UNTILCXZ%@NL@%
- %@NL@%
- mov cl, 4%@NL@%
- shl al, cl %@AB@%; Multiply high digit by 16%@AE@%%@NL@%
- or al, ah %@AB@%; AL = binary value of attribute%@AE@%%@NL@%
- push ax %@AB@%; Save new attribute%@AE@%%@NL@%
- %@NL@%
- mov al, 2 %@AB@%; Request function 2%@AE@%%@NL@%
- call CallMultiplex %@AB@%; Get shared memory addr in ES:DI%@AE@%%@NL@%
- .IF ax != IS_INSTALLED %@AB@%; If TSR is not installed:%@AE@%%@NL@%
- pop ax %@AB@%; Clean stack and%@AE@%%@NL@%
- mov ax, CANT_ACCESS %@AB@%; quit with error message%@AE@%%@NL@%
- jmp exit%@NL@%
- .ELSE %@AB@%; If TSR is installed:%@AE@%%@NL@%
- pop ax %@AB@%; Recover new fill attribute in AL%@AE@%%@NL@%
- mov es:[di], al %@AB@%; Write it to resident shared memory%@AE@%%@NL@%
- mov ax, OK_ACCESS %@AB@%; Signal successful completion%@AE@%%@NL@%
- jmp exit%@NL@%
- .ENDIF%@NL@%
- %@NL@%
- %@AB@%; This section sets up the TSR's interrupt handlers and%@AE@%%@NL@%
- %@AB@%; makes the program memory-resident%@AE@%%@NL@%
- %@NL@%
- installtsr:%@NL@%
- push es %@AB@%; Preserve PSP address%@AE@%%@NL@%
- %@NL@%
- mov ax, @code%@NL@%
- mov es, ax%@NL@%
- mov bx, OFFSET Snap %@AB@%; ES:BX points to Snap%@AE@%%@NL@%
- INVOKE Install, %@AB@%; Install handlers%@AE@%%@NL@%
- HOT_SCAN, %@AB@%; Scan code of hot key%@AE@%%@NL@%
- HOT_SHIFT, %@AB@%; Bit value of hot key%@AE@%%@NL@%
- HOT_MASK, %@AB@%; Bit mask for shift hot key%@AE@%%@NL@%
- es::bx %@AB@%; Far address of Snap procedure%@AE@%%@NL@%
- %@NL@%
- pop bx %@AB@%; Recover PSP address%@AE@%%@NL@%
- or ax, ax %@AB@%; If non-zero return code,%@AE@%%@NL@%
- jnz exit %@AB@%; exit with appropriate message%@AE@%%@NL@%
- mov ax, INSTALLCODE %@AB@%; Bottom of resident section%@AE@%%@NL@%
- sub ax, bx %@AB@%; AX = number of paragraphs in%@AE@%%@NL@%
- %@AB@%; block to be made resident%@AE@%%@NL@%
- INVOKE KeepTsr, %@AB@%; Make TSR memory-resident%@AE@%%@NL@%
- ax %@AB@%; Resident paragraphs%@AE@%%@NL@%
- %@NL@%
- %@AB@%; This section deinstalls the resident TSR from memory%@AE@%%@NL@%
- %@NL@%
- deinstalltsr:%@NL@%
- %@NL@%
- INVOKE Deinstall %@AB@%; Unchain interrupt handlers%@AE@%%@NL@%
- %@NL@%
- .IF ax > OK_ARGUMENT %@AB@%; If successful:%@AE@%%@NL@%
- INVOKE FreeTsr, %@AB@%; Deinstall TSR by freeing memory%@AE@%%@NL@%
- ax %@AB@%; Address of resident seg%@AE@%%@NL@%
- .ENDIF %@AB@%; Else exit with message%@AE@%%@NL@%
- exit:%@NL@%
- INVOKE FatalError, %@AB@%; Exit to DOS with message%@AE@%%@NL@%
- ax %@AB@%; Error number%@AE@%%@NL@%
- %@NL@%
- Begin ENDP%@NL@%
- %@NL@%
- INSTALLCODE ENDS%@NL@%
- %@NL@%
- END Begin%@NL@%
- %@1@%%@AH@%Microsoft MASM: Sample Code from Version 5.x%@EH@%%@AE@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%BA.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\MIXED\BA.ASM%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- .MODEL medium%@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%; BASIC function for QuickBASIC, Version 4 and future versions%@AE@%%@NL@%
- %@AB@%; of Microsoft and IBM BASIC Compilers%@AE@%%@NL@%
- %@NL@%
- PUBLIC Power2%@NL@%
- Power2 PROC%@NL@%
- push bp %@AB@%; Entry sequence - save old BP%@AE@%%@NL@%
- mov bp,sp %@AB@%; Set stack framepointer%@AE@%%@NL@%
- %@NL@%
- mov bx,[bp+8] %@AB@%; Load Arg1 into%@AE@%%@NL@%
- mov ax,[bx] %@AB@%; AX%@AE@%%@NL@%
- mov bx,[bp+6] %@AB@%; Load Arg2 into%@AE@%%@NL@%
- mov cx,[bx] %@AB@%; CX%@AE@%%@NL@%
- shl ax,cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- %@AB@%; Leave return value in AX%@AE@%%@NL@%
- %@NL@%
- pop bp %@AB@%; Restore old framepointer%@AE@%%@NL@%
- ret 4 %@AB@%; Exit, and restore 4 bytes of args%@AE@%%@NL@%
- Power2 ENDP%@NL@%
- %@NL@%
- %@AB@%; BASIC subprogram for QuickBASIC, Versions 1, 2, and 3;%@AE@%%@NL@%
- %@AB@%; for the Microsoft BASIC Compiler through Version 5.36%@AE@%%@NL@%
- %@AB@%; for the IBM BASIC Compiler through Version 2.02%@AE@%%@NL@%
- %@NL@%
- PUBLIC Power2S%@NL@%
- Power2S PROC%@NL@%
- push bp %@AB@%; Entry sequence - save old BP%@AE@%%@NL@%
- mov bp,sp %@AB@%; Set stack framepointer%@AE@%%@NL@%
- %@NL@%
- mov bx,[bp+10] %@AB@%; Load Arg1 into%@AE@%%@NL@%
- mov ax,[bx] %@AB@%; AX%@AE@%%@NL@%
- mov bx,[bp+8] %@AB@%; Load Arg2 into%@AE@%%@NL@%
- mov cx,[bx] %@AB@%; CX%@AE@%%@NL@%
- shl ax,cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- mov bx,[bp+6] %@AB@%; Store result in%@AE@%%@NL@%
- mov [bx],ax %@AB@%; Arg3%@AE@%%@NL@%
- %@NL@%
- pop bp %@AB@%; Restore old framepointer%@AE@%%@NL@%
- ret 4 %@AB@%; Exit, and restore 4 bytes of args%@AE@%%@NL@%
- Power2S ENDP%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%CA.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\MIXED\CA.ASM%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- .MODEL SMALL%@NL@%
- .CODE%@NL@%
- PUBLIC _Power2%@NL@%
- _Power2 PROC%@NL@%
- push bp %@AB@%;Entry sequence%@AE@%%@NL@%
- mov bp,sp%@NL@%
- %@NL@%
- mov ax,[bp+4] %@AB@%; Load Arg1 into AX%@AE@%%@NL@%
- mov cx,[bp+6] %@AB@%; Load Arg2 into CX%@AE@%%@NL@%
- shl ax,cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- %@AB@%; Leave return value in AX%@AE@%%@NL@%
- %@NL@%
- pop bp %@AB@%; Exit sequence%@AE@%%@NL@%
- ret%@NL@%
- _Power2 ENDP%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%FA.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\MIXED\FA.ASM%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- .MODEL large%@NL@%
- .CODE%@NL@%
- PUBLIC Power2%@NL@%
- Power2 PROC%@NL@%
- push bp %@AB@%; Entry sequence - save old BP%@AE@%%@NL@%
- mov bp,sp %@AB@%; Set stack framepointer%@AE@%%@NL@%
- %@NL@%
- les bx,[bp+10] %@AB@%; Load Arg1 into%@AE@%%@NL@%
- mov ax,[bx] %@AB@%; AX%@AE@%%@NL@%
- les bx,[bp+6] %@AB@%; Load Arg2 into%@AE@%%@NL@%
- mov cx,[bx] %@AB@%; CX%@AE@%%@NL@%
- shl ax,cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- %@AB@%; Leave return value in AX%@AE@%%@NL@%
- %@NL@%
- pop bp %@AB@%; Restore old framepointer%@AE@%%@NL@%
- ret 4 %@AB@%; Exit, and restore 4 bytes of args%@AE@%%@NL@%
- Power2 ENDP%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%PA.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\MIXED\PA.ASM%@AE@%%@NL@%
- %@NL@%
- %@NL@%
- .MODEL medium%@NL@%
- .CODE%@NL@%
- PUBLIC Power2%@NL@%
- Power2 PROC%@NL@%
- push bp %@AB@%; Entry sequence - save old BP%@AE@%%@NL@%
- mov bp,sp %@AB@%; Set stack framepointer%@AE@%%@NL@%
- %@NL@%
- mov ax,[bp+8] %@AB@%; Load Arg1 into AX%@AE@%%@NL@%
- mov cx,[bp+6] %@AB@%; Load Arg2 into CX%@AE@%%@NL@%
- shl ax,cl %@AB@%; AX = AX * (2 to power of CX)%@AE@%%@NL@%
- %@AB@%; Leave return value in AX%@AE@%%@NL@%
- %@NL@%
- pop bp %@AB@%; Restore old framepointer%@AE@%%@NL@%
- ret 4 %@AB@%; Exit, and restore 4 bytes of args%@AE@%%@NL@%
- Power2 ENDP%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%PAGERP.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\PAGERP.ASM%@AE@%%@NL@%
- %@NL@%
- TITLE Pager%@NL@%
- .MODEL small, pascal%@NL@%
- %@NL@%
- INCL_VIO EQU 1%@NL@%
- %@NL@%
- INCLUDE os2.inc%@NL@%
- .DATA%@NL@%
- EXTRN stAtrib:BYTE, scAtrib:BYTE, Cell:WORD, stLine:BYTE%@NL@%
- EXTRN sBuffer:WORD, oBuffer:WORD, Buffer:DWORD, lBuffer:WORD%@NL@%
- EXTRN nLines:WORD, curLine:WORD%@NL@%
- %@NL@%
- .CODE%@NL@%
- PUBLIC Pager%@NL@%
- %@NL@%
- %@AB@%; Procedure Pager%@AE@%%@NL@%
- %@AB@%; Purpose Displays status and text lines%@AE@%%@NL@%
- %@AB@%; Input Stack variable: lines to scroll (negative up, positive down)%@AE@%%@NL@%
- %@AB@%; Global variables: "sbuffer", "oBuffer", "curLine"%@AE@%%@NL@%
- %@AB@%; Output To screen%@AE@%%@NL@%
- %@NL@%
- Pager PROC count%@NL@%
- %@NL@%
- mov es, sBuffer %@AB@%; Initialize buffer position%@AE@%%@NL@%
- mov di, oBuffer%@NL@%
- %@NL@%
- mov cx, count %@AB@%; Get count argument%@AE@%%@NL@%
- mov ax, 10 %@AB@%; Search for linefeed%@AE@%%@NL@%
- %@NL@%
- or cx, cx %@AB@%; Argument 0?%@AE@%%@NL@%
- jl skip1 %@AB@%; If below, backward%@AE@%%@NL@%
- jg skip2 %@AB@%; If above, forward%@AE@%%@NL@%
- jmp SHORT skip3 %@AB@%; If equal, done%@AE@%%@NL@%
- %@NL@%
- skip1: call GoBack %@AB@%; Adjust backward%@AE@%%@NL@%
- jmp SHORT skip3 %@AB@%; Show screen%@AE@%%@NL@%
- skip2: call GoForwd %@AB@%; Adjust forward%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write line number to status line%@AE@%%@NL@%
- %@NL@%
- skip3: cld %@AB@%; Go forward%@AE@%%@NL@%
- push di %@AB@%; Save%@AE@%%@NL@%
- push ds %@AB@%; ES = DS%@AE@%%@NL@%
- pop es%@NL@%
- %@NL@%
- %@AB@%; BinToStr (curLine, OFFSET stLine[6])%@AE@%%@NL@%
- %@NL@%
- push curLine %@AB@%; Arg 1%@AE@%%@NL@%
- @Pushc <OFFSET stLine[6]> %@AB@%; Arg 2%@AE@%%@NL@%
- call BinToStr %@AB@%; Convert to string%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Fill in status line%@AE@%%@NL@%
- %@NL@%
- mov cx, 6 %@AB@%; Six spaces to fill%@AE@%%@NL@%
- sub cx, ax %@AB@%; Subtract those already done%@AE@%%@NL@%
- mov al, " " %@AB@%; Fill with space%@AE@%%@NL@%
- rep stosb%@NL@%
- %@NL@%
- @VioWrtCharStrAtt stLine, 80, 0, 0, stAtrib, 0 %@AB@%; Write to screen%@AE@%%@NL@%
- %@NL@%
- pop di %@AB@%; Update position%@AE@%%@NL@%
- mov si, di%@NL@%
- mov cx, nLines %@AB@%; Lines per screen%@AE@%%@NL@%
- %@NL@%
- loop1: mov bx, nLines %@AB@%; Lines of text%@AE@%%@NL@%
- inc bx %@AB@%; Adjust for 0%@AE@%%@NL@%
- sub bx, cx %@AB@%; Calculate current row%@AE@%%@NL@%
- push cx %@AB@%; Save line number%@AE@%%@NL@%
- %@NL@%
- %@AB@%; ShowLine (position, line, maxlength, &scAtrib)%@AE@%%@NL@%
- %@NL@%
- push sBuffer %@AB@%; Arg 1%@AE@%%@NL@%
- push si%@NL@%
- push bx %@AB@%; Arg 2%@AE@%%@NL@%
- push lBuffer %@AB@%; Arg 3%@AE@%%@NL@%
- push ds %@AB@%; Arg r4%@AE@%%@NL@%
- @Pushc <OFFSET scAtrib>%@NL@%
- call ShowLine %@AB@%; Write line%@AE@%%@NL@%
- %@NL@%
- pop cx %@AB@%; Restore line number%@AE@%%@NL@%
- mov si, ax %@AB@%; Get returned position%@AE@%%@NL@%
- %@NL@%
- cmp ax, lBuffer %@AB@%; If beyond end of file,%@AE@%%@NL@%
- jae skip4 %@AB@%; fill screen with spaces%@AE@%%@NL@%
- loop loop1 %@AB@%; else next line%@AE@%%@NL@%
- jmp SHORT exit %@AB@%; Exit if done%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Fill the rest with spaces%@AE@%%@NL@%
- %@NL@%
- skip4: dec cx%@NL@%
- jcxz exit%@NL@%
- mov ax, 80 %@AB@%; Columns times remaining lines%@AE@%%@NL@%
- mul cl%@NL@%
- mov dx, ax %@AB@%; Macros use AX, so use DX%@AE@%%@NL@%
- sub cx, nLines %@AB@%; Calculate starting line%@AE@%%@NL@%
- neg cx%@NL@%
- inc cx%@NL@%
- %@NL@%
- @VioWrtNCell Cell, dx, cx, 0, 0 %@AB@%; Write space cells%@AE@%%@NL@%
- %@NL@%
- exit: ret%@NL@%
- Pager ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure ShowLine (inLine, sRow, &pAtrib)%@AE@%%@NL@%
- %@AB@%; Purpose Writes a line to screen%@AE@%%@NL@%
- %@AB@%; Input Stack variables: 1 - FAR PTR to input line%@AE@%%@NL@%
- %@AB@%; 2 - line number%@AE@%%@NL@%
- %@AB@%; 3 - maximum number of characters (file length)%@AE@%%@NL@%
- %@AB@%; 4 - FAR PTR to attribute%@AE@%%@NL@%
- %@AB@%; Output Line to screen%@AE@%%@NL@%
- %@NL@%
- ShowLine PROC USES si di, inLine:FAR PTR BYTE, srow, max, pAtrib:FAR PTR BYTE%@NL@%
- LOCAL outLine[80]:BYTE%@NL@%
- %@NL@%
- push ds %@AB@%; Save%@AE@%%@NL@%
- push ss %@AB@%; ES = SS%@AE@%%@NL@%
- pop es%@NL@%
- lea di, outLine %@AB@%; Destination line%@AE@%%@NL@%
- lds si, inLine %@AB@%; Source line%@AE@%%@NL@%
- mov cx, 80 %@AB@%; Cells per row%@AE@%%@NL@%
- mov bx, di %@AB@%; Save copy of start for tab calc%@AE@%%@NL@%
- loop1: lodsb %@AB@%; Get character%@AE@%%@NL@%
- cmp al, 9 %@AB@%; Tab?%@AE@%%@NL@%
- je skip1 %@AB@%; Space out tab%@AE@%%@NL@%
- cmp al, 13 %@AB@%; CR?%@AE@%%@NL@%
- je skip3 %@AB@%; Fill rest of line with spaces%@AE@%%@NL@%
- stosb %@AB@%; Copy out%@AE@%%@NL@%
- cmp si, max %@AB@%; Check for end of file%@AE@%%@NL@%
- ja skip3%@NL@%
- loop loop1%@NL@%
- %@NL@%
- loop2: lodsb %@AB@%; Throw away rest of line to truncate%@AE@%%@NL@%
- cmp si, max %@AB@%; Check for end of file%@AE@%%@NL@%
- ja exit%@NL@%
- cmp al, 13 %@AB@%; Check for end of line%@AE@%%@NL@%
- jne loop2%@NL@%
- inc si %@AB@%; Throw away line feed%@AE@%%@NL@%
- %@NL@%
- jmp SHORT exit %@AB@%; Done%@AE@%%@NL@%
- %@NL@%
- skip1: push bx %@AB@%; Fill tab with spaces%@AE@%%@NL@%
- push cx%@NL@%
- %@NL@%
- sub bx, di %@AB@%; Get current position in line%@AE@%%@NL@%
- neg bx%@NL@%
- %@NL@%
- mov cx, 8 %@AB@%; Default count 8%@AE@%%@NL@%
- and bx, 7 %@AB@%; Get modulus%@AE@%%@NL@%
- sub cx, bx %@AB@%; Subtract%@AE@%%@NL@%
- mov bx, cx %@AB@%; Save modulus%@AE@%%@NL@%
- %@NL@%
- mov al, " " %@AB@%; Write spaces%@AE@%%@NL@%
- rep stosb%@NL@%
- %@NL@%
- pop cx%@NL@%
- sub cx, bx %@AB@%; Adjust count%@AE@%%@NL@%
- jns skip2 %@AB@%; Make negative count 0%@AE@%%@NL@%
- sub cx, cx%@NL@%
- skip2: pop bx%@NL@%
- jcxz loop2 %@AB@%; If beyond limit done%@AE@%%@NL@%
- jmp SHORT loop1%@NL@%
- %@NL@%
- skip3: inc si %@AB@%; After CR, throw away LF%@AE@%%@NL@%
- mov al, ' ' %@AB@%; Fill rest of line%@AE@%%@NL@%
- rep stosb%@NL@%
- %@NL@%
- exit: pop ds%@NL@%
- @VioWrtCharStrAtt outLine, 80, [srow], 0, [pAtrib], 0%@NL@%
- %@NL@%
- mov ax, si %@AB@%; Return position%@AE@%%@NL@%
- ret%@NL@%
- ShowLine ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure GoBack%@AE@%%@NL@%
- %@AB@%; Purpose Searches backward through buffer%@AE@%%@NL@%
- %@AB@%; Input CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
- %@AB@%; Output Updates "curLine" and "oBuffer"%@AE@%%@NL@%
- %@NL@%
- GoBack PROC%@NL@%
- std %@AB@%; Go backward%@AE@%%@NL@%
- neg cx %@AB@%; Make count positive%@AE@%%@NL@%
- mov dx, cx %@AB@%; Save a copy%@AE@%%@NL@%
- inc cx %@AB@%; One extra to go up one%@AE@%%@NL@%
- or di, di %@AB@%; Start of file?%@AE@%%@NL@%
- je exit %@AB@%; If so, ignore%@AE@%%@NL@%
- loop1: push cx %@AB@%; else save count%@AE@%%@NL@%
- mov cx, 0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- cmp cx, di %@AB@%; Near start of buffer?%@AE@%%@NL@%
- jl skip1 %@AB@%; No? Continue%@AE@%%@NL@%
- mov cx, di %@AB@%; else search only to start%@AE@%%@NL@%
- skip1: repne scasb %@AB@%; Find last previous LF%@AE@%%@NL@%
- jcxz skip4 %@AB@%; If not found, must be at start%@AE@%%@NL@%
- pop cx%@NL@%
- loop loop1%@NL@%
- cmp curLine, -1 %@AB@%; End of file flag?%@AE@%%@NL@%
- jne skip2 %@AB@%; No? Continue%@AE@%%@NL@%
- add di, 2 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
- mov oBuffer, di %@AB@%; Save position%@AE@%%@NL@%
- call EndCount %@AB@%; Count back to get line number%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- skip2: sub curLine, dx %@AB@%; Calculate line number%@AE@%%@NL@%
- jg skip3%@NL@%
- mov curLine, 1 %@AB@%; Set to 1 if negative%@AE@%%@NL@%
- skip3: add di, 2 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
- mov oBuffer, di %@AB@%; Save position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- skip4: pop cx%@NL@%
- sub di, di %@AB@%; Load start of file%@AE@%%@NL@%
- mov curLine, 1 %@AB@%; Line 1%@AE@%%@NL@%
- mov oBuffer, di %@AB@%; Save position%@AE@%%@NL@%
- exit: ret%@NL@%
- GoBack ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure GoForwd%@AE@%%@NL@%
- %@AB@%; Purpose Searches forward through a buffer%@AE@%%@NL@%
- %@AB@%; Input CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
- %@AB@%; Output Updates "curLine" and "oBuffer"%@AE@%%@NL@%
- %@NL@%
- GoForwd PROC%@NL@%
- cld %@AB@%; Go forward%@AE@%%@NL@%
- mov dx, cx %@AB@%; Copy count%@AE@%%@NL@%
- loop1: push cx %@AB@%; Save count%@AE@%%@NL@%
- mov cx, 0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- mov bx, lBuffer %@AB@%; Get end of file%@AE@%%@NL@%
- %@NL@%
- sub bx, di %@AB@%; Characters to end of file%@AE@%%@NL@%
- cmp cx, bx %@AB@%; Less than maximum per line?%@AE@%%@NL@%
- jb skip1%@NL@%
- mov cx, bx%@NL@%
- skip1: repne scasb %@AB@%; Find next LF%@AE@%%@NL@%
- jcxz exit %@AB@%; If not found, must be at end%@AE@%%@NL@%
- cmp di, lBuffer %@AB@%; Beyond end?%@AE@%%@NL@%
- jae exit%@NL@%
- pop cx%@NL@%
- loop loop1%@NL@%
- add curLine, dx %@AB@%; Calulate line number%@AE@%%@NL@%
- mov oBuffer, di %@AB@%; Save position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- exit: pop cx%@NL@%
- mov di, oBuffer %@AB@%; Restore position%@AE@%%@NL@%
- ret%@NL@%
- GoForwd ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure EndCount%@AE@%%@NL@%
- %@AB@%; Purpose Counts backward to count lines in file%@AE@%%@NL@%
- %@AB@%; Input ES:DI has buffer position%@AE@%%@NL@%
- %@AB@%; Output Modifies "curLine"%@AE@%%@NL@%
- %@NL@%
- EndCount PROC%@NL@%
- push di%@NL@%
- %@NL@%
- mov al, 13 %@AB@%; Search for CR%@AE@%%@NL@%
- mov curLine, 0 %@AB@%; Initialize%@AE@%%@NL@%
- %@NL@%
- loop1: inc curLine %@AB@%; Adjust count%@AE@%%@NL@%
- mov cx, 0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- cmp cx, di %@AB@%; Near start of buffer?%@AE@%%@NL@%
- jl skip1 %@AB@%; No? Continue%@AE@%%@NL@%
- mov cx, di %@AB@%; else search only to start%@AE@%%@NL@%
- skip1: repne scasb %@AB@%; Find last previous cr%@AE@%%@NL@%
- jcxz exit %@AB@%; If not found, must be at start%@AE@%%@NL@%
- jmp SHORT loop1%@NL@%
- %@NL@%
- exit: pop di%@NL@%
- ret%@NL@%
- EndCount ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure BinToStr (number, string)%@AE@%%@NL@%
- %@AB@%; Purpose Converts integer to string%@AE@%%@NL@%
- %@AB@%; Input Stack arguments: 1 - Number to convert; 2 - Near address for write%@AE@%%@NL@%
- %@AB@%; Output AX has characters written%@AE@%%@NL@%
- %@NL@%
- BinToStr PROC number, string:PTR BYTE%@NL@%
- %@NL@%
- mov ax,number%@NL@%
- mov di,string%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Clear counter%@AE@%%@NL@%
- mov bx, 10 %@AB@%; Divide by 10%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Convert and save on stack backwards%@AE@%%@NL@%
- %@NL@%
- loop1: sub dx, dx %@AB@%; Clear top%@AE@%%@NL@%
- div bx %@AB@%; Divide to get last digit as remainder%@AE@%%@NL@%
- add dl, "0" %@AB@%; Convert to ASCII%@AE@%%@NL@%
- push dx %@AB@%; Save on stack%@AE@%%@NL@%
- or ax, ax %@AB@%; Quotient 0?%@AE@%%@NL@%
- loopnz loop1 %@AB@%; No? Get another%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Take off the stack and store forward%@AE@%%@NL@%
- %@NL@%
- neg cx %@AB@%; Negate and save count%@AE@%%@NL@%
- mov dx, cx%@NL@%
- loop2: pop ax %@AB@%; Get character%@AE@%%@NL@%
- stosb %@AB@%; Store it%@AE@%%@NL@%
- loop loop2%@NL@%
- mov ax, dx %@AB@%; Return digit count%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- BinToStr ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%PAGERR.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\PAGERR.ASM%@AE@%%@NL@%
- %@NL@%
- PAGE 60,132%@NL@%
- .MODEL small%@NL@%
- .DATA%@NL@%
- EXTRN statatr:BYTE,scrnatr:BYTE,sbuffer:WORD,pbuffer:WORD%@NL@%
- EXTRN fsize:WORD,cell:WORD,statline:BYTE,linenum:WORD%@NL@%
- EXTRN rows:WORD,vidadr:WORD,cga:BYTE%@NL@%
- %@NL@%
- .CODE%@NL@%
- PUBLIC Pager,isEGA%@NL@%
- %@NL@%
- %@AB@%; Procedure Pager%@AE@%%@NL@%
- %@AB@%; Purpose Displays status and text lines%@AE@%%@NL@%
- %@AB@%; Input Stack variable: lines to scroll (negative up, positive down)%@AE@%%@NL@%
- %@AB@%; Global variables: "sbuffer", "pbuffer", "linenum"%@AE@%%@NL@%
- %@AB@%; Output To screen%@AE@%%@NL@%
- %@NL@%
- Pager PROC%@NL@%
- push bp%@NL@%
- mov bp,sp%@NL@%
- %@NL@%
- mov es,sbuffer %@AB@%; Initialize buffer position%@AE@%%@NL@%
- mov di,pbuffer%@NL@%
- %@NL@%
- mov cx,[bp+4] %@AB@%; Get count argument%@AE@%%@NL@%
- mov ax,10 %@AB@%; Search for linefeed%@AE@%%@NL@%
- %@NL@%
- or cx,cx %@AB@%; Argument 0?%@AE@%%@NL@%
- jg forward %@AB@%; If above, forward%@AE@%%@NL@%
- jl backward %@AB@%; If below, backward%@AE@%%@NL@%
- jmp SHORT show %@AB@%; If equal, done%@AE@%%@NL@%
- %@NL@%
- backward: call GoBack %@AB@%; Adjust backward%@AE@%%@NL@%
- jmp SHORT show %@AB@%; Show screen%@AE@%%@NL@%
- forward: call GoForwd %@AB@%; Adjust forward%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Write line number to status line%@AE@%%@NL@%
- %@NL@%
- show: cld %@AB@%; Go forward%@AE@%%@NL@%
- push di%@NL@%
- push es%@NL@%
- push ds %@AB@%; Load DS to ES%@AE@%%@NL@%
- pop es%@NL@%
- %@NL@%
- %@AB@%; BinToStr (linenum,OFFSET statline[7])%@AE@%%@NL@%
- %@NL@%
- push linenum %@AB@%; Arg 1%@AE@%%@NL@%
- mov ax,OFFSET statline[7]%@NL@%
- push ax %@AB@%; Arg 2%@AE@%%@NL@%
- call BinToStr %@AB@%; Convert to string%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Fill in status line%@AE@%%@NL@%
- %@NL@%
- mov cx,7 %@AB@%; Seven spaces to fill%@AE@%%@NL@%
- sub cx,ax %@AB@%; Subtract those already done%@AE@%%@NL@%
- mov al," " %@AB@%; Fill with space%@AE@%%@NL@%
- rep stosb%@NL@%
- pop es%@NL@%
- %@NL@%
- mov bl,statatr %@AB@%; Load status attribute%@AE@%%@NL@%
- mov BYTE PTR cell[1],bl%@NL@%
- %@NL@%
- %@AB@%; CellWrt (DS,OFFSET statline,0,cell)%@AE@%%@NL@%
- %@NL@%
- push ds %@AB@%; Arg 1%@AE@%%@NL@%
- mov ax,OFFSET statline %@AB@%; Arg 2%@AE@%%@NL@%
- push ax%@NL@%
- sub ax,ax %@AB@%; Arg 3%@AE@%%@NL@%
- push ax%@NL@%
- push cell %@AB@%; Arg 4%@AE@%%@NL@%
- call CellWrt %@AB@%; Write status line%@AE@%%@NL@%
- %@NL@%
- pop di%@NL@%
- mov bl,scrnatr %@AB@%; Load screen attribute%@AE@%%@NL@%
- mov BYTE PTR cell[1],bl%@NL@%
- mov si,di %@AB@%; Update position%@AE@%%@NL@%
- mov cx,rows %@AB@%; Lines per screen%@AE@%%@NL@%
- %@NL@%
- show1: mov bx,rows %@AB@%; Lines of text%@AE@%%@NL@%
- inc bx %@AB@%; Adjust for 0%@AE@%%@NL@%
- sub bx,cx %@AB@%; Calculate current row%@AE@%%@NL@%
- push cx %@AB@%; Save line number%@AE@%%@NL@%
- %@NL@%
- %@AB@%; CellWrt (sbuffer,position,line,cell)%@AE@%%@NL@%
- %@NL@%
- push sbuffer %@AB@%; Arg 1%@AE@%%@NL@%
- push si %@AB@%; Arg 2%@AE@%%@NL@%
- push bx %@AB@%; Arg 3%@AE@%%@NL@%
- push cell %@AB@%; Arg 4%@AE@%%@NL@%
- call cellwrt %@AB@%; Write line%@AE@%%@NL@%
- %@NL@%
- push ss %@AB@%; Restore DS from SS%@AE@%%@NL@%
- pop ds%@NL@%
- %@NL@%
- pop cx %@AB@%; Restore line number%@AE@%%@NL@%
- mov si,ax %@AB@%; Get returned position%@AE@%%@NL@%
- %@NL@%
- cmp ax,fsize %@AB@%; Beyond end of file?%@AE@%%@NL@%
- jae fillout %@AB@%; Yes? Fill screen with spaces%@AE@%%@NL@%
- loop show1 %@AB@%; else next line%@AE@%%@NL@%
- jmp SHORT pagedone %@AB@%; Get out if done%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Fill the rest with spaces%@AE@%%@NL@%
- %@NL@%
- fillout: dec cx %@AB@%; Adjust%@AE@%%@NL@%
- jcxz pagedone%@NL@%
- mov al,80 %@AB@%; Columns times remaining lines%@AE@%%@NL@%
- mul cl%@NL@%
- %@NL@%
- %@AB@%; CellFil (sbuffer,count,cell)%@AE@%%@NL@%
- %@NL@%
- push sbuffer %@AB@%; Arg 1%@AE@%%@NL@%
- push ax %@AB@%; Arg 2%@AE@%%@NL@%
- push cell %@AB@%; Arg 3%@AE@%%@NL@%
- call CellFil %@AB@%; Fill screen with spaces%@AE@%%@NL@%
- %@NL@%
- push ss %@AB@%; Restore DS from SS%@AE@%%@NL@%
- pop ds%@NL@%
- %@NL@%
- pagedone: pop bp%@NL@%
- ret 2%@NL@%
- Pager ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure CellWrt (segment,offset,line,cell)%@AE@%%@NL@%
- %@AB@%; Purpose Writes a line to screen buffer%@AE@%%@NL@%
- %@AB@%; Input Stack variables: 1 - segment of line%@AE@%%@NL@%
- %@AB@%; 2 - offset%@AE@%%@NL@%
- %@AB@%; 3 - line number%@AE@%%@NL@%
- %@AB@%; 4 - attribute%@AE@%%@NL@%
- %@AB@%; Output Line to screen buffer%@AE@%%@NL@%
- %@NL@%
- CellWrt PROC%@NL@%
- push bp%@NL@%
- mov bp,sp%@NL@%
- sub dx,dx %@AB@%; Clear as flag for scan%@AE@%%@NL@%
- cmp cga,1 %@AB@%; CGA?%@AE@%%@NL@%
- jne noscan%@NL@%
- mov dx,03DAh %@AB@%; Load port #%@AE@%%@NL@%
- %@NL@%
- noscan: mov es,vidadr %@AB@%; Load screen buffer segment%@AE@%%@NL@%
- mov ds,[bp+10] %@AB@%; Buffer segment%@AE@%%@NL@%
- mov si,[bp+8] %@AB@%; Buffer position%@AE@%%@NL@%
- mov cx,80 %@AB@%; Cells per row%@AE@%%@NL@%
- mov ax,[bp+6] %@AB@%; Starting row%@AE@%%@NL@%
- mov bx,80*2 %@AB@%; Bytes per row%@AE@%%@NL@%
- mul bl %@AB@%; Figure columns per row%@AE@%%@NL@%
- mov di,ax %@AB@%; Load as destination%@AE@%%@NL@%
- mov bx,di %@AB@%; Save start for tab calculation%@AE@%%@NL@%
- mov ax,[bp+4] %@AB@%; Attribute%@AE@%%@NL@%
- movechar: lodsb %@AB@%; Get character%@AE@%%@NL@%
- cmp al,13 %@AB@%; CR?%@AE@%%@NL@%
- je fillspc%@NL@%
- cmp al,9 %@AB@%; Tab?%@AE@%%@NL@%
- jne notab%@NL@%
- call filltab %@AB@%; Yes? fill with spaces%@AE@%%@NL@%
- jcxz nextline %@AB@%; If beyond limit done%@AE@%%@NL@%
- jmp SHORT movechar%@NL@%
- %@NL@%
- notab: or dx,dx %@AB@%; CGA?%@AE@%%@NL@%
- je notab2%@NL@%
- call Retrace %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
- loop movechar%@NL@%
- jmp SHORT nextline%@NL@%
- %@NL@%
- notab2: stosw %@AB@%; Write%@AE@%%@NL@%
- loop movechar%@NL@%
- jmp SHORT nextline %@AB@%; Done%@AE@%%@NL@%
- %@NL@%
- fillspc: mov al," " %@AB@%; Fill with space%@AE@%%@NL@%
- %@NL@%
- or dx,dx %@AB@%; CGA?%@AE@%%@NL@%
- je space2%@NL@%
- space1: call Retrace %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
- loop space1%@NL@%
- inc si %@AB@%; Adjust%@AE@%%@NL@%
- jmp SHORT exit %@AB@%; Done%@AE@%%@NL@%
- %@NL@%
- space2: rep stosw %@AB@%; Write%@AE@%%@NL@%
- inc si %@AB@%; Adjust for LF%@AE@%%@NL@%
- jmp SHORT exit %@AB@%; Done%@AE@%%@NL@%
- %@NL@%
- nextline: mov ah,10 %@AB@%; Search for next line feed%@AE@%%@NL@%
- chklf: lodsb %@AB@%; Load and compare%@AE@%%@NL@%
- cmp al,ah%@NL@%
- loopne chklf%@NL@%
- %@NL@%
- exit: mov ax,si %@AB@%; Return position%@AE@%%@NL@%
- pop bp%@NL@%
- ret 8%@NL@%
- CellWrt ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure CellFil (segment,count,cell)%@AE@%%@NL@%
- %@AB@%; Purpose Fills screen with character%@AE@%%@NL@%
- %@AB@%; Input Stack variables: 1 - segment of text (offset 0)%@AE@%%@NL@%
- %@AB@%; 2 - number of characters%@AE@%%@NL@%
- %@AB@%; 3 - attribute and character%@AE@%%@NL@%
- %@AB@%; Output Characters to screen buffer%@AE@%%@NL@%
- %@NL@%
- CellFil PROC%@NL@%
- push bp%@NL@%
- mov bp,sp%@NL@%
- sub dx,dx %@AB@%; Clear as flag for scan%@AE@%%@NL@%
- cmp cga,1 %@AB@%; CGA?%@AE@%%@NL@%
- jne noscan2%@NL@%
- mov dx,03DAh %@AB@%; Load port #%@AE@%%@NL@%
- %@NL@%
- noscan2: mov es,vidadr %@AB@%; Load screen buffer segment%@AE@%%@NL@%
- mov ds,[bp+8] %@AB@%; Buffer segment (position 0)%@AE@%%@NL@%
- mov cx,[bp+6] %@AB@%; Characters to fill%@AE@%%@NL@%
- mov ax,[bp+4] %@AB@%; Attribute%@AE@%%@NL@%
- or dx,dx %@AB@%; CGA?%@AE@%%@NL@%
- je fillem2%@NL@%
- fillem1: call Retrace %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
- loop fillem1%@NL@%
- jmp SHORT filled %@AB@%; Done%@AE@%%@NL@%
- fillem2: rep stosw %@AB@%; Write%@AE@%%@NL@%
- %@NL@%
- filled: pop bp%@NL@%
- ret 6%@NL@%
- CellFil ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure FillTab%@AE@%%@NL@%
- %@AB@%; Purpose Writes spaces for tab to screen%@AE@%%@NL@%
- %@AB@%; Input BX points to start of line, DI points to current position%@AE@%%@NL@%
- %@AB@%; Output Spaces to screen buffer%@AE@%%@NL@%
- %@NL@%
- FillTab PROC%@NL@%
- push bx%@NL@%
- push cx%@NL@%
- %@NL@%
- sub bx,di %@AB@%; Get current position in line%@AE@%%@NL@%
- neg bx%@NL@%
- shr bx,1 %@AB@%; Divide by 2 bytes per character%@AE@%%@NL@%
- %@NL@%
- mov cx,8 %@AB@%; Default count 8%@AE@%%@NL@%
- and bx,7 %@AB@%; Get modulus%@AE@%%@NL@%
- sub cx,bx %@AB@%; Subtract%@AE@%%@NL@%
- mov bx,cx %@AB@%; Save modulus%@AE@%%@NL@%
- %@NL@%
- mov al," " %@AB@%; Spaces%@AE@%%@NL@%
- or dx,dx %@AB@%; CGA?%@AE@%%@NL@%
- je tabem2%@NL@%
- %@NL@%
- tabem1: call Retrace %@AB@%; Yes? Write during retrace%@AE@%%@NL@%
- loop tabem1%@NL@%
- jmp SHORT tabbed%@NL@%
- tabem2: rep stosw %@AB@%; Write%@AE@%%@NL@%
- %@NL@%
- tabbed: pop cx%@NL@%
- sub cx,bx %@AB@%; Adjust count%@AE@%%@NL@%
- jns nomore %@AB@%; Make negative count 0%@AE@%%@NL@%
- sub cx,cx%@NL@%
- nomore: pop bx%@NL@%
- ret%@NL@%
- FillTab ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure GoBack%@AE@%%@NL@%
- %@AB@%; Purpose Searches backward through buffer%@AE@%%@NL@%
- %@AB@%; Input CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
- %@AB@%; Output Updates "linenum" and "pbuffer"%@AE@%%@NL@%
- %@NL@%
- GoBack PROC%@NL@%
- std %@AB@%; Go backward%@AE@%%@NL@%
- neg cx %@AB@%; Make count positive%@AE@%%@NL@%
- mov dx,cx %@AB@%; Save a copy%@AE@%%@NL@%
- inc cx %@AB@%; One extra to go up one%@AE@%%@NL@%
- or di,di %@AB@%; Start of file?%@AE@%%@NL@%
- je exback %@AB@%; If so, ignore%@AE@%%@NL@%
- findb: push cx %@AB@%; else save count%@AE@%%@NL@%
- mov cx,0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- cmp cx,di %@AB@%; Near start of buffer?%@AE@%%@NL@%
- jl notnear %@AB@%; No? Continue%@AE@%%@NL@%
- mov cx,di %@AB@%; else search only to start%@AE@%%@NL@%
- notnear: repne scasb %@AB@%; Find last previous LF%@AE@%%@NL@%
- jcxz atstart %@AB@%; If not found, must be at start%@AE@%%@NL@%
- pop cx%@NL@%
- loop findb%@NL@%
- cmp linenum,0FFFFh %@AB@%; End of file flag?%@AE@%%@NL@%
- jne notend %@AB@%; No? Continue%@AE@%%@NL@%
- add di,2 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
- mov pbuffer,di %@AB@%; Save position%@AE@%%@NL@%
- call EndCount %@AB@%; Count back to get line number%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- notend: sub linenum,dx %@AB@%; Calculate line number%@AE@%%@NL@%
- jg positive%@NL@%
- mov linenum,1 %@AB@%; Set to 1 if negative%@AE@%%@NL@%
- positive: add di,2 %@AB@%; Adjust for cr/lf%@AE@%%@NL@%
- mov pbuffer,di %@AB@%; Save position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- atstart: pop cx%@NL@%
- sub di,di %@AB@%; Load start of file%@AE@%%@NL@%
- mov linenum,1 %@AB@%; Line 1%@AE@%%@NL@%
- mov pbuffer,di %@AB@%; Save position%@AE@%%@NL@%
- exback: ret%@NL@%
- GoBack ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure GoForwd%@AE@%%@NL@%
- %@AB@%; Purpose Searches forward through a buffer%@AE@%%@NL@%
- %@AB@%; Input CX has number of lines; ES:DI has buffer position%@AE@%%@NL@%
- %@AB@%; Output Updates "linenum" and "pbuffer"%@AE@%%@NL@%
- %@NL@%
- GoForwd PROC%@NL@%
- cld %@AB@%; Go forward%@AE@%%@NL@%
- mov dx,cx %@AB@%; Copy count%@AE@%%@NL@%
- findf: push cx %@AB@%; Save count%@AE@%%@NL@%
- mov cx,0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- repne scasb %@AB@%; Find next LF%@AE@%%@NL@%
- jcxz atend %@AB@%; If not found, must be at end%@AE@%%@NL@%
- cmp di,fsize %@AB@%; Beyond end?%@AE@%%@NL@%
- jae atend%@NL@%
- pop cx%@NL@%
- loop findf%@NL@%
- add linenum,dx %@AB@%; Calulate line number%@AE@%%@NL@%
- mov pbuffer,di %@AB@%; Save position%@AE@%%@NL@%
- ret%@NL@%
- %@NL@%
- atend: pop cx%@NL@%
- mov di,pbuffer %@AB@%; Restore position%@AE@%%@NL@%
- ret%@NL@%
- GoForwd ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure EndCount%@AE@%%@NL@%
- %@AB@%; Purpose Counts backward to count lines in file%@AE@%%@NL@%
- %@AB@%; Input ES:DI has buffer position%@AE@%%@NL@%
- %@AB@%; Output Modifies "linenum"%@AE@%%@NL@%
- %@NL@%
- EndCount PROC%@NL@%
- push di%@NL@%
- %@NL@%
- mov al,13 %@AB@%; Search for CR%@AE@%%@NL@%
- mov linenum,0 %@AB@%; Initialize%@AE@%%@NL@%
- %@NL@%
- findstrt: inc linenum %@AB@%; Adjust count%@AE@%%@NL@%
- mov cx,0FFh %@AB@%; Load maximum character count%@AE@%%@NL@%
- cmp cx,di %@AB@%; Near start of buffer?%@AE@%%@NL@%
- jl notnear2 %@AB@%; No? Continue%@AE@%%@NL@%
- mov cx,di %@AB@%; else search only to start%@AE@%%@NL@%
- notnear2: repne scasb %@AB@%; Find last previous cr%@AE@%%@NL@%
- jcxz found %@AB@%; If not found, must be at start%@AE@%%@NL@%
- jmp SHORT findstrt%@NL@%
- %@NL@%
- found: pop di%@NL@%
- ret%@NL@%
- EndCount ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure isEGA%@AE@%%@NL@%
- %@AB@%; Purpose Determines if an EGA is active%@AE@%%@NL@%
- %@AB@%; Input None%@AE@%%@NL@%
- %@AB@%; Output 0 if no; lines per screen if yes%@AE@%%@NL@%
- %@NL@%
- isEGA PROC%@NL@%
- push bp%@NL@%
- push es%@NL@%
- mov ah,12h %@AB@%; Call EGA status function%@AE@%%@NL@%
- mov bl,10h%@NL@%
- sub cx,cx %@AB@%; Clear status bits%@AE@%%@NL@%
- int 10h%@NL@%
- sub ax,ax %@AB@%; Segment 0 and assume no EGA%@AE@%%@NL@%
- jcxz noega %@AB@%; If status still clear, no EGA%@AE@%%@NL@%
- %@NL@%
- mov es,ax %@AB@%; ES=0%@AE@%%@NL@%
- test BYTE PTR es:[487h],1000b %@AB@%; Test active bit%@AE@%%@NL@%
- jnz noega %@AB@%; If set, not active%@AE@%%@NL@%
- mov ax,1130h %@AB@%; Get EGA information%@AE@%%@NL@%
- int 10h%@NL@%
- mov al,dl %@AB@%; Return lines per screen%@AE@%%@NL@%
- cbw%@NL@%
- %@NL@%
- noega: pop es%@NL@%
- pop bp%@NL@%
- ret%@NL@%
- isEGA ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure BinToStr (number,address)%@AE@%%@NL@%
- %@AB@%; Purpose Converts integer to string%@AE@%%@NL@%
- %@AB@%; Input Stack arguments: 1 - Number to convert; 2 - Near address for write%@AE@%%@NL@%
- %@AB@%; Output AX has characters written%@AE@%%@NL@%
- %@NL@%
- BinToStr PROC%@NL@%
- push bp%@NL@%
- mov bp,sp%@NL@%
- mov ax,[bp+6] %@AB@%; Arg 1%@AE@%%@NL@%
- mov di,[bp+4] %@AB@%; Arg 2%@AE@%%@NL@%
- %@NL@%
- sub cx,cx %@AB@%; Clear counter%@AE@%%@NL@%
- mov bx,10 %@AB@%; Divide by 10%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Convert and save on stack backwards%@AE@%%@NL@%
- %@NL@%
- getdigit: sub dx,dx %@AB@%; Clear top%@AE@%%@NL@%
- div bx %@AB@%; Divide to get last digit as remainder%@AE@%%@NL@%
- add dl,"0" %@AB@%; Convert to ASCII%@AE@%%@NL@%
- push dx %@AB@%; Save on stack%@AE@%%@NL@%
- or ax,ax %@AB@%; Quotient 0?%@AE@%%@NL@%
- loopnz getdigit %@AB@%; No? Get another%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Take off the stack and store forward%@AE@%%@NL@%
- %@NL@%
- neg cx %@AB@%; Negate and save count%@AE@%%@NL@%
- mov dx,cx%@NL@%
- putdigit: pop ax %@AB@%; Get character%@AE@%%@NL@%
- stosb %@AB@%; Store it%@AE@%%@NL@%
- loop putdigit%@NL@%
- mov ax,dx %@AB@%; Return digit count%@AE@%%@NL@%
- %@NL@%
- pop bp%@NL@%
- ret 4%@NL@%
- BinToStr ENDP%@NL@%
- %@NL@%
- %@AB@%; Procedure Retrace%@AE@%%@NL@%
- %@AB@%; Purpose Writes cell during horizontal retrace (CGA)%@AE@%%@NL@%
- %@AB@%; Input ES:DI has screen buffer position, AX has cell%@AE@%%@NL@%
- %@AB@%; Output Character to screen buffer%@AE@%%@NL@%
- %@NL@%
- Retrace PROC%@NL@%
- push bx%@NL@%
- mov bx,ax %@AB@%; Save character%@AE@%%@NL@%
- lscan2: in al,dx %@AB@%; Look in the port%@AE@%%@NL@%
- shr al,1 %@AB@%; until it goes low%@AE@%%@NL@%
- jc lscan2%@NL@%
- cli%@NL@%
- hscan2: in al,dx %@AB@%; Look in the port%@AE@%%@NL@%
- shr al,1 %@AB@%; until it goes high%@AE@%%@NL@%
- jnc hscan2%@NL@%
- mov ax,bx %@AB@%; Restore and write it%@AE@%%@NL@%
- stosw%@NL@%
- sti%@NL@%
- pop bx%@NL@%
- ret%@NL@%
- Retrace ENDP%@NL@%
- %@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%POWER2.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\MIXED\POWER2.ASM%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Default command line for BASIC: MASM /Dmodel=medium /Dlang=BASIC power2;%@AE@%%@NL@%
- %@AB@%; Default command line for C: MASM /MX /Dmodel=small /Dlang=C power2;%@AE@%%@NL@%
- %@AB@%; Default command line for FORTRAN: MASM /Dmodel=large /Dlang=FORTRAN power2;%@AE@%%@NL@%
- %@AB@%; Default command line for Pascal: MASM /Dmodel=large /Dlang=Pascal power2;%@AE@%%@NL@%
- %@NL@%
- % .MODEL model,lang%@NL@%
- INCLUDE mixed.inc%@NL@%
- %@NL@%
- % IFIDNI <lang>,<BASIC>%@NL@%
- reference EQU 1%@NL@%
- % ELSEIFIDNI <lang>,<FORTRAN>%@NL@%
- reference EQU 1%@NL@%
- ENDIF%@NL@%
- %@NL@%
- .CODE%@NL@%
- %@NL@%
- %@AB@%; Function for C, FORTRAN, Pascal, Version 4 of QuickBASIC, and%@AE@%%@NL@%
- %@AB@%; future versions of Microsoft and IBM BASIC Compilers%@AE@%%@NL@%
- %@NL@%
- IFDEF reference %@AB@%; Pass by reference for BASIC or FORTRAN%@AE@%%@NL@%
- Power2 PROC Value:PTR WORD, Count:PTR WORD%@NL@%
- %@NL@%
- pLes bx,Value %@AB@%; Load arguments passed by reference%@AE@%%@NL@%
- mov ax,FP[bx]%@NL@%
- pLes bx,Count%@NL@%
- mov cx,FP[bx]%@NL@%
- %@NL@%
- ELSE %@AB@%; Pass by value for C or Pascal%@AE@%%@NL@%
- Power2 PROC Value, Count%@NL@%
- %@NL@%
- mov ax,Value %@AB@%; Load arguments passed by value%@AE@%%@NL@%
- mov cx,Count%@NL@%
- ENDIF%@NL@%
- %@NL@%
- shl ax,cl %@AB@%; AX = AX * (2 to power of CL)%@AE@%%@NL@%
- %@AB@%; Return result in AX%@AE@%%@NL@%
- ret%@NL@%
- Power2 ENDP%@NL@%
- %@NL@%
- IFIDNI <lang>,<BASIC>%@NL@%
- %@NL@%
- %@AB@%; Subprogram for QuickBASIC, Versions 1, 2, and 3;%@AE@%%@NL@%
- %@AB@%; for the Microsoft BASIC Compiler through Version 5.36%@AE@%%@NL@%
- %@AB@%; for the IBM BASIC Compiler through Version 2.02%@AE@%%@NL@%
- %@NL@%
- Power2S PROC Value:PTR WORD, Count:PTR WORD, RetVal:PTR WORD%@NL@%
- %@NL@%
- pLes bx,Value %@AB@%; Load BASIC arguments%@AE@%%@NL@%
- mov ax,FP[bx] %@AB@%; passed by reference%@AE@%%@NL@%
- pLes bx,Count%@NL@%
- mov cx,FP[bx]%@NL@%
- %@NL@%
- shl ax,cl %@AB@%; AX = AX * (2 to power of CL)%@AE@%%@NL@%
- %@NL@%
- pLes bx,RetVal %@AB@%; Load return address%@AE@%%@NL@%
- mov FP[bx],ax %@AB@%; and store result in it%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- Power2S ENDP%@NL@%
- ENDIF %@AB@%; BASIC%@AE@%%@NL@%
- END%@NL@%
- %@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%SHOWP.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\SHOWP.ASM%@AE@%%@NL@%
- %@NL@%
- TITLE Show%@NL@%
- %@NL@%
- %@AB@%; Program SHOW.ASM%@AE@%%@NL@%
- %@AB@%; Purpose Text file displayer%@AE@%%@NL@%
- %@AB@%; Input File name from command line or prompt%@AE@%%@NL@%
- %@AB@%; Output Display file to screen%@AE@%%@NL@%
- %@NL@%
- DOSSEG%@NL@%
- .MODEL small, pascal%@NL@%
- %@NL@%
- INCL_DOSFILEMGR EQU 1 %@AB@%; Enable call groups%@AE@%%@NL@%
- INCL_DOSMEMMGR EQU 1%@NL@%
- INCL_KBD EQU 1%@NL@%
- INCL_VIO EQU 1%@NL@%
- %@NL@%
- INCLUDE os2.inc%@NL@%
- INCLUDELIB doscalls.lib%@NL@%
- %@NL@%
- .STACK 800h%@NL@%
- %@NL@%
- .DATA%@NL@%
- %@NL@%
- %@AB@%; Status line%@AE@%%@NL@%
- %@NL@%
- PUBLIC stLine, nLines, curLine%@NL@%
- curLine DW 1 %@AB@%; Current line number%@AE@%%@NL@%
- nLines DW ? %@AB@%; Lines per screen%@AE@%%@NL@%
- stLine DB "Line: 12345 "%@NL@%
- stFile DB "File: 12345678.123 "%@NL@%
- DB "Quit: Q Next: ESC Move: PGUP PGDN HOME END"%@NL@%
- %@NL@%
- %@AB@%; Variables for screen and cursor handling%@AE@%%@NL@%
- %@NL@%
- PUBLIC vMode, Cell, stAtrib, scAtrib%@NL@%
- vMode VIOMODEINFO <> %@AB@%; Structures for video and cursor data%@AE@%%@NL@%
- lvMode EQU $ - vMode %@AB@%; Length of structure%@AE@%%@NL@%
- vType DW 0 %@AB@%; Video type - 0 flag for no change%@AE@%%@NL@%
- %@NL@%
- cMode VIOCURSORINFO <>%@NL@%
- cAtrib DW -1 %@AB@%; Cursor attribute (initized to hidden)%@AE@%%@NL@%
- cStatus DB 0 %@AB@%; 0 = cursor visible, position unchanged%@AE@%%@NL@%
- %@AB@%; 1 = cursor invisible, position unchanged%@AE@%%@NL@%
- %@AB@%; 2 = cursor invisible, position changed%@AE@%%@NL@%
- %@NL@%
- stAtrib DB 030h %@AB@%; Status line color default - black on cyan%@AE@%%@NL@%
- stBW EQU 070h %@AB@%; B&W default - black on white%@AE@%%@NL@%
- Cell LABEL WORD %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
- scChar DB " " %@AB@%; Initialize to space%@AE@%%@NL@%
- scAtrib DB 017h %@AB@%; Screen color default - white on blue%@AE@%%@NL@%
- scBW EQU 007h %@AB@%; B&W default - white on black%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Variables for buffer and file handling%@AE@%%@NL@%
- %@NL@%
- PUBLIC Buffer, oBuffer, sBuffer, lBuffer%@NL@%
- Buffer LABEL DWORD%@NL@%
- oBuffer DW 0 %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
- sBuffer DW ? %@AB@%; Base of buffer (segment)%@AE@%%@NL@%
- lBuffer DW ? %@AB@%; Length of buffer%@AE@%%@NL@%
- %@NL@%
- %@AB@%; File information%@AE@%%@NL@%
- %@NL@%
- lfName EQU 66%@NL@%
- fName DB lfName DUP (" ")%@NL@%
- fHandle DW ? %@AB@%; Holds file handle on open%@AE@%%@NL@%
- fAction DW ? %@AB@%; Result of open%@AE@%%@NL@%
- fAtrib EQU 0 %@AB@%; Normal file%@AE@%%@NL@%
- fFlag EQU 1 %@AB@%; Open file if exist, fail if not exist%@AE@%%@NL@%
- %@AB@%; Read only, deny none, private, error codes, use cache, normal file%@AE@%%@NL@%
- 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@%
- fMode fModeRec <>%@NL@%
- fRead DW ? %@AB@%; Bytes read from file%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Directory information for file name search%@AE@%%@NL@%
- %@NL@%
- dHandle DW -1 %@AB@%; Directory handle%@AE@%%@NL@%
- dResult FILEFINDBUF <> %@AB@%; Structure for results%@AE@%%@NL@%
- dlResult EQU $ - dResult %@AB@%; length of result%@AE@%%@NL@%
- dCount DW 1 %@AB@%; Find one file at a time%@AE@%%@NL@%
- %@NL@%
- Prompt DB 13,10,"Enter filename: "%@NL@%
- lPrompt EQU $ - Prompt%@NL@%
- Prompt2 DB 13,10,"No such file. Try again? "%@NL@%
- lPrompt2 EQU $ - Prompt2%@NL@%
- Prompt3 DB 13,10,"File too large: "%@NL@%
- lPrompt3 EQU $ - Prompt3%@NL@%
- Prompt4 DB 13,10,"Memory problem.",13,10%@NL@%
- lPrompt4 EQU $ - Prompt4%@NL@%
- %@NL@%
- %@AB@%; Keyboard data%@AE@%%@NL@%
- %@NL@%
- kChar KBDKEYINFO <> %@AB@%; Structures for character and string input%@AE@%%@NL@%
- kStr STRINGINBUF <>%@NL@%
- kWait EQU 0 %@AB@%; Wait flag%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Call table%@AE@%%@NL@%
- %@NL@%
- kTable DB 71,72,73,79,80,81,'q','Q'%@AB@%; Key codes%@AE@%%@NL@%
- lkTable EQU $-kTable%@NL@%
- procTable DW homek %@AB@%; Table of keys and procedures%@AE@%%@NL@%
- DW upk%@NL@%
- DW pgupk%@NL@%
- DW endk%@NL@%
- DW downk%@NL@%
- DW pgdnk%@NL@%
- DW Quit%@NL@%
- DW Quit%@NL@%
- DW nonek%@NL@%
- %@NL@%
- .CODE%@NL@%
- EXTRN Pager:PROC %@AB@%; Routine in other module%@AE@%%@NL@%
- %@NL@%
- start PROC%@NL@%
- mov es, ax %@AB@%; Load environment segment%@AE@%%@NL@%
- mov di, bx%@NL@%
- %@NL@%
- %@AB@%; Throw away .EXE name%@AE@%%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Find null at end of program name%@AE@%%@NL@%
- repne scasb%@NL@%
- cmp BYTE PTR es:[di], 0%@AB@%; If double zero, there's no name%@AE@%%@NL@%
- je Prompter %@AB@%; so get from prompt%@AE@%%@NL@%
- %@NL@%
- cmp BYTE PTR es:[di], ' '%@NL@%
- jne skip1%@NL@%
- inc di %@AB@%; Skip leading space%@AE@%%@NL@%
- skip1:%@NL@%
- %@AB@%; Copy command line to file name buffer%@AE@%%@NL@%
- %@NL@%
- mov si, di %@AB@%; Filename source%@AE@%%@NL@%
- mov di, OFFSET fName %@AB@%; Name buffer destination%@AE@%%@NL@%
- mov bx, ds %@AB@%; Save segment registers%@AE@%%@NL@%
- mov dx, es%@NL@%
- mov ds, dx %@AB@%; DS = ES%@AE@%%@NL@%
- mov es, bx %@AB@%; ES = DS%@AE@%%@NL@%
- mov cx, lfName %@AB@%; Count = max file name allowed%@AE@%%@NL@%
- loop1: lodsb %@AB@%; Copy first character%@AE@%%@NL@%
- stosb%@NL@%
- cmp al,' ' %@AB@%; Terminate on space too%@AE@%%@NL@%
- je skip2%@NL@%
- or al,al%@NL@%
- loopnz loop1 %@AB@%; If not null, copy another%@AE@%%@NL@%
- skip2:%@NL@%
- mov ds, bx %@AB@%; Restore DS%@AE@%%@NL@%
- mov BYTE PTR [di-1], 0%@NL@%
- jmp FindFile%@NL@%
- %@NL@%
- NoFile: @VioWrtTTy Prompt2, lPrompt2, 0%@NL@%
- @KbdCharIn kChar, kWait, 0%@NL@%
- and kChar.kbci_chChar, 11011111b %@AB@%; Convert to uppercase%@AE@%%@NL@%
- cmp kChar.kbci_chChar, "Y"%@NL@%
- mov dHandle, -1%@NL@%
- mov dCount, 1%@NL@%
- je Prompter %@AB@%; If yes, try again%@AE@%%@NL@%
- jmp Quit %@AB@%; else quit%@AE@%%@NL@%
- %@NL@%
- Prompter: @VioWrtTTy Prompt, lPrompt, 0 %@AB@%; Else prompt for file name%@AE@%%@NL@%
- %@NL@%
- mov kStr.kbsi_cb, lfName%@NL@%
- %@NL@%
- @KbdStringIn fName, kStr, kWait, 0%@NL@%
- mov di, kStr.kbsi_cchIn %@AB@%; Null terminate%@AE@%%@NL@%
- mov fName[di], 0%@NL@%
- %@NL@%
- %@AB@%; Find first (or only) file in filespec%@AE@%%@NL@%
- %@NL@%
- FindFile: @DosFindFirst fName, dHandle, 0, dResult, dlResult, dCount, 0%@NL@%
- or ax, ax%@NL@%
- jz skip3%@NL@%
- jmp NoFile%@NL@%
- %@NL@%
- %@AB@%; Adjust for current mode and video adapter and hide cursor%@AE@%%@NL@%
- skip3: call GetVid%@NL@%
- %@NL@%
- FileLoop:%@NL@%
- mov cStatus, 2 %@AB@%; Cursor invisible, position unchanged%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Copy file name to file spec%@AE@%%@NL@%
- %@NL@%
- push ds %@AB@%; Get file name position in file spec%@AE@%%@NL@%
- @Pushc <OFFSET fName>%@NL@%
- call GetNamPos%@NL@%
- mov si, OFFSET dResult.findbuf_achName %@AB@%; Load source name%@AE@%%@NL@%
- mov es, dx %@AB@%; Load adjusted destination address%@AE@%%@NL@%
- mov di, ax %@AB@%; from return value%@AE@%%@NL@%
- sub cx, cx %@AB@%; Load file length%@AE@%%@NL@%
- mov cl, dResult.findbuf_cchName%@NL@%
- rep movsb %@AB@%; Copy to spec%@AE@%%@NL@%
- mov BYTE PTR es:[di], 0%@AB@%; Null terminate%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Copy file name to status line%@AE@%%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Load file length%@AE@%%@NL@%
- mov cl, dResult.findbuf_cchName%@NL@%
- mov bx, 12 %@AB@%; Calculate blank spaces to fill%@AE@%%@NL@%
- sub bx, cx%@NL@%
- push ds %@AB@%; ES=DS%@AE@%%@NL@%
- pop es%@NL@%
- mov si, OFFSET dResult.findbuf_achName %@AB@%; File name as source%@AE@%%@NL@%
- mov di, OFFSET stFile[6] %@AB@%; Status line as destination%@AE@%%@NL@%
- rep movsb%@NL@%
- mov al, " " %@AB@%; Fill rest of name space with blanks%@AE@%%@NL@%
- mov cx, bx%@NL@%
- rep stosb%@NL@%
- %@NL@%
- %@AB@%; Open file%@AE@%%@NL@%
- %@NL@%
- @DosOpen fName, fHandle, fAction, 0, fAtrib, fFlag, [fMode], 0%@NL@%
- or ax, ax%@NL@%
- jz skip4%@NL@%
- jmp NoFile%@NL@%
- %@NL@%
- skip4: cmp WORD PTR dResult.findbuf_cbFile[2], 0%@NL@%
- jz skip6 %@AB@%; Make sure file is less than a segment%@AE@%%@NL@%
- mov cStatus, 1 %@AB@%; Cursor invisible, position unchanged%@AE@%%@NL@%
- @VioWrtTTy Prompt3, lPrompt3, 0%@NL@%
- @VioWrtTTy <stFile + 6>, 12, 0%@NL@%
- cmp [dCount], 0 %@AB@%; Get key if there's another file%@AE@%%@NL@%
- je skip5%@NL@%
- @KbdCharIn kChar, kWait, 0%@NL@%
- skip5: jmp skip11%@NL@%
- %@NL@%
- %@AB@%; Allocate file buffer%@AE@%%@NL@%
- %@NL@%
- skip6: mov ax, WORD PTR dResult.findbuf_cbFile[0] %@AB@%; Save size%@AE@%%@NL@%
- mov lBuffer, ax%@NL@%
- mov oBuffer, 0%@NL@%
- @DosAllocSeg ax, sBuffer, 0%@NL@%
- or ax, ax%@NL@%
- jz skip7%@NL@%
- mov cStatus, 1 %@AB@%; Cursor invisible, position unchanged%@AE@%%@NL@%
- @VioWrtTTy Prompt4, lPrompt4, 0%@NL@%
- jmp Quit%@NL@%
- %@NL@%
- %@AB@%; Read the file into the buffer%@AE@%%@NL@%
- %@NL@%
- skip7: @DosRead [fHandle], [Buffer], [lBuffer], fRead%@NL@%
- or ax, ax%@NL@%
- jz skip8%@NL@%
- jmp NoFile%@NL@%
- %@NL@%
- %@AB@%; Search back for EOF marker and adjust if necessary%@AE@%%@NL@%
- %@NL@%
- skip8: mov di, [fRead] %@AB@%; Load file length%@AE@%%@NL@%
- dec di %@AB@%; and adjust%@AE@%%@NL@%
- mov es, [sBuffer] %@AB@%; Save ES and load buffer segment%@AE@%%@NL@%
- std %@AB@%; Look backward for 255 characters%@AE@%%@NL@%
- mov cx, 0FFh%@NL@%
- cmp cx, di%@NL@%
- jb skip9%@NL@%
- mov cx, di%@NL@%
- skip9: mov al, 1Ah %@AB@%; Search for EOF marker%@AE@%%@NL@%
- repe scasb%@NL@%
- cld%@NL@%
- jcxz skip10 %@AB@%; If none, we're OK%@AE@%%@NL@%
- inc di %@AB@%; else adjust and save file size%@AE@%%@NL@%
- mov [lBuffer], di%@NL@%
- %@NL@%
- %@AB@%; Show a screen of text and allow commands%@AE@%%@NL@%
- %@NL@%
- skip10: call Show%@NL@%
- %@NL@%
- %@NL@%
- skip11: @DosClose [fHandle] %@AB@%; Close file%@AE@%%@NL@%
- %@NL@%
- @DosFreeSeg [sBuffer] %@AB@%; Free memofy%@AE@%%@NL@%
- %@NL@%
- @DosFindNext [dHandle], dResult, dlResult, dCount %@AB@%; Get next file%@AE@%%@NL@%
- %@NL@%
- cmp [dCount], 0 %@AB@%; Quit if no next file%@AE@%%@NL@%
- jz exit%@NL@%
- jmp FileLoop%@NL@%
- %@NL@%
- exit: jmp Quit%@NL@%
- start ENDP%@NL@%
- %@NL@%
- Show PROC%@NL@%
- %@NL@%
- %@AB@%; Display first page%@AE@%%@NL@%
- %@NL@%
- @Pushc 0 %@AB@%; Start at 0%@AE@%%@NL@%
- call Pager%@NL@%
- %@NL@%
- %@AB@%; Handle keys%@AE@%%@NL@%
- %@NL@%
- nextkey: @KbdCharIn kChar, kWait, 0 %@AB@%; Get a key and load to register%@AE@%%@NL@%
- mov al, kChar.kbci_chChar%@NL@%
- or al, al %@AB@%; Is ascii code null?%@AE@%%@NL@%
- jz skip1 %@AB@%; Yes? Load scan%@AE@%%@NL@%
- cmp al, 0E0h %@AB@%; Extended key on extended keyboard?%@AE@%%@NL@%
- jne skip2 %@AB@%; No? Got code%@AE@%%@NL@%
- skip1: mov al, kChar.kbci_chScan%@NL@%
- skip2:%@NL@%
- cmp al, 27 %@AB@%; Is it ESCAPE?%@AE@%%@NL@%
- je Exit %@AB@%; Yes? Get out for next file%@AE@%%@NL@%
- %@NL@%
- push ds %@AB@%; ES = DS%@AE@%%@NL@%
- pop es%@NL@%
- mov di, OFFSET kTable %@AB@%; Load address and length of key list%@AE@%%@NL@%
- mov cx, lkTable + 1%@NL@%
- repne scasb %@AB@%; Find position and point to key%@AE@%%@NL@%
- sub di, (OFFSET kTable) + 1%@NL@%
- shl di, 1 %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
- call procTable[di] %@AB@%; Call procedure%@AE@%%@NL@%
- jmp nextkey%@NL@%
- %@NL@%
- exit: ret%@NL@%
- Show ENDP%@NL@%
- %@NL@%
- homek: mov oBuffer, 0 %@AB@%; HOME - set position to 0%@AE@%%@NL@%
- push oBuffer%@NL@%
- mov curLine, 1%@NL@%
- call Pager%@NL@%
- retn%@NL@%
- %@NL@%
- upk: @Pushc -1 %@AB@%; UP - scroll back 1 line%@AE@%%@NL@%
- call Pager%@NL@%
- retn%@NL@%
- %@NL@%
- pgupk: mov ax, nLines %@AB@%; PGUP - Page back%@AE@%%@NL@%
- neg ax%@NL@%
- push ax%@NL@%
- call Pager%@NL@%
- retn%@NL@%
- %@NL@%
- endk: mov ax, lBuffer %@AB@%; END - Get last byte of file%@AE@%%@NL@%
- mov oBuffer, ax %@AB@%; Make it the file position%@AE@%%@NL@%
- mov curLine, -1 %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
- mov ax, nLines %@AB@%; Page back%@AE@%%@NL@%
- neg ax%@NL@%
- push ax%@NL@%
- call Pager%@NL@%
- retn%@NL@%
- %@NL@%
- downk: @Pushc 1 %@AB@%; DOWN - scroll forward 1 line%@AE@%%@NL@%
- call Pager%@NL@%
- retn%@NL@%
- %@NL@%
- pgdnk: push nLines %@AB@%; PGDN - page forward%@AE@%%@NL@%
- call Pager%@NL@%
- retn%@NL@%
- %@NL@%
- nonek: retn %@AB@%; Ignore unknown key%@AE@%%@NL@%
- %@NL@%
- GetVid PROC%@NL@%
- %@NL@%
- mov vMode.viomi_cb, lvMode%@NL@%
- @VioGetMode vMode, 0 %@AB@%; Get video mode%@AE@%%@NL@%
- %@NL@%
- sub ax, ax %@AB@%; Clear AH%@AE@%%@NL@%
- mov al, vMode.viomi_fbType %@AB@%; Put type in register%@AE@%%@NL@%
- mov vType, ax %@AB@%; and save%@AE@%%@NL@%
- test al, 1 %@AB@%; Test for color%@AE@%%@NL@%
- jz skip1 %@AB@%; No? Mono%@AE@%%@NL@%
- test al, 100b %@AB@%; Test for color burst on%@AE@%%@NL@%
- jz skip2 %@AB@%; Yes? Color%@AE@%%@NL@%
- skip1: mov stAtrib, stBW %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
- mov scAtrib, scBW %@AB@%; and screen background%@AE@%%@NL@%
- %@NL@%
- skip2: @VioGetCurType cMode, 0 %@AB@%; Get cursor mode%@AE@%%@NL@%
- mov ax, cMode.vioci_attr %@AB@%; Save attribute%@AE@%%@NL@%
- xchg cAtrib, ax%@NL@%
- mov cMode.vioci_attr, ax %@AB@%; Set hidden cursor attribute%@AE@%%@NL@%
- mov ax, vMode.viomi_row%@AB@%; Get number of rows and adjust%@AE@%%@NL@%
- dec ax%@NL@%
- mov nLines, ax%@NL@%
- %@NL@%
- @VioSetCurType cMode, 0 %@AB@%; Hide cursor%@AE@%%@NL@%
- %@NL@%
- ret%@NL@%
- GetVid ENDP%@NL@%
- %@NL@%
- GetNamPos PROC USES di si, argline:FAR PTR BYTE%@NL@%
- %@NL@%
- les di, argline %@AB@%; Load address of file name%@AE@%%@NL@%
- mov si, di %@AB@%; Save copy%@AE@%%@NL@%
- %@NL@%
- sub cx, cx %@AB@%; Ignore count%@AE@%%@NL@%
- sub dx, dx %@AB@%; Use DX as found flag%@AE@%%@NL@%
- dec di %@AB@%; Adjust%@AE@%%@NL@%
- mov ax, "\" %@AB@%; Search for backslash%@AE@%%@NL@%
- loop1: scasb %@AB@%; Get next character%@AE@%%@NL@%
- jz skip1 %@AB@%; If backslash, set flag and save%@AE@%%@NL@%
- cmp BYTE PTR es:[di], 0%@AB@%; If end of name, done%@AE@%%@NL@%
- je skip2%@NL@%
- loop loop1 %@AB@%; If neither, continue%@AE@%%@NL@%
- skip1: mov si, di %@AB@%; Save position%@AE@%%@NL@%
- inc dx %@AB@%; Set flag to true%@AE@%%@NL@%
- loop loop1%@NL@%
- %@NL@%
- skip2: or dx, dx %@AB@%; Found backslash?%@AE@%%@NL@%
- je skip3 %@AB@%; If none, search for colon%@AE@%%@NL@%
- mov ax, si %@AB@%; else return position in DX:AX%@AE@%%@NL@%
- jmp SHORT exit%@NL@%
- %@NL@%
- skip3: neg cx %@AB@%; Adjust count%@AE@%%@NL@%
- mov di, si %@AB@%; Restore start of name%@AE@%%@NL@%
- mov ax, ":" %@AB@%; Search for colon%@AE@%%@NL@%
- repne scasb%@NL@%
- jnz skip4 %@AB@%; If no colon, restore original%@AE@%%@NL@%
- mov ax, di %@AB@%; else return position in DX:AX%@AE@%%@NL@%
- jmp SHORT exit%@NL@%
- %@NL@%
- skip4: mov ax, si %@AB@%; Return original address%@AE@%%@NL@%
- %@NL@%
- exit: mov dx, es%@NL@%
- ret%@NL@%
- GetNamPos ENDP%@NL@%
- %@NL@%
- Quit PROC%@NL@%
- %@NL@%
- mov scAtrib, 7 %@AB@%; Restore cell attribute for clear screen%@AE@%%@NL@%
- %@NL@%
- cmp cStatus, 1 %@AB@%; Check cursor status%@AE@%%@NL@%
- jg skip1 %@AB@%; 2 - Make cursor visible on last line%@AE@%%@NL@%
- je skip1 %@AB@%; 1 - Make cursor visible%@AE@%%@NL@%
- jmp SHORT skip3 %@AB@%; 0 - Leave cursor as is%@AE@%%@NL@%
- %@NL@%
- skip1: @VioSetCurPos [nLines], 0, 0 %@AB@%; Restore cursor on last line%@AE@%%@NL@%
- @VioScrollDn [nLines], 0, [nLines], 79, 1, Cell, 0%@NL@%
- %@NL@%
- %@NL@%
- skip2: mov ax, cAtrib %@AB@%; Restore cursor attribute%@AE@%%@NL@%
- mov cMode.vioci_attr, ax%@NL@%
- @VioSetCurType cMode, 0%@NL@%
- %@NL@%
- skip3: @DosExit 1, 0 %@AB@%; Quit%@AE@%%@NL@%
- %@NL@%
- Quit ENDP%@NL@%
- %@NL@%
- END start%@NL@%
- %@NL@%
- %@NL@%
- %@2@%%@AH@%SHOWR.ASM%@AE@%%@EH@%%@NL@%
- %@AS@%CD-ROM Disc Path: \SAMPCODE\MASM\MASM5\SHOWR.ASM%@AE@%%@NL@%
- %@NL@%
- PAGE 60,132%@NL@%
- TITLE SHOW%@NL@%
- %@NL@%
- %@AB@%; Program SHOW.ASM%@AE@%%@NL@%
- %@AB@%; Purpose Text file displayer%@AE@%%@NL@%
- %@AB@%; Input File name from command line or prompt%@AE@%%@NL@%
- %@AB@%; Output Display file to screen%@AE@%%@NL@%
- %@NL@%
- DOSSEG%@NL@%
- .MODEL small%@NL@%
- %@NL@%
- INCLUDE dos.inc%@NL@%
- INCLUDE bios.inc%@NL@%
- %@NL@%
- .STACK 100h%@NL@%
- %@NL@%
- .DATA%@NL@%
- %@NL@%
- %@AB@%; Status line%@AE@%%@NL@%
- %@NL@%
- PUBLIC statline,linenum%@NL@%
- statline DB " Line: "%@NL@%
- statfile DB " File: "%@NL@%
- stathelp DB " Quit: ESC Move: PGUP PGDN HOME END "%@NL@%
- linenum DW 1%@NL@%
- %@NL@%
- %@AB@%; Variables for screen handling%@AE@%%@NL@%
- %@NL@%
- PUBLIC cell,rows,columns,vidadr,statatr,scrnatr,cga%@NL@%
- cell LABEL WORD %@AB@%; Cell (character and attribute)%@AE@%%@NL@%
- char DB " " %@AB@%; Initialize to space%@AE@%%@NL@%
- attr DB ? %@AB@%; Attribute%@AE@%%@NL@%
- %@NL@%
- columns EQU 80 %@AB@%; Number of columns%@AE@%%@NL@%
- rows DW 24 %@AB@%; Number of rows - status line takes one more%@AE@%%@NL@%
- mode DB ? %@AB@%; Initial mode%@AE@%%@NL@%
- pag DB ? %@AB@%; Initial display page%@AE@%%@NL@%
- newvid DB 0 %@AB@%; Video change flag%@AE@%%@NL@%
- cga DB 1 %@AB@%; CGA flag - default yes%@AE@%%@NL@%
- %@NL@%
- vidadr DW 0B800h %@AB@%; Video buffer address - default CGA%@AE@%%@NL@%
- mono EQU 0B000h %@AB@%; Monochrome address%@AE@%%@NL@%
- statatr DB 030h %@AB@%; Color default - black on cyan%@AE@%%@NL@%
- bwstat EQU 070h %@AB@%; B&W default - black on white%@AE@%%@NL@%
- scrnatr DB 017h %@AB@%; Color default - white on blue%@AE@%%@NL@%
- bwscrn EQU 007h %@AB@%; B&W default - white on black%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Variables for buffer and file handling%@AE@%%@NL@%
- %@NL@%
- PUBLIC buffer,pbuffer,sbuffer,fsize,namebuf%@NL@%
- buffer LABEL DWORD%@NL@%
- pbuffer DW 0 %@AB@%; Position in buffer (offset)%@AE@%%@NL@%
- sbuffer DW ? %@AB@%; Base of buffer (segment)%@AE@%%@NL@%
- lbuffer DW ? %@AB@%; Length of buffer%@AE@%%@NL@%
- fhandle DW ? %@AB@%; Holds file handle on open%@AE@%%@NL@%
- fsize DW ? %@AB@%; File size after dosopen%@AE@%%@NL@%
- %@NL@%
- prompt DB 13,10,13,10,"Enter filename: $"%@NL@%
- prompt2 DB 13,10,"File problem. Try again? $"%@NL@%
- namebuf DB 66,?%@NL@%
- filename DB 66 DUP (0) %@AB@%; Buffer for file name%@AE@%%@NL@%
- %@NL@%
- err1 DB 13,10,"Must have DOS 2.0 or higher",13,10,"$"%@NL@%
- err2 DB 13,10,"File too big",13,10,"$"%@NL@%
- %@NL@%
- %@AB@%; Call table%@AE@%%@NL@%
- %@NL@%
- exkeys DB 71,72,73,79,80,81 %@AB@%; Extended key codes%@AE@%%@NL@%
- lexkeys EQU $-exkeys %@AB@%; Table of keys%@AE@%%@NL@%
- extable DW homek%@NL@%
- DW upk%@NL@%
- DW pgupk%@NL@%
- DW endk%@NL@%
- DW downk%@NL@%
- DW pgdnk%@NL@%
- DW nonek%@NL@%
- %@NL@%
- .CODE%@NL@%
- EXTRN pager:PROC,isEGA:PROC %@AB@%; Routines in other module%@AE@%%@NL@%
- start: mov ax,@DATA %@AB@%; Initialize data segment%@AE@%%@NL@%
- mov ds,ax%@NL@%
- %@NL@%
- cli %@AB@%; Turn off interrupts%@AE@%%@NL@%
- mov ss,ax %@AB@%; Make SS and%@AE@%%@NL@%
- mov sp,OFFSET STACK %@AB@%; SP relative to DGROUP%@AE@%%@NL@%
- sti%@NL@%
- %@NL@%
- %@AB@%; Adjust memory allocation%@AE@%%@NL@%
- %@NL@%
- mov bx,sp %@AB@%; Convert stack pointer to paragraphs%@AE@%%@NL@%
- mov cl,4 %@AB@%; to get stack size%@AE@%%@NL@%
- shr bx,cl%@NL@%
- add ax,bx %@AB@%; Add SS to get end of program%@AE@%%@NL@%
- mov bx,es %@AB@%; Get start of program%@AE@%%@NL@%
- sub ax,bx %@AB@%; Subtract start from end%@AE@%%@NL@%
- @ModBlok ax %@AB@%; Release memory after program%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Allocate dynamic memory for file buffer%@AE@%%@NL@%
- %@NL@%
- @GetBlok 0FFFh %@AB@%; Try to allocate 64K%@AE@%%@NL@%
- mov sbuffer,ax %@AB@%; Save buffer segment%@AE@%%@NL@%
- mov lbuffer,bx %@AB@%; Save actual length allocated%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Check DOS%@AE@%%@NL@%
- %@NL@%
- @GetVer %@AB@%; Get DOS version%@AE@%%@NL@%
- cmp al,2 %@AB@%; Requires DOS 2.0%@AE@%%@NL@%
- jge video%@NL@%
- @DispStr err1 %@AB@%; else error and quit%@AE@%%@NL@%
- int 20h%@NL@%
- %@NL@%
- %@AB@%; Adjust for current mode and and video adapter%@AE@%%@NL@%
- %@NL@%
- video: call isEGA %@AB@%; EGA (or VGA)?%@AE@%%@NL@%
- or ax,ax %@AB@%; If 0 must be CGA or MA%@AE@%%@NL@%
- je modechk %@AB@%; Leave default%@AE@%%@NL@%
- mov rows,ax %@AB@%; Load rows%@AE@%%@NL@%
- dec cga %@AB@%; Not CGA%@AE@%%@NL@%
- %@NL@%
- modechk: @GetMode %@AB@%; Get video mode%@AE@%%@NL@%
- mov mode,al %@AB@%; Save initial mode and page%@AE@%%@NL@%
- mov pag,bh%@NL@%
- mov dl,al %@AB@%; Work on copy%@AE@%%@NL@%
- cmp dl,7 %@AB@%; Is it mono 7?%@AE@%%@NL@%
- je loadmono %@AB@%; Yes? Set mono%@AE@%%@NL@%
- cmp dl,15 %@AB@%; Is it mono 15?%@AE@%%@NL@%
- jne graphchk %@AB@%; No? Check graphics%@AE@%%@NL@%
- loadmono: mov vidadr,mono %@AB@%; Load mono address%@AE@%%@NL@%
- mov statatr,bwstat %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
- mov scrnatr,bwscrn %@AB@%; and screen background%@AE@%%@NL@%
- dec cga %@AB@%; Not CGA%@AE@%%@NL@%
- cmp al,15 %@AB@%; Is it mono 15?%@AE@%%@NL@%
- jne cmdchk %@AB@%; No? Done%@AE@%%@NL@%
- mov dl,7 %@AB@%; Yes? Set standard mono%@AE@%%@NL@%
- jmp SHORT chmode%@NL@%
- %@NL@%
- graphchk: cmp dl,7 %@AB@%; 7 or higher?%@AE@%%@NL@%
- jg color %@AB@%; 8 to 14 are color (7 and 15 done)%@AE@%%@NL@%
- cmp dl,4 %@AB@%; 4 or higher?%@AE@%%@NL@%
- jg bnw %@AB@%; 5 and 6 are probably black and white%@AE@%%@NL@%
- je color %@AB@%; 4 is color%@AE@%%@NL@%
- test dl,1 %@AB@%; Even?%@AE@%%@NL@%
- jz bnw %@AB@%; 0 and 2 are black and white%@AE@%%@NL@%
- color: %@AB@%; 1 and 3 are color%@AE@%%@NL@%
- cmp dl,3 %@AB@%; 3?%@AE@%%@NL@%
- je cmdchk %@AB@%; Yes? Done%@AE@%%@NL@%
- mov dl,3 %@AB@%; Change mode to 3%@AE@%%@NL@%
- jmp SHORT chmode%@NL@%
- %@NL@%
- bnw: mov statatr,bwstat %@AB@%; Set B&W defaults for status line%@AE@%%@NL@%
- mov scrnatr,bwscrn %@AB@%; and screen background%@AE@%%@NL@%
- cmp dl,2 %@AB@%; 2?%@AE@%%@NL@%
- je cmdchk %@AB@%; Yes? Done%@AE@%%@NL@%
- mov dl,2 %@AB@%; Make it 2%@AE@%%@NL@%
- %@NL@%
- chmode: @SetMode dl %@AB@%; Set video mode%@AE@%%@NL@%
- @SetPage 0 %@AB@%; Set video page%@AE@%%@NL@%
- mov newvid,1 %@AB@%; Set flag%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Try to open command line file%@AE@%%@NL@%
- %@NL@%
- cmdchk: mov bl,es:[80h] %@AB@%; Get length%@AE@%%@NL@%
- sub bh,bh%@NL@%
- mov WORD PTR es:[bx+81h],0%@AB@%; Convert to ASCIIZ%@AE@%%@NL@%
- push ds%@NL@%
- @OpenFil 82h,0,es %@AB@%; Open argument%@AE@%%@NL@%
- pop ds%@NL@%
- jc getname %@AB@%; If error, get from prompt%@AE@%%@NL@%
- mov fhandle,ax %@AB@%; else save handle%@AE@%%@NL@%
- push ds%@NL@%
- @GetFirst 82h,,es %@AB@%; Let DOS convert to file name%@AE@%%@NL@%
- pop ds%@NL@%
- jnc opened %@AB@%; If OK file is open%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Prompt for file%@AE@%%@NL@%
- %@NL@%
- getname: @DispStr prompt %@AB@%; Prompt for file%@AE@%%@NL@%
- @GetStr namebuf,0 %@AB@%; Get response as ASCIIZ%@AE@%%@NL@%
- @OpenFil filename,0 %@AB@%; Try to open response%@AE@%%@NL@%
- jc badfile %@AB@%; If successful, continue%@AE@%%@NL@%
- mov fhandle,ax %@AB@%; Save handle%@AE@%%@NL@%
- @GetFirst filename %@AB@%; Let DOS convert to file name%@AE@%%@NL@%
- jnc opened %@AB@%; If OK, file is opened%@AE@%%@NL@%
- %@NL@%
- badfile: @DispStr prompt2 %@AB@%; else prompt to try again%@AE@%%@NL@%
- @GetKey 0,1,0%@NL@%
- and al,11011111b %@AB@%; Convert key to uppercase%@AE@%%@NL@%
- cmp al,"Y" %@AB@%; If yes,%@AE@%%@NL@%
- je getname %@AB@%; try again%@AE@%%@NL@%
- jmp quit %@AB@%; else quit%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Copy file name to status line%@AE@%%@NL@%
- %@NL@%
- opened: mov si,9Eh %@AB@%; Load FCB as as source%@AE@%%@NL@%
- mov di,OFFSET statfile[7] %@AB@%; Load status line as destination%@AE@%%@NL@%
- mov al,es:[si] %@AB@%; Load first byte%@AE@%%@NL@%
- inc si%@NL@%
- copy: mov [di],al %@AB@%; Save and load bytes until 0%@AE@%%@NL@%
- inc di%@NL@%
- mov al,es:[si]%@NL@%
- inc si%@NL@%
- or al,al %@AB@%; Check for 0%@AE@%%@NL@%
- loopne copy%@NL@%
- %@NL@%
- %@AB@%; Check file size%@AE@%%@NL@%
- %@NL@%
- @GetFilSz fhandle %@AB@%; Get file size%@AE@%%@NL@%
- %@NL@%
- or dx,dx %@AB@%; Larger than 64K?%@AE@%%@NL@%
- jne big %@AB@%; Yes? Too big%@AE@%%@NL@%
- mov fsize,ax %@AB@%; Save file size%@AE@%%@NL@%
- mov cx,4 %@AB@%; Convert to paragraphs%@AE@%%@NL@%
- shr ax,cl%@NL@%
- cmp ax,lbuffer %@AB@%; Is it larger than buffer%@AE@%%@NL@%
- jle fileread %@AB@%; No? Continue%@AE@%%@NL@%
- %@NL@%
- big: @DispStr err2 %@AB@%; else error%@AE@%%@NL@%
- @Exit 2%@NL@%
- %@NL@%
- fileread: push ds%@NL@%
- @Read buffer,fsize,fhandle %@AB@%; Read file%@AE@%%@NL@%
- pop ds%@NL@%
- jnc readok %@AB@%; If no read error continue%@AE@%%@NL@%
- jmp getname %@AB@%; else try again%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Search back for EOF marker and adjust if necessary%@AE@%%@NL@%
- %@NL@%
- readok: mov di,ax %@AB@%; Load file length%@AE@%%@NL@%
- push es %@AB@%; Save ES and load buffer segment%@AE@%%@NL@%
- mov es,sbuffer%@NL@%
- std %@AB@%; Look backward for 255 characters%@AE@%%@NL@%
- mov cx,0FFh%@NL@%
- mov al,1Ah %@AB@%; Search for EOF marker%@AE@%%@NL@%
- repne scasb%@NL@%
- cld%@NL@%
- jcxz noeof %@AB@%; If none, we're OK%@AE@%%@NL@%
- inc di %@AB@%; else adjust and save file size%@AE@%%@NL@%
- mov fsize,di%@NL@%
- %@NL@%
- noeof: pop es%@NL@%
- @SetCurPos 0,43 %@AB@%; Turn off cursor by moving off screen%@AE@%%@NL@%
- %@NL@%
- %@AB@%; Display first page%@AE@%%@NL@%
- %@NL@%
- xor ax,ax %@AB@%; Start at 0%@AE@%%@NL@%
- push ax%@NL@%
- firstpg: call pager%@NL@%
- %@NL@%
- %@AB@%; Handle keys%@AE@%%@NL@%
- %@NL@%
- nextkey: @GetKey 0,0,0 %@AB@%; Get a key%@AE@%%@NL@%
- nextkey2: cmp al,0 %@AB@%; Is it a null?%@AE@%%@NL@%
- je extended %@AB@%; Yes? Must be extended code%@AE@%%@NL@%
- %@NL@%
- cmp al,27 %@AB@%; Is it ESCAPE?%@AE@%%@NL@%
- jne nextkey %@AB@%; No? Ignore unknown command%@AE@%%@NL@%
- %@NL@%
- quit: @ClosFil fhandle %@AB@%; Yes? Close file%@AE@%%@NL@%
- @FreeBlok sbuffer %@AB@%; Release buffer%@AE@%%@NL@%
- cmp newvid,1 %@AB@%; Restore video?%@AE@%%@NL@%
- jne thatsall %@AB@%; No?%@AE@%%@NL@%
- @SetMode mode %@AB@%; Restore video mode, page, and cursor%@AE@%%@NL@%
- @SetPage pag%@NL@%
- thatsall: mov dx,rows %@AB@%; Load last row and first column%@AE@%%@NL@%
- xchg dl,dh%@NL@%
- mov cx,dx %@AB@%; Make row the same%@AE@%%@NL@%
- mov dl,79%@NL@%
- @Scroll 0 %@AB@%; Clear last line%@AE@%%@NL@%
- sub dl,dl%@NL@%
- @SetCurPos %@AB@%; Set cursor%@AE@%%@NL@%
- %@NL@%
- @Exit 0 %@AB@%; Quit%@AE@%%@NL@%
- %@NL@%
- extended: @GetKey 0,0,0 %@AB@%; Get extended code%@AE@%%@NL@%
- push es%@NL@%
- push ds %@AB@%; Load DS into ES%@AE@%%@NL@%
- pop es%@NL@%
- mov di,OFFSET exkeys %@AB@%; Load address and length of key list%@AE@%%@NL@%
- mov cx,lexkeys+1%@NL@%
- repne scasb %@AB@%; Find position%@AE@%%@NL@%
- pop es%@NL@%
- sub di,(OFFSET exkeys)+1 %@AB@%; Point to key%@AE@%%@NL@%
- shl di,1 %@AB@%; Adjust pointer for word addresses%@AE@%%@NL@%
- call extable[di] %@AB@%; Call procedure%@AE@%%@NL@%
- jmp nextkey%@NL@%
- %@NL@%
- homek: mov pbuffer,0 %@AB@%; HOME - set position to 0%@AE@%%@NL@%
- push pbuffer%@NL@%
- mov linenum,1%@NL@%
- call pager%@NL@%
- retn%@NL@%
- %@NL@%
- upk: mov ax,-1 %@AB@%; UP - scroll back 1 line%@AE@%%@NL@%
- push ax%@NL@%
- call pager%@NL@%
- retn%@NL@%
- %@NL@%
- pgupk: mov ax,rows %@AB@%; PGUP - Page back%@AE@%%@NL@%
- neg ax%@NL@%
- push ax%@NL@%
- call pager%@NL@%
- retn%@NL@%
- %@NL@%
- endk: mov ax,fsize %@AB@%; END - Get last byte of file%@AE@%%@NL@%
- mov pbuffer,ax %@AB@%; Make it the file position%@AE@%%@NL@%
- mov linenum,-1 %@AB@%; Set illegal line number as flag%@AE@%%@NL@%
- mov ax,rows %@AB@%; Page back%@AE@%%@NL@%
- neg ax%@NL@%
- push ax%@NL@%
- call pager%@NL@%
- retn%@NL@%
- %@NL@%
- downk: mov ax,1 %@AB@%; DOWN - scroll forward 1 line%@AE@%%@NL@%
- push ax%@NL@%
- call pager%@NL@%
- retn%@NL@%
- %@NL@%
- pgdnk: push rows %@AB@%; PGDN - page forward%@AE@%%@NL@%
- call pager%@NL@%
- retn%@NL@%
- %@NL@%
- nonek: retn %@AB@%; Ignore unknown key%@AE@%%@NL@%
- %@NL@%
- END start%@NL@%
- %@NL@%
-