void Command::GetConfig::run()
{
- if (_options_parser.hasArgs())
+ if (_options_parser.has_args())
{
cerr << _("Command 'get-config' does not take arguments.") << endl;
exit(EXIT_FAILURE);
namespace
{
- const option OPTIONS[] = {
- { "columns", required_argument, 0, 0},
- { 0, 0, 0, 0 }
+ const vector<Option> OPTIONS = {
+ Option("columns", required_argument)
};
}
void Command::ListConfigs::run()
{
- if (_options_parser.hasArgs())
+ if (_options_parser.has_args())
{
cerr << _("Command 'list-configs' does not take arguments.") << endl;
exit(EXIT_FAILURE);
namespace
{
- const option OPTIONS[] = {
- { "columns", required_argument, 0, 0},
- { 0, 0, 0, 0 }
+ const vector<Option> OPTIONS = {
+ Option("columns", required_argument)
};
}
void Command::ListSnapshots::run()
{
- if (_options_parser.hasArgs())
+ if (_options_parser.has_args())
{
cerr << _("Command 'list' does not take arguments.") << endl;
exit(EXIT_FAILURE);
namespace
{
- const option OPTIONS[] = {
- { "type", required_argument, 0, 't' },
- { "disable-used-space", no_argument, 0, 0 },
- { "all-configs", no_argument, 0, 'a' },
- { "columns", required_argument, 0, 0},
- { 0, 0, 0, 0 }
+ const vector<Option> OPTIONS = {
+ Option("type", required_argument, 't'),
+ Option("disable-used-space", no_argument),
+ Option("all-configs", no_argument, 'a'),
+ Option("columns", required_argument)
};
}
const string DEFAULT_ROOT = "/";
- const option OPTIONS[] = {
- { "quiet", no_argument, 0, 'q' },
- { "verbose", no_argument, 0, 'v' },
- { "utc", no_argument, 0, 0 },
- { "iso", no_argument, 0, 0 },
- { "table-style", required_argument, 0, 't' },
- { "machine-readable", required_argument, 0, 0 },
- { "csvout", no_argument, 0, 0 },
- { "jsonout", no_argument, 0, 0 },
- { "separator", required_argument, 0, 0 },
- { "config", required_argument, 0, 'c' },
- { "no-dbus", no_argument, 0, 0 },
- { "root", required_argument, 0, 'r' },
- { "ambit", required_argument, 0, 'a' },
- { "version", no_argument, 0, 0 },
- { "help", no_argument, 0, 'h' },
- { 0, 0, 0, 0 }
+ const vector<Option> OPTIONS = {
+ Option("quiet", no_argument, 'q'),
+ Option("verbose", no_argument, 'v'),
+ Option("utc", no_argument),
+ Option("iso", no_argument),
+ Option("table-style", required_argument, 't'),
+ Option("machine-readable", required_argument),
+ Option("csvout", no_argument),
+ Option("jsonout", no_argument),
+ Option("separator", required_argument),
+ Option("config", required_argument, 'c'),
+ Option("no-dbus", no_argument),
+ Option("root", required_argument, 'r'),
+ Option("ambit", required_argument, 'a'),
+ Option("version", no_argument),
+ Option("help", no_argument, 'h')
};
}
{
if (has_option("root") && !has_option("no-dbus"))
{
- string error =_("root argument can be used only together with no-dbus.\n"
- "Try 'snapper --help' for more information.");
+ string error =_("root argument can be used only together with no-dbus.");
SN_THROW(OptionsException(error));
}
using std::vector;
- struct OptionsException : public Exception
- {
- explicit OptionsException(const string& msg) : Exception(msg) {}
- };
-
-
namespace cli
{
GetOpts& _parser;
- GetOpts::parsed_opts _options;
+ ParsedOpts _options;
};
/*
* Copyright (c) 2015 Novell, Inc.
- * Copyright (c) 2018 SUSE LLC
+ * Copyright (c) [2018-2020] SUSE LLC
*
* All Rights Reserved.
*
setLogDo(&log_do);
setLogQuery(&log_query);
- const struct option options[] = {
- { "step", required_argument, 0, 0 },
- { "device", required_argument, 0, 0 },
- { "root-prefix", required_argument, 0, 0 },
- { "default-subvolume-name", required_argument, 0, 0 },
- { "snapshot-type", required_argument, 0, 0 },
- { "pre-num", required_argument, 0, 0 },
- { "description", required_argument, 0, 0 },
- { "cleanup", required_argument, 0, 0 },
- { "userdata", required_argument, 0, 0 },
- { 0, 0, 0, 0 }
- };
-
string step;
string device;
string root_prefix = "/";
string cleanup;
map<string, string> userdata;
- GetOpts getopts;
+ try
+ {
+ const vector<Option> options = {
+ Option("step", required_argument),
+ Option("device", required_argument),
+ Option("root-prefix", required_argument),
+ Option("default-subvolume-name", required_argument),
+ Option("snapshot-type", required_argument),
+ Option("pre-num", required_argument),
+ Option("description", required_argument),
+ Option("cleanup", required_argument),
+ Option("userdata", required_argument)
+ };
- getopts.init(argc, argv);
+ GetOpts get_opts(argc, argv);
- GetOpts::parsed_opts opts = getopts.parse(options);
+ ParsedOpts opts = get_opts.parse(options);
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
- if ((opt = opts.find("step")) != opts.end())
- step = opt->second;
+ if ((opt = opts.find("step")) != opts.end())
+ step = opt->second;
- if ((opt = opts.find("device")) != opts.end())
- device = opt->second;
+ if ((opt = opts.find("device")) != opts.end())
+ device = opt->second;
- if ((opt = opts.find("root-prefix")) != opts.end())
- root_prefix = opt->second;
+ if ((opt = opts.find("root-prefix")) != opts.end())
+ root_prefix = opt->second;
- if ((opt = opts.find("default-subvolume-name")) != opts.end())
- default_subvolume_name = opt->second;
+ if ((opt = opts.find("default-subvolume-name")) != opts.end())
+ default_subvolume_name = opt->second;
- if ((opt = opts.find("snapshot-type")) != opts.end())
- snapshot_type = opt->second;
+ if ((opt = opts.find("snapshot-type")) != opts.end())
+ snapshot_type = opt->second;
- if ((opt = opts.find("pre-num")) != opts.end())
- pre_num = read_num(opt->second);
+ if ((opt = opts.find("pre-num")) != opts.end())
+ pre_num = read_num(opt->second);
- if ((opt = opts.find("description")) != opts.end())
- description = opt->second;
+ if ((opt = opts.find("description")) != opts.end())
+ description = opt->second;
- if ((opt = opts.find("cleanup")) != opts.end())
- cleanup = opt->second;
+ if ((opt = opts.find("cleanup")) != opts.end())
+ cleanup = opt->second;
- if ((opt = opts.find("userdata")) != opts.end())
- userdata = read_userdata(opt->second);
+ if ((opt = opts.find("userdata")) != opts.end())
+ userdata = read_userdata(opt->second);
+ }
+ catch (const OptionsException& e)
+ {
+ SN_CAUGHT(e);
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
if (step == "1")
step1(device, description, cleanup, userdata);
map<string, string>
-read_configdata(const list<string>& l, const map<string, string>& old)
+read_configdata(const vector<string>& v, const map<string, string>& old)
{
- if (l.empty())
+ if (v.empty())
{
cerr << _("Empty configdata.") << endl;
exit(EXIT_FAILURE);
map<string, string> configdata = old;
- for (list<string>::const_iterator it = l.begin(); it != l.end(); ++it)
+ for (vector<string>::const_iterator it = v.begin(); it != v.end(); ++it)
{
string::size_type pos = it->find("=");
if (pos == string::npos)
show_userdata(const map<string, string>& userdata);
map<string, string>
-read_configdata(const list<string>& l, const map<string, string>& old = map<string, string>());
+read_configdata(const vector<string>& v, const map<string, string>& old = map<string, string>());
string
username(uid_t uid);
{
setlocale(LC_ALL, "");
- const struct option options[] = {
- { "nocow", no_argument, 0, 0 },
- { "verbose", no_argument, 0, 'v' },
- { 0, 0, 0, 0 }
- };
-
- GetOpts getopts;
-
- getopts.init(argc, argv);
+ try
+ {
+ const vector<Option> options = {
+ Option("nocow", no_argument),
+ Option("verbose", no_argument, 'v'),
+ };
- GetOpts::parsed_opts opts = getopts.parse(options);
+ GetOpts get_opts(argc, argv);
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts opts = get_opts.parse(options);
- if ((opt = opts.find("nocow")) != opts.end())
- set_nocow = true;
+ if (opts.has_option("nocow"))
+ set_nocow = true;
- if ((opt = opts.find("verbose")) != opts.end())
- verbose = true;
+ if (opts.has_option("verbose"))
+ verbose = true;
- if (getopts.numArgs() != 1)
- usage();
+ if (get_opts.num_args() != 1)
+ usage();
- target = getopts.popArg();
+ target = get_opts.pop_arg();
+ }
+ catch (const OptionsException& e)
+ {
+ SN_CAUGHT(e);
+ cerr << e.what() << endl;
+ usage();
+ }
try
{
struct Cmd
{
- typedef void (*cmd_func_t)(cli::GlobalOptions& global_options, ProxySnappers* snappers,
- ProxySnapper* snapper);
+ typedef void (*cmd_func_t)(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers,
+ ProxySnapper* snapper);
typedef void (*help_func_t)();
};
-GetOpts getopts;
-
-
struct MyFiles : public Files
{
MyFiles(const Files& files) : Files(files) {}
- void bulk_process(FILE* file, std::function<void(File& file)> callback);
+ void bulk_process(FILE* file, GetOpts& get_opts, std::function<void(File& file)> callback);
};
void
-MyFiles::bulk_process(FILE* file, std::function<void(File& file)> callback)
+MyFiles::bulk_process(FILE* file, GetOpts& get_opts, std::function<void(File& file)> callback)
{
if (file)
{
}
else
{
- if (getopts.numArgs() == 0)
+ if (get_opts.num_args() == 0)
{
for (Files::iterator it = begin(); it != end(); ++it)
callback(*it);
}
else
{
- while (getopts.numArgs() > 0)
+ while (get_opts.num_args() > 0)
{
- string name = getopts.popArg();
+ string name = get_opts.pop_arg();
Files::iterator it = findAbsolutePath(name);
if (it == end())
void
-command_list_configs(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
+command_list_configs(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper*)
{
- cli::Command::ListConfigs command(global_options, getopts, *snappers);
+ cli::Command::ListConfigs command(global_options, get_opts, *snappers);
command.run();
}
void
-command_create_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
+command_create_config(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper*)
{
- const struct option options[] = {
- { "fstype", required_argument, 0, 'f' },
- { "template", required_argument, 0, 't' },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("fstype", required_argument, 'f'),
+ Option("template", required_argument, 't')
};
- GetOpts::parsed_opts opts = getopts.parse("create-config", options);
- if (getopts.numArgs() != 1)
+ ParsedOpts opts = get_opts.parse("create-config", options);
+ if (get_opts.num_args() != 1)
{
cerr << _("Command 'create-config' needs one argument.") << endl;
exit(EXIT_FAILURE);
}
- string subvolume = realpath(getopts.popArg());
+ string subvolume = realpath(get_opts.pop_arg());
if (subvolume.empty())
{
cerr << _("Invalid subvolume.") << endl;
string fstype = "";
string template_name = "default";
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
if ((opt = opts.find("fstype")) != opts.end())
fstype = opt->second;
void
-command_delete_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
+command_delete_config(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper*)
{
- getopts.parse("delete-config", GetOpts::no_options);
- if (getopts.hasArgs())
+ get_opts.parse("delete-config", GetOpts::no_options);
+ if (get_opts.has_args())
{
cerr << _("Command 'delete-config' does not take arguments.") << endl;
exit(EXIT_FAILURE);
void
-command_get_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
+command_get_config(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper*)
{
- cli::Command::GetConfig command(global_options, getopts, *snappers);
+ cli::Command::GetConfig command(global_options, get_opts, *snappers);
command.run();
}
void
-command_set_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_set_config(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- getopts.parse("set-config", GetOpts::no_options);
- if (!getopts.hasArgs())
+ get_opts.parse("set-config", GetOpts::no_options);
+ if (!get_opts.has_args())
{
cerr << _("Command 'set-config' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
}
- ProxyConfig config(read_configdata(getopts.getArgs()));
+ ProxyConfig config(read_configdata(get_opts.get_args()));
snapper->setConfig(config);
}
void
-command_list(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
+command_list(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper*)
{
- cli::Command::ListSnapshots command(global_options, getopts, *snappers);
+ cli::Command::ListSnapshots command(global_options, get_opts, *snappers);
command.run();
}
void
-command_create(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_create(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- const struct option options[] = {
- { "type", required_argument, 0, 't' },
- { "pre-number", required_argument, 0, 0 },
- { "print-number", no_argument, 0, 'p' },
- { "description", required_argument, 0, 'd' },
- { "cleanup-algorithm", required_argument, 0, 'c' },
- { "userdata", required_argument, 0, 'u' },
- { "command", required_argument, 0, 0 },
- { "read-only", no_argument, 0, 0 },
- { "read-write", no_argument, 0, 0 },
- { "from", required_argument, 0, 0 },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("type", required_argument, 't'),
+ Option("pre-number", required_argument),
+ Option("print-number", no_argument, 'p'),
+ Option("description", required_argument, 'd'),
+ Option("cleanup-algorithm", required_argument, 'c'),
+ Option("userdata", required_argument, 'u'),
+ Option("command", required_argument),
+ Option("read-only", no_argument),
+ Option("read-write", no_argument),
+ Option("from", required_argument)
};
- GetOpts::parsed_opts opts = getopts.parse("create", options);
- if (getopts.hasArgs())
+ ParsedOpts opts = get_opts.parse("create", options);
+ if (get_opts.has_args())
{
cerr << _("Command 'create' does not take arguments.") << endl;
exit(EXIT_FAILURE);
string command;
ProxySnapshots::const_iterator parent = snapshots.getCurrent();
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
if ((opt = opts.find("type")) != opts.end())
{
void
-command_modify(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_modify(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- const struct option options[] = {
- { "description", required_argument, 0, 'd' },
- { "cleanup-algorithm", required_argument, 0, 'c' },
- { "userdata", required_argument, 0, 'u' },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("description", required_argument, 'd'),
+ Option("cleanup-algorithm", required_argument, 'c'),
+ Option("userdata", required_argument, 'u')
};
- GetOpts::parsed_opts opts = getopts.parse("modify", options);
- if (!getopts.hasArgs())
+ ParsedOpts opts = get_opts.parse("modify", options);
+ if (!get_opts.has_args())
{
cerr << _("Command 'modify' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
ProxySnapshots& snapshots = snapper->getSnapshots();
- while (getopts.hasArgs())
+ while (get_opts.has_args())
{
- ProxySnapshots::iterator snapshot = snapshots.findNum(getopts.popArg());
+ ProxySnapshots::iterator snapshot = snapshots.findNum(get_opts.pop_arg());
SMD smd = snapshot->getSmd();
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
if ((opt = opts.find("description")) != opts.end())
smd.description = opt->second;
void
-command_delete(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_delete(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- const struct option options[] = {
- { "sync", no_argument, 0, 's' },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("sync", no_argument, 's')
};
- GetOpts::parsed_opts opts = getopts.parse("delete", options);
- if (!getopts.hasArgs())
+ ParsedOpts opts = get_opts.parse("delete", options);
+ if (!get_opts.has_args())
{
cerr << _("Command 'delete' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
bool sync = false;
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
if ((opt = opts.find("sync")) != opts.end())
sync = true;
vector<ProxySnapshots::iterator> nums;
- while (getopts.hasArgs())
+ while (get_opts.has_args())
{
- string arg = getopts.popArg();
+ string arg = get_opts.pop_arg();
if (arg.find_first_of("-") == string::npos)
{
void
-command_mount(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_mount(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- getopts.parse("mount", GetOpts::no_options);
- if (!getopts.hasArgs())
+ get_opts.parse("mount", GetOpts::no_options);
+ if (!get_opts.has_args())
{
cerr << _("Command 'mount' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
const ProxySnapshots& snapshots = snapper->getSnapshots();
- while (getopts.hasArgs())
+ while (get_opts.has_args())
{
- ProxySnapshots::const_iterator snapshot = snapshots.findNum(getopts.popArg());
+ ProxySnapshots::const_iterator snapshot = snapshots.findNum(get_opts.pop_arg());
snapshot->mountFilesystemSnapshot(true);
}
}
void
-command_umount(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_umount(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- getopts.parse("umount", GetOpts::no_options);
- if (!getopts.hasArgs())
+ get_opts.parse("umount", GetOpts::no_options);
+ if (!get_opts.has_args())
{
cerr << _("Command 'umount' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
const ProxySnapshots& snapshots = snapper->getSnapshots();
- while (getopts.hasArgs())
+ while (get_opts.has_args())
{
- ProxySnapshots::const_iterator snapshot = snapshots.findNum(getopts.popArg());
+ ProxySnapshots::const_iterator snapshot = snapshots.findNum(get_opts.pop_arg());
snapshot->umountFilesystemSnapshot(true);
}
}
void
-command_status(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_status(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- const struct option options[] = {
- { "output", required_argument, 0, 'o' },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("output", required_argument, 'o')
};
- GetOpts::parsed_opts opts = getopts.parse("status", options);
- if (getopts.numArgs() != 1)
+ ParsedOpts opts = get_opts.parse("status", options);
+ if (get_opts.num_args() != 1)
{
cerr << _("Command 'status' needs one argument.") << endl;
- if (getopts.numArgs() == 2)
+ if (get_opts.num_args() == 2)
{
cerr << _("Maybe you forgot the delimiter '..' between the snapshot numbers.") << endl
<< _("See 'man snapper' for further instructions.") << endl;
exit(EXIT_FAILURE);
}
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
ProxySnapshots& snapshots = snapper->getSnapshots();
pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> range =
- snapshots.findNums(getopts.popArg());
+ snapshots.findNums(get_opts.pop_arg());
ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, false);
void
-command_diff(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_diff(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- const struct option options[] = {
- { "input", required_argument, 0, 'i' },
- { "diff-cmd", required_argument, 0, 0 },
- { "extensions", required_argument, 0, 'x' },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("input", required_argument, 'i'),
+ Option("diff-cmd", required_argument),
+ Option("extensions", required_argument, 'x'),
};
- GetOpts::parsed_opts opts = getopts.parse("diff", options);
- if (getopts.numArgs() < 1)
+ ParsedOpts opts = get_opts.parse("diff", options);
+ if (get_opts.num_args() < 1)
{
cerr << _("Command 'diff' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
FILE* file = NULL;
Differ differ;
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
if ((opt = opts.find("input")) != opts.end())
{
ProxySnapshots& snapshots = snapper->getSnapshots();
pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> range =
- snapshots.findNums(getopts.popArg());
+ snapshots.findNums(get_opts.pop_arg());
ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, true);
MyFiles files(comparison.getFiles());
- files.bulk_process(file, [differ](const File& file) {
+ files.bulk_process(file, get_opts, [differ](const File& file) {
differ.run(file.getAbsolutePath(LOC_PRE), file.getAbsolutePath(LOC_POST));
});
}
void
-command_undo(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_undo(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- const struct option options[] = {
- { "input", required_argument, 0, 'i' },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("input", required_argument, 'i')
};
- GetOpts::parsed_opts opts = getopts.parse("undochange", options);
- if (getopts.numArgs() < 1)
+ ParsedOpts opts = get_opts.parse("undochange", options);
+ if (get_opts.num_args() < 1)
{
cerr << _("Command 'undochange' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
ProxySnapshots& snapshots = snapper->getSnapshots();
pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> range =
- snapshots.findNums(getopts.popArg());
+ snapshots.findNums(get_opts.pop_arg());
FILE* file = NULL;
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
if ((opt = opts.find("input")) != opts.end())
{
MyFiles files(comparison.getFiles());
- files.bulk_process(file, [](File& file) {
+ files.bulk_process(file, get_opts, [](File& file) {
file.setUndo(true);
});
void
-command_rollback(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_rollback(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- const struct option options[] = {
- { "print-number", no_argument, 0, 'p' },
- { "description", required_argument, 0, 'd' },
- { "cleanup-algorithm", required_argument, 0, 'c' },
- { "userdata", required_argument, 0, 'u' },
- { 0, 0, 0, 0 }
+ const vector<Option> options = {
+ Option("print-number", no_argument, 'p'),
+ Option("description", required_argument, 'd'),
+ Option("cleanup-algorithm", required_argument, 'c'),
+ Option("userdata", required_argument, 'u')
};
- GetOpts::parsed_opts opts = getopts.parse("rollback", options);
- if (getopts.hasArgs() && getopts.numArgs() != 1)
+ ParsedOpts opts = get_opts.parse("rollback", options);
+ if (get_opts.has_args() && get_opts.num_args() != 1)
{
cerr << _("Command 'rollback' takes either one or no argument.") << endl;
exit(EXIT_FAILURE);
SCD scd2;
scd2.description = default_description2;
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
if ((opt = opts.find("print-number")) != opts.end())
print_number = true;
ProxySnapshots::const_iterator snapshot1 = snapshots.end();
ProxySnapshots::const_iterator snapshot2 = snapshots.end();
- if (getopts.numArgs() == 0)
+ if (get_opts.num_args() == 0)
{
if (!global_options.quiet())
cout << _("Creating read-only snapshot of default subvolume.") << flush;
}
else
{
- ProxySnapshots::const_iterator tmp = snapshots.findNum(getopts.popArg());
+ ProxySnapshots::const_iterator tmp = snapshots.findNum(get_opts.pop_arg());
if (!global_options.quiet())
cout << _("Creating read-only snapshot of current system.") << flush;
ProxySnapshots::iterator snapshot = snapshots.end();
- if (getopts.numArgs() == 0)
+ if (get_opts.num_args() == 0)
{
snapshot = snapshots.getActive();
}
else
{
- snapshot = snapshots.findNum(getopts.popArg());
+ snapshot = snapshots.findNum(get_opts.pop_arg());
}
if (previous_default == snapshot)
void
-command_setup_quota(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_setup_quota(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- GetOpts::parsed_opts opts = getopts.parse("setup-quota", GetOpts::no_options);
- if (getopts.numArgs() != 0)
+ ParsedOpts opts = get_opts.parse("setup-quota", GetOpts::no_options);
+ if (get_opts.num_args() != 0)
{
cerr << _("Command 'setup-quota' does not take arguments.") << endl;
exit(EXIT_FAILURE);
void
-command_cleanup(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_cleanup(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- GetOpts::parsed_opts opts = getopts.parse("cleanup", GetOpts::no_options);
- if (getopts.numArgs() != 1)
+ ParsedOpts opts = get_opts.parse("cleanup", GetOpts::no_options);
+ if (get_opts.num_args() != 1)
{
cerr << _("Command 'cleanup' needs one arguments.") << endl;
exit(EXIT_FAILURE);
}
- string cleanup = getopts.popArg();
+ string cleanup = get_opts.pop_arg();
if (cleanup == "number")
{
void
-command_debug(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
+command_debug(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper*)
{
- getopts.parse("debug", GetOpts::no_options);
- if (getopts.hasArgs())
+ get_opts.parse("debug", GetOpts::no_options);
+ if (get_opts.has_args())
{
cerr << _("Command 'debug' does not take arguments.") << endl;
exit(EXIT_FAILURE);
}
void
-command_xa_diff(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_xa_diff(cli::GlobalOptions& global_options, GetOpts& get_opts, ProxySnappers* snappers, ProxySnapper* snapper)
{
- GetOpts::parsed_opts opts = getopts.parse("xadiff", GetOpts::no_options);
- if (getopts.numArgs() < 1)
+ ParsedOpts opts = get_opts.parse("xadiff", GetOpts::no_options);
+ if (get_opts.num_args() < 1)
{
cerr << _("Command 'xadiff' needs at least one argument.") << endl;
exit(EXIT_FAILURE);
ProxySnapshots& snapshots = snapper->getSnapshots();
pair<ProxySnapshots::const_iterator, ProxySnapshots::const_iterator> range =
- snapshots.findNums(getopts.popArg());
+ snapshots.findNums(get_opts.pop_arg());
ProxyComparison comparison = snapper->createComparison(*range.first, *range.second, true);
MyFiles files(comparison.getFiles());
- if (getopts.numArgs() == 0)
+ if (get_opts.num_args() == 0)
{
for (Files::const_iterator it1 = files.begin(); it1 != files.end(); ++it1)
if (it1->getPreToPostStatus() & XATTRS)
}
else
{
- while (getopts.numArgs() > 0)
+ while (get_opts.num_args() > 0)
{
- string name = getopts.popArg();
+ string name = get_opts.pop_arg();
Files::const_iterator it1 = files.findAbsolutePath(name);
if (it1 == files.end())
void help() __attribute__ ((__noreturn__));
void
-help(const list<Cmd>& cmds)
+help(const vector<Cmd>& cmds, GetOpts& get_opts)
{
- getopts.parse("help", GetOpts::no_options);
- if (getopts.hasArgs())
+ get_opts.parse("help", GetOpts::no_options);
+ if (get_opts.has_args())
{
cerr << _("Command 'help' does not take arguments.") << endl;
exit(EXIT_FAILURE);
cout << cli::GlobalOptions::help_text() << endl;
- for (list<Cmd>::const_iterator cmd = cmds.begin(); cmd != cmds.end(); ++cmd)
- (*cmd->help_func)();
+ for (const Cmd& cmd : cmds)
+ (*cmd.help_func)();
exit(EXIT_SUCCESS);
}
setLogDo(&log_do);
setLogQuery(&log_query);
- const list<Cmd> cmds = {
+ const vector<Cmd> cmds = {
Cmd("list-configs", command_list_configs, help_list_configs, false),
Cmd("create-config", command_create_config, help_create_config, false),
Cmd("delete-config", command_delete_config, help_delete_config, false),
try
{
- getopts.init(argc, argv);
+ GetOpts get_opts(argc, argv);
- cli::GlobalOptions global_options(getopts);
+ cli::GlobalOptions global_options(get_opts);
if (global_options.version())
{
if (global_options.help())
{
- help(cmds);
+ help(cmds, get_opts);
}
- if (!getopts.hasArgs())
+ if (!get_opts.has_args())
{
cerr << _("No command provided.") << endl
<< _("Try 'snapper --help' for more information.") << endl;
exit(EXIT_FAILURE);
}
- const char* command = getopts.popArg();
+ const char* command = get_opts.pop_arg();
- list<Cmd>::const_iterator cmd = cmds.begin();
+ vector<Cmd>::const_iterator cmd = cmds.begin();
while (cmd != cmds.end() && (cmd->name != command && !contains(cmd->aliases, command)))
++cmd;
ProxySnappers::createDbus());
if (cmd->needs_snapper)
- (*cmd->cmd_func)(global_options, &snappers, snappers.getSnapper(global_options.config()));
+ (*cmd->cmd_func)(global_options, get_opts, &snappers, snappers.getSnapper(global_options.config()));
else
- (*cmd->cmd_func)(global_options, &snappers, nullptr);
+ (*cmd->cmd_func)(global_options, get_opts, &snappers, nullptr);
}
catch (const DBus::ErrorException& e)
{
catch (const OptionsException& e)
{
SN_CAUGHT(e);
- cerr << e.what() << endl;
+ cerr << e.what() << endl
+ << _("Try 'snapper --help' for more information.") << endl;
exit(EXIT_FAILURE);
}
catch (const Exception& e)
catch (const OptionsException& e)
{
SN_CAUGHT(e);
- cerr << e.what() << endl;
+ cerr << e.what() << endl
+ << _("Try 'snapper --help' for more information.") << endl;
exit(EXIT_FAILURE);
}
/*
* Copyright (c) [2014-2015] Novell, Inc.
- * Copyright (c) [2016,2018] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
*
* All Rights Reserved.
*
{
setlocale(LC_ALL, "");
- const struct option options[] = {
- { "timeline", no_argument, 0, 0 },
- { "cleanup", no_argument, 0, 0 },
- { "userdata", required_argument, 0, 'u' },
- { 0, 0, 0, 0 }
- };
-
bool do_timeline = false;
bool do_cleanup = false;
-
map<string, string> userdata;
- GetOpts getopts;
+ try
+ {
+ const vector<Option> options = {
+ Option("timeline", no_argument),
+ Option("cleanup", no_argument),
+ Option("userdata", required_argument, 'u')
+ };
- getopts.init(argc, argv);
+ GetOpts get_opts(argc, argv);
- GetOpts::parsed_opts opts = getopts.parse(options);
+ ParsedOpts opts = get_opts.parse(options);
- GetOpts::parsed_opts::const_iterator opt;
+ ParsedOpts::const_iterator opt;
- if (opts.find("timeline") != opts.end())
- do_timeline = true;
+ if (opts.has_option("timeline"))
+ do_timeline = true;
- if (opts.find("cleanup") != opts.end())
- do_cleanup = true;
+ if (opts.has_option("cleanup"))
+ do_cleanup = true;
- if ((opt = opts.find("userdata")) != opts.end())
- userdata = read_userdata(opt->second);
+ if ((opt = opts.find("userdata")) != opts.end())
+ userdata = read_userdata(opt->second);
+ }
+ catch (const OptionsException& e)
+ {
+ SN_CAUGHT(e);
+ cerr << e.what() << endl;
+ exit(EXIT_FAILURE);
+ }
bool ok = true;
-
-#include <iostream>
-#include <boost/algorithm/string.hpp>
+/*
+ * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) [2016-2020] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#include <algorithm>
#include <snapper/AppUtil.h>
#include "GetOpts.h"
#include "text.h"
-using namespace std;
-using namespace snapper;
-
-
-// based on getopt.cc from zypper, thanks jkupec
+namespace snapper
+{
-const struct option GetOpts::no_options[1] = {
- { 0, 0, 0, 0 }
-};
+ using namespace std;
-void
-GetOpts::init(int new_argc, char** new_argv)
-{
- argc = new_argc;
- argv = new_argv;
-}
+ const struct vector<Option> GetOpts::no_options = {};
-GetOpts::parsed_opts
-GetOpts::parse(const struct option* longopts)
-{
- return parse(NULL, longopts);
-}
+ GetOpts::GetOpts(int argc, char** argv)
+ : argc(argc), argv(argv)
+ {
+ opterr = 0; // we report errors on our own
+ }
-GetOpts::parsed_opts
-GetOpts::parse(const char* command, const struct option* longopts)
-{
- parsed_opts result;
- opterr = 0; // we report errors on our own
+ ParsedOpts
+ GetOpts::parse(const vector<Option>& options)
+ {
+ return parse(nullptr, options);
+ }
- string optstring = make_optstring(longopts);
- short2long_t short2long = make_short2long(longopts);
- while (true)
+ ParsedOpts
+ GetOpts::parse(const char* command, const vector<Option>& options)
{
- int option_index = 0;
- int c = getopt_long(argc, argv, optstring.c_str(), longopts, &option_index);
+ string optstring = make_optstring(options);
+ vector<struct option> longopts = make_longopts(options);
+
+ map<string, string> result;
- switch (c)
+ while (true)
{
- case -1:
- return result;
-
- case '?':
- if (!command)
- cerr << sformat(_("Unknown global option '%s'."), argv[optind - 1]) << endl;
- else
- cerr << sformat(_("Unknown option '%s' for command '%s'."), argv[optind - 1], command) << endl;
- cerr << _("Try 'snapper --help' for more information.") << endl;
- exit(EXIT_FAILURE);
-
- case ':':
- if (!command)
- cerr << sformat(_("Missing argument for global option '%s'."), argv[optind - 1]) << endl;
- else
- cerr << sformat(_("Missing argument for command option '%s'."), argv[optind - 1]) << endl;
- cerr << _("Try 'snapper --help' for more information.") << endl;
- exit(EXIT_FAILURE);
-
- default:
- const char* opt = c ? short2long[c] : longopts[option_index].name;
- result[opt] = optarg ? optarg : "";
- break;
+ int option_index = 0;
+ int c = getopt_long(argc, argv, optstring.c_str(), &longopts[0], &option_index);
+
+ switch (c)
+ {
+ case -1:
+ {
+ return result;
+ }
+
+ case '?':
+ {
+ string opt;
+ if (optopt != 0)
+ opt = string("-") + (char)(optopt);
+ else
+ opt = argv[optind - 1];
+
+ string msg;
+ if (!command)
+ msg = sformat(_("Unknown global option '%s'."), opt.c_str());
+ else
+ msg = sformat(_("Unknown option '%s' for command '%s'."), opt.c_str(), command);
+
+ SN_THROW(OptionsException(msg));
+ break;
+ }
+
+ case ':':
+ {
+ string opt;
+ if (optopt != 0)
+ {
+ vector<Option>::const_iterator it = find(options, optopt);
+ if (it == options.end())
+ SN_THROW(Exception("option not found"));
+
+ opt = string("--") + it->name;
+ }
+ else
+ {
+ opt = argv[optind - 1];
+ }
+
+ string msg;
+ if (!command)
+ msg = sformat(_("Missing argument for global option '%s'."), opt.c_str());
+ else
+ msg = sformat(_("Missing argument for command option '%s'."), opt.c_str());
+
+ SN_THROW(OptionsException(msg));
+ break;
+ }
+
+ default:
+ {
+ vector<Option>::const_iterator it = c ? find(options, c) : options.begin() + option_index;
+ if (it == options.end())
+ SN_THROW(Exception("option not found"));
+
+ result[it->name] = optarg ? optarg : "";
+ break;
+ }
+ }
}
}
-}
-string
-GetOpts::make_optstring(const struct option* longopts) const
-{
- // '+' - do not permute, stop at the 1st nonoption, which is the command or an argument
- // ':' - return ':' to indicate missing arg, not '?'
- string optstring = "+:";
+ vector<Option>::const_iterator
+ GetOpts::find(const vector<Option>& options, char c) const
+ {
+ return find_if(options.begin(), options.end(), [c](const Option& option)
+ { return option.c == c; }
+ );
+ }
- for (; longopts && longopts->name; ++longopts)
+
+ string
+ GetOpts::make_optstring(const vector<Option>& options) const
{
- if (!longopts->flag && longopts->val)
+ // '+' - do not permute, stop at the 1st non-option, which is the command or an argument
+ // ':' - return ':' to indicate missing arg, not '?'
+ string optstring = "+:";
+
+ for (const Option& option : options)
{
- optstring += (char) longopts->val;
- if (longopts->has_arg == required_argument)
- optstring += ':';
- else if (longopts->has_arg == optional_argument)
- optstring += "::";
+ if (option.c == 0)
+ continue;
+
+ optstring += option.c;
+
+ switch (option.has_arg)
+ {
+ case no_argument:
+ break;
+
+ case required_argument:
+ optstring += ':';
+ break;
+ }
}
+
+ return optstring;
}
- return optstring;
-}
+ vector<struct option>
+ GetOpts::make_longopts(const vector<Option> options) const
+ {
+ vector<struct option> ret;
-GetOpts::short2long_t
-GetOpts::make_short2long(const struct option* longopts) const
-{
- short2long_t result;
+ for (const Option& option : options)
+ ret.push_back({ option.name, option.has_arg, nullptr, option.c });
- for (; longopts && longopts->name; ++longopts)
- {
- if (!longopts->flag && longopts->val)
- {
- result[longopts->val] = longopts->name;
- }
+ ret.push_back({ nullptr, 0, nullptr, 0 });
+
+ return ret;
}
- return result;
}
-#ifndef GET_OPTS_H
-#define GET_OPTS_H
+/*
+ * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) [2016-2020] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#ifndef SNAPPER_GET_OPTS_H
+#define SNAPPER_GET_OPTS_H
#include <getopt.h>
#include <string>
+#include <vector>
#include <map>
-#include <list>
+#include <snapper/Exception.h>
-class GetOpts
+
+namespace snapper
{
-public:
- static const struct option no_options[1];
+ using namespace std;
+
+
+ struct OptionsException : public Exception
+ {
+ explicit OptionsException(const string& msg) : Exception(msg) {}
+ };
+
+
+ struct Option
+ {
+ Option(const char* name, int has_arg, char c = 0)
+ : name(name), has_arg(has_arg), c(c)
+ {
+ }
+
+ const char* name;
+ int has_arg;
+ char c;
+ };
+
+
+ class ParsedOpts
+ {
+ public:
+
+ ParsedOpts() = default; // TODO remove
+
+ ParsedOpts(const map<string, string>& args) : args(args) {}
+
+ using const_iterator = map<string, string>::const_iterator;
+
+ bool has_option(const string& name) const { return find(name) != end(); }
+
+ const_iterator find(const string& name) const { return args.find(name); }
+
+ const_iterator end() const { return args.end(); }
+
+ private:
+
+ map<string, string> args; // TODO make const
+
+ };
+
+
+ class GetOpts
+ {
+ public:
- typedef std::map<std::string, std::string> parsed_opts;
+ static const vector<Option> no_options;
- void init(int argc, char** argv);
+ GetOpts(int argc, char** argv);
- // longopts.flag must be NULL
- parsed_opts parse(const struct option* longopts);
- parsed_opts parse(const char* command, const struct option* longopts);
+ ParsedOpts parse(const vector<Option>& options);
+ ParsedOpts parse(const char* command, const vector<Option>& options);
- bool hasArgs() const { return argc - optind > 0; }
+ bool has_args() const { return argc - optind > 0; }
- int numArgs() const { return argc - optind; }
+ int num_args() const { return argc - optind; }
- const char* popArg() { return argv[optind++]; }
+ const char* pop_arg() { return argv[optind++]; }
- std::list<std::string> getArgs() const {
- return std::list<std::string>(&argv[optind], &argv[argc]);
- }
+ vector<string> get_args() const { return vector<string>(&argv[optind], &argv[argc]); }
-private:
+ private:
- int argc;
- char** argv;
+ int argc;
+ char** argv;
- std::string make_optstring(const struct option* longopts) const;
+ string make_optstring(const vector<Option>& options) const;
+ vector<struct option> make_longopts(const vector<Option> options) const;
- typedef std::map<int, const char*> short2long_t;
+ vector<Option>::const_iterator find(const vector<Option>& options, char c) const;
- short2long_t make_short2long(const struct option* longopts) const;
+ };
-};
+}
#endif
+-------------------------------------------------------------------
+Fri Aug 28 11:06:23 CEST 2020 - aschnell@suse.com
+
+- improved error reporting in getopt wrapper (part of bsc#1150156)
+
-------------------------------------------------------------------
Thu Aug 27 12:04:44 CEST 2020 - aschnell@suse.com
check_PROGRAMS = sysconfig-get1.test dirname1.test basename1.test \
equal-date.test dbus-escape.test cmp-lt.test humanstring.test table.test \
- csv-formatter.test json-formatter.test
+ csv-formatter.test json-formatter.test getopts.test
if ENABLE_BTRFS_QUOTA
check_PROGRAMS += qgroup1.test
csv_formatter_test_LDADD = -lboost_unit_test_framework ../client/utils/libutils.la
json_formatter_test_LDADD = -lboost_unit_test_framework ../client/utils/libutils.la
+
+getopts_test_LDADD = -lboost_unit_test_framework ../client/utils/libutils.la
--- /dev/null
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE getopt
+
+#include <boost/test/unit_test.hpp>
+
+#include "../client/utils/GetOpts.h"
+
+using namespace snapper;
+
+
+class Args
+{
+
+public:
+
+ Args(std::initializer_list<string> init)
+ {
+ optind = 0;
+
+ for (const string& s : init)
+ tmp.push_back(strdup(s.c_str()));
+ tmp.push_back(nullptr);
+ }
+
+ ~Args()
+ {
+ for (char* s : tmp)
+ free(s);
+ }
+
+ int argc() const { return tmp.size() - 1; }
+ char** argv() { return &tmp.front(); }
+
+ bool all_used() const { return (size_t)(optind) == tmp.size() - 1; }
+
+private:
+
+ vector<char*> tmp;
+
+};
+
+
+const vector<Option> global_opts = {
+ Option("verbose", no_argument, 'v'),
+ Option("table-style", required_argument, 't')
+};
+
+
+const vector<Option> create_opts = {
+ Option("type", required_argument, 't'),
+ Option("print-number", no_argument, 'p'),
+};
+
+
+BOOST_AUTO_TEST_CASE(good1)
+{
+ Args args({ "getopt", "--verbose" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ ParsedOpts parsed_global_opts = get_opts.parse(global_opts);
+
+ BOOST_CHECK(parsed_global_opts.has_option("verbose"));
+ BOOST_CHECK(!parsed_global_opts.has_option("read-my-mind"));
+
+ BOOST_CHECK(!get_opts.has_args());
+
+ BOOST_CHECK(args.all_used());
+}
+
+
+BOOST_AUTO_TEST_CASE(good2)
+{
+ Args args({ "getopt", "-v", "create", "--type", "pre" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ // parse global options
+
+ ParsedOpts parsed_global_opts = get_opts.parse(global_opts);
+
+ BOOST_CHECK(parsed_global_opts.has_option("verbose"));
+ BOOST_CHECK(!parsed_global_opts.has_option("dry-run"));
+
+ // check that command is there
+
+ BOOST_CHECK(get_opts.has_args());
+ BOOST_CHECK_EQUAL(get_opts.pop_arg(), "create");
+
+ // parse create options
+
+ ParsedOpts parsed_create_opts = get_opts.parse("create", create_opts);
+
+ BOOST_CHECK(parsed_create_opts.has_option("type"));
+
+ ParsedOpts::const_iterator it = parsed_create_opts.find("type");
+ BOOST_CHECK(it != parsed_create_opts.end());
+ BOOST_CHECK(it->second == "pre");
+
+ // check that no further command is there
+
+ BOOST_CHECK(!get_opts.has_args());
+
+ BOOST_CHECK(args.all_used());
+}
+
+
+BOOST_AUTO_TEST_CASE(good3)
+{
+ Args args({ "getopt", "create", "-tpre" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ // parse global options
+
+ ParsedOpts parsed_global_opts = get_opts.parse(global_opts);
+
+ // check that command is there
+
+ BOOST_CHECK(get_opts.has_args());
+ BOOST_CHECK_EQUAL(get_opts.pop_arg(), "create");
+
+ // parse create options
+
+ ParsedOpts parsed_create_opts = get_opts.parse("create", create_opts);
+
+ BOOST_CHECK(parsed_create_opts.has_option("type"));
+
+ ParsedOpts::const_iterator it = parsed_create_opts.find("type");
+ BOOST_CHECK(it != parsed_create_opts.end());
+ BOOST_CHECK(it->second == "pre");
+
+ // check that no further command is there
+
+ BOOST_CHECK(!get_opts.has_args());
+
+ BOOST_CHECK(args.all_used());
+}
+
+
+BOOST_AUTO_TEST_CASE(error1)
+{
+ Args args({ "getopt", "--table-style" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ BOOST_CHECK_EXCEPTION(get_opts.parse(global_opts), OptionsException, [](const exception& e) {
+ return strcmp(e.what(), "Missing argument for global option '--table-style'.") == 0;
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE(error2)
+{
+ Args args({ "getopt", "create", "--type" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ get_opts.parse(global_opts);
+ get_opts.pop_arg();
+
+ BOOST_CHECK_EXCEPTION(get_opts.parse("create", create_opts), OptionsException, [](const exception& e) {
+ return strcmp(e.what(), "Missing argument for command option '--type'.") == 0;
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE(error3)
+{
+ Args args({ "getopt", "--read-my-mind" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ BOOST_CHECK_EXCEPTION(get_opts.parse(global_opts), OptionsException, [](const exception& e) {
+ return strcmp(e.what(), "Unknown global option '--read-my-mind'.") == 0;
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE(error4)
+{
+ Args args({ "getopt", "create", "--read-my-mind" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ get_opts.parse(global_opts);
+ get_opts.pop_arg();
+
+ BOOST_CHECK_EXCEPTION(get_opts.parse("create", create_opts), OptionsException, [](const exception& e) {
+ return strcmp(e.what(), "Unknown option '--read-my-mind' for command 'create'.") == 0;
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE(error5)
+{
+ Args args({ "getopt", "create", "-px" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ get_opts.parse(global_opts);
+ get_opts.pop_arg();
+
+ BOOST_CHECK_EXCEPTION(get_opts.parse("create", create_opts), OptionsException, [](const exception& e) {
+ return strcmp(e.what(), "Unknown option '-x' for command 'create'.") == 0;
+ });
+}
+
+
+BOOST_AUTO_TEST_CASE(error6)
+{
+ Args args({ "getopt", "create", "-pt" });
+ GetOpts get_opts(args.argc(), args.argv());
+
+ get_opts.parse(global_opts);
+ get_opts.pop_arg();
+
+ BOOST_CHECK_EXCEPTION(get_opts.parse("create", create_opts), OptionsException, [](const exception& e) {
+ return strcmp(e.what(), "Missing argument for command option '--type'.") == 0;
+ });
+}