dos_compilers/Microsoft QuickC v2/SAMPLES/MISCDEMO.ASM
2024-07-02 06:32:02 -07:00

1019 lines
30 KiB
NASM
Raw Blame History

;* MISCDEMO - Invokes many of the QuickAssembler example procedures, most of
;* them demonstrating assembly language instructions and calls to the system
;* BIOS. MISCDEMO demonstrates how to:
;*
;* - determine hardware information
;* - display time and date while waiting for keystrokes
;* - play notes of any frequency on the speaker
;* - change the line mode for EGA or VGA systems
;* - create non-destructive pop-up windows
;* - execute another program as a child process
;* - create primitive handlers for Interrupts 1Bh, 23h, and 24h
;* - use C-callable procedures in assembly programs
;* - use simplified segment directives
;* - write model-independent procedures
;* - declare and initialize data with DUP, DB, DW, and DD
;* - create structures with the STRUCT directive
;* - declare macros
;* - set up a dispatch table
;*
;* MISCDEMO.EXE is built from the following files:
;* MISCDEMO.ASM - Main program
;* MISC.ASM - QuickAssembler procedures for MISCDEMO
;* COMMON.ASM - QuickAssembler procedures shared by other example programs
;* DEMO.INC - Include file with macros, structure declarations
;*
;* Procedures: GetVidConfig GetCurPos VeriPrint GetPSP
;* WinOpen VeriAnsi VeriCop GetVer
;* WinClose StrWrite SetLineMode NewBlockSize
;* SetCurSize GetKeyClock BinToHex IntToAsc
;* SetCurPos GetShift Sound Colors
;* GetCurSize GetMem Pause Exec
;* WriteTTY Initialize
DOSSEG
.MODEL small, c
INCLUDE demo.inc
PGMSIZE EQU 500h ; Maximum program size in paragraphs
F1 EQU 59 ; Extended code for first option key
F7 EQU 65 ; Extended code for last option key
CLKRW EQU 0 ; Row for on-screen clock
CLKCL EQU 62 ; Column for on-screen clock
;* Box - Macro to color portion of screen for effect. Not to be confused with
;* the WinOpen procedure, which is far more capable.
;*
;* Params: row1 - Screen row at top of box
;* col1 - Screen column at left side of box
;* row2 - Screen row at bottom of box
;* col2 - Screen column at right side of box
Box MACRO row1, col1, row2, col2
LOCAL sk
mov ax, 0600h ;; Scroll service
mov bh, filmono ;; Fill attribute
cmp vconfig.adapter, MDA ;; Monochrome?
je sk ;; Yes? Continue
mov bh, filcolr ;; No? Use color fill attribute
sk: mov ch, row1
mov cl, col1 ;; CX = row/col for upper left
mov dh, row2
mov dl, col2 ;; DX = row/col for lower right
int 10h ;; Blank window area on screen
ENDM
.STACK
.DATA
oldmode DB ? ; Original video mode
oldcurs DW ? ; Original cursor coordinates
keepseg DW ? ; Segment addr, orig screen
buffer DB BUFFER_SIZE DUP(?) ; Buffer for diskette read
filcolr DB 1Fh, 20h, 3Bh, 4Eh ; Color fill attributes
filmono DB 70h, 89h, 78h, 1 ; Monochrome fill attributes
fill DB 7 ; Default attribute for menu
filsub DB ? ; Fore/background colors in submenu
presmsg DB '. . . press a key to continue', 0
yes DB 'yes'
no DB 'no '
; Main menu text
menu1 DB '*** QuickAssembler Misc Demonstration Program ***', 0
menu2 DB 'F1 System Configuration', 0
menu3 DB 'F2 Speaker Test', 0
menu4 DB 'F3 Toggle Line Mode', 0
menu5 DB 'F4 Windows', 0
menu6 DB 'F5 Screen Colors', 0
menu7 DB 'F6 Exec Program', 0
menu8 DB 'Select an option, or press ESC to quit:', 0
; Option F1 - System Configuration
monostr DB 'monochrome'
clrstr DB 'color '
adapstr DB 'MDA CGA MCGAEGA VGA '
vidmsg1 DB 'Adapter: xxxx', 0
vidmsg2 DB 'Display: xxxxxxxxxx', 0
vidmsg3 DB 'Mode: xx', 0
vidmsg4 DB 'Rows: xx', 0
memmsg1 DB 'Total memory: xxxx Kb', 0
memmsg2 DB 'Available memory: xxxx Kb', 0
prnmsg DB 'Printer ready: xxx', 0
ansimsg DB 'ANSI driver installed: xxx', 0
copmsg DB 'Coprocessor installed: xxx', 0
LEN1 EQU $ - copmsg - 4
; Option F3 - Toggle Line Mode
linemsg DB 'Line mode reset available only for EGA or VGA', 0
; Option F4 - Windows
winmsg DB 'WINDOW x', 0
LEN3 EQU $ - winmsg - 2
; Option F5 Screen Colors
cmsg1 DB 'Toggle Step', 0
cmsg2 DB '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>', 0
cmsg3 DB 'B blink ', 27, 26, ' foreground', 0
cmsg4 DB 'I intensity ', 24, 25, ' background', 0
cmsg5 DB 'Foreground: press F, then color number 0-7', 0
cmsg6 DB 'Background: press A, then color number 0-7', 0
cmsg7 DB 'Color Numbers', 0
cmsg8 DB '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>', 0
cmsg9 DB '0 black 4 red', 0
cmsg10 DB '1 blue 5 magenta', 0
cmsg11 DB '2 green 6 brown', 0
cmsg12 DB '3 cyan 7 white', 0
cmsg13 DB 'Toggle', 0
cmsg14 DB '<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>', 0
cmsg15 DB 'B blink', 0
cmsg16 DB 'I intensity', 0
cmsg17 DB 'U underline', 0
cmsg18 DB 'R reverse', 0
; Option F6 - Exec Program
retmsg DB 'Return code: '
recode DB 6 DUP (?) ; ASCII string for return code
execmsg DB 'Enter program file spec (including .COM or .EXE):', 0
tailmsg DB 'Enter command-line argument(s):', 0
fspec DB 50, 50 DUP (?) ; File specification (max length = 50)
tail DB 50, 50 DUP (?) ; Command-line tail (max length = 50)
fcblk1 DB 0 ; Allocate space for 1st FCB
DB 11 DUP (?)
DB 25 DUP (0)
fcblk2 DB 0 ; Allocate space for 2nd FCB
DB 11 DUP (?)
DB 25 DUP (0)
pb parmblk <> ; Parameter block structure
; Initialize dispatch table with offsets for internal procedures.
table DW get_config, speaker, set_lines
DW pop_windows, set_attrs, exec_pgm
.CODE
EXTRN GetVidConfig:PROC, GetCurPos:PROC, VeriPrint:PROC
EXTRN GetPSP:PROC, WinOpen:PROC, VeriAnsi:PROC
EXTRN VeriCop:PROC, WinClose:PROC, WriteTTY:PROC
EXTRN StrWrite:PROC, SetLineMode:PROC, NewBlockSize:PROC
EXTRN SetCurSize:PROC, GetKeyClock:PROC, BinToHex:PROC
EXTRN SetCurPos:PROC, GetShift:PROC, Sound:PROC
EXTRN GetCurSize:PROC, GetMem:PROC, Pause:PROC
EXTRN IntToAsc:PROC, Colors:PROC, GetVer:PROC
EXTRN Exec:PROC, Initialize:PROC
.STARTUP
call Initialize ; Initialize _psp and _env variables
mov ax, PGMSIZE ; Shrink memory block
push ax ; allocated to program
push _psp ; Push PSP segment address
call NewBlockSize ; Return unused memory to DOS
add sp, 4 ; Clean stack
call GetVidConfig ; Initialize variables
mov al, vconfig.rows
mov oldmode, al ; Preserve original line mode
call GetCurPos ; Get current cursor position
mov oldcurs, ax ; Store it
mov ax, 7
push ax ; Pass display attribute = 7
mov al, 79
push ax ; Pass right column
mov al, vconfig.rows
push ax ; Pass bottom row
sub al, al
push ax ; Pass left column
push ax ; and top row
call WinOpen ; Preserve original screen
add sp, 10 ; Clean stack
mov keepseg, ax ; Keep segment address
or ax, ax ; Window opened successfully?
jnz renew ; Yes? Continue
.EXIT 1 ; No? Exit with return code = 1
renew: call disp_menu ; Display main menu
Box CLKRW, CLKCL-1, CLKRW, CLKCL+17 ; Highlight on-screen clock
mov ax, CLKCL ; Column for clock
push ax
mov ax, CLKRW ; Row for clock
push ax
call GetKeyClock ; Poll for keyboard selection
add sp, 4 ; Clean stack
cmp al, ESCAPE ; Esc key?
je restr ; Yes? Quit
cmp ah, F1 ; No? Then is scan code for
jb renew ; one of the function keys
cmp ah, F7 ; between F1 and F7?
ja renew ; No? Try again
xchg al, ah ; Yes? Make AX = AH
sub al, F1 ; Normalize to 0
shl al, 1 ; Double to make word index
mov bx, ax ; BX = index to table
call table[bx] ; Call procedure
jmp SHORT renew ; Loop for another key
restr: mov al, oldmode ; Get original line mode
cmp al, vconfig.rows ; Same as current mode?
je @F ; Yes? Continue
inc ax ; No? Increment to 25/43/50
push ax ; Pass to procedure
call SetLineMode ; Restore line mode
add sp, 2 ; Clean stack
@@: push keepseg ; Segment with screen contents
call WinClose ; Restore original screen
add sp, 2 ; Clean stack
mov ax, oldcurs
push ax ; Pass old cursor column coord
mov al, ah
push ax ; Pass old cursor row coord
call SetCurPos ; Restore cursor to orig place
add sp, 4 ; Clean stack
.EXIT 0 ; Exit wih return code 0
;* disp_menu - Displays main menu.
;*
;* Uses: vconfig - Video configuration structure, declared in the
;* DEMO.INC include file. The structure must first be
;* initialized by calling the GetVidConfig procedure.
;*
;* Return: None
disp_menu PROC NEAR
mov ax, 0600h ; Scroll screen service
mov bh, fill ; Menu display attribute
sub cx, cx ; From row 0, col 0
mov dh, vconfig.rows ; to bottom row,
mov dl, 79 ; rightmost column
int 10h ; Clear entire screen
DispText 4, 15, <OFFSET menu1> ; Display menu
DispText 8, 28, <OFFSET menu2>
DispText 9, 28, <OFFSET menu3>
DispText 10, 28, <OFFSET menu4>
DispText 11, 28, <OFFSET menu5>
DispText 12, 28, <OFFSET menu6>
DispText 13, 28, <OFFSET menu7>
DispText 17, 15, <OFFSET menu8>
mov ax, 56
push ax ; Push column
mov al, 17
push ax ; Push row
call SetCurPos ; Park cursor at prompt
add sp, 4
ret
disp_menu ENDP
;* press - Displays a prompt, then waits for a key press.
;*
;* Uses: vconfig - Video configuration structure, declared in the
;* DEMO.INC include file. The structure must first be
;* initialized by calling the GetVidConfig procedure.
;*
;* Return: None
press PROC NEAR
mov dl, vconfig.rows
DispText dx, 50, <OFFSET presmsg>
mov ax, 48
push ax
mov al, vconfig.rows ; Bottom row of screen
push ax
call SetCurPos ; Park cursor at prompt
add sp, 4 ; Clean stack
mov ax, CLKCL ; Column for clock
push ax
mov ax, CLKRW ; Row for clock
push ax
call GetKeyClock ; Wait for keypress
add sp, 4 ; Clean stack
ret
press ENDP
;* get_vidinfo - Initializes video configuration message for display.
;*
;* Uses: vconfig - Video configuration structure, declared in the
;* DEMO.INC include file. The structure must first be
;* initialized by calling the GetVidConfig procedure.
;*
;* Return: None
get_vidinfo PROC NEAR
push ds
pop es ; Point ES to data segment
mov al, 4 ; Find index to 4-character
mul vconfig.adapter ; group in string
add ax, OFFSET adapstr ; Point AX to proper group
mov si, ax ; Put pointer in SI
lea di, vidmsg1[LEN1] ; Point to 1st line of message
mov cx, 2 ; Copy 4 letters (adapter
rep movsw ; designation) to message
mov si, OFFSET monostr ; Assume display is monochrome
cmp vconfig.display, MONO ; Then check with video struct
je @F ; Yes? Continue
mov si, OFFSET clrstr ; No? Point to "color" string
@@: lea di, vidmsg2[LEN1] ; Point to 2nd line of message
mov cx, 5 ; Copy 10 chars ("monochrome"
rep movsw ; or "color ") to msg
mov al, vconfig.mode
cbw ; AX = video mode
call IntToAsc ; Convert AX to ASCII
xchg ah, al ; Flip bytes for word write
mov WORD PTR vidmsg3[LEN1], ax ; Insert in message string
mov al, vconfig.rows
cbw
inc ax ; AX = number of screen rows
call IntToAsc ; Convert to ASCII
xchg ah, al ; Flip bytes for word write
mov WORD PTR vidmsg4[LEN1], ax ; Insert in message string
ret
get_vidinfo ENDP
;* get_mem - Initializes memory information message.
;*
;* Return: None
get_mem PROC NEAR
call GetMem ; DX = total memory
push ax ; AX = available memory
mov ax, dx
call IntToAsc ; Convert AX to ASCII
xchg dh, dl ; Flip bytes for word write
xchg ah, al
mov WORD PTR memmsg1[LEN1], dx ; Insert in message
mov WORD PTR memmsg1[LEN1+2], ax ; string
pop ax ; Recover avail memory #
call IntToAsc ; Convert to ASCII
xchg dh, dl ; Flip bytes for word write
xchg ah, al
mov WORD PTR memmsg2[LEN1], dx ; Insert in message
mov WORD PTR memmsg2[LEN1+2], ax ; string
ret
get_mem ENDP
;* check_printer - Initializes printer status message.
;*
;* Shows: Instruction - movsb
;*
;* Return: None
check_printer PROC NEAR
push ds
pop es ; Point ES to data segment
mov si, OFFSET yes ; Assume answer is "yes"
call VeriPrint ; Check if printer ready
or al, al ; Ready?
jnz @F ; Yes? Continue
mov si, OFFSET no ; No? Point to "no" answer
@@: lea di, prnmsg[LEN1] ; Point to print message
mov cx, 3 ; Copy 3 letters (either "yes"
rep movsb ; or "no ") to message
ret
check_printer ENDP
;* check_ansi - Initializes status message for ANSI driver.
;*
;* Return: None
check_ansi PROC NEAR
push ds
pop es ; Point ES to data segment
mov si, OFFSET yes ; Assume answer is "yes"
call VeriAnsi ; Check if driver installed
or al, al ; Installed?
jnz @F ; Yes? Continue
mov si, OFFSET no ; No? Point to "no" answer
@@: lea di, ansimsg[LEN1] ; Point to ansi message
mov cx, 3 ; Copy 3 letters (either "yes"
rep movsb ; or "no ") to message
ret
check_ansi ENDP
;* check_coproc - Initializes coprocessor status message.
;*
;* Return: None
check_coproc PROC NEAR
push ds
pop es ; Point ES to data segment
mov si, OFFSET yes ; Assume answer is "yes"
call VeriCop ; Check for coprocessor
or al, al ; Installed?
jnz @F ; Yes? Continue
mov si, OFFSET no ; No? Point to "no" answer
@@: lea di, copmsg[LEN1] ; Point to coprocessor message
mov cx, 3 ; Copy 3 letters (either "yes"
rep movsb ; or "no ") to message
ret
check_coproc ENDP
;* get_config - Displays system configuration information.
get_config PROC NEAR
call get_vidinfo ; Initialize video message
call get_mem ; Initialize memory message
call check_printer ; Initialize printer message
call check_ansi ; Initialize ANSI driver msg
call check_coproc ; Initialize coprocessor msg
Box 4, 13, 20, 67 ; Clear screen with box
DispText 6, 23, <OFFSET vidmsg1>
DispText 7, 23, <OFFSET vidmsg2>
DispText 8, 23, <OFFSET vidmsg3>
DispText 9, 23, <OFFSET vidmsg4>
DispText 11, 23, <OFFSET memmsg1>
DispText 12, 23, <OFFSET memmsg2>
DispText 14, 23, <OFFSET prnmsg>
DispText 16, 23, <OFFSET ansimsg>
DispText 18, 23, <OFFSET copmsg>
call press ; Prompt for keypress
ret
get_config ENDP
;* speaker - Sounds speaker with ascending frequencies.
;*
;* Return: None
speaker PROC NEAR
sub ax, ax
loop1: add ax, 100 ; Sound with frequencies
cmp ax, 3000 ; from 100 to 3000
ja exit
push ax ; Save frequency
mov bx, 1 ; Use duration = 1 clock
push bx ; Pass duration
push ax ; Pass frequency
call Sound ; Beep speaker
add sp, 4 ; Clean stack
pop ax
jmp SHORT loop1
exit: ret
speaker ENDP
;* set_lines - Toggles between 25/43-line mode for EGA or 25/43/50-line mode
;* for VGA.
;*
;* Uses: vconfig - Video configuration structure, declared in the
;* DEMO.INC include file. The structure must first be
;* initialized by calling the GetVidConfig procedure.
;*
;* Return: None
set_lines PROC NEAR
mov al, 25 ; Assume toggle to 25 line
cmp vconfig.rows, 49 ; Current mode 50 lines?
je toggle ; Yes? Toggle VGA to 25-line
cmp vconfig.rows, 42 ; Current mode 43 lines?
jne @F ; No? Must be 25
cmp vconfig.adapter, EGA ; Yes? And is adapter EGA?
je toggle ; Yes? Then toggle to 25 line
mov al, 50 ; No? Toggle VGA to 50 line
jmp SHORT toggle
@@: mov al, 43 ; If currently 25 lines, make
; either EGA or VGA 43 lines
toggle: push ax ; Pass requested mode param
call SetLineMode ; Change line mode
add sp, 2 ; Clean stack
or al, al ; Error?
jnz e_exit ; Yes? Display message
call GetVidConfig ; No? Update configuration
jmp SHORT exit ; structure and return
e_exit: Box 16, 13, 20, 67 ; Display error message
DispText 18, 17, <OFFSET linemsg>
call press
exit: ret
set_lines ENDP
;* pop_windows - Demonstrates windowing with the WinOpen and WinClose
;* procedures.
;*
;* Uses: vconfig - Video configuration structure, declared in the
;* DEMO.INC include file. The structure must first be
;* initialized by calling the GetVidConfig procedure.
;*
;* Return: None
pop_windows PROC NEAR
LOCAL row1:WORD, col1:WORD, row2:WORD, col2:WORD
LOCAL index:BYTE, addr[4]:WORD, csize:WORD
call GetCurSize ; Get current cursor size
mov csize, ax ; Store it
or al, 100000b ; Set 5th bit for cursor off
push ax ; Bottom line (arbitrary)
push ax ; Top line (arbitrary)
call SetCurSize ; Turn cursor off
add sp, 4 ; Clean stack
mov winmsg[LEN3], '0' ; Initialize window message
mov row1, 4 ; Initialize window coords
mov col1, 10
mov row2, 20
mov col2, 34
mov index, 0
mov cx, 4 ; Open 4 windows
open: push cx ; Save loop counter
mov al, index
mov bx, OFFSET filmono ; BX points to fill attributes
cmp vconfig.display, MONO ; If monochrome, continue
je @F
mov bx, OFFSET filcolr ; Else repoint to color attributes
@@: xlat ; Get attributes in succession
push ax ; Push fill attribute
push col2 ; Push right column
push row2 ; Push bottom row
push col1 ; Push left column
push row1 ; Push top row
call WinOpen ; Open a window
add sp, 10 ; Clean stack
pop di ; Recover counter in DI
push di ; and save it again
dec di
shl di, 1 ; Make DI a word index
mov addr[di], ax ; Save address of allocated
; block returned by WinOpen
inc winmsg[LEN3] ; Increment window number
mov bx, row1
add bl, 2 ; Message row
mov cx, col1
add cl, 9 ; Message column
DispText bx, cx, <OFFSET winmsg>; Display "Window" message
mov ax, 18
push ax
call Pause ; Pause for approx 1 second
add sp, 2 ; Clean stack
add row1, 2 ; Adjust coordinates for
add col1, 13 ; next window
sub row2, 2
add col2, 13
inc index
pop cx ; Recover counter
loop open
mov cx, 4 ; Close 4 windows
sub di, di ; DI = index to addresses
close: push cx ; Save loop counter
push addr[di] ; Push allocation address
call WinClose ; Close the window associated
add sp, 2 ; with allocated block
mov ax, 18
push ax
call Pause ; Pause for 1 second
add sp, 2
add di, 2 ; Point to next address
pop cx ; Recover counter
loop close ; Close another window
mov ax, csize ; Get original cursor size
push ax ; Push bottom line number
mov al, ah
push ax ; Push top line number
call SetCurSize ; Restore cursor size
add sp, 4 ; Clean stack
ret
pop_windows ENDP
;* set_ attrs - Changes display attributes for the main menu.
;*
;* Uses: vconfig - Video configuration structure, declared in the
;* DEMO.INC include file. The structure must first be
;* initialized by calling the GetVidConfig procedure.
;*
;* Return: None
set_attrs PROC NEAR
Box 3, 12, 23, 68
cmp vconfig.adapter, MDA ; Monochrome?
jne @F
jmp d_mono
@@: DispText 4, 18, <OFFSET cmsg1> ; Display "colors" menu for
DispText 5, 18, <OFFSET cmsg2> ; color system
DispText 6, 22, <OFFSET cmsg3>
DispText 7, 22, <OFFSET cmsg4>
DispText 10, 18, <OFFSET cmsg5>
DispText 11, 18, <OFFSET cmsg6>
DispText 14, 18, <OFFSET cmsg7>
DispText 15, 18, <OFFSET cmsg8>
DispText 16, 22, <OFFSET cmsg9>
DispText 17, 22, <OFFSET cmsg10>
DispText 18, 22, <OFFSET cmsg11>
DispText 19, 22, <OFFSET cmsg12>
mov al, filcolr ; Initialize filsub variable
mov filsub, al ; for color
jmp prompt
d_mono: DispText 8, 32, <OFFSET cmsg13> ; Display "colors" menu for
DispText 9, 32, <OFFSET cmsg14> ; monochrome system
DispText 10, 36, <OFFSET cmsg15>
DispText 11, 36, <OFFSET cmsg16>
DispText 12, 36, <OFFSET cmsg17>
DispText 13, 36, <OFFSET cmsg18>
mov al, filmono ; Initialize filsub variable
mov filsub, al ; for monochrome
prompt: DispText 22, 15, <OFFSET menu8>
mov ax, 56
push ax
mov al, 22
push ax
call SetCurPos ; Park cursor at prompt
add sp, 4 ; Clean stack
poll: mov ax, CLKCL ; Column for clock
push ax
mov ax, CLKRW ; Row for clock
push ax
call GetKeyClock ; Wait for keypress
add sp, 4 ; Clean stack
cmp al, ESCAPE ; Esc key?
jne @F ; No? Continue
jmp exit ; Yes? Exit
@@: cmp al, 'a' ; Convert letters to uppercase
jb @F ; to make comparisons easier
cmp al, 'z'
ja @F
and al, 5Fh
@@: cmp al, 'B' ; Request blink toggle?
je blink
cmp al, 'I' ; Request intensity toggle?
je intens
mov bl, filsub ; Get window display attribute
cmp vconfig.adapter, MDA ; Monochrome?
jne colr ; No? Jump to color selections
cmp al, 'U' ; Request underline toggle?
je under
cmp al, 'R' ; Request reverse toggle?
jne poll ; No? Then skip invalid key
; What with cross-toggling between reverse, normal, and underline, three
; bit settings can exist in monochrome: x111x000 for reverse, x000x111 for
; normal, and x000x001 for underline. Changing between the three involves
; more than simply XOR-ing the current attribute; each condition must check
; for the other two.
rever: test bl, 1 ; Reverse video on?
jz @F ; Yes? Go to next step
or bl, 00000111b ; No? Ensure normal bits are on
@@: xor bl, 01110111b ; Toggle for reverse/normal
mov cl, 6 ; Set code for MOV
jmp switch
under: test bl, 1 ; Reverse video on?
jnz @F ; No? Go to next step
and bl, 10001111b ; Yes? Clear bits 4-6 and
or bl, 00000111b ; set bits 0-2
@@: xor bl, 00000110b ; Toggle bits 1-2 for underline
mov cl, 6 ; Set code for MOV
jmp switch
; Blink and intensity use the same bits for color and monochrome.
blink: mov bl, 10000000b ; Set bit 7 for blink
mov cl, 4 ; Set code for XOR
jmp switch
intens: mov bl, 00001000b ; Set bit 3 for intensity
mov cl, 4 ; Set code for XOR
jmp switch
; Enter this section only for color displays. First check for arrow keys,
; which increment or decrement the foreground or background bits of the
; current attribute stored in the variable filsub. If arrow keys are not
; pressed, check for the F or A keys, which request specific colors for the
; foreground or background colors.
colr: mov ch, bl ; Copy current attribute to CH
cmp ah, 72 ; Up arrow?
jne @F ; No? Continue check
mov cl, 4 ; Yes? Increment bits 4-6
shr ch, cl ; to next background color
inc ch
and ch, 00000111b
shl ch, cl
mov dl, 10001111b ; Set background mask
jmp SHORT step
@@: cmp ah, 75 ; Left arrow?
jne @F ; No? Continue check
inc ch ; Yes? Increment bits 0-2
and ch, 00000111b ; to next foreground color
mov dl, 11111000b ; Set foreground mask
jmp SHORT step
@@: cmp ah, 77 ; Right arrow?
jne @F ; No? Continue check
dec ch ; Yes? Decrement bits 0-2
and ch, 00000111b ; to previous foreground color
mov dl, 11111000b ; Set foreground mask
jmp SHORT step
@@: cmp ah, 80 ; Down arrow?
jne chk_fa ; No? Continue check
mov cl, 4 ; Yes? Decrement bits 4-6
shr ch, cl ; to previous background color
dec ch
and ch, 00000111b
shl ch, cl
mov dl, 10001111b ; Set background mask
step: and bl, dl ; Mask out fore or back bits
or bl, ch ; Copy into original attribute
mov filsub, bl ; Store the new submenu color
mov cl, 6 ; Request move operation in
jmp SHORT switch ; Colors procedure
; This section checks for the F or A keys; if found it checks again for
; a number key between 0 and 7, then inserts the correct foreground or
; background bit pattern into the current fill attribute.
chk_fa: sub cx, cx ; Clear flag for foreground request
cmp al, 'F' ; Request to set foreground color?
je @F ; Yes? Continue
cmp al, 'A' ; Request to set background color?
jne gopoll ; No? Then skip invalid key
inc cx ; Set flag for background request
@@: push cx ; Save flag
mov ax, CLKCL ; Column for clock
push ax
mov ax, CLKRW ; Row for clock
push ax
call GetKeyClock ; Get color number from keyboard
add sp, 4 ; Clean stack
pop cx ; Recover flag
cmp al, '0' ; Check for proper number
jb gopoll ; between 0 and 7
cmp al, '7'
jbe @F
gopoll: jmp poll ; If not valid key, ignore it
@@: xor al, '0' ; Convert ASCII numeral into binary
mov dl, 11111000b ; Set foreground mask
jcxz @F ; Skip if foreground request
mov cl, 4 ; Otherwise shift bits 0-2
shl al, cl ; to positions 4-6
mov dl, 10001111b ; Set background mask
@@: mov bl, filsub
and bl, dl ; Mask out fore or back bits
or bl, al ; Insert number into fore or back bits
mov filsub, bl ; Store the new submenu color
mov cl, 6 ; Request move
switch: mov ax, 68
push ax ; Push window right column
mov al, 23
push ax ; Push window bottom row
mov al, 12
push ax ; Push window left column
mov al, 3
push ax ; Push window top row
push bx ; Push new attribute
push cx ; Push logic code
call Colors ; Reset new attributes in window
add sp, 12
mov ah, 8 ; Function 8, get char/attribute
mov bh, vconfig.dpage
int 10h ; Get attribute in AH
mov fill, ah ; New fill variable for main menu
mov filsub, ah ; and for submenu
jmp poll
exit: ret
set_attrs ENDP
;* exec_pgm - Executes a specified program as a child process.
;*
;* Uses: vconfig - Video configuration structure, declared in the
;* DEMO.INC include file. The structure must first be
;* initialized by calling the GetVidConfig procedure.
;* pb - Parameter block structure, declared in the DEMO.INC file
;*
;* Return: None
exec_pgm PROC NEAR
Box 16, 13, 20, 67
DispText 17, 16, <OFFSET execmsg> ; Display prompt for file spec
mov ax, 16
push ax
mov al, 19
push ax
call SetCurPos ; Park cursor below prompt
add sp, 4 ; Clean stack
mov ah, 0Ah ; Request DOS to read keyboard
mov dx, OFFSET fspec ; input into fspec string
int 21h ; Read Buffered Keyboard Input
Box 16, 13, 20, 67
DispText 17, 16, <OFFSET tailmsg> ; Display prompt for command tail
mov ax, 16
push ax
mov al, 19
push ax
call SetCurPos ; Park cursor below prompt
add sp, 4 ; Clean stack
mov ah, 0Ah ; Request DOS to read keyboard
mov dx, OFFSET tail ; input into tail string
int 21h ; Read Buffered Keyboard Input
sub bh, bh ; Clear BH
mov si, OFFSET fspec ; DS:SI points to file spec string
mov bl, [si+1] ; BL = number of chars in spec
mov BYTE PTR [si+bx+2], 0 ; Terminate string with 0
mov ax, _env ; Get segment address of environment
mov pb.env, ax ; Copy it to parameter block
mov ax, @data ; AX points to data segment
lea bx, tail[1] ; BX points to command-line tail
mov WORD PTR pb.taddr[0], bx; Copy address of command-line tail
mov WORD PTR pb.taddr[2], ax; to parameter block
mov bx, OFFSET fcblk1 ; BX points to first FCB
mov WORD PTR pb.fcb1[0], bx ; Copy address of first FCB
mov WORD PTR pb.fcb1[2], ax ; to parameter block
mov bx, OFFSET fcblk2 ; BX points to second FCB
mov WORD PTR pb.fcb2[0], bx ; Copy address of second FCB
mov WORD PTR pb.fcb2[2], ax ; to parameter block
; At this point, the program file is specified, the command line tail is set,
; and the parameter block is properly initialized. The Exec procedure will
; take care of loading the FCBs with command-line arguments and resetting
; interrupt vectors. Now blank the screen in preparation for executing the
; process and pass the five pointers to the Exec procedure.
mov ax, 0600h ; AH = scroll service, AL = 0
mov bh, 7 ; Blank with normal attribute
sub cx, cx ; From row 0, col 0
mov dh, vconfig.rows ; to bottom row
mov dl, 79 ; and rightmost column
int 10h ; Blank screen
sub al, al
push ax ; Push column
push ax ; Push row
call SetCurPos ; Set cursor at top of screen
add sp, 4 ; Clean stack
IF @CodeSize ; If medium or large model,
push cs ; pass code segment
ENDIF
mov ax, OFFSET NewCritErr ; Pass pointer to new critical
push ax ; error handler
IF @CodeSize
push cs
ENDIF
mov ax, OFFSET NewCtrlC ; Pass pointer to new Ctrl-C
push ax ; error handler
IF @CodeSize
push cs
ENDIF
mov ax, OFFSET NewBreak ; Pass pointer to new
push ax ; Ctrl-Break handler
IF @DataSize
push ds
ENDIF
mov ax, OFFSET pb ; Pass far pointer to
push ax ; parameter block
IF @DataSize
push ds
ENDIF
lea bx, fspec[2] ; Pass far pointer to
push bx ; file specification
call Exec ; Exec specified program
IF @CodeSize
add sp, 6 ; Clean stack (far code)
ENDIF
IF @DataSize
add sp, 4 ; Clean stack (far data)
ENDIF
add sp, 10 ; Clean remainder of stack
cmp ax, -1 ; Successful?
je e_exit ; No? Beep speaker and exit
IF @DataSize ; Yes? Prepare to display return code
push ds
ENDIF
mov bx, OFFSET recode
push bx ; Pass pointer to 6-byte string
push ax ; Pass return code
call BinToHex ; Convert return code to string
IF @DataSize
add sp, 6
ELSE
add sp, 4 ; Clean stack
ENDIF
call GetVidConfig ; Update video structure
Box CLKRW, CLKCL-1, CLKRW, CLKCL+17 ; Highlight on-screen clock
Box vconfig.rows, 0, vconfig.rows, 79 ; Highlight bottom row
mov dl, vconfig.rows
DispText dx, 0, <OFFSET retmsg> ; Display return code at bottom,
call press ; wait for keypress,
jmp SHORT exit ; and exit
e_exit: mov ax, 0E07h ; Write ASCII 7 character
int 10h ; (bell) to console
exit: ret
exec_pgm ENDP
;* The following three procedures are primitive handlers for Interrupt 1Bh
;* (Ctrl-Break), Interrupt 23h (Ctrl-C), and Interrupt 24h (Critical Error).
;* The purpose of an interrupt handler in this context is to prevent termina-
;* tion of both parent and child processes when the interrupt is invoked.
;* Such handlers often set flags to signal a process that the interrupt has
;* been called.
;* NewBreak - Handler for Interrupt 1Bh.
NewBreak PROC
sti ; Reenable interrupts
push ax ; Preserve AX register
mov al, 20h ; Send end-of-interrupt signal
out 20h, al ; to interrupt controller
pop ax ; Recover AX register
iret ; Return from handler
; without taking action
NewBreak ENDP
;* NewCtrlC - Handler for Interrupt 23h.
NewCtrlC PROC
iret ; Return from handler
; without taking action
NewCtrlC ENDP
;* NewCritErr - Handler for Interrupt 24h.
NewCritErr PROC
sub al, al ; Tell DOS to ignore error
iret ; Return from handler
; without taking action
NewCritErr ENDP
END