From 8a1e4a48dd598b5663fc60668755b0ce0a312c6c Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Thu, 28 Aug 2014 05:46:49 +0200 Subject: [PATCH] cmdargs: use boost::program_options --- configure.ac | 10 +++ src/cmdargs.cpp | 188 +++++++++++++++++++++++++++++------------------ src/cmdargs.h | 2 +- src/ncmpcpp.cpp | 25 +------ src/settings.cpp | 20 +---- src/settings.h | 7 +- 6 files changed, 133 insertions(+), 119 deletions(-) diff --git a/configure.ac b/configure.ac index d64ec02d..b12253fa 100644 --- a/configure.ac +++ b/configure.ac @@ -146,6 +146,16 @@ AC_CHECK_HEADERS([boost/date_time/posix_time/posix_time.hpp], , AC_MSG_ERROR(boost/date_time/posix_time/posix_time.hpp is missing) ) +dnl ====================================== +dnl = checking for boost.program_options = +dnl ====================================== +AC_CHECK_HEADERS([boost/program_options.hpp], , + AC_MSG_ERROR(boost/program_options.hpp is missing) +) +AC_CHECK_LIB(boost_program_options$BOOST_LIB_SUFFIX, main, LDFLAGS="$LDFLAGS -lboost_program_options$BOOST_LIB_SUFFIX", + AC_MSG_ERROR([no boost.program_options library found]) +) + dnl ============================ dnl = checking for boost.regex = dnl ============================ diff --git a/src/cmdargs.cpp b/src/cmdargs.cpp index a246fa76..871a4ed1 100644 --- a/src/cmdargs.cpp +++ b/src/cmdargs.cpp @@ -18,115 +18,159 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include #include +#include "bindings.h" #include "cmdargs.h" #include "config.h" #include "mpdpp.h" #include "settings.h" -void ParseArgv(int argc, char **argv) +namespace po = boost::program_options; + +using std::cerr; +using std::cout; + +namespace { + +const char *env_home; + +void replace_tilda_with_home(std::string &s) { - for (int i = 1; i < argc; ++i) + if (!s.empty() && s[0] == '~') + s.replace(0, 1, env_home); +} + +} + +bool ParseArguments(int argc, char **argv) +{ + std::string bindings_path, config_path; + + po::options_description desc("Options"); + desc.add_options() + ("host,h", po::value()->default_value("localhost"), "connect to server at host") + ("port,p", po::value()->default_value(6600), "connect to server at port") + ("config,c", po::value(&config_path)->default_value("~/.ncmpcpp/config"), "specify configuration file") + ("bindigs,b", po::value(&bindings_path)->default_value("~/.ncmpcpp/bindings"), "specify bindings file") + ("screen,s", po::value(), "specify the startup screen") + ("help,?", "show help message") + ("version,v", "display version information") + ; + + po::variables_map vm; + try { - if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host")) + po::store(po::parse_command_line(argc, argv, desc), vm); + + if (vm.count("help")) { - if (++i >= argc) - exit(1); - Mpd.SetHostname(argv[i]); - continue; + cout << "Usage: " << argv[0] << " [options]...\n" << desc << "\n"; + return false; } - if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")) - { - if (++i >= argc) - exit(1); - Mpd.SetPort(atoi(argv[i])); - continue; - } - else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) + if (vm.count("version")) { std::cout << "ncmpcpp " << VERSION << "\n\n" << "optional screens compiled-in:\n" -# ifdef HAVE_TAGLIB_H + # ifdef HAVE_TAGLIB_H << " - tag editor\n" << " - tiny tag editor\n" -# endif -# ifdef HAVE_CURL_CURL_H + # endif + # ifdef HAVE_CURL_CURL_H << " - artist info\n" -# endif -# ifdef ENABLE_OUTPUTS + # endif + # ifdef ENABLE_OUTPUTS << " - outputs\n" -# endif -# ifdef ENABLE_VISUALIZER + # endif + # ifdef ENABLE_VISUALIZER << " - visualizer\n" -# endif -# ifdef ENABLE_CLOCK + # endif + # ifdef ENABLE_CLOCK << " - clock\n" -# endif + # endif << "\nencoding detection: " -# ifdef HAVE_LANGINFO_H + # ifdef HAVE_LANGINFO_H << "enabled" -# else + # else << "disabled" -# endif // HAVE_LANGINFO_H + # endif // HAVE_LANGINFO_H << "\nbuilt with support for:" -# ifdef HAVE_CURL_CURL_H + # ifdef HAVE_CURL_CURL_H << " curl" -# endif -# ifdef HAVE_FFTW3_H + # endif + # ifdef HAVE_FFTW3_H << " fftw" -# endif -# ifdef USE_PDCURSES + # endif + # ifdef USE_PDCURSES << " pdcurses" -# else + # else << " ncurses" -# endif -# ifdef HAVE_TAGLIB_H + # endif + # ifdef HAVE_TAGLIB_H << " taglib" -# endif -# ifdef NCMPCPP_UNICODE + # endif + # ifdef NCMPCPP_UNICODE << " unicode" -# endif - << std::endl; - exit(0); + # endif + << "\n"; + return false; } - else if (!strcmp(argv[i], "-?") || !strcmp(argv[i], "--help")) + + po::notify(vm); + + env_home = getenv("HOME"); + if (env_home == nullptr) { - std::cout - << "Usage: ncmpcpp [OPTION]...\n" - << " -h, --host connect to server at host [localhost]\n" - << " -p, --port connect to server at port [6600]\n" - << " -c, --config use alternative configuration file\n" - << " -s, --screen specify the startup screen\n" - << " -?, --help show help message\n" - << " -v, --version display version information\n" - ; - exit(0); + cerr << "Fatal error: HOME environment variable is not defined\n"; + return false; } - - if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--screen")) + replace_tilda_with_home(config_path); + replace_tilda_with_home(bindings_path); + + // read configuration + Config.SetDefaults(); + Config.Read(config_path); + Config.GenerateColumns(); + + // read bindings + if (Bindings.read(bindings_path) == false) + return false; + Bindings.generateDefaults(); + + // try to get MPD connection details from environment variables + // as they take precedence over these from the configuration. + auto env_host = getenv("MPD_HOST"); + auto env_port = getenv("MPD_PORT"); + + if (env_host != nullptr) + Mpd.SetHostname(env_host); + if (env_port != nullptr) + Mpd.SetPort(boost::lexical_cast(env_port)); + + // if MPD connection details are provided as command line + // parameters, use them as their priority is the highest. + if (vm.count("host")) + Mpd.SetHostname(vm["host"].as()); + if (vm.count("port")) + Mpd.SetPort(vm["port"].as()); + + // custom startup screen + if (vm.count("screen")) { - if (++i == argc) - { - std::cerr << "No screen specified" << std::endl; - exit(1); - } - Config.startup_screen_type = stringtoStartupScreenType(argv[i]); + auto screen = vm["screen"].as(); + Config.startup_screen_type = stringtoStartupScreenType(screen); if (Config.startup_screen_type == ScreenType::Unknown) { - std::cerr << "Invalid screen: " << argv[i] << std::endl; - exit(1); + std::cerr << "Invalid screen: " << screen << "\n"; + return false; } } - else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config")) - { - // this is used in Configuration::CheckForCommandLineConfigFilePath, ignoring here. - ++i; - } - else - { - std::cerr << "Invalid option: " << argv[i] << std::endl; - exit(1); - } } + catch (std::exception &e) + { + cerr << "Error while parsing command line options: " << e.what() << "\n"; + return false; + } + return true; } diff --git a/src/cmdargs.h b/src/cmdargs.h index 11a034fc..1a087737 100644 --- a/src/cmdargs.h +++ b/src/cmdargs.h @@ -21,6 +21,6 @@ #ifndef NCMPCPP_CMDARGS_H #define NCMPCPP_CMDARGS_H -void ParseArgv(int argc, char **argv); +bool ParseArguments(int argc, char **argv); #endif // NCMPCPP_CMDARGS_H diff --git a/src/ncmpcpp.cpp b/src/ncmpcpp.cpp index e6dd2cfb..9dfb0e77 100644 --- a/src/ncmpcpp.cpp +++ b/src/ncmpcpp.cpp @@ -101,31 +101,10 @@ int main(int argc, char **argv) std::setlocale(LC_ALL, ""); std::locale::global(Charset::internalLocale()); - Config.CheckForCommandLineConfigFilePath(argv, argc); - - Config.SetDefaults(); - Config.Read(); - Config.GenerateColumns(); - - if (!Bindings.read(Config.ncmpcpp_directory + "bindings")) - return 1; - Bindings.generateDefaults(); - - if (getenv("MPD_HOST")) - Mpd.SetHostname(getenv("MPD_HOST")); - if (getenv("MPD_PORT")) - Mpd.SetPort(atoi(getenv("MPD_PORT"))); - - if (Config.mpd_host != "localhost") - Mpd.SetHostname(Config.mpd_host); - if (Config.mpd_port != 6600) - Mpd.SetPort(Config.mpd_port); + if (!ParseArguments(argc, argv)) + return 0; Mpd.SetTimeout(Config.mpd_connection_timeout); - - if (argc > 1) - ParseArgv(argc, argv); - CreateDir(Config.ncmpcpp_directory); // always execute these commands, even if ncmpcpp use exit function diff --git a/src/settings.cpp b/src/settings.cpp index f8475721..941e73f5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -221,7 +221,6 @@ Configuration::Configuration() ncmpcpp_directory = GetHomeDirectory() + ".ncmpcpp/"; lyrics_directory = GetHomeDirectory() + ".lyrics/"; # endif // WIN32 - config_file_path = ncmpcpp_directory + "config"; } const std::string &Configuration::GetHomeDirectory() @@ -242,24 +241,9 @@ const std::string &Configuration::GetHomeDirectory() return home_directory; } -void Configuration::CheckForCommandLineConfigFilePath(char **argv, int argc) +void Configuration::Read(const std::string &config_path) { - if (argc < 3) - return; - for (int i = 1; i < argc; ++i) - { - if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config")) - { - if (++i >= argc) - continue; - config_file_path = argv[i]; - } - } -} - -void Configuration::Read() -{ - std::ifstream f(config_file_path.c_str()); + std::ifstream f(config_path.c_str()); std::string cl, v, name; if (!f.is_open()) diff --git a/src/settings.h b/src/settings.h index 976d4beb..60bde129 100644 --- a/src/settings.h +++ b/src/settings.h @@ -30,8 +30,6 @@ #include "screen_type.h" #include "strbuffer.h" -struct BaseScreen; // forward declaration for screens sequence - enum SortMode { smName, smMTime, smCustomFormat }; struct Column @@ -56,7 +54,7 @@ struct Configuration void CheckForCommandLineConfigFilePath(char **argv, int argc); void SetDefaults(); - void Read(); + void Read(const std::string& config_path); void GenerateColumns(); std::string ncmpcpp_directory; @@ -197,9 +195,8 @@ struct Configuration private: void MakeProperPath(std::string &dir); - + std::string home_directory; - std::string config_file_path; }; extern Configuration Config;