ReactOS  0.4.14-dev-358-gbef841c
CommandLine.c
Go to the documentation of this file.
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 
15 
16 #define COUNT_OF(x) (sizeof((x))/sizeof((x)[0]))
17 
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 
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. */
93 
94 /* The list of tests. */
95 typedef struct _TEST_CASE
96 {
100 
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,
116 {
117  BOOL bRet;
118 
119  BOOL bWasntInQuotes = (UtilityProgramDirectory[0] != L'"');
120  WCHAR CmdLine[MAX_PATH] = L"";
121  STARTUPINFOW si;
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 
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,
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. */
171  GENERIC_READ,
172  0, NULL,
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 
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. */
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  */
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  */
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" */
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. */
311 
312 
313  /*
314  * Now launch the tests.
315  */
316  for (i = 0 ; i < COUNT_OF(TestCases) ; ++i)
317  {
319  }
320 }
321 
322 /* EOF */
#define DATAFILE
Definition: CmdLineUtil.h:11
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:609
#define DQUOTECHAR
Definition: CommandLine.c:23
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:406
static void Test_CommandLine(IN ULONG TestNumber, IN PTEST_CASE TestCase)
Definition: CommandLine.c:114
#define SPACECHAR
Definition: CommandLine.c:22
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:186
uint16_t * PWSTR
Definition: typedefs.h:54
LPWSTR ExtractCmdLine(IN LPWSTR lpszCommandLine)
Definition: CommandLine.c:25
#define INVALID_HANDLE_VALUE
Definition: compat.h:399
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1642
uint32_t ULONG_PTR
Definition: typedefs.h:63
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned int BOOL
Definition: ntddk_ex.h:94
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
START_TEST(CommandLine)
Definition: CommandLine.c:285
smooth NULL
Definition: ftsmooth.c:416
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcsrchr(_In_z_ const wchar_t *_Str, _In_ wchar_t _Ch)
VOID ExtractCmdLine_U(IN OUT PUNICODE_STRING pCommandLine_U)
Definition: CommandLine.c:52
#define OPEN_EXISTING
Definition: compat.h:434
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
Definition: proc.c:4593
#define COUNT_OF(x)
Definition: CommandLine.c:16
LPWSTR CmdLine
Definition: CommandLine.c:97
DWORD cb
Definition: winbase.h:824
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define MAX_PATH
Definition: compat.h:26
unsigned long DWORD
Definition: ntddk_ex.h:95
_Check_return_ _CRTIMP int __cdecl wcsncmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
static DWORD pi
Definition: protocol.c:150
static TEST_CASE TestCases[]
Definition: CommandLine.c:101
BOOL bEncloseProgramNameInQuotes
Definition: CommandLine.c:98
CHAR CmdLine[MAX_PATH]
Definition: mach.c:34
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1250
#define GENERIC_READ
Definition: compat.h:124
_In_ HANDLE hFile
Definition: mswsock.h:90
#define ok(value,...)
Definition: atltest.h:57
static WCHAR UtilityProgramDirectory[MAX_PATH]
Definition: CommandLine.c:92
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
#define min(a, b)
Definition: monoChain.cc:55
#define CreateFileW
Definition: compat.h:408
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
struct _TEST_CASE TEST_CASE
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define INFINITE
Definition: serial.h:102
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
struct _TEST_CASE * PTEST_CASE
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54