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