mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-02-26 08:22:31 +00:00
Basic and advanced command line parsing implemented.
This commit is contained in:
parent
0862d24e99
commit
718183d30a
@ -13,8 +13,8 @@
|
||||
#include "propedit/change.h"
|
||||
|
||||
change_c::change_c(change_c::change_type_e type,
|
||||
const std::string name,
|
||||
const std::string value)
|
||||
const std::string &name,
|
||||
const std::string &value)
|
||||
: m_type(type)
|
||||
, m_name(name)
|
||||
, m_value(value)
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/smart_pointers.h"
|
||||
|
||||
class change_c {
|
||||
public:
|
||||
enum change_type_e {
|
||||
@ -27,9 +29,10 @@ public:
|
||||
std::string m_name, m_value;
|
||||
|
||||
public:
|
||||
change_c(change_type_e type, const std::string name, const std::string value);
|
||||
change_c(change_type_e type, const std::string &name, const std::string &value);
|
||||
|
||||
void validate();
|
||||
};
|
||||
typedef counted_ptr<change_c> change_cptr;
|
||||
|
||||
#endif // __PROPEDIT_CHANGE_H
|
||||
|
@ -20,4 +20,48 @@ options_c::options_c()
|
||||
|
||||
void
|
||||
options_c::validate() {
|
||||
if (m_file_name.empty())
|
||||
mxerror(Y("No file name given.\n"));
|
||||
}
|
||||
|
||||
target_cptr
|
||||
options_c::add_target(target_c::target_type_e type,
|
||||
const std::string &spec) {
|
||||
target_cptr target(new target_c);
|
||||
target->m_type = type;
|
||||
target->parse_target_spec(spec);
|
||||
|
||||
m_targets.push_back(target);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
target_cptr
|
||||
options_c::add_target(target_c::target_type_e type) {
|
||||
return add_target(type, "");
|
||||
}
|
||||
|
||||
target_cptr
|
||||
options_c::add_target(const std::string &spec) {
|
||||
return add_target(target_c::tt_undefined, spec);
|
||||
}
|
||||
|
||||
void
|
||||
options_c::set_file_name(const std::string &file_name) {
|
||||
if (!m_file_name.empty())
|
||||
mxinfo(boost::format(Y("More than one file name has been given ('%1%' and '%2%').")) % m_file_name % file_name);
|
||||
|
||||
m_file_name = file_name;
|
||||
}
|
||||
|
||||
void
|
||||
options_c::set_parse_mode(const std::string &parse_mode) {
|
||||
if (parse_mode == "full")
|
||||
m_parse_mode = kax_analyzer_c::parse_mode_full;
|
||||
|
||||
else if (parse_mode == "fast")
|
||||
m_parse_mode = kax_analyzer_c::parse_mode_fast;
|
||||
|
||||
else
|
||||
throw false;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
class options_c {
|
||||
public:
|
||||
std::string m_file_name;
|
||||
std::vector<target_c> m_targets;
|
||||
std::vector<target_cptr> m_targets;
|
||||
bool m_show_progress;
|
||||
kax_analyzer_c::parse_mode_e m_parse_mode;
|
||||
|
||||
@ -32,6 +32,15 @@ public:
|
||||
options_c();
|
||||
|
||||
void validate();
|
||||
|
||||
target_cptr add_target(target_c::target_type_e type);
|
||||
target_cptr add_target(const std::string &spec);
|
||||
void set_file_name(const std::string &file_name);
|
||||
void set_parse_mode(const std::string &parse_mode);
|
||||
|
||||
protected:
|
||||
target_cptr add_target(target_c::target_type_e type, const std::string &spec);
|
||||
};
|
||||
typedef counted_ptr<options_c> options_cptr;
|
||||
|
||||
#endif // __PROPEDIT_OPTIONS_H
|
||||
|
@ -13,19 +13,19 @@
|
||||
#include "propedit/setup.h"
|
||||
|
||||
static void
|
||||
run(options_c &options) {
|
||||
kax_analyzzer_cptr analyzer;
|
||||
run(options_cptr options) {
|
||||
console_kax_analyzer_cptr analyzer;
|
||||
|
||||
try {
|
||||
if (!kax_analyzer_c::probe(options.m_file_name))
|
||||
mxerror(boost::format("The file '%1%' is not a Matroska file or it could not be found.") % options.m_file_name);
|
||||
if (!kax_analyzer_c::probe(options->m_file_name))
|
||||
mxerror(boost::format("The file '%1%' is not a Matroska file or it could not be found.\n") % options->m_file_name);
|
||||
|
||||
analyzer = kax_analyzer_c::open(options.m_file_name);
|
||||
analyzer = console_kax_analyzer_cptr(new console_kax_analyzer_c(options->m_file_name));
|
||||
} catch (...) {
|
||||
mxerror(boost::format("The file '%1%' could not be opened for read/write access.") % options.m_file_name);
|
||||
mxerror(boost::format("The file '%1%' could not be opened for read/write access.\n") % options->m_file_name);
|
||||
}
|
||||
|
||||
|
||||
analyzer->set_show_progress(options->m_show_progress);
|
||||
}
|
||||
|
||||
/** \brief Setup and high level program control
|
||||
@ -38,8 +38,8 @@ main(int argc,
|
||||
char **argv) {
|
||||
setup();
|
||||
|
||||
options_c options = parse_args(command_line_utf8(argc, argv));
|
||||
options.validate();
|
||||
options_cptr options = propedit_cli_parser_c(command_line_utf8(argc, argv)).run();
|
||||
options->validate();
|
||||
|
||||
run(options);
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "common/os.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
@ -22,6 +23,9 @@
|
||||
#include "common/command_line.h"
|
||||
#include "common/common.h"
|
||||
#include "common/ebml.h"
|
||||
#include "common/translation.h"
|
||||
#include "common/unique_numbers.h"
|
||||
#include "common/xml/element_mapping.h"
|
||||
#include "propedit/setup.h"
|
||||
|
||||
#ifdef SYS_WINDOWS
|
||||
@ -30,27 +34,115 @@
|
||||
|
||||
using namespace libmatroska;
|
||||
|
||||
/** \brief Outputs usage information
|
||||
*/
|
||||
static void
|
||||
set_usage() {
|
||||
usage_text = "";
|
||||
usage_text += Y("mkvpropedit <file> [options]\n");
|
||||
usage_text += "\n";
|
||||
usage_text += Y(" Global options:\n");
|
||||
usage_text += Y(" -v, --verbose verbose status\n");
|
||||
usage_text += "\n";
|
||||
propedit_cli_parser_c::propedit_cli_parser_c(const std::vector<std::string> &args)
|
||||
: cli_parser_c(args)
|
||||
, m_options(options_cptr(new options_c))
|
||||
, m_target(m_options->add_target(target_c::tt_segment_info))
|
||||
{
|
||||
}
|
||||
|
||||
options_c
|
||||
parse_args(std::vector<std::string> args) {
|
||||
set_usage();
|
||||
while (handle_common_cli_args(args, ""))
|
||||
set_usage();
|
||||
propedit_cli_parser_c::~propedit_cli_parser_c() {
|
||||
}
|
||||
|
||||
options_c options;
|
||||
void
|
||||
propedit_cli_parser_c::set_usage() {
|
||||
usage_text = "";
|
||||
usage_text += Y("mkvpropedit [options] <file> [actions]\n");
|
||||
usage_text += "\n";
|
||||
usage_text += Y(" Options:\n");
|
||||
usage_text += Y(" -v, --verbose Show verbose progress reports\n");
|
||||
usage_text += Y(" -p, --parse-mode <mode> Sets the Matroska parser mode to 'fast'\n");
|
||||
usage_text += Y(" (default) or 'full'\n");
|
||||
usage_text += "\n";
|
||||
usage_text += Y(" Actions:\n");
|
||||
usage_text += Y(" -e, --edit <selector> Sets the Matroska file section that all following\n");
|
||||
usage_text += Y(" add/set/delete actions operate on (see man page)\n");
|
||||
usage_text += Y(" -a, --add <name=value> Add a property with a value even if such a\n");
|
||||
usage_text += Y(" property already exists\n");
|
||||
usage_text += Y(" -s, --set <name=value> Set a property to a value if it exists and\n");
|
||||
usage_text += Y(" add it otherwise\n");
|
||||
usage_text += Y(" -d, --delete <name> Delete all occurences of a property\n");
|
||||
usage_text += Y(" Other options:\n");
|
||||
usage_text += Y(" -l, --list-property-names\n");
|
||||
usage_text += Y(" Lists all valid property names\n");
|
||||
usage_text += Y(" --ui-language <code> Force the translations for 'code' to be used.\n");
|
||||
usage_text += Y(" --command-line-charset <charset>\n"
|
||||
" Charset for strings on the command line\n");
|
||||
usage_text += Y(" --output-charset <cset> Output messages in this charset\n");
|
||||
usage_text += Y(" -r, --redirect-output <file>\n"
|
||||
" Redirects all messages into this file.\n");
|
||||
usage_text += Y(" @optionsfile Reads additional command line options from\n"
|
||||
" the specified file (see man page).\n");
|
||||
usage_text += Y(" -h, --help Show this help.\n");
|
||||
usage_text += Y(" -V, --version Show version information.\n");
|
||||
usage_text += "\n\n";
|
||||
usage_text += Y("The order of the various options is not important.\n");
|
||||
|
||||
return options;
|
||||
version_info = "mkvpropedit v" VERSION " ('" VERSIONNAME "')";
|
||||
}
|
||||
|
||||
void
|
||||
propedit_cli_parser_c::add_option(const std::string &spec,
|
||||
void (propedit_cli_parser_c::*callback)(),
|
||||
const std::string &description) {
|
||||
cli_parser_c::add_option(spec, boost::bind(callback, this), description);
|
||||
}
|
||||
|
||||
void
|
||||
propedit_cli_parser_c::set_parse_mode() {
|
||||
try {
|
||||
m_options->set_parse_mode(m_next_arg);
|
||||
} catch (...) {
|
||||
mxerror(boost::format(Y("Unknown parse mode in '%1% %2%'.")) % m_current_arg % m_next_arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
propedit_cli_parser_c::add_target() {
|
||||
try {
|
||||
m_target = m_options->add_target(m_next_arg);
|
||||
} catch (...) {
|
||||
mxerror(boost::format(Y("Invalid selector in '%1% %2%'.\n")) % m_current_arg % m_next_arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
propedit_cli_parser_c::add_change() {
|
||||
try {
|
||||
change_c::change_type_e type = (m_current_arg == "-a") || (m_current_arg == "--add") ? change_c::ct_add
|
||||
: (m_current_arg == "-s") || (m_current_arg == "--set") ? change_c::ct_set
|
||||
: change_c::ct_delete;
|
||||
m_target->add_change(type, m_next_arg);
|
||||
} catch (const char *message) {
|
||||
mxerror(boost::format(Y("Invalid change spec (%3%) in '%1% %2%'.\n")) % m_current_arg % m_next_arg % message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
propedit_cli_parser_c::list_property_names() {
|
||||
mxinfo(Y("All known property names and their meaning:\n"));
|
||||
mxexit(0);
|
||||
}
|
||||
|
||||
void
|
||||
propedit_cli_parser_c::set_file_name() {
|
||||
m_options->set_file_name(m_current_arg);
|
||||
}
|
||||
|
||||
options_cptr
|
||||
propedit_cli_parser_c::run() {
|
||||
add_option("e|edit=s", &propedit_cli_parser_c::add_target, "");
|
||||
add_option("a|add|s|set|d|delete=s", &propedit_cli_parser_c::add_change, "");
|
||||
add_option("p|parse-mode=s", &propedit_cli_parser_c::set_parse_mode, "");
|
||||
add_option("l|list-propety-names", &propedit_cli_parser_c::list_property_names, "");
|
||||
set_default_callback(boost::bind(&propedit_cli_parser_c::set_file_name, this));
|
||||
|
||||
parse_args();
|
||||
|
||||
m_options->validate();
|
||||
m_options->m_show_progress = 1 < verbose;
|
||||
|
||||
return m_options;
|
||||
}
|
||||
|
||||
/** \brief Initialize global variables
|
||||
|
@ -16,9 +16,32 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/cli_parser.h"
|
||||
#include "propedit/options.h"
|
||||
|
||||
void setup();
|
||||
options_c parse_args(std::vector<std::string> args);
|
||||
|
||||
class propedit_cli_parser_c: public cli_parser_c {
|
||||
protected:
|
||||
options_cptr m_options;
|
||||
target_cptr m_target;
|
||||
|
||||
public:
|
||||
propedit_cli_parser_c(const std::vector<std::string> &args);
|
||||
virtual ~propedit_cli_parser_c();
|
||||
|
||||
virtual options_cptr run();
|
||||
|
||||
protected:
|
||||
void add_option(const std::string &spec, void (propedit_cli_parser_c::*callback)(), const std::string &description);
|
||||
|
||||
virtual void set_usage();
|
||||
|
||||
void add_target();
|
||||
void add_change();
|
||||
void set_parse_mode();
|
||||
void set_file_name();
|
||||
void list_property_names();
|
||||
};
|
||||
|
||||
#endif // __PROPEDIT_SETUP_H
|
||||
|
@ -10,13 +10,70 @@
|
||||
|
||||
#include "common/os.h"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/strings/editing.h"
|
||||
#include "propedit/target.h"
|
||||
|
||||
target_c::target_c()
|
||||
: m_target(NULL)
|
||||
: m_type(target_c::tt_undefined)
|
||||
, m_selection_mode(target_c::sm_undefined)
|
||||
, m_selection_param(-1)
|
||||
, m_target(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
target_c::validate() {
|
||||
}
|
||||
|
||||
void
|
||||
target_c::add_change(change_c::change_type_e type,
|
||||
const std::string &spec) {
|
||||
std::string name, value;
|
||||
if (change_c::ct_delete == type)
|
||||
name = spec;
|
||||
|
||||
else {
|
||||
std::vector<std::string> parts = split(spec, "=", 2);
|
||||
if (2 != parts.size())
|
||||
throw Y("missing value");
|
||||
|
||||
name = parts[0];
|
||||
value = parts[1];
|
||||
}
|
||||
|
||||
if (name.empty())
|
||||
throw Y("missing property name");
|
||||
|
||||
m_changes.push_back(change_cptr(new change_c(type, name, value)));
|
||||
}
|
||||
|
||||
void
|
||||
target_c::parse_target_spec(std::string spec) {
|
||||
if (spec.empty())
|
||||
return;
|
||||
|
||||
spec = downcase(spec);
|
||||
|
||||
if ((spec == "segment_info") || (spec == "segmentinfo") || (spec == "info")) {
|
||||
m_type = target_c::tt_segment_info;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string prefix("track:");
|
||||
if (starts_with_case(spec, prefix)) {
|
||||
parse_track_spec(spec.substr(prefix.length()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
target_c::parse_track_spec(const std::string &spec) {
|
||||
boost::regex track_re("^([[:alpha:]]+)?(_[[:alpha:]]+)?(\\.[^@]+)?(@.+)?", boost::regex::perl);
|
||||
boost::smatch matches;
|
||||
|
||||
if (!boost::regex_match(spec, matches, track_re))
|
||||
throw false;
|
||||
}
|
||||
|
@ -20,16 +20,40 @@
|
||||
|
||||
#include "propedit/change.h"
|
||||
|
||||
using namespace libebml;
|
||||
|
||||
class target_c {
|
||||
public:
|
||||
std::vector<change_c> m_changes;
|
||||
std::string m_target_spec;
|
||||
enum target_type_e {
|
||||
tt_undefined,
|
||||
tt_segment_info,
|
||||
tt_track,
|
||||
};
|
||||
|
||||
enum selection_mode_e {
|
||||
sm_undefined,
|
||||
sm_by_number,
|
||||
sm_by_uid,
|
||||
sm_by_position,
|
||||
sm_by_type_and_position,
|
||||
};
|
||||
|
||||
target_type_e m_type;
|
||||
selection_mode_e m_selection_mode;
|
||||
int64_t m_selection_param;
|
||||
|
||||
EbmlMaster *m_target;
|
||||
std::vector<change_cptr> m_changes;
|
||||
|
||||
public:
|
||||
target_c();
|
||||
|
||||
void validate();
|
||||
|
||||
void add_change(change_c::change_type_e type, const std::string &spec);
|
||||
void parse_target_spec(std::string spec);
|
||||
void parse_track_spec(const std::string &spec);
|
||||
};
|
||||
typedef counted_ptr<target_c> target_cptr;
|
||||
|
||||
#endif // __PROPEDIT_TARGET_H
|
||||
|
Loading…
Reference in New Issue
Block a user