As part of a much larger project I'm undertaking, this is the first of the library routines that will become part of Horizons.lib
If there is sufficient interest, I will continue posting as I progress through the code. This is a hobby project that has it's foundation as a doubly linked list.
If you use this code, I would appreciate acknowledgment under the auspices of GPL
.486
.model flat, stdcall
option casemap:none
GetCommandLineA PROTO
GetCommandLine equ <GetCommandLineA>
includelib kernel32.lib
option prologue:none
option epilogue:none
.code
; =============================================================================================
; ENTRY: Arg1 = MaxArgs (maximum number of dword pointers)
; push 18
; call ParseCL
; LEAVE EAX - bit 16 ON if mismatched quotes
; AX = Number of parameters passed, 0 if procedure already called
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParseCL PROC MaxArgs:DWORD
; Create a procedure frame suitably large to accomadate MaxArg dword pointers as if it had
; been created by caller.
pop eax ; Get callers return
pop edx ; MaxArg's (the reason proc does not accept arguments)
mov ecx, edx
shl ecx, 2 ; ECX = Actual number of bytes required of stack
sub esp, ecx ; Allocate space
mov ecx, esp ; Will need this pointer for EBX later
push eax ; Reposition return address
; Save essential registers as per M$ specifications for windows applications.
push ebx
push esi
push edi
; Initialize registers to values required by routines primary loop
; EAX & ECX = NULL
; EBX = Base pointer to array of dword pointers
; EDX = Maximum number of pointers that can be stored
; ESI & EDI = Command line string, facilitates compression algorythim
mov ebx, ecx
call GetCommandLine
mov esi, eax
mov edi, esi
push esi ; Is required for comparison later
xor eax, eax
mov ecx, eax
; Cycle through each of the characters in command line, stripping quotes single and double
; and spaces that are not in quotations. Padded spaces will also be compressed to null.
NextCh: mov ah, al ; Save copy of previous character
lodsb ; Read character from source string
and al, al
jz Done ; Break from loop if end of source string
; Evaluate primary delimiters, firstly quotes and then spaces. Anytime a user defined
; argument is passed and requires embedded spaces, it must be enclosed in single quotes.
cmp al, 27H ; Is it a single quote
jbe @F
; At this point character is valid and the only thing need be determined if it's the
; begining of a new argument
and ah, ah ; Was previous character null
jnz Done - 3 ; Just go ahead and post, not the beginning of new one
cmp ecx, edx ; Is buffer full yet
jnz Post ; ZR = 1, discontinue
bts eax, 17 ; Set overflow condition
jmp Done
; Now address in EDI can be written to array as it is the beginning of a new argument
Post: mov [ebx + ecx * 4], edi
inc ecx ; Bump counter
jmp Done - 3
; Although contrary to what is allowed in command lines as far as special characters the
; only one we'll check for now is space. All others will be considered valid.
@@: jz @F ; It is a single quote so treat as double
cmp al, '"' ; Is it a double quote
jnz Spaces ; Carry on if not
; All quotes are cohersed to nulls and so this routine can't be called twice special
; processing to determine if it's the first quote in the string
@@: xor al, al ; Nullify
btc eax, 16 ; Toggle in quotes flag
jc @F ; Post NULL if trailing quote
; This bit will nullify command string as passed by OS so this procedure can be called more
; than once, but won't destroy contents of first time
cmp edi, [esp] ; First byte
jz @F ; Post NULL if so
jmp NextCh ; Otherwise ignore and grab another character
; This sets spaces as delimiters if not in quotes and also compressed padded occurences
Spaces: bt eax, 16 ; Are we inside quotes
jc @F ; CY = 1, inside quotes
cmp al, ' ' ; Is it a space character
jnz @F
xor al, al
and ax, ax ; Was previous a null too?
jz NextCh ; Ingnore, compress string
@@: stosb ; Post to compressed buffer
jmp NextCh ; Keep cycling until null
; Now that arguments have been parsed, then need to be moved up in stack to touch callers
; bottom of stack
Done: stosb
; In the event there is overlap, contents of stack must be moved in reverses order.
; IE: If MaxArgs was twelve and there were eight parameters, overlap is 4.
mov ax, cx ; Setup return value
add ecx, 4 ; Account for locals
lea esi, [esp+ecx*4] ; Source pointer
dec edx ; Zero index MaxArgs
lea edi, [ebx+edx*4] ; Desintation pointer
std ; Set auto decrement
rep movsd ; Block move buffer
cld ; Set to default, auto increment
mov esp, edi ; Set new stack pointer
pop ebx ; Waste this so it will be overwritten
pop edi
pop esi ; Restore essential registers
pop ebx
; Even though an argument was passed on stack we don't need to worry about it due to the
; special handling of stack in this procedure.
ret ; ret 4 (not required)
ParseCL ENDP
;---------------------------------------------------------------------------------------------
END
Hutch, if you feel this or anything else I post is worthy of becoming part of the MASM32 project, please feel free to use it.
Hi,
Welcome on board. Thanks for the offer, many will be interested to see the type of code you develop.
Hi Tight_Coder_Ex,
Welcome to the forum.
Thanks. Hopefully my two bits worth is of some value.