1 /* 2 * libjingle 3 * Copyright 2006, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 33 #ifdef WIN32 34 #include "talk/base/win32.h" 35 #include <shellapi.h> 36 #endif 37 38 #include "talk/base/flags.h" 39 40 41 // ----------------------------------------------------------------------------- 42 // Implementation of Flag 43 44 Flag::Flag(const char* file, const char* name, const char* comment, 45 Type type, void* variable, FlagValue default__) 46 : file_(file), 47 name_(name), 48 comment_(comment), 49 type_(type), 50 variable_(reinterpret_cast<FlagValue*>(variable)), 51 default_(default__) { 52 FlagList::Register(this); 53 } 54 55 56 void Flag::SetToDefault() { 57 // Note that we cannot simply do '*variable_ = default_;' since 58 // flag variables are not really of type FlagValue and thus may 59 // be smaller! The FlagValue union is simply 'overlayed' on top 60 // of a flag variable for convenient access. Since union members 61 // are guarantee to be aligned at the beginning, this works. 62 switch (type_) { 63 case Flag::BOOL: 64 variable_->b = default_.b; 65 return; 66 case Flag::INT: 67 variable_->i = default_.i; 68 return; 69 case Flag::FLOAT: 70 variable_->f = default_.f; 71 return; 72 case Flag::STRING: 73 variable_->s = default_.s; 74 return; 75 } 76 UNREACHABLE(); 77 } 78 79 80 static const char* Type2String(Flag::Type type) { 81 switch (type) { 82 case Flag::BOOL: return "bool"; 83 case Flag::INT: return "int"; 84 case Flag::FLOAT: return "float"; 85 case Flag::STRING: return "string"; 86 } 87 UNREACHABLE(); 88 return NULL; 89 } 90 91 92 static void PrintFlagValue(Flag::Type type, FlagValue* p) { 93 switch (type) { 94 case Flag::BOOL: 95 printf("%s", (p->b ? "true" : "false")); 96 return; 97 case Flag::INT: 98 printf("%d", p->i); 99 return; 100 case Flag::FLOAT: 101 printf("%f", p->f); 102 return; 103 case Flag::STRING: 104 printf("%s", p->s); 105 return; 106 } 107 UNREACHABLE(); 108 } 109 110 111 void Flag::Print(bool print_current_value) { 112 printf(" --%s (%s) type: %s default: ", name_, comment_, 113 Type2String(type_)); 114 PrintFlagValue(type_, &default_); 115 if (print_current_value) { 116 printf(" current value: "); 117 PrintFlagValue(type_, variable_); 118 } 119 printf("\n"); 120 } 121 122 123 // ----------------------------------------------------------------------------- 124 // Implementation of FlagList 125 126 Flag* FlagList::list_ = NULL; 127 128 129 FlagList::FlagList() { 130 list_ = NULL; 131 } 132 133 void FlagList::Print(const char* file, bool print_current_value) { 134 // Since flag registration is likely by file (= C++ file), 135 // we don't need to sort by file and still get grouped output. 136 const char* current = NULL; 137 for (Flag* f = list_; f != NULL; f = f->next()) { 138 if (file == NULL || file == f->file()) { 139 if (current != f->file()) { 140 printf("Flags from %s:\n", f->file()); 141 current = f->file(); 142 } 143 f->Print(print_current_value); 144 } 145 } 146 } 147 148 149 Flag* FlagList::Lookup(const char* name) { 150 Flag* f = list_; 151 while (f != NULL && strcmp(name, f->name()) != 0) 152 f = f->next(); 153 return f; 154 } 155 156 157 void FlagList::SplitArgument(const char* arg, 158 char* buffer, int buffer_size, 159 const char** name, const char** value, 160 bool* is_bool) { 161 *name = NULL; 162 *value = NULL; 163 *is_bool = false; 164 165 if (*arg == '-') { 166 // find the begin of the flag name 167 arg++; // remove 1st '-' 168 if (*arg == '-') 169 arg++; // remove 2nd '-' 170 if (arg[0] == 'n' && arg[1] == 'o') { 171 arg += 2; // remove "no" 172 *is_bool = true; 173 } 174 *name = arg; 175 176 // find the end of the flag name 177 while (*arg != '\0' && *arg != '=') 178 arg++; 179 180 // get the value if any 181 if (*arg == '=') { 182 // make a copy so we can NUL-terminate flag name 183 int n = static_cast<int>(arg - *name); 184 if (n >= buffer_size) 185 Fatal(__FILE__, __LINE__, "CHECK(%s) failed", "n < buffer_size"); 186 memcpy(buffer, *name, n * sizeof(char)); 187 buffer[n] = '\0'; 188 *name = buffer; 189 // get the value 190 *value = arg + 1; 191 } 192 } 193 } 194 195 196 int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv, 197 bool remove_flags) { 198 // parse arguments 199 for (int i = 1; i < *argc; /* see below */) { 200 int j = i; // j > 0 201 const char* arg = argv[i++]; 202 203 // split arg into flag components 204 char buffer[1024]; 205 const char* name; 206 const char* value; 207 bool is_bool; 208 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool); 209 210 if (name != NULL) { 211 // lookup the flag 212 Flag* flag = Lookup(name); 213 if (flag == NULL) { 214 fprintf(stderr, "Error: unrecognized flag %s\n", arg); 215 return j; 216 } 217 218 // if we still need a flag value, use the next argument if available 219 if (flag->type() != Flag::BOOL && value == NULL) { 220 if (i < *argc) { 221 value = argv[i++]; 222 } else { 223 fprintf(stderr, "Error: missing value for flag %s of type %s\n", 224 arg, Type2String(flag->type())); 225 return j; 226 } 227 } 228 229 // set the flag 230 char empty[] = { '\0' }; 231 char* endp = empty; 232 switch (flag->type()) { 233 case Flag::BOOL: 234 *flag->bool_variable() = !is_bool; 235 break; 236 case Flag::INT: 237 *flag->int_variable() = strtol(value, &endp, 10); 238 break; 239 case Flag::FLOAT: 240 *flag->float_variable() = strtod(value, &endp); 241 break; 242 case Flag::STRING: 243 *flag->string_variable() = value; 244 break; 245 } 246 247 // handle errors 248 if ((flag->type() == Flag::BOOL && value != NULL) || 249 (flag->type() != Flag::BOOL && is_bool) || 250 *endp != '\0') { 251 fprintf(stderr, "Error: illegal value for flag %s of type %s\n", 252 arg, Type2String(flag->type())); 253 return j; 254 } 255 256 // remove the flag & value from the command 257 if (remove_flags) 258 while (j < i) 259 argv[j++] = NULL; 260 } 261 } 262 263 // shrink the argument list 264 if (remove_flags) { 265 int j = 1; 266 for (int i = 1; i < *argc; i++) { 267 if (argv[i] != NULL) 268 argv[j++] = argv[i]; 269 } 270 *argc = j; 271 } 272 273 // parsed all flags successfully 274 return 0; 275 } 276 277 void FlagList::Register(Flag* flag) { 278 assert(flag != NULL && strlen(flag->name()) > 0); 279 if (Lookup(flag->name()) != NULL) 280 Fatal(flag->file(), 0, "flag %s declared twice", flag->name()); 281 flag->next_ = list_; 282 list_ = flag; 283 } 284 285 #ifdef WIN32 286 WindowsCommandLineArguments::WindowsCommandLineArguments() { 287 // start by getting the command line. 288 LPTSTR command_line = ::GetCommandLine(); 289 // now, convert it to a list of wide char strings. 290 LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_); 291 // now allocate an array big enough to hold that many string pointers. 292 argv_ = new char*[argc_]; 293 294 // iterate over the returned wide strings; 295 for(int i = 0; i < argc_; ++i) { 296 std::string s = talk_base::ToUtf8(wide_argv[i], wcslen(wide_argv[i])); 297 char *buffer = new char[s.length() + 1]; 298 talk_base::strcpyn(buffer, s.length() + 1, s.c_str()); 299 300 // make sure the argv array has the right string at this point. 301 argv_[i] = buffer; 302 } 303 LocalFree(wide_argv); 304 } 305 306 WindowsCommandLineArguments::~WindowsCommandLineArguments() { 307 // need to free each string in the array, and then the array. 308 for(int i = 0; i < argc_; i++) { 309 delete[] argv_[i]; 310 } 311 312 delete[] argv_; 313 } 314 #endif // WIN32 315 316