; *** PARSE COMMAND LINE ***
; ENTRY: ESP + 4 > Points to callers bottom of stack
; LEAVE: ESP > Points to address of array of string pointers
; AL > Number of parameters passed to application
; AH > Bit 0 = 1 If mismatched quotes, Bit 1 = 1, if array overflow.
; NOTE: As this routine modifies ESP,it is important calling routine take appropriate
; measures to account for this fact.
; Routine modifies original string, it is important ParseCL only be called once.
ParseCL pop eax ; Get callers return.
; Allocate 512 bytes from stack for a maximum of 128 32 bit pointers to strings. Max
; value for ECX is 1020 due to the 8 bit unsigned value returned in AL.
mov ecx, 512
sub esp, ecx
mov edx, esp ; Needed later for base pointer.
push eax ; Callers return to top of stack again.
push esi
push edi ; Save essential registers
push ebx
; Initialize pointers and data required by parsing loop
mov ebx, edx ; EBX = Base of parameter pointers
call _GetCommandLineA@0
mov esi, eax
mov edi, eax
mov edx, ecx
shr edx, 2 ; EDX = Number of pointers that can be saved.
xor ecx, ecx
mov eax, ecx
cld ; Assure STOS & LODS will auto-inc indices.
.NextCh mov ah, al ; Save previously read character
lodsb ; Get character from source
and al, al ; Is it NULL (termination byte)
jz .Done ; ZR = 1, if finished
; Quotation marks have a special meaning as that inside quotes the other delimiting
; character being the space are to be treated as literal. Toggle bit 16 in EAX to
; indicate this, and if bit 16 is on upon return we know there were mismatched quotes.
cmp al, '"'
jnz .Space ; ZR = 0, if it wasn't a quotation mark
xor al, al ; Quotes are always converted to null
btc eax, 16 ; Toggle InQuotes flag
jnc .NextCh ; Pass over if it's leading quote
.Post stosb
jmp short .NextCh
; Spaces are the other delimiter and except when inside quotes are to be treated as
; end of string. NOTE: Embedded spaces may cause paramter to be misiterpreted.
.Space cmp al, ' '
jnz .Default ; ZR = 0, if this is not a space
bt eax, 16 ; Are we inside quotation marks
jc .Post ; NC = 1, if in quotes
xor al, al ; Nullify character
and ah, ah ; Determine if previous character is null
jz .NextCh ; Ignore leading spaces
jmp short .Post
; All other characters are treated literaly, and if the previous character (AH) is null
; then we know this is the begining of the next parameter
.Default and ah, ah
jnz .Post ; Not first character of parameter
; Check value of CX versus DX which is the maximum number of pointers that can be save
; in allocated stack space.
cmp cx, dx
ja .NoRoomLeft
mov [ebx + ecx * 4], edi ; Save pointer
inc ecx
jmp short .Post
.NoRoomLeft bts eax, 17 ; Set error condition, buffer overflow
jmp short .Done + 2
.Done stosb
; Establish return value in EAX, by shifting status bits 16 & 17 into 8 & 9 and then
; moving number of parameters passed into AL, resulting in AX being retunred value
shr eax, 8 ; Shift Status bits
mov al, cl ; Parameters passed into AL
; Stack space must be compressed so last parameters pointer is on top of callers stack.
add ecx, 4 ; Account for values on stack already
sub edx, ecx ; Offset from maximum allowable
shl edx, 2 ; Determine actual number of bytes
add edx, ebx ; EDX = Offset from top of callers stack
; Initialize indexes with appropriate values for block move MOVSD and move block.
mov edi, edx
mov esi, esp
rep movsd
mov esp, edx ; Now stack pointer can be relocated
; Restore all register and return to caller with appropriate pointers on stack
pop ebx
pop edi
pop esi
ret