| 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 |