Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
e4115e36
Commit
e4115e36
authored
Nov 26, 2018
by
Nikolay Sivov
Committed by
Alexandre Julliard
Nov 26, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
shcore: Add CommandLineToArgvW().
Signed-off-by:
Nikolay Sivov
<
nsivov@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
aa6b8072
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
259 additions
and
1 deletion
+259
-1
main.c
dlls/shcore/main.c
+258
-0
shcore.spec
dlls/shcore/shcore.spec
+1
-1
No files found.
dlls/shcore/main.c
View file @
e4115e36
...
...
@@ -29,6 +29,7 @@
#include "ocidl.h"
#include "shellscalingapi.h"
#include "wine/debug.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
shcore
);
...
...
@@ -234,3 +235,260 @@ HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid)
*
appid
=
NULL
;
return
E_NOTIMPL
;
}
/*************************************************************************
* CommandLineToArgvW [SHCORE.@]
*
* We must interpret the quotes in the command line to rebuild the argv
* array correctly:
* - arguments are separated by spaces or tabs
* - quotes serve as optional argument delimiters
* '"a b"' -> 'a b'
* - escaped quotes must be converted back to '"'
* '\"' -> '"'
* - consecutive backslashes preceding a quote see their number halved with
* the remainder escaping the quote:
* 2n backslashes + quote -> n backslashes + quote as an argument delimiter
* 2n+1 backslashes + quote -> n backslashes + literal quote
* - backslashes that are not followed by a quote are copied literally:
* 'a\b' -> 'a\b'
* 'a\\b' -> 'a\\b'
* - in quoted strings, consecutive quotes see their number divided by three
* with the remainder modulo 3 deciding whether to close the string or not.
* Note that the opening quote must be counted in the consecutive quotes,
* that's the (1+) below:
* (1+) 3n quotes -> n quotes
* (1+) 3n+1 quotes -> n quotes plus closes the quoted string
* (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
* - in unquoted strings, the first quote opens the quoted string and the
* remaining consecutive quotes follow the above rule.
*/
WCHAR
**
WINAPI
CommandLineToArgvW
(
const
WCHAR
*
cmdline
,
int
*
numargs
)
{
int
qcount
,
bcount
;
const
WCHAR
*
s
;
WCHAR
**
argv
;
DWORD
argc
;
WCHAR
*
d
;
if
(
!
numargs
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
NULL
;
}
if
(
*
cmdline
==
0
)
{
/* Return the path to the executable */
DWORD
len
,
deslen
=
MAX_PATH
,
size
;
size
=
sizeof
(
WCHAR
*
)
*
2
+
deslen
*
sizeof
(
WCHAR
);
for
(;;)
{
if
(
!
(
argv
=
LocalAlloc
(
LMEM_FIXED
,
size
)))
return
NULL
;
len
=
GetModuleFileNameW
(
0
,
(
WCHAR
*
)(
argv
+
2
),
deslen
);
if
(
!
len
)
{
LocalFree
(
argv
);
return
NULL
;
}
if
(
len
<
deslen
)
break
;
deslen
*=
2
;
size
=
sizeof
(
WCHAR
*
)
*
2
+
deslen
*
sizeof
(
WCHAR
);
LocalFree
(
argv
);
}
argv
[
0
]
=
(
WCHAR
*
)(
argv
+
2
);
argv
[
1
]
=
NULL
;
*
numargs
=
1
;
return
argv
;
}
/* --- First count the arguments */
argc
=
1
;
s
=
cmdline
;
/* The first argument, the executable path, follows special rules */
if
(
*
s
==
'"'
)
{
/* The executable path ends at the next quote, no matter what */
s
++
;
while
(
*
s
)
if
(
*
s
++
==
'"'
)
break
;
}
else
{
/* The executable path ends at the next space, no matter what */
while
(
*
s
&&
*
s
!=
' '
&&
*
s
!=
'\t'
)
s
++
;
}
/* skip to the first argument, if any */
while
(
*
s
==
' '
||
*
s
==
'\t'
)
s
++
;
if
(
*
s
)
argc
++
;
/* Analyze the remaining arguments */
qcount
=
bcount
=
0
;
while
(
*
s
)
{
if
((
*
s
==
' '
||
*
s
==
'\t'
)
&&
qcount
==
0
)
{
/* skip to the next argument and count it if any */
while
(
*
s
==
' '
||
*
s
==
'\t'
)
s
++
;
if
(
*
s
)
argc
++
;
bcount
=
0
;
}
else
if
(
*
s
==
'\\'
)
{
/* '\', count them */
bcount
++
;
s
++
;
}
else
if
(
*
s
==
'"'
)
{
/* '"' */
if
((
bcount
&
1
)
==
0
)
qcount
++
;
/* unescaped '"' */
s
++
;
bcount
=
0
;
/* consecutive quotes, see comment in copying code below */
while
(
*
s
==
'"'
)
{
qcount
++
;
s
++
;
}
qcount
=
qcount
%
3
;
if
(
qcount
==
2
)
qcount
=
0
;
}
else
{
/* a regular character */
bcount
=
0
;
s
++
;
}
}
/* 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
+
1
)
*
sizeof
(
WCHAR
*
)
+
(
strlenW
(
cmdline
)
+
1
)
*
sizeof
(
WCHAR
));
if
(
!
argv
)
return
NULL
;
/* --- Then split and copy the arguments */
argv
[
0
]
=
d
=
strcpyW
((
WCHAR
*
)(
argv
+
argc
+
1
),
cmdline
);
argc
=
1
;
/* The first argument, the executable path, follows special rules */
if
(
*
d
==
'"'
)
{
/* The executable path ends at the next quote, no matter what */
s
=
d
+
1
;
while
(
*
s
)
{
if
(
*
s
==
'"'
)
{
s
++
;
break
;
}
*
d
++
=
*
s
++
;
}
}
else
{
/* The executable path ends at the next space, no matter what */
while
(
*
d
&&
*
d
!=
' '
&&
*
d
!=
'\t'
)
d
++
;
s
=
d
;
if
(
*
s
)
s
++
;
}
/* close the executable path */
*
d
++
=
0
;
/* skip to the first argument and initialize it if any */
while
(
*
s
==
' '
||
*
s
==
'\t'
)
s
++
;
if
(
!*
s
)
{
/* There are no parameters so we are all done */
argv
[
argc
]
=
NULL
;
*
numargs
=
argc
;
return
argv
;
}
/* Split and copy the remaining arguments */
argv
[
argc
++
]
=
d
;
qcount
=
bcount
=
0
;
while
(
*
s
)
{
if
((
*
s
==
' '
||
*
s
==
'\t'
)
&&
qcount
==
0
)
{
/* close the argument */
*
d
++
=
0
;
bcount
=
0
;
/* skip to the next one and initialize it if any */
do
{
s
++
;
}
while
(
*
s
==
' '
||
*
s
==
'\t'
);
if
(
*
s
)
argv
[
argc
++
]
=
d
;
}
else
if
(
*
s
==
'\\'
)
{
*
d
++
=
*
s
++
;
bcount
++
;
}
else
if
(
*
s
==
'"'
)
{
if
((
bcount
&
1
)
==
0
)
{
/* Preceded by an even number of '\', this is half that
* number of '\', plus a quote which we erase.
*/
d
-=
bcount
/
2
;
qcount
++
;
}
else
{
/* Preceded by an odd number of '\', this is half that
* number of '\' followed by a '"'
*/
d
=
d
-
bcount
/
2
-
1
;
*
d
++
=
'"'
;
}
s
++
;
bcount
=
0
;
/* Now count the number of consecutive quotes. Note that qcount
* already takes into account the opening quote if any, as well as
* the quote that lead us here.
*/
while
(
*
s
==
'"'
)
{
if
(
++
qcount
==
3
)
{
*
d
++
=
'"'
;
qcount
=
0
;
}
s
++
;
}
if
(
qcount
==
2
)
qcount
=
0
;
}
else
{
/* a regular character */
*
d
++
=
*
s
++
;
bcount
=
0
;
}
}
*
d
=
'\0'
;
argv
[
argc
]
=
NULL
;
*
numargs
=
argc
;
return
argv
;
}
dlls/shcore/shcore.spec
View file @
e4115e36
1 stub @
@ stdcall CommandLineToArgvW(wstr ptr)
shell32.CommandLineToArgvW
@ stdcall CommandLineToArgvW(wstr ptr)
@ stub CreateRandomAccessStreamOnFile
@ stub CreateRandomAccessStreamOverStream
@ stub CreateStreamOverRandomAccessStream
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment