Bug 679138: argv past script argument should not be interpreted as options. (r=dvander)
authorChris Leary <cdleary@mozilla.com>
Mon, 29 Aug 2011 12:19:19 -0700
changeset 77503 ee787d92a2e161bd457f11601e630a1bb34b9320
parent 77502 ba38da32b8483d359991524a18cc977ec7d6d76e
child 77504 4a31be812223e5f03439f96f0e9f04166a6ea4c8
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs679138
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 679138: argv past script argument should not be interpreted as options. (r=dvander)
js/src/methodjit/Compiler.cpp
js/src/shell/js.cpp
js/src/shell/jsoptparse.cpp
js/src/shell/jsoptparse.h
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -220,18 +220,18 @@ mjit::Compiler::performCompilation(JITSc
     CHECK_STATUS(generateEpilogue());
     CHECK_STATUS(finishThisUp(jitp));
 
 #ifdef JS_METHODJIT_SPEW
     prof.stop();
     JaegerSpew(JSpew_Prof, "compilation took %d us\n", prof.time_us());
 #endif
 
-    JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%ld\")\n",
-               (*jitp)->code.m_code.executableAddress(), (*jitp)->code.m_size);
+    JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%u\")\n",
+               (*jitp)->code.m_code.executableAddress(), unsigned((*jitp)->code.m_size));
 
     return Compile_Okay;
 }
 
 #undef CHECK_STATUS
 
 mjit::Compiler::~Compiler()
 {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5603,16 +5603,18 @@ main(int argc, char **argv, char **envp)
 #endif
         || !op.addOptionalStringArg("script", "A script to execute (after all options)")
         || !op.addOptionalMultiStringArg("scriptArgs",
                                          "String arguments to bind as |arguments| in the "
                                          "shell's global")) {
         return EXIT_FAILURE;
     }
 
+    op.setArgTerminatesOptions("script", true);
+
     switch (op.parseArgs(argc, argv)) {
       case OptionParser::ParseHelp:
         return EXIT_SUCCESS;
       case OptionParser::ParseError:
         op.printHelp(argv[0]);
         return EXIT_FAILURE;
       case OptionParser::Fail:
         return EXIT_FAILURE;
--- a/js/src/shell/jsoptparse.cpp
+++ b/js/src/shell/jsoptparse.cpp
@@ -79,16 +79,22 @@ Option::asValued() const
     return const_cast<Option *>(this)->asValued();
 }
 
 OPTION_CONVERT_IMPL(Bool)
 OPTION_CONVERT_IMPL(String)
 OPTION_CONVERT_IMPL(Int)
 OPTION_CONVERT_IMPL(MultiString)
 
