|
1 | 1 |
|
2 | | -#define true 1 |
3 | | -#define false 0 |
4 | | - |
5 | | -#pragma comment(lib, "kernel32") |
6 | | - |
7 | | -static int character_is_whitespace(char c){ |
8 | | - return (c == '\v') || (c == '\t') || (c == '\f') || (c == ' '); |
9 | | -} |
10 | | - |
11 | | - |
12 | | -// arguments: |
13 | | -// 'command_line' = the unprocessed command line received by calling 'GetCommandLineA' |
14 | | -// 'command_line_size' = the size of the command line, not including the zero_terminator |
15 | | -// 'out_buffer' = a buffer that is at least as long as the command line, |
16 | | -// which will recieve the processed command line as serial zero_terminated strings |
17 | | -// the return value is the amount of arguments we got. |
18 | | -static int windows_parse_command_line__internal(char *command_line, __int64 command_line_size, char *out_buffer){ |
19 | | - |
20 | | - // According to msdn: |
21 | | - // 1) Arguments are delimited by white space, which is either a space or tab. |
22 | | - // 2) The first argument must be valid and is the program name. Can be in quotes. |
23 | | - // Everything else does not apply. |
24 | | - // 3) Quotes give rise to arguements that conain spaces. |
25 | | - // Double quotes ("") in qotes give rise to a single quote. |
26 | | - // If the command line ends before ending the last argument then all character read so far are |
27 | | - // the last argument |
28 | | - // 4) \" is just ". |
29 | | - // 5) \ is just \ if it does not precedes a ". |
30 | | - // 6) if there are an even number of \ preceeding ", then they get halved and the " is a delimiter |
31 | | - // 7) if there are an add number of \ preceeding ", then they get halved and the last \" is just ". |
32 | | - |
33 | | - |
34 | | - // Examples: argv[1] argv[2] argv[3] |
35 | | - // 1) "abc" d e -> abc d e |
36 | | - // 2) a\\b d"e f"g h -> a\\b de fg h |
37 | | - // 3) a\\\"b c d -> a\"b c d |
38 | | - // 4) a\\\\"b c" d -> a\\ b c d |
39 | | - |
40 | | - char *at = out_buffer; |
41 | | - |
42 | | - // if 'in_quotes' we are also 'in_argument' |
43 | | - int in_quotes = false; |
44 | | - int in_argument = false; |
45 | | - |
46 | | - int amount_of_arguments = 0; |
47 | | - |
48 | | - for(__int64 i = 0; i < command_line_size; ){ |
49 | | - // @note: accsessing command_line[i + 1] is save because of zero termination |
50 | | - // assert(!in_quotes || in_argument); |
51 | | - |
52 | | - if(command_line[i] == '\\'){ |
53 | | - if(!in_argument){ |
54 | | - in_argument = true; |
55 | | - amount_of_arguments++; |
56 | | - } |
57 | | - |
58 | | - int amount_of_slashes = 0; |
59 | | - for(; i < command_line_size; i++){ |
60 | | - if(command_line[i] != '\\') break; |
61 | | - amount_of_slashes += 1; |
62 | | - } |
63 | | - |
64 | | - if(command_line[i] == '"'){ |
65 | | - // emit one slash for every pair of slashes |
66 | | - for(int s = 0; s < amount_of_slashes/2; s++) *at++ = '\\'; |
67 | | - |
68 | | - if(amount_of_slashes & 1){ |
69 | | - *at++ = '"'; // it was escaped |
70 | | - i++; // eat the '"' |
71 | | - }else{ |
72 | | - continue; |
73 | | - } |
74 | | - }else{ |
75 | | - // just emit all the slashes |
76 | | - for(int s = 0; s < amount_of_slashes; s++) *at++ = '\\'; |
77 | | - } |
78 | | - }else if(command_line[i] == '"'){ |
79 | | - if(!in_quotes){ |
80 | | - i++; // skip the '"' |
81 | | - in_quotes = true; |
82 | | - |
83 | | - if(!in_argument){ |
84 | | - in_argument = true; // if the argument started with quotes ("asd"bcd -> asdbcd) |
85 | | - amount_of_arguments++; |
86 | | - } |
87 | | - }else{ |
88 | | - if(command_line[i + 1] == '"'){ |
89 | | - i += 2; |
90 | | - *at++ = '"'; |
91 | | - }else{ |
92 | | - i++; |
93 | | - in_quotes = false; |
94 | | - } |
95 | | - } |
96 | | - }else if(character_is_whitespace(command_line[i])){ |
97 | | - if(in_quotes){ |
98 | | - *at++ = command_line[i]; |
99 | | - }else if(in_argument){ |
100 | | - in_argument = false; // end the argument |
101 | | - *at++ = 0; |
102 | | - }else{ |
103 | | - // do nothing we are currently in whitespace |
104 | | - } |
105 | | - i++; |
106 | | - }else{ |
107 | | - *at++ = command_line[i]; // always just output the character |
108 | | - i++; |
109 | | - if(!in_argument){ |
110 | | - in_argument = true; |
111 | | - amount_of_arguments++; |
112 | | - } |
113 | | - } |
114 | | - } |
115 | | - *at++ = 0; // zero terminate |
116 | | - |
117 | | - return amount_of_arguments; |
118 | | -} |
119 | | - |
120 | | -__declspec(dllimport) void* GlobalAlloc(unsigned int uFlags, unsigned __int64 dwBytes); |
121 | | -__declspec(dllimport) char* GetCommandLineA(void); |
122 | | -__declspec(dllimport) __declspec(noreturn) void ExitProcess(unsigned int uExitCode); |
| 2 | +#include "pre_main_common.c" |
123 | 3 |
|
124 | 4 | int main(int argc, char *argv[]); |
125 | 5 |
|
126 | 6 | int _start(void){ |
127 | | - char *command_line = GetCommandLineA(); |
128 | | - |
129 | | - unsigned __int64 command_line_size = 0; |
130 | | - for(char *it = command_line; *it; it++) command_line_size++; |
131 | | - |
132 | | -#define GMEM_FIXED 0 |
133 | | - char *preped_command_line = (char *)GlobalAlloc(GMEM_FIXED, command_line_size + 1); |
134 | | - int argc = windows_parse_command_line__internal(command_line, command_line_size, preped_command_line); |
135 | 7 |
|
136 | | - char **argv = (char **)GlobalAlloc(GMEM_FIXED, (argc + 1) * sizeof(char *)); |
137 | | - char *at = preped_command_line; |
138 | | - for(int i = 0; i < argc; i++){ |
139 | | - argv[i] = at; |
140 | | - while(*at++); // skip to past the next zero_terminator |
141 | | - } |
142 | | - argv[argc] = 0; |
| 8 | + pre_main_common(); |
143 | 9 |
|
144 | 10 | int exit_code = main(argc, argv); |
145 | 11 |
|
|
0 commit comments