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 FATAL() << "unreachable code"; 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 FATAL() << "unreachable code"; 71 } 72 73 74 static void PrintFlagValue(Flag::Type type, FlagValue* p) { 75 switch (type) { 76 case Flag::BOOL: 77 printf("%s", (p->b ? "true" : "false")); 78 return; 79 case Flag::INT: 80 printf("%d", p->i); 81 return; 82 case Flag::FLOAT: 83 printf("%f", p->f); 84 return; 85 case Flag::STRING: 86 printf("%s", p->s); 87 return; 88 } 89 FATAL() << "unreachable code"; 90 } 91 92 93 void Flag::Print(bool print_current_value) { 94 printf(" --%s (%s) type: %s default: ", name_, comment_, 95 Type2String(type_)); 96 PrintFlagValue(type_, &default_); 97 if (print_current_value) { 98 printf(" current value: "); 99 PrintFlagValue(type_, variable_); 100 } 101 printf("\n"); 102 } 103 104 105 // ----------------------------------------------------------------------------- 106 // Implementation of FlagList 107 108 Flag* FlagList::list_ = NULL; 109 110 111 FlagList::FlagList() { 112 list_ = NULL; 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 = NULL; 119 for (Flag* f = list_; f != NULL; f = f->next()) { 120 if (file == NULL || 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 != NULL && 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 = NULL; 144 *value = NULL; 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 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 != NULL) { 192 // lookup the flag 193 Flag* flag = Lookup(name); 194 if (flag == NULL) { 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 == NULL) { 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 != NULL) || 230 (flag->type() != Flag::BOOL && is_bool) || 231 *endp != '\0') { 232 fprintf(stderr, "Error: illegal value for flag %s of type %s\n", 233 arg, Type2String(flag->type())); 234 return j; 235 } 236 237 // remove the flag & value from the command 238 if (remove_flags) 239 while (j < i) 240 argv[j++] = NULL; 241 } 242 } 243 244 // shrink the argument list 245 if (remove_flags) { 246 int j = 1; 247 for (int i = 1; i < *argc; i++) { 248 if (argv[i] != NULL) 249 argv[j++] = argv[i]; 250 } 251 *argc = j; 252 } 253 254 // parsed all flags successfully 255 return 0; 256 } 257 258 void FlagList::Register(Flag* flag) { 259 assert(flag != NULL && strlen(flag->name()) > 0); 260 CHECK(!Lookup(flag->name())) << "flag " << flag->name() << " declared twice"; 261 flag->next_ = list_; 262 list_ = flag; 263 } 264 265 #if defined(WEBRTC_WIN) 266 WindowsCommandLineArguments::WindowsCommandLineArguments() { 267 // start by getting the command line. 268 LPTSTR command_line = ::GetCommandLine(); 269 // now, convert it to a list of wide char strings. 270 LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_); 271 // now allocate an array big enough to hold that many string pointers. 272 argv_ = new char*[argc_]; 273 274 // iterate over the returned wide strings; 275 for(int i = 0; i < argc_; ++i) { 276 std::string s = rtc::ToUtf8(wide_argv[i], wcslen(wide_argv[i])); 277 char *buffer = new char[s.length() + 1]; 278 rtc::strcpyn(buffer, s.length() + 1, s.c_str()); 279 280 // make sure the argv array has the right string at this point. 281 argv_[i] = buffer; 282 } 283 LocalFree(wide_argv); 284 } 285 286 WindowsCommandLineArguments::~WindowsCommandLineArguments() { 287 // need to free each string in the array, and then the array. 288 for(int i = 0; i < argc_; i++) { 289 delete[] argv_[i]; 290 } 291 292 delete[] argv_; 293 } 294 #endif // WEBRTC_WIN 295 296 } // namespace rtc 297