• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
typev8::internal::__anone8648bea0111::Flag64   FlagType type() const { return type_; }
65 
namev8::internal::__anone8648bea0111::Flag66   const char* name() const { return name_; }
67 
commentv8::internal::__anone8648bea0111::Flag68   const char* comment() const { return cmt_; }
69 
bool_variablev8::internal::__anone8648bea0111::Flag70   bool* bool_variable() const {
71     ASSERT(type_ == TYPE_BOOL);
72     return reinterpret_cast<bool*>(valptr_);
73   }
74 
int_variablev8::internal::__anone8648bea0111::Flag75   int* int_variable() const {
76     ASSERT(type_ == TYPE_INT);
77     return reinterpret_cast<int*>(valptr_);
78   }
79 
float_variablev8::internal::__anone8648bea0111::Flag80   double* float_variable() const {
81     ASSERT(type_ == TYPE_FLOAT);
82     return reinterpret_cast<double*>(valptr_);
83   }
84 
string_valuev8::internal::__anone8648bea0111::Flag85   const char* string_value() const {
86     ASSERT(type_ == TYPE_STRING);
87     return *reinterpret_cast<const char**>(valptr_);
88   }
89 
set_string_valuev8::internal::__anone8648bea0111::Flag90   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 
args_variablev8::internal::__anone8648bea0111::Flag98   JSArguments* args_variable() const {
99     ASSERT(type_ == TYPE_ARGS);
100     return reinterpret_cast<JSArguments*>(valptr_);
101   }
102 
bool_defaultv8::internal::__anone8648bea0111::Flag103   bool bool_default() const {
104     ASSERT(type_ == TYPE_BOOL);
105     return *reinterpret_cast<const bool*>(defptr_);
106   }
107 
int_defaultv8::internal::__anone8648bea0111::Flag108   int int_default() const {
109     ASSERT(type_ == TYPE_INT);
110     return *reinterpret_cast<const int*>(defptr_);
111   }
112 
float_defaultv8::internal::__anone8648bea0111::Flag113   double float_default() const {
114     ASSERT(type_ == TYPE_FLOAT);
115     return *reinterpret_cast<const double*>(defptr_);
116   }
117 
string_defaultv8::internal::__anone8648bea0111::Flag118   const char* string_default() const {
119     ASSERT(type_ == TYPE_STRING);
120     return *reinterpret_cast<const char* const *>(defptr_);
121   }
122 
args_defaultv8::internal::__anone8648bea0111::Flag123   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.
IsDefaultv8::internal::__anone8648bea0111::Flag129   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.
Resetv8::internal::__anone8648bea0111::Flag152   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 
Type2String(Flag::FlagType type)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 
ToString(Flag * flag)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
argv()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.
SplitArgument(const char * arg,char * buffer,int buffer_size,const char ** name,const char ** value,bool * is_bool)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 
NormalizeChar(char ch)318 inline char NormalizeChar(char ch) {
319   return ch == '_' ? '-' : ch;
320 }
321 
322 
EqualNames(const char * a,const char * b)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 
FindFlag(const char * name)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
SetFlagsFromCommandLine(int * argc,char ** argv,bool remove_flags)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 
SkipWhiteSpace(char * p)458 static char* SkipWhiteSpace(char* p) {
459   while (*p != '\0' && isspace(*p) != 0) p++;
460   return p;
461 }
462 
463 
SkipBlackSpace(char * p)464 static char* SkipBlackSpace(char* p) {
465   while (*p != '\0' && isspace(*p) == 0) p++;
466   return p;
467 }
468 
469 
470 // static
SetFlagsFromString(const char * str,int len)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
ResetAllFlags()507 void FlagList::ResetAllFlags() {
508   for (size_t i = 0; i < num_flags; ++i) {
509     flags[i].Reset();
510   }
511 }
512 
513 
514 // static
PrintHelp()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 
EnforceFlagImplications()538 void FlagList::EnforceFlagImplications() {
539 #define FLAG_MODE_DEFINE_IMPLICATIONS
540 #include "flag-definitions.h"
541 }
542 
543 } }  // namespace v8::internal
544