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