home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / batutil / ask.asm < prev    next >
Assembly Source File  |  1994-03-04  |  14KB  |  365 lines

  1.  
  2.  
  3. ; ASK program to enable you to ask questions and let users type in a
  4. ; one-character response. This allows you to build simple menu-driven
  5. ; batch file or yes/no type questions.
  6. ;
  7. ; See the external docuementation for more details.
  8. ; Written by Peter Wu; April, 1986
  9. ; UUCP: {seismo|ihnp4|harvard|ucbvax|allegra|topaz}!uwvax!uwmacc!pwu
  10. ; ARPA: pwu@unix.macc.uwisc.edu
  11. ;
  12. argl    equ     80h             ; start of command line
  13. special equ     '^'             ; the special escape character
  14. switch  equ     '/'             ; switch character preceeding options
  15. cmdlen  equ     150             ; max length of converted cmd line
  16. maxargc equ     4               ; max # of arguements
  17. squote  equ     39              ; ASCII of '
  18.  
  19. all     segment 'code'
  20.         assume  cs:all,ds:all
  21.         org     100h
  22. entry:  jmp     start
  23.  
  24. ;********************** data area ***********************
  25. line    db      cmdlen dup(?)   ; store the converted command line
  26. argc    db      ?
  27. argv    dw      maxargc * 2 dup(?)      ; *argv[]
  28. 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
  29.               ; 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
  30.                 ; 0 = option off, 1=invalid option, 2 = option on
  31. cry     db      'unknown option ',squote
  32. unkopt  db      ?               ; fill in the unknown option here
  33.         db      squote,' ignored',13,10,'$'
  34.  
  35. ;*********************** code area **********************
  36. ; getc returns a converted character. bx should point to command line
  37. ; cl should contain the length of the command line
  38. ; ah=0 if normal character; ah='\' if special character.
  39.  
  40. three   db      ?               ; for counting down from 3
  41. ten     db      10              ; for multiplying
  42.  
  43. getc    proc    near
  44.         xor     ax,ax           ; clear character
  45.         sub     cl,1            ; len = len - 1
  46.         jc      eoln            ; reached end of command line
  47.  
  48.         mov     al,[bx]         ; get a character
  49.         inc     bx              ; point to next one
  50.         cmp     al,special      ; is it the special char '\' ?
  51.         jnz     normal          ; nop; just a normal character
  52.  
  53.         sub     cl,1            ; len = len - 1
  54.         jc      eoln            ; last character is '\'; ignore it
  55.  
  56.         mov     ah,al           ; flag special char
  57.         mov     al,[bx]         ; get the next char
  58.         inc     bx              ; point to next char
  59.  
  60. ; translate \nnn characters into ascii
  61.         cmp     al,'0'          ; see if first n is a digit
  62.         jb      notdig          ; not a digit
  63.         cmp     al,'9'
  64.         ja      notdig          ; not a digit
  65.  
  66. ; first n is a digit
  67.         xor     ch,ch           ; init accumulator
  68.         mov     three,3         ; convert 3 digits at most
  69.  
  70. digit:
  71.         sub     al,'0'          ; convert to binary
  72. ; now multiply cl by ten and add al to it
  73.         xchg    al,ch           ; do this so we can use al to multiply
  74.         mul     ten             ; assume result is still 8 bits
  75.         add     ch,al           ; one digit is done.
  76.  
  77. ; more digits?
  78.         dec     three
  79.         jz      gotit           ; converted all three digits
  80.         mov     al,[bx]         ; examine next char
  81.         cmp     al,'0'          ; is it a digit
  82.         jb      gotit           ; not a digit; end translation
  83.         cmp     al,'9'
  84.         ja      gotit           ; not a digit; end translation
  85.         inc     bx              ; point to next char
  86.         jmp     digit           ; process digit
  87.  
  88. gotit:
  89.         mov     ah,special      ; flag special char even for \nnn
  90.         mov     al,ch           ; return char in al
  91.         ret
  92. normal:
  93.         ret
  94.  
  95. notdig:                         ; not \nnn (e.g. \a \b \c \d ...)
  96.         cmp     al,special      ; \\ => \
  97.         je      skip
  98.         cmp     al,'"'          ; \" => "
  99.         je      skip
  100.         and     al,31           ; \a => ctrl-a; \b => ctrl-b; ...
  101. skip:
  102.         ret
  103.  
  104. eoln:
  105.         xor     ax,ax           ; return end-of-line char
  106.         ret
  107.  
  108. getc    endp
  109.  
  110. ;*********************** prts **********************
  111. count   dw      ?
  112. p       dw      ?
  113.  
  114. prts    proc    near            ; print string to stdout; si points to string
  115.         mov     ax,[si+2]       ; pointer to string
  116.         mov     p,ax            ; save pointer
  117.         mov     ax,[si]         ; get length of string
  118.         mov     count,ax
  119.  
  120. ploop:  sub     count,1
  121.         jc      d1              ; end of string
  122.         mov     bx,p
  123.         mov     dl,[bx]         ; current character to be printed
  124.         inc     p               ; point to next character
  125.         mov     ah,2            ; function number for print character
  126.         int     21h             ; print character
  127.         jmp     ploop           ; repeat
  128.  
  129. d1:     ret
  130. prts    endp
  131.  
  132. ;********************* main *********************
  133.  
  134. mc      db      ?               ; loop index
  135. char    db      ?               ; key pressed by user
  136.  
  137. crlf    db      13,10,'$'       ; crlf string
  138.  
  139. helpms  db      'Usage:',13,10
  140.         db      '  ask [',switch,'c',switch,'q] '
  141.         db      '"prompt message" "expected response"',13,10,10
  142.         db      '    ',switch
  143.         db      'c makes the response case sensitive',13,10
  144.         db      '    ',switch,'q will accept non-expected response (returns'
  145.         db      ' 0)',13,10
  146.         db      '    "prompt message" and "expected response" are quoted'
  147.         db      ' strings',13,10
  148.         db      '    To embed special characters use ',special
  149.         db      'nnn where nnn is a 3-digit ASCII',13,10
  150.         db      '    or ',special,'a for ctrl-a, ',special,'b for'
  151.         db      ' ctrl-b, ... (except ',special,special,' for ',special
  152.         db      ' itself',13,10,'    and ^" for the quote character)',13,10
  153.         db      '  Response can be tested with if errorlevel',13,10
  154.         db      '  Errorlevel is set to index("expected response",key '
  155.         db      'pressed)',13,10,10
  156.         db      'See the external document for more information',13,10
  157.         db      '$'
  158. nom     db      '*BEEP*  Unexpected response',13,10,10,'$'
  159.  
  160. start   proc    near
  161.  
  162.         mov     bx,argl         ; start of parameters
  163.         mov     cl,[bx]         ; length of parameter
  164.         inc     bx              ; now point to first char
  165.         mov     di,offset line  ; point to convert line buffer
  166.         mov     si,offset argv - 4      ; point to *argv[0] - 4
  167.  
  168.         mov     argc,0          ; normally start at 1; but for ask.com 0 is ok
  169.  
  170. ; now split command line into arguements in argv[]
  171. loop:
  172.         cmp     argc,maxargc    ; can we handle more arguements?
  173.         jae     done            ; if not; get out
  174.  
  175.         call    getc            ; convert one character
  176.         or      ax,ax           ; check for done
  177.         jz      done            ; end of command line
  178.  
  179.         cmp     al,' '          ; a blank space?
  180.         jz      loop            ; skip it
  181.  
  182. ; now we must be seeing the beginning of an arguement
  183.         inc     argc            ; count it
  184.         add     si,4            ; point to next *argv[]
  185.         mov     [si+2],di       ; where string start
  186.         mov     word ptr [si],0 ; set length to 0
  187.  
  188.         mov     dx,' '          ; assume this is the separator
  189.         cmp     ax,'"'          ; start of quoted string?
  190.         jne     noquote         ;
  191.         mov     dx,'"'          ; make this the separator
  192.         jmp     next            ; don't store the first "
  193.  
  194. noquote:
  195.         mov     [di],al         ; store the character
  196.         inc     di
  197.         inc     word ptr [si]   ; increment argv's length
  198. next:
  199.         call    getc
  200.         or      ax,ax
  201.         jz      done            ; end of arguement
  202.  
  203.         cmp     ax,dx           ; is this the separator?
  204.         jz      loop            ; find next arguement
  205.  
  206.         jmp     noquote         ; keep storing
  207.  
  208. ; now done with splitting argv[]'s
  209. done:
  210. ; now let's check for options
  211.         mov     ah,argc
  212.         mov     mc,ah           ; for mc = argc downto 1 do
  213.         mov     si,offset argv - 4
  214.         or      ah,ah           ; do we any argv at all?
  215.         jz      endopt
  216. more:
  217.         add     si,4            ; point to *argv[0,1,2,...]
  218.         mov     bx,[si+2]       ; address of string
  219.         cmp     byte ptr [bx],switch    ; is this string an option?
  220.         jnz     endopt          ; no more options
  221.  
  222. ; process this option (option can be /abc or /a /b /c or /a/b/c)
  223.         mov     cx,[si]         ; length of option string
  224. mopts:
  225.         inc     bx              ; point to char after the switch
  226.         dec     cx              ; decrement length of option string
  227.         jz      nextop          ; done with this option string. Next.
  228.  
  229. ; now scrutinize the option letter
  230.         mov     al,[bx]         ; the option letter
  231.         cmp     al,switch       ; is the switch embedded in here?
  232.         je      mopts           ; ignore it
  233.  
  234.         cmp     al,'A'          ; check for legal option letters
  235.         jb      badopt
  236.         cmp     al,'Z'
  237.         jbe     goodopt         ; a valid uppercase option letter
  238.  
  239.         cmp     al,'a'
  240.         jb      badopt
  241.         cmp     al,'z'
  242.         ja      badopt
  243.  
  244. goodopt:
  245.         mov     dl,al           ; save option letter in case of error
  246.         and     al,31           ; convert to 1-26
  247.         dec     al              ; convert to 0-25
  248.         xor     ah,ah
  249.         mov     di,ax           ; use as an index
  250.         mov     al,dl           ; in case we need this to print error
  251.         cmp     option[di],1    ; check if this is a known option
  252.         je      badopt          ; if not, yell at user
  253.         mov     option[di],2    ; set the option
  254.         jmp     mopts           ; go look at next option char.
  255.  
  256. badopt:                         ; yell at user for bad option character
  257.         mov     unkopt,al
  258.         mov     dx,offset cry
  259.         mov     ah,9            ; print the error message
  260.         int     21h
  261.         jmp     mopts           ; look at next option char.
  262.  
  263. nextop:
  264.         dec     mc              ; count down argc
  265.         jnz     more
  266.  
  267. ; now process the parameters
  268. endopt:
  269.         cmp     mc,0            ; see if there's any arguements at all
  270.         ja      nohelp
  271.         mov     dx,offset helpms        ; if not, print a summary
  272.         mov     ah,9            ; print string
  273.         int     21h
  274.         xor     al,al           ; return code 0
  275.         jmp     die
  276.  
  277. nohelp:                         ; si is pointing to a parameter *argv[]
  278.         mov     di,si
  279.         add     di,4            ; if mc = 2 then di is pointing to the
  280.                                 ;  expected response string's argv[]
  281.  
  282. ; now see if we should convert the "expected response" to upper case
  283.         cmp     mc,2            ; is there an "expected response" at all?
  284.         jb      ask             ; if not, then forget about converting
  285.         cmp     option + 'c' - 'a',2    ; should we be case sensitive?
  286.         je      ask             ; if so, then forget about converting
  287.  
  288. ; convert "expected response" to upper case
  289.         mov     cx,[di]         ; length of "expected response"
  290.         mov     bx,[di+2]       ; point to the actual string
  291.  
  292. convert:
  293.         mov     al,[bx]         ; get a character from "expected response"
  294.         cmp     al,'a'          ; see if it's a lower case letter
  295.         jb      notlow
  296.         cmp     al,'z'
  297.         ja      notlow
  298.  
  299. ; alright, we have a lower case letter here, make it upper and store it back
  300.         sub     al,32
  301.         mov     [bx],al
  302.  
  303. notlow:
  304.         inc     bx              ; point to next char
  305.         dec     cx              ; decrement length
  306.         jnz     convert         ; until all characters are converted
  307.  
  308. ask:
  309.         call    prts            ; print first parameter (the prompt)
  310.         mov     ah,1            ; keyboard input function code
  311.         int     21h             ; get a char
  312.         mov     char,al         ; save it
  313.  
  314.         mov     dx,offset crlf  ; print a carriage return
  315.         mov     ah,9
  316.         int     21h
  317.  
  318. ; now see if the /c option is on or off
  319.         mov     al,char         ; get it back
  320.         cmp     byte ptr [option+'c'-'a'],2
  321.         je      nocase          ; no case translation if on
  322.  
  323. ; translate to upper case
  324.         cmp     al,'a'
  325.         jb      nocase
  326.         cmp     al,'z'
  327.         ja      nocase
  328.         sub     al,32           ; convert lower case to upper case
  329.  
  330. nocase:
  331.         cmp     mc,2            ; test if expected response is present
  332.         jb      die             ; if not present, just return the ASCII
  333.  
  334. ; now we should try to search the key pressed with expected response
  335.         mov     cx,[di]         ; length of string
  336.         mov     bx,[di+2]       ; start of string
  337.         mov     ah,al           ; mov char into ah
  338.         xor     al,al           ; use this to keep track of the index
  339.  
  340. search:
  341.         inc     al              ; adjust index
  342.         cmp     [bx],ah         ; match ?
  343.         je      die             ; if so, exit with index as errorlevel
  344.         inc     bx              ; point to next char
  345.         dec     cx              ; more to check?
  346.         jnz     search
  347.  
  348. ; ok, no match, what should we do?
  349.         xor     al,al           ; return this if quiet option is set
  350.         cmp     option + 'q' - 'a',2    ; quiet option set?
  351.         je      die             ; return with errorlevel = 0
  352.  
  353.         mov     dx,offset nom   ; quiet option not set, so yell at user!
  354.         mov     ah,9
  355.         int     21h
  356.         jmp     ask             ; prompt user again until he gets it right
  357.  
  358. die:
  359.         mov     ah,4ch          ; terminate; errorlevel in al
  360.         int     21h
  361.  
  362. start   endp
  363. all     ends
  364.         end     entry
  365.