[WS2_32_APITEST]
[reactos.git] / rostests / apitests / msvcrt / CommandLine.c
1 /*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for CRT command-line handling.
5 * PROGRAMMER: Hermès BÉLUSCA - MAÏTO <hermes.belusca@sfr.fr>
6 */
7
8 #include <apitest.h>
9
10 #define WIN32_NO_STATUS
11 #include <stdio.h>
12 #include <ndk/umtypes.h>
13
14 #include "./CmdLineUtil/CmdLineUtil.h"
15
16 #define COUNT_OF(x) (sizeof((x))/sizeof((x)[0]))
17
18 /**
19 * Extracts the command tail from the command line
20 * (deletes the program's name and keep the rest).
21 **/
22 #define SPACECHAR L' '
23 #define DQUOTECHAR L'"'
24
25 LPWSTR ExtractCmdLine(IN LPWSTR lpszCommandLine)
26 {
27 BOOL inDoubleQuote = FALSE;
28
29 /*
30 * Skip the program's name (the first token in the command line).
31 * Handle quoted program's name.
32 */
33 if (lpszCommandLine)
34 {
35 while ( (*lpszCommandLine > SPACECHAR) ||
36 (*lpszCommandLine && inDoubleQuote) )
37 {
38 if (*lpszCommandLine == DQUOTECHAR)
39 inDoubleQuote = !inDoubleQuote;
40
41 ++lpszCommandLine;
42 }
43
44 /* Skip all white spaces preceeding the second token. */
45 while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
46 ++lpszCommandLine;
47 }
48
49 return lpszCommandLine;
50 }
51
52 VOID ExtractCmdLine_U(IN OUT PUNICODE_STRING pCommandLine_U)
53 {
54 BOOL inDoubleQuote = FALSE;
55 PWSTR lpszCommandLine;
56
57 /*
58 * Skip the program's name (the first token in the command line).
59 * Handle quoted program's name.
60 */
61 if (pCommandLine_U && pCommandLine_U->Buffer && (pCommandLine_U->Length != 0))
62 {
63 lpszCommandLine = pCommandLine_U->Buffer;
64
65 while ( (pCommandLine_U->Length > 0) &&
66 ( (*lpszCommandLine > SPACECHAR) ||
67 (*lpszCommandLine && inDoubleQuote) ) )
68 {
69 if (*lpszCommandLine == DQUOTECHAR)
70 inDoubleQuote = !inDoubleQuote;
71
72 ++lpszCommandLine;
73 pCommandLine_U->Length -= sizeof(WCHAR);
74 }
75
76 /* Skip all white spaces preceeding the second token. */
77 while ((pCommandLine_U->Length > 0) && *lpszCommandLine && (*lpszCommandLine <= SPACECHAR))
78 {
79 ++lpszCommandLine;
80 pCommandLine_U->Length -= sizeof(WCHAR);
81 }
82
83 pCommandLine_U->Buffer = lpszCommandLine;
84 }
85
86 return;
87 }
88
89 /******************************************************************************/
90
91 /* The path to the utility program run by this test. */
92 static WCHAR UtilityProgramDirectory[MAX_PATH];
93
94 /* The list of tests. */
95 typedef struct _TEST_CASE
96 {
97 LPWSTR CmdLine;
98 BOOL bEncloseProgramNameInQuotes;
99 } TEST_CASE, *PTEST_CASE;
100
101 static TEST_CASE TestCases[] =
102 {
103 {L"", FALSE},
104 {L"foo bar", FALSE},
105 {L"\"foo bar\"", FALSE},
106 {L"foo \"bar John\" Doe", FALSE},
107
108 {L"", TRUE},
109 {L"foo bar", TRUE},
110 {L"\"foo bar\"", TRUE},
111 {L"foo \"bar John\" Doe", TRUE},
112 };
113
114 static void Test_CommandLine(IN ULONG TestNumber,
115 IN PTEST_CASE TestCase)
116 {
117 BOOL bRet;
118
119 BOOL bWasntInQuotes = (UtilityProgramDirectory[0] != L'"');
120 WCHAR CmdLine[MAX_PATH] = L"";
121 STARTUPINFOW si;
122 PROCESS_INFORMATION pi;
123
124 ZeroMemory(&si, sizeof(si));
125 ZeroMemory(&pi, sizeof(pi));
126 si.cb = sizeof(si);
127
128
129 /* Initialize the command line. */
130 if (TestCase->bEncloseProgramNameInQuotes && bWasntInQuotes)
131 wcscpy(CmdLine, L"\"");
132
133 wcscat(CmdLine, UtilityProgramDirectory);
134
135 if (TestCase->bEncloseProgramNameInQuotes && bWasntInQuotes)
136 wcscat(CmdLine, L"\"");
137
138 /* Add a separating space and copy the tested command line parameters. */
139 wcscat(CmdLine, L" ");
140 wcscat(CmdLine, TestCase->CmdLine);
141
142
143 /*
144 * Launch the utility program and wait till it's terminated.
145 */
146 bRet = CreateProcessW(NULL,
147 CmdLine,
148 NULL, NULL,
149 FALSE,
150 CREATE_UNICODE_ENVIRONMENT,
151 NULL, NULL,
152 &si, &pi);
153 ok(bRet, "Test %lu - Failed to launch ' %S ', error = %lu.\n", TestNumber, CmdLine, GetLastError());
154
155 if (bRet)
156 {
157 /* Wait until child process exits. */
158 WaitForSingleObject(pi.hProcess, INFINITE);
159
160 /* Close process and thread handles. */
161 CloseHandle(pi.hThread);
162 CloseHandle(pi.hProcess);
163 }
164
165 /*
166 * Analyses the result.
167 */
168 {
169 /* Open the data file. */
170 HANDLE hFile = CreateFileW(DATAFILE,
171 GENERIC_READ,
172 0, NULL,
173 OPEN_EXISTING,
174 FILE_ATTRIBUTE_NORMAL,
175 NULL);
176 ok(hFile != INVALID_HANDLE_VALUE, "Test %lu - Failed to open the data file 'C:\\cmdline.dat', error = %lu.\n", TestNumber, GetLastError());
177
178 if (hFile != INVALID_HANDLE_VALUE)
179 {
180 WCHAR BuffWinMain[MAX_PATH]; LPWSTR WinMainCmdLine = BuffWinMain;
181 WCHAR BuffWin32[MAX_PATH] ; LPWSTR Win32CmdLine = BuffWin32 ;
182 WCHAR BuffNT[0xffff /* Maximum USHORT size */];
183 UNICODE_STRING NTCmdLine;
184
185 DWORD dwSize, dwStringSize;
186
187 /*
188 * Format of the data file :
189 *
190 * [size_of_string 4 bytes][null_terminated_C_string]
191 * [size_of_string 4 bytes][null_terminated_C_string]
192 * [UNICODE_STRING_structure][string_buffer_of_UNICODE_STRING]
193 */
194
195 /* 1- Read the WinMain's command line. */
196 dwStringSize = 0;
197
198 ReadFile(hFile,
199 &dwStringSize,
200 sizeof(dwStringSize),
201 &dwSize,
202 NULL);
203
204 dwStringSize = min(dwStringSize, sizeof(BuffWinMain));
205 ReadFile(hFile,
206 WinMainCmdLine,
207 dwStringSize,
208 &dwSize,
209 NULL);
210 *(LPWSTR)((ULONG_PTR)WinMainCmdLine + dwStringSize) = 0;
211
212 /* 2- Read the Win32 mode command line. */
213 dwStringSize = 0;
214
215 ReadFile(hFile,
216 &dwStringSize,
217 sizeof(dwStringSize),
218 &dwSize,
219 NULL);
220
221 dwStringSize = min(dwStringSize, sizeof(BuffWin32));
222 ReadFile(hFile,
223 Win32CmdLine,
224 dwStringSize,
225 &dwSize,
226 NULL);
227 *(LPWSTR)((ULONG_PTR)Win32CmdLine + dwStringSize) = 0;
228
229 /* 3- Finally, read the UNICODE_STRING command line. */
230 ReadFile(hFile,
231 &NTCmdLine,
232 sizeof(NTCmdLine),
233 &dwSize,
234 NULL);
235
236 NTCmdLine.Buffer = BuffNT;
237 ReadFile(hFile,
238 NTCmdLine.Buffer,
239 NTCmdLine.Length,
240 &dwSize,
241 NULL);
242
243 /* Now close the file. */
244 CloseHandle(hFile);
245
246 /*
247 * Remove the program's name in the Win32 and NT command lines.
248 */
249 Win32CmdLine = ExtractCmdLine(Win32CmdLine);
250 ExtractCmdLine_U(&NTCmdLine);
251
252 /* Print the results */
253 /*
254 *(LPWSTR)((ULONG_PTR)NTCmdLine.Buffer + NTCmdLine.Length) = 0;
255 printf("WinMain cmdline = '%S'\n"
256 "Win32 cmdline = '%S'\n"
257 "NT cmdline = '%S'\n"
258 "NT length = %u\n",
259 WinMainCmdLine,
260 Win32CmdLine,
261 NTCmdLine.Buffer, NTCmdLine.Length);
262 */
263
264 /*
265 * Now check the results.
266 */
267 dwStringSize = min(wcslen(WinMainCmdLine), wcslen(Win32CmdLine));
268 ok(wcslen(WinMainCmdLine) == wcslen(Win32CmdLine), "Test %lu - WinMain and Win32 command lines do not have the same length !\n", TestNumber);
269 ok(wcsncmp(WinMainCmdLine, Win32CmdLine, dwStringSize) == 0, "Test %lu - WinMain and Win32 command lines are different !\n", TestNumber);
270
271 dwStringSize = min(wcslen(WinMainCmdLine), NTCmdLine.Length / sizeof(WCHAR));
272 ok(wcsncmp(WinMainCmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - WinMain and NT command lines are different !\n", TestNumber);
273
274 dwStringSize = min(wcslen(Win32CmdLine), NTCmdLine.Length / sizeof(WCHAR));
275 ok(wcsncmp(Win32CmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - Win32 and NT command lines are different !\n", TestNumber);
276 }
277 }
278
279 /*
280 * Always delete the data file.
281 */
282 DeleteFileW(DATAFILE);
283 }
284
285 START_TEST(CommandLine)
286 {
287 ULONG i;
288
289 DWORD dwRet;
290 LPWSTR p = NULL;
291
292
293 /*
294 * Initialize the UtilityProgramDirectory variable.
295 */
296 dwRet = GetModuleFileNameW(NULL, UtilityProgramDirectory, COUNT_OF(UtilityProgramDirectory));
297 ok(dwRet != 0, "ERROR: Cannot retrieve the path to the current running process, last error %lu\n", GetLastError());
298 if (dwRet == 0) return;
299
300 /* Path : executable.exe or "executable.exe" or C:\path\executable.exe or "C:\path\executable.exe" */
301 p = wcsrchr(UtilityProgramDirectory, L'\\');
302 if (p && *p != 0)
303 *++p = 0; /* Null-terminate there : C:\path\ or "C:\path\ */
304 else
305 UtilityProgramDirectory[0] = 0; /* Suppress the executable.exe name */
306
307 wcscat(UtilityProgramDirectory, L"testdata\\CmdLineUtil.exe");
308
309 /* Close the opened quote if needed. */
310 if (UtilityProgramDirectory[0] == L'"') wcscat(UtilityProgramDirectory, L"\"");
311
312
313 /*
314 * Now launch the tests.
315 */
316 for (i = 0 ; i < COUNT_OF(TestCases) ; ++i)
317 {
318 Test_CommandLine(i, &TestCases[i]);
319 }
320 }
321
322 /* EOF */