UMBC CMSC 211

UMBC | CSEE |


The Utility Routines ParseCmd, CCheck, and WCheck

ParseCmd

;;  PARSECMD.ASM--A function which returns successively with es:si
;;   pointing to null-terminated command-line arguments.  When the
;;   end of the arguments is reached, returns si = 0
;;
;;  Program text (c) Copyright 2001 Scott/Jones Inc.
;;
        .MODEL  SMALL
        .586

IFDEF   ??version
PSP     SEGMENT 0 USE16
ELSE
PSP     SEGMENT AT 0
ENDIF

        ORG     80h
CmdLen  DB      ?
Command DB      127 DUP (?)
PSP     ENDS

        .DATA
        PUBLIC  CmdTail ;   RedirErr uses CmdTail

CmdTail DD      0 ;    Segment of 0 indicates CmdTail not yet

;                       initialized (state 1).  Seg <> 0 and
;                       offset = 0 indicates we've reached the
;                       end of the command line
CMDSEG  EQU     WORD PTR CmdTail + 2 ;  Low order first
CMDOFF  EQU     WORD PTR CmdTail
CR      EQU     13
TAB     EQU     9
Warning DB      'Warning:  ParseCmd assuming es = SEG PSP'
        DB      13, 10, '$'

        .CODE
        Public  ParseCmd

ParseCmd PROC

        push    ds
        push    bx
        push    ax
        mov     si, @data ; Using si as we needn't save and 
        mov     ds, si ;     restore it
        ASSUME  ds : @data, es : NOTHING
        cmp     CMDSEG, 0
        jne     NotFirst ;  Not first call to ParseCmd
        push    ax ;     State 1:  Use DOS call to get PSP loc
        mov     ah, 62h
        int     21h ;     Get PSP segment from DOS
        mov     CMDSEG, bx

GetOff:
        mov     CMDOFF, OFFSET Command

        mov     es, bx ;    Check for correct length
        ASSUME  es : PSP
        mov     bl, CmdLen
        sub     bh, bh
        cmp     bx, 126
        jbe     LenOK
        mov     CmdLen, 126

LenOK:  mov     [Command + bx], CR ; make sure terminated with CR

        pop     ax

NotFirst:       ;   State 2 or 3?
        les     si, CmdTail
        test    si, si
        jz      Done ; State 3; Offset 0 indicates no more params

ParseLoop:      ;   State 2:  May be more params
        mov     ah, es:[si] ; skip over initial white space
        cmp     ah, ' '
        je      SkipIt
        cmp     ah, TAB ;   9 = TAB
        jne     IsQuote?

SkipIt:
        inc     si
        jmp     ParseLoop

IsQuote?:       ;   found start of token; is it a quote?
        cmp     ah, CR
        je      NoMore ;    Reached end of command line
        cmp     ah, '"'
        je      ItsAQuote
        cmp     ah, "'"
        je      ItsAQuote
        mov     ah, ' ' ;   ah = param terminator
        jmp     FindEnd

ItsAQuote:
        inc     si ;    skip over quote mark

FindEnd:
        mov     bx, si;  search for end of parameter

EndLoop:
        mov     al, es:[bx]
        cmp     al, CR ;    Return ends it even if quoted
        je      NoMore1 ;   no parameters after this one
        cmp     ah, al ;    is it the terminator
        je      Done
        cmp     ah, ' ' ;   If the terminator is a blank,
        jne     NextChar ;   tab also terminates
        cmp     al, TAB
        je      Done

NextChar:
        inc     bx
        jmp     EndLoop
    
NoMore:
        mov     si, 0
        mov     CMDOFF, si
        jmp     Done1

NoMore1:        ;   Go to State 3
        mov     CMDOFF, 0
        mov     BYTE PTR es:[bx], 0 ;   null-terminate param
        jmp     Done1

Done:
        mov     BYTE PTR es:[bx], 0 ;   null-terminate param
        inc     bx
        mov     CMDOFF, bx ;            Prepare for next param

Done1:
        pop     ax
        pop     bx
        pop     ds
        ret

ParseCmd    ENDP

        END                        ; Notice no label here!

  

CCHECK and WCHECK

;; ERRMSG.ASM--two procedures for checking for errors on DOS commands.
;;
;;  CCheck  checks for CFlag set and if so, prints error whose
;;      number is is in ax.  Not all messages available
;;      (Should contain those for I/O, EXEC, and Mem Alloc)
;;      _Exits with code 1 if error
;;  WCheck  Used for _Write command.  First does CCheck and if
;;      that returns, compares ax = number of bytes written
;;      to cx = number of bytes requested to write and
;;      prints message and _Exits with code 2
;;
;;  Library source text from "Assembly Language for the IBM PC Family" by
;;   William B. Jones, (c) Copyright 1992, 1997, 2001, Scott/Jones Inc.
;;
        .MODEL  SMALL
        .586
INCLUDE PCMAC.INC

        .DATA
;*** first, as list of messages:
Inval   DB      'Invalid function number$'
NotFnd  DB      'File not found$'
Path    DB      'Path not found$'
TooMany DB      'Too many open files$'
Access  DB      'Access denied$'
Handle  DB      'Invalid handle$'
Corrupt DB      'Memory control blocks destroyed$'
NoMem   DB      'Insufficient memory$'
Block   DB      'Invalid memory block address$'
Envir   DB      'Invalid environment$'
Format  DB      'Invalid format$'
ACode   DB      'Invalid access code$'
Drive   DB      'Invalid drive specified$'
Device  DB      'Not same device$'
Files   DB      'No more files$'
Unk     DB      'Unknown error number$'


;*** Then, an array Msg of pointers such that Msg[n] = offset of 
;***  message for error n


Msg     DW      ?, Inval, NotFnd, Path, TooMany, Access, Handle, Corrupt
        DW      NoMem, Block, Envir, Format, ACode, Unk, Unk, Drive, Unk
        DW      Device, Files
MSGLIM  EQU     ($ - Msg - 2) /2

;*** Message for write count error

WrtCnt  DB      'Different number of bytes written than requested$'
Err1    DB      '*** DOS call ERROR at $'
Err2    DB      'h *** $'
CRLF    DB      13, 10, '$'

        .CODE
        PUBLIC  CCheck, WCheck
        EXTRN   PutHex : NEAR

CCheck  PROC
        jc      DoMessage
        ret

DoMessage:
        mov     bx, @data
        mov     ds, bx          ; Just in case
        mov     bx, ax
        _PutStr Err1
        pop     ax              ; Return address is location of error
        call    PutHex          ; (Don't need it any more)
        _PutStr Err2
        cmp     bx, 1
        jl      DispUnk         ; Just in case
        cmp     bx, MSGLIM
        jg      DispUnk
        shl     bx, 1
        add     bx, OFFSET Msg  ; bx --> appropriate error message
        mov     dx, [bx]
        mov     ah, 09h
        int     21h

Finish:

        _PutStr CRLF
        _Exit   1

DispUnk:
        _PutStr Unk
        jmp     Finish

CCheck  ENDP

WCheck  PROC

        jnc     NoDOSErr
        jmp     CCheck ;    Don't destroy original return address!

NoDOSErr:

        cmp     ax, cx
        jne     WErr
        ret

WErr:
        _PutStr Err1, @data
        pop     ax
        call    PutHex
        _PutStr Err2
        _PutStr WrtCnt
        _PutStr CRLF

        _Exit   2

WCheck  ENDP
        END
  


UMBC | CSEE