News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Command Line Parser

Started by Tight_Coder_Ex, November 21, 2007, 07:18:23 PM

Previous topic - Next topic

Tight_Coder_Ex

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.

hutch--

Hi,

Welcome on board. Thanks for the offer, many will be interested to see the type of code you develop.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Vortex

Hi Tight_Coder_Ex,

Welcome to the forum.

Tight_Coder_Ex

Thanks. Hopefully my two bits worth is of some value.