PowerBASIC has a COMMAND$ command that works fine in most instances, here is an alternative algorithm that can be called with either basic dynamic string or as a zero terminated string. Note that neither solve a problem with the API CreateProcess() where the file name and command tail are not parsed correctly. The assembler code was written in MASM and directly ported to PowerBASIC.
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
#include "\basic\include\win32api.inc"
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION PBmain as LONG
LOCAL pCmt as ASCIIZ PTR
' cmd$ = command$
'
' If cmd$ = "" Then
' StdOut "No command tail"
' Else
' StdOut cmd$ ' display basic string
' End If
'
' If cmd$ = "" Then
' StdOut "No command tail"
' Else
' StdOut cmd$ ' display basic string
' End If
' --------------------
' BASIC string version
' --------------------
cmd$ = GetCmdTail
If cmd$ = "" Then
StdOut "No command tail"
Else
StdOut cmd$ ' display basic string
End If
' ------------------------------
' zero terminated string version
' ------------------------------
pCmt = szCmdTail
If pCmt = 0 Then
StdOut "No command tail"
Else
StdOut @pCmt ' display zero terminated string
GlobalFree pCmt
End If
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION szCmdTail() as DWORD
' -----------------------------------------------------------------------
' If command tail is not empty and the memory pointer is returned, it
' must be freed in the same scope as the caller with theAPI GlobalFree().
' -----------------------------------------------------------------------
LOCAL lCmd as DWORD
LOCAL pCmd as DWORD
LOCAL pBuf as DWORD
pCmd = GetCommandLine()
! push pCmd ; push cmdline pointer onto stack
! call slen ; call the short lenth function
! mov lCmd, eax ; allocate this much memory
pBuf = GlobalAlloc(%GMEM_FIXED or %GMEM_ZEROINIT, lCmd+16)
! push pBuf
! push pCmd
! call cmdtail
! test eax, eax ; check if the length is zero
! jne bye
GlobalFree pBuf ' deallocate the memory
FUNCTION = 0 ' exit with zero and do
Exit FUNCTION ' not allocate memory
bye:
FUNCTION = pBuf ' return the memory address
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION GetCmdTail() as STRING
LOCAL lCmd as DWORD
LOCAL pCmd as DWORD
LOCAL pBuf as DWORD
LOCAL tLen as DWORD
pCmd = GetCommandLine()
! push pCmd ; push cmdline pointer onto stack
! call slen ; call the short lenth function
! mov lCmd, eax ; store it in lCmd
outpt$ = space$(lCmd)
pBuf = StrPtr(outpt$)
! push pBuf
! push pCmd
! call cmdtail
! mov tLen, eax
FUNCTION = left$(outpt$,tLen)
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FASTPROC slen
PREFIX "!"
mov eax, [esp+4]
sub eax, 1
lbl:
add eax, 1
cmp BYTE PTR [eax], 0
jne lbl
sub eax, [esp+4]
ret 4
END PREFIX
END FASTPROC
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FASTPROC cmdtail
PREFIX "!"
; ------------------------------------------------------
; pCmd is the address of the command line
; pBuf is the target address for the command tail
; NOTE: The pBuf argument should be allocated to the size
; of the command line returned by GetCommandLine()
; API to ensure that the app can handle exploits
;
; The return value in EAX is the command tail length,
; if the length is 0 there is no command tail
; ------------------------------------------------------
; ***************************************************************
; ANSI quoted and unquoted file name version to get command tail.
; ***************************************************************
mov ecx, [esp+4]
mov edx, [esp+8]
tstchar1: ; see if its a quote or not
cmp BYTE PTR [ecx], 34 ; test for double quote character
jne noquote ; if not 34 branch to noquote handler
; -------------------------------------------------------------
; strip the quoted file name from the start of the command line
; -------------------------------------------------------------
quoted:
add ecx, 1
cmp BYTE PTR [ecx], 34 ; test for 2nd double quote character
jne quoted
jmp ftrim
; ---------------------------------------------------------------
; strip the unquoted file name from the start of the command line
; ---------------------------------------------------------------
noquote:
add ecx, 1
cmp BYTE PTR [ecx], 32
jg noquote ; if > 32, throw it away
sub ecx, 1
; ------------------------------------------------
; trim any leading white space from command tail
; ------------------------------------------------
ftrim:
add ecx, 1
cmp BYTE PTR [ecx], 32
je ftrim
cmp BYTE PTR [ecx], 9
je ftrim
; ------------------------------------------
; copy the command tail to the output buffer
; ------------------------------------------
copytail:
movzx eax, BYTE PTR [ecx]
mov [edx], al
add ecx, 1
add edx, 1
test eax, eax
jnz copytail
mov BYTE PTR [edx], 0 ; append a terminator
sub edx, 1
; ----------------------------------------------
; return value in EAX is the command tail length
; ----------------------------------------------
sub edx, [esp+8]
mov eax, edx
ret 8
END PREFIX
END FASTPROC
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