OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2006 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/base/flags.h" | |
12 | |
13 #include <stdio.h> | |
14 #include <stdlib.h> | |
15 #include <string.h> | |
16 | |
17 #include "webrtc/base/checks.h" | |
18 | |
19 #if defined(WEBRTC_WIN) | |
20 #include "webrtc/base/win32.h" | |
21 #include <shellapi.h> | |
22 #endif | |
23 | |
24 namespace rtc { | |
25 // ----------------------------------------------------------------------------- | |
26 // Implementation of Flag | |
27 | |
28 Flag::Flag(const char* file, const char* name, const char* comment, | |
29 Type type, void* variable, FlagValue default__) | |
30 : file_(file), | |
31 name_(name), | |
32 comment_(comment), | |
33 type_(type), | |
34 variable_(reinterpret_cast<FlagValue*>(variable)), | |
35 default_(default__) { | |
36 FlagList::Register(this); | |
37 } | |
38 | |
39 | |
40 void Flag::SetToDefault() { | |
41 // Note that we cannot simply do '*variable_ = default_;' since | |
42 // flag variables are not really of type FlagValue and thus may | |
43 // be smaller! The FlagValue union is simply 'overlayed' on top | |
44 // of a flag variable for convenient access. Since union members | |
45 // are guarantee to be aligned at the beginning, this works. | |
46 switch (type_) { | |
47 case Flag::BOOL: | |
48 variable_->b = default_.b; | |
49 return; | |
50 case Flag::INT: | |
51 variable_->i = default_.i; | |
52 return; | |
53 case Flag::FLOAT: | |
54 variable_->f = default_.f; | |
55 return; | |
56 case Flag::STRING: | |
57 variable_->s = default_.s; | |
58 return; | |
59 } | |
60 FATAL() << "unreachable code"; | |
61 } | |
62 | |
63 | |
64 static const char* Type2String(Flag::Type type) { | |
65 switch (type) { | |
66 case Flag::BOOL: return "bool"; | |
67 case Flag::INT: return "int"; | |
68 case Flag::FLOAT: return "float"; | |
69 case Flag::STRING: return "string"; | |
70 } | |
71 FATAL() << "unreachable code"; | |
72 } | |
73 | |
74 | |
75 static void PrintFlagValue(Flag::Type type, FlagValue* p) { | |
76 switch (type) { | |
77 case Flag::BOOL: | |
78 printf("%s", (p->b ? "true" : "false")); | |
79 return; | |
80 case Flag::INT: | |
81 printf("%d", p->i); | |
82 return; | |
83 case Flag::FLOAT: | |
84 printf("%f", p->f); | |
85 return; | |
86 case Flag::STRING: | |
87 printf("%s", p->s); | |
88 return; | |
89 } | |
90 FATAL() << "unreachable code"; | |
91 } | |
92 | |
93 | |
94 void Flag::Print(bool print_current_value) { | |
95 printf(" --%s (%s) type: %s default: ", name_, comment_, | |
96 Type2String(type_)); | |
97 PrintFlagValue(type_, &default_); | |
98 if (print_current_value) { | |
99 printf(" current value: "); | |
100 PrintFlagValue(type_, variable_); | |
101 } | |
102 printf("\n"); | |
103 } | |
104 | |
105 | |
106 // ----------------------------------------------------------------------------- | |
107 // Implementation of FlagList | |
108 | |
109 Flag* FlagList::list_ = nullptr; | |
110 | |
111 FlagList::FlagList() { | |
112 list_ = nullptr; | |
113 } | |
114 | |
115 void FlagList::Print(const char* file, bool print_current_value) { | |
116 // Since flag registration is likely by file (= C++ file), | |
117 // we don't need to sort by file and still get grouped output. | |
118 const char* current = nullptr; | |
119 for (Flag* f = list_; f != nullptr; f = f->next()) { | |
120 if (file == nullptr || file == f->file()) { | |
121 if (current != f->file()) { | |
122 printf("Flags from %s:\n", f->file()); | |
123 current = f->file(); | |
124 } | |
125 f->Print(print_current_value); | |
126 } | |
127 } | |
128 } | |
129 | |
130 | |
131 Flag* FlagList::Lookup(const char* name) { | |
132 Flag* f = list_; | |
133 while (f != nullptr && strcmp(name, f->name()) != 0) | |
134 f = f->next(); | |
135 return f; | |
136 } | |
137 | |
138 | |
139 void FlagList::SplitArgument(const char* arg, | |
140 char* buffer, int buffer_size, | |
141 const char** name, const char** value, | |
142 bool* is_bool) { | |
143 *name = nullptr; | |
144 *value = nullptr; | |
145 *is_bool = false; | |
146 | |
147 if (*arg == '-') { | |
148 // find the begin of the flag name | |
149 arg++; // remove 1st '-' | |
150 if (*arg == '-') | |
151 arg++; // remove 2nd '-' | |
152 if (arg[0] == 'n' && arg[1] == 'o') { | |
153 arg += 2; // remove "no" | |
154 *is_bool = true; | |
155 } | |
156 *name = arg; | |
157 | |
158 // find the end of the flag name | |
159 while (*arg != '\0' && *arg != '=') | |
160 arg++; | |
161 | |
162 // get the value if any | |
163 if (*arg == '=') { | |
164 // make a copy so we can NUL-terminate flag name | |
165 int n = static_cast<int>(arg - *name); | |
166 RTC_CHECK_LT(n, buffer_size); | |
167 memcpy(buffer, *name, n * sizeof(char)); | |
168 buffer[n] = '\0'; | |
169 *name = buffer; | |
170 // get the value | |
171 *value = arg + 1; | |
172 } | |
173 } | |
174 } | |
175 | |
176 | |
177 int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv, | |
178 bool remove_flags) { | |
179 // parse arguments | |
180 for (int i = 1; i < *argc; /* see below */) { | |
181 int j = i; // j > 0 | |
182 const char* arg = argv[i++]; | |
183 | |
184 // split arg into flag components | |
185 char buffer[1024]; | |
186 const char* name; | |
187 const char* value; | |
188 bool is_bool; | |
189 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool); | |
190 | |
191 if (name != nullptr) { | |
192 // lookup the flag | |
193 Flag* flag = Lookup(name); | |
194 if (flag == nullptr) { | |
195 fprintf(stderr, "Error: unrecognized flag %s\n", arg); | |
196 return j; | |
197 } | |
198 | |
199 // if we still need a flag value, use the next argument if available | |
200 if (flag->type() != Flag::BOOL && value == nullptr) { | |
201 if (i < *argc) { | |
202 value = argv[i++]; | |
203 } else { | |
204 fprintf(stderr, "Error: missing value for flag %s of type %s\n", | |
205 arg, Type2String(flag->type())); | |
206 return j; | |
207 } | |
208 } | |
209 | |
210 // set the flag | |
211 char empty[] = { '\0' }; | |
212 char* endp = empty; | |
213 switch (flag->type()) { | |
214 case Flag::BOOL: | |
215 *flag->bool_variable() = !is_bool; | |
216 break; | |
217 case Flag::INT: | |
218 *flag->int_variable() = strtol(value, &endp, 10); | |
219 break; | |
220 case Flag::FLOAT: | |
221 *flag->float_variable() = strtod(value, &endp); | |
222 break; | |
223 case Flag::STRING: | |
224 *flag->string_variable() = value; | |
225 break; | |
226 } | |
227 | |
228 // handle errors | |
229 if ((flag->type() == Flag::BOOL && value != nullptr) || | |
230 (flag->type() != Flag::BOOL && is_bool) || *endp != '\0') { | |
231 fprintf(stderr, "Error: illegal value for flag %s of type %s\n", | |
232 arg, Type2String(flag->type())); | |
233 return j; | |
234 } | |
235 | |
236 // remove the flag & value from the command | |
237 if (remove_flags) | |
238 while (j < i) | |
239 argv[j++] = nullptr; | |
240 } | |
241 } | |
242 | |
243 // shrink the argument list | |
244 if (remove_flags) { | |
245 int j = 1; | |
246 for (int i = 1; i < *argc; i++) { | |
247 if (argv[i] != nullptr) | |
248 argv[j++] = argv[i]; | |
249 } | |
250 *argc = j; | |
251 } | |
252 | |
253 // parsed all flags successfully | |
254 return 0; | |
255 } | |
256 | |
257 void FlagList::Register(Flag* flag) { | |
258 RTC_DCHECK(flag); | |
259 RTC_DCHECK_GT(strlen(flag->name()), 0); | |
260 // NOTE: Don't call Lookup() within Register because it accesses the name_ | |
261 // of other flags in list_, and if the flags are coming from two different | |
262 // compilation units, the initialization order between them is undefined, and | |
263 // this will trigger an asan initialization-order-fiasco error. | |
264 flag->next_ = list_; | |
265 list_ = flag; | |
266 } | |
267 | |
268 #if defined(WEBRTC_WIN) | |
269 WindowsCommandLineArguments::WindowsCommandLineArguments() { | |
270 // start by getting the command line. | |
271 LPTSTR command_line = ::GetCommandLine(); | |
272 // now, convert it to a list of wide char strings. | |
273 LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_); | |
274 // now allocate an array big enough to hold that many string pointers. | |
275 argv_ = new char*[argc_]; | |
276 | |
277 // iterate over the returned wide strings; | |
278 for(int i = 0; i < argc_; ++i) { | |
279 std::string s = rtc::ToUtf8(wide_argv[i], wcslen(wide_argv[i])); | |
280 char *buffer = new char[s.length() + 1]; | |
281 rtc::strcpyn(buffer, s.length() + 1, s.c_str()); | |
282 | |
283 // make sure the argv array has the right string at this point. | |
284 argv_[i] = buffer; | |
285 } | |
286 LocalFree(wide_argv); | |
287 } | |
288 | |
289 WindowsCommandLineArguments::~WindowsCommandLineArguments() { | |
290 // need to free each string in the array, and then the array. | |
291 for(int i = 0; i < argc_; i++) { | |
292 delete[] argv_[i]; | |
293 } | |
294 | |
295 delete[] argv_; | |
296 } | |
297 #endif // WEBRTC_WIN | |
298 | |
299 } // namespace rtc | |
OLD | NEW |