diff options
-rw-r--r-- | config/main.cpp | 8 | ||||
-rw-r--r-- | lib/configuration/configuration.cpp | 83 | ||||
-rw-r--r-- | lib/configuration/configuration.h | 23 | ||||
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/browser.cpp | 3 | ||||
-rw-r--r-- | src/commandline.cpp | 135 | ||||
-rw-r--r-- | src/commandline.h | 38 | ||||
-rw-r--r-- | src/main.cpp | 26 |
8 files changed, 96 insertions, 222 deletions
diff --git a/config/main.cpp b/config/main.cpp index 16ff6db..2ebad8d 100644 --- a/config/main.cpp +++ b/config/main.cpp @@ -15,12 +15,12 @@ int main(int argc, char **argv) app.setQuitOnLastWindowClosed(true); Configuration config; - config.read(Configuration::defaultUserConfigLocation()); + config.parseConfigFile(config.value<std::string>("config").value()); SettingsDialog dlg(&config); - dlg.configPath = Configuration::defaultUserConfigLocation(); - dlg.setWindowTitle("poi-config: " + Configuration::defaultUserConfigLocation()); + dlg.configPath = QString::fromStdString(config.value<std::string>("config").value()); + dlg.setWindowTitle("poi-config: " + dlg.configPath); dlg.show(); return app.exec(); -}
\ No newline at end of file +} diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp index 48f051d..7032a1d 100644 --- a/lib/configuration/configuration.cpp +++ b/lib/configuration/configuration.cpp @@ -10,16 +10,49 @@ #include <QStandardPaths> #include <fstream> #include <boost/algorithm/string/predicate.hpp> +#include <iostream> +#include <QCoreApplication> namespace po = boost::program_options; +inline std::string defaultUserConfigLocation() +{ + // try to locate an existing config + QString path = QStandardPaths::locate(QStandardPaths::ConfigLocation, "smolbote/smolbote.cfg"); + + // it's possible there is no config, so set the path properly + if(path.isEmpty()) + path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/smolbote/smolbote.cfg"; + + return path.toStdString(); +} + +constexpr const char *defaultSocketPath() +{ +#if defined(Q_OS_UNIX) + // could be a path such as "/tmp/foo" + return "/tmp/smolbote.socket"; +#elif defined(Q_OS_WIN32) + // could be a pipe path such as "\\.\pipe\foo" + return "\\\\.\\pipe\\smolbote_socket"; +#endif +} + Configuration::Configuration() { m_homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString(); - // create description - desc.add_options() + commandLine_desc.add_options() + ("help,h", "Display this help.") + ("version,v", "Display version information.") + + ("config,c", po::value<std::string>()->default_value(defaultUserConfigLocation()), "Set the configuration file.") + ("socket,s", po::value<std::string>()->default_value(defaultSocketPath()), "Local server socket") + + ("url", po::value<std::vector<std::string>>(), "URLs") + ; + configuration_desc.add_options() // main window ui ("mainwindow.height", po::value<int>()->default_value(720)) ("mainwindow.width", po::value<int>()->default_value(1280)) @@ -82,46 +115,56 @@ Configuration::Configuration() ("downloads.path", po::value<std::string>()->default_value("~/Downloads")) ("downloads.shortcut", po::value<std::string>()->default_value("Ctrl+D")) ; + + arguments_desc.add("url", -1); } Configuration::~Configuration() = default; -QString Configuration::defaultUserConfigLocation() -{ - // try to locate an existing config - QString path = QStandardPaths::locate(QStandardPaths::ConfigLocation, "smolbote/smolbote.cfg"); - - // it's possible there is no config, so set the path properly - if(path.isEmpty()) - path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/smolbote/smolbote.cfg"; - - return path; -} - -bool Configuration::read(const QString &path) +bool Configuration::parseConfigFile(const std::string &path) { - std::ifstream f(path.toStdString(), std::ifstream::in); + std::ifstream f(path, std::ifstream::in); // parse_config_file(file, options_description, allow_unregistered) - po::store(po::parse_config_file(f, desc, true), vm); + po::store(po::parse_config_file(f, configuration_desc, true), vm); return true; } -bool Configuration::parse(int argc, char **argv) +bool Configuration::parseCommandLine(int argc, char **argv) { try { - po::store(po::parse_command_line(argc, argv, desc), vm); + auto cmd = po::command_line_parser(argc, argv); + po::options_description desc; + desc.add(commandLine_desc).add(configuration_desc); + cmd.options(desc); + cmd.positional(arguments_desc); + po::store(cmd.run(), vm); } catch(const po::error &e) { + qWarning("Error parsing command line: %s", e.what()); return false; } + if(vm.count("help")) { + std::cout << qUtf8Printable(qApp->applicationName()) << " " << qUtf8Printable(qApp->applicationVersion()) << ": yet another no-frills browser" << std::endl; + std::cout << "Usage: " << qUtf8Printable(qApp->arguments().at(0)) << " [options] URL(s)" << std::endl; + + std::cout << std::endl << "Command-line Options: " << std::endl << commandLine_desc << std::endl; + std::cout << std::endl << "Configuration Options: " << std::endl << configuration_desc << std::endl; + exit(0); + } + + if(vm.count("version")) { + std::cout << qUtf8Printable(qApp->applicationName()) << " " << qUtf8Printable(qApp->applicationVersion()) << std::endl; + exit(0); + } + return true; } QHash<QString, QString> Configuration::section(const std::string &prefix) const { QHash<QString, QString> v; - for(auto &s : desc.options()) { + for(auto &s : configuration_desc.options()) { if(boost::starts_with(s->long_name(), prefix)) { v[s->long_name().c_str()] = QString::fromStdString(value<std::string>(s->long_name().c_str()).value()); } diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h index 5b59766..5bb9f5d 100644 --- a/lib/configuration/configuration.h +++ b/lib/configuration/configuration.h @@ -23,10 +23,8 @@ public: explicit Configuration(); ~Configuration(); - static QString defaultUserConfigLocation(); - - bool read(const QString &path); - bool parse(int argc, char **argv); + bool parseConfigFile(const std::string &path); + bool parseCommandLine(int argc, char **argv); template <typename T> std::optional<T> value(const char *path) const @@ -66,13 +64,26 @@ public: const std::vector<boost::shared_ptr<boost::program_options::option_description>> &options() { - return desc.options(); + return configuration_desc.options(); } QHash<QString, QString> section(const std::string &prefix) const; + QStringList positionalArguments() const + { + QStringList l; + if(vm.count("url")) { + std::vector<std::string> urls = vm["url"].as<std::vector<std::string>>(); + for(const std::string &s : urls) { + l.append(QString::fromStdString(s)); + } + } + return l; + } private: - boost::program_options::options_description desc; + boost::program_options::options_description commandLine_desc; + boost::program_options::options_description configuration_desc; + boost::program_options::positional_options_description arguments_desc; boost::program_options::variables_map vm; std::string m_homePath; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1321604..dd325ec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,8 +13,6 @@ add_executable(poi singleapplication.h browser.cpp browser.h - commandline.cpp - commandline.h ../data/resources.qrc # main window diff --git a/src/browser.cpp b/src/browser.cpp index 9b691e4..3f4805a 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -28,7 +28,8 @@ Browser::Browser(int &argc, char *argv[]) Browser::~Browser() { - m_bookmarks->save(); + if(m_bookmarks) + m_bookmarks->save(); qDeleteAll(m_windows); m_windows.clear(); } diff --git a/src/commandline.cpp b/src/commandline.cpp deleted file mode 100644 index 6082686..0000000 --- a/src/commandline.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * This file is part of smolbote. It's copyrighted by the contributors recorded - * in the version control history of the file, available from its original - * location: https://neueland.iserlohn-fortress.net/smolbote.hg - * - * SPDX-License-Identifier: GPL-3.0 - */ - -#include "commandline.h" -#include "version.h" -#include <configuration.h> -#include <iomanip> -#include <iostream> - -inline std::string optionText(const QStringList &opts) -{ - std::string r; - for(auto i = opts.constBegin(); i != opts.constEnd(); ) { - if(i->length() == 1) { - r.append("-" + i->toStdString()); - } else { - r.append("--" + i->toStdString()); - } - - ++i; - if(i != opts.constEnd()) { - r.append(", "); - } - } - return r; -} - -inline void printOption(const QCommandLineOption &option) -{ - std::cout << " " - << std::setw(18) << std::left << optionText(option.names()) - << std::setw(32) << std::left << option.description().toStdString() - << std::setw(18) << std::left << option.defaultValues().join(", ").toStdString() - << std::endl; -} - -constexpr const char *socketPath() -{ -#if defined(Q_OS_UNIX) - // could be a path such as "/tmp/foo" - return "/tmp/smolbote.socket"; -#elif defined(Q_OS_WIN32) - // could be a pipe path such as "\\.\pipe\foo" - return "\\\\.\\pipe\\smolbote_socket"; -#endif -} - -CommandLine::CommandLine() - : QCommandLineParser() - , helpOption(addHelpOption()) - , versionOption(addVersionOption()) - , buildOption("build", "Displays build information.") - , configOption({ "c", "config" }, "Sets configuration file.", "path", Configuration::defaultUserConfigLocation()) - , profileOption({ "p", "profile" }, "Sets default profile.", "profile", "") - , socketOption("socket", "Sets local socket.", "name", socketPath()) - , newWindowOption("in-new-window", "Open URL in new window") -{ - setApplicationDescription("yet another no-frills browser"); - - addOption(buildOption); - addOption(configOption); - addOption(profileOption); - addOption(socketOption); - addOption(newWindowOption); - - addPositionalArgument("URL", "URL(s) to open"); -} - -void CommandLine::parseCommandLine(const QCoreApplication &app) -{ - QCommandLineParser::parse(app.arguments()); - - application = const_cast<QCoreApplication *>(&app); - - if(isSet(helpOption)) { - printHelp(); - } - - if(isSet(versionOption)) { - printVersion(); - } - - if(isSet(buildOption)) { - printBuild(); - } -} - -void CommandLine::printHelp(int exitCode) -{ - std::cout << "Usage: " << application->arguments().at(0).toStdString() << " [options] URL" << std::endl; - std::cout << application->applicationName().toStdString() << " " << SMOLBOTE_DESCRIBE << ": " - << applicationDescription().toStdString() << std::endl - << std::endl; - - std::cout << "Options: " << std::endl; - printOption(helpOption); - printOption(versionOption); - printOption(buildOption); - printOption(configOption); - printOption(profileOption); - printOption(socketOption); - printOption(newWindowOption); - std::cout << std::endl; - - std::cout << "You can also overwrite configuration options using the syntax: " << std::endl - << "--browser.setting.path=value" << std::endl - << "More information on available keys can be found on the manual page." << std::endl - << std::endl; - - std::cout << "Arguments: " << std::endl; - std::cout << "- " - << std::setw(20) << std::left << "URL" - << std::setw(40) << std::left << "URL(s) to open" - << std::endl - << std::endl; - - exit(exitCode); -} - -void CommandLine::printVersion(int exitCode) -{ - std::cout << application->applicationName().toStdString() << " " << SMOLBOTE_DESCRIBE << std::endl; - exit(exitCode); -} - -void CommandLine::printBuild(int exitCode) -{ - std::cout << SMOLBOTE_BRANCH << ":" << SMOLBOTE_COMMIT << std::endl; - exit(exitCode); -} diff --git a/src/commandline.h b/src/commandline.h deleted file mode 100644 index cb2f334..0000000 --- a/src/commandline.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of smolbote. It's copyrighted by the contributors recorded - * in the version control history of the file, available from its original - * location: https://neueland.iserlohn-fortress.net/smolbote.hg - * - * SPDX-License-Identifier: GPL-3.0 - */ - -#ifndef SMOLBOTE_COMMANDLINE_H -#define SMOLBOTE_COMMANDLINE_H - -#include <QCommandLineParser> - -class CommandLine : public QCommandLineParser -{ -public: - CommandLine(); - - void parseCommandLine(const QCoreApplication &app); - - void printHelp(int exitCode = 0); - void printVersion(int exitCode = 0); - void printBuild(int exitCode = 0); - - const QCommandLineOption helpOption; - const QCommandLineOption versionOption; - const QCommandLineOption buildOption; - - const QCommandLineOption configOption; - const QCommandLineOption profileOption; - const QCommandLineOption socketOption; - const QCommandLineOption newWindowOption; - -private: - QCoreApplication *application; -}; - -#endif // SMOLBOTE_COMMANDLINE_H diff --git a/src/main.cpp b/src/main.cpp index 52df7ac..bfe4ecd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,6 @@ */ #include "browser.h" -#include "commandline.h" #include "mainwindow/mainwindow.h" #include "version.h" #include "webengine/webprofile.h" @@ -18,36 +17,31 @@ int main(int argc, char **argv) { Browser app(argc, argv); - CommandLine parser; - parser.parseCommandLine(app); - // create and load configuration std::shared_ptr<Configuration> config = std::make_shared<Configuration>(); - config->read(parser.value(parser.configOption)); - - if(!parser.unknownOptionNames().isEmpty()) { - qDebug("config->parse: %s", config->parse(argc, argv) ? "true" : "false"); + if(!config->parseCommandLine(argc, argv)) { + qWarning("Check --help for usage."); + return -1; + } + if(!config->parseConfigFile(config->value<std::string>("config").value())) { + qWarning("Error parsing config file."); } app.setConfiguration(config); // set up socket - bool isSingleInstance = app.bindLocalSocket(parser.value(parser.socketOption)); + bool isSingleInstance = app.bindLocalSocket(QString::fromStdString(config->value<std::string>("socket").value())); #ifdef QT_DEBUG - qDebug("bindLocalSocket(%s) = %s", qUtf8Printable(parser.value(parser.socketOption)), isSingleInstance ? "true" : "false"); + qDebug("bindLocalSocket(%s) = %s", qUtf8Printable(QString::fromStdString(config->value<std::string>("socket").value())), isSingleInstance ? "true" : "false"); #endif // if we are the only instance, set up the browser if(isSingleInstance) { - if(parser.isSet(parser.profileOption)) - app.setup(parser.value(parser.profileOption)); - else - app.setup(QString::fromStdString(config->value<std::string>("profile.default").value())); - + app.setup(QString::fromStdString(config->value<std::string>("profile.default").value())); QObject::connect(&app, &Browser::messageAvailable, &app, &Browser::createSession); } - app.sendMessage(parser.value(parser.profileOption), parser.isSet(parser.newWindowOption), parser.positionalArguments()); + app.sendMessage("", false, config->positionalArguments()); if(isSingleInstance) return app.exec(); |