From 2889b1ea86b637e68b081c241e85180eac6da5a7 Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Mon, 10 Nov 2008 14:27:08 +0000 Subject: [PATCH] Flag passes rest of command line to the shell/scripts being run. Arguments on the command line are made available as a global "arguments" array. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@724 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/d8.cc | 13 ++++++++ src/flag-definitions.h | 19 +++++++++++ src/flags.cc | 82 ++++++++++++++++++++++++++++++++++++++++++++--- src/flags.h | 4 ++- test/cctest/test-flags.cc | 64 ++++++++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+), 6 deletions(-) diff --git a/src/d8.cc b/src/d8.cc index 67e8c8e..480d4ae 100644 --- a/src/d8.cc +++ b/src/d8.cc @@ -235,6 +235,19 @@ void Shell::Initialize() { utility_context_->SetSecurityToken(Undefined()); Context::Scope utility_scope(utility_context_); + i::JSArguments js_args = i::FLAG_js_arguments; + i::Handle arguments_array = + i::Factory::NewFixedArray(js_args.argc()); + for (int j = 0; j < js_args.argc(); j++) { + i::Handle arg = + i::Factory::NewStringFromUtf8(i::CStrVector(js_args[j])); + arguments_array->set(j, *arg); + } + i::Handle arguments_jsarray = + i::Factory::NewJSArrayWithElements(arguments_array); + global_template->Set(String::New("arguments"), + Utils::ToLocal(arguments_jsarray)); + // Install the debugger object in the utility scope i::Debug::Load(); i::Debug::debug_context()->set_security_token(i::Heap::undefined_value()); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 6e2462b..5c96429 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -69,10 +69,27 @@ #error No mode supplied when including flags.defs #endif +#ifdef FLAG_MODE_DECLARE +// Structure used to hold a collection of arguments to the JavaScript code. +struct JSArguments { +public: + JSArguments(); + JSArguments(int argc, const char** argv); + int argc() const; + const char** argv(); + const char*& operator[](int idx); + JSArguments& operator=(JSArguments args); +private: + int argc_; + const char** argv_; +}; +#endif + #define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt) #define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt) #define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt) #define DEFINE_string(nam, def, cmt) FLAG(STRING, const char*, nam, def, cmt) +#define DEFINE_args(nam, def, cmt) FLAG(ARGS, JSArguments, nam, def, cmt) // // Flags in all modes. @@ -202,6 +219,8 @@ DEFINE_string(testing_serialization_file, "/tmp/serdes", DEFINE_bool(help, false, "Print usage message, including flags, on console") DEFINE_bool(dump_counters, false, "Dump counters on exit") +DEFINE_args(js_arguments, JSArguments(), + "Pass all remaining arguments to the script. Alias for \"--\".") // // Debug only flags diff --git a/src/flags.cc b/src/flags.cc index 4daea39..db1e892 100644 --- a/src/flags.cc +++ b/src/flags.cc @@ -48,7 +48,7 @@ namespace { // to the actual flag, default value, comment, etc. This is designed to be POD // initialized as to avoid requiring static constructors. struct Flag { - enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING }; + enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS }; FlagType type_; // What type of flag, bool, int, or string. const char* name_; // Name of the flag, ex "my_flag". @@ -82,6 +82,11 @@ struct Flag { return reinterpret_cast(valptr_); } + JSArguments* args_variable() const { + ASSERT(type_ == TYPE_ARGS); + return reinterpret_cast(valptr_); + } + bool bool_default() const { ASSERT(type_ == TYPE_BOOL); return *reinterpret_cast(defptr_); @@ -102,6 +107,11 @@ struct Flag { return *reinterpret_cast(defptr_); } + JSArguments args_default() const { + ASSERT(type_ == TYPE_ARGS); + return *reinterpret_cast(defptr_); + } + // Compare this flag's current value against the default. bool IsDefault() const { switch (type_) { @@ -111,12 +121,15 @@ struct Flag { return *int_variable() == int_default(); case TYPE_FLOAT: return *float_variable() == float_default(); - case TYPE_STRING: + case TYPE_STRING: { const char* str1 = *string_variable(); const char* str2 = string_default(); if (str2 == NULL) return str1 == NULL; if (str1 == NULL) return str2 == NULL; return strcmp(str1, str2) == 0; + } + case TYPE_ARGS: + return args_variable()->argc() == 0; } UNREACHABLE(); return true; @@ -137,6 +150,9 @@ struct Flag { case TYPE_STRING: *string_variable() = string_default(); break; + case TYPE_ARGS: + *args_variable() = args_default(); + break; } } }; @@ -157,6 +173,7 @@ static const char* Type2String(Flag::FlagType type) { case Flag::TYPE_INT: return "int"; case Flag::TYPE_FLOAT: return "float"; case Flag::TYPE_STRING: return "string"; + case Flag::TYPE_ARGS: return "arguments"; } UNREACHABLE(); return NULL; @@ -178,7 +195,7 @@ static char* ToString(Flag* flag) { value = Vector::New(20); OS::SNPrintF(value, "%f", *flag->float_variable()); break; - case Flag::TYPE_STRING: + case Flag::TYPE_STRING: { const char* str = *flag->string_variable(); if (str) { int length = strlen(str) + 1; @@ -189,6 +206,26 @@ static char* ToString(Flag* flag) { OS::SNPrintF(value, "NULL"); } break; + } + case Flag::TYPE_ARGS: { + JSArguments args = *flag->args_variable(); + if (args.argc() == 0) { + value = Vector::New(0); + break; + } + int len = args.argc() - 1; + for (int i = 0; i < args.argc(); i++) { + len += strlen(args[i]); + } + value = Vector::New(len); + for (int i = 0; i < args.argc(); i++) { + if (i > 0) { + OS::SNPrintF(value, " "); + } + OS::SNPrintF(value, "%s", args[i]); + } + break; + } } ASSERT(!value.is_empty()); return value.start(); @@ -239,8 +276,14 @@ static void SplitArgument(const char* arg, if (*arg == '-') { // find the begin of the flag name arg++; // remove 1st '-' - if (*arg == '-') + if (*arg == '-') { arg++; // remove 2nd '-' + if (arg[0] == '\0') { + const char* kJSArgumentsFlagName = "js_arguments"; + *name = kJSArgumentsFlagName; + return; + } + } if (arg[0] == 'n' && arg[1] == 'o') { arg += 2; // remove "no" *is_bool = true; @@ -324,7 +367,9 @@ int FlagList::SetFlagsFromCommandLine(int* argc, } // if we still need a flag value, use the next argument if available - if (flag->type() != Flag::TYPE_BOOL && value == NULL) { + if (flag->type() != Flag::TYPE_BOOL && + flag->type() != Flag::TYPE_ARGS && + value == NULL) { if (i < *argc) { value = argv[i++]; } else { @@ -350,6 +395,19 @@ int FlagList::SetFlagsFromCommandLine(int* argc, case Flag::TYPE_STRING: *flag->string_variable() = value; break; + case Flag::TYPE_ARGS: + int start_pos = (value == NULL) ? i : i - 1; + int js_argc = *argc - start_pos; + const char** js_argv = new const char*[js_argc]; + if (value != NULL) { + js_argv[0] = value; + } + for (int k = i; k < *argc; k++) { + js_argv[k - start_pos] = argv[k]; + } + *flag->args_variable() = JSArguments(js_argc, js_argv); + i = *argc; // Consume all arguments + break; } // handle errors @@ -474,4 +532,18 @@ void FlagList::PrintHelp() { } } +JSArguments::JSArguments() + : argc_(0), argv_(NULL) {} +JSArguments::JSArguments(int argc, const char** argv) + : argc_(argc), argv_(argv) {} +int JSArguments::argc() const { return argc_; } +const char** JSArguments::argv() { return argv_; } +const char*& JSArguments::operator[](int idx) { return argv_[idx]; } +JSArguments& JSArguments::operator=(JSArguments args) { + argc_ = args.argc_; + argv_ = args.argv_; + return *this; +} + + } } // namespace v8::internal diff --git a/src/flags.h b/src/flags.h index 813ea95..78ea80e 100644 --- a/src/flags.h +++ b/src/flags.h @@ -35,6 +35,7 @@ namespace v8 { namespace internal { #define FLAG_MODE_DECLARE #include "flag-definitions.h" + // The global list of all flags. class FlagList { public: @@ -50,7 +51,7 @@ class FlagList { // set, the flags and associated values are removed from (argc, // argv). Returns 0 if no error occurred. Otherwise, returns the argv // index > 0 for the argument where an error occurred. In that case, - // (argc, argv) will remain unchanged indepdendent of the remove_flags + // (argc, argv) will remain unchanged independent of the remove_flags // value, and no assumptions about flag settings should be made. // // The following syntax for flags is accepted (both '-' and '--' are ok): @@ -59,6 +60,7 @@ class FlagList { // --noflag (bool flags only) // --flag=value (non-bool flags only, no spaces around '=') // --flag value (non-bool flags only) + // -- (equivalent to --js_arguments, captures all remaining args) static int SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags); // Set the flag values by parsing the string str. Splits string into argc diff --git a/test/cctest/test-flags.cc b/test/cctest/test-flags.cc index a3aa4b2..9019a89 100644 --- a/test/cctest/test-flags.cc +++ b/test/cctest/test-flags.cc @@ -168,3 +168,67 @@ TEST(Flags6b) { const char* str = " --testing-int-flag 0 --testing_float_flag "; CHECK_EQ(3, FlagList::SetFlagsFromString(str, strlen(str))); } + + +TEST(FlagsJSArguments1) { + SetFlagsToDefault(); + int argc = 6; + const char* argv[] = {"TestJSArgs1", + "--testing-int-flag", "42", + "--", "testing-float-flag", "7"}; + CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc, + const_cast(argv), + true)); + CHECK_EQ(42, FLAG_testing_int_flag); + CHECK_EQ(2.5, FLAG_testing_float_flag); + CHECK_EQ(2, FLAG_js_arguments.argc()); + CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag")); + CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7")); + CHECK_EQ(1, argc); +} + + +TEST(FlagsJSArguments1b) { + SetFlagsToDefault(); + const char* str = "--testing-int-flag 42 -- testing-float-flag 7"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + CHECK_EQ(42, FLAG_testing_int_flag); + CHECK_EQ(2.5, FLAG_testing_float_flag); + CHECK_EQ(2, FLAG_js_arguments.argc()); + CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag")); + CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7")); +} + + +TEST(FlagsJSArguments2) { + SetFlagsToDefault(); + const char* str = "--testing-int-flag 42 --js-arguments testing-float-flag 7"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + CHECK_EQ(42, FLAG_testing_int_flag); + CHECK_EQ(2.5, FLAG_testing_float_flag); + CHECK_EQ(2, FLAG_js_arguments.argc()); + CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag")); + CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7")); +} + + +TEST(FlagsJSArguments3) { + SetFlagsToDefault(); + const char* str = "--testing-int-flag 42 --js-arguments=testing-float-flag 7"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + CHECK_EQ(42, FLAG_testing_int_flag); + CHECK_EQ(2.5, FLAG_testing_float_flag); + CHECK_EQ(2, FLAG_js_arguments.argc()); + CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag")); + CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7")); +} + + +TEST(FlagsJSArguments4) { + SetFlagsToDefault(); + const char* str = "--testing-int-flag 42 --"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + CHECK_EQ(42, FLAG_testing_int_flag); + CHECK_EQ(0, FLAG_js_arguments.argc()); +} + -- 2.7.4