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 76192 ee787d92a2e161bd457f11601e630a1bb34b9320
parent 76191 ba38da32b8483d359991524a18cc977ec7d6d76e
child 76193 4a31be812223e5f03439f96f0e9f04166a6ea4c8
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersdvander
bugs679138
milestone9.0a1
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;