xref: /trunk/main/sal/systools/win32/uwinapi/CommandLineToArgvW.cpp (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
28 #pragma warning(disable:4740)
29 #endif
30 
31 #include "macros.h"
32 
33 #ifdef __cplusplus
34 #define local inline
35 #else
36 #define local static
37 #endif
38 
39 local LPCWSTR SkipBlanks( LPCWSTR lpScan )
40 {
41     while ( ' ' == *lpScan || '\t' == *lpScan )
42         lpScan++;
43 
44     return lpScan;
45 }
46 
47 
48 local LPCWSTR SkipArgument( LPCWSTR lpScan )
49 {
50     BOOL    fQuoted = FALSE;
51     LPCWSTR lpArgEnd = NULL;
52 
53     do
54     {
55         switch ( *lpScan )
56         {
57         case ' ':
58         case '\t':
59             if ( fQuoted )
60                 lpScan++;
61             else
62                 lpArgEnd = lpScan;
63             break;
64         case '\"':
65             lpScan++;
66             fQuoted = !fQuoted;
67             break;
68         case '\0':
69             lpArgEnd = lpScan;
70             break;
71         default:
72             lpScan++;
73             break;
74         }
75     } while( *lpScan && !lpArgEnd );
76 
77     return lpScan;
78 }
79 
80 
81 IMPLEMENT_THUNK( shell32, WINDOWS, LPWSTR *, WINAPI, CommandLineToArgvW, ( LPCWSTR lpCmdLineW, int *pNumArgs ) )
82 {
83     LPWSTR  *lpArgvW = NULL;
84 
85     if ( !lpCmdLineW || !*lpCmdLineW )
86     {
87         CHAR    szFileName[MAX_PATH];
88 
89         DWORD   dwResult = GetModuleFileNameA( NULL, szFileName, MAX_PATH );
90 
91         if ( dwResult && dwResult < MAX_PATH )
92         {
93             int cchNeeded = MultiByteToWideChar( CP_ACP, 0, szFileName, -1, NULL, 0 );
94 
95             lpArgvW = (LPWSTR *)GlobalAlloc( 0, cchNeeded * sizeof(WCHAR) + sizeof(LPWSTR) );
96 
97             if ( lpArgvW )
98             {
99                 lpArgvW[0] = (LPWSTR)(lpArgvW + 1);
100 
101                 MultiByteToWideChar( CP_ACP, 0, szFileName, -1, lpArgvW[0], cchNeeded );
102                 *pNumArgs = 1;
103             }
104             else
105                 SetLastError( ERROR_OUTOFMEMORY );
106         }
107     }
108     else
109     {
110         LPCWSTR lpScan = lpCmdLineW;
111         int     nTokens = 0;
112         int     cchNeeded = 0;
113 
114         // Count arguments and required size
115 
116         while ( *lpScan )
117         {
118             lpScan = SkipBlanks( lpScan );
119             if ( *lpScan )
120             {
121                 LPCWSTR lpArgEnd = SkipArgument( lpScan );
122 
123                 nTokens++;
124                 cchNeeded += lpArgEnd - lpScan + 1;
125                 lpScan = lpArgEnd;
126             }
127         }
128 
129         // Allocate space for one additional NULL pointer to terminate list
130 
131         lpArgvW = (LPWSTR *)GlobalAlloc( 0, sizeof(LPWSTR) * (nTokens + 1) + sizeof(WCHAR) * cchNeeded );
132 
133         if ( lpArgvW )
134         {
135             // Collect arguments
136 
137             LPWSTR  lpDestination = (LPWSTR)&lpArgvW[nTokens + 1];
138 
139             lpScan = lpCmdLineW;
140             nTokens = 0;
141 
142             while ( *lpScan )
143             {
144                 lpScan = SkipBlanks( lpScan );
145                 if ( *lpScan )
146                 {
147                     LPCWSTR lpArgEnd = SkipArgument( lpScan );
148 
149                     lpArgvW[nTokens++] = lpDestination;
150 
151                     while ( lpScan < lpArgEnd )
152                     {
153                         if ( '\"' != *lpScan )
154                             *lpDestination++ = *lpScan;
155 
156                         lpScan++;
157                     }
158                     *lpDestination++ = 0;
159                 }
160             }
161 
162             lpArgvW[nTokens] = NULL;
163 
164             *pNumArgs = nTokens;
165         }
166         else
167             SetLastError( ERROR_OUTOFMEMORY );
168 
169     }
170 
171     return lpArgvW;
172 }