fd9779f001e843d3fb23a09af28295d27e2549c4
[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 #define WIN32_NO_STATUS
9 #define UNICODE
10 #include <stdio.h>
11 #include <wine/test.h>
12 #include <ndk/ntndk.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 typedef struct _TEST_CASE
91 {
92 LPWSTR CmdLine;
93 } TEST_CASE, *PTEST_CASE;
94
95 static TEST_CASE TestCases[] =
96 {
97 {L"CmdLineUtil.exe"},
98 {L"CmdLineUtil.exe foo bar"},
99 {L"CmdLineUtil.exe \"foo bar\""},
100 {L"CmdLineUtil.exe foo \"bar John\" Doe"},
101
102 {L"\"CmdLineUtil.exe\""},
103 {L"\"CmdLineUtil.exe\" foo bar"},
104 {L"\"CmdLineUtil.exe\" \"foo bar\""},
105 {L"\"CmdLineUtil.exe\" foo \"bar John\" Doe"},
106
107 {L"\"CmdLineUtil.exe\""},
108 {L"\"CmdLineUtil.exe \"foo bar\"\""},
109 };
110
111 static void Test_CommandLine(IN ULONG TestNumber,
112 IN PTEST_CASE TestCase)
113 {
114 BOOL bRet;
115
116 WCHAR CmdLine[MAX_PATH];
117 STARTUPINFOW si;
118 PROCESS_INFORMATION pi;
119
120 ZeroMemory(&si, sizeof(si));
121 ZeroMemory(&pi, sizeof(pi));
122 si.cb = sizeof(si);
123
124 wcscpy(CmdLine, TestCase->CmdLine);
125
126 /*
127 * Launch the utility program and wait till it's terminated.
128 */
129 bRet = CreateProcessW(NULL,
130 CmdLine,
131 NULL, NULL,
132 FALSE,
133 CREATE_UNICODE_ENVIRONMENT,
134 NULL, NULL,
135 &si, &pi);
136 ok(bRet, "Test %lu - Failed to launch ' %S ', error = %lu.\n", TestNumber, TestCase->CmdLine, GetLastError());
137
138 if (bRet)
139 {
140 /* Wait until child process exits. */
141 WaitForSingleObject(pi.hProcess, INFINITE);
142
143 /* Close process and thread handles. */
144 CloseHandle(pi.hThread);
145 CloseHandle(pi.hProcess);
146 }
147
148 /*
149 * Analyses the result.
150 */
151 {
152 /* Open the data file. */
153 HANDLE hFile = CreateFileW(DATAFILE,
154 GENERIC_READ,
155 0, NULL,
156 OPEN_EXISTING,
157 FILE_ATTRIBUTE_NORMAL,
158 NULL);
159 ok(hFile != INVALID_HANDLE_VALUE, "Test %lu - Failed to open the data file 'C:\\cmdline.dat', error = %lu.\n", TestNumber, GetLastError());
160
161 if (hFile != INVALID_HANDLE_VALUE)
162 {
163 WCHAR BuffWinMain[MAX_PATH]; LPWSTR WinMainCmdLine = BuffWinMain;
164 WCHAR BuffWin32[MAX_PATH] ; LPWSTR Win32CmdLine = BuffWin32 ;
165 WCHAR BuffNT[0xffff /* Maximum USHORT size */];
166 UNICODE_STRING NTCmdLine;
167
168 DWORD dwSize, dwStringSize;
169
170 /*
171 * Format of the data file :
172 *
173 * [size_of_string 4 bytes][null_terminated_C_string]
174 * [size_of_string 4 bytes][null_terminated_C_string]
175 * [UNICODE_STRING_structure][string_buffer_of_UNICODE_STRING]
176 */
177
178 /* 1- Read the WinMain's command line. */
179 dwStringSize = 0;
180
181 ReadFile(hFile,
182 &dwStringSize,
183 sizeof(dwStringSize),
184 &dwSize,
185 NULL);
186
187 dwStringSize = min(dwStringSize, sizeof(BuffWinMain));
188 ReadFile(hFile,
189 WinMainCmdLine,
190 dwStringSize,
191 &dwSize,
192 NULL);
193 *(LPWSTR)((ULONG_PTR)WinMainCmdLine + dwStringSize) = 0;
194
195 /* 2- Read the Win32 mode command line. */
196 dwStringSize = 0;
197
198 ReadFile(hFile,
199 &dwStringSize,
200 sizeof(dwStringSize),
201 &dwSize,
202 NULL);
203
204 dwStringSize = min(dwStringSize, sizeof(BuffWin32));
205 ReadFile(hFile,
206 Win32CmdLine,
207 dwStringSize,
208 &dwSize,
209 NULL);
210 *(LPWSTR)((ULONG_PTR)Win32CmdLine + dwStringSize) = 0;
211
212 /* 3- Finally, read the UNICODE_STRING command line. */
213 ReadFile(hFile,
214 &NTCmdLine,
215 sizeof(NTCmdLine),
216 &dwSize,
217 NULL);
218
219 NTCmdLine.Buffer = BuffNT;
220 ReadFile(hFile,
221 NTCmdLine.Buffer,
222 NTCmdLine.Length,
223 &dwSize,
224 NULL);
225
226 /* Now close the file. */
227 CloseHandle(hFile);
228
229 /*
230 * Remove the program's name in the Win32 and NT command lines.
231 */
232 Win32CmdLine = ExtractCmdLine(Win32CmdLine);
233 ExtractCmdLine_U(&NTCmdLine);
234
235 /* Print the results */
236 /*
237 *(LPWSTR)((ULONG_PTR)NTCmdLine.Buffer + NTCmdLine.Length) = 0;
238 printf("WinMain cmdline = '%S'\n"
239 "Win32 cmdline = '%S'\n"
240 "NT cmdline = '%S'\n"
241 "NT length = %u\n",
242 WinMainCmdLine,
243 Win32CmdLine,
244 NTCmdLine.Buffer, NTCmdLine.Length);
245 */
246
247 /*
248 * Now check the results.
249 */
250 dwStringSize = min(wcslen(WinMainCmdLine), wcslen(Win32CmdLine));
251 ok(wcslen(WinMainCmdLine) == wcslen(Win32CmdLine), "Test %lu - WinMain and Win32 command lines do not have the same length !\n", TestNumber);
252 ok(wcsncmp(WinMainCmdLine, Win32CmdLine, dwStringSize) == 0, "Test %lu - WinMain and Win32 command lines are different !\n", TestNumber);
253
254 dwStringSize = min(wcslen(WinMainCmdLine), NTCmdLine.Length / sizeof(WCHAR));
255 ok(wcsncmp(WinMainCmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - WinMain and NT command lines are different !\n", TestNumber);
256
257 dwStringSize = min(wcslen(Win32CmdLine), NTCmdLine.Length / sizeof(WCHAR));
258 ok(wcsncmp(Win32CmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - Win32 and NT command lines are different !\n", TestNumber);
259 }
260 }
261
262 /*
263 * Always delete the data file.
264 */
265 DeleteFileW(DATAFILE);
266 }
267
268 START_TEST(CommandLine)
269 {
270 ULONG i;
271
272 for (i = 0 ; i < COUNT_OF(TestCases) ; ++i)
273 {
274 Test_CommandLine(i, &TestCases[i]);
275 }
276 }
277
278 /* EOF */