xref: /reactos/sdk/lib/ucrt/startup/argv_winmain.cpp (revision a6a07059)
1 /***
2 *wincmdln.c - process command line for WinMain
3 *
4 *       Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 *       Prepare command line to be passed to [w]WinMain.
8 *
9 *******************************************************************************/
10 
11 #include <corecrt_internal.h>
12 #include <mbstring.h>
13 
14 
15 
16 // In the function below, we need to ensure that we've initialized the mbc table
17 // before we start performing character transformations.
18 static void do_locale_initialization(unsigned char) throw() { __acrt_initialize_multibyte(); }
19 static void do_locale_initialization(wchar_t)       throw() { /* no-op */                    }
20 
21 static unsigned char* get_command_line(unsigned char) throw()
22 {
23     return reinterpret_cast<unsigned char *>(_acmdln);
24 }
25 
26 static wchar_t* get_command_line(wchar_t) throw() { return _wcmdln; }
27 
28 
29 // should_copy_another_character is *ONLY* checking for DBCS lead bytes to see if there
30 // might be a following trail byte.  This works because the callers are only concerned
31 // about escaped quote sequences and other codepages aren't using those quotes.
32 static bool __cdecl should_copy_another_character(unsigned char const c) throw()
33 {
34     // This is OK for UTF-8 as a quote is never a trail byte.
35     return _ismbblead(c) != 0;
36 }
37 
38 static bool __cdecl should_copy_another_character(wchar_t) throw()
39 {
40     // This is OK for UTF-16 as a quote is never part of a surrogate pair.
41     return false;
42 }
43 
44 
45 
46 /***
47 *_[w]wincmdln
48 *
49 *Purpose:
50 *       Extract the command line tail to be passed to WinMain.
51 *
52 *       Be warned! This code was originally implemented by the NT group and
53 *       has remained pretty much unchanged since 12-91. It should be changed
54 *       only with extreme care since there are undoubtedly many apps which
55 *       depend on its historical behavior.
56 *
57 *Entry:
58 *       The global variable _[a|w]cmdln is set to point at the complete
59 *       command line.
60 *
61 *Exit:
62 *       Returns a pointer to the command line tail.
63 *
64 *Exceptions:
65 *
66 *******************************************************************************/
67 template <typename Character>
68 static Character* __cdecl common_wincmdln() throw()
69 {
70     do_locale_initialization(Character());
71 
72     static Character empty_string[] = { '\0' };
73 
74     Character* command_line = get_command_line(Character()) == nullptr
75         ? empty_string
76         : get_command_line(Character());
77 
78     // Skip past the program name (the first token in the command line) and
79     // check for and handle a quoted program name:
80     bool in_double_quotes = false;
81     while (*command_line > ' ' || (*command_line != '\0' && in_double_quotes))
82     {
83         // Toggle the in_double_quotes flag if the current character is '"'
84         if (*command_line == '"')
85             in_double_quotes = !in_double_quotes;
86 
87         if (should_copy_another_character(*command_line))
88             ++command_line;
89 
90         ++command_line;
91     }
92 
93     // Skip past any whitespace preceding the next token:
94     while (*command_line != '\0' && *command_line <= ' ')
95         ++command_line;
96 
97     return command_line;
98 }
99 
100 
101 
102 extern "C" char* __cdecl _get_narrow_winmain_command_line()
103 {   // Need to use unsigned char so that we correctly handle ASCII characters
104     // above 127, in particular the comparison to ' ' (space - 0x20).
105     return reinterpret_cast<char *>(common_wincmdln<unsigned char>());
106 }
107 
108 extern "C" wchar_t* __cdecl _get_wide_winmain_command_line()
109 {
110     return common_wincmdln<wchar_t>();
111 }
112