| UMBC CMSC 211 |
;; 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!
;; 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