# # # patch "mtn_cvs/mtn_cvs.cc" # from [154cdf31a157a95dc0e83e4c697923247671cf2f] # to [03d9034c943e682f87d545eda52f763a5b11b03f] # # patch "mtn_cvs/mtncvs_state.hh" # from [e2f9b651f0dc2d627deadcc3c467fa1e69d655a6] # to [3e366f3dcffa1252a31946e75f091d6cd630fa0c] # # patch "mtn_cvs/options_list.hh" # from [7c1d0776e9f5b2c2cf0d208167aa435211809732] # to [b5cff95686fc6317318e75b74ac7fcc2a3f6da0b] # ============================================================ --- mtn_cvs/mtn_cvs.cc 154cdf31a157a95dc0e83e4c697923247671cf2f +++ mtn_cvs/mtn_cvs.cc 03d9034c943e682f87d545eda52f763a5b11b03f @@ -143,7 +143,28 @@ CMD(takeover, N_("working copy"), N_("[C #include +using std::cout; +using std::cerr; +using std::endl; +using std::ostringstream; +using std::string; + void +get_version(string & out) +{ + out = (F("%s (base revision: %s)") + % PACKAGE_STRING % string(package_revision_constant)).str(); +} + +void +print_version() +{ + string s; + get_version(s); + cout << s << endl; +} + +void get_full_version(std::string & out) { out="mtn_cvs version 0.1 ("+std::string(package_revision_constant)+")"; } @@ -160,6 +181,7 @@ using boost::shared_ptr; using std::ios_base; using boost::shared_ptr; +#if 0 static void tokenize_for_command_line(string const & from, vector & to) { @@ -228,6 +250,7 @@ tokenize_for_command_line(string const & if (have_tok) to.push_back(cur); } +#endif // This is in a sepaarte procedure so it can be called from code that's called // before cpp_main(), such as program option object creation code. It's made @@ -244,6 +267,33 @@ void localize_monotone() } } +// read command-line options and return the command name +string read_options(options & opts, vector args) +{ + option::concrete_option_set optset = + options::opts::all_options().instantiate(&opts); + optset.from_command_line(args); + + // consume the command, and perform completion if necessary + string cmd; + if (!opts.args.empty()) + cmd = commands::complete_command(idx(opts.args, 0)()); + + // reparse options, now that we know what command-specific + // options are allowed. + + options::options_type cmdopts = commands::command_options(opts.args); + optset.reset(); + + optset = (options::opts::globals() | cmdopts).instantiate(&opts); + optset.from_command_line(args, false); + + if (!opts.args.empty()) + opts.args.erase(opts.args.begin()); + + return cmd; +} + int cpp_main(int argc, char ** argv) { @@ -262,153 +312,51 @@ cpp_main(int argc, char ** argv) // conversion etc try { - bool requested_help=false; - // Set up the global sanity object. No destructor is needed and // therefore no wrapper object is needed either. global_sanity.initialize(argc, argv, setlocale(LC_ALL, 0)); // Set up secure memory allocation etc botan_library acquire_botan; + + // Record where we are. This has to happen before any use of + // boost::filesystem. + save_initial_path(); - // set up some marked strings, so even if our logbuf overflows, we'll get - // this data in a crash. - std::string cmdline_string; - { - std::ostringstream cmdline_ss; - for (int i = 0; i < argc; ++i) - { - if (i) - cmdline_ss << ", "; - cmdline_ss << "'" << argv[i] << "'"; - } - cmdline_string = cmdline_ss.str(); - } - MM(cmdline_string); - L(FL("command line: %s\n") % cmdline_string); - - std::string locale_string = (setlocale(LC_ALL, NULL) == NULL ? "n/a" : setlocale(LC_ALL, NULL)); - MM(locale_string); - L(FL("set locale: LC_ALL=%s\n") % locale_string); - - std::string full_version_string; - get_full_version(full_version_string); - MM(full_version_string); - - // Set up secure memory allocation etc - Botan::Init::initialize(); - Botan::set_default_allocator("malloc"); - // decode all argv values into a UTF-8 array - save_initial_path(); - std::vector args; - utf8 progname; - for (int i = 0; i < argc; ++i) + vector args; + for (int i = 1; i < argc; ++i) { external ex(argv[i]); utf8 ut; system_to_utf8(ex, ut); - if (i) - args.push_back(ut()); - else - progname = ut; + args.push_back(ut()); } - // find base name of executable - std::string prog_path = fs::path(progname()).leaf(); - if (prog_path.rfind(".exe") == prog_path.size() - 4) - prog_path = prog_path.substr(0, prog_path.size() - 4); - utf8 prog_name(prog_path); + // find base name of executable, convert to utf8, and save it in the + // global ui object + { + string prog_name = fs::path(argv[0]).leaf(); + if (prog_name.rfind(".exe") == prog_name.size() - 4) + prog_name = prog_name.substr(0, prog_name.size() - 4); + utf8 prog_name_u; + system_to_utf8(prog_name, prog_name_u); + ui.prog_name = prog_name_u(); + I(!ui.prog_name.empty()); + } mtncvs_state app; -#if 0 try { - -// app.set_prog_name(prog_name); - - // set up for parsing. we add a hidden argument that collections all - // positional arguments, which we process ourselves in a moment. - po::options_description all_options; - all_options.add(option::global_options); - all_options.add(option::specific_options); - all_options.add_options() - ("all_positional_args", po::value< vector >()); - po::positional_options_description all_positional_args; - all_positional_args.add("all_positional_args", -1); - - // Check the command line for -@/--xargs - { - po::parsed_options parsed = po::command_line_parser(args) - .style(po::command_line_style::default_style & - ~po::command_line_style::allow_guessing) - .options(all_options) - .run(); - po::variables_map vm; - po::store(parsed, vm); - po::notify(vm); -#if 0 - if (option::argfile.given(vm)) - { - vector files = option::argfile.get(vm); - for (vector::iterator f = files.begin(); - f != files.end(); ++f) - { - data dat; - read_data_for_command_line(*f, dat); - vector fargs; - tokenize_for_command_line(dat(), fargs); - for (vector::const_iterator i = fargs.begin(); - i != fargs.end(); ++i) - { - args.push_back(*i); - } - } - } -#endif - } - - po::parsed_options parsed = po::command_line_parser(args) - .style(po::command_line_style::default_style & - ~po::command_line_style::allow_guessing) - .options(all_options) - .positional(all_positional_args) - .run(); - po::variables_map vm; - po::store(parsed, vm); - po::notify(vm); - - // consume the command, and perform completion if necessary - std::string cmd; - vector positional_args; - if (vm.count("all_positional_args")) + string cmd = read_options(app.opts, args); + + if (app.opts.version_given) { - positional_args = vm["all_positional_args"].as< vector >(); - cmd = commands::complete_command(idx(positional_args, 0)); - positional_args.erase(positional_args.begin()); + print_version(); + return 0; } - // build an options_description specific to this cmd. - po::options_description cmd_options_desc = commands::command_options(cmd); - - po::options_description all_for_this_cmd; - all_for_this_cmd.add(option::global_options); - all_for_this_cmd.add(cmd_options_desc); - - // reparse arguments using specific options. - parsed = po::command_line_parser(args) - .style(po::command_line_style::default_style & - ~po::command_line_style::allow_guessing) - .options(all_for_this_cmd) - .run(); - po::store(parsed, vm); - po::notify(vm); - - if (option::debug.given(vm)) - { - global_sanity.set_debug(); - } - +#if 0 if (option::full.given(vm)) app.full=true; if (option::since.given(vm)) app.since=string(option::since.get(vm)); @@ -423,13 +371,6 @@ cpp_main(int argc, char ** argv) app.revisions.push_back(revision_id(option::revision.get(vm))); } - if (option::version.given(vm)) - { std::string version; - get_full_version(version); - std::cout << version << '\n'; - return 0; - } - if (option::help.given(vm)) requested_help = true; if (option::mtn.given(vm)) app.mtn_binary = option::mtn.get(vm); @@ -457,9 +398,10 @@ cpp_main(int argc, char ** argv) if (option::key.given(vm)) app.mtn_options.push_back(string("--key=")+option::key.get(vm)); +#endif // stop here if they asked for help - if (requested_help) + if (app.opts.help) { throw usage(cmd); // cmd may be empty, and that's fine. } @@ -483,47 +425,41 @@ cpp_main(int argc, char ** argv) } else { - vector args(positional_args.begin(), positional_args.end()); + vector args(app.opts.args.begin(), app.opts.args.end()); return commands::process(app.downcast(), cmd, args); } } - catch (po::ambiguous_option const & e) + catch (option::option_error const & e) { - std::string msg = (F("%s:\n") % e.what()).str(); - vector::const_iterator it = e.alternatives.begin(); - for (; it != e.alternatives.end(); ++it) - msg += *it + "\n"; - N(false, i18n_format(msg)); + N(false, i18n_format("%s") % e.what()); } - catch (po::error const & e) - { - N(false, F("%s") % e.what()); - } catch (usage & u) { - // Make sure to hide documentation that's not part of - // the current command. + // we send --help output to stdout, so that "mtn --help | less" works + // but we send error-triggered usage information to stderr, so that if + // you screw up in a script, you don't just get usage information sent + // merrily down your pipes. + std::ostream & usage_stream = (app.opts.help ? cout : cerr); - po::options_description cmd_options_desc = commands::command_options(u.which); - unsigned count = cmd_options_desc.options().size(); + usage_stream << F("Usage: %s [OPTION...] command [ARG...]") % ui.prog_name << "\n\n"; + usage_stream << options::opts::globals().instantiate(&app.opts).get_usage_str() << "\n"; - cout << F("Usage: %s [OPTION...] command [ARG...]") % prog_name << "\n\n"; - cout << option::global_options << "\n"; - - if (count > 0) + // Make sure to hide documentation that's not part of + // the current command. + options::options_type cmd_options = commands::toplevel_command_options(u.which); + if (!cmd_options.empty()) { - cout << F("Options specific to '%s %s':") % prog_name % u.which << "\n\n"; - cout << cmd_options_desc << "\n"; + usage_stream << F("Options specific to '%s %s':") % ui.prog_name % u.which << "\n\n"; + usage_stream << cmd_options.instantiate(&app.opts).get_usage_str() << "\n"; } - commands::explain_usage(u.which, cout); - if (requested_help) + commands::explain_usage(u.which, usage_stream); + if (app.opts.help) return 0; else return 2; } -#endif } catch (informative_failure & inf) { ============================================================ --- mtn_cvs/mtncvs_state.hh e2f9b651f0dc2d627deadcc3c467fa1e69d655a6 +++ mtn_cvs/mtncvs_state.hh 3e366f3dcffa1252a31946e75f091d6cd630fa0c @@ -22,6 +22,8 @@ struct mtncvs_state : private app_state, std::vector mtn_options; utf8 branch; utf8 domain; + + options opts; mtncvs_state() : full(), mtn_binary("mtn"), domain("cvs") {} ============================================================ --- mtn_cvs/options_list.hh 7c1d0776e9f5b2c2cf0d208167aa435211809732 +++ mtn_cvs/options_list.hh b5cff95686fc6317318e75b74ac7fcc2a3f6da0b @@ -32,20 +32,46 @@ OPT(full, "full", bool, false, N_("ignor } #endif -OPT(revision, "revision,r", std::string, "", N_("select revision id for operation")) +OPTVAR(revision, std::vector, revisions, ) +OPTION(revision, revision, true, "revision,r", + N_("select revision id(s) for operation")) #ifdef option_bodies { - // revision = true; + revisions.push_back(revision_id(arg)); } #endif -#if 0 -COPT(revision, "revision,r", string, N_("select revision id for operation")); +GOPT(version, "version,V", bool, false, + gettext_noop("print version number, then exit")) +#ifdef option_bodies +{ + version = true; +} +#endif -GOPT(debug, "debug", nil, N_("print debug log to stderr while running")); -GOPT(help, "help,h", nil, N_("display help message")); -GOPT(version, "version,V", nil, N_("print version number, then exit")); -GOPT(mtn, "mtn", string, N_("monotone binary name")); +GOPT(help, "help,h", bool, false, gettext_noop("display help message")) +#ifdef option_bodies +{ + help = true; +} +#endif + +OPTION(globals, debug, false, "debug", + gettext_noop("print debug log to stderr while running")) +#ifdef option_bodies +{ + global_sanity.set_debug(); +} +#endif + +GOPT(mtn, "mtn", std::string, , gettext_noop("monotone binary name")) +#ifdef option_bodies +{ + mtn = arg; +} +#endif + +#if 0 GOPT(mtn_option, "mtn-option", string, N_("pass option to monotone")); // these options are passed transparently GOPT(db, "db,d", string, N_("passed: database location"));