+void
+OptionParser::setArgTerminatesOptions(const char *name, bool enabled)
+{
+    findArgument(name)->setTerminatesOptions(enabled);
+}
+
 OptionParser::Result
 OptionParser::error(const char *fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
     fprintf(stderr, "Error: ");
     vfprintf(stderr, fmt, args);
     va_end(args);
@@ -279,18 +285,21 @@ OptionParser::extractValue(size_t argc, 
         return error("Expected a value for option %s", argv[*i]);
 
     *i += 1;
     *value = argv[*i];
     return Okay;
 }
 
 OptionParser::Result
-OptionParser::handleOption(Option *opt, size_t argc, char **argv, size_t *i)
+OptionParser::handleOption(Option *opt, size_t argc, char **argv, size_t *i, bool *optionsAllowed)
 {
+    if (opt->getTerminatesOptions())
+        *optionsAllowed = false;
+
     switch (opt->kind) {
       case OptionKindBool:
       {
         if (opt == &helpOption)
             return printHelp(argv[0]);
         opt->asBoolOption()->value = true;
         return Okay;
       }
@@ -324,22 +333,26 @@ OptionParser::handleOption(Option *opt, 
       }
       default:
         JS_NOT_REACHED("unhandled option kind");
         return Fail;
     }
 }
 
 OptionParser::Result
-OptionParser::handleArg(size_t argc, char **argv, size_t *i)
+OptionParser::handleArg(size_t argc, char **argv, size_t *i, bool *optionsAllowed)
 {
     if (nextArgument >= arguments.length())
         return error("Too many arguments provided");
 
     Option *arg = arguments[nextArgument];
+
+    if (arg->getTerminatesOptions())
+        *optionsAllowed = false;
+
     switch (arg->kind) {
       case OptionKindString:
         arg->asStringOption()->value = argv[*i];
         nextArgument += 1;
         return Okay;
       case OptionKindMultiString:
       {
         /* Don't advance the next argument -- there can only be one (final) variadic argument. */
@@ -352,21 +365,23 @@ OptionParser::handleArg(size_t argc, cha
     }
 }
 
 OptionParser::Result
 OptionParser::parseArgs(int inputArgc, char **argv)
 {
     JS_ASSERT(inputArgc >= 0);
     size_t argc = inputArgc;
+    /* Permit a "no more options" capability, like |--| offers in many shell interfaces. */
+    bool optionsAllowed = true;
 
     for (size_t i = 1; i < argc; ++i) {
         char *arg = argv[i];
         Result r;
-        if (arg[0] == '-') {
+        if (arg[0] == '-' && optionsAllowed) {
             /* Option. */
             size_t arglen = strlen(arg);
             if (arglen < 2) /* Do not permit solo dash option. */
                 return error("Invalid dash option");
 
             Option *opt;
             if (arg[1] == '-') {
                 /* Long option. */
@@ -377,20 +392,20 @@ OptionParser::parseArgs(int inputArgc, c
                 /* Short option */
                 if (arg[2] != '\0')
                     return error("Short option followed by junk: %s", arg);
                 opt = findOption(arg[1]);
                 if (!opt)
                     return error("Invalid short option: %s", arg);
             }
 
-            r = handleOption(opt, argc, argv, &i);
+            r = handleOption(opt, argc, argv, &i, &optionsAllowed);
         } else {
             /* Argument. */
-            r = handleArg(argc, argv, &i);
+            r = handleArg(argc, argv, &i, &optionsAllowed);
         }
         switch (r) {
           case Okay:
             break;
           default:
             return r;
         }
     }
--- a/js/src/shell/jsoptparse.h
+++ b/js/src/shell/jsoptparse.h
@@ -65,23 +65,27 @@ enum OptionKind
 };
 
 struct Option
 {
     const char  *longflag;
     const char  *help;
     OptionKind  kind;
     char        shortflag;
+    bool        terminatesOptions;
 
     Option(OptionKind kind, char shortflag, const char *longflag, const char *help)
-      : longflag(longflag), help(help), kind(kind), shortflag(shortflag)
+      : longflag(longflag), help(help), kind(kind), shortflag(shortflag), terminatesOptions(false)
     {}
 
     virtual ~Option() = 0;
 
+    void setTerminatesOptions(bool enabled) { terminatesOptions = enabled; }
+    bool getTerminatesOptions() const { return terminatesOptions; }
+
     virtual bool isValued() const { return false; }
 
     /* Only some valued options are variadic (like MultiStringOptions). */
     virtual bool isVariadic() const { return false; }
 
     /* 
      * For arguments, the shortflag field is used to indicate whether the
      * argument is optional.
@@ -243,18 +247,18 @@ class OptionParser
     const Option *findOption(char shortflag) const;
     Option *findOption(const char *longflag);
     const Option *findOption(const char *longflag) const;
     Option *findArgument(const char *name);
     const Option *findArgument(const char *name) const;
 
     Result error(const char *fmt, ...);
     Result extractValue(size_t argc, char **argv, size_t *i, char **value);
-    Result handleArg(size_t argc, char **argv, size_t *i);
-    Result handleOption(Option *opt, size_t argc, char **argv, size_t *i);
+    Result handleArg(size_t argc, char **argv, size_t *i, bool *optsAllowed);
+    Result handleOption(Option *opt, size_t argc, char **argv, size_t *i, bool *optsAllowed);
 
   public:
     explicit OptionParser(const char *usage)
       : helpOption('h', "help", "Display help information"),
         usage(usage), ver(NULL), descr(NULL), descrWidth(80), helpWidth(80), nextArgument(0)
     {}
 
     ~OptionParser();
@@ -264,16 +268,17 @@ class OptionParser
 
     /* Metadata */
 
     void setVersion(const char *version) { ver = version; }
     void setHelpWidth(size_t width) { helpWidth = width; }
     void setDescriptionWidth(size_t width) { descrWidth = width; }
     void setDescription(const char *description) { descr = description; }
     void setHelpOption(char shortflag, const char *longflag, const char *help);
+    void setArgTerminatesOptions(const char *name, bool enabled);
 
     /* Arguments: no further arguments may be added after a variadic argument. */
 
     bool addOptionalStringArg(const char *name, const char *help);
     bool addOptionalMultiStringArg(const char *name, const char *help);
 
     const char *getStringArg(const char *name) const;
     MultiStringRange getMultiStringArg(const char *name) const;