1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <ctype.h> 29 #include <stdlib.h> 30 31 #include "v8.h" 32 33 #include "platform.h" 34 #include "smart-pointers.h" 35 #include "string-stream.h" 36 37 #if V8_TARGET_ARCH_ARM 38 #include "arm/assembler-arm-inl.h" 39 #endif 40 41 namespace v8 { 42 namespace internal { 43 44 // Define all of our flags. 45 #define FLAG_MODE_DEFINE 46 #include "flag-definitions.h" 47 48 // Define all of our flags default values. 49 #define FLAG_MODE_DEFINE_DEFAULTS 50 #include "flag-definitions.h" 51 52 namespace { 53 54 // This structure represents a single entry in the flag system, with a pointer 55 // to the actual flag, default value, comment, etc. This is designed to be POD 56 // initialized as to avoid requiring static constructors. 57 struct Flag { 58 enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS }; 59 60 FlagType type_; // What type of flag, bool, int, or string. 61 const char* name_; // Name of the flag, ex "my_flag". 62 void* valptr_; // Pointer to the global flag variable. 63 const void* defptr_; // Pointer to the default value. 64 const char* cmt_; // A comment about the flags purpose. 65 bool owns_ptr_; // Does the flag own its string value? 66 67 FlagType type() const { return type_; } 68 69 const char* name() const { return name_; } 70 71 const char* comment() const { return cmt_; } 72 73 bool* bool_variable() const { 74 ASSERT(type_ == TYPE_BOOL); 75 return reinterpret_cast<bool*>(valptr_); 76 } 77 78 int* int_variable() const { 79 ASSERT(type_ == TYPE_INT); 80 return reinterpret_cast<int*>(valptr_); 81 } 82 83 double* float_variable() const { 84 ASSERT(type_ == TYPE_FLOAT); 85 return reinterpret_cast<double*>(valptr_); 86 } 87 88 const char* string_value() const { 89 ASSERT(type_ == TYPE_STRING); 90 return *reinterpret_cast<const char**>(valptr_); 91 } 92 93 void set_string_value(const char* value, bool owns_ptr) { 94 ASSERT(type_ == TYPE_STRING); 95 const char** ptr = reinterpret_cast<const char**>(valptr_); 96 if (owns_ptr_ && *ptr != NULL) DeleteArray(*ptr); 97 *ptr = value; 98 owns_ptr_ = owns_ptr; 99 } 100 101 JSArguments* args_variable() const { 102 ASSERT(type_ == TYPE_ARGS); 103 return reinterpret_cast<JSArguments*>(valptr_); 104 } 105 106 bool bool_default() const { 107 ASSERT(type_ == TYPE_BOOL); 108 return *reinterpret_cast<const bool*>(defptr_); 109 } 110 111 int int_default() const { 112 ASSERT(type_ == TYPE_INT); 113 return *reinterpret_cast<const int*>(defptr_); 114 } 115 116 double float_default() const { 117 ASSERT(type_ == TYPE_FLOAT); 118 return *reinterpret_cast<const double*>(defptr_); 119 } 120 121 const char* string_default() const { 122 ASSERT(type_ == TYPE_STRING); 123 return *reinterpret_cast<const char* const *>(defptr_); 124 } 125 126 JSArguments args_default() const { 127 ASSERT(type_ == TYPE_ARGS); 128 return *reinterpret_cast<const JSArguments*>(defptr_); 129 } 130 131 // Compare this flag's current value against the default. 132 bool IsDefault() const { 133 switch (type_) { 134 case TYPE_BOOL: 135 return *bool_variable() == bool_default(); 136 case TYPE_INT: 137 return *int_variable() == int_default(); 138 case TYPE_FLOAT: 139 return *float_variable() == float_default(); 140 case TYPE_STRING: { 141 const char* str1 = string_value(); 142 const char* str2 = string_default(); 143 if (str2 == NULL) return str1 == NULL; 144 if (str1 == NULL) return str2 == NULL; 145 return strcmp(str1, str2) == 0; 146 } 147 case TYPE_ARGS: 148 return args_variable()->argc() == 0; 149 } 150 UNREACHABLE(); 151 return true; 152 } 153 154 // Set a flag back to it's default value. 155 void Reset() { 156 switch (type_) { 157 case TYPE_BOOL: 158 *bool_variable() = bool_default(); 159 break; 160 case TYPE_INT: 161 *int_variable() = int_default(); 162 break; 163 case TYPE_FLOAT: 164 *float_variable() = float_default(); 165 break; 166 case TYPE_STRING: 167 set_string_value(string_default(), false); 168 break; 169 case TYPE_ARGS: 170 *args_variable() = args_default(); 171 break; 172 } 173 } 174 }; 175 176 Flag flags[] = { 177 #define FLAG_MODE_META 178 #include "flag-definitions.h" 179 }; 180 181 const size_t num_flags = sizeof(flags) / sizeof(*flags); 182 183 } // namespace 184 185 186 static const char* Type2String(Flag::FlagType type) { 187 switch (type) { 188 case Flag::TYPE_BOOL: return "bool"; 189 case Flag::TYPE_INT: return "int"; 190 case Flag::TYPE_FLOAT: return "float"; 191 case Flag::TYPE_STRING: return "string"; 192 case Flag::TYPE_ARGS: return "arguments"; 193 } 194 UNREACHABLE(); 195 return NULL; 196 } 197 198 199 static SmartArrayPointer<const char> ToString(Flag* flag) { 200 HeapStringAllocator string_allocator; 201 StringStream buffer(&string_allocator); 202 switch (flag->type()) { 203 case Flag::TYPE_BOOL: 204 buffer.Add("%s", (*flag->bool_variable() ? "true" : "false")); 205 break; 206 case Flag::TYPE_INT: 207 buffer.Add("%d", *flag->int_variable()); 208 break; 209 case Flag::TYPE_FLOAT: 210 buffer.Add("%f", FmtElm(*flag->float_variable())); 211 break; 212 case Flag::TYPE_STRING: { 213 const char* str = flag->string_value(); 214 buffer.Add("%s", str ? str : "NULL"); 215 break; 216 } 217 case Flag::TYPE_ARGS: { 218 JSArguments args = *flag->args_variable(); 219 if (args.argc() > 0) { 220 buffer.Add("%s", args[0]); 221 for (int i = 1; i < args.argc(); i++) { 222 buffer.Add(" %s", args[i]); 223 } 224 } 225 break; 226 } 227 } 228 return buffer.ToCString(); 229 } 230 231 232 // static 233 List<const char*>* FlagList::argv() { 234 List<const char*>* args = new List<const char*>(8); 235 Flag* args_flag = NULL; 236 for (size_t i = 0; i < num_flags; ++i) { 237 Flag* f = &flags[i]; 238 if (!f->IsDefault()) { 239 if (f->type() == Flag::TYPE_ARGS) { 240 ASSERT(args_flag == NULL); 241 args_flag = f; // Must be last in arguments. 242 continue; 243 } 244 HeapStringAllocator string_allocator; 245 StringStream buffer(&string_allocator); 246 if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) { 247 buffer.Add("--%s", f->name()); 248 } else { 249 buffer.Add("--no%s", f->name()); 250 } 251 args->Add(buffer.ToCString().Detach()); 252 if (f->type() != Flag::TYPE_BOOL) { 253 args->Add(ToString(f).Detach()); 254 } 255 } 256 } 257 if (args_flag != NULL) { 258 HeapStringAllocator string_allocator; 259 StringStream buffer(&string_allocator); 260 buffer.Add("--%s", args_flag->name()); 261 args->Add(buffer.ToCString().Detach()); 262 JSArguments jsargs = *args_flag->args_variable(); 263 for (int j = 0; j < jsargs.argc(); j++) { 264 args->Add(StrDup(jsargs[j])); 265 } 266 } 267 return args; 268 } 269 270 271 // Helper function to parse flags: Takes an argument arg and splits it into 272 // a flag name and flag value (or NULL if they are missing). is_bool is set 273 // if the arg started with "-no" or "--no". The buffer may be used to NUL- 274 // terminate the name, it must be large enough to hold any possible name. 275 static void SplitArgument(const char* arg, 276 char* buffer, 277 int buffer_size, 278 const char** name, 279 const char** value, 280 bool* is_bool) { 281 *name = NULL; 282 *value = NULL; 283 *is_bool = false; 284 285 if (arg != NULL && *arg == '-') { 286 // find the begin of the flag name 287 arg++; // remove 1st '-' 288 if (*arg == '-') { 289 arg++; // remove 2nd '-' 290 if (arg[0] == '\0') { 291 const char* kJSArgumentsFlagName = "js_arguments"; 292 *name = kJSArgumentsFlagName; 293 return; 294 } 295 } 296 if (arg[0] == 'n' && arg[1] == 'o') { 297 arg += 2; // remove "no" 298 *is_bool = true; 299 } 300 *name = arg; 301 302 // find the end of the flag name 303 while (*arg != '\0' && *arg != '=') 304 arg++; 305 306 // get the value if any 307 if (*arg == '=') { 308 // make a copy so we can NUL-terminate flag name 309 size_t n = arg - *name; 310 CHECK(n < static_cast<size_t>(buffer_size)); // buffer is too small 311 OS::MemCopy(buffer, *name, n); 312 buffer[n] = '\0'; 313 *name = buffer; 314 // get the value 315 *value = arg + 1; 316 } 317 } 318 } 319 320 321 inline char NormalizeChar(char ch) { 322 return ch == '_' ? '-' : ch; 323 } 324 325 326 static bool EqualNames(const char* a, const char* b) { 327 for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) { 328 if (a[i] == '\0') { 329 return true; 330 } 331 } 332 return false; 333 } 334 335 336 static Flag* FindFlag(const char* name) { 337 for (size_t i = 0; i < num_flags; ++i) { 338 if (EqualNames(name, flags[i].name())) 339 return &flags[i]; 340 } 341 return NULL; 342 } 343 344 345 // static 346 int FlagList::SetFlagsFromCommandLine(int* argc, 347 char** argv, 348 bool remove_flags) { 349 int return_code = 0; 350 // parse arguments 351 for (int i = 1; i < *argc;) { 352 int j = i; // j > 0 353 const char* arg = argv[i++]; 354 355 // split arg into flag components 356 char buffer[1*KB]; 357 const char* name; 358 const char* value; 359 bool is_bool; 360 SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool); 361 362 if (name != NULL) { 363 // lookup the flag 364 Flag* flag = FindFlag(name); 365 if (flag == NULL) { 366 if (remove_flags) { 367 // We don't recognize this flag but since we're removing 368 // the flags we recognize we assume that the remaining flags 369 // will be processed somewhere else so this flag might make 370 // sense there. 371 continue; 372 } else { 373 PrintF(stderr, "Error: unrecognized flag %s\n" 374 "Try --help for options\n", arg); 375 return_code = j; 376 break; 377 } 378 } 379 380 // if we still need a flag value, use the next argument if available 381 if (flag->type() != Flag::TYPE_BOOL && 382 flag->type() != Flag::TYPE_ARGS && 383 value == NULL) { 384 if (i < *argc) { 385 value = argv[i++]; 386 } else { 387 PrintF(stderr, "Error: missing value for flag %s of type %s\n" 388 "Try --help for options\n", 389 arg, Type2String(flag->type())); 390 return_code = j; 391 break; 392 } 393 } 394 395 // set the flag 396 char* endp = const_cast<char*>(""); // *endp is only read 397 switch (flag->type()) { 398 case Flag::TYPE_BOOL: 399 *flag->bool_variable() = !is_bool; 400 break; 401 case Flag::TYPE_INT: 402 *flag->int_variable() = strtol(value, &endp, 10); // NOLINT 403 break; 404 case Flag::TYPE_FLOAT: 405 *flag->float_variable() = strtod(value, &endp); 406 break; 407 case Flag::TYPE_STRING: 408 flag->set_string_value(value ? StrDup(value) : NULL, true); 409 break; 410 case Flag::TYPE_ARGS: { 411 int start_pos = (value == NULL) ? i : i - 1; 412 int js_argc = *argc - start_pos; 413 const char** js_argv = NewArray<const char*>(js_argc); 414 if (value != NULL) { 415 js_argv[0] = StrDup(value); 416 } 417 for (int k = i; k < *argc; k++) { 418 js_argv[k - start_pos] = StrDup(argv[k]); 419 } 420 *flag->args_variable() = JSArguments::Create(js_argc, js_argv); 421 i = *argc; // Consume all arguments 422 break; 423 } 424 } 425 426 // handle errors 427 if ((flag->type() == Flag::TYPE_BOOL && value != NULL) || 428 (flag->type() != Flag::TYPE_BOOL && is_bool) || 429 *endp != '\0') { 430 PrintF(stderr, "Error: illegal value for flag %s of type %s\n" 431 "Try --help for options\n", 432 arg, Type2String(flag->type())); 433 return_code = j; 434 break; 435 } 436 437 // remove the flag & value from the command 438 if (remove_flags) { 439 while (j < i) { 440 argv[j++] = NULL; 441 } 442 } 443 } 444 } 445 446 // shrink the argument list 447 if (remove_flags) { 448 int j = 1; 449 for (int i = 1; i < *argc; i++) { 450 if (argv[i] != NULL) 451 argv[j++] = argv[i]; 452 } 453 *argc = j; 454 } 455 456 if (FLAG_help) { 457 PrintHelp(); 458 exit(0); 459 } 460 // parsed all flags successfully 461 return return_code; 462 } 463 464 465 static char* SkipWhiteSpace(char* p) { 466 while (*p != '\0' && isspace(*p) != 0) p++; 467 return p; 468 } 469 470 471 static char* SkipBlackSpace(char* p) { 472 while (*p != '\0' && isspace(*p) == 0) p++; 473 return p; 474 } 475 476 477 // static 478 int FlagList::SetFlagsFromString(const char* str, int len) { 479 // make a 0-terminated copy of str 480 ScopedVector<char> copy0(len + 1); 481 OS::MemCopy(copy0.start(), str, len); 482 copy0[len] = '\0'; 483 484 // strip leading white space 485 char* copy = SkipWhiteSpace(copy0.start()); 486 487 // count the number of 'arguments' 488 int argc = 1; // be compatible with SetFlagsFromCommandLine() 489 for (char* p = copy; *p != '\0'; argc++) { 490 p = SkipBlackSpace(p); 491 p = SkipWhiteSpace(p); 492 } 493 494 // allocate argument array 495 ScopedVector<char*> argv(argc); 496 497 // split the flags string into arguments 498 argc = 1; // be compatible with SetFlagsFromCommandLine() 499 for (char* p = copy; *p != '\0'; argc++) { 500 argv[argc] = p; 501 p = SkipBlackSpace(p); 502 if (*p != '\0') *p++ = '\0'; // 0-terminate argument 503 p = SkipWhiteSpace(p); 504 } 505 506 // set the flags 507 int result = SetFlagsFromCommandLine(&argc, argv.start(), false); 508 509 return result; 510 } 511 512 513 // static 514 void FlagList::ResetAllFlags() { 515 for (size_t i = 0; i < num_flags; ++i) { 516 flags[i].Reset(); 517 } 518 } 519 520 521 // static 522 void FlagList::PrintHelp() { 523 #if V8_TARGET_ARCH_ARM 524 CpuFeatures::PrintTarget(); 525 CpuFeatures::Probe(); 526 CpuFeatures::PrintFeatures(); 527 #endif // V8_TARGET_ARCH_ARM 528 529 printf("Usage:\n"); 530 printf(" shell [options] -e string\n"); 531 printf(" execute string in V8\n"); 532 printf(" shell [options] file1 file2 ... filek\n"); 533 printf(" run JavaScript scripts in file1, file2, ..., filek\n"); 534 printf(" shell [options]\n"); 535 printf(" shell [options] --shell [file1 file2 ... filek]\n"); 536 printf(" run an interactive JavaScript shell\n"); 537 printf(" d8 [options] file1 file2 ... filek\n"); 538 printf(" d8 [options]\n"); 539 printf(" d8 [options] --shell [file1 file2 ... filek]\n"); 540 printf(" run the new debugging shell\n\n"); 541 printf("Options:\n"); 542 for (size_t i = 0; i < num_flags; ++i) { 543 Flag* f = &flags[i]; 544 SmartArrayPointer<const char> value = ToString(f); 545 printf(" --%s (%s)\n type: %s default: %s\n", 546 f->name(), f->comment(), Type2String(f->type()), *value); 547 } 548 } 549 550 551 void FlagList::EnforceFlagImplications() { 552 #define FLAG_MODE_DEFINE_IMPLICATIONS 553 #include "flag-definitions.h" 554 #undef FLAG_MODE_DEFINE_IMPLICATIONS 555 } 556 557 } } // namespace v8::internal 558