home *** CD-ROM | disk | FTP | other *** search
- ; ASK program to enable you to ask questions and let users type in a
- ; one-character response. This allows you to build simple menu-driven
- ; batch file or yes/no type questions.
- ;
- ; See the external docuementation for more details.
- ; Written by Peter Wu; April, 1986
- ; UUCP: {seismo|ihnp4|harvard|ucbvax|allegra|topaz}!uwvax!uwmacc!pwu
- ; ARPA: pwu@unix.macc.uwisc.edu
- ;
- ; Slightly tweaked by David Kirschbaum, Toad Hall
-
- ARGL equ 80h ; start of command line
- SPECIAL equ '^' ; the special escape character
- SWITCH equ '/' ; switch character preceeding options
- CMDLEN equ 150 ; max length of converted cmd line
- MAXARGC equ 4 ; max # of arguements
- SQUOTE equ 39 ; ASCII of '
- CR equ 0DH
- LF equ 0AH
-
- All SEGMENT 'CODE'
- ASSUME CS:All,DS:All
- ORG 100h
-
- Entry proc near
- jmp Start
-
- ;********************** data area ***********************
- line db CMDLEN dup(?) ; store the converted command line
- argc db ?
- argv dw MAXARGC * 2 dup(?) ; *argv[]
- option db 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1
- ; a b c d e f g h i j k l m n o p q r s t u v w x y z
- ; 0 = option off, 1=invalid option, 2 = option on
- cry db 'unknown option ',SQUOTE
- unkopt db ? ; fill in the unknown option here
- db SQUOTE,' ignored',CR,LF,'$'
-
- ;*********************** code area **********************
- ; GetC returns a converted character. bx should point to command line
- ; cl should contain the length of the command line
- ; ah=0 if normal character; ah='\' if special character.
-
- three db ? ; for counting down from 3
- ten db 10 ; for multiplying
- Entry endp
-
-
- GetC proc near
- xor ax,ax ; clear character
- sub cl,1 ; len = len - 1
- jc Eoln ; reached end of command line
-
- mov al,[bx] ; get a character
- inc bx ; point to next one
- cmp al,SPECIAL ; is it the special char '\' ?
- jnz Normal ; nop; just a normal character
-
- sub cl,1 ; len = len - 1
- jc Eoln ; last character is '\'; ignore it
-
- mov ah,al ; flag special char
- mov al,[bx] ; get the next char
- inc bx ; point to next char
-
- ; translate \nnn characters into ascii
- cmp al,'0' ; see if first n is a digit
- jb NotDig ; not a digit
- cmp al,'9'
- ja NotDig ; not a digit
-
- ; first n is a digit
- xor ch,ch ; init accumulator
- mov three,3 ; convert 3 digits at most
-
- Digit: sub al,'0' ; convert to binary
- ; now multiply cl by ten and add al to it
- xchg al,ch ; do this so we can use al to multiply
- mul ten ; assume result is still 8 bits
- add ch,al ; one digit is done.
-
- ; more digits?
- dec three
- jz GotIt ; converted all three digits
- mov al,[bx] ; examine next char
- cmp al,'0' ; is it a digit
- jb GotIt ; not a digit; end translation
- cmp al,'9'
- ja GotIt ; not a digit; end translation
- inc bx ; point to next char
- jmp Digit ; process digit
-
- GotIt: mov ah,SPECIAL ; flag special char even for \nnn
- mov al,ch ; return char in al
- Normal: ret
-
- NotDig: ; not \nnn (e.g. \a \b \c \d ...)
- cmp al,SPECIAL ; \\ => \
- je Skip
- cmp al,'"' ; \" => "
- je Skip
- and al,31 ; \a => ctrl-a; \b => ctrl-b; ...
- Skip: ret
-
- Eoln: xor ax,ax ; return end-of-line char
- ret
-
- GetC endp
-
- ;*********************** PrtS **********************
- count dw ?
- p dw ?
-
- PrtS proc near ; print string to stdout; si points to string
- mov ax,[si+2] ; pointer to string
- mov p,ax ; save pointer
- mov ax,[si] ; get length of string
- mov count,ax
-
- Ploop: sub count,1
- jc D1 ; end of string
- mov bx,p
- mov dl,[bx] ; current character to be printed
- inc p ; point to next character
- mov ah,2 ; function number for print character
- int 21h ; print character
- jmp Ploop ; repeat
-
- D1: ret
- PrtS endp
-
- ;********************* main *********************
-
- mc db ? ; loop index
- char db ? ; key pressed by user
-
- crlf db CR,LF,'$' ; crlf string
-
- helpms db 'Usage:',CR,LF
- db ' ask [',SWITCH,'c',SWITCH,'q] '
- db '"prompt message" "expected response"',CR,LF,LF
- db ' ',SWITCH,'c makes the response case sensitive',CR,LF
- db ' ',SWITCH,'q will accept non-expected response (returns 0)',CR,LF
- db ' "prompt message" and "expected response" are quoted strings',CR,LF
- db ' To embed special characters use ',SPECIAL
- db 'nnn where nnn is a 3-digit ASCII',CR,LF
- db ' or ',SPECIAL,'a for ctrl-a, ',SPECIAL,'b for'
- db ' ctrl-b, ... (except ',SPECIAL,SPECIAL,' for ',SPECIAL,' itself',CR,LF
- db ' and ^" for the quote character)',CR,LF
- db ' Response can be tested with if errorlevel',CR,LF
- db ' Errorlevel is set to index("expected response",key pressed)',CR,LF,LF
- db 'See the external document for more information',CR,LF
- db '$'
- nom db '*BEEP* Unexpected response',CR,LF,LF,'$'
-
- Start proc near
-
- mov bx,ARGL ; start of parameters
- mov cl,[bx] ; length of parameter
- inc bx ; now point to first char
- mov di,offset line ; point to convert line buffer
- mov si,offset argv - 4 ; point to *argv[0] - 4
-
- mov argc,0 ; normally start at 1; but for ask.com 0 is ok
-
- ; now split command line into arguements in argv[]
- Loopit:
- cmp argc,MAXARGC ; can we handle more arguements?
- jae Done ; if not; get out
-
- call GetC ; convert one character
- or ax,ax ; check for done
- jz Done ; end of command line
-
- cmp al,' ' ; a blank space?
- jz Loopit ; skip it
-
- ; now we must be seeing the beginning of an arguement
- inc argc ; count it
- add si,4 ; point to next *argv[]
- mov [si+2],di ; where string start
- mov word ptr [si],0 ; set length to 0
-
- mov dx,' ' ; assume this is the separator
- cmp ax,'"' ; start of quoted string?
- jne NoQuote ;
- mov dx,'"' ; make this the separator
- jmp short Next ; don't store the first "
-
- NoQuote:
- mov [di],al ; store the character
- inc di
- inc word ptr [si] ; increment argv's length
- Next: call GetC
- or ax,ax
- jz Done ; end of arguement
-
- cmp ax,dx ; is this the separator?
- jz Loopit ; find next arguement
-
- jmp NoQuote ; keep storing
-
- ; now done with splitting argv[]'s
- Done:
- ; now let's check for options
- mov ah,argc
- mov mc,ah ; for mc = argc downto 1 do
- mov si,offset argv - 4
- or ah,ah ; do we any argv at all?
- jz EndOpt
- More: add si,4 ; point to *argv[0,1,2,...]
- mov bx,[si+2] ; address of string
- cmp byte ptr [bx],SWITCH ; is this string an option?
- jnz EndOpt ; no more options
-
- ; process this option (option can be /abc or /a /b /c or /a/b/c)
- mov cx,[si] ; length of option string
- Mopts: inc bx ; point to char after the switch
- dec cx ; decrement length of option string
- jz NextOp ; done with this option string. Next.
-
- ; now scrutinize the option letter
- mov al,[bx] ; the option letter
- cmp al,SWITCH ; is the switch embedded in here?
- je Mopts ; ignore it
-
- cmp al,'A' ; check for legal option letters
- jb BadOpt
- cmp al,'Z'
- jbe GoodOpt ; a valid uppercase option letter
-
- cmp al,'a'
- jb BadOpt
- cmp al,'z'
- ja BadOpt
-
- GoodOpt:
- mov dl,al ; save option letter in case of error
- and al,31 ; convert to 1-26
- dec al ; convert to 0-25
- xor ah,ah
- mov di,ax ; use as an index
- mov al,dl ; in case we need this to print error
- cmp option[di],1 ; check if this is a known option
- je BadOpt ; if not, yell at user
- mov option[di],2 ; set the option
- jmp short Mopts ; go look at next option char.
-
- BadOpt: ; yell at user for bad option character
- mov unkopt,al
- mov dx,offset cry
- mov ah,9 ; print the error message
- int 21h
- jmp short Mopts ; look at next option char.
-
- NextOp: dec mc ; count down argc
- jnz More
-
- ; now process the parameters
- EndOpt: cmp mc,0 ; see if there's any arguements at all
- ja NoHelp
- mov dx,offset helpms ; if not, print a summary
- mov ah,9 ; print string
- int 21h
- xor al,al ; return code 0
- jmp Die
-
- NoHelp: ; si is pointing to a parameter *argv[]
- mov di,si
- add di,4 ; if mc = 2 then di is pointing to the
- ; expected response string's argv[]
-
- ; now see if we should convert the "expected response" to upper case
- cmp mc,2 ; is there an "expected response" at all?
- jb Ask ; if not, then forget about converting
- cmp option + 'c' - 'a',2 ; should we be case sensitive?
- je Ask ; if so, then forget about converting
-
- ; convert "expected response" to upper case
- mov cx,[di] ; length of "expected response"
- mov bx,[di+2] ; point to the actual string
-
- Convert:
- mov al,[bx] ; get a character from "expected response"
- cmp al,'a' ; see if it's a lower case letter
- jb NotLow
- cmp al,'z'
- ja NotLow
-
- ; alright, we have a lower case letter here, make it upper and store it back
- sub al,32
- mov [bx],al
-
- NotLow: inc bx ; point to next char
- dec cx ; decrement length
- jnz Convert ; until all characters are converted
-
- Ask: call PrtS ; print first parameter (the prompt)
- mov ah,1 ; keyboard input function code
- int 21h ; get a char
- mov char,al ; save it
-
- mov dx,offset crlf ; print a carriage return
- mov ah,9
- int 21h
-
- ; now see if the /c option is on or off
- mov al,char ; get it back
- cmp byte ptr [option+'c'-'a'],2
- je NoCase ; no case translation if on
-
- ; translate to upper case
- cmp al,'a'
- jb NoCase
- cmp al,'z'
- ja NoCase
- sub al,32 ; convert lower case to upper case
-
- NoCase: cmp mc,2 ; test if expected response is present
- jb Die ; if not present, just return the ASCII
-
- ; now we should try to search the key pressed with expected response
- mov cx,[di] ; length of string
- mov bx,[di+2] ; start of string
- mov ah,al ; mov char into ah
- xor al,al ; use this to keep track of the index
-
- Search: inc al ; adjust index
- cmp [bx],ah ; match ?
- je Die ; if so, exit with index as errorlevel
- inc bx ; point to next char
- dec cx ; more to check?
- jnz Search
-
- ; ok, no match, what should we do?
- xor al,al ; return this if quiet option is set
- cmp option + 'q' - 'a',2 ; quiet option set?
- je Die ; return with errorlevel = 0
-
- mov dx,offset nom ; quiet option not set, so yell at user!
- mov ah,9
- int 21h
- jmp Ask ; prompt user again until he gets it right
-
- Die: mov ah,4ch ; terminate; errorlevel in al
- int 21h
-
- Start endp
- All ends
- end Entry