?? choice.asm
字號:
; Created by Ericst on 5/14/92.
; Modified by Ericst on 8/25/92 to use 1 for first choice instead of 0
; Modified by Ericst on 8/31/92 to change /T syntax from /Tnn,c to /Tc,nn
; to be consistent with select-boot timeout syntax
; Also fixed bug 1018 (timeout doesn't work with 12 seconds.
;
; CHOICE [/c choices] [/N] [/S] [/T:c,nn] [text]
; /c[:]choices Specifies allowable response keys. The
; default is "yn". Keys are not case sensitive
; unless /S is specified. If choices are specified
; more than once, no error is generated and the last
; set of choices are used.
; /N Causes CHOICE to Not display choices (and ?) at the end of
; the string, enclosed in square brackets.
; /S Case sensitive. Default is case insensitive.
; /T[:]c,nn Timeout after nn seconds and take choice c.
; c must be in choices. If c is not
; in choices an error message is displayed.
; text Specifies a string to be displayed. If no text
; is specified, only the choices are displayed (unless
; /N is specified). The string can be enclosed in
; quotes ("), or may simply be terminated by end of
; the line, or by a switch.
;
; When one of the choices is entered, the index of the choice is
; returned in ERRORLEVEL, where 1 means the first letter in choices
; was pressed, 2 means the second, and so on. CHOICE beeps if any
; choice other than those in choices is specified. CHOICE returns 255
; if a problem is encountered (bad arg, etc.), or if user
; runs with /? switch. No control-break handler is provided, so
; user pressing control-c results in errorlevel 0.
.MODEL tiny
.code
org 100h
public start
start:
jmp begin
include choice.inc
begin:
cld ; force string ops to be forward.
; ************************************************************************
; *** Verify MS-DOS version is 4.0 or later ***
; ************************************************************************
mov al,01h ; version number, not OEM flag
mov ah,30h ; Get Version Function
int 21h
cmp al, 3 ; This program requires 4.0 or later
jg GetTable
WrongVersion:
strout BADVERMSG
mov al, ERROREXIT
jmp ChoiceDone
; ************************************************************************
; *** Get Upper Case Table address/bias ***
; ************************************************************************
GetTable:
push es
mov ax,GETUPPERTABLE
mov bx,-1 ; current code page
mov cx,5 ; size of info for upper case table
mov dx,bx ; current country id
push cs
mov di,offset UCaseTbl ; point at buffer for table
int 21h
; assume no error
inc di ; point at start of table
les di,[di] ; load table address
mov bx,es:[di] ; load table size
mov ax,256 ; compute table size bias
sub ax,bx
mov UCaseTblBias,ax ; save it for later
add di,2 ; Shift UcaseTbl Address so that
mov word ptr UCaseTbl,di ; it is at UCaseTbl (instead of
mov word ptr UCaseTbl+2,es ; UCaseTbl + 1; before shift, UCaseTbl
pop es ; points to table ID which is always 2).
; ********************************************************************
; *** Parse command line ***
; *** Set Show=FALSE if /N, ***
; *** Set Choices to choices from /C, if specified ***
; *** Set CaseSense=True if /S ***
; *** Set TimeOut=<secs>&TimeOutDefault=char to timeout too if ***
; *** /T is specified ***
; *** Set PROMPT to user specified prompt, if specified. ***
; ********************************************************************
mov si,081h ; Offset of command line in PSP
; While !(end of line) do
Parse1:
lodsb ; get first char
cmp al, CR ; end of line?
je ParseDone ; if so, Exit parse loop
cmp al, SWITCHCHAR ; is it a switch?
je IsSwitch
cmp al, Blank ; if blank, ignore
je Parse1
cmp al, Tab ; if tab, ignore
je Parse1
; Prompt: parse it off
mov di, offset PROMPT ; di points to prompt
cmp BYTE PTR [di], NUL ; Prompt already specified?
jne MultPromptErr
; Set dl depending on Quoted or not.
cmp al, QUOTE ; Terminator for Quoted String: CR and
jne NoQuote ; QUOTE (set dl to QUOTE).
mov dl, QUOTE
jmp prompt1
NoQuote:
mov dl, SWITCHCHAR ; Terminator for unquoted String:CR and
stosb ; SWITCHCHAR (set dl to SWITCHCHAR)
; Repeat
Prompt1:
mov al, [si] ; want SI to point to term if we exit
cmp al, CR ; End of line? If so, leave si pointing
je Parse1 ; at it. No need to increment.
cmp al, dl ; If an end-quote we'll need to inc
je Terminator ;
stosb ; save the char.
inc si ; get next char
jmp Prompt1
; Until (terminator char found)
Terminator: ; encountered end-quote or switch char
cmp al, SWITCHCHAR ; if a switch leave si pointing to it.
je Parse1 ; If a quote, si should point to next
inc si ; character after the quote.
jmp Parse1 ; parse next field.
MultPromptErr:
strout MULTPROMPTERRMSG
strout SYNTAXMSG
mov al, ERROREXIT
jmp ChoiceDone
IsSwitch: ; Case Switch of:
lodsb ; get switch char
call ToUpper ; Case Switch of:
cmp al,HELPSWITCH ; /?
je IsHelpSwitch
cmp al,CHOICESWITCH ; /c choices
je IsChoiceSwitch
cmp al,DISPLAYSWITCH ; /N
je IsDisplaySwitch
cmp al,TIMEOUTSWITCH ; /Tc,nn
je IsTimeoutSwitch
cmp al,CASESWITCH ; /S
je IsCaseSwitch
strout BADSWITCHMSG ; invalid switch
strout SYNTAXMSG
mov al, ERROREXIT
jmp ChoiceDone ; End CASE switch.
IsHelpSwitch: ; /?
strout HELPMSG0
strout SYNTAXMSG
strout HELPMSG1
mov al, ERROREXIT
jmp ChoiceDone
IsChoiceSwitch: ; Set of choices, get them.
mov di, offset choices
GetChoices:
mov al, [si]
cmp al, CHOICESDELIM ; expect choicedelim or first choice
jne ChoiceSw1
inc si
mov al, [si]
ChoiceSw1:
cmp al, BLANK
je ChoiceSwDone
cmp al, TAB
je ChoiceSwDone
cmp al, CR
je ChoiceSwDone
cmp al, SWITCHCHAR
je ChoiceSwDone
stosb ; save choice
inc si ; loop until switch or delim found.
mov al, [si]
jmp ChoiceSw1 ; get next choice.
ChoiceSwDone: ; Have all choices now.
mov al, NUL ; mark end in case of 1 char choice.
mov [di],al
cmp di, offset choices ; At least 1 choice specified?
jne Parse1
strout NEEDCHOICE ; No choices specified.
mov al, ERROREXIT
jmp ChoiceDone
IsDisplaySwitch: ; Display options Switch
mov Show, FALSE
jmp Parse1
IsTimeoutSwitch: ; Timeout Switch
mov al, [si] ; in form /T[:]c,n[n]
cmp al, TIMEDELIM
jne GetDefChar
inc si ; skip over ':'
mov al, [si]
GetDefChar:
cmp al, CR ; whitespace & Switch not allowed
je BadTimeOut
cmp al, SWITCHCHAR
je BadTimeOut
cmp al, Blank
je BadTimeOut
cmp al, Tab
je BadTimeOut
mov TimeOutDefault, al ; save default char
inc si
mov al, [si]
cmp al, TIMEDEFDELIM ; Delim for timeout?
jne BadTimeOut
inc si ; skip over delim
mov al, [si]
cmp al, '0' ; Ensure it's a digit
jb BadTimeOut
cmp al, '9'
ja BadTimeOut
and ax, 0fh ; Conver to binary
mov TimeOut, al ; save (incase 1 digit)
inc si ; Check for another digit
mov al, [si]
cmp al, '0'
jb Parse1 ; Not part of timeout switch
cmp al, '9'
ja Parse1 ; Not part of timeout switch
mov al,TimeOut
mov dx, 10 ; num=1st dig *10 + 2nd dig
mul dl
mov bl, [si]
and bl, 0fh
add al, bl
mov TimeOut, al ; save timeout
inc si
jmp Parse1
BadTimeOut:
strout BADTIMEOUTMSG
mov al, ERROREXIT
jmp ChoiceDone
IsCaseSwitch: ; Case Sensitive Switch
mov CaseSense,TRUE
jmp Parse1
ParseDone:
; ********************************************************************
; *** Done Parsing Command Line. Unless specified otherwise, ***
; *** convert choices and default to Upper Case ***
; ********************************************************************
cmp [CaseSense],TRUE ; If CaseSense is set, skip upper casing
je DoneUpCasing
mov al, TimeOutDefault ; Convert Timeout Default to upper case
call ToUpper
mov TimeOutDefault, al
mov si, offset Choices ; Now convert the choices to upcase
ChoiceUCase1:
cmp BYTE PTR [si], NUL
je DoneUpCasing
mov al, [si]
call ToUpper
mov [si], al
inc si
jmp ChoiceUCase1
DoneUpCasing:
; ********************************************************************
; *** if /t (timeout) was specified, verify specified default is ***
; *** in Choices ***
; ********************************************************************
mov di, offset Choices
mov cx, MAXPROMPT ; search entire buffer (it is 0 filled)
mov al, TimeOutDefault
repnz scasb
jz TimeOutValid
strout BADTIMEOUTCHARMSG ; char not in choices.
mov al, ERROREXIT
jmp ChoiceDone
TimeOutValid:
; ********************************************************************
; *** Display prompt, if any ***
; *** if /N (No Display Choices) was not specified, display ***
; *** choices with leading space if any prompt), enclosed in [], ***
; *** separated by commas, followed by '?' ***
; ********************************************************************
strout prompt
cmp [Show],TRUE ; /N not specified
jne PromptDone
mov di, offset Choices
; putchr BLANK
putchr CHOICEBEG ; display leading [
ChoiceOut:
putchr [di]
inc di
cmp BYTE PTR [di], NUL ; more?
je Choice20
putchr CHOICEDELIM
jmp ChoiceOut
Choice20:
putchr CHOICEEND ; put on final ]?
putchr QUESTION
PromptDone:
; ********************************************************************
; *** If TimeOut specified, wait for timeout or keypress and ***
; *** set Key to timeout default value if timeout occurs. ***
; ********************************************************************
cmp TimeOut, 0
je TimeOutDone
mov ah, 2ch ; Get Start Seconds
int 21h
mov LastSecs, dh
CheckKeyPress:
mov ah, 0bh ; check for keypress
int 21h
and ax, 0001h
or ax,0
jnz TimeOutDone ; key was pressed
TimeOutLoop1:
mov ah, 2ch ; Get Seconds
int 21h
cmp [LastSecs], dh
je CheckKeyPress
mov LastSecs,dh
dec TimeOut ; second elapsed
jnz CheckKeyPress ; check for another key
mov al, TimeOutDefault ; Timed out. simulate reading of char
jmp GetKey01
TimeOutDone:
; ********************************************************************
; *** If no TimeOut occurred, THEN ***
; *** LOOP ***
; *** wait for keypress. ***
; *** if key is not valid print BEL char & set Key=0 ***
; *** UNTIL key !=0 ***
; *** ENDIF ***
; ********************************************************************
GetKey0:
getchr
GetKey01: ; Jump here if Timed Out
mov di, offset CHOICES ; search for key in choices
GetKey1: cmp [CaseSense], TRUE ; Unless CaseSense, convert to ucase
je GetKey2
call ToUpper ; convert to al upper case
GetKey2:
cmp BYTE PTR [di], NUL
je Badkey
scasb
je GotKey
jmp GetKey2
Badkey:
putchr BEL
jmp GetKey0
GotKey:
putchr al
putchr CR
putchr LF
sub di, offset choices ; convert to offset
mov ax, di
; ********************************************************************
; *** Exit (offset of Key in Choices) ***
; ********************************************************************
ChoiceDone:
mov ah, 04Ch
int 21h ; Exit
; ********************************************************************
; *** MyStrOut
; *** Input Args: bx address of string
; *** Destroys: nothing
; *** Returns: nothing
; ********************************************************************
MyStrOut PROC USES ax di dx
mov ah, 02h ; Display Char function. Can't use 09
; because we need to print $'s.
xor di,di ; di is offset of chars to print
MyStrOutLoop1:
mov dl, [bx+di]
cmp dl, NUL
je MyStrOutDone
int 21h
inc di
jmp MyStrOutLoop1
MyStrOutDone:
ret
MyStrOut ENDP
; ********************************************************************
; *** ToUpper converts charcter in al to upper case ***
; *** For extended characters, uses uppercase table ***
; *** Call with: ***
; *** al = char to uppcase ***
; *** destroys: ah & converts al to uppercase ***
; ********************************************************************
ToUpper PROC uses bx di es
cmp al,'a'
jb ToUpperDone
cmp al,'z'
ja NotAlpha
sub al, 20h ; convert to uppercase
jmp ToUpperDone
NotAlpha:
cmp al,80h ; if DL is extended char, get mapping
jb ToUpperDone ; AL not extended char
les di,dword ptr UCaseTbl ; get the table
mov bx, ax
xor bh,bh
sub bx, UCaseTblBias ; get the index
mov al,es:[di+bx] ; get the char
ToUpperDone:
ret
ToUpper ENDP
END start
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -