diff --git a/renderdoccmd/3rdparty/cmdline/cmdline.h b/renderdoccmd/3rdparty/cmdline/cmdline.h index 297cbe446..be35c6042 100644 --- a/renderdoccmd/3rdparty/cmdline/cmdline.h +++ b/renderdoccmd/3rdparty/cmdline/cmdline.h @@ -39,6 +39,10 @@ #include #include +#ifdef max +#undef max +#endif + namespace cmdline{ namespace detail{ @@ -147,6 +151,7 @@ struct default_reader{ T operator()(const std::string &str){ return detail::lexical_cast(str); } + std::string description() const { return ""; } }; template @@ -154,9 +159,11 @@ struct range_reader{ range_reader(const T &low, const T &high): low(low), high(high) {} T operator()(const std::string &s) const { T ret=default_reader()(s); - if (!(ret>=low && ret<=high)) throw cmdline::cmdline_error("range_error"); + if (!(ret>=low && ret<=high)) + throw cmdline::cmdline_error(description()); return ret; } + std::string description() const { return "Must be within [" + detail::lexical_cast(low) + ", " + detail::lexical_cast(high) + "]"; } private: T low, high; }; @@ -172,10 +179,17 @@ struct oneof_reader{ T operator()(const std::string &s){ T ret=default_reader()(s); if (std::find(alt.begin(), alt.end(), ret)==alt.end()) - throw cmdline_error(""); + throw cmdline::cmdline_error("'" + s + "' is not one of the accepted values"); return ret; } void add(const T &v){ alt.push_back(v); } + std::string description() const + { + std::string ret = "Options are:"; + for(size_t i=0; i < alt.size(); i++) + ret += "\n * " + detail::lexical_cast(alt[i]); + return ret; + } private: std::vector alt; }; @@ -310,6 +324,7 @@ oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a1 class parser{ public: parser(){ + stop = false; } ~parser(){ for (std::map::iterator p=options.begin(); @@ -346,10 +361,18 @@ public: ordered.push_back(options[name]); } - void footer(const std::string &f){ + void set_header(const std::string &f){ + hdr=f; + } + + void set_footer(const std::string &f){ ftr=f; } + void stop_at_rest(bool s){ + stop=s; + } + void set_program_name(const std::string &name){ prog_name=name; } @@ -371,67 +394,25 @@ public: return others; } - bool parse(const std::string &arg){ - std::vector args; - - std::string buf; - bool in_quote=false; - for (std::string::size_type i=0; i=arg.length()){ - errors.push_back("unexpected occurrence of '\\' at end of string"); - return false; - } - } - - buf+=arg[i]; - } - - if (in_quote){ - errors.push_back("quote is not closed"); - return false; - } - - if (buf.length()>0) - args.push_back(buf); - - for (size_t i=0; i &args){ + bool parse(const std::vector &args, bool processed_arg0 = false){ int argc=static_cast(args.size()); std::vector argv(argc); for (int i=0; i lookup; @@ -449,8 +430,10 @@ public: } } - for (int i=1; i &args){ - if (!options.count("help")) - add("help", '?', "print this message"); - check((int)args.size(), parse(args)); - } - - void parse_check(int argc, char *argv[]){ - if (!options.count("help")) - add("help", '?', "print this message"); - check(argc, parse(argc, argv)); - } - - std::string error() const{ - return errors.size()>0?errors[0]:""; + check((int)args.size(), parse(args, processed_arg0)); } std::string error_full() const{ @@ -555,13 +525,13 @@ public: std::string usage() const { std::ostringstream oss; - oss<<"usage: "<must()) oss<short_description()<<" "; } - oss<<"[options] ... "<name(); for (size_t j=ordered[i]->name().length(); jdescription()<description(); + + // allow multiline descriptions, align them properly + size_t nl = desc.find('\n'); + + while(nl != std::string::npos) + { + std::string firstline = desc.substr(0, nl); + desc = desc.substr(nl+1); + + // print the first line + oss<set(value)){ - errors.push_back("option value is invalid: --"+name+"="+value); + std::string err_details = options[name]->error_details(); + if(err_details.empty()) + errors.push_back("option value is invalid: --"+name+"="+value); + else + errors.push_back("option value is invalid: --"+name+"="+value+" ("+err_details+")"); return; } } @@ -631,6 +632,8 @@ private: virtual bool valid() const=0; virtual bool must() const=0; + virtual const std::string error_details() { return ""; } + virtual const std::string &name() const=0; virtual char short_name() const=0; virtual const std::string &description() const=0; @@ -685,6 +688,8 @@ private: return "--"+nam; } + virtual const std::string error_details() { return nam+" can't have parameter"; } + private: std::string nam; char snam; @@ -703,6 +708,7 @@ private: : nam(name), snam(short_name), need(need), has(false) , def(def), actual(def) { this->desc=full_description(desc); + this->error = " (Unknown error)"; } ~option_with_value(){} @@ -722,12 +728,14 @@ private: has=true; } catch(const std::exception &e){ - (void)e; + error = e.what(); return false; } return true; } + virtual const std::string error_details() { return error; } + bool has_set() const{ return has; } @@ -754,15 +762,19 @@ private: } std::string short_description() const{ - return "--"+nam+"="+detail::readable_typename(); + return "--"+nam+"=<"+detail::readable_typename() + ">"; } protected: std::string full_description(const std::string &desc){ + std::string defval = detail::default_value(def); + return - desc+" ("+detail::readable_typename()+ - (need?"":" [="+detail::default_value(def)+"]") - +")"; + desc+" ("+ + (need?"":"optional ")+ + detail::readable_typename()+ + (!need && !defval.empty() ? "="+defval : "")+ + ")"; } virtual T read(const std::string &s)=0; @@ -771,6 +783,7 @@ private: char snam; bool need; std::string desc; + std::string error; bool has; T def; @@ -787,6 +800,10 @@ private: const std::string &desc, F reader) : option_with_value(name, short_name, need, def, desc), reader(reader){ + std::string reader_description = this->reader.description(); + + if(!reader_description.empty()) + this->desc = this->desc + " " + reader_description; } private: @@ -799,7 +816,9 @@ private: std::map options; std::vector ordered; + std::string hdr; std::string ftr; + bool stop; std::string prog_name; std::vector others;