Home | History | Annotate | Download | only in src
      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-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 SmartPointer<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 == '-') {
    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(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   char* copy0 = NewArray<char>(len + 1);
    474   memcpy(copy0, str, len);
    475   copy0[len] = '\0';
    476 
    477   // strip leading white space
    478   char* copy = SkipWhiteSpace(copy0);
    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   char** argv = NewArray<char*>(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, false);
    501 
    502   // cleanup
    503   DeleteArray(argv);
    504   DeleteArray(copy0);
    505 
    506   return result;
    507 }
    508 
    509 
    510 // static
    511 void FlagList::ResetAllFlags() {
    512   for (size_t i = 0; i < num_flags; ++i) {
    513     flags[i].Reset();
    514   }
    515 }
    516 
    517 
    518 // static
    519 void FlagList::PrintHelp() {
    520   printf("Usage:\n");
    521   printf("  shell [options] -e string\n");
    522   printf("    execute string in V8\n");
    523   printf("  shell [options] file1 file2 ... filek\n");
    524   printf("    run JavaScript scripts in file1, file2, ..., filek\n");
    525   printf("  shell [options]\n");
    526   printf("  shell [options] --shell [file1 file2 ... filek]\n");
    527   printf("    run an interactive JavaScript shell\n");
    528   printf("  d8 [options] file1 file2 ... filek\n");
    529   printf("  d8 [options]\n");
    530   printf("  d8 [options] --shell [file1 file2 ... filek]\n");
    531   printf("    run the new debugging shell\n\n");
    532   printf("Options:\n");
    533   for (size_t i = 0; i < num_flags; ++i) {
    534     Flag* f = &flags[i];
    535     SmartPointer<const char> value = ToString(f);
    536     printf("  --%s (%s)\n        type: %s  default: %s\n",
    537            f->name(), f->comment(), Type2String(f->type()), *value);
    538   }
    539 }
    540 
    541 JSArguments::JSArguments()
    542     : argc_(0), argv_(NULL) {}
    543 JSArguments::JSArguments(int argc, const char** argv)
    544     : argc_(argc), argv_(argv) {}
    545 int JSArguments::argc() const { return argc_; }
    546 const char** JSArguments::argv() { return argv_; }
    547 const char*& JSArguments::operator[](int idx) { return argv_[idx]; }
    548 JSArguments& JSArguments::operator=(JSArguments args) {
    549     argc_ = args.argc_;
    550     argv_ = args.argv_;
    551     return *this;
    552 }
    553 
    554 
    555 } }  // namespace v8::internal
    556