xref: /AOO41X/main/sal/systools/win32/uwinapi/CommandLineToArgvW.cpp (revision fc0bc00825ec02ef04af0b032f1c57b312b79937)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
24 #pragma warning(disable:4740)
25 #endif
26 
27 #include "macros.h"
28 
29 #ifdef __cplusplus
30 #define local inline
31 #else
32 #define local static
33 #endif
34 
SkipBlanks(LPCWSTR lpScan)35 local LPCWSTR SkipBlanks( LPCWSTR lpScan )
36 {
37     while ( ' ' == *lpScan || '\t' == *lpScan )
38         lpScan++;
39 
40     return lpScan;
41 }
42 
43 
SkipArgument(LPCWSTR lpScan)44 local LPCWSTR SkipArgument( LPCWSTR lpScan )
45 {
46     BOOL    fQuoted = FALSE;
47     LPCWSTR lpArgEnd = NULL;
48 
49     do
50     {
51         switch ( *lpScan )
52         {
53         case ' ':
54         case '\t':
55             if ( fQuoted )
56                 lpScan++;
57             else
58                 lpArgEnd = lpScan;
59             break;
60         case '\"':
61             lpScan++;
62             fQuoted = !fQuoted;
63             break;
64         case '\0':
65             lpArgEnd = lpScan;
66             break;
67         default:
68             lpScan++;
69             break;
70         }
71     } while( *lpScan && !lpArgEnd );
72 
73     return lpScan;
74 }
75 
76 
77 IMPLEMENT_THUNK( shell32, WINDOWS, LPWSTR *, WINAPI, CommandLineToArgvW, ( LPCWSTR lpCmdLineW, int *pNumArgs ) )
78 {
79     LPWSTR  *lpArgvW = NULL;
80 
81     if ( !lpCmdLineW || !*lpCmdLineW )
82     {
83         CHAR    szFileName[MAX_PATH];
84 
85         DWORD   dwResult = GetModuleFileNameA( NULL, szFileName, MAX_PATH );
86 
87         if ( dwResult && dwResult < MAX_PATH )
88         {
89             int cchNeeded = MultiByteToWideChar( CP_ACP, 0, szFileName, -1, NULL, 0 );
90 
91             lpArgvW = (LPWSTR *)GlobalAlloc( 0, cchNeeded * sizeof(WCHAR) + sizeof(LPWSTR) );
92 
93             if ( lpArgvW )
94             {
95                 lpArgvW[0] = (LPWSTR)(lpArgvW + 1);
96 
97                 MultiByteToWideChar( CP_ACP, 0, szFileName, -1, lpArgvW[0], cchNeeded );
98                 *pNumArgs = 1;
99             }
100             else
101                 SetLastError( ERROR_OUTOFMEMORY );
102         }
103     }
104     else
105     {
106         LPCWSTR lpScan = lpCmdLineW;
107         int     nTokens = 0;
108         int     cchNeeded = 0;
109 
110         // Count arguments and required size
111 
112         while ( *lpScan )
113         {
114             lpScan = SkipBlanks( lpScan );
115             if ( *lpScan )
116             {
117                 LPCWSTR lpArgEnd = SkipArgument( lpScan );
118 
119                 nTokens++;
120                 cchNeeded += lpArgEnd - lpScan + 1;
121                 lpScan = lpArgEnd;
122             }
123         }
124 
125         // Allocate space for one additional NULL pointer to terminate list
126 
127         lpArgvW = (LPWSTR *)GlobalAlloc( 0, sizeof(LPWSTR) * (nTokens + 1) + sizeof(WCHAR) * cchNeeded );
128 
129         if ( lpArgvW )
130         {
131             // Collect arguments
132 
133             LPWSTR  lpDestination = (LPWSTR)&lpArgvW[nTokens + 1];
134 
135             lpScan = lpCmdLineW;
136             nTokens = 0;
137 
138             while ( *lpScan )
139             {
140                 lpScan = SkipBlanks( lpScan );
141                 if ( *lpScan )
142                 {
143                     LPCWSTR lpArgEnd = SkipArgument( lpScan );
144 
145                     lpArgvW[nTokens++] = lpDestination;
146 
147                     while ( lpScan < lpArgEnd )
148                     {
149                         if ( '\"' != *lpScan )
150                             *lpDestination++ = *lpScan;
151 
152                         lpScan++;
153                     }
154                     *lpDestination++ = 0;
155                 }
156             }
157 
158             lpArgvW[nTokens] = NULL;
159 
160             *pNumArgs = nTokens;
161         }
162         else
163             SetLastError( ERROR_OUTOFMEMORY );
164 
165     }
166 
167     return lpArgvW;
168 }