diff -r 000000000000 -r 6474c204b198 js/src/shell/jsoptparse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/shell/jsoptparse.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,294 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef shell_jsoptparse_h +#define shell_jsoptparse_h + +#include + +#include "jsalloc.h" +#include "jsutil.h" + +#include "js/Vector.h" + +namespace js { +namespace cli { + +namespace detail { + +struct BoolOption; +struct MultiStringOption; +struct ValuedOption; +struct StringOption; +struct IntOption; + +enum OptionKind +{ + OptionKindBool, + OptionKindString, + OptionKindInt, + OptionKindMultiString, + OptionKindInvalid +}; + +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), 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. + */ + bool isOptional() { return shortflag; } + + void setFlagInfo(char shortflag, const char *longflag, const char *help) { + this->shortflag = shortflag; + this->longflag = longflag; + this->help = help; + } + + ValuedOption *asValued(); + const ValuedOption *asValued() const; + +#define OPTION_CONVERT_DECL(__cls) \ + bool is##__cls##Option() const; \ + __cls##Option *as##__cls##Option(); \ + const __cls##Option *as##__cls##Option() const; + + OPTION_CONVERT_DECL(Bool) + OPTION_CONVERT_DECL(String) + OPTION_CONVERT_DECL(Int) + OPTION_CONVERT_DECL(MultiString) +}; + +inline Option::~Option() {} + +struct BoolOption : public Option +{ + size_t argno; + bool value; + + BoolOption(char shortflag, const char *longflag, const char *help) + : Option(OptionKindBool, shortflag, longflag, help), value(false) + {} + + virtual ~BoolOption() {} +}; + +struct ValuedOption : public Option +{ + const char *metavar; + + ValuedOption(OptionKind kind, char shortflag, const char *longflag, const char *help, + const char *metavar) + : Option(kind, shortflag, longflag, help), metavar(metavar) + {} + + virtual ~ValuedOption() = 0; + virtual bool isValued() const { return true; } +}; + +inline ValuedOption::~ValuedOption() {} + +struct StringOption : public ValuedOption +{ + const char *value; + + StringOption(char shortflag, const char *longflag, const char *help, const char *metavar) + : ValuedOption(OptionKindString, shortflag, longflag, help, metavar), value(nullptr) + {} + + virtual ~StringOption() {} +}; + +struct IntOption : public ValuedOption +{ + int value; + + IntOption(char shortflag, const char *longflag, const char *help, const char *metavar, + int defaultValue) + : ValuedOption(OptionKindInt, shortflag, longflag, help, metavar), value(defaultValue) + {} + + virtual ~IntOption() {} +}; + +struct StringArg +{ + char *value; + size_t argno; + + StringArg(char *value, size_t argno) : value(value), argno(argno) {} +}; + +struct MultiStringOption : public ValuedOption +{ + Vector strings; + + MultiStringOption(char shortflag, const char *longflag, const char *help, const char *metavar) + : ValuedOption(OptionKindMultiString, shortflag, longflag, help, metavar) + {} + + virtual ~MultiStringOption() {} + + virtual bool isVariadic() const { return true; } +}; + +} /* namespace detail */ + +class MultiStringRange +{ + typedef detail::StringArg StringArg; + const StringArg *cur; + const StringArg *end; + + public: + explicit MultiStringRange(const StringArg *cur, const StringArg *end) + : cur(cur), end(end) { + JS_ASSERT(end - cur >= 0); + } + + bool empty() const { return cur == end; } + void popFront() { JS_ASSERT(!empty()); ++cur; } + char *front() const { JS_ASSERT(!empty()); return cur->value; } + size_t argno() const { JS_ASSERT(!empty()); return cur->argno; } +}; + +/* + * Builder for describing a command line interface and parsing the resulting + * specification. + * + * - A multi-option is an option that can appear multiple times and still + * parse as valid command line arguments. + * - An "optional argument" is supported for backwards compatibility with prior + * command line interface usage. Once one optional argument has been added, + * *only* optional arguments may be added. + */ +class OptionParser +{ + public: + enum Result + { + Okay = 0, + Fail, /* As in, allocation fail. */ + ParseError, /* Successfully parsed but with an error. */ + ParseHelp /* Aborted on help flag. */ + }; + + private: + typedef Vector Options; + typedef detail::Option Option; + typedef detail::BoolOption BoolOption; + + Options options; + Options arguments; + BoolOption helpOption; + const char *usage; + const char *ver; + const char *descr; + size_t descrWidth; + size_t helpWidth; + size_t nextArgument; + + // If '--' is passed, all remaining arguments should be interpreted as the + // argument at index 'restArgument'. Defaults to the next unassigned + // argument. + int restArgument; + + static const char prognameMeta[]; + + Option *findOption(char shortflag); + const Option *findOption(char shortflag) const; + Option *findOption(const char *longflag); + const Option *findOption(const char *longflag) const; + int findArgumentIndex(const char *name) 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, 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(nullptr), descr(nullptr), descrWidth(80), helpWidth(80), + nextArgument(0), restArgument(-1) + {} + + ~OptionParser(); + + Result parseArgs(int argc, char **argv); + Result printHelp(const char *progname); + + /* 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); + void setArgCapturesRest(const char *name); + + /* 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; + + /* Options */ + + bool addBoolOption(char shortflag, const char *longflag, const char *help); + bool addStringOption(char shortflag, const char *longflag, const char *help, + const char *metavar); + bool addIntOption(char shortflag, const char *longflag, const char *help, + const char *metavar, int defaultValue); + bool addMultiStringOption(char shortflag, const char *longflag, const char *help, + const char *metavar); + bool addOptionalVariadicArg(const char *name); + + int getIntOption(char shortflag) const; + int getIntOption(const char *longflag) const; + const char *getStringOption(char shortflag) const; + const char *getStringOption(const char *longflag) const; + bool getBoolOption(char shortflag) const; + bool getBoolOption(const char *longflag) const; + MultiStringRange getMultiStringOption(char shortflag) const; + MultiStringRange getMultiStringOption(const char *longflag) const; + + /* + * Return whether the help option was present (and thus help was already + * displayed during parse_args). + */ + bool getHelpOption() const; +}; + +} /* namespace cli */ +} /* namespace js */ + +#endif /* shell_jsoptparse_h */