# # # delete "popt" # # delete "popt/CHANGES" # # delete "popt/COPYING" # # delete "popt/README" # # delete "popt/findme.c" # # delete "popt/findme.h" # # delete "popt/popt.3" # # delete "popt/popt.c" # # delete "popt/popt.h" # # delete "popt/popt.ps" # # delete "popt/poptconfig.c" # # delete "popt/popthelp.c" # # delete "popt/poptint.h" # # delete "popt/poptparse.c" # # delete "popt/system.h" # # delete "popt/test1.c" # # delete "popt/test2.c" # # delete "popt/test3.c" # # delete "popt/testit.sh" # # patch "AUTHORS" # from [b8056b4cefa9663455b5c7cf8bc9e17ce249b253] # to [85acc30a0ac5ae50301dfca3ec5c8e6e9c154251] # # patch "Makefile.am" # from [14af4c728a8cdfc6154741d88841de958b71a7df] # to [aa593e547b6cdcf55dca02a4155a7877e3ceb43b] # # patch "app_state.cc" # from [6a8be1d3051e8e84464730d9d4f60cc9abca098d] # to [d6e222da129d8b10fadc92dc72289e416ac95347] # # patch "app_state.hh" # from [4d4ab0e35a58144708b8a67252fec3a37f0ea71a] # to [c37b993b8453eed5474a2a204c8504115d37ee3b] # # patch "cert.cc" # from [90434ca979245b8d440c3daead3d8ad5120e27ee] # to [911fae2acc11bec4a0ba3b82b6fda6db6d5f58e2] # # patch "cmd.hh" # from [60c6bbe98e2513189c4cd84d8b6cfcc6429e15f5] # to [5cab22f4ed2558c7339d7d12f345f4f92c201585] # # patch "cmd_automate.cc" # from [d973f6704cc5cf5a777b8e4f5bdd60ee10048b7c] # to [2276c7f444f7608692b11b96aee2a9777b2eb178] # # patch "cmd_db.cc" # from [cef42bd1ec6ec18b7e37bfbd70d1d9decee2d679] # to [6c69652adbaceee9c90e299e563a99d42a7d617c] # # patch "cmd_diff_log.cc" # from [31fe8c5d41bd88bd58dae13ad2b21a8839b5a415] # to [0fa7daad5f4c627f8394b3812dc751e8c3f32ebe] # # patch "cmd_files.cc" # from [d8a4d7557dacbd31b9d9b7b15b62d231dcfbfe43] # to [6cd5382a6f9956e00dea0bbd13a76a8311505707] # # patch "cmd_key_cert.cc" # from [6b1f09475de549a193b7604f4512b0a4e6a5ff2e] # to [1713716538c8a4bd862c893db65a250b1549d751] # # patch "cmd_list.cc" # from [5fcd71a963f52bf864f3a8f392c8d9ae328ac953] # to [2d0e1fac84a4db2f99366d2bbf159e04332d94f1] # # patch "cmd_merging.cc" # from [b98e34e5f0f820fcadd105b56c91dd0ed7ffae66] # to [992d2636e85ee32969adcd7ea91bae9407aee467] # # patch "cmd_netsync.cc" # from [431b5bb6daff4f8d8992eee7ff14a21512895b81] # to [5854e5d663e78753bfce09d12c5874d89a713a29] # # patch "cmd_othervcs.cc" # from [2a6c2ccd297e79ee652a1c7189e7d3c45de47c40] # to [d4031c567c49093b03f3d8a2b525b4536ff569c5] # # patch "cmd_packet.cc" # from [26b3d187c3a139599b7c50ba80c29f81c382dfdd] # to [f906375a6c7a3ccc384fecf3f83abbf31e81fac2] # # patch "cmd_ws_commit.cc" # from [130ebf460f4770ca6b39dd7c5d2b8dbf39405656] # to [5fa9b556de08d2750a569e98660ccb059a0a9551] # # patch "commands.cc" # from [a02d61685a3807368a2e1ec1fed79ea5f342ea79] # to [593ec7c6c510ce95545ff592ddbbdb3de4a302db] # # patch "commands.hh" # from [a04625b93f41cb792463b71062a1265e0d85a19f] # to [3911eb2fdb483e56d204d4171178066b97991e4c] # # patch "configure.ac" # from [9a0e730650f554caa768ae612c5583b69bc10330] # to [f7b30db05b4fe83a334c870aabaea6fa833035b4] # # patch "monotone.cc" # from [7ce7990a7e4ebb99f1980ccdeca7a6e1b297ea7b] # to [5adef7e9f83b109da2a223597c0eaf041ac12268] # # patch "options.hh" # from [a093ddbe1d7f14fa737498deeecd16b099ea45d7] # to [a1618c597c735f96615340df71f5ae77a54634d3] # ============================================================ --- AUTHORS b8056b4cefa9663455b5c7cf8bc9e17ce249b253 +++ AUTHORS 85acc30a0ac5ae50301dfca3ec5c8e6e9c154251 @@ -252,16 +252,6 @@ --- -The files in popt/* are copies of the original popt 1.7 as provided by -Debian (their own version number is 1.7-5). According to the README -(reproduced as popt/README), it was written by a (former?) RedHat -employee using the address address@hidden popt is licensed with the -X Consortium public license, nowadays called the "X.Net, Inc. License". -It's reproduced in popt/COPYING. - - ---- - The file contrib/colorize is a copy of a perl script written by Cédric Bouvier, which is released under the GNU GPL. ============================================================ --- Makefile.am 14af4c728a8cdfc6154741d88841de958b71a7df +++ Makefile.am aa593e547b6cdcf55dca02a4155a7877e3ceb43b @@ -214,11 +214,6 @@ idna/gunicomp.h idna/idna.c idna/idn-int.h idna/profiles.c \ idna/punycode.h idna/stringprep.c idna/toutf8.c -POPT_SOURCES = \ - popt/findme.c popt/poptconfig.c popt/poptint.h \ - popt/findme.h popt/popt.h popt/poptparse.c \ - popt/popt.c popt/popthelp.c popt/system.h - UNIX_PLATFORM_SOURCES = \ unix/read_password.cc unix/get_system_flavour.cc unix/process.cc unix/terminal.cc \ unix/inodeprint.cc unix/fs.cc unix/make_io_binary.cc @@ -245,7 +240,6 @@ lib3rdparty_a_SOURCES = $(BOOST_SANDBOX_SOURCES) \ $(BOTAN_SOURCES) \ $(IDNA_SOURCES) \ - $(POPT_SOURCES) \ $(NETXX_SOURCES) \ $(LUA_SOURCES) \ $(SQLITE_SOURCES) @@ -391,8 +385,6 @@ package.m4 \ package_revision.txt package_full_revision_dist.txt \ $(wildcard $(srcdir)/m4/*.m4) \ - popt/README popt/CHANGES popt/COPYING popt/popt.3 popt/popt.ps \ - $(wildcard $(srcdir)/popt/test?.c) popt/testit.sh \ sqlite/keywordhash.h \ contrib/README \ contrib/monoprof.sh \ ============================================================ --- app_state.cc 6a8be1d3051e8e84464730d9d4f60cc9abca098d +++ app_state.cc d6e222da129d8b10fadc92dc72289e416ac95347 @@ -50,17 +50,15 @@ } void -app_state::set_is_explicit_option (int option_id) +app_state::set_is_explicit_option (std::string o) { - explicit_option_map[option_id] = true; + explicit_options.insert(o); } bool -app_state::is_explicit_option(int option_id) const +app_state::is_explicit_option(std::string o) const { - std::map::const_iterator i = explicit_option_map.find(option_id); - if (i == explicit_option_map.end()) return false; - return i->second; + return explicit_options.find(o) != explicit_options.end(); } void ============================================================ --- app_state.hh 4d4ab0e35a58144708b8a67252fec3a37f0ea71a +++ app_state.hh c37b993b8453eed5474a2a204c8504115d37ee3b @@ -18,6 +18,7 @@ #include "database.hh" #include "lua_hooks.hh" +#include "options.hh" #include "work.hh" #include "vocab.hh" #include "paths.hh" @@ -73,9 +74,9 @@ std::set attrs_to_drop; bool no_files; - std::map explicit_option_map; // set if the value of the flag was explicitly given on the command line - void set_is_explicit_option (int option_id); - bool is_explicit_option(int option_id) const; + std::set explicit_options; // in set if the value of the flag was explicitly given on the command line + void set_is_explicit_option (std::string o); + bool is_explicit_option(std::string o) const; // These are used to cache signers/verifiers (if the hook allows). // They can't be function-static variables in key.cc, since they must be ============================================================ --- cert.cc 90434ca979245b8d440c3daead3d8ad5120e27ee +++ cert.cc 911fae2acc11bec4a0ba3b82b6fda6db6d5f58e2 @@ -447,7 +447,7 @@ app_state & app, cert_value & branchname) { - if ((app.branch_name() != "") && app.is_explicit_option(OPT_BRANCH_NAME)) + if ((app.branch_name() != "") && app.is_explicit_option(option::branch_name())) { branchname = app.branch_name(); } ============================================================ --- cmd.hh 60c6bbe98e2513189c4cd84d8b6cfcc6429e15f5 +++ cmd.hh 5cab22f4ed2558c7339d7d12f345f4f92c201585 @@ -1,6 +1,9 @@ #ifndef __CMD_HH__ #define __CMD_HH__ +#include +#include + #include "sanity.hh" #include "options.hh" #include "constants.hh" @@ -14,19 +17,20 @@ namespace commands { using std::set; - struct no_opts {}; + using boost::program_options::option_description; + using boost::shared_ptr; + struct command_opts { - set opts; + set< shared_ptr > opts; command_opts() {} - command_opts & operator%(int o) - { opts.insert(o); return *this; } - command_opts & operator%(no_opts o) + command_opts & operator%(shared_ptr p) + { opts.insert(p); return *this; } + command_opts & operator%(option::no_option) { return *this; } command_opts & operator%(command_opts const &o) { opts.insert(o.opts.begin(), o.opts.end()); return *this; } }; - extern const no_opts OPT_NONE; struct command { ============================================================ --- cmd_automate.cc d973f6704cc5cf5a777b8e4f5bdd60ee10048b7c +++ cmd_automate.cc 2276c7f444f7608692b11b96aee2a9777b2eb178 @@ -33,7 +33,7 @@ "packet_for_fdelta OLD_FILE NEW_FILE\n" "keys\n"), N_("automation interface"), - OPT_NONE) + option::none) { if (args.size() == 0) throw usage(name); ============================================================ --- cmd_db.cc cef42bd1ec6ec18b7e37bfbd70d1d9decee2d679 +++ cmd_db.cc 6c69652adbaceee9c90e299e563a99d42a7d617c @@ -46,7 +46,7 @@ "rosterify\n" "set_epoch BRANCH EPOCH\n"), N_("manipulate database state"), - OPT_DROP_ATTR) + option::drop_attr) { if (args.size() == 1) { @@ -104,7 +104,7 @@ CMD(set, N_("vars"), N_("DOMAIN NAME VALUE"), N_("set the database variable NAME to VALUE, in domain DOMAIN"), - OPT_NONE) + option::none) { if (args.size() != 3) throw usage(name); @@ -120,7 +120,7 @@ CMD(unset, N_("vars"), N_("DOMAIN NAME"), N_("remove the database variable NAME in domain DOMAIN"), - OPT_NONE) + option::none) { if (args.size() != 2) throw usage(name); @@ -136,7 +136,7 @@ CMD(complete, N_("informative"), N_("(revision|file|key) PARTIAL-ID"), N_("complete partial id"), - OPT_VERBOSE) + option::verbose) { if (args.size() != 2) throw usage(name); ============================================================ --- cmd_diff_log.cc 31fe8c5d41bd88bd58dae13ad2b21a8839b5a415 +++ cmd_diff_log.cc 0fa7daad5f4c627f8394b3812dc751e8c3f32ebe @@ -326,9 +326,8 @@ "If one revision is given, the diff between the workspace and\n" "that revision is shown. If two revisions are given, the diff between\n" "them is given. If no format is specified, unified is used by default."), - OPT_REVISION % OPT_DEPTH % OPT_EXCLUDE % - OPT_UNIFIED_DIFF % OPT_CONTEXT_DIFF % OPT_EXTERNAL_DIFF % - OPT_EXTERNAL_DIFF_ARGS) + option::revision % option::depth % option::exclude % option::unified_diff + % option::context_diff % option::external_diff % option::external_diff_args) { bool new_is_archived; diff_type type = app.diff_format; @@ -522,8 +521,8 @@ CMD(log, N_("informative"), N_("[FILE] ..."), N_("print history in reverse order (filtering by 'FILE'). If one or more\n" "revisions are given, use them as a starting point."), - OPT_LAST % OPT_NEXT % OPT_REVISION % OPT_BRIEF % OPT_DIFFS % OPT_NO_MERGES % - OPT_NO_FILES) + option::last % option::next % option::revision % option::brief + % option::diffs % option::no_merges % option::no_files) { if (app.revision_selectors.size() == 0) app.require_workspace("try passing a --revision to start at"); ============================================================ --- cmd_files.cc d8a4d7557dacbd31b9d9b7b15b62d231dcfbfe43 +++ cmd_files.cc 6cd5382a6f9956e00dea0bbd13a76a8311505707 @@ -14,7 +14,7 @@ // fload and fmerge are simple commands for debugging the line // merger. -CMD(fload, N_("debug"), "", N_("load file contents into db"), OPT_NONE) +CMD(fload, N_("debug"), "", N_("load file contents into db"), option::none) { string s = get_stdin(); @@ -29,7 +29,7 @@ CMD(fmerge, N_("debug"), N_(" "), N_("merge 3 files and output result"), - OPT_NONE) + option::none) { if (args.size() != 3) throw usage(name); @@ -62,7 +62,7 @@ CMD(annotate, N_("informative"), N_("PATH"), N_("print annotated copy of the file from REVISION"), - OPT_REVISION % OPT_BRIEF) + option::revision % option::brief) { revision_id rid; @@ -101,7 +101,7 @@ CMD(identify, N_("debug"), N_("[PATH]"), N_("calculate identity of PATH or stdin"), - OPT_NONE) + option::none) { if (!(args.size() == 0 || args.size() == 1)) throw usage(name); @@ -125,7 +125,7 @@ CMD(cat, N_("informative"), N_("FILENAME"), N_("write file from database to stdout"), - OPT_REVISION) + option::revision) { if (args.size() != 1) throw usage(name); ============================================================ --- cmd_key_cert.cc 6b1f09475de549a193b7604f4512b0a4e6a5ff2e +++ cmd_key_cert.cc 1713716538c8a4bd862c893db65a250b1549d751 @@ -12,7 +12,7 @@ #include using std::cout; -CMD(genkey, N_("key and cert"), N_("KEYID"), N_("generate an RSA key-pair"), OPT_NONE) +CMD(genkey, N_("key and cert"), N_("KEYID"), N_("generate an RSA key-pair"), option::none) { if (args.size() != 1) throw usage(name); @@ -36,7 +36,7 @@ app.keys.put_key_pair(ident, kp); } -CMD(dropkey, N_("key and cert"), N_("KEYID"), N_("drop a public and private key"), OPT_NONE) +CMD(dropkey, N_("key and cert"), N_("KEYID"), N_("drop a public and private key"), option::none) { bool key_deleted = false; @@ -75,7 +75,7 @@ CMD(chkeypass, N_("key and cert"), N_("KEYID"), N_("change passphrase of a private RSA key"), - OPT_NONE) + option::none) { if (args.size() != 1) throw usage(name); @@ -95,7 +95,7 @@ } CMD(cert, N_("key and cert"), N_("REVISION CERTNAME [CERTVAL]"), - N_("create a cert for a revision"), OPT_NONE) + N_("create a cert for a revision"), option::none) { if ((args.size() != 3) && (args.size() != 2)) throw usage(name); @@ -133,7 +133,7 @@ CMD(trusted, N_("key and cert"), N_("REVISION NAME VALUE SIGNER1 [SIGNER2 [...]]"), N_("test whether a hypothetical cert would be trusted\n" "by current settings"), - OPT_NONE) + option::none) { if (args.size() < 4) throw usage(name); @@ -177,7 +177,7 @@ } CMD(tag, N_("review"), N_("REVISION TAGNAME"), - N_("put a symbolic tag cert on a revision"), OPT_NONE) + N_("put a symbolic tag cert on a revision"), option::none) { if (args.size() != 2) throw usage(name); @@ -190,7 +190,7 @@ CMD(testresult, N_("review"), N_("ID (pass|fail|true|false|yes|no|1|0)"), - N_("note the results of running a test on a revision"), OPT_NONE) + N_("note the results of running a test on a revision"), option::none) { if (args.size() != 2) throw usage(name); @@ -204,7 +204,7 @@ CMD(approve, N_("review"), N_("REVISION"), N_("approve of a particular revision"), - OPT_BRANCH_NAME) + option::branch_name) { if (args.size() != 1) throw usage(name); @@ -219,7 +219,7 @@ } CMD(comment, N_("review"), N_("REVISION [COMMENT]"), - N_("comment on a particular revision"), OPT_NONE) + N_("comment on a particular revision"), option::none) { if (args.size() != 1 && args.size() != 2) throw usage(name); ============================================================ --- cmd_list.cc 5fcd71a963f52bf864f3a8f392c8d9ae328ac953 +++ cmd_list.cc 2d0e1fac84a4db2f99366d2bbf159e04332d94f1 @@ -443,7 +443,7 @@ "changed"), N_("show database objects, or the current workspace manifest, or known,\n" "unknown, intentionally ignored, missing, or changed state files"), - OPT_DEPTH % OPT_EXCLUDE) + option::depth % option::exclude) { if (args.size() == 0) throw usage(name); ============================================================ --- cmd_merging.cc b98e34e5f0f820fcadd105b56c91dd0ed7ffae66 +++ cmd_merging.cc 992d2636e85ee32969adcd7ea91bae9407aee467 @@ -39,7 +39,7 @@ "different revision, preserving uncommitted changes as it does so.\n" "If a revision is given, update the workspace to that revision.\n" "If not, update the workspace to the head of the branch."), - OPT_BRANCH_NAME % OPT_REVISION) + option::branch_name % option::revision) { revision_set r_working; roster_t working_roster, chosen_roster, target_roster; @@ -273,7 +273,7 @@ // should merge support --message, --message-file? It seems somewhat weird, // since a single 'merge' command may perform arbitrarily many actual merges. CMD(merge, N_("tree"), "", N_("merge unmerged heads of branch"), - OPT_BRANCH_NAME % OPT_DATE % OPT_AUTHOR) + option::branch_name % option::date % option::author) { set heads; @@ -327,7 +327,7 @@ CMD(propagate, N_("tree"), N_("SOURCE-BRANCH DEST-BRANCH"), N_("merge from one branch to another asymmetrically"), - OPT_DATE % OPT_AUTHOR % OPT_MESSAGE % OPT_MSGFILE) + option::date % option::author % option::message % option::msgfile) { if (args.size() != 2) throw usage(name); @@ -338,7 +338,7 @@ CMD(merge_into_dir, N_("tree"), N_("SOURCE-BRANCH DEST-BRANCH DIR"), N_("merge one branch into a subdirectory in another branch"), - OPT_DATE % OPT_AUTHOR % OPT_MESSAGE % OPT_MSGFILE) + option::date % option::author % option::message % option::msgfile) { // this is a special merge operator, but very useful for people maintaining // "slightly disparate but related" trees. it does a one-way merge; less @@ -489,7 +489,7 @@ CMD(explicit_merge, N_("tree"), N_("LEFT-REVISION RIGHT-REVISION DEST-BRANCH"), N_("merge two explicitly given revisions, placing result in given branch"), - OPT_DATE % OPT_AUTHOR) + option::date % option::author) { revision_id left, right; string branch; @@ -532,7 +532,7 @@ } CMD(show_conflicts, N_("informative"), N_("REV REV"), N_("Show what conflicts would need to be resolved to merge the given revisions."), - OPT_BRANCH_NAME % OPT_DATE % OPT_AUTHOR) + option::branch_name % option::date % option::author) { if (args.size() != 2) throw usage(name); @@ -565,7 +565,7 @@ } CMD(heads, N_("tree"), "", N_("show unmerged head revisions of branch"), - OPT_BRANCH_NAME) + option::branch_name) { set heads; if (args.size() != 0) @@ -590,7 +590,7 @@ CMD(get_roster, N_("debug"), N_("REVID"), N_("dump the roster associated with the given REVID"), - OPT_NONE) + option::none) { if (args.size() != 1) throw usage(name); ============================================================ --- cmd_netsync.cc 431b5bb6daff4f8d8992eee7ff14a21512895b81 +++ cmd_netsync.cc 5854e5d663e78753bfce09d12c5874d89a713a29 @@ -93,7 +93,7 @@ CMD(push, N_("network"), N_("[ADDRESS[:PORTNUMBER] [PATTERN]]"), N_("push branches matching PATTERN to netsync server at ADDRESS"), - OPT_SET_DEFAULT % OPT_EXCLUDE % OPT_KEY_TO_PUSH) + option::set_default % option::exclude % option::key_to_push) { utf8 addr, include_pattern, exclude_pattern; process_netsync_args(name, args, addr, include_pattern, exclude_pattern, true, false, app); @@ -108,7 +108,7 @@ CMD(pull, N_("network"), N_("[ADDRESS[:PORTNUMBER] [PATTERN]]"), N_("pull branches matching PATTERN from netsync server at ADDRESS"), - OPT_SET_DEFAULT % OPT_EXCLUDE) + option::set_default % option::exclude) { utf8 addr, include_pattern, exclude_pattern; process_netsync_args(name, args, addr, include_pattern, exclude_pattern, true, false, app); @@ -122,7 +122,7 @@ CMD(sync, N_("network"), N_("[ADDRESS[:PORTNUMBER] [PATTERN]]"), N_("sync branches matching PATTERN with netsync server at ADDRESS"), - OPT_SET_DEFAULT % OPT_EXCLUDE % OPT_KEY_TO_PUSH) + option::set_default % option::exclude % option::key_to_push) { utf8 addr, include_pattern, exclude_pattern; process_netsync_args(name, args, addr, include_pattern, exclude_pattern, true, false, app); @@ -169,7 +169,7 @@ CMD_NO_WORKSPACE(serve, N_("network"), N_("PATTERN ..."), N_("serve the branches specified by PATTERNs to connecting clients"), - OPT_BIND % OPT_PIDFILE % OPT_EXCLUDE) + option::bind % option::pidfile % option::exclude) { if (args.size() < 1) throw usage(name); ============================================================ --- cmd_othervcs.cc 2a6c2ccd297e79ee652a1c7189e7d3c45de47c40 +++ cmd_othervcs.cc d4031c567c49093b03f3d8a2b525b4536ff569c5 @@ -6,7 +6,7 @@ N_("parse versions in RCS files\n" "this command doesn't reconstruct or import revisions." "you probably want cvs_import"), - OPT_BRANCH_NAME) + option::branch_name) { if (args.size() < 1) throw usage(name); @@ -20,7 +20,7 @@ CMD(cvs_import, N_("rcs"), N_("CVSROOT"), N_("import all versions in CVS repository"), - OPT_BRANCH_NAME) + option::branch_name) { if (args.size() != 1) throw usage(name); ============================================================ --- cmd_packet.cc 26b3d187c3a139599b7c50ba80c29f81c382dfdd +++ cmd_packet.cc f906375a6c7a3ccc384fecf3f83abbf31e81fac2 @@ -9,7 +9,7 @@ using std::cin; CMD(pubkey, N_("packet i/o"), N_("ID"), N_("write public key packet to stdout"), - OPT_NONE) + option::none) { if (args.size() != 1) throw usage(name); @@ -37,7 +37,7 @@ } CMD(privkey, N_("packet i/o"), N_("ID"), N_("write private key packet to stdout"), - OPT_NONE) + option::none) { if (args.size() != 1) throw usage(name); @@ -56,7 +56,7 @@ CMD(read, N_("packet i/o"), "[FILE1 [FILE2 [...]]]", N_("read packets from files or stdin"), - OPT_NONE) + option::none) { packet_db_writer dbw(app); size_t count = 0; ============================================================ --- cmd_ws_commit.cc 130ebf460f4770ca6b39dd7c5d2b8dbf39405656 +++ cmd_ws_commit.cc 5fa9b556de08d2750a569e98660ccb059a0a9551 @@ -36,7 +36,7 @@ CMD(revert, N_("workspace"), N_("[PATH]..."), N_("revert file(s), dir(s) or entire workspace (\".\")"), - OPT_DEPTH % OPT_EXCLUDE % OPT_MISSING) + option::depth % option::exclude % option::missing) { if (args.size() < 1) throw usage(name); @@ -147,7 +147,7 @@ CMD(disapprove, N_("review"), N_("REVISION"), N_("disapprove of a particular revision"), - OPT_BRANCH_NAME) + option::branch_name) { if (args.size() != 1) throw usage(name); @@ -197,7 +197,7 @@ CMD(add, N_("workspace"), N_("[PATH]..."), - N_("add files to workspace"), OPT_UNKNOWN) + N_("add files to workspace"), option::unknown) { if (!app.unknown && (args.size() < 1)) throw usage(name); @@ -223,7 +223,7 @@ } CMD(drop, N_("workspace"), N_("[PATH]..."), - N_("drop files from workspace"), OPT_EXECUTE % OPT_MISSING % OPT_RECURSIVE) + N_("drop files from workspace"), option::execute % option::missing % option::recursive) { if (!app.missing && (args.size() < 1)) throw usage(name); @@ -251,7 +251,7 @@ N_("SRC DEST\n" "SRC1 [SRC2 [...]] DEST_DIR"), N_("rename entries in the workspace"), - OPT_EXECUTE) + option::execute) { if (args.size() < 2) throw usage(name); @@ -278,7 +278,7 @@ "will be the root directory, and the directory that is currently the root\n" "directory will have name PUT_OLD.\n" "Using --execute is strongly recommended."), - OPT_EXECUTE) + option::execute) { if (args.size() != 2) throw usage(name); @@ -290,7 +290,7 @@ } CMD(status, N_("informative"), N_("[PATH]..."), N_("show status of workspace"), - OPT_DEPTH % OPT_EXCLUDE % OPT_BRIEF) + option::depth % option::exclude % option::brief) { roster_t old_roster, new_roster, restricted_roster; cset included, excluded; @@ -354,7 +354,7 @@ "If a revision is given, that's the one that will be checked out.\n" "Otherwise, it will be the head of the branch (given or implicit).\n" "If no directory is given, the branch name will be used as directory"), - OPT_BRANCH_NAME % OPT_REVISION) + option::branch_name % option::revision) { revision_id ident; system_path dir; @@ -479,7 +479,7 @@ CMD(attr, N_("workspace"), N_("set PATH ATTR VALUE\nget PATH [ATTR]\ndrop PATH [ATTR]"), N_("set, get or drop file attributes"), - OPT_NONE) + option::none) { if (args.size() < 2 || args.size() > 4) throw usage(name); @@ -572,8 +572,8 @@ CMD(commit, N_("workspace"), N_("[PATH]..."), N_("commit workspace to database"), - OPT_BRANCH_NAME % OPT_MESSAGE % OPT_MSGFILE % OPT_DATE % - OPT_AUTHOR % OPT_DEPTH % OPT_EXCLUDE) + option::branch_name % option::message % option::msgfile % option::date % + option::author % option::depth % option::exclude) { string log_message(""); bool log_message_given; @@ -794,7 +794,7 @@ CMD_NO_WORKSPACE(setup, N_("tree"), N_("[DIRECTORY]"), N_("setup a new workspace directory, default to current"), - OPT_BRANCH_NAME) + option::branch_name) { if (args.size() > 1) throw usage(name); @@ -814,7 +814,7 @@ } CMD(refresh_inodeprints, N_("tree"), "", N_("refresh the inodeprint cache"), - OPT_NONE) + option::none) { app.require_workspace(); enable_inodeprints(); ============================================================ --- commands.cc a02d61685a3807368a2e1ec1fed79ea5f342ea79 +++ commands.cc 593ec7c6c510ce95545ff592ddbbdb3de4a302db @@ -15,7 +15,7 @@ #include "cert.hh" #include "cmd.hh" -// + // this file defines the task-oriented "top level" commands which can be // issued as part of a monotone command line. the command line can only // have one such command on it, followed by a vector of strings which are its @@ -25,7 +25,7 @@ // we might expose this blunt command interface to scripting someday. but // not today. -namespace commands +namespace commands { using std::map; // This must be a pointer. @@ -34,13 +34,13 @@ // guarantee about what order they'll be initialized in. So have this // be something that doesn't get automatic initialization, and initialize // it ourselves the first time we use it. - static map *cmds; + static map * cmds; command::command(string const & n, - string const & g, - string const & p, - string const & d, - bool u, - command_opts const & o) + string const & g, + string const & p, + string const & d, + bool u, + command_opts const & o) : name(n), cmdgroup(g), params(p), desc(d), use_workspace_options(u), options(o) { @@ -213,7 +213,7 @@ } } - set command_options(string const & cmd) + set< shared_ptr > command_options(string const & cmd) { if ((*cmds).find(cmd) != (*cmds).end()) { @@ -221,15 +221,13 @@ } else { - return set(); + return set< shared_ptr >(); } } - - const no_opts OPT_NONE = no_opts(); } //////////////////////////////////////////////////////////////////////// -CMD(help, N_("informative"), N_("command [ARGS...]"), N_("display command help"), OPT_NONE) +CMD(help, N_("informative"), N_("command [ARGS...]"), N_("display command help"), option::none) { if (args.size() < 1) throw usage(""); @@ -433,12 +431,12 @@ N(app.message().length() == 0 || app.message_file().length() == 0, F("--message and --message-file are mutually exclusive")); - if (app.is_explicit_option(OPT_MESSAGE)) + if (app.is_explicit_option(option::message())) { log_message = app.message(); given = true; } - else if (app.is_explicit_option(OPT_MSGFILE)) + else if (app.is_explicit_option(option::msgfile())) { data dat; read_data_for_command_line(app.message_file(), dat); ============================================================ --- commands.hh a04625b93f41cb792463b71062a1265e0d85a19f +++ commands.hh 3911eb2fdb483e56d204d4171178066b97991e4c @@ -9,7 +9,12 @@ #include #include #include +#include +#include +using boost::shared_ptr; +using boost::program_options::option_description; + // this defines a global function which processes command-line-like things, // possibly from the command line and possibly internal scripting if we ever // bind tcl or lua or something in here @@ -27,7 +32,7 @@ void explain_usage(std::string const & cmd, std::ostream & out); std::string complete_command(std::string const & cmd); int process(app_state & app, std::string const & cmd, std::vector const & args); - std::set command_options(std::string const & cmd); + std::set< shared_ptr > command_options(std::string const & cmd); }; #endif ============================================================ --- configure.ac 9a0e730650f554caa768ae612c5583b69bc10330 +++ configure.ac f7b30db05b4fe83a334c870aabaea6fa833035b4 @@ -219,6 +219,17 @@ [AC_MSG_FAILURE([libboost_regex failure])]) +LIBS="-lboost_program_options${BOOST_SUFFIX} $LIBS" +AC_MSG_CHECKING(for the libboost_program_options${BOOST_SUFFIX} library) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + using namespace boost::program_options; +]], +[[options_description od("foo"); od.add_options()("test", "a test option");]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_FAILURE([libboost_program_options failure])]) + + # check for static boost option AC_ARG_ENABLE(static-boost, AS_HELP_STRING([--enable-static-boost@<:@=prefix@:>@], @@ -349,39 +360,6 @@ fi AC_SUBST(SQLITE_CPPFLAGS) -########## -# We use our bundled popt unconditionally, because the external one has -# serious bugs that we can't live with. Maybe some time in the future... -# The following was simply taken from the configure.in that comes with popt. -#AC_LANG_PUSH(C) -AC_CHECK_HEADERS([alloca.h float.h libintl.h mcheck.h]) -AC_MSG_CHECKING(for /usr/ucblib in LIBS) -if test -d /usr/ucblib ; then - if test "$build" = "mips-sni-sysv4" ; then - addlib /usr/ccs/lib -lc - fi - - addlib /usr/ucblib - - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi -AC_CHECK_FUNCS(strerror strptime mtrace getuid geteuid) -AC_CHECK_FUNC(setreuid, [], [ - AC_CHECK_LIB(ucb, setreuid, [if echo $LIBS | grep -- -lucb >/dev/null ;then :; else LIBS="$LIBS -lc -lucb" USEUCB=y;fi]) -]) - -POPT_SOURCE_PATH="`pwd`" -AC_DEFINE_UNQUOTED(POPT_SOURCE_PATH, "$POPT_SOURCE_PATH", - [Full path to popt top_sourcedir.]) -AC_SUBST(POPT_SOURCE_PATH) -#AC_LANG_POP() - - -########## - - # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/file.h sys/socket.h sys/time.h termios.h unistd.h]) ============================================================ --- monotone.cc 7ce7990a7e4ebb99f1980ccdeca7a6e1b297ea7b +++ monotone.cc 5adef7e9f83b109da2a223597c0eaf041ac12268 @@ -6,7 +6,6 @@ #include "config.h" -#include "popt/popt.h" #include #include #include @@ -19,6 +18,8 @@ #include #include +#include +#include #include "botan/botan.h" @@ -35,79 +36,99 @@ #include "options.hh" #include "paths.hh" +using std::cout; +using std::string; +using std::ostringstream; +using std::set; +using std::vector; +using std::ios_base; +using boost::shared_ptr; +namespace po = boost::program_options; + // main option processing and exception handling code -using namespace std; +// options are split into two categories. the first covers global options, +// which globally affect program behaviour. the second covers options +// specific to one or more commands. these command-specific options are +// defined in a single group, with the intent that any command-specific +// option means the same thing for any command that uses it. -char * argstr = NULL; -long arglong = 0; +namespace option +{ + using boost::program_options::value; + using boost::program_options::option_description; + using boost::program_options::options_description; -// Options are split between two tables. The first one is command-specific -// options (hence the `c' in `coptions'). The second is the global one -// with options that aren't tied to specific commands. -// -// the intent is to ensure that any command specific options mean the same -// thing to all commands that use them + options_description global_options; + options_description specific_options; -struct poptOption coptions[] = + no_option none; + + po::value_semantic * + null_value() { - {"branch", 'b', POPT_ARG_STRING, &argstr, OPT_BRANCH_NAME, gettext_noop("select branch cert for operation"), NULL}, - {"revision", 'r', POPT_ARG_STRING, &argstr, OPT_REVISION, gettext_noop("select revision id for operation"), NULL}, - {"message", 'm', POPT_ARG_STRING, &argstr, OPT_MESSAGE, gettext_noop("set commit changelog message"), NULL}, - {"message-file", 0, POPT_ARG_STRING, &argstr, OPT_MSGFILE, gettext_noop("set filename containing commit changelog message"), NULL}, - {"date", 0, POPT_ARG_STRING, &argstr, OPT_DATE, gettext_noop("override date/time for commit"), NULL}, - {"author", 0, POPT_ARG_STRING, &argstr, OPT_AUTHOR, gettext_noop("override author for commit"), NULL}, - {"depth", 0, POPT_ARG_LONG, &arglong, OPT_DEPTH, gettext_noop("limit the number of levels of directories to descend"), NULL}, - {"last", 0, POPT_ARG_LONG, &arglong, OPT_LAST, gettext_noop("limit log output to the last number of entries"), NULL}, - {"next", 0, POPT_ARG_LONG, &arglong, OPT_NEXT, gettext_noop("limit log output to the next number of entries"), NULL}, - {"pid-file", 0, POPT_ARG_STRING, &argstr, OPT_PIDFILE, gettext_noop("record process id of server"), NULL}, - {"brief", 0, POPT_ARG_NONE, NULL, OPT_BRIEF, gettext_noop("print a brief version of the normal output"), NULL}, - {"diffs", 0, POPT_ARG_NONE, NULL, OPT_DIFFS, gettext_noop("print diffs along with logs"), NULL}, - {"no-merges", 0, POPT_ARG_NONE, NULL, OPT_NO_MERGES, gettext_noop("exclude merges when printing logs"), NULL}, - {"set-default", 0, POPT_ARG_NONE, NULL, OPT_SET_DEFAULT, gettext_noop("use the current arguments as the future default"), NULL}, - {"exclude", 0, POPT_ARG_STRING, &argstr, OPT_EXCLUDE, gettext_noop("leave out anything described by its argument"), NULL}, - {"unified", 0, POPT_ARG_NONE, NULL, OPT_UNIFIED_DIFF, gettext_noop("use unified diff format"), NULL}, - {"context", 0, POPT_ARG_NONE, NULL, OPT_CONTEXT_DIFF, gettext_noop("use context diff format"), NULL}, - {"external", 0, POPT_ARG_NONE, NULL, OPT_EXTERNAL_DIFF, gettext_noop("use external diff hook for generating diffs"), NULL}, - {"diff-args", 0, POPT_ARG_STRING, &argstr, OPT_EXTERNAL_DIFF_ARGS, gettext_noop("argument to pass external diff hook"), NULL}, - {"execute", 'e', POPT_ARG_NONE, NULL, OPT_EXECUTE, gettext_noop("perform the associated file operation"), NULL}, - {"bind", 0, POPT_ARG_STRING, &argstr, OPT_BIND, gettext_noop("address:port to listen on (default :4691)"), NULL}, - {"missing", 0, POPT_ARG_NONE, NULL, OPT_MISSING, gettext_noop("perform the operations for files missing from workspace"), NULL}, - {"unknown", 0, POPT_ARG_NONE, NULL, OPT_UNKNOWN, gettext_noop("perform the operations for unknown files from workspace"), NULL}, - {"key-to-push", 0, POPT_ARG_STRING, &argstr, OPT_KEY_TO_PUSH, gettext_noop("push the specified key even if it hasn't signed anything"), NULL}, - {"drop-attr", 0, POPT_ARG_STRING, &argstr, OPT_DROP_ATTR, gettext_noop("when rosterifying, drop attrs entries with the given key"), NULL}, - {"no-files", 0, POPT_ARG_NONE, NULL, OPT_NO_FILES, gettext_noop("exclude files when printing logs"), NULL}, - {"recursive", 'R', POPT_ARG_NONE, NULL, OPT_RECURSIVE, gettext_noop("also operate on the contents of any listed directories"), NULL}, - { NULL, 0, 0, NULL, 0, NULL, NULL } - }; + return new po::untyped_value(true); + } -struct poptOption options[] = - { - // Use the coptions table as well. - { NULL, 0, POPT_ARG_INCLUDE_TABLE, coptions, 0, NULL, NULL }, + // the options below are also declared in options.hh for other users. the + // GOPT and COPT defines are just to reduce duplication, maybe there is a + // cleaner way to do the same thing? - {"debug", 0, POPT_ARG_NONE, NULL, OPT_DEBUG, gettext_noop("print debug log to stderr while running"), NULL}, - {"dump", 0, POPT_ARG_STRING, &argstr, OPT_DUMP, gettext_noop("file to dump debugging log to, on failure"), NULL}, - {"log", 0, POPT_ARG_STRING, &argstr, OPT_LOG, gettext_noop("file to write the log to"), NULL}, - {"quiet", 0, POPT_ARG_NONE, NULL, OPT_QUIET, gettext_noop("suppress verbose, informational and progress messages"), NULL}, - {"reallyquiet", 0, POPT_ARG_NONE, NULL, OPT_REALLYQUIET, gettext_noop("suppress warning, verbose, informational and progress messages"), NULL}, - {"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, gettext_noop("display help message"), NULL}, - {"version", 0, POPT_ARG_NONE, NULL, OPT_VERSION, gettext_noop("print version number, then exit"), NULL}, - {"full-version", 0, POPT_ARG_NONE, NULL, OPT_FULL_VERSION, gettext_noop("print detailed version number, then exit"), NULL}, - {"xargs", '@', POPT_ARG_STRING, &argstr, OPT_ARGFILE, gettext_noop("insert command line arguments taken from the given file"), NULL}, - {"ticker", 0, POPT_ARG_STRING, &argstr, OPT_TICKER, gettext_noop("set ticker style (count|dot|none)"), NULL}, - {"nostd", 0, POPT_ARG_NONE, NULL, OPT_NOSTD, gettext_noop("do not load standard lua hooks"), NULL}, - {"norc", 0, POPT_ARG_NONE, NULL, OPT_NORC, gettext_noop("do not load ~/.monotone/monotonerc or _MTN/monotonerc lua files"), NULL}, - {"rcfile", 0, POPT_ARG_STRING, &argstr, OPT_RCFILE, gettext_noop("load extra rc file"), NULL}, - {"key", 'k', POPT_ARG_STRING, &argstr, OPT_KEY_NAME, gettext_noop("set key for signatures"), NULL}, - {"db", 'd', POPT_ARG_STRING, &argstr, OPT_DB_NAME, gettext_noop("set name of database"), NULL}, - {"root", 0, POPT_ARG_STRING, &argstr, OPT_ROOT, gettext_noop("limit search for workspace to specified root"), NULL}, - {"verbose", 0, POPT_ARG_NONE, NULL, OPT_VERBOSE, gettext_noop("verbose completion output"), NULL}, - {"keydir", 0, POPT_ARG_STRING, &argstr, OPT_KEY_DIR, gettext_noop("set location of key store"), NULL}, - {"confdir", 0, POPT_ARG_STRING, &argstr, OPT_CONF_DIR, gettext_noop("set location of configuration directory"), NULL}, - { NULL, 0, 0, NULL, 0, NULL, NULL } - }; + // global options +#define GOPT(NAME, OPT, TYPE, DESC) global NAME(new option_description(OPT, TYPE, DESC)) + GOPT(debug, "debug", null_value(), gettext_noop("print debug log to stderr while running")); + GOPT(dump, "dump", value(), gettext_noop("file to dump debugging log to, on failure")); + GOPT(log, "log", value(), gettext_noop("file to write the log to")); + GOPT(quiet, "quiet", null_value(), gettext_noop("suppress verbose, informational and progress messages")); + GOPT(reallyquiet, "reallyquiet", null_value(), gettext_noop("suppress warning, verbose, informational and progress messages")); + GOPT(help, "help,h", null_value(), gettext_noop("display help message")); + GOPT(version, "version", null_value(), gettext_noop("print version number, then exit")); + GOPT(full_version, "full-version", null_value(), gettext_noop("print detailed version number, then exit")); + GOPT(argfile, "xargs,@", value(), gettext_noop("insert command line arguments taken from the given file")); + GOPT(ticker, "ticker", value(), gettext_noop("set ticker style (count|dot|none)")); + GOPT(nostd, "nostd", null_value(), gettext_noop("do not load standard lua hooks")); + GOPT(norc, "norc", null_value(), gettext_noop("do not load ~/.monotone/monotonerc or _MTN/monotonerc lua files")); + GOPT(rcfile, "rcfile", value(), gettext_noop("load extra rc file")); + GOPT(key_name, "key,k", value(), gettext_noop("set key for signatures")); + GOPT(db_name, "db,d", value(), gettext_noop("set name of database")); + GOPT(root, "root", value(), gettext_noop("limit search for workspace to specified root")); + GOPT(verbose, "verbose", null_value(), gettext_noop("verbose completion output")); + GOPT(key_dir, "keydir", value(), gettext_noop("set location of key store")); + GOPT(conf_dir, "confdir", value(), gettext_noop("set location of configuration directory")); +#undef OPT + // command-specific options +#define COPT(NAME, OPT, TYPE, DESC) specific NAME(new option_description(OPT, TYPE, DESC)) + COPT(author, "author", value(), gettext_noop("override author for commit")); + COPT(bind, "bind", value(), gettext_noop("address:port to listen on (default :4691)")); + COPT(branch_name, "branch,b", value(), gettext_noop("select branch cert for operation")); + COPT(brief, "brief", null_value(), gettext_noop("print a brief version of the normal output")); + COPT(context_diff, "context", null_value(), gettext_noop("use context diff format")); + COPT(date, "date", value(), gettext_noop("override date/time for commit")); + COPT(depth, "depth", value(), gettext_noop("limit the number of levels of directories to descend")); + COPT(diffs, "diffs", null_value(), gettext_noop("print diffs along with logs")); + COPT(drop_attr, "drop-attr", value(), gettext_noop("when rosterifying, drop attrs entries with the given key")); + COPT(exclude, "exclude", value(), gettext_noop("leave out anything described by its argument")); + COPT(execute, "execute,e", null_value(), gettext_noop("perform the associated file operation")); + COPT(external_diff, "external", null_value(), gettext_noop("use external diff hook for generating diffs")); + COPT(external_diff_args, "diff-args", value(), gettext_noop("argument to pass external diff hook")); + COPT(key_to_push, "key-to-push", value(), gettext_noop("push the specified key even if it hasn't signed anything")); + COPT(last, "last", value(), gettext_noop("limit log output to the last number of entries")); + COPT(message, "message,m", value(), gettext_noop("set commit changelog message")); + COPT(missing, "missing", null_value(), gettext_noop("perform the operations for files missing from workspace")); + COPT(msgfile, "message-file", value(), gettext_noop("set filename containing commit changelog message")); + COPT(next, "next", value(), gettext_noop("limit log output to the next number of entries")); + COPT(no_files, "no-files", null_value(), gettext_noop("exclude files when printing logs")); + COPT(no_merges, "no-merges", null_value(), gettext_noop("exclude merges when printing logs")); + COPT(pidfile, "pid-file", value(), gettext_noop("record process id of server")); + COPT(recursive, "recursive,R", null_value(), gettext_noop("also operate on the contents of any listed directories")); + COPT(revision, "revision,r", value(), gettext_noop("select revision id for operation")); + COPT(set_default, "set-default", null_value(), gettext_noop("use the current arguments as the future default")); + COPT(unified_diff, "unified", null_value(), gettext_noop("use unified diff format")); + COPT(unknown, "unknown", null_value(), gettext_noop("perform the operations for unknown files from workspace")); +#undef COPT +} + // there are 3 variables which serve as roots for our system. // // "global_sanity" is a global object, which contains the error logging @@ -132,17 +153,17 @@ // in other words, this program should *never* unexpectedly terminate // without dumping some diagnostics. -void -dumper() +void +dumper() { if (!global_sanity.clean_shutdown) global_sanity.dump_buffer(); - + Botan::Init::deinitialize(); } -struct +struct utf8_argv { int argc; @@ -165,7 +186,7 @@ } } - ~utf8_argv() + ~utf8_argv() { if (argv != NULL) { @@ -173,21 +194,11 @@ if (argv[i] != NULL) free(argv[i]); free(argv); - } + } } }; -// Stupid type system tricks: to use a cleanup_ptr, we need to know the return -// type of the cleanup function. But popt silently changed the return type of -// poptFreeContext at some point, I guess because they thought it would be -// "backwards compatible". We don't actually _use_ the return value of -// poptFreeContext, so this little wrapper works. -static void -my_poptFreeContext(poptContext con) -{ - poptFreeContext(con); -} - +#if 0 // FIXME! need b::po equiv. // Read arguments from a file. The special file '-' means stdin. // Returned value must be free()'d, after arg parsing has completed. static void @@ -223,23 +234,9 @@ free(argv); } +#endif -static string -coption_string(int o) -{ - char buf[2] = { 0,0 }; - for(struct poptOption *opt = coptions; opt->val; opt++) - if (o == opt->val) - { - buf[0] = opt->shortName; - return opt->longName - ? string("--") + string(opt->longName) - : string("-") + string(buf); - } - return string(); -} - -int +int cpp_main(int argc, char ** argv) { int ret = 0; @@ -247,7 +244,6 @@ atexit(&dumper); // go-go gadget i18n - setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); @@ -260,9 +256,9 @@ // set up some marked strings, so even if our logbuf overflows, we'll get // this data in a crash. - std::string cmdline_string; + string cmdline_string; { - std::ostringstream cmdline_ss; + ostringstream cmdline_ss; for (int i = 0; i < argc; ++i) { if (i) @@ -274,313 +270,368 @@ 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)); + 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; + 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(); utf8_argv uv(argc, argv); // find base name of executable - string prog_path = fs::path(uv.argv[0]).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); - // prepare for arg parsing - - cleanup_ptr - ctx(poptGetContext(NULL, argc, (char const **) uv.argv, options, 0), - &my_poptFreeContext); - - set local_options; - for (poptOption *opt = coptions; opt->val; opt++) - local_options.insert(opt->val); - // process main program options - - int opt; bool requested_help = false; - set used_local_options; - poptSetOtherOptionHelp(ctx(), _("[OPTION...] command [ARGS...]\n")); - try { app_state app; app.set_prog_name(prog_name); - while ((opt = poptGetNextOpt(ctx())) > 0) + // 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); + + po::parsed_options parsed = po::command_line_parser(argc, uv.argv) + .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 + string cmd; + vector positional_args; + if (vm.count("all_positional_args")) { - if (local_options.find(opt) != local_options.end()) - used_local_options.insert(opt); + positional_args = vm["all_positional_args"].as< vector >(); + cmd = commands::complete_command(idx(positional_args, 0)); + positional_args.erase(positional_args.begin()); + } - switch(opt) - { - case OPT_DEBUG: - global_sanity.set_debug(); - break; + // build an options_description specific to this cmd. + set< shared_ptr > cmd_options; + cmd_options = commands::command_options(cmd); + po::options_description cmd_options_desc; + set< shared_ptr >::const_iterator it; + for (it = cmd_options.begin(); it != cmd_options.end(); ++it) + cmd_options_desc.add(*it); - case OPT_QUIET: - global_sanity.set_quiet(); - ui.set_tick_writer(new tick_write_nothing); - break; + po::options_description all_for_this_cmd; + all_for_this_cmd.add(option::global_options); + all_for_this_cmd.add(cmd_options_desc); - case OPT_REALLYQUIET: - global_sanity.set_reallyquiet(); - ui.set_tick_writer(new tick_write_nothing); - break; + // reparse arguments using specific options. + parsed = po::command_line_parser(argc, uv.argv) + .options(all_for_this_cmd) + .run(); + po::store(parsed, vm); + po::notify(vm); - case OPT_NOSTD: - app.set_stdhooks(false); - break; + if (vm.count(option::debug())) + { + global_sanity.set_debug(); + } - case OPT_NORC: - app.set_rcfiles(false); - break; + if (vm.count(option::quiet())) + { + global_sanity.set_quiet(); + ui.set_tick_writer(new tick_write_nothing); + } - case OPT_VERBOSE: - app.set_verbose(true); - break; + if (vm.count(option::reallyquiet())) + { + global_sanity.set_reallyquiet(); + ui.set_tick_writer(new tick_write_nothing); + } - case OPT_RCFILE: - app.add_rcfile(string(argstr)); - break; + if (vm.count(option::nostd())) + { + app.set_stdhooks(false); + } - case OPT_DUMP: - global_sanity.filename = system_path(argstr); - break; + if (vm.count(option::norc())) + { + app.set_rcfiles(false); + } - case OPT_LOG: - ui.redirect_log_to(system_path(argstr)); - break; + if (vm.count(option::verbose())) + { + app.set_verbose(true); + } - case OPT_DB_NAME: - app.set_database(system_path(argstr)); - break; + if (vm.count(option::rcfile())) + { + app.add_rcfile(vm[option::rcfile()].as()); + } - case OPT_KEY_DIR: - app.set_key_dir(system_path(argstr)); - break; + if (vm.count(option::dump())) + { + global_sanity.filename = system_path(vm[option::dump()].as()); + } - case OPT_CONF_DIR: - app.set_confdir(system_path(argstr)); - break; + if (vm.count(option::log())) + { + ui.redirect_log_to(system_path(vm[option::log()].as())); + } - case OPT_TICKER: - if (string(argstr) == "none" || global_sanity.quiet) - ui.set_tick_writer(new tick_write_nothing); - else if (string(argstr) == "dot") - ui.set_tick_writer(new tick_write_dot); - else if (string(argstr) == "count") - ui.set_tick_writer(new tick_write_count); - else - requested_help = true; - break; + if (vm.count(option::db_name())) + { + app.set_database(system_path(vm[option::db_name()].as())); + } - case OPT_KEY_NAME: - app.set_signing_key(string(argstr)); - break; + if (vm.count(option::key_dir())) + { + app.set_key_dir(system_path(vm[option::key_dir()].as())); + } - case OPT_BRANCH_NAME: - app.set_branch(string(argstr)); - app.set_is_explicit_option(OPT_BRANCH_NAME); - break; + if (vm.count(option::conf_dir())) + { + app.set_confdir(system_path(vm[option::conf_dir()].as())); + } - case OPT_VERSION: - print_version(); - global_sanity.clean_shutdown = true; - return 0; + if (vm.count(option::ticker())) + { + string ticker = vm[option::ticker()].as(); + if (ticker == "none" || global_sanity.quiet) + ui.set_tick_writer(new tick_write_nothing); + else if (ticker == "dot") + ui.set_tick_writer(new tick_write_dot); + else if (ticker == "count") + ui.set_tick_writer(new tick_write_count); + else + requested_help = true; + } - case OPT_FULL_VERSION: - print_full_version(); - global_sanity.clean_shutdown = true; - return 0; + if (vm.count(option::key_name())) + { + app.set_signing_key(vm[option::key_name()].as()); + } - case OPT_REVISION: - app.add_revision(string(argstr)); - break; + if (vm.count(option::branch_name())) + { + app.set_branch(vm[option::branch_name()].as()); + app.set_is_explicit_option(option::branch_name()); + } - case OPT_MESSAGE: - app.set_message(string(argstr)); - app.set_is_explicit_option(OPT_MESSAGE); - break; + if (vm.count(option::version())) + { + print_version(); + global_sanity.clean_shutdown = true; + return 0; + } - case OPT_MSGFILE: - app.set_message_file(string(argstr)); - app.set_is_explicit_option(OPT_MSGFILE); - break; + if (vm.count(option::full_version())) + { + print_full_version(); + global_sanity.clean_shutdown = true; + return 0; + } - case OPT_DATE: - app.set_date(string(argstr)); - break; + if (vm.count(option::revision())) + { + app.add_revision(vm[option::revision()].as()); + } - case OPT_AUTHOR: - app.set_author(string(argstr)); - break; + if (vm.count(option::message())) + { + app.set_message(vm[option::message()].as()); + app.set_is_explicit_option(option::message()); + } - case OPT_ROOT: - app.set_root(system_path(argstr)); - break; + if (vm.count(option::msgfile())) + { + app.set_message_file(vm[option::msgfile()].as()); + app.set_is_explicit_option(option::msgfile()); + } - case OPT_LAST: - app.set_last(arglong); - break; + if (vm.count(option::date())) + { + app.set_date(vm[option::date()].as()); + } - case OPT_NEXT: - app.set_next(arglong); - break; + if (vm.count(option::author())) + { + app.set_author(vm[option::author()].as()); + } - case OPT_DEPTH: - app.set_depth(arglong); - break; + if (vm.count(option::root())) + { + app.set_root(system_path(vm[option::root()].as())); + } - case OPT_BRIEF: - global_sanity.set_brief(); - break; + if (vm.count(option::last())) + { + app.set_last(vm[option::last()].as()); + } - case OPT_DIFFS: - app.diffs = true; - break; + if (vm.count(option::next())) + { + app.set_next(vm[option::next()].as()); + } - case OPT_NO_MERGES: - app.no_merges = true; - break; + if (vm.count(option::depth())) + { + app.set_depth(vm[option::depth()].as()); + } - case OPT_SET_DEFAULT: - app.set_default = true; - break; + if (vm.count(option::brief())) + { + global_sanity.set_brief(); + } - case OPT_EXCLUDE: - app.add_exclude(utf8(string(argstr))); - break; + if (vm.count(option::diffs())) + { + app.diffs = true; + } - case OPT_PIDFILE: - app.set_pidfile(system_path(argstr)); - break; + if (vm.count(option::no_merges())) + { + app.no_merges = true; + } - case OPT_ARGFILE: - my_poptStuffArgFile(ctx(), utf8(string(argstr))); - break; + if (vm.count(option::set_default())) + { + app.set_default = true; + } - case OPT_UNIFIED_DIFF: - app.set_diff_format(unified_diff); - break; + if (vm.count(option::exclude())) + { + app.add_exclude(utf8(vm[option::exclude()].as())); + } - case OPT_CONTEXT_DIFF: - app.set_diff_format(context_diff); - break; + if (vm.count(option::pidfile())) + { + app.set_pidfile(system_path(vm[option::pidfile()].as())); + } - case OPT_EXTERNAL_DIFF: - app.set_diff_format(external_diff); - break; - - case OPT_EXTERNAL_DIFF_ARGS: - app.set_diff_args(utf8(string(argstr))); - break; + if (vm.count(option::argfile())) + { +#if 0 + // FIXME! + my_poptStuffArgFile(ctx(), utf8(string(argstr))); +#endif + } - case OPT_EXECUTE: - app.execute = true; - break; + if (vm.count(option::unified_diff())) + { + app.set_diff_format(unified_diff); + } - case OPT_BIND: + if (vm.count(option::context_diff())) + { + app.set_diff_format(context_diff); + } + + if (vm.count(option::external_diff())) + { + app.set_diff_format(external_diff); + } + + if (vm.count(option::external_diff_args())) + { + app.set_diff_args(utf8(vm[option::external_diff_args()].as())); + } + + if (vm.count(option::execute())) + { + app.execute = true; + } + + if (vm.count(option::bind())) + { + { + string arg = vm[option::bind()].as(); + string addr_part, port_part; + size_t l_colon = arg.find(':'); + size_t r_colon = arg.rfind(':'); + + // not an ipv6 address, as that would have at least two colons + if (l_colon == r_colon) { - std::string arg(argstr); - std::string addr_part, port_part; - size_t l_colon = arg.find(':'); - size_t r_colon = arg.rfind(':'); - - // not an ipv6 address, as that would have at least two colons - if (l_colon == r_colon) + addr_part = (r_colon == string::npos ? arg : arg.substr(0, r_colon)); + port_part = (r_colon == string::npos ? "" : arg.substr(r_colon+1, arg.size() - r_colon)); + } + else + { + // IPv6 addresses have a port specified in the style: [2001:388:0:13::]:80 + size_t squareb = arg.rfind(']'); + if ((arg.find('[') == 0) && (squareb != string::npos)) { - addr_part = (r_colon == std::string::npos ? arg : arg.substr(0, r_colon)); - port_part = (r_colon == std::string::npos ? "" : arg.substr(r_colon+1, arg.size() - r_colon)); + if (squareb < r_colon) + port_part = (r_colon == string::npos ? "" : arg.substr(r_colon+1, arg.size() - r_colon)); + else + port_part = ""; + addr_part = (squareb == string::npos ? arg.substr(1, arg.size()) : arg.substr(1, squareb-1)); } else - { - // IPv6 addresses have a port specified in the style: [2001:388:0:13::]:80 - size_t squareb = arg.rfind(']'); - if ((arg.find('[') == 0) && (squareb != std::string::npos)) - { - if (squareb < r_colon) - port_part = (r_colon == std::string::npos ? "" : arg.substr(r_colon+1, arg.size() - r_colon)); - else - port_part = ""; - addr_part = (squareb == std::string::npos ? arg.substr(1, arg.size()) : arg.substr(1, squareb-1)); - } - else - { - addr_part = arg; - port_part = ""; - } + { + addr_part = arg; + port_part = ""; } - app.bind_address = utf8(addr_part); - app.bind_port = utf8(port_part); } - app.set_is_explicit_option(OPT_BIND); - break; + app.bind_address = utf8(addr_part); + app.bind_port = utf8(port_part); + } + app.set_is_explicit_option(option::bind()); + } - case OPT_MISSING: - app.missing = true; - break; + if (vm.count(option::missing())) + { + app.missing = true; + } - case OPT_UNKNOWN: - app.unknown = true; - break; + if (vm.count(option::unknown())) + { + app.unknown = true; + } - case OPT_KEY_TO_PUSH: - { - app.add_key_to_push(string(argstr)); - } - break; + if (vm.count(option::key_to_push())) + { + app.add_key_to_push(vm[option::key_to_push()].as()); + } - case OPT_DROP_ATTR: - app.attrs_to_drop.insert(string(argstr)); - break; + if (vm.count(option::drop_attr())) + { + app.attrs_to_drop.insert(vm[option::drop_attr()].as()); + } - case OPT_NO_FILES: - app.no_files = true; - break; - - case OPT_RECURSIVE: - app.set_recursive(); - break; - - case OPT_HELP: - default: - requested_help = true; - break; - } + if (vm.count(option::no_files())) + { + app.no_files = true; } - // verify that there are no errors in the command line + if (vm.count(option::recursive())) + { + app.set_recursive(); + } - N(opt == -1, - F("syntax error near the \"%s\" option: %s") % - poptBadOption(ctx(), POPT_BADOPTION_NOALIAS) % poptStrerror(opt)); - - // complete the command if necessary - - string cmd; - if (poptPeekArg(ctx())) + if (vm.count(option::help())) { - cmd = commands::complete_command(poptGetArg(ctx())); + requested_help = true; } // stop here if they asked for help - if (requested_help) { throw usage(cmd); // cmd may be empty, and that's fine. @@ -592,69 +643,54 @@ // from _MTN/options happens later. // Certain commands may subsequently require a workspace or fail // if we didn't find one at this point. - app.allow_workspace(); - // main options processed, now invoke the + // main options processed, now invoke the // sub-command w/ remaining args - if (cmd.empty()) { throw usage(""); } else { - // Make sure the local options used are really used by the - // given command. - set command_options = commands::command_options(cmd); - for (set::const_iterator i = used_local_options.begin(); - i != used_local_options.end(); ++i) - N(command_options.find(*i) != command_options.end(), - F("monotone %s doesn't use the option %s") - % cmd % coption_string(*i)); - - vector args; - while(poptPeekArg(ctx())) - { - args.push_back(utf8(string(poptGetArg(ctx())))); - } + vector args(positional_args.begin(), positional_args.end()); ret = commands::process(app, cmd, args); } } + catch (po::ambiguous_option const & e) + { + 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)); + } + 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. - set command_options = commands::command_options(u.which); - int count = 0; - for (poptOption *o = coptions; o->val != 0; o++) + set< shared_ptr > cmd_options; + cmd_options = commands::command_options(u.which); + + unsigned count = 0; + po::options_description cmd_options_desc; + set< shared_ptr >::const_iterator it; + for (it = cmd_options.begin(); it != cmd_options.end(); ++it, ++count) + cmd_options_desc.add(*it); + + cout << F("Usage: %s [OPTION...] command [ARG...]") % prog_name << "\n\n"; + cout << option::global_options << "\n"; + + if (count > 0) { - if (command_options.find(o->val) != command_options.end()) - { - o->argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; - L(FL("Removed 'hidden' from option # %d\n") % o->argInfo); - count++; - } - else - { - o->argInfo |= POPT_ARGFLAG_DOC_HIDDEN; - L(FL("Added 'hidden' to option # %d\n") % o->argInfo); - } + cout << F("Options specific to '%s %s':") % prog_name % u.which << "\n\n"; + cout << cmd_options_desc << "\n"; } - free((void *)options[0].descrip); options[0].descrip = NULL; - if (count != 0) - { - ostringstream sstr; - sstr << F("Options specific to '%s %s':") - % prog_name % u.which; - options[0].descrip = strdup(sstr.str().c_str()); - options[0].argInfo |= POPT_ARGFLAG_DOC_HIDDEN; - L(FL("Added 'hidden' to option # %d\n") % options[0].argInfo); - } - - poptPrintHelp(ctx(), stdout, 0); - cout << endl; commands::explain_usage(u.which, cout); global_sanity.clean_shutdown = true; return 2; @@ -666,7 +702,7 @@ global_sanity.clean_shutdown = true; return 1; } - catch (std::ios_base::failure const & ex) + catch (ios_base::failure const & ex) { global_sanity.clean_shutdown = true; return 1; ============================================================ --- options.hh a093ddbe1d7f14fa737498deeecd16b099ea45d7 +++ options.hh a1618c597c735f96615340df71f5ae77a54634d3 @@ -1,57 +1,100 @@ +#ifndef __OPTIONS_HH__ +#define __OPTIONS_HH__ + // -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*- // copyright (C) 2002, 2003 graydon hoare // copyright (C) 2005 Richard Levitte +// copyright (C) 2006 Matthew Gregan // all rights reserved. // licensed to the public under the terms of the GNU GPL (>= 2) // see the file COPYING for details -#include "popt/popt.h" +#include +#include +namespace option +{ + using boost::program_options::option_description; + using boost::program_options::options_description; + using boost::shared_ptr; + + extern options_description global_options; + extern options_description specific_options; + + struct option + { + char const * operator()() { return o->long_name().c_str(); } + operator shared_ptr () { return o; } + protected: + option(option_description * p) : o(p) {} + shared_ptr o; + }; + + struct global : public option + { + global(option_description * p) : option(p) { global_options.add(o); } + }; + + struct specific : public option + { + specific(option_description * p) : option(p) { specific_options.add(o); } + }; + + struct no_option + { + }; + + extern no_option none; + + // global options + extern global argfile; + extern global conf_dir; + extern global db_name; + extern global debug; + extern global dump; + extern global full_version; + extern global help; + extern global key_dir; + extern global key_name; + extern global log; + extern global norc; + extern global nostd; + extern global quiet; + extern global rcfile; + extern global reallyquiet; + extern global root; + extern global ticker; + extern global verbose; + extern global version; + + // command-specific options + extern specific author; + extern specific bind; + extern specific branch_name; + extern specific brief; + extern specific context_diff; + extern specific date; + extern specific depth; + extern specific diffs; + extern specific drop_attr; + extern specific exclude; + extern specific execute; + extern specific external_diff; + extern specific external_diff_args; + extern specific key_to_push; + extern specific last; + extern specific message; + extern specific missing; + extern specific msgfile; + extern specific next; + extern specific no_files; + extern specific no_merges; + extern specific pidfile; + extern specific recursive; + extern specific revision; + extern specific set_default; + extern specific unified_diff; + extern specific unknown; +} + +#endif // __OPTIONS_HH__ -#define OPT_DEBUG 1 -#define OPT_HELP 2 -#define OPT_NOSTD 3 -#define OPT_NORC 4 -#define OPT_RCFILE 5 -#define OPT_DB_NAME 6 -#define OPT_KEY_NAME 7 -#define OPT_BRANCH_NAME 8 -#define OPT_QUIET 9 -#define OPT_VERSION 10 -#define OPT_DUMP 11 -#define OPT_TICKER 12 -#define OPT_FULL_VERSION 13 -#define OPT_REVISION 14 -#define OPT_MESSAGE 15 -#define OPT_ROOT 16 -#define OPT_DEPTH 17 -#define OPT_ARGFILE 18 -#define OPT_DATE 19 -#define OPT_AUTHOR 20 -#define OPT_ALL_FILES 21 -#define OPT_PIDFILE 22 -#define OPT_MSGFILE 23 -#define OPT_BRIEF 24 -#define OPT_DIFFS 25 -#define OPT_NO_MERGES 26 -#define OPT_LAST 27 -#define OPT_NEXT 28 -#define OPT_VERBOSE 29 -#define OPT_SET_DEFAULT 30 -#define OPT_EXCLUDE 31 -#define OPT_UNIFIED_DIFF 32 -#define OPT_CONTEXT_DIFF 33 -#define OPT_EXTERNAL_DIFF 34 -#define OPT_EXTERNAL_DIFF_ARGS 35 -// formerly OPT_LCA was here -#define OPT_EXECUTE 37 -#define OPT_KEY_DIR 38 -#define OPT_BIND 39 -#define OPT_MISSING 40 -#define OPT_UNKNOWN 41 -#define OPT_KEY_TO_PUSH 42 -#define OPT_CONF_DIR 43 -#define OPT_DROP_ATTR 44 -#define OPT_NO_FILES 45 -#define OPT_LOG 46 -#define OPT_RECURSIVE 47 -#define OPT_REALLYQUIET 48