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 <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 16 #if defined(WEBRTC_WIN) 17 #include "webrtc/base/win32.h" 18 #include <shellapi.h> 19 #endif 20 21 #include "webrtc/base/flags.h" 22 23 namespace rtc { 24 // ----------------------------------------------------------------------------- 25 // Implementation of Flag 26 27 Flag::Flag(const char* file, const char* name, const char* comment, 28 Type type, void* variable, FlagValue default__) 29 : file_(file), 30 name_(name), 31 comment_(comment), 32 type_(type), 33 variable_(reinterpret_cast<FlagValue*>(variable)), 34 default_(default__) { 35 FlagList::Register(this); 36 } 37 38 39 void Flag::SetToDefault() { 40 // Note that we cannot simply do '*variable_ = default_;' since 41 // flag variables are not really of type FlagValue and thus may 42 // be smaller! The FlagValue union is simply 'overlayed' on top 43 // of a flag variable for convenient access. Since union members 44 // are guarantee to be aligned at the beginning, this works. 45 switch (type_) { 46 case Flag::BOOL: 47 variable_->b = default_.b; 48 return; 49 case Flag::INT: 50 variable_->i = default_.i; 51 return; 52 case Flag::FLOAT: 53 variable_->f = default_.f; 54 return; 55 case Flag::STRING: 56 variable_->s = default_.s; 57 return; 58 } 59 UNREACHABLE(); 60 } 61 62 63 static const char* Type2String(Flag::Type type) { 64 switch (type) { 65 case Flag::BOOL: return "bool"; 66 case Flag::INT: return "int"; 67 case Flag::FLOAT: return "float"; 68 case Flag::STRING: return "string"; 69 } 70 UNREACHABLE(); 71 return NULL; 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 UNREACHABLE(); 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_ = NULL; 110 111 112 FlagList::FlagList() { 113 list_ = NULL; 114 } 115 116 void FlagList::Print(const char* file, bool print_current_value) { 117 // Since flag registration is likely by file (= C++ file), 118 // we don't need to sort by file and still get grouped output. 119 const char* current = NULL; 120 for (Flag* f = list_; f != NULL; f = f->next()) { 121 if (file == NULL || file == f->file()) { 122 if (current != f->file()) { 123 printf("Flags from %s:\n", f->file()); 124 current = f->file(); 125 } 126 f->Print(print_current_value); 127 } 128 } 129 } 130 131 132 Flag* FlagList::Lookup(const char* name) { 133 Flag* f = list_; 134 while (f != NULL && strcmp(name, f->name()) != 0) 135 f = f->next(); 136 return f; 137 } 138 139 140 void FlagList::SplitArgument(const char* arg, 141 char* buffer, int buffer_size, 142 const char** name, const char** value, 143 bool* is_bool) { 144 *name = NULL; 145 *value = NULL; 146 *is_bool = false; 147 148 if (*arg == '-') { 149 // find the begin of the flag name 150 arg++; // remove 1st '-' 151 if (*arg == '-') 152 arg++; // remove 2nd '-' 153 if (arg[0] == 'n' && arg[1] == 'o') { 154 arg += 2; // remove "no" 155 *is_bool = true; 156 } 157 *name = arg; 158 159 // find the end of the flag name 160 while (*arg != '\0' && *arg != '=') 161 arg++; 162 163 // get the value if any 164 if (*arg == '=') { 165 // make a copy so we can NUL-terminate flag name 166 int n = static_cast<int>(arg - *name); 167 if (n >= buffer_size) 168 Fatal(__FILE__, __LINE__, "CHECK(%s) failed", "n < buffer_size"); 169 memcpy(buffer, *name, n * sizeof(char)); 170 buffer[n] = '\0'; 171 *name = buffer; 172 // get the value 173 *value = arg + 1; 174 } 175 } 176 } 177 178 179 int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv, 180 bool remove_flags) { 181 // parse arguments 182 for (int i = 1; i < *argc; /* see below */) { 183 int j = i; // j > 0 184 const char* arg = argv[i++]; 185 186 // split arg into flag components 187 char buffer[1024]; 188 const char* name; 189 const char* value; 190 bool is_bool; 191 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool); 192 193 if (name != NULL) { 194 // lookup the flag 195 Flag* flag = Lookup(name); 196 if (flag == NULL) { 197 fprintf(stderr, "Error: unrecognized flag %s\n", arg); 198 return j; 199 } 200 201 // if we still need a flag value, use the next argument if available 202 if (flag->type() != Flag::BOOL && value == NULL) { 203 if (i < *argc) { 204 value = argv[i++]; 205 } else { 206 fprintf(stderr, "Error: missing value for flag %s of type %s\n", 207 arg, Type2String(flag->type())); 208 return j; 209 } 210 } 211 212 // set the flag 213 char empty[] = { '\0' }; 214 char* endp = empty; 215 switch (flag->type()) { 216 case Flag::BOOL: 217 *flag->bool_variable() = !is_bool; 218 break; 219 case Flag::INT: 220 *flag->int_variable() = strtol(value, &endp, 10); 221 break; 222 case Flag::FLOAT: 223 *flag->float_variable() = strtod(value, &endp); 224 break; 225 case Flag::STRING: 226 *flag->string_variable() = value; 227 break; 228 } 229 230 // handle errors 231 if ((flag->type() == Flag::BOOL && value != NULL) || 232 (flag->type() != Flag::BOOL && is_bool) || 233 *endp != '\0') { 234 fprintf(stderr, "Error: illegal value for flag %s of type %s\n", 235 arg, Type2String(flag->type())); 236 return j; 237 } 238 239 // remove the flag & value from the command 240 if (remove_flags) 241 while (j < i) 242 argv[j++] = NULL; 243 } 244 } 245 246 // shrink the argument list 247 if (remove_flags) { 248 int j = 1; 249 for (int i = 1; i < *argc; i++) { 250 if (argv[i] != NULL) 251 argv[j++] = argv[i]; 252 } 253 *argc = j; 254 } 255 256 // parsed all flags successfully 257 return 0; 258 } 259 260 void FlagList::Register(Flag* flag) { 261 assert(flag != NULL && strlen(flag->name()) > 0); 262 if (Lookup(flag->name()) != NULL) 263 Fatal(flag->file(), 0, "flag %s declared twice", flag->name()); 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 300