shell32: Simplify CommandLineToArgvW() a bit.

This commit is contained in:
Francois Gouget 2012-10-09 00:13:35 +02:00 committed by Alexandre Julliard
parent 1e3834aa14
commit 35004f84a2
1 changed files with 33 additions and 47 deletions

View File

@ -76,19 +76,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell);
* - '\' that are not followed by a '"' are copied literally * - '\' that are not followed by a '"' are copied literally
* 'a\b' -> 'a\b' * 'a\b' -> 'a\b'
* 'a\\b' -> 'a\\b' * 'a\\b' -> 'a\\b'
*
* Note:
* '\t' == 0x0009
* ' ' == 0x0020
* '"' == 0x0022
* '\\' == 0x005c
*/ */
LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs) LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
{ {
DWORD argc; DWORD argc;
LPWSTR *argv; LPWSTR *argv;
LPCWSTR cs; LPCWSTR s;
LPWSTR arg,s,d; LPWSTR d;
LPWSTR cmdline; LPWSTR cmdline;
int in_quotes,bcount; int in_quotes,bcount;
@ -124,32 +118,29 @@ LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
return argv; return argv;
} }
/* to get a writable copy */ /* --- First count the arguments */
argc=0; argc=1;
bcount=0; bcount=0;
in_quotes=0; in_quotes=0;
cs=lpCmdline; s=lpCmdline;
while (1) while (*s)
{ {
if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes)) if (((*s==' ' || *s=='\t') && !in_quotes))
{ {
/* space */ /* skip to the next argument and count it if any */
while (*s==' ' || *s=='\t')
s++;
if (*s)
argc++; argc++;
/* skip the remaining spaces */
while (*cs==0x0009 || *cs==0x0020) {
cs++;
}
if (*cs==0)
break;
bcount=0; bcount=0;
continue; continue;
} }
else if (*cs==0x005c) else if (*s=='\\')
{ {
/* '\', count them */ /* '\', count them */
bcount++; bcount++;
} }
else if ((*cs==0x0022) && ((bcount & 1)==0)) else if ((*s=='"') && ((bcount & 1)==0))
{ {
/* unescaped '"' */ /* unescaped '"' */
in_quotes=!in_quotes; in_quotes=!in_quotes;
@ -160,10 +151,12 @@ LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
/* a regular character */ /* a regular character */
bcount=0; bcount=0;
} }
cs++; s++;
} }
/* Allocate in a single lump, the string array, and the strings that go with it.
* This way the caller can make a single GlobalFree call to free both, as per MSDN. /* Allocate in a single lump, the string array, and the strings that go
* with it. This way the caller can make a single LocalFree() call to free
* both, as per MSDN.
*/ */
argv=LocalAlloc(LMEM_FIXED, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR)); argv=LocalAlloc(LMEM_FIXED, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
if (!argv) if (!argv)
@ -171,36 +164,33 @@ LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
cmdline=(LPWSTR)(argv+argc); cmdline=(LPWSTR)(argv+argc);
strcpyW(cmdline, lpCmdline); strcpyW(cmdline, lpCmdline);
argc=0; /* --- Then split and copy the arguments */
argc=1;
bcount=0; bcount=0;
in_quotes=0; in_quotes=0;
arg=d=s=cmdline; s=argv[0]=d=cmdline;
while (*s) while (*s)
{ {
if ((*s==0x0009 || *s==0x0020) && !in_quotes) if ((*s==' ' || *s=='\t') && !in_quotes)
{ {
/* Close the argument and copy it */ /* close the argument */
*d=0; *d++=0;
argv[argc++]=arg; bcount=0;
/* skip the remaining spaces */ /* skip to the next one and initialize it if any */
do { do {
s++; s++;
} while (*s==0x0009 || *s==0x0020); } while (*s==' ' || *s=='\t');
if (*s)
/* Start with a new argument */ argv[argc++]=d;
arg=d=s;
bcount=0;
} }
else if (*s==0x005c) else if (*s=='\\')
{ {
/* '\\' */
*d++=*s++; *d++=*s++;
bcount++; bcount++;
} }
else if (*s==0x0022) else if (*s=='"')
{ {
/* '"' */
if ((bcount & 1)==0) if ((bcount & 1)==0)
{ {
/* Preceded by an even number of '\', this is half that /* Preceded by an even number of '\', this is half that
@ -228,11 +218,7 @@ LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
bcount=0; bcount=0;
} }
} }
if (*arg)
{
*d='\0'; *d='\0';
argv[argc++]=arg;
}
*numargs=argc; *numargs=argc;
return argv; return argv;