729 lines
16 KiB
NASM
729 lines
16 KiB
NASM
NAME SETARGV
|
||
PAGE 60,132
|
||
;[]------------------------------------------------------------[]
|
||
;| SETARGV.ASM -- Parse Command Line |
|
||
;| |
|
||
;| Turbo-C Run Time Library version 2.0 |
|
||
;| |
|
||
;| Copyright (c) 1988 by Borland International Inc. |
|
||
;| All Rights Reserved. |
|
||
;[]------------------------------------------------------------[]
|
||
|
||
INCLUDE RULES.ASI
|
||
|
||
; Segment and Group declarations
|
||
|
||
Header@
|
||
|
||
; External references
|
||
|
||
ExtSym@ _argc, WORD, __CDECL__
|
||
dPtrExt@ _argv, __CDECL__
|
||
ExtSym@ _psp, WORD, __CDECL__
|
||
ExtSym@ _envseg, WORD, __CDECL__
|
||
ExtSym@ _envLng, WORD, __CDECL__
|
||
ExtSym@ _osmajor, BYTE, __CDECL__
|
||
ExtProc@ abort, __CDECL__
|
||
|
||
ifdef WILD
|
||
ExtProc@ sbrk, __CDECL__
|
||
endif
|
||
|
||
SUBTTL Parse Command Line
|
||
PAGE
|
||
;/* */
|
||
;/*-----------------------------------------------------*/
|
||
;/* */
|
||
;/* Parse Command Line */
|
||
;/* ------------------ */
|
||
;/* */
|
||
;/*-----------------------------------------------------*/
|
||
;/* */
|
||
PSPCmd equ 00080h
|
||
|
||
CSeg@
|
||
|
||
IF LPROG
|
||
SavedReturn dd ?
|
||
ELSE
|
||
SavedReturn dw ?
|
||
ENDIF
|
||
SavedDS dw ?
|
||
SavedBP dw ?
|
||
|
||
|
||
ifdef WILD
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Not enough space on stack for the program name.
|
||
;
|
||
BadProgName label near
|
||
jmp abort@
|
||
|
||
endif
|
||
|
||
;==============================================================================
|
||
|
||
ifdef WILD
|
||
PubProc@ _wildargv, __CDECL__
|
||
else
|
||
PubProc@ _setargv, __CDECL__
|
||
endif
|
||
|
||
; First, save caller context and Return Address
|
||
|
||
pop word ptr SavedReturn
|
||
IF LPROG
|
||
pop word ptr SavedReturn+2
|
||
ENDIF
|
||
mov SavedDS, ds
|
||
cld
|
||
|
||
; Compute Command Line size
|
||
|
||
mov es, _psp@
|
||
mov si, PSPCmd ; ES: SI = Command Line address
|
||
xor ah, ah
|
||
lods byte ptr es:[si]
|
||
inc ax ; AX = Command Line size including \r
|
||
mov bp, es
|
||
xchg dx, si ; BP:DX = Command Line address
|
||
xchg bx, ax ; BX = Command line size
|
||
|
||
; Compute Program Name size
|
||
|
||
mov si, _envLng@
|
||
add si, 2 ; SI = Program name offset
|
||
mov cx, 1 ; CX = Filename size (includes \0)
|
||
cmp _osmajor@, 3
|
||
jb NoProgramName
|
||
mov es, _envseg@
|
||
mov di, si ; SI = argv[0] address
|
||
mov cl, 07fh
|
||
xor al, al
|
||
repnz scasb
|
||
jcxz BadProgName
|
||
xor cl, 07fh ; CX = Filename size (includes \0)
|
||
NoProgramName label near
|
||
|
||
; Reserve space for the arguments
|
||
|
||
sub sp, 2 ; To be sure nothing in SS:FFFF
|
||
mov ax, 1
|
||
ifndef WILD
|
||
add ax, bx
|
||
endif
|
||
add ax, cx
|
||
and ax, not 1
|
||
mov di, sp
|
||
sub di, ax
|
||
jb BadProgName
|
||
mov sp, di ; SS:DI = Command Line storage address
|
||
|
||
; Copy ProgName to the stack
|
||
|
||
mov ax, es
|
||
mov ds, ax
|
||
mov ax, ss
|
||
mov es, ax
|
||
ifndef WILD
|
||
push cx
|
||
endif
|
||
dec cx
|
||
rep movsb
|
||
xor al, al
|
||
stosb ; ASCIIZ string
|
||
|
||
; Process Command Line.
|
||
|
||
;==============================================================================
|
||
ifdef WILD
|
||
;==============================================================================
|
||
|
||
;
|
||
; The value of "wild_attr" is used in the "findfirst" call as the file
|
||
; attribute.
|
||
;
|
||
; The default value is 0, which will only include "regular" files.
|
||
;
|
||
; Adding 10H to this value will include directories, 04h will include system
|
||
; files, and 02h will include hidden files.
|
||
;
|
||
|
||
wild_attr equ 0 ; include only regular files
|
||
|
||
;------------------------------------------------------------------------------
|
||
|
||
ffblk struc
|
||
|
||
ff_reserved db 21 dup (?)
|
||
ff_attrib db ?
|
||
ff_ftime dw ?
|
||
ff_fdate dw ?
|
||
ff_fsize dd ?
|
||
ff_name db 14 dup (?)
|
||
|
||
ffblk ends
|
||
|
||
wild_init_space equ 128 ; initial buffer allocation
|
||
wild_more_space equ 256 ; buffer size increment
|
||
|
||
;------------------------------------------------------------------------------
|
||
|
||
wild_buff_addr equ [bp]
|
||
wild_buff_size equ [bp+4]
|
||
wild_buff_max equ [bp+6]
|
||
wild_arg_src equ [bp+8]
|
||
wild_arg_dst equ [bp+10]
|
||
|
||
wild_argument equ [bp+12]
|
||
wild_destin equ [bp+16]
|
||
wild_path_len equ [bp+20]
|
||
wild_argc equ [bp+22]
|
||
|
||
wild_DTA_save equ [bp+24]
|
||
wild_ffblk equ [bp+28]
|
||
|
||
wild_frame_size equ 28 + TYPE ffblk
|
||
|
||
;------------------------------------------------------------------------------
|
||
|
||
mov cx, bp ; save segment of command line
|
||
dec bx ; don't need trailing \0
|
||
|
||
sub sp, wild_frame_size
|
||
mov bp, sp ; bp points at local variables
|
||
|
||
push dx ; save cmd line addr
|
||
push cx ; save cmd line seg
|
||
push bx ; save cmd line size
|
||
mov ax, wild_init_space
|
||
mov wild_buff_size, ax ; save initial size
|
||
ifndef __HUGE__
|
||
mov ds, savedDS
|
||
endif
|
||
push ax
|
||
call sbrk@
|
||
pop cx ; toss parameter
|
||
pop cx ; restore cmd line size
|
||
pop ds ; restore cmd line seg
|
||
pop si ; restore cmd line addr
|
||
|
||
mov wild_buff_addr, ax ; save offset
|
||
if LDATA
|
||
mov wild_buff_addr+2, dx ; save segment
|
||
and ax, dx
|
||
else
|
||
mov wild_buff_addr+2, ss ; seg = SS
|
||
endif
|
||
cmp ax, -1
|
||
je NoSbrkSpace ; abort if not enough space
|
||
add ax, wild_buff_size
|
||
mov wild_buff_max, ax ; save max offset
|
||
|
||
mov ah, 2fh
|
||
int 21h ; get current DTA
|
||
mov wild_DTA_save, bx
|
||
mov wild_DTA_save+2, es
|
||
push ds
|
||
push ss ; fflbk is on stack
|
||
pop ds
|
||
lea dx, wild_ffblk
|
||
mov ah, 1ah
|
||
int 21h ; switch DTA to ffblk
|
||
pop ds
|
||
|
||
les di, dword ptr wild_buff_addr
|
||
xor dx, dx ; dx = # of arguments
|
||
;
|
||
; Start new argument.
|
||
;
|
||
NewArg: mov wild_arg_dst, di
|
||
xor bh, bh ; bh = wildcard flag
|
||
;
|
||
; Skip leading whitespace.
|
||
;
|
||
ArgCopy: mov wild_arg_src, si ; save address of argument
|
||
call GetChar
|
||
jc ArgCopyDone ; jump if no more characters
|
||
jz ArgCopyLoop
|
||
cmp al, ' '
|
||
je ArgCopy ; skip whitespace
|
||
cmp al, 9
|
||
je ArgCopy
|
||
cmp al, 13
|
||
je ArgCopy
|
||
cmp al, '"'
|
||
je ArgQuote ; jump if quoted string
|
||
;
|
||
; Loop to copy unquoted argument.
|
||
;
|
||
ArgCopyLoop: call ArgPushChar ; store character in destination
|
||
call GetChar
|
||
jc ArgComplete ; jump if end of line
|
||
jz ArgCopyLoop ; jump if \"
|
||
cmp al, ' '
|
||
je ArgComplete ; whitespace terminates
|
||
cmp al, 9
|
||
je ArgComplete
|
||
cmp al, 13
|
||
je ArgComplete ; whitespace terminates
|
||
cmp al, '"'
|
||
jne ArgCopyLoop
|
||
ArgComplete: call ProcessArg ; copy or expand argument
|
||
jmp SHORT NewArg
|
||
|
||
NoSbrkSpace: jmp abort@ ; error jump
|
||
|
||
;
|
||
; Here if quoted argument.
|
||
;
|
||
ArgQuote: call GetChar
|
||
jc QuoteDone
|
||
jz QuoteNext
|
||
cmp al, '"' ; terminating quote ?
|
||
je QuoteDone
|
||
QuoteNext: call ArgPushChar ; store character in destination
|
||
jmp SHORT ArgQuote
|
||
;
|
||
; End of a quoted argument. Push terminating null, do not expand.
|
||
;
|
||
QuoteDone: xor al, al
|
||
call ArgPushChar ; push terminating null
|
||
inc dx ; bump arg count
|
||
jmp SHORT NewArg ; go get more
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Here when done expanding command line. Go build the argv array.
|
||
;
|
||
ArgCopyDone: mov ax, di ; ax = unused space
|
||
sub ax, wild_buff_max
|
||
jz ArgNoWaste ; skip if all used
|
||
push dx
|
||
push di
|
||
ifndef __HUGE__
|
||
mov ds, savedDS
|
||
endif
|
||
push ax
|
||
call sbrk@ ; release unused memory
|
||
pop cx ; toss parameter
|
||
pop di
|
||
pop dx
|
||
ArgNoWaste: lds si, dword ptr wild_buff_addr
|
||
mov cx, di
|
||
sub cx, si ; cx = number of bytes in expanded line
|
||
inc dx ; count program name
|
||
jmp BuildArgv
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Routine to retrieve the next character from the command line.
|
||
; Sets CF when end of line reached.
|
||
; Sets ZF when \ character found (i.e. \")
|
||
;
|
||
; bh.bit0 set if wildcard chars found (* or ?)
|
||
; bh.bit1 set if \ character found (\")
|
||
;
|
||
GetChar proc near
|
||
|
||
jcxz GchEnd ; jump if no more
|
||
lodsb
|
||
dec cx
|
||
cmp al, '\' ; escape ?
|
||
je GchEsc
|
||
cmp al, '?'
|
||
je GchWild
|
||
cmp al, '*'
|
||
je GchWild
|
||
GchRet: or ah, 1 ; clear CF and ZF
|
||
ret
|
||
GchWild: test bh, bh
|
||
jnz GchRet ; give up if \" has been found
|
||
or bh, 1
|
||
ret
|
||
GchEsc: jcxz GchRet ; check for \ at end of line
|
||
cmp byte ptr [si],'"'
|
||
jne GchRet ; only \" is special
|
||
lodsb
|
||
dec cx
|
||
mov bh, 2 ; set \ flag
|
||
xor ah, ah ; clear CF, set ZF
|
||
ret
|
||
GchEnd: stc
|
||
ret
|
||
|
||
GetChar endp
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Routine to expand a wildcard parameter.
|
||
;
|
||
; DS:SI = argument address
|
||
; ES:DI = destination
|
||
; Returns:
|
||
; CX = number of expanded arguments (0 = no match)
|
||
;
|
||
WildExpand proc near
|
||
|
||
push ds
|
||
mov wild_argument, si
|
||
mov wild_argument+2, ds
|
||
mov wild_destin, di
|
||
mov wild_destin+2, es
|
||
mov word ptr wild_argc, 0
|
||
;
|
||
; Find the length of the path prefix, if any.
|
||
;
|
||
mov bx, si
|
||
WildFindPath: lodsb
|
||
and al, al
|
||
jz WildEndPath
|
||
cmp al, '\'
|
||
je WildDelimiter
|
||
cmp al, ':'
|
||
je WildDelimiter
|
||
cmp al, '\'
|
||
jne WildFindPath
|
||
WildDelimiter: mov bx, si ; save addr past last delimiter
|
||
jmp SHORT WildFindPath
|
||
WildEndPath: sub bx, wild_argument
|
||
mov wild_path_len, bx
|
||
|
||
mov ah, 4eh
|
||
mov cx, wild_attr ; file attribute
|
||
lds dx, dword ptr wild_argument
|
||
int 21h ; find first matching file ...
|
||
jc WildDone
|
||
;
|
||
; We have a matching file. Add it to the destination string (unless "." or "..")
|
||
;
|
||
WildAddArg:
|
||
;
|
||
; If directories are included (10h set in wild_attr), ignore "." and ".."
|
||
;
|
||
if wild_attr AND 10h
|
||
push ss
|
||
pop ds
|
||
lea si,wild_ffblk.ff_name
|
||
cmp byte ptr [si],'.' ; skip if doesn't start with "."
|
||
jne WildNoDir
|
||
cmp byte ptr [si+1],0 ; check for "."
|
||
je WildNameNext
|
||
cmp word ptr [si+1],'.' ; check for ".."
|
||
je WildNameNext
|
||
WildNoDir:
|
||
endif
|
||
|
||
inc word ptr wild_argc
|
||
les di, dword ptr wild_destin
|
||
mov cx, wild_path_len ; prefix filename with path
|
||
jcxz WildCopyName
|
||
lds si, dword ptr wild_argument
|
||
WildCopyPath: lodsb
|
||
call ArgPushChar
|
||
loop WildCopyPath
|
||
WildCopyName: lea si,wild_ffblk.ff_name ; copy filename from ffblk
|
||
WildNameLoop: lods byte ptr ss:[si]
|
||
push ax
|
||
call ArgPushChar ; store char in destination
|
||
pop ax
|
||
and al, al ; continue until \0
|
||
jnz WildNameLoop
|
||
mov wild_destin, di
|
||
WildNameNext: mov ah, 4fh
|
||
int 21h ; find next matching file
|
||
jnc WildAddArg
|
||
;
|
||
; Done with expansion. Restore ES:DI, set CX, and return.
|
||
;
|
||
WildDone: mov cx, wild_argc
|
||
les di, dword ptr wild_destin
|
||
pop ds
|
||
ret
|
||
|
||
WildExpand endp
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Routine to store a character in the destination string.
|
||
;
|
||
ArgPushChar proc near
|
||
|
||
cmp di, wild_buff_max ; space available ?
|
||
jae ArgMoreSpace
|
||
stosb ; yes --> store character
|
||
ret
|
||
;
|
||
; No more argument space. Grab some more memory through sbrk.
|
||
;
|
||
ArgMoreSpace: push ds
|
||
push es
|
||
push si
|
||
push di
|
||
push ax
|
||
push bx
|
||
push cx
|
||
push dx
|
||
|
||
ifndef __HUGE__
|
||
mov ds, savedDS
|
||
endif
|
||
mov ax, wild_more_space
|
||
add wild_buff_size, ax ; bump allocated size
|
||
add wild_buff_max, ax ; bump end pointer
|
||
push ax
|
||
call sbrk@
|
||
pop cx
|
||
if LDATA
|
||
and ax, dx
|
||
endif
|
||
cmp ax, -1
|
||
je NoArgSpace ; abort if not enough space
|
||
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
pop ax
|
||
pop di
|
||
pop si
|
||
pop es
|
||
pop ds
|
||
stosb ; store character
|
||
ret
|
||
|
||
ArgPushChar endp
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Not enough space to process the command line .... abort.
|
||
;
|
||
NoArgSpace: jmp abort@
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Routine to process an argument.
|
||
;
|
||
ProcessArg proc near
|
||
|
||
push bx
|
||
xor al, al
|
||
call ArgPushChar ; null-terminate
|
||
pop bx
|
||
test bh, 1 ; wildcards present ?
|
||
jnz ArgWild
|
||
inc dx ; bump arg count
|
||
ret
|
||
;
|
||
; We have a wildcard argument. Expand it.
|
||
;
|
||
ArgWild: push cx
|
||
push [si] ; save word following argument
|
||
mov byte ptr [si],0 ; null-terminate argument
|
||
xchg si, wild_arg_src ; si = argument address
|
||
push di
|
||
mov di, wild_arg_dst
|
||
push dx
|
||
call WildExpand
|
||
pop dx
|
||
pop bx
|
||
and cx, cx ; see if any matched
|
||
jnz ArgWildSome
|
||
mov di, bx ; none ---> use unexpanded argument
|
||
mov cx, 1 ; bump arg count by 1
|
||
ArgWildSome: add dx, cx
|
||
mov si, wild_arg_src
|
||
pop [si] ; restore word following argument
|
||
pop cx
|
||
ret
|
||
|
||
ProcessArg endp
|
||
|
||
;------------------------------------------------------------------------------
|
||
;
|
||
; Build the argv array. [DS:SI] is the expanded command line, CX its length.
|
||
; DX has the number of arguments (including the program name).
|
||
;
|
||
BuildArgv: push ds
|
||
push dx
|
||
lds dx, dword ptr wild_DTA_save
|
||
mov ah, 1ah
|
||
int 21h ; switch to original DTA
|
||
pop dx
|
||
pop ds
|
||
|
||
add sp, wild_frame_size ; remove local variables
|
||
|
||
mov es,savedDS
|
||
mov es:[_argc@], dx
|
||
inc dx ; argv ends with a NULL pointer
|
||
shl dx, 1 ; argc * 2 (LDATA = 0)
|
||
IF LDATA
|
||
shl dx, 1 ; argc * 4 (LDATA = 1)
|
||
ENDIF
|
||
mov bx, sp ; point to program name
|
||
mov bp, sp
|
||
sub bp, dx
|
||
jb NoArgSpace
|
||
mov sp, bp ; SS:BP = argv array address
|
||
mov word ptr es:[_argv@], bp
|
||
IF LDATA
|
||
mov word ptr es:[_argv@+2], ss
|
||
ENDIF
|
||
mov [bp], bx ; set argv[0] to program name
|
||
IF LDATA
|
||
mov [bp+2], ss ; program name is on the stack
|
||
ENDIF
|
||
add bp, dPtrSize
|
||
|
||
SetArgvX label near
|
||
jcxz SetLastArg
|
||
mov [bp], si ; Set argv[n]
|
||
IF LDATA
|
||
mov [bp+2], ds
|
||
ENDIF
|
||
add bp, dPtrSize
|
||
CopyArg label near
|
||
lodsb
|
||
or al, al
|
||
loopnz CopyArg
|
||
jz SetArgvX
|
||
SetLastArg label near
|
||
xor ax, ax
|
||
mov [bp], ax
|
||
IF LDATA
|
||
mov [bp+2], ax
|
||
ENDIF
|
||
mov ds, savedDS
|
||
|
||
;==============================================================================
|
||
else
|
||
;==============================================================================
|
||
|
||
mov ds, bp
|
||
xchg si, dx ; DS: SI = Command Line address
|
||
xchg bx, cx ; CX = Command Line size including \r
|
||
mov ax, bx
|
||
mov dx, ax ; AX = BX = DX = 0
|
||
inc bx ; BX = Nb of arguments (at least 1)
|
||
Processing label near
|
||
call NextChar
|
||
ja NotQuote ; Not a quote and there are more
|
||
InString label near
|
||
jb BuildArgv ; Command line is empty now
|
||
call NextChar
|
||
ja InString ; Not a quote and there are more
|
||
NotQuote label near
|
||
cmp al, ' '
|
||
je EndArgument ; Space is an argument separator
|
||
cmp al, 13
|
||
je EndArgument ; \r is an argument separator
|
||
cmp al, 9
|
||
jne Processing ; \t is an argument separator
|
||
EndArgument label near
|
||
xor al, al ; Space and TAB are argument separators
|
||
jmp short Processing
|
||
|
||
; Character test function used in SetArgs
|
||
; On entry AL holds the previous character
|
||
; On exit AL holds the next character
|
||
; ZF on if the next character is quote (") and AL = 0
|
||
; CF on if end of command line and AL = 0
|
||
|
||
NextChar PROC NEAR
|
||
or ax, ax
|
||
jz NextChar0
|
||
inc dx ; DX = Actual length of CmdLine
|
||
stosb
|
||
or al, al
|
||
jnz NextChar0
|
||
inc bx ; BX = Number of parameters
|
||
NextChar0 label near
|
||
xchg ah, al
|
||
xor al, al
|
||
stc
|
||
jcxz NextChar2 ; End of command line --> CF ON
|
||
lodsb
|
||
dec cx
|
||
sub al, '"'
|
||
jz NextChar2 ; Quote found --> AL = 0 and ZF ON
|
||
add al, '"'
|
||
cmp al,'\'
|
||
jne NextChar1 ; It is not a \
|
||
cmp byte ptr ds:[si], '"'
|
||
jne NextChar1 ; Only " is transparent after \
|
||
lodsb
|
||
dec cx
|
||
NextChar1 label near
|
||
or si, si ; Be sure both CF & ZF are OFF
|
||
NextChar2 label near
|
||
ret
|
||
NextChar ENDP
|
||
|
||
; Invalid program name
|
||
|
||
BadProgName label near
|
||
jmp abort@
|
||
|
||
; Now, build the argv array
|
||
|
||
BuildArgv label near
|
||
pop cx
|
||
add cx, dx ; CX = Argument area size
|
||
mov ds, SavedDS
|
||
mov _argc@, bx
|
||
inc bx ; argv ends with a NULL pointer
|
||
add bx, bx ; argc * 2 (LDATA = 0)
|
||
IF LDATA
|
||
add bx, bx ; argc * 4 (LDATA = 1)
|
||
ENDIF
|
||
mov si, sp
|
||
mov bp, sp
|
||
sub bp, bx
|
||
jb BadProgName
|
||
mov sp, bp ; SS:BP = argv array address
|
||
mov word ptr _argv@, bp
|
||
IF LDATA
|
||
mov word ptr _argv@+2, ss
|
||
ENDIF
|
||
SetArgvX label near
|
||
jcxz SetLastArg
|
||
mov [bp], si ; Set argv[n]
|
||
IF LDATA
|
||
mov [bp+2], ss
|
||
ENDIF
|
||
add bp, dPtrSize
|
||
CopyArg label near
|
||
lods byte ptr ss:[si]
|
||
or al, al
|
||
loopnz CopyArg
|
||
jz SetArgvX
|
||
SetLastArg label near
|
||
xor ax, ax
|
||
mov [bp], ax
|
||
IF LDATA
|
||
mov [bp+2], ax
|
||
ENDIF
|
||
|
||
;==============================================================================
|
||
endif ; ifdef WILD
|
||
;==============================================================================
|
||
|
||
; Restore caller context and exit
|
||
|
||
IF LPROG
|
||
jmp dword ptr SavedReturn
|
||
ELSE
|
||
jmp word ptr SavedReturn
|
||
ENDIF
|
||
|
||
ifdef WILD
|
||
EndProc@ _wildargv, __CDECL__
|
||
else
|
||
EndProc@ _setargv, __CDECL__
|
||
endif
|
||
|
||
CSegEnd@
|
||
END
|
||
|