home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / advos2 / ch12 / tinycmd.asm < prev    next >
Encoding:
Assembly Source File  |  1988-12-12  |  11.6 KB  |  318 lines

  1.     title    TINYCMD -- Simple Command Interpreter
  2.         page    55,132
  3.     .286
  4.  
  5. ;
  6. ; TINYCMD.ASM
  7. ;
  8. ; A simple command interpreter for OS/2.
  9. ;
  10. ; Assemble with:  C> masm tinycmd.asm;
  11. ; Link with:  C> link tinycmd,,,os2,tinycmd
  12. ; Usage is:  C> tinycmd
  13. ;
  14. ; Copyright (C) 1988 Ray Duncan
  15. ;
  16.  
  17. cr      equ     0dh                     ; ASCII carriage return
  18. lf    equ    0ah            ; ASCII linefeed
  19. tab     equ     09h                     ; ASCII tab
  20. blank   equ     20h                     ; ASCII blank code
  21. escape  equ     01bh                    ; ASCII escape code
  22.  
  23. inpsize equ     80                      ; maximum input length
  24.  
  25.         extrn   DosExecPgm:far          ; OS/2 API functions
  26.         extrn   DosExit:far
  27.         extrn   DosGetVersion:far
  28.         extrn   KbdStringIn:far
  29.         extrn   VioWrtTTY:far
  30.  
  31. DGROUP  group   _DATA
  32.  
  33. _DATA   segment word public 'DATA'
  34.  
  35. ; Intrinsic commands table: Each entry is an ASCIIZ string
  36. ; followed by the offset of the corresponding procedure.
  37.  
  38. commands label  byte
  39.     db    'CLS',0         ; clear screen command
  40.         dw      cls_cmd
  41.         db      'VER',0                 ; display OS/2 version
  42.         dw      ver_cmd
  43.         db      'EXIT',0                ; exit from TINYCMD
  44.         dw      exit_cmd
  45.         db      0                       ; end of table
  46.  
  47. input   db      (inpsize+2) dup (0)     ; keyboard input buffer
  48. ibinfo  dw      inpsize,0               ; input buffer info
  49.  
  50. pbuff   db      (inpsize+2) dup (0)     ; program name moved here
  51.  
  52. cinfo   dw      0                       ; child termination type
  53.         dw      0                       ; child return code
  54.  
  55. prompt  db      cr,lf,'>> '             ; TINYCMD's user prompt
  56. pr_len  equ     $-prompt
  57.  
  58. delims  db      0,blank,tab,';,='       ; delimiters for first  
  59. de_len  equ     $-delims                ; command line token
  60.  
  61. pext    db      '.EXE',0                ; program file extension
  62. pe_len equ      $-pext
  63.  
  64. wlen    dw      0                       ; receives bytes written
  65. verinfo db      0,0                     ; receives OS/2 version
  66.  
  67. msg1    db      cr,lf,lf                ; error message
  68.         db      'Bad command or filename'
  69.         db      cr,lf
  70. msg1_len equ    $-msg1
  71.  
  72. msg2    db      escape,'[2J'            ; ANSI escape sequence
  73. msg2_len equ    $-msg2                  ; to clear the screen
  74.  
  75. msg3    db      cr,lf,lf                ; version number message
  76.         db      'OS/2 version '
  77. msg3a   db      'nn.'
  78. msg3b   db      'nn'
  79.         db      cr,lf
  80. msg3_len equ    $-msg3
  81.  
  82. _DATA   ends
  83.  
  84.  
  85. _TEXT   segment word public 'CODE'
  86.  
  87.         assume  cs:_TEXT,ds:DGROUP,es:DGROUP
  88.  
  89. main    proc    far                     ; entry point from OS/2
  90.  
  91.         push    ds                      ; make DGROUP addressable
  92.         pop     es                      ;  with ES too
  93.         cld                             ; clear direction flag
  94.  
  95. main1:                                  ; main interpreter loop
  96.         call    gcmd                    ; get command from user
  97.  
  98.         call    intrinsic               ; check if intrinsic function
  99.         jnc     main1                   ; yes, it was processed
  100.  
  101.     call    extrinsic        ; no, run EXE file, then
  102.         jmp     main1                   ; get another command
  103.  
  104. main    endp
  105.  
  106. ; Try to match first command token against COMMANDS table.
  107. ; If match, run the routine, return Carry = False.
  108. ; If no match, return Carry = True.
  109.  
  110. intrinsic proc  near
  111.                                 
  112.                                         ; point to command table
  113.         mov     si,offset DGROUP:commands
  114.  
  115. intr1:                                  ; try next table entry...
  116.         cmp     byte ptr [si],0         ; end of entire table?
  117.         je      intr6                   ; jump if table exhausted
  118.  
  119.         mov     di,offset DGROUP:input  ; point to user's command
  120.  
  121. intr2:  mov     al,[si]                 ; next character from table
  122.  
  123.         or      al,al                   ; end of table entry?
  124.         jz      intr3                   ; yes, jump
  125.  
  126.         cmp     al,[di]                 ; compare to input character
  127.         jnz     intr4                   ; jump, found mismatch
  128.  
  129.         inc     si                      ; advance string pointers
  130.         inc     di
  131.         jmp     intr2
  132.  
  133. intr3:  cmp     byte ptr [di],0         ; user's entry same length?
  134.         jne     intr5                   ; no, not a match
  135.  
  136.         call    word ptr [si+1]         ; run the command routine
  137.  
  138.         clc                             ; return Carry = False
  139.         ret                             ; as success signal
  140.  
  141. intr4:  lodsb                           ; look for end of this
  142.         or      al,al                   ; command string (null byte)
  143.         jnz     intr4                   ; not end yet, loop
  144.  
  145. intr5:  add     si,2                    ; skip over routine address
  146.         jmp     intr1                   ; try to match next command
  147.  
  148. intr6:  stc                             ; command not matched, exit
  149.         ret                             ; with Carry = True
  150.  
  151. intrinsic endp
  152.  
  153. ; Append .EXE to first token and attempt to execute program, 
  154. ; passing address of argument strings block and null pointer 
  155. ; for environment (child process inherits TINYCMD's environment).
  156.  
  157. extrinsic proc  near
  158.  
  159.         mov     si,offset DGROUP:input  ; copy first token of
  160.         mov     di,offset DGROUP:pbuff  ; user command to pbuff
  161.  
  162. extr1:  lodsb                           ; get next character
  163.         or      al,al                   ; found null?
  164.         jz      extr2                   ; yes, end of token
  165.         stosb                           ; no, copy character
  166.         jmp     extr1                   ; and get next char.
  167.  
  168. extr2:  mov     si,offset DGROUP:pext   ; append .EXE extension
  169.         mov     cx,pe_len               ; to token, forming 
  170.         rep movsb                       ; program filename
  171.  
  172.                                         ; try and run program...
  173.         push    0                       ; object name buffer
  174.         push    0
  175.         push    0                       ; object name buffer length
  176.     push    0            ; asynchronous execution mode
  177.     push    ds            ; address of argument strings
  178.         push    offset DGROUP:input
  179.         push    0                       ; environment pointer
  180.         push    0
  181.         push    ds                      ; receives termination info
  182.         push    offset DGROUP:cinfo
  183.         push    ds                      ; address of program name
  184.         push    offset DGROUP:pbuff
  185.         call    DosExecPgm              ; transfer to OS/2
  186.         or      ax,ax                   ; was function successful?
  187.         jz      extr3                   ; yes, jump
  188.  
  189.                                         ; no, display error message...
  190.         push    ds                      ; message address
  191.         push    offset DGROUP:msg1
  192.         push    msg1_len                ; message length
  193.         push    0                       ; default video handle
  194.         call    VioWrtTTY               ; transfer to OS/2
  195.  
  196. extr3:  ret                             ; back to caller
  197.  
  198. extrinsic endp
  199.  
  200. ; Get input from user, convert it to argument strings block
  201. ; by breaking out first token with null and appending double
  202. ; null to entire line, and convert first token to uppercase.
  203.  
  204. gcmd    proc    near                    ; prompt user, get command
  205.  
  206.                                         ; display TINYCMD prompt...
  207.         push    ds                      ; address of prompt
  208.         push    offset DGROUP:prompt
  209.         push    pr_len                  ; length of prompt
  210.         push    0                       ; default video handle
  211.         call    VioWrtTTY
  212.  
  213.         mov     ibinfo+2,0              ; disable buffer editing
  214.  
  215.                                         ; get entry from user...
  216.         push    ds                      ; address of input buffer
  217.         push    offset DGROUP:input
  218.         push    ds                      ; input buffer info
  219.         push    offset DGROUP:ibinfo
  220.         push    0                       ; 0 = wait for input
  221.         push    0                       ; default keyboard handle
  222.         call    KbdStringIn
  223.  
  224.         mov     cx,inpsize              ; look for carriage return
  225.         mov     al,cr                   ; if any...     
  226.         mov     di,offset DGROUP:input
  227.         repnz scasb
  228.         jnz     gcmd1
  229.         dec     di
  230. gcmd1:    mov    word ptr [di],0     ; and replace with 2 nulls
  231.         mov     si,offset DGROUP:input  ; break out first token...
  232.  
  233. gcmd2:  lodsb                           ; compare next character 
  234.         mov     di,offset DGROUP:delims ; to delimiter table
  235.         mov     cx,de_len
  236.         repnz scasb
  237.         jnz     gcmd2                   ; jump, no match
  238.         mov     byte ptr [si-1],0       ; replace delimiter with 0
  239.  
  240.     mov    si,offset DGROUP:input    ; fold token to uppercase
  241.  
  242. gcmd3:  cmp     byte ptr [si],0         ; end of token?
  243.         jz      gcmd5                   ; found end, jump
  244.         cmp     byte ptr [si],'a'       
  245.         jb      gcmd4                   ; jump if not 'a-z'
  246.         cmp     byte ptr [si],'z'
  247.         ja      gcmd4                   ; jump if not 'a-z'
  248.     sub    byte ptr [si],'a'-'A'    ; convert to uppercase
  249.  
  250. gcmd4:  inc     si                      ; go to next character
  251.         jmp     gcmd3
  252.  
  253. gcmd5:  ret                             ; back to caller
  254.  
  255. gcmd    endp
  256.  
  257.  
  258. cls_cmd proc    near                    ; intrinsic CLS command 
  259.  
  260.                                         ; send ANSI escape sequence
  261.                                         ; to clear the screen...
  262.         push    ds                      ; escape sequence address
  263.         push    offset DGROUP:msg2
  264.         push    msg2_len                ; escape sequence length
  265.         push    0                       ; default video handle
  266.         call    VioWrtTTY               ; transfer to OS/2
  267.         ret                             ; back to caller
  268.  
  269. cls_cmd endp
  270.  
  271.  
  272. ver_cmd proc    near                    ; intrinsic VER command
  273.  
  274.                                         ; get OS/2 version number...
  275.         push    ds                      ; receives version info
  276.         push    offset DGROUP:verinfo
  277.         call    DosGetVersion           ; transfer to OS/2
  278.  
  279.                                         ; format the version...
  280.         mov     al,verinfo              ; convert minor version 
  281.         aam                             ; number to ASCII
  282.         add     ax,'00'
  283.         xchg    al,ah
  284.         mov     word ptr msg3b,ax       ; store ASCII characters
  285.  
  286.         mov     al,verinfo+1            ; convert major version 
  287.         aam                             ; number to ASCII
  288.         add     ax,'00'
  289.         xchg    al,ah
  290.         mov     word ptr msg3a,ax       ; store ASCII characters
  291.  
  292.                                         ; display version number...     
  293.         push    ds                      ; message address
  294.         push    offset DGROUP:msg3
  295.         push    msg3_len                ; message length
  296.         push    0                       ; default video handle
  297.         call    VioWrtTTY               ; transfer to OS/2
  298.  
  299.         ret                             ; back to caller
  300.  
  301. ver_cmd endp
  302.  
  303.  
  304. exit_cmd proc   near                    ; intrinsic EXIT Command 
  305.  
  306.                                         ; final exit to OS/2...
  307.         push    1                       ; terminate all threads
  308.         push    0                       ; return code = 0
  309.         call    DosExit                 ; transfer to OS/2
  310.  
  311. exit_cmd endp
  312.  
  313. _TEXT   ends
  314.  
  315.         end     main                    ; defines entry point
  316. 
  317.