Port command line option handling to boost::program_options

This allows for better separation of options in common, gnucash and gnucash-cli options.
pull/728/head
Geert Janssens 6 years ago
parent 317f32de0b
commit a435b4c4f6

@ -517,13 +517,13 @@ set (Boost_FIND_QUIETLY ON)
if (NOT DEFINED ${BOOST_ROOT})
set(BOOST_ROOT $ENV{BOOST_ROOT})
endif()
find_package (Boost 1.67.0 COMPONENTS date_time regex locale filesystem system)
find_package (Boost 1.67.0 COMPONENTS date_time regex locale filesystem system program_options)
if (Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
set(HAVE_BOOST 1)
else()
find_package (Boost 1.60.0 REQUIRED COMPONENTS date_time regex locale filesystem system)
find_package (Boost 1.60.0 REQUIRED COMPONENTS date_time regex locale filesystem system program_options)
if (Boost_FOUND)
include (CheckIncludeFileCXX)
set(CMAKE_REQUIRED_FLAGS "-std=c++17")
@ -538,7 +538,7 @@ else()
endif()
endif()
if (NOT HAVE_BOOST)
message (SEND_ERROR "A suitable Boost is not installed, and is required. GnuCash requires that Boost be compatible and compiled with C++17. Boost 1.67 is the first compatible release but some distributions have patched earlier ones to work with C++17. Please install it and ensure that the following libraries are built: date_time, filesystem, locale, and regex.")
message (SEND_ERROR "A suitable Boost is not installed, and is required. GnuCash requires that Boost be compatible and compiled with C++17. Boost 1.67 is the first compatible release but some distributions have patched earlier ones to work with C++17. Please install it and ensure that the following libraries are built: date_time, filesystem, locale, regex, program_options and system.")
endif()

@ -33,6 +33,7 @@
extern "C" {
#include <gnc-engine-guile.h>
#include <gnc-prefs.h>
#include <gnc-prefs-utils.h>
#include <gnc-gnome-utils.h>
#include <gnc-session.h>
@ -107,17 +108,71 @@ fail:
gnc_shutdown(1);
}
namespace Gnucash {
class GnucashCli : public CoreApp
{
public:
GnucashCli (const char* app_name);
void parse_command_line (int *argc, char ***argv);
void start (int argc, char **argv);
private:
void configure_program_options (void);
std::string m_quotes_file;
};
}
Gnucash::GnucashCli::GnucashCli (const char *app_name) : Gnucash::CoreApp (app_name)
{
configure_program_options();
}
void
Gnucash::GnucashCli::parse_command_line (int *argc, char ***argv)
{
Gnucash::CoreApp::parse_command_line (argc, argv);
if (m_opt_map.count ("namespace"))
gnc_prefs_set_namespace_regexp(m_opt_map["namespace"].
as<std::string>().c_str());
if (m_opt_map.count ("add-price-quotes"))
m_quotes_file = m_opt_map["add-price-quotes"].as<std::string>();
}
// Define command line options specific to gnucash-cli.
void
Gnucash::GnucashCli::configure_program_options (void)
{
bpo::options_description quotes_options(_("Price Retrieval Options"));
quotes_options.add_options()
("add-price-quotes", bpo::value<std::string>(),
N_("Add price quotes to given GnuCash datafile.\n"))
("namespace", bpo::value<std::string>(),
N_("Regular expression determining which namespace commodities will be retrieved"));
m_opt_desc->add (quotes_options);
}
void
Gnucash::GnucashCli::start (int argc, char **argv)
{
Gnucash::CoreApp::start();
if (not m_quotes_file.empty())
scm_boot_guile (argc, argv, inner_main_add_price_quotes, (void *)m_quotes_file.c_str());
}
int
main(int argc, char ** argv)
main(int argc, char **argv)
{
Gnucash::CoreApp application;
Gnucash::GnucashCli application (argv[0]);
application.parse_command_line (&argc, &argv);
application.start ();
auto quotes_file = application.get_quotes_file ();
if (quotes_file)
scm_boot_guile (argc, argv, inner_main_add_price_quotes, (void *)quotes_file);
application.start (argc, argv);
exit(0); /* never reached */
}

@ -49,6 +49,8 @@ extern "C" {
#include <boost/locale.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace bl = boost::locale;
@ -542,11 +544,22 @@ Gnucash::CoreApp::CoreApp ()
textdomain(PROJECT_NAME);
bind_textdomain_codeset(PROJECT_NAME, "UTF-8");
g_free(localedir);
}
Gnucash::CoreApp::CoreApp (const char* app_name)
{
CoreApp();
m_app_name = std::string(app_name);
// Now that gettext is properly initialized, set our help tagline.
tagline = bl::translate("- GnuCash, accounting for personal and small business finance").str(gnc_get_locale());
m_opt_desc = std::make_unique<bpo::options_description> ((bl::format (bl::gettext ("{1} [options]")) % m_app_name).str() + tagline);
add_common_program_options();
}
/* Parse command line options, using GOption interface.
* We can't let gtk_init_with_args do it because it fails
* before parsing any arguments if the GUI can't be initialized.
@ -560,93 +573,9 @@ Gnucash::CoreApp::parse_command_line (int *argc, char ***argv)
char *tmp_log_to_filename = NULL;
#endif
GOptionEntry options[] =
{
{
"version", 'v', 0, G_OPTION_ARG_NONE, &gnucash_show_version,
N_("Show GnuCash version"), NULL
},
{
"debug", '\0', 0, G_OPTION_ARG_NONE, &debugging,
N_("Enable debugging mode: provide deep detail in the logs.\nThis is equivalent to: --log \"=info\" --log \"qof=info\" --log \"gnc=info\""), NULL
},
{
"extra", '\0', 0, G_OPTION_ARG_NONE, &extra,
N_("Enable extra/development/debugging features."), NULL
},
{
"log", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &log_flags,
N_("Log level overrides, of the form \"modulename={debug,info,warn,crit,error}\"\nExamples: \"--log qof=debug\" or \"--log gnc.backend.file.sx=info\"\nThis can be invoked multiple times."),
NULL
},
{
"logto", '\0', 0, G_OPTION_ARG_STRING, &tmp_log_to_filename,
N_("File to log into; defaults to \"/tmp/gnucash.trace\"; can be \"stderr\" or \"stdout\"."),
NULL
},
{
"nofile", '\0', 0, G_OPTION_ARG_NONE, &nofile,
N_("Do not load the last file opened"), NULL
},
{
"gsettings-prefix", '\0', 0, G_OPTION_ARG_STRING, &gsettings_prefix,
N_("Set the prefix for gsettings schemas for gsettings queries. This can be useful to have a different settings tree while debugging."),
/* Translators: Argument description for autohelp; see
* http://developer.gnome.org/doc/API/2.0/glib/glib-Commandline-option-parser.html */
N_("GSETTINGSPREFIX")
},
{
"add-price-quotes", '\0', 0, G_OPTION_ARG_STRING, &add_quotes_file,
N_("Add price quotes to given GnuCash datafile"),
/* Translators: Argument description for autohelp; see
* http://developer.gnome.org/doc/API/2.0/glib/glib-Commandline-option-parser.html */
N_("FILE")
},
{
"namespace", '\0', 0, G_OPTION_ARG_STRING, &namespace_regexp,
N_("Regular expression determining which namespace commodities will be retrieved"),
/* Translators: Argument description for autohelp; see
* http://developer.gnome.org/doc/API/2.0/glib/glib-Commandline-option-parser.html */
N_("REGEXP")
},
{
G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args_remaining, NULL, N_("[datafile]")
},
{ NULL }
};
GError *error = NULL;
GOptionContext *context = g_option_context_new (tagline.c_str());
g_option_context_add_main_entries (context, options, PROJECT_NAME);
if (!gtk_help_msg.empty())
{
GOptionEntry gtk_help_options[] =
{
{
"help-gtk", 'v', 0, G_OPTION_ARG_NONE, &gtk_show_help,
N_("Show GTK+ Options"), NULL
},
{ NULL }
};
g_option_group_add_entries (g_option_context_get_main_group (context), gtk_help_options);
}
if (!g_option_context_parse (context, argc, argv, &error))
{
std::cerr << error->message << "\n"
<< bl::format (bl::translate ("Run '{1} --help' to see a full list of available command line options.")) % *argv[0]
<< "\n";
g_error_free (error);
exit (1);
}
g_option_context_free (context);
bpo::store (bpo::command_line_parser (*argc, *argv).
options (*m_opt_desc.get()).positional(m_pos_opt_desc).run(), m_opt_map);
bpo::notify (m_opt_map);
if (tmp_log_to_filename != NULL)
{
@ -658,7 +587,7 @@ Gnucash::CoreApp::parse_command_line (int *argc, char ***argv)
#endif
}
if (gnucash_show_version)
if (m_opt_map.count ("version"))
{
bl::format rel_fmt (bl::translate ("GnuCash {1}"));
bl::format dev_fmt (bl::translate ("GnuCash {1} development version"));
@ -672,19 +601,53 @@ Gnucash::CoreApp::parse_command_line (int *argc, char ***argv)
exit(0);
}
gnc_prefs_set_debugging(debugging);
gnc_prefs_set_extra(extra);
if (m_opt_map.count ("help"))
{
std::cout << *m_opt_desc.get() << "\n";
exit(0);
}
if (gsettings_prefix)
gnc_gsettings_set_prefix(g_strdup(gsettings_prefix));
gnc_prefs_set_debugging (m_opt_map.count ("debug"));
gnc_prefs_set_extra (m_opt_map.count ("extra"));
if (namespace_regexp)
gnc_prefs_set_namespace_regexp(namespace_regexp);
if (m_opt_map.count ("gsettings-prefix"))
gnc_gsettings_set_prefix (m_opt_map["gsettings-prefix"].
as<std::string>().c_str());
if (args_remaining)
file_to_load = args_remaining[0];
}
/* Define command line options common to all gnucash binaries. */
void
Gnucash::CoreApp::add_common_program_options (void)
{
#ifdef __MINGW64__
wchar_t *tmp_log_to_filename = NULL;
#else
char *tmp_log_to_filename = NULL;
#endif
bpo::options_description common_options(_("Common Options"));
common_options.add_options()
("help,h",
N_("Show this help message"))
("version,v",
N_("Show GnuCash version"))
("debug",
N_("Enable debugging mode: provide deep detail in the logs.\nThis is equivalent to: --log \"=info\" --log \"qof=info\" --log \"gnc=info\""))
("extra",
N_("Enable extra/development/debugging features."))
("log", bpo::value< std::vector<std::string> >(),
N_("Log level overrides, of the form \"modulename={debug,info,warn,crit,error}\"\nExamples: \"--log qof=debug\" or \"--log gnc.backend.file.sx=info\"\nThis can be invoked multiple times."))
("logto", bpo::value<std::string>(),
N_("File to log into; defaults to \"/tmp/gnucash.trace\"; can be \"stderr\" or \"stdout\"."))
("gsettings-prefix", bpo::value<std::string>(),
N_("Set the prefix for gsettings schemas for gsettings queries. This can be useful to have a different settings tree while debugging."));
m_opt_desc->add (common_options);
}
const char*
Gnucash::CoreApp::get_file_to_load (void)
{
@ -697,12 +660,6 @@ Gnucash::CoreApp::get_no_file (void)
return nofile;
}
const char*
Gnucash::CoreApp::get_quotes_file (void)
{
return add_quotes_file;
}
void
Gnucash::CoreApp::start (void)
{

@ -24,34 +24,43 @@
#ifndef GNUCASH_CORE_APP_HPP
#define GNUCASH_CORE_APP_HPP
#include <boost/program_options.hpp>
#include <string>
#include <vector>
namespace Gnucash {
namespace bpo = boost::program_options;
class CoreApp
{
public:
CoreApp ();
CoreApp (const char* app_name);
void parse_command_line (int *argc, char ***argv);
void start (void);
const char *get_file_to_load (void);
int get_no_file (void);
const char *get_quotes_file (void);
protected:
std::string gtk_help_msg;
int gtk_show_help = 0;
std::string m_app_name;
std::string tagline;
std::unique_ptr<bpo::options_description> m_opt_desc;
bpo::variables_map m_opt_map;
bpo::positional_options_description m_pos_opt_desc;
private:
void add_common_program_options (void);
/* Command-line option variables */
int gnucash_show_version = 0;
int debugging = 0;
int extra = 0;
char **log_flags = nullptr;
char **log_flags;
char *log_to_filename = nullptr;
int nofile = 0;
const char *gsettings_prefix = nullptr;

@ -356,41 +356,84 @@ namespace Gnucash {
class Gnucash : public CoreApp
{
public:
Gnucash (const char* app_name);
void parse_command_line (int *argc, char ***argv);
std::string get_quotes_file (void)
{ return m_quotes_file; }
private:
void configure_program_options (void);
std::string m_gtk_help_msg;
std::string m_quotes_file; // Deprecated will be removed in gnucash 5.0
};
}
Gnucash::Gnucash::Gnucash (const char *app_name) : Gnucash::CoreApp (app_name)
{
configure_program_options();
}
void
Gnucash::Gnucash::parse_command_line (int *argc, char ***argv)
{
Gnucash::CoreApp::parse_command_line (argc, argv);
if (m_opt_map.count ("help-gtk"))
{
std::cout << m_gtk_help_msg;
exit(0);
}
if (m_opt_map.count ("namespace"))
gnc_prefs_set_namespace_regexp (m_opt_map["namespace"].
as<std::string>().c_str());
if (m_opt_map.count ("add-price-quotes"))
m_quotes_file = m_opt_map["add-price-quotes"].as<std::string>();
}
// Define command line options specific to gnucash.
void
Gnucash::Gnucash::configure_program_options (void)
{
// The g_option context dance below is done to be able to show a help message
// for gtk's options. The options themselves are already parsed out by
// gtk_init_check by the time this function is called though. So it really only
// serves to be able to display a help message.
GError *error = NULL;
auto context = g_option_context_new (tagline.c_str());
auto gtk_options = gtk_get_option_group(FALSE);
g_option_context_add_group (context, gtk_options);
gtk_help_msg = std::string (g_option_context_get_help (context, FALSE, gtk_options));
m_gtk_help_msg = g_option_context_get_help (context, FALSE, gtk_options);
g_option_context_free (context);
// Pass remaining command line bits to our base class for further parsing
// This will include a --help-gtk option to display gtk's option help
// extracted above
Gnucash::CoreApp::parse_command_line (argc, argv);
if (gtk_show_help)
{
std::cout << gtk_help_msg;
exit(0);
}
bpo::options_description app_options(_("Application Options"));
app_options.add_options()
("nofile",
N_("Do not load the last file opened"))
("help-gtk", _("Show help for gtk options"))
("add-price-quotes", bpo::value<std::string>(),
N_("Add price quotes to given GnuCash datafile.\n"
"Note this option has been deprecated and will be removed in GnuCash 5.0.\n"
"Please use \"gnucash-cli --add-price-quotes\" instead."))
("namespace", bpo::value<std::string>(),
N_("Regular expression determining which namespace commodities will be retrieved"
"Note this option has been deprecated and will be removed in GnuCash 5.0.\n"
"Please use \"gnucash-cli --add-price-quotes\" instead."))
("input-file", bpo::value<std::string>(),
N_("[datafile]"));
m_pos_opt_desc.add("input-file", -1);
m_opt_desc->add (app_options);
}
int
main(int argc, char ** argv)
{
Gnucash::Gnucash application;
Gnucash::Gnucash application (argv[0]);
/* We need to initialize gtk before looking up all modules */
if(!gtk_init_check (&argc, &argv))
@ -407,9 +450,9 @@ main(int argc, char ** argv)
/* If asked via a command line parameter, fetch quotes only */
auto quotes_file = application.get_quotes_file ();
if (quotes_file)
if (!quotes_file.empty())
{
scm_boot_guile (argc, argv, inner_main_add_price_quotes, (void*) quotes_file);
scm_boot_guile (argc, argv, inner_main_add_price_quotes, (void*) quotes_file.c_str());
exit (0); /* never reached */
}

Loading…
Cancel
Save