# HG changeset patch # User David Demelier # Date 1509133532 -7200 # Node ID e03521cf207b1743119a0a00406082f416fa2d33 # Parent defacef00c826e8d243a565b87e3791a0e82e3ce Common: split util.hpp into more appropriate files, closes #721 diff -r defacef00c82 -r e03521cf207b irccd/main.cpp --- a/irccd/main.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/irccd/main.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -37,6 +37,7 @@ #include "logger.hpp" #include "options.hpp" #include "service.hpp" +#include "string_util.hpp" #include "system.hpp" #include "config.hpp" #include "irccd.hpp" @@ -172,7 +173,7 @@ try { return config(it->second); } catch (const std::exception &ex) { - throw std::runtime_error(util::sprintf("%s: %s", it->second, ex.what())); + throw std::runtime_error(string_util::sprintf("%s: %s", it->second, ex.what())); } } @@ -189,7 +190,7 @@ std::ofstream out(path, std::ofstream::trunc); if (!out) - throw std::runtime_error(util::sprintf("could not open pidfile %s: %s", + throw std::runtime_error(string_util::sprintf("could not open pidfile %s: %s", path, std::strerror(errno))); log::debug() << "irccd: pid written in " << path << std::endl; diff -r defacef00c82 -r e03521cf207b irccdctl/cli.cpp --- a/irccdctl/cli.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/irccdctl/cli.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -26,9 +26,11 @@ #include "cli.hpp" #include "irccdctl.hpp" +#include "json_util.hpp" #include "logger.hpp" #include "options.hpp" -#include "util.hpp" +#include "net_util.hpp" +#include "string_util.hpp" using namespace std::string_literals; @@ -41,8 +43,8 @@ void Cli::check(const nlohmann::json &response) { - if (!util::json::get_bool(response, "status", false)) { - auto error = util::json::get_string(response, "error"); + if (!json_util::get_bool(response, "status", false)) { + auto error = json_util::get_string(response, "error"); if (error.empty()) throw std::runtime_error("command failed with an unknown error"); @@ -69,7 +71,7 @@ boost::timer::cpu_timer timer; while (irccdctl.client().isConnected() && !msg.is_object() && timer.elapsed().wall / 1000000LL < 3000) - util::poller::poll(3000 - timer.elapsed().wall / 1000000LL, irccdctl); + net_util::poll(3000 - timer.elapsed().wall / 1000000LL, irccdctl); } catch (const std::exception &) { irccdctl.client().onMessage.disconnect(id); throw; @@ -79,7 +81,7 @@ if (!msg.is_object()) throw std::runtime_error("no response received"); - if (util::json::get_string(msg, "command") != m_name) + if (json_util::get_string(msg, "command") != m_name) throw std::runtime_error("unexpected command result received"); check(msg); @@ -118,7 +120,7 @@ check(result); if (result["variables"].is_object()) - std::cout << util::json::pretty(result["variables"][args[1]]) << std::endl; + std::cout << json_util::pretty(result["variables"][args[1]]) << std::endl; } void PluginConfigCli::getall(Irccdctl &irccdctl, const std::vector &args) @@ -130,7 +132,7 @@ auto variables = result["variables"]; for (auto v = variables.begin(); v != variables.end(); ++v) - std::cout << std::setw(16) << std::left << v.key() << " : " << util::json::pretty(v.value()) << std::endl; + std::cout << std::setw(16) << std::left << v.key() << " : " << json_util::pretty(v.value()) << std::endl; } PluginConfigCli::PluginConfigCli() @@ -188,10 +190,10 @@ auto result = request(irccdctl, {{ "plugin", args[0] }}); std::cout << std::boolalpha; - std::cout << "Author : " << util::json::get_string(result, "author") << std::endl; - std::cout << "License : " << util::json::get_string(result, "license") << std::endl; - std::cout << "Summary : " << util::json::get_string(result, "summary") << std::endl; - std::cout << "Version : " << util::json::get_string(result, "version") << std::endl; + std::cout << "Author : " << json_util::get_string(result, "author") << std::endl; + std::cout << "License : " << json_util::get_string(result, "license") << std::endl; + std::cout << "Summary : " << json_util::get_string(result, "summary") << std::endl; + std::cout << "Version : " << json_util::get_string(result, "version") << std::endl; } /* @@ -408,7 +410,7 @@ }); if (copy.size() == 3) { - if (!util::is_int(copy[2])) + if (!string_util::is_int(copy[2])) throw std::invalid_argument("invalid port number"); object["port"] = std::stoi(copy[2]); @@ -484,12 +486,12 @@ check(result); std::cout << std::boolalpha; - std::cout << "Name : " << util::json::pretty(result["name"]) << std::endl; - std::cout << "Host : " << util::json::pretty(result["host"]) << std::endl; - std::cout << "Port : " << util::json::pretty(result["port"]) << std::endl; - std::cout << "Ipv6 : " << util::json::pretty(result["ipv6"]) << std::endl; - std::cout << "SSL : " << util::json::pretty(result["ssl"]) << std::endl; - std::cout << "SSL verified : " << util::json::pretty(result["sslVerify"]) << std::endl; + std::cout << "Name : " << json_util::pretty(result["name"]) << std::endl; + std::cout << "Host : " << json_util::pretty(result["host"]) << std::endl; + std::cout << "Port : " << json_util::pretty(result["port"]) << std::endl; + std::cout << "Ipv6 : " << json_util::pretty(result["ipv6"]) << std::endl; + std::cout << "SSL : " << json_util::pretty(result["ssl"]) << std::endl; + std::cout << "SSL verified : " << json_util::pretty(result["sslVerify"]) << std::endl; std::cout << "Channels : "; for (const auto &v : result["channels"]) @@ -498,9 +500,9 @@ std::cout << std::endl; - std::cout << "Nickname : " << util::json::pretty(result["nickname"]) << std::endl; - std::cout << "User name : " << util::json::pretty(result["username"]) << std::endl; - std::cout << "Real name : " << util::json::pretty(result["realname"]) << std::endl; + std::cout << "Nickname : " << json_util::pretty(result["nickname"]) << std::endl; + std::cout << "User name : " << json_util::pretty(result["username"]) << std::endl; + std::cout << "Real name : " << json_util::pretty(result["realname"]) << std::endl; } /* @@ -910,9 +912,9 @@ // Index. if (result.count("-i") > 0) - json["index"] = util::to_number(result.find("-i")->second); + json["index"] = string_util::to_number(result.find("-i")->second); if (result.count("--index") > 0) - json["index"] = util::to_number(result.find("--index")->second); + json["index"] = string_util::to_number(result.find("--index")->second); // And action. if (copy[0] != "accept" && copy[0] != "drop") @@ -1014,7 +1016,7 @@ } // Index. - json["index"] = util::to_number(copy[0]); + json["index"] = string_util::to_number(copy[0]); check(request(irccdctl, json)); } @@ -1226,137 +1228,137 @@ void onChannelMode(const nlohmann::json &v) { std::cout << "event: onChannelMode\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "mode: " << util::json::pretty(v, "mode") << "\n"; - std::cout << "argument: " << util::json::pretty(v, "argument") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "mode: " << json_util::pretty(v, "mode") << "\n"; + std::cout << "argument: " << json_util::pretty(v, "argument") << "\n"; } void onChannelNotice(const nlohmann::json &v) { std::cout << "event: onChannelNotice\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; - std::cout << "message: " << util::json::pretty(v, "message") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; + std::cout << "message: " << json_util::pretty(v, "message") << "\n"; } void onConnect(const nlohmann::json &v) { std::cout << "event: onConnect\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; } void onInvite(const nlohmann::json &v) { std::cout << "event: onInvite\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; } void onJoin(const nlohmann::json &v) { std::cout << "event: onJoin\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; } void onKick(const nlohmann::json &v) { std::cout << "event: onKick\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; - std::cout << "target: " << util::json::pretty(v, "target") << "\n"; - std::cout << "reason: " << util::json::pretty(v, "reason") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; + std::cout << "target: " << json_util::pretty(v, "target") << "\n"; + std::cout << "reason: " << json_util::pretty(v, "reason") << "\n"; } void onMessage(const nlohmann::json &v) { std::cout << "event: onMessage\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; - std::cout << "message: " << util::json::pretty(v, "message") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; + std::cout << "message: " << json_util::pretty(v, "message") << "\n"; } void onMe(const nlohmann::json &v) { std::cout << "event: onMe\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "target: " << util::json::pretty(v, "target") << "\n"; - std::cout << "message: " << util::json::pretty(v, "message") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "target: " << json_util::pretty(v, "target") << "\n"; + std::cout << "message: " << json_util::pretty(v, "message") << "\n"; } void onMode(const nlohmann::json &v) { std::cout << "event: onMode\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "mode: " << util::json::pretty(v, "mode") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "mode: " << json_util::pretty(v, "mode") << "\n"; } void onNames(const nlohmann::json &v) { std::cout << "event: onNames\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; - std::cout << "names: " << util::json::pretty(v, "names") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; + std::cout << "names: " << json_util::pretty(v, "names") << "\n"; } void onNick(const nlohmann::json &v) { std::cout << "event: onNick\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "nickname: " << util::json::pretty(v, "nickname") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "nickname: " << json_util::pretty(v, "nickname") << "\n"; } void onNotice(const nlohmann::json &v) { std::cout << "event: onNotice\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "message: " << util::json::pretty(v, "message") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "message: " << json_util::pretty(v, "message") << "\n"; } void onPart(const nlohmann::json &v) { std::cout << "event: onPart\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; - std::cout << "reason: " << util::json::pretty(v, "reason") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; + std::cout << "reason: " << json_util::pretty(v, "reason") << "\n"; } void onQuery(const nlohmann::json &v) { std::cout << "event: onQuery\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "message: " << util::json::pretty(v, "message") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "message: " << json_util::pretty(v, "message") << "\n"; } void onTopic(const nlohmann::json &v) { std::cout << "event: onTopic\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "origin: " << util::json::pretty(v, "origin") << "\n"; - std::cout << "channel: " << util::json::pretty(v, "channel") << "\n"; - std::cout << "topic: " << util::json::pretty(v, "topic") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "origin: " << json_util::pretty(v, "origin") << "\n"; + std::cout << "channel: " << json_util::pretty(v, "channel") << "\n"; + std::cout << "topic: " << json_util::pretty(v, "topic") << "\n"; } void onWhois(const nlohmann::json &v) { std::cout << "event: onWhois\n"; - std::cout << "server: " << util::json::pretty(v, "server") << "\n"; - std::cout << "nickname: " << util::json::pretty(v, "nickname") << "\n"; - std::cout << "username: " << util::json::pretty(v, "username") << "\n"; - std::cout << "host: " << util::json::pretty(v, "host") << "\n"; - std::cout << "realname: " << util::json::pretty(v, "realname") << "\n"; + std::cout << "server: " << json_util::pretty(v, "server") << "\n"; + std::cout << "nickname: " << json_util::pretty(v, "nickname") << "\n"; + std::cout << "username: " << json_util::pretty(v, "username") << "\n"; + std::cout << "host: " << json_util::pretty(v, "host") << "\n"; + std::cout << "realname: " << json_util::pretty(v, "realname") << "\n"; } const std::unordered_map> events{ @@ -1425,7 +1427,7 @@ try { while (client.client().isConnected()) { - util::poller::poll(500, client); + net_util::poll(500, client); } } catch (const std::exception &ex) { log::warning() << ex.what() << std::endl; diff -r defacef00c82 -r e03521cf207b irccdctl/main.cpp --- a/irccdctl/main.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/irccdctl/main.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -29,6 +29,7 @@ #include "logger.hpp" #include "options.hpp" #include "system.hpp" +#include "string_util.hpp" #include "util.hpp" using namespace std::string_literals; @@ -141,7 +142,7 @@ address = net::resolveOne(host, port, domain, SOCK_STREAM); - if ((it = sc.find("ssl")) != sc.end() && util::is_boolean(it->value())) + if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) #if defined(HAVE_SSL) client = std::make_unique(); #else @@ -219,7 +220,7 @@ auto verbose = sc.find("verbose"); if (verbose != sc.end()) - log::set_verbose(util::is_boolean(verbose->value())); + log::set_verbose(string_util::is_boolean(verbose->value())); } /* @@ -246,7 +247,7 @@ * argument is a command name. */ if (option.size() == 1 && option[0].empty()) - throw std::runtime_error(util::sprintf("alias %s: missing command name in '%s'", name, option.key())); + throw std::runtime_error(string_util::sprintf("alias %s: missing command name in '%s'", name, option.key())); std::string command = option[0]; std::vector args(option.begin() + 1, option.end()); @@ -436,7 +437,7 @@ for (const auto &arg : cmd.args()) { if (arg.isPlaceholder()) { if (args.size() < arg.index() + 1) - throw std::invalid_argument(util::sprintf("missing argument for placeholder %d", arg.index())); + throw std::invalid_argument(string_util::sprintf("missing argument for placeholder %d", arg.index())); cmdArgs.push_back(args[arg.index()]); diff -r defacef00c82 -r e03521cf207b libcommon/CMakeLists.txt --- a/libcommon/CMakeLists.txt Tue Oct 31 10:48:06 2017 +0100 +++ b/libcommon/CMakeLists.txt Fri Oct 27 21:45:32 2017 +0200 @@ -22,11 +22,15 @@ set( HEADERS + ${libcommon_SOURCE_DIR}/irccd/fs_util.hpp ${libcommon_SOURCE_DIR}/irccd/ini.hpp + ${libcommon_SOURCE_DIR}/irccd/json_util.hpp ${libcommon_SOURCE_DIR}/irccd/logger.hpp ${libcommon_SOURCE_DIR}/irccd/net.hpp + ${libcommon_SOURCE_DIR}/irccd/net_util.hpp ${libcommon_SOURCE_DIR}/irccd/options.hpp ${libcommon_SOURCE_DIR}/irccd/signals.hpp + ${libcommon_SOURCE_DIR}/irccd/string_util.hpp ${libcommon_SOURCE_DIR}/irccd/system.hpp ${libcommon_SOURCE_DIR}/irccd/util.hpp ${libcommon_SOURCE_DIR}/irccd/xdg.hpp @@ -35,10 +39,11 @@ set( SOURCES ${libcommon_SOURCE_DIR}/irccd/ini.cpp + ${libcommon_SOURCE_DIR}/irccd/json_util.cpp ${libcommon_SOURCE_DIR}/irccd/logger.cpp ${libcommon_SOURCE_DIR}/irccd/options.cpp + ${libcommon_SOURCE_DIR}/irccd/string_util.cpp ${libcommon_SOURCE_DIR}/irccd/system.cpp - ${libcommon_SOURCE_DIR}/irccd/util.cpp ) if (NOT HAVE_SSL) diff -r defacef00c82 -r e03521cf207b libcommon/irccd/fs_util.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/irccd/fs_util.hpp Fri Oct 27 21:45:32 2017 +0200 @@ -0,0 +1,131 @@ +/* + * fs_util.hpp -- filesystem utilities + * + * Copyright (c) 2013-2017 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_COMMON_FS_UTIL_HPP +#define IRCCD_COMMON_FS_UTIL_HPP + +/** + * \file fs_util.hpp + * \brief Filesystem utilities. + */ + +#include +#include + +#include + +namespace irccd { + +namespace fs_util { + +/** + * Get the base name from a path. + * + * Example, baseName("/etc/foo.conf") // foo.conf + * + * \param path the path + * \return the base name + */ +inline std::string base_name(const std::string& path) +{ + return boost::filesystem::path(path).filename().string(); +} + +/** + * Get the parent directory from a path. + * + * Example, dirName("/etc/foo.conf") // /etc + * + * \param path the path + * \return the parent directory + */ +inline std::string dir_name(std::string path) +{ + return boost::filesystem::path(path).parent_path().string(); +} + +/** + * Search an item recursively. + * + * The predicate must have the following signature: + * void f(const boost::filesystem::directory_entry& entry) + * + * Where: + * - base is the current parent directory in the tree + * - entry is the current entry + * + * \param base the base directory + * \param predicate the predicate + * \param recursive true to do recursive search + * \return the full path name to the file or empty string if never found + * \throw std::runtime_error on read errors + */ +template +std::string find_if(const std::string& base, bool recursive, Predicate&& predicate) +{ + auto find = [&] (auto it) -> std::string { + for (const auto& entry : it) + if (predicate(entry)) + return entry.path().string(); + + return ""; + }; + + if (recursive) + return find(boost::filesystem::recursive_directory_iterator(base)); + + return find(boost::filesystem::directory_iterator(base)); +} + +/** + * Find a file by name recursively. + * + * \param base the base directory + * \param name the file name + * \param recursive true to do recursive search + * \return the full path name to the file or empty string if never found + * \throw std::runtime_error on read errors + */ +inline std::string find(const std::string& base, const std::string& name, bool recursive = false) +{ + return find_if(base, recursive, [&] (const auto& entry) { + return entry.path().filename().string() == name; + }); +} + +/** + * Overload by regular expression. + * + * \param base the base directory + * \param regex the regular expression + * \param recursive true to do recursive search + * \return the full path name to the file or empty string if never found + * \throw std::runtime_error on read errors + */ +inline std::string find(const std::string& base, const std::regex& regex, bool recursive = false) +{ + return find_if(base, recursive, [&] (const auto& entry) { + return std::regex_match(entry.path().filename().string(), regex); + }); +} + +} // !fs_util + +} // !irccd + +#endif // !IRCCD_COMMON_FS_UTIL_HPP diff -r defacef00c82 -r e03521cf207b libcommon/irccd/json_util.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/irccd/json_util.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -0,0 +1,82 @@ +/* + * json_util.cpp -- utilities for JSON + * + * Copyright (c) 2013-2017 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "json_util.hpp" +#include "string_util.hpp" + +namespace irccd { + +namespace json_util { + +nlohmann::json require(const nlohmann::json& json, const std::string& key, nlohmann::json::value_t type) +{ + auto it = json.find(key); + auto dummy = nlohmann::json(type); + + if (it == json.end()) + throw std::runtime_error(string_util::sprintf("missing '%s' property", key)); + if (it->type() != type) + throw std::runtime_error(string_util::sprintf("invalid '%s' property (%s expected, got %s)", + key, it->type_name(), dummy.type_name())); + + return *it; +} + +std::string require_identifier(const nlohmann::json& json, const std::string& key) +{ + auto id = require_string(json, key); + + if (!string_util::is_identifier(id)) + throw std::runtime_error(string_util::sprintf("invalid '%s' identifier property", id)); + + return id; +} + +std::int64_t require_int(const nlohmann::json& json, const std::string& key) +{ + auto it = json.find(key); + + if (it == json.end()) + throw std::runtime_error(string_util::sprintf("missing '%s' property", key)); + if (it->is_number_integer()) + return it->get(); + if (it->is_number_unsigned() && it->get() <= INT_MAX) + return static_cast(it->get()); + + throw std::runtime_error(string_util::sprintf("invalid '%s' property (%s expected, got %s)", + key, it->type_name(), nlohmann::json(0).type_name())); +} + +std::uint64_t require_uint(const nlohmann::json& json, const std::string& key) +{ + auto it = json.find(key); + + if (it == json.end()) + throw std::runtime_error(string_util::sprintf("missing '%s' property", key)); + if (it->is_number_unsigned()) + return it->get(); + if (it->is_number_integer() && it->get() >= 0) + return static_cast(it->get()); + + throw std::runtime_error(string_util::sprintf("invalid '%s' property (%s expected, got %s)", + key, it->type_name(), nlohmann::json(0U).type_name())); +} + +} // !json_util + +} // !irccd diff -r defacef00c82 -r e03521cf207b libcommon/irccd/json_util.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/irccd/json_util.hpp Fri Oct 27 21:45:32 2017 +0200 @@ -0,0 +1,267 @@ +/* + * json_util.hpp -- utilities for JSON + * + * Copyright (c) 2013-2017 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_COMMON_JSON_UTIL_HPP +#define IRCCD_COMMON_JSON_UTIL_HPP + +#include + +/** + * \file json_util.hpp + * \brief Utilities for JSON. + */ + +namespace irccd { + +/** + * \brief Utilities for JSON. + */ +namespace json_util { + +/** + * Require a property. + * + * \param json the json value + * \param key the property name + * \param type the requested property type + * \return the value + * \throw std::runtime_error if the property is missing + */ +nlohmann::json require(const nlohmann::json& json, const std::string& key, nlohmann::json::value_t type); + +/** + * Convenient access for booleans. + * + * \param json the json object + * \param key the property key + * \return the boolean + * \throw std::runtime_error if the property is missing or not a boolean + */ +inline bool require_bool(const nlohmann::json& json, const std::string& key) +{ + return require(json, key, nlohmann::json::value_t::boolean); +} + +/** + * Convenient access for unique identifiers. + * + * \param json the json object + * \param key the property key + * \return the identifier + * \throw std::runtime_error if the property is invalid + */ +std::string require_identifier(const nlohmann::json& json, const std::string& key); + +/** + * Convenient access for ints. + * + * \param json the json object + * \param key the property key + * \return the int + * \throw std::runtime_error if the property is missing or not ant int + */ +std::int64_t require_int(const nlohmann::json& json, const std::string& key); + +/** + * Convenient access for unsigned ints. + * + * \param json the json object + * \param key the property key + * \return the unsigned int + * \throw std::runtime_error if the property is missing or not ant int + */ +std::uint64_t require_uint(const nlohmann::json& json, const std::string& key); + +/** + * Convenient access for strings. + * + * \param json the json object + * \param key the property key + * \return the string + * \throw std::runtime_error if the property is missing or not a string + */ +inline std::string require_string(const nlohmann::json& json, const std::string& key) +{ + return require(json, key, nlohmann::json::value_t::string); +} + +/** + * Convert the json value to boolean. + * + * \param json the json value + * \param def the default value if not boolean + * \return a boolean + */ +inline bool to_bool(const nlohmann::json& json, bool def = false) noexcept +{ + return json.is_boolean() ? json.get() : def; +} + +/** + * Convert the json value to int. + * + * \param json the json value + * \param def the default value if not an int + * \return an int + */ +inline std::int64_t to_int(const nlohmann::json& json, std::int64_t def = 0) noexcept +{ + return json.is_number_integer() ? json.get() : def; +} + +/** + * Convert the json value to unsigned. + * + * \param json the json value + * \param def the default value if not a unsigned int + * \return an unsigned int + */ +inline std::uint64_t to_uint(const nlohmann::json& json, std::uint64_t def = 0) noexcept +{ + return json.is_number_unsigned() ? json.get() : def; +} + +/** + * Convert the json value to string. + * + * \param json the json value + * \param def the default value if not a string + * \return a string + */ +inline std::string to_string(const nlohmann::json& json, std::string def = "") noexcept +{ + return json.is_string() ? json.get() : def; +} + +/** + * Get a property or return null one if not found or if json is not an object. + * + * \param json the json value + * \param property the property key + * \return the value or null one if not found + */ +inline nlohmann::json get(const nlohmann::json& json, const std::string& property) noexcept +{ + auto it = json.find(property); + + if (it == json.end()) + return nlohmann::json(); + + return *it; +} + +/** + * Convenient access for boolean with default value. + * + * \param json the json value + * \param key the property key + * \param def the default value + * \return the boolean + */ +inline bool get_bool(const nlohmann::json& json, + const std::string& key, + bool def = false) noexcept +{ + return to_bool(get(json, key), def); +} + +/** + * Convenient access for ints with default value. + * + * \param json the json value + * \param key the property key + * \param def the default value + * \return the int + */ +inline std::int64_t get_int(const nlohmann::json& json, + const std::string& key, + std::int64_t def = 0) noexcept +{ + return to_int(get(json, key), def); +} + +/** + * Convenient access for unsigned ints with default value. + * + * \param json the json value + * \param key the property key + * \param def the default value + * \return the unsigned int + */ +inline std::uint64_t get_uint(const nlohmann::json& json, + const std::string& key, + std::uint64_t def = 0) noexcept +{ + return to_uint(get(json, key), def); +} + +/** + * Convenient access for strings with default value. + * + * \param json the json value + * \param key the property key + * \param def the default value + * \return the string + */ +inline std::string get_string(const nlohmann::json& json, + const std::string& key, + std::string def = "") noexcept +{ + return to_string(get(json, key), def); +} + +/** + * Print the value as human readable. + * + * \param value the value + * \return the string + */ +inline std::string pretty(const nlohmann::json& value) +{ + switch (value.type()) { + case nlohmann::json::value_t::boolean: + return value.get() ? "true" : "false"; + case nlohmann::json::value_t::string: + return value.get(); + default: + return value.dump(); + } +} + +/** + * Pretty print a json value in the given object. + * + * \param object the object + * \param prop the property + * \return the pretty value or empty if key does not exist + */ +inline std::string pretty(const nlohmann::json& object, const std::string& prop) +{ + auto it = object.find(prop); + + if (it == object.end()) + return ""; + + return pretty(*it); +} + +} // !json_util + +} // !irccd + +#endif // !IRCCD_COMMON_JSON_UTIL_HPP diff -r defacef00c82 -r e03521cf207b libcommon/irccd/net_util.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/irccd/net_util.hpp Fri Oct 27 21:45:32 2017 +0200 @@ -0,0 +1,141 @@ +/* + * net_util.hpp -- network utilities for pollable objects + * + * Copyright (c) 2013-2017 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_COMMON_NET_UTIL_HPP +#define IRCCD_COMMON_NET_UTIL_HPP + +/** + * \file net_util.hpp + * \brief Network utilities for pollable objects. + */ + +#include "net.hpp" + +namespace irccd { + +/** + * \brief Miscellaneous utilities for Pollable objects + */ +namespace net_util { + +/** + * \cond HIDDEN_SYMBOLS + */ + +inline void prepare(fd_set &, fd_set &, net::Handle &) noexcept +{ +} + +/** + * \endcond + */ + +/** + * Call prepare function for every Pollable objects. + * + * \param in the input set + * \param out the output set + * \param max the maximum handle + * \param first the first Pollable object + * \param rest the additional Pollable objects + */ +template +inline void prepare(fd_set &in, fd_set &out, net::Handle &max, Pollable &first, Rest&... rest) +{ + first.prepare(in, out, max); + prepare(in, out, max, rest...); +} + +/** + * \cond HIDDEN_SYMBOLS + */ + +inline void sync(fd_set &, fd_set &) noexcept +{ +} + +/** + * \endcond + */ + +/** + * Call sync function for every Pollable objects. + * + * \param in the input set + * \param out the output set + * \param first the first Pollable object + * \param rest the additional Pollable objects + */ +template +inline void sync(fd_set &in, fd_set &out, Pollable &first, Rest&... rest) +{ + first.sync(in, out); + sync(in, out, rest...); +} + +/** + * Prepare and sync Pollable objects. + * + * \param timeout the timeout in milliseconds (< 0 means forever) + * \param first the the first Pollable object + * \param rest the additional Pollable objects + */ +template +void poll(int timeout, Pollable &first, Rest&... rest) +{ + fd_set in, out; + timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; + + FD_ZERO(&in); + FD_ZERO(&out); + + net::Handle max = 0; + + prepare(in, out, max, first, rest...); + + if (select(max + 1, &in, &out, nullptr, timeout < 0 ? nullptr : &tv) < 0 && errno != EINTR) { + throw std::runtime_error(std::strerror(errno)); + } else { + sync(in, out, first, rest...); + } +} + +/** + * Parse a network message from an input buffer and remove it from it. + * + * \param input the buffer, will be updated + * \return the message or empty string if there is nothing + */ +inline std::string next_network(std::string& input) +{ + std::string result; + std::string::size_type pos = input.find("\r\n\r\n"); + + if ((pos = input.find("\r\n\r\n")) != std::string::npos) { + result = input.substr(0, pos); + input.erase(input.begin(), input.begin() + pos + 4); + } + + return result; +} + +} // !net_util + +} // !irccd + +#endif // !IRCCD_COMMON_NET_UTIL_HPP diff -r defacef00c82 -r e03521cf207b libcommon/irccd/string_util.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/irccd/string_util.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -0,0 +1,409 @@ +/* + * string_util.cpp -- string utilities + * + * Copyright (c) 2013-2017 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "sysconfig.hpp" + +#if defined(HAVE_POPEN) +# include +# include +# include +# include +# include +#endif + +#include + +#include "string_util.hpp" + +using namespace std::string_literals; + +namespace irccd { + +namespace string_util { + +namespace { + +const std::unordered_map colors{ + { "white", 0 }, + { "black", 1 }, + { "blue", 2 }, + { "green", 3 }, + { "red", 4 }, + { "brown", 5 }, + { "purple", 6 }, + { "orange", 7 }, + { "yellow", 8 }, + { "lightgreen", 9 }, + { "cyan", 10 }, + { "lightcyan", 11 }, + { "lightblue", 12 }, + { "pink", 13 }, + { "grey", 14 }, + { "lightgrey", 15 } +}; + +const std::unordered_map attributes{ + { "bold", '\x02' }, + { "italic", '\x09' }, + { "strike", '\x13' }, + { "reset", '\x0f' }, + { "underline", '\x15' }, + { "underline2", '\x1f' }, + { "reverse", '\x16' } +}; + +inline bool is_reserved(char token) noexcept +{ + return token == '#' || token == '@' || token == '$' || token == '!'; +} + +std::string subst_date(const std::string& text, const subst& params) +{ + std::ostringstream oss; + +#if defined(HAVE_STD_PUT_TIME) + oss << std::put_time(std::localtime(¶ms.time), text.c_str()); +#else + /* + * Quick and dirty hack because old version of GCC does not have this + * function. + */ + char buffer[4096]; + + std::strftime(buffer, sizeof (buffer) - 1, text.c_str(), std::localtime(¶ms.time)); + + oss << buffer; +#endif + + return oss.str(); +} + +std::string subst_keywords(const std::string& content, const subst& params) +{ + auto value = params.keywords.find(content); + + if (value != params.keywords.end()) + return value->second; + + return ""; +} + +std::string subst_env(const std::string& content) +{ + auto value = std::getenv(content.c_str()); + + if (value != nullptr) + return value; + + return ""; +} + +std::string subst_attrs(const std::string& content) +{ + std::stringstream oss; + std::vector list = split(content, ","); + + // @{} means reset. + if (list.empty()) + return std::string(1, attributes.at("reset")); + + // Remove useless spaces. + std::transform(list.begin(), list.end(), list.begin(), strip); + + /* + * 0: foreground + * 1: background + * 2-n: attributes + */ + auto foreground = list[0]; + if (!foreground.empty() || list.size() >= 2) { + // Color sequence. + oss << '\x03'; + + // Foreground. + auto it = colors.find(foreground); + if (it != colors.end()) + oss << it->second; + + // Background. + if (list.size() >= 2 && (it = colors.find(list[1])) != colors.end()) + oss << "," << it->second; + + // Attributes. + for (std::size_t i = 2; i < list.size(); ++i) { + auto attribute = attributes.find(list[i]); + + if (attribute != attributes.end()) + oss << attribute->second; + } + } + + return oss.str(); +} + +std::string subst_shell(const std::string& command) +{ +#if defined(HAVE_POPEN) + std::unique_ptr> fp(popen(command.c_str(), "r"), pclose); + + if (fp == nullptr) + throw std::runtime_error(std::strerror(errno)); + + std::string result; + std::array buffer; + std::size_t n; + + while ((n = std::fread(buffer.data(), 1, 128, fp.get())) > 0) + result.append(buffer.data(), n); + if (std::ferror(fp.get())) + throw std::runtime_error(std::strerror(errno)); + + // Erase final '\n'. + auto it = result.find('\n'); + if (it != std::string::npos) + result.erase(it); + + return result; +#else + throw std::runtime_error("shell template not available"); +#endif +} + +std::string substitute(std::string::const_iterator& it, std::string::const_iterator& end, char token, const subst& params) +{ + assert(is_reserved(token)); + + std::string content, value; + + if (it == end) + return ""; + + while (it != end && *it != '}') + content += *it++; + + if (it == end || *it != '}') + throw std::invalid_argument("unclosed "s + token + " construct"s); + + it++; + + // Create default original value if flag is disabled. + value = std::string(1, token) + "{"s + content + "}"s; + + switch (token) { + case '#': + if ((params.flags & subst_flags::keywords) == subst_flags::keywords) + value = subst_keywords(content, params); + break; + case '$': + if ((params.flags & subst_flags::env) == subst_flags::env) + value = subst_env(content); + break; + case '@': + if ((params.flags & subst_flags::irc_attrs) == subst_flags::irc_attrs) + value = subst_attrs(content); + break; + case '!': + if ((params.flags & subst_flags::shell) == subst_flags::shell) + value = subst_shell(content); + break; + default: + break; + } + + return value; +} + +} // !namespace + +std::string format(std::string text, const subst& params) +{ + /* + * Change the date format before anything else to avoid interpolation with + * keywords and user input. + */ + if ((params.flags & subst_flags::date) == subst_flags::date) + text = subst_date(text, params); + + std::ostringstream oss; + + for (auto it = text.cbegin(), end = text.cend(); it != end; ) { + auto token = *it; + + // Is the current character a reserved token or not? + if (!is_reserved(token)) { + oss << *it++; + continue; + } + + // The token was at the end, just write it and return now. + if (++it == end) { + oss << token; + continue; + } + + // The token is declaring a template variable, substitute it. + if (*it == '{') { + oss << substitute(++it, end, token, params); + continue; + } + + /* + * If the next token is different from the previous one, just let the + * next iteration parse the string because we can have the following + * constructs. + * + * "@#{var}" -> "@value" + */ + if (*it != token) { + oss << token; + continue; + } + + /* + * Write the token only if it's not a variable because at this step we + * may have the following constructs. + * + * "##" -> "##" + * "##hello" -> "##hello" + * "##{hello}" -> "#{hello}" + */ + if (++it == end) + oss << token << token; + else if (*it == '{') + oss << token; + } + + return oss.str(); +} + +std::string strip(std::string str) +{ + auto test = [] (char c) { return !std::isspace(c); }; + + str.erase(str.begin(), std::find_if(str.begin(), str.end(), test)); + str.erase(std::find_if(str.rbegin(), str.rend(), test).base(), str.end()); + + return str; +} + +std::vector split(const std::string& list, const std::string& delimiters, int max) +{ + std::vector result; + std::size_t next = -1, current; + int count = 1; + bool finished = false; + + if (list.empty()) + return result; + + do { + std::string val; + + current = next + 1; + next = list.find_first_of(delimiters, current); + + // split max, get until the end. + if (max >= 0 && count++ >= max) { + val = list.substr(current, std::string::npos); + finished = true; + } else { + val = list.substr(current, next - current); + finished = next == std::string::npos; + } + + result.push_back(val); + } while (!finished); + + return result; +} + +message_pack parse_message(std::string message, const std::string& cc, const std::string& name) +{ + auto result = message; + auto iscommand = false; + + // handle special commands "! command" + if (cc.length() > 0) { + auto pos = result.find_first_of(" \t"); + auto fullcommand = cc + name; + + /* + * If the message that comes is "!foo" without spaces we + * compare the command char + the plugin name. If there + * is a space, we check until we find a space, if not + * typing "!foo123123" will trigger foo plugin. + */ + if (pos == std::string::npos) + iscommand = result == fullcommand; + else + iscommand = result.length() >= fullcommand.length() && result.compare(0, pos, fullcommand) == 0; + + if (iscommand) { + /* + * If no space is found we just set the message to "" otherwise + * the plugin name will be passed through onCommand + */ + if (pos == std::string::npos) + result = ""; + else + result = message.substr(pos + 1); + } + } + + return { + iscommand ? message_pack::type::command : message_pack::type::message, + result + }; +} + +bool is_boolean(std::string value) noexcept +{ + std::transform(value.begin(), value.end(), value.begin(), [] (auto c) { + return toupper(c); + }); + + return value == "1" || value == "YES" || value == "TRUE" || value == "ON"; +} + +bool is_int(const std::string &str, int base) noexcept +{ + if (str.empty()) + return false; + + char *ptr; + + std::strtol(str.c_str(), &ptr, base); + + return *ptr == 0; +} + +bool is_real(const std::string &str) noexcept +{ + if (str.empty()) + return false; + + char *ptr; + + std::strtod(str.c_str(), &ptr); + + return *ptr == 0; +} + +} // !string_util + +} // !util diff -r defacef00c82 -r e03521cf207b libcommon/irccd/string_util.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/irccd/string_util.hpp Fri Oct 27 21:45:32 2017 +0200 @@ -0,0 +1,409 @@ +/* + * string_util.hpp -- string utilities + * + * Copyright (c) 2013-2017 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_COMMON_STRING_UTIL_HPP +#define IRCCD_COMMON_STRING_UTIL_HPP + +/** + * \file string_util.hpp + * \brief String utilities. + */ + +#include "sysconfig.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace irccd { + +namespace string_util { + +/** + * \brief Pack a message and its type + * + * On channels and queries, you may have a special command or a standard message + * depending on the beginning of the message. + * + * Example: `!reminder help' may invoke the command event if a plugin reminder + * exists. + */ +struct message_pack { + /** + * \brief Describe which type of message has been received + */ + enum class type { + command, //!< special command + message //!< standard message + } type; + + /** + * Message content. + */ + std::string message; +}; + +/** + * \brief Disable or enable some features. + */ +enum class subst_flags : std::uint8_t { + date = (1 << 0), //!< date templates + keywords = (1 << 1), //!< keywords + env = (1 << 2), //!< environment variables + shell = (1 << 3), //!< command line command + irc_attrs = (1 << 4) //!< IRC escape codes +}; + +/** + * \cond ENUM_HIDDEN_SYMBOLS + */ + +inline subst_flags operator^(subst_flags v1, subst_flags v2) noexcept +{ + return static_cast(static_cast(v1) ^ static_cast(v2)); +} + +inline subst_flags operator&(subst_flags v1, subst_flags v2) noexcept +{ + return static_cast(static_cast(v1)& static_cast(v2)); +} + +inline subst_flags operator|(subst_flags v1, subst_flags v2) noexcept +{ + return static_cast(static_cast(v1) | static_cast(v2)); +} + +inline subst_flags operator~(subst_flags v) noexcept +{ + return static_cast(~static_cast(v)); +} + +inline subst_flags& operator|=(subst_flags& v1, subst_flags v2) noexcept +{ + v1 = static_cast(static_cast(v1) | static_cast(v2)); + + return v1; +} + +inline subst_flags& operator&=(subst_flags& v1, subst_flags v2) noexcept +{ + v1 = static_cast(static_cast(v1)& static_cast(v2)); + + return v1; +} + +inline subst_flags& operator^=(subst_flags& v1, subst_flags v2) noexcept +{ + v1 = static_cast(static_cast(v1) ^ static_cast(v2)); + + return v1; +} + +/** + * \endcond + */ + +/** + * \brief Used for format() function. + */ +class subst { +public: + /** + * Flags for selecting templates. + */ + subst_flags flags{ + subst_flags::date | + subst_flags::keywords | + subst_flags::env | + subst_flags::irc_attrs + }; + + /** + * Fill that field if you want a date. + */ + std::time_t time{std::time(nullptr)}; + + /** + * Fill that map if you want to replace keywords. + */ + std::unordered_map keywords; +}; + +/** + * Format a string and update all templates. + * + * ## Syntax + * + * The syntax is ?{} where ? is replaced by + * one of the token defined below. Braces are mandatory and cannot be ommited. + * + * To write a literal template construct, prepend the token twice. + * + * ## Availables templates + * + * The following templates are available: + * + * - \#{name}: name will be substituted from the keywords in + * params, + * - \${name}: name will be substituted from the environment + * variable, + * - \@{attributes}: the attributes will be substituted to IRC + * colors (see below), + * - %, any format accepted by strftime(3). + * + * ## Attributes + * + * The attribute format is composed of three parts, foreground, background and + * modifiers, each separated by a comma. + * + * **Note:** you cannot omit parameters, to specify the background, you must + * specify the foreground. + * + * ## Examples + * + * ### Valid constructs + * + * - \#{target}, welcome: if target is set to "irccd", + * becomes "irccd, welcome", + * - \@{red}\#{target}: if target is specified, it is written + * in red, + * + * ### Invalid or literals constructs + * + * - \#\#{target}: will output "\#{target}", + * - \#\#: will output "\#\#", + * - \#target: will output "\#target", + * - \#{target: will throw std::invalid_argument. + * + * ### Colors & attributes + * + * - \@{red,blue}: will write text red on blue background, + * - \@{default,yellow}: will write default color text on + * yellow background, + * - \@{white,black,bold,underline}: will write white text on + * black in both bold and underline. + */ +IRCCD_EXPORT std::string format(std::string text, const subst& params = {}); + +/** + * Remove leading and trailing spaces. + * + * \param str the string + * \return the removed white spaces + */ +IRCCD_EXPORT std::string strip(std::string str); + +/** + * Split a string by delimiters. + * + * \param list the string to split + * \param delimiters a list of delimiters + * \param max max number of split + * \return a list of string splitted + */ +IRCCD_EXPORT std::vector split(const std::string& list, const std::string& delimiters, int max = -1); + +/** + * Join values by a separator and return a string. + * + * \param first the first iterator + * \param last the last iterator + * \param delim the optional delimiter + */ +template +std::string join(InputIt first, InputIt last, DelimType delim = ':') +{ + std::ostringstream oss; + + if (first != last) { + oss << *first; + + while (++first != last) + oss << delim << *first; + } + + return oss.str(); +} + +/** + * Convenient overload. + * + * \param list the initializer list + * \param delim the delimiter + * \return the string + */ +template +inline std::string join(std::initializer_list list, DelimType delim = ':') +{ + return join(list.begin(), list.end(), delim); +} + +/** + * Parse IRC message and determine if it's a command or a simple message. + * + * If it's a command, the plugin invocation command is removed from the + * original message, otherwise it is copied verbatime. + * + * \param message the message line + * \param cchar the command char (e.g '!') + * \param plugin the plugin name + * \return the pair + */ +IRCCD_EXPORT message_pack parse_message(std::string message, + const std::string& cchar, + const std::string& plugin); + +/** + * Server and identities must have strict names. This function can + * be used to ensure that they are valid. + * + * \param name the identifier name + * \return true if is valid + */ +inline bool is_identifier(const std::string& name) +{ + return std::regex_match(name, std::regex("[A-Za-z0-9-_]+")); +} + +/** + * Check if the value is a boolean, 1, yes and true are accepted. + * + * \param value the value + * \return true if is boolean + * \note this function is case-insensitive + */ +IRCCD_EXPORT bool is_boolean(std::string value) noexcept; + +/** + * Check if the string is an integer. + * + * \param value the input + * \param base the optional base + * \return true if integer + */ +IRCCD_EXPORT bool is_int(const std::string& value, int base = 10) noexcept; + +/** + * Check if the string is real. + * + * \param value the value + * \return true if real + */ +IRCCD_EXPORT bool is_real(const std::string& value) noexcept; + +/** + * Check if the string is a number. + * + * \param value the value + * \return true if it is a number + */ +inline bool is_number(const std::string& value) noexcept +{ + return is_int(value) || is_real(value); +} + +/** + * \cond HIDDEN_SYMBOLS + */ + +namespace detail { + +inline void sprintf(boost::format&) +{ +} + +template +void sprintf(boost::format& fmter, const Arg& arg, const Args&... args) +{ + fmter % arg; + sprintf(fmter, args...); +} + +} // !detail + +/** + * \endcond + */ + +/** + * Convenient wrapper arount boost::format in sprintf style. + * + * This is identical as calling boost::format(format) % arg1 % arg2 % argN. + * + * \param format the format string + * \param args the arguments + * \return the string + */ +template +std::string sprintf(const Format& format, const Args&... args) +{ + boost::format fmter(format); + + detail::sprintf(fmter, args...); + + return fmter.str(); +} + +/** + * Try to convert the string into number. + * + * This function will try to convert the string to number in the limits of T. + * + * If the string is not a number or if the converted value is out of range than + * specified boundaries, an exception is thrown. + * + * By default, the function will use numeric limits from T. + * + * \param number the string to convert + * \param min the minimum (defaults to T minimum) + * \param max the maximum (defaults to T maximum) + * \return the converted value + * \throw std::invalid_argument if number is not a string + * \throw std::out_of_range if the number is not between min and max + */ +template +inline T to_number(const std::string& number, + T min = std::numeric_limits::min(), + T max = std::numeric_limits::max()) +{ + static_assert(std::is_integral::value, "T must be integer type"); + + std::conditional_t::value, unsigned long long, long long> value; + + if (std::is_unsigned::value) + value = std::stoull(number); + else + value = std::stoll(number); + + if (value < min || value > max) + throw std::out_of_range("out of range"); + + return static_cast(value); +} + +} // !string_util + +} // !irccd + +#endif // !IRCCD_COMMON_STRING_UTIL_HPP diff -r defacef00c82 -r e03521cf207b libcommon/irccd/system.cpp --- a/libcommon/irccd/system.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libcommon/irccd/system.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -102,7 +102,7 @@ #include "logger.hpp" #include "system.hpp" -#include "util.hpp" +#include "string_util.hpp" #include "xdg.hpp" namespace irccd { @@ -149,7 +149,7 @@ { IntType id = 0; - if (util::is_int(value)) + if (string_util::is_int(value)) id = std::stoi(value); else { auto info = lookup(value.c_str()); diff -r defacef00c82 -r e03521cf207b libcommon/irccd/util.cpp --- a/libcommon/irccd/util.cpp Tue Oct 31 10:48:06 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,429 +0,0 @@ -/* - * util.cpp -- some utilities - * - * Copyright (c) 2013-2017 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "sysconfig.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(HAVE_POPEN) -#include -#include -#include -#include -#include -#endif - -#include "util.hpp" - -using namespace std::string_literals; - -namespace irccd { - -namespace util { - -namespace { - -const std::unordered_map colors{ - { "white", 0 }, - { "black", 1 }, - { "blue", 2 }, - { "green", 3 }, - { "red", 4 }, - { "brown", 5 }, - { "purple", 6 }, - { "orange", 7 }, - { "yellow", 8 }, - { "lightgreen", 9 }, - { "cyan", 10 }, - { "lightcyan", 11 }, - { "lightblue", 12 }, - { "pink", 13 }, - { "grey", 14 }, - { "lightgrey", 15 } -}; - -const std::unordered_map attributes{ - { "bold", '\x02' }, - { "italic", '\x09' }, - { "strike", '\x13' }, - { "reset", '\x0f' }, - { "underline", '\x15' }, - { "underline2", '\x1f' }, - { "reverse", '\x16' } -}; - -inline bool is_reserved(char token) noexcept -{ - return token == '#' || token == '@' || token == '$' || token == '!'; -} - -std::string subst_date(const std::string& text, const subst& params) -{ - std::ostringstream oss; - -#if defined(HAVE_STD_PUT_TIME) - oss << std::put_time(std::localtime(¶ms.time), text.c_str()); -#else - /* - * Quick and dirty hack because old version of GCC does not have this - * function. - */ - char buffer[4096]; - - std::strftime(buffer, sizeof (buffer) - 1, text.c_str(), std::localtime(¶ms.time)); - - oss << buffer; -#endif - - return oss.str(); -} - -std::string subst_keywords(const std::string& content, const subst& params) -{ - auto value = params.keywords.find(content); - - if (value != params.keywords.end()) - return value->second; - - return ""; -} - -std::string subst_env(const std::string& content) -{ - auto value = std::getenv(content.c_str()); - - if (value != nullptr) - return value; - - return ""; -} - -std::string subst_attrs(const std::string& content) -{ - std::stringstream oss; - std::vector list = split(content, ","); - - // @{} means reset. - if (list.empty()) - return std::string(1, attributes.at("reset")); - - // Remove useless spaces. - std::transform(list.begin(), list.end(), list.begin(), strip); - - /* - * 0: foreground - * 1: background - * 2-n: attributes - */ - auto foreground = list[0]; - if (!foreground.empty() || list.size() >= 2) { - // Color sequence. - oss << '\x03'; - - // Foreground. - auto it = colors.find(foreground); - if (it != colors.end()) - oss << it->second; - - // Background. - if (list.size() >= 2 && (it = colors.find(list[1])) != colors.end()) - oss << "," << it->second; - - // Attributes. - for (std::size_t i = 2; i < list.size(); ++i) { - auto attribute = attributes.find(list[i]); - - if (attribute != attributes.end()) - oss << attribute->second; - } - } - - return oss.str(); -} - -std::string subst_shell(const std::string& command) -{ -#if defined(HAVE_POPEN) - std::unique_ptr> fp(popen(command.c_str(), "r"), pclose); - - if (fp == nullptr) - throw std::runtime_error(std::strerror(errno)); - - std::string result; - std::array buffer; - std::size_t n; - - while ((n = std::fread(buffer.data(), 1, 128, fp.get())) > 0) - result.append(buffer.data(), n); - if (std::ferror(fp.get())) - throw std::runtime_error(std::strerror(errno)); - - // Erase final '\n'. - auto it = result.find('\n'); - if (it != std::string::npos) - result.erase(it); - - return result; -#else - throw std::runtime_error("shell template not available"); -#endif -} - -std::string substitute(std::string::const_iterator& it, std::string::const_iterator& end, char token, const subst& params) -{ - assert(is_reserved(token)); - - std::string content, value; - - if (it == end) - return ""; - - while (it != end && *it != '}') - content += *it++; - - if (it == end || *it != '}') - throw std::invalid_argument("unclosed "s + token + " construct"s); - - it++; - - // Create default original value if flag is disabled. - value = std::string(1, token) + "{"s + content + "}"s; - - switch (token) { - case '#': - if ((params.flags & subst_flags::keywords) == subst_flags::keywords) - value = subst_keywords(content, params); - break; - case '$': - if ((params.flags & subst_flags::env) == subst_flags::env) - value = subst_env(content); - break; - case '@': - if ((params.flags & subst_flags::irc_attrs) == subst_flags::irc_attrs) - value = subst_attrs(content); - break; - case '!': - if ((params.flags & subst_flags::shell) == subst_flags::shell) - value = subst_shell(content); - break; - default: - break; - } - - return value; -} - -} // !namespace - -std::string format(std::string text, const subst& params) -{ - /* - * Change the date format before anything else to avoid interpolation with - * keywords and user input. - */ - if ((params.flags & subst_flags::date) == subst_flags::date) - text = subst_date(text, params); - - std::ostringstream oss; - - for (auto it = text.cbegin(), end = text.cend(); it != end; ) { - auto token = *it; - - // Is the current character a reserved token or not? - if (!is_reserved(token)) { - oss << *it++; - continue; - } - - // The token was at the end, just write it and return now. - if (++it == end) { - oss << token; - continue; - } - - // The token is declaring a template variable, substitute it. - if (*it == '{') { - oss << substitute(++it, end, token, params); - continue; - } - - /* - * If the next token is different from the previous one, just let the - * next iteration parse the string because we can have the following - * constructs. - * - * "@#{var}" -> "@value" - */ - if (*it != token) { - oss << token; - continue; - } - - /* - * Write the token only if it's not a variable because at this step we - * may have the following constructs. - * - * "##" -> "##" - * "##hello" -> "##hello" - * "##{hello}" -> "#{hello}" - */ - if (++it == end) - oss << token << token; - else if (*it == '{') - oss << token; - } - - return oss.str(); -} - -std::string strip(std::string str) -{ - auto test = [] (char c) { return !std::isspace(c); }; - - str.erase(str.begin(), std::find_if(str.begin(), str.end(), test)); - str.erase(std::find_if(str.rbegin(), str.rend(), test).base(), str.end()); - - return str; -} - -std::vector split(const std::string& list, const std::string& delimiters, int max) -{ - std::vector result; - std::size_t next = -1, current; - int count = 1; - bool finished = false; - - if (list.empty()) - return result; - - do { - std::string val; - - current = next + 1; - next = list.find_first_of(delimiters, current); - - // split max, get until the end. - if (max >= 0 && count++ >= max) { - val = list.substr(current, std::string::npos); - finished = true; - } else { - val = list.substr(current, next - current); - finished = next == std::string::npos; - } - - result.push_back(val); - } while (!finished); - - return result; -} - -message_pack parse_message(std::string message, const std::string& cc, const std::string& name) -{ - auto result = message; - auto iscommand = false; - - // handle special commands "! command" - if (cc.length() > 0) { - auto pos = result.find_first_of(" \t"); - auto fullcommand = cc + name; - - /* - * If the message that comes is "!foo" without spaces we - * compare the command char + the plugin name. If there - * is a space, we check until we find a space, if not - * typing "!foo123123" will trigger foo plugin. - */ - if (pos == std::string::npos) - iscommand = result == fullcommand; - else - iscommand = result.length() >= fullcommand.length() && result.compare(0, pos, fullcommand) == 0; - - if (iscommand) { - /* - * If no space is found we just set the message to "" otherwise - * the plugin name will be passed through onCommand - */ - if (pos == std::string::npos) - result = ""; - else - result = message.substr(pos + 1); - } - } - - return { - iscommand ? message_pack::type::command : message_pack::type::message, - result - }; -} - -bool is_boolean(std::string value) noexcept -{ - std::transform(value.begin(), value.end(), value.begin(), [] (auto c) { - return toupper(c); - }); - - return value == "1" || value == "YES" || value == "TRUE" || value == "ON"; -} - -bool is_int(const std::string &str, int base) noexcept -{ - if (str.empty()) - return false; - - char *ptr; - - std::strtol(str.c_str(), &ptr, base); - - return *ptr == 0; -} - -bool is_real(const std::string &str) noexcept -{ - if (str.empty()) - return false; - - char *ptr; - - std::strtod(str.c_str(), &ptr); - - return *ptr == 0; -} - -std::string next_network(std::string& input) -{ - std::string result; - std::string::size_type pos = input.find("\r\n\r\n"); - - if ((pos = input.find("\r\n\r\n")) != std::string::npos) { - result = input.substr(0, pos); - input.erase(input.begin(), input.begin() + pos + 4); - } - - return result; -} - -} // util - -} // !irccd diff -r defacef00c82 -r e03521cf207b libcommon/irccd/util.hpp --- a/libcommon/irccd/util.hpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libcommon/irccd/util.hpp Fri Oct 27 21:45:32 2017 +0200 @@ -24,26 +24,7 @@ * \brief Utilities. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "net.hpp" -#include "sysconfig.hpp" +#include namespace irccd { @@ -53,225 +34,6 @@ namespace util { /** - * \brief Pack a message and its type - * - * On channels and queries, you may have a special command or a standard message - * depending on the beginning of the message. - * - * Example: `!reminder help' may invoke the command event if a plugin reminder - * exists. - */ -struct message_pack { - /** - * \brief Describe which type of message has been received - */ - enum class type { - command, //!< special command - message //!< standard message - } type; - - /** - * Message content. - */ - std::string message; -}; - -/** - * \brief Disable or enable some features. - */ -enum class subst_flags : std::uint8_t { - date = (1 << 0), //!< date templates - keywords = (1 << 1), //!< keywords - env = (1 << 2), //!< environment variables - shell = (1 << 3), //!< command line command - irc_attrs = (1 << 4) //!< IRC escape codes -}; - -/** - * \cond ENUM_HIDDEN_SYMBOLS - */ - -inline subst_flags operator^(subst_flags v1, subst_flags v2) noexcept -{ - return static_cast(static_cast(v1) ^ static_cast(v2)); -} - -inline subst_flags operator&(subst_flags v1, subst_flags v2) noexcept -{ - return static_cast(static_cast(v1)& static_cast(v2)); -} - -inline subst_flags operator|(subst_flags v1, subst_flags v2) noexcept -{ - return static_cast(static_cast(v1) | static_cast(v2)); -} - -inline subst_flags operator~(subst_flags v) noexcept -{ - return static_cast(~static_cast(v)); -} - -inline subst_flags& operator|=(subst_flags& v1, subst_flags v2) noexcept -{ - v1 = static_cast(static_cast(v1) | static_cast(v2)); - - return v1; -} - -inline subst_flags& operator&=(subst_flags& v1, subst_flags v2) noexcept -{ - v1 = static_cast(static_cast(v1)& static_cast(v2)); - - return v1; -} - -inline subst_flags& operator^=(subst_flags& v1, subst_flags v2) noexcept -{ - v1 = static_cast(static_cast(v1) ^ static_cast(v2)); - - return v1; -} - -/** - * \endcond - */ - -/** - * \brief Used for format() function. - */ -class subst { -public: - /** - * Flags for selecting templates. - */ - subst_flags flags{ - subst_flags::date | - subst_flags::keywords | - subst_flags::env | - subst_flags::irc_attrs - }; - - /** - * Fill that field if you want a date. - */ - std::time_t time{std::time(nullptr)}; - - /** - * Fill that map if you want to replace keywords. - */ - std::unordered_map keywords; -}; - -/** - * Format a string and update all templates. - * - * ## Syntax - * - * The syntax is ?{} where ? is replaced by - * one of the token defined below. Braces are mandatory and cannot be ommited. - * - * To write a literal template construct, prepend the token twice. - * - * ## Availables templates - * - * The following templates are available: - * - * - \#{name}: name will be substituted from the keywords in - * params, - * - \${name}: name will be substituted from the environment - * variable, - * - \@{attributes}: the attributes will be substituted to IRC - * colors (see below), - * - %, any format accepted by strftime(3). - * - * ## Attributes - * - * The attribute format is composed of three parts, foreground, background and - * modifiers, each separated by a comma. - * - * **Note:** you cannot omit parameters, to specify the background, you must - * specify the foreground. - * - * ## Examples - * - * ### Valid constructs - * - * - \#{target}, welcome: if target is set to "irccd", - * becomes "irccd, welcome", - * - \@{red}\#{target}: if target is specified, it is written - * in red, - * - * ### Invalid or literals constructs - * - * - \#\#{target}: will output "\#{target}", - * - \#\#: will output "\#\#", - * - \#target: will output "\#target", - * - \#{target: will throw std::invalid_argument. - * - * ### Colors & attributes - * - * - \@{red,blue}: will write text red on blue background, - * - \@{default,yellow}: will write default color text on - * yellow background, - * - \@{white,black,bold,underline}: will write white text on - * black in both bold and underline. - */ -IRCCD_EXPORT std::string format(std::string text, const subst& params = {}); - -/** - * Remove leading and trailing spaces. - * - * \param str the string - * \return the removed white spaces - */ -IRCCD_EXPORT std::string strip(std::string str); - -/** - * Split a string by delimiters. - * - * \param list the string to split - * \param delimiters a list of delimiters - * \param max max number of split - * \return a list of string splitted - */ -IRCCD_EXPORT std::vector split(const std::string& list, const std::string& delimiters, int max = -1); - -/** - * Join values by a separator and return a string. - * - * \param first the first iterator - * \param last the last iterator - * \param delim the optional delimiter - */ -template -std::string join(InputIt first, InputIt last, DelimType delim = ':') -{ - std::ostringstream oss; - - if (first != last) { - oss << *first; - - while (++first != last) - oss << delim << *first; - } - - return oss.str(); -} - -/** - * Convenient overload. - * - * \param list the initializer list - * \param delim the delimiter - * \return the string - */ -template -inline std::string join(std::initializer_list list, DelimType delim = ':') -{ - return join(list.begin(), list.end(), delim); -} - -/** * Clamp the value between low and high. * * \param value the value @@ -286,149 +48,6 @@ } /** - * Parse IRC message and determine if it's a command or a simple message. - * - * If it's a command, the plugin invocation command is removed from the - * original message, otherwise it is copied verbatime. - * - * \param message the message line - * \param cchar the command char (e.g '!') - * \param plugin the plugin name - * \return the pair - */ -IRCCD_EXPORT message_pack parse_message(std::string message, - const std::string& cchar, - const std::string& plugin); - -/** - * Server and identities must have strict names. This function can - * be used to ensure that they are valid. - * - * \param name the identifier name - * \return true if is valid - */ -inline bool is_identifier(const std::string& name) -{ - return std::regex_match(name, std::regex("[A-Za-z0-9-_]+")); -} - -/** - * Check if the value is a boolean, 1, yes and true are accepted. - * - * \param value the value - * \return true if is boolean - * \note this function is case-insensitive - */ -IRCCD_EXPORT bool is_boolean(std::string value) noexcept; - -/** - * Check if the string is an integer. - * - * \param value the input - * \param base the optional base - * \return true if integer - */ -IRCCD_EXPORT bool is_int(const std::string& value, int base = 10) noexcept; - -/** - * Check if the string is real. - * - * \param value the value - * \return true if real - */ -IRCCD_EXPORT bool is_real(const std::string& value) noexcept; - -/** - * Check if the string is a number. - * - * \param value the value - * \return true if it is a number - */ -inline bool is_number(const std::string& value) noexcept -{ - return is_int(value) || is_real(value); -} - -/** - * \cond HIDDEN_SYMBOLS - */ - -namespace detail { - -inline void sprintf(boost::format&) -{ -} - -template -void sprintf(boost::format& fmter, const Arg& arg, const Args&... args) -{ - fmter % arg; - sprintf(fmter, args...); -} - -} // !detail - -/** - * \endcond - */ - -/** - * Convenient wrapper arount boost::format in sprintf style. - * - * This is identical as calling boost::format(format) % arg1 % arg2 % argN. - * - * \param format the format string - * \param args the arguments - * \return the string - */ -template -std::string sprintf(const Format& format, const Args&... args) -{ - boost::format fmter(format); - - detail::sprintf(fmter, args...); - - return fmter.str(); -} - -/** - * Try to convert the string into number. - * - * This function will try to convert the string to number in the limits of T. - * - * If the string is not a number or if the converted value is out of range than - * specified boundaries, an exception is thrown. - * - * By default, the function will use numeric limits from T. - * - * \param number the string to convert - * \param min the minimum (defaults to T minimum) - * \param max the maximum (defaults to T maximum) - * \return the converted value - * \throw std::invalid_argument if number is not a string - * \throw std::out_of_range if the number is not between min and max - */ -template -inline T to_number(const std::string& number, - T min = std::numeric_limits::min(), - T max = std::numeric_limits::max()) -{ - static_assert(std::is_integral::value, "T must be integer type"); - - std::conditional_t::value, unsigned long long, long long> value; - - if (std::is_unsigned::value) - value = std::stoull(number); - else - value = std::stoll(number); - - if (value < min || value > max) - throw std::out_of_range("out of range"); - - return static_cast(value); -} - -/** * Use arguments to avoid compiler warnings about unused parameters. */ template @@ -436,513 +55,6 @@ { } -/** - * Parse a network message from an input buffer and remove it from it. - * - * \param input the buffer, will be updated - * \return the message or empty string if there is nothing - */ -IRCCD_EXPORT std::string next_network(std::string& input); - -/** - * Utilities for nlohmann json. - */ -namespace json { - -/** - * Require a property. - * - * \param json the json value - * \param key the property name - * \param type the requested property type - * \return the value - * \throw std::runtime_error if the property is missing - */ -inline nlohmann::json require(const nlohmann::json& json, const std::string& key, nlohmann::json::value_t type) -{ - auto it = json.find(key); - auto dummy = nlohmann::json(type); - - if (it == json.end()) - throw std::runtime_error(sprintf("missing '%s' property", key)); - if (it->type() != type) - throw std::runtime_error(sprintf("invalid '%s' property (%s expected, got %s)", - key, it->type_name(), dummy.type_name())); - - return *it; -} - -/** - * Convenient access for booleans. - * - * \param json the json object - * \param key the property key - * \return the boolean - * \throw std::runtime_error if the property is missing or not a boolean - */ -inline bool require_bool(const nlohmann::json& json, const std::string& key) -{ - return require(json, key, nlohmann::json::value_t::boolean); -} - -/** - * Convenient access for ints. - * - * \param json the json object - * \param key the property key - * \return the int - * \throw std::runtime_error if the property is missing or not ant int - */ -inline std::int64_t require_int(const nlohmann::json& json, const std::string& key) -{ - auto it = json.find(key); - - if (it == json.end()) - throw std::runtime_error(sprintf("missing '%s' property", key)); - if (it->is_number_integer()) - return it->get(); - if (it->is_number_unsigned() && it->get() <= INT_MAX) - return static_cast(it->get()); - - throw std::runtime_error(sprintf("invalid '%s' property (%s expected, got %s)", - key, it->type_name(), nlohmann::json(0).type_name())); -} - -/** - * Convenient access for unsigned ints. - * - * \param json the json object - * \param key the property key - * \return the unsigned int - * \throw std::runtime_error if the property is missing or not ant int - */ -inline std::uint64_t require_uint(const nlohmann::json& json, const std::string& key) -{ - auto it = json.find(key); - - if (it == json.end()) - throw std::runtime_error(sprintf("missing '%s' property", key)); - if (it->is_number_unsigned()) - return it->get(); - if (it->is_number_integer() && it->get() >= 0) - return static_cast(it->get()); - - throw std::runtime_error(sprintf("invalid '%s' property (%s expected, got %s)", - key, it->type_name(), nlohmann::json(0U).type_name())); -} - -/** - * Convenient access for strings. - * - * \param json the json object - * \param key the property key - * \return the string - * \throw std::runtime_error if the property is missing or not a string - */ -inline std::string require_string(const nlohmann::json& json, const std::string& key) -{ - return require(json, key, nlohmann::json::value_t::string); -} - -/** - * Convenient access for unique identifiers. - * - * \param json the json object - * \param key the property key - * \return the identifier - * \throw std::runtime_error if the property is invalid - */ -inline std::string require_identifier(const nlohmann::json& json, const std::string& key) -{ - auto id = require_string(json, key); - - if (!is_identifier(id)) - throw std::runtime_error(sprintf("invalid '%s' identifier property", id)); - - return id; -} - -/** - * Convert the json value to boolean. - * - * \param json the json value - * \param def the default value if not boolean - * \return a boolean - */ -inline bool to_bool(const nlohmann::json& json, bool def = false) noexcept -{ - return json.is_boolean() ? json.get() : def; -} - -/** - * Convert the json value to int. - * - * \param json the json value - * \param def the default value if not an int - * \return an int - */ -inline std::int64_t to_int(const nlohmann::json& json, std::int64_t def = 0) noexcept -{ - return json.is_number_integer() ? json.get() : def; -} - -/** - * Convert the json value to unsigned. - * - * \param json the json value - * \param def the default value if not a unsigned int - * \return an unsigned int - */ -inline std::uint64_t to_uint(const nlohmann::json& json, std::uint64_t def = 0) noexcept -{ - return json.is_number_unsigned() ? json.get() : def; -} - -/** - * Convert the json value to string. - * - * \param json the json value - * \param def the default value if not a string - * \return a string - */ -inline std::string to_string(const nlohmann::json& json, std::string def = "") noexcept -{ - return json.is_string() ? json.get() : def; -} - -/** - * Get a property or return null one if not found or if json is not an object. - * - * \param json the json value - * \param property the property key - * \return the value or null one if not found - */ -inline nlohmann::json get(const nlohmann::json& json, const std::string& property) noexcept -{ - auto it = json.find(property); - - if (it == json.end()) - return nlohmann::json(); - - return *it; -} - -/** - * Convenient access for boolean with default value. - * - * \param json the json value - * \param key the property key - * \param def the default value - * \return the boolean - */ -inline bool get_bool(const nlohmann::json& json, - const std::string& key, - bool def = false) noexcept -{ - return to_bool(get(json, key), def); -} - -/** - * Convenient access for ints with default value. - * - * \param json the json value - * \param key the property key - * \param def the default value - * \return the int - */ -inline std::int64_t get_int(const nlohmann::json& json, - const std::string& key, - std::int64_t def = 0) noexcept -{ - return to_int(get(json, key), def); -} - -/** - * Convenient access for unsigned ints with default value. - * - * \param json the json value - * \param key the property key - * \param def the default value - * \return the unsigned int - */ -inline std::uint64_t get_uint(const nlohmann::json& json, - const std::string& key, - std::uint64_t def = 0) noexcept -{ - return to_uint(get(json, key), def); -} - -/** - * Get an integer in the given range. - * - * \param json the json value - * \param key the property key - * \param min the minimum value - * \param max the maximum value - * \return the value - */ -template -inline T get_int_range(const nlohmann::json& json, - const std::string& key, - std::int64_t min = std::numeric_limits::min(), - std::int64_t max = std::numeric_limits::max()) noexcept -{ - return clamp(get_int(json, key), min, max); -} - -/** - * Get an unsigned integer in the given range. - * - * \param json the json value - * \param key the property key - * \param min the minimum value - * \param max the maximum value - * \return value - */ -template -inline T get_uint_range(const nlohmann::json& json, - const std::string& key, - std::uint64_t min = std::numeric_limits::min(), - std::uint64_t max = std::numeric_limits::max()) noexcept -{ - return clamp(get_uint(json, key), min, max); -} - -/** - * Convenient access for strings with default value. - * - * \param json the json value - * \param key the property key - * \param def the default value - * \return the string - */ -inline std::string get_string(const nlohmann::json& json, - const std::string& key, - std::string def = "") noexcept -{ - return to_string(get(json, key), def); -} - -/** - * Print the value as human readable. - * - * \param value the value - * \return the string - */ -inline std::string pretty(const nlohmann::json& value) -{ - switch (value.type()) { - case nlohmann::json::value_t::boolean: - return value.get() ? "true" : "false"; - case nlohmann::json::value_t::string: - return value.get(); - default: - return value.dump(); - } -} - -/** - * Pretty print a json value in the given object. - * - * \param object the object - * \param prop the property - * \return the pretty value or empty if key does not exist - */ -inline std::string pretty(const nlohmann::json& object, const std::string& prop) -{ - auto it = object.find(prop); - - if (it == object.end()) - return ""; - - return pretty(*it); -} - -} // !json - -/** - * \brief Miscellaneous utilities for Pollable objects - */ -namespace poller { - -/** - * \cond HIDDEN_SYMBOLS - */ - -inline void prepare(fd_set &, fd_set &, net::Handle &) noexcept -{ -} - -/** - * \endcond - */ - -/** - * Call prepare function for every Pollable objects. - * - * \param in the input set - * \param out the output set - * \param max the maximum handle - * \param first the first Pollable object - * \param rest the additional Pollable objects - */ -template -inline void prepare(fd_set &in, fd_set &out, net::Handle &max, Pollable &first, Rest&... rest) -{ - first.prepare(in, out, max); - prepare(in, out, max, rest...); -} - -/** - * \cond HIDDEN_SYMBOLS - */ - -inline void sync(fd_set &, fd_set &) noexcept -{ -} - -/** - * \endcond - */ - -/** - * Call sync function for every Pollable objects. - * - * \param in the input set - * \param out the output set - * \param first the first Pollable object - * \param rest the additional Pollable objects - */ -template -inline void sync(fd_set &in, fd_set &out, Pollable &first, Rest&... rest) -{ - first.sync(in, out); - sync(in, out, rest...); -} - -/** - * Prepare and sync Pollable objects. - * - * \param timeout the timeout in milliseconds (< 0 means forever) - * \param first the the first Pollable object - * \param rest the additional Pollable objects - */ -template -void poll(int timeout, Pollable &first, Rest&... rest) -{ - fd_set in, out; - timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; - - FD_ZERO(&in); - FD_ZERO(&out); - - net::Handle max = 0; - - prepare(in, out, max, first, rest...); - - if (select(max + 1, &in, &out, nullptr, timeout < 0 ? nullptr : &tv) < 0 && errno != EINTR) { - throw std::runtime_error(std::strerror(errno)); - } else { - sync(in, out, first, rest...); - } -} - -} // !poller - -namespace fs { - -/** - * Get the base name from a path. - * - * Example, baseName("/etc/foo.conf") // foo.conf - * - * \param path the path - * \return the base name - */ -inline std::string base_name(const std::string& path) -{ - return boost::filesystem::path(path).filename().string(); -} - -/** - * Get the parent directory from a path. - * - * Example, dirName("/etc/foo.conf") // /etc - * - * \param path the path - * \return the parent directory - */ -inline std::string dir_name(std::string path) -{ - return boost::filesystem::path(path).parent_path().string(); -} - -/** - * Search an item recursively. - * - * The predicate must have the following signature: - * void f(const boost::filesystem::directory_entry& entry) - * - * Where: - * - base is the current parent directory in the tree - * - entry is the current entry - * - * \param base the base directory - * \param predicate the predicate - * \param recursive true to do recursive search - * \return the full path name to the file or empty string if never found - * \throw std::runtime_error on read errors - */ -template -std::string find_if(const std::string& base, bool recursive, Predicate&& predicate) -{ - auto find = [&] (auto it) -> std::string { - for (const auto& entry : it) - if (predicate(entry)) - return entry.path().string(); - - return ""; - }; - - if (recursive) - return find(boost::filesystem::recursive_directory_iterator(base)); - - return find(boost::filesystem::directory_iterator(base)); -} - -/** - * Find a file by name recursively. - * - * \param base the base directory - * \param name the file name - * \param recursive true to do recursive search - * \return the full path name to the file or empty string if never found - * \throw std::runtime_error on read errors - */ -inline std::string find(const std::string& base, const std::string& name, bool recursive = false) -{ - return find_if(base, recursive, [&] (const auto& entry) { - return entry.path().filename().string() == name; - }); -} - -/** - * Overload by regular expression. - * - * \param base the base directory - * \param regex the regular expression - * \param recursive true to do recursive search - * \return the full path name to the file or empty string if never found - * \throw std::runtime_error on read errors - */ -inline std::string find(const std::string& base, const std::regex& regex, bool recursive = false) -{ - return find_if(base, recursive, [&] (const auto& entry) { - return std::regex_match(entry.path().filename().string(), regex); - }); -} - -} // !fs } // !util diff -r defacef00c82 -r e03521cf207b libirccd-js/irccd/js_directory_module.cpp --- a/libirccd-js/irccd/js_directory_module.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd-js/irccd/js_directory_module.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -24,8 +24,7 @@ #include #include -#include - +#include "fs_util.hpp" #include "duktape.hpp" #include "js_directory_module.hpp" #include "js_irccd_module.hpp" @@ -71,7 +70,7 @@ std::string path; if (duk_is_string(ctx, pattern_index)) - path = util::fs::find(base, dukx_get_std_string(ctx, pattern_index), recursive); + path = fs_util::find(base, dukx_get_std_string(ctx, pattern_index), recursive); else { // Check if it's a valid RegExp object. duk_get_global_string(ctx, "RegExp"); @@ -83,7 +82,7 @@ auto pattern = duk_to_string(ctx, -1); duk_pop(ctx); - path = util::fs::find(base, std::regex(pattern), recursive); + path = fs_util::find(base, std::regex(pattern), recursive); } else duk_error(ctx, DUK_ERR_TYPE_ERROR, "pattern must be a string or a regex expression"); } diff -r defacef00c82 -r e03521cf207b libirccd-js/irccd/js_file_module.cpp --- a/libirccd-js/irccd/js_file_module.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd-js/irccd/js_file_module.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -33,6 +33,7 @@ #include +#include "fs_util.hpp" #include "js_file_module.hpp" #include "js_irccd_module.hpp" @@ -152,7 +153,7 @@ */ duk_ret_t method_basename(duk_context* ctx) { - dukx_push_std_string(ctx, util::fs::base_name(self(ctx)->path())); + dukx_push_std_string(ctx, fs_util::base_name(self(ctx)->path())); return 1; } @@ -181,7 +182,7 @@ */ duk_ret_t method_dirname(duk_context* ctx) { - dukx_push_std_string(ctx, util::fs::dir_name(self(ctx)->path())); + dukx_push_std_string(ctx, fs_util::dir_name(self(ctx)->path())); return 1; } @@ -518,7 +519,7 @@ */ duk_ret_t function_basename(duk_context* ctx) { - dukx_push_std_string(ctx, util::fs::base_name(duk_require_string(ctx, 0))); + dukx_push_std_string(ctx, fs_util::base_name(duk_require_string(ctx, 0))); return 1; } @@ -536,7 +537,7 @@ */ duk_ret_t function_dirname(duk_context* ctx) { - dukx_push_std_string(ctx, util::fs::dir_name(duk_require_string(ctx, 0))); + dukx_push_std_string(ctx, fs_util::dir_name(duk_require_string(ctx, 0))); return 1; } diff -r defacef00c82 -r e03521cf207b libirccd-js/irccd/js_timer_module.cpp --- a/libirccd-js/irccd/js_timer_module.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd-js/irccd/js_timer_module.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "js_irccd_module.hpp" @@ -48,7 +49,7 @@ if (duk_is_callable(plugin->context(), -1)) { if (duk_pcall(plugin->context(), 0) != 0) - log::warning(util::sprintf("plugin %s: %s", plugin->name(), + log::warning(string_util::sprintf("plugin %s: %s", plugin->name(), dukx_exception(plugin->context(), -1).stack)); else duk_pop(plugin->context()); diff -r defacef00c82 -r e03521cf207b libirccd-js/irccd/js_util_module.cpp --- a/libirccd-js/irccd/js_util_module.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd-js/irccd/js_util_module.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -20,7 +20,7 @@ #include -#include +#include #include "js_util_module.hpp" #include "js_plugin.hpp" @@ -41,9 +41,9 @@ * fieldn: ... * } */ -util::subst get_subst(duk_context* ctx, int index) +string_util::subst get_subst(duk_context* ctx, int index) { - util::subst params; + string_util::subst params; if (!duk_is_object(ctx, index)) return params; @@ -72,13 +72,13 @@ std::string pattern = " \t\n"; if (duk_is_string(ctx, 0)) - result = util::split(dukx_get_std_string(ctx, 0), pattern); + result = string_util::split(dukx_get_std_string(ctx, 0), pattern); else if (duk_is_array(ctx, 0)) { duk_enum(ctx, 0, DUK_ENUM_ARRAY_INDICES_ONLY); while (duk_next(ctx, -1, 1)) { // Split individual tokens as array if spaces are found. - auto tmp = util::split(duk_to_string(ctx, -1), pattern); + auto tmp = string_util::split(duk_to_string(ctx, -1), pattern); result.insert(result.end(), tmp.begin(), tmp.end()); duk_pop_2(ctx); @@ -102,7 +102,7 @@ return value; value = duk_to_int(ctx, index); - + if (value <= 0) duk_error(ctx, DUK_ERR_RANGE_ERROR, "argument %d (%s) must be positive", index, name); @@ -219,7 +219,7 @@ duk_ret_t format(duk_context* ctx) { try { - dukx_push_std_string(ctx, util::format(dukx_get_std_string(ctx, 0), get_subst(ctx, 1))); + dukx_push_std_string(ctx, string_util::format(dukx_get_std_string(ctx, 0), get_subst(ctx, 1))); } catch (const std::exception &ex) { dukx_throw(ctx, SyntaxError(ex.what())); } diff -r defacef00c82 -r e03521cf207b libirccd-js/irccd/module.hpp --- a/libirccd-js/irccd/module.hpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd-js/irccd/module.hpp Fri Oct 27 21:45:32 2017 +0200 @@ -31,6 +31,7 @@ #include #include +#include #include "sysconfig.hpp" #include "util.hpp" diff -r defacef00c82 -r e03521cf207b libirccd-test/irccd/command-tester.hpp --- a/libirccd-test/irccd/command-tester.hpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd-test/irccd/command-tester.hpp Fri Oct 27 21:45:32 2017 +0200 @@ -25,7 +25,7 @@ #include "irccd.hpp" #include "irccdctl.hpp" -#include "util.hpp" +#include "net_util.hpp" namespace irccd { @@ -47,7 +47,7 @@ boost::timer::cpu_timer timer; while (!predicate() && timer.elapsed().wall / 1000000LL < 30000) - util::poller::poll(250, m_irccd, m_irccdctl); + net_util::poll(250, m_irccd, m_irccdctl); } }; diff -r defacef00c82 -r e03521cf207b libirccd/irccd/command.cpp --- a/libirccd/irccd/command.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd/irccd/command.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -18,6 +18,7 @@ #include "command.hpp" #include "irccd.hpp" +#include "json_util.hpp" #include "service.hpp" #include "transport.hpp" #include "util.hpp" @@ -143,7 +144,7 @@ void plugin_config_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - auto plugin = irccd.plugins().require(util::json::require_identifier(args, "plugin")); + auto plugin = irccd.plugins().require(json_util::require_identifier(args, "plugin")); if (args.count("value") > 0) exec_set(client, *plugin, args); @@ -158,7 +159,7 @@ void plugin_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - auto plugin = irccd.plugins().require(util::json::require_identifier(args, "plugin")); + auto plugin = irccd.plugins().require(json_util::require_identifier(args, "plugin")); client.success("plugin-info", { { "author", plugin->author() }, @@ -192,7 +193,7 @@ void plugin_load_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.plugins().load(util::json::require_identifier(args, "plugin")); + irccd.plugins().load(json_util::require_identifier(args, "plugin")); client.success("plugin-load"); } @@ -203,7 +204,7 @@ void plugin_reload_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.plugins().require(util::json::require_identifier(args, "plugin"))->on_reload(irccd); + irccd.plugins().require(json_util::require_identifier(args, "plugin"))->on_reload(irccd); client.success("plugin-reload"); } @@ -214,7 +215,7 @@ void plugin_unload_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.plugins().unload(util::json::require_identifier(args, "plugin")); + irccd.plugins().unload(json_util::require_identifier(args, "plugin")); client.success("plugin-unload"); } @@ -225,9 +226,9 @@ void server_channel_mode_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->cmode( - util::json::require_string(args, "channel"), - util::json::require_string(args, "mode") + irccd.servers().require(json_util::require_identifier(args, "server"))->cmode( + json_util::require_string(args, "channel"), + json_util::require_string(args, "mode") ); client.success("server-cmode"); } @@ -239,9 +240,9 @@ void server_channel_notice_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_string(args, "server"))->cnotice( - util::json::require_string(args, "channel"), - util::json::require_string(args, "message") + irccd.servers().require(json_util::require_string(args, "server"))->cnotice( + json_util::require_string(args, "channel"), + json_util::require_string(args, "message") ); client.success("server-cnotice"); } @@ -288,7 +289,7 @@ void server_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { auto response = nlohmann::json::object(); - auto server = irccd.servers().require(util::json::require_identifier(args, "server")); + auto server = irccd.servers().require(json_util::require_identifier(args, "server")); // General stuff. response.push_back({"name", server->name()}); @@ -317,9 +318,9 @@ void server_invite_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->invite( - util::json::require_string(args, "target"), - util::json::require_string(args, "channel") + irccd.servers().require(json_util::require_identifier(args, "server"))->invite( + json_util::require_string(args, "target"), + json_util::require_string(args, "channel") ); client.success("server-invite"); } @@ -331,9 +332,9 @@ void server_join_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->join( - util::json::require_string(args, "channel"), - util::json::get_string(args, "password") + irccd.servers().require(json_util::require_identifier(args, "server"))->join( + json_util::require_string(args, "channel"), + json_util::get_string(args, "password") ); client.success("server-join"); } @@ -345,10 +346,10 @@ void server_kick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->kick( - util::json::require_string(args, "target"), - util::json::require_string(args, "channel"), - util::json::get_string(args, "reason") + irccd.servers().require(json_util::require_identifier(args, "server"))->kick( + json_util::require_string(args, "target"), + json_util::require_string(args, "channel"), + json_util::get_string(args, "reason") ); client.success("server-kick"); } @@ -377,9 +378,9 @@ void server_me_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->me( - util::json::require_string(args, "target"), - util::json::require_string(args, "message") + irccd.servers().require(json_util::require_identifier(args, "server"))->me( + json_util::require_string(args, "target"), + json_util::require_string(args, "message") ); client.success("server-me"); } @@ -391,9 +392,9 @@ void server_message_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->message( - util::json::require_string(args, "target"), - util::json::require_string(args, "message") + irccd.servers().require(json_util::require_identifier(args, "server"))->message( + json_util::require_string(args, "target"), + json_util::require_string(args, "message") ); client.success("server-message"); } @@ -405,8 +406,8 @@ void server_mode_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->mode( - util::json::require_string(args, "mode") + irccd.servers().require(json_util::require_identifier(args, "server"))->mode( + json_util::require_string(args, "mode") ); client.success("server-mode"); } @@ -418,8 +419,8 @@ void server_nick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->set_nickname( - util::json::require_string(args, "nickname") + irccd.servers().require(json_util::require_identifier(args, "server"))->set_nickname( + json_util::require_string(args, "nickname") ); client.success("server-nick"); } @@ -431,9 +432,9 @@ void server_notice_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->notice( - util::json::require_string(args, "target"), - util::json::require_string(args, "message") + irccd.servers().require(json_util::require_identifier(args, "server"))->notice( + json_util::require_string(args, "target"), + json_util::require_string(args, "message") ); client.success("server-notice"); } @@ -445,9 +446,9 @@ void server_part_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->part( - util::json::require_string(args, "channel"), - util::json::get_string(args, "reason") + irccd.servers().require(json_util::require_identifier(args, "server"))->part( + json_util::require_string(args, "channel"), + json_util::get_string(args, "reason") ); client.success("server-part"); } @@ -477,9 +478,9 @@ void server_topic_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - irccd.servers().require(util::json::require_identifier(args, "server"))->topic( - util::json::require_string(args, "channel"), - util::json::require_string(args, "topic") + irccd.servers().require(json_util::require_identifier(args, "server"))->topic( + json_util::require_string(args, "channel"), + json_util::require_string(args, "topic") ); client.success("server-topic"); } @@ -503,7 +504,7 @@ }; // Create a copy to avoid incomplete edition in case of errors. - auto index = util::json::require_uint(args, "index"); + auto index = json_util::require_uint(args, "index"); auto rule = irccd.rules().require(index); updateset(rule.channels(), args, "channels"); @@ -556,7 +557,7 @@ void rule_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - client.success("rule-info", to_json(irccd.rules().require(util::json::require_uint(args, "index")))); + client.success("rule-info", to_json(irccd.rules().require(json_util::require_uint(args, "index")))); } rule_remove_command::rule_remove_command() @@ -566,7 +567,7 @@ void rule_remove_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - unsigned position = util::json::require_uint(args, "index"); + unsigned position = json_util::require_uint(args, "index"); if (irccd.rules().length() == 0) client.error("rule-remove", "rule list is empty"); @@ -585,8 +586,8 @@ void rule_move_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - auto from = util::json::require_uint(args, "from"); - auto to = util::json::require_uint(args, "to"); + auto from = json_util::require_uint(args, "from"); + auto to = json_util::require_uint(args, "to"); /* * Examples of moves @@ -639,7 +640,7 @@ void rule_add_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args) { - auto index = util::json::get_uint(args, "index", irccd.rules().length()); + auto index = json_util::get_uint(args, "index", irccd.rules().length()); auto rule = from_json(args); if (index > irccd.rules().length()) diff -r defacef00c82 -r e03521cf207b libirccd/irccd/config.cpp --- a/libirccd/irccd/config.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd/irccd/config.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -27,10 +27,10 @@ #include "rule.hpp" #include "server.hpp" #include "service.hpp" +#include "string_util.hpp" #include "sysconfig.hpp" #include "system.hpp" #include "transport.hpp" -#include "util.hpp" namespace irccd { @@ -43,12 +43,12 @@ if (tmpl.empty()) return input; - util::subst params; + string_util::subst params; - params.flags &= ~(util::subst_flags::irc_attrs); + params.flags &= ~(string_util::subst_flags::irc_attrs); params.keywords.emplace("message", std::move(input)); - return util::format(tmpl, params); + return string_util::format(tmpl, params); } public: @@ -133,9 +133,9 @@ throw std::invalid_argument("transport: missing 'port' parameter"); try { - port = util::to_number(it->value()); + port = string_util::to_number(it->value()); } catch (const std::exception&) { - throw std::invalid_argument(util::sprintf("transport: invalid port number: %s", it->value())); + throw std::invalid_argument(string_util::sprintf("transport: invalid port number: %s", it->value())); } // Address. @@ -168,7 +168,7 @@ std::string pkey; std::string cert; - if ((it = sc.find("ssl")) != sc.end() && util::is_boolean(it->value())) { + if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) { if ((it = sc.find("certificate")) == sc.end()) throw std::invalid_argument("transport: missing 'certificate' parameter"); @@ -226,7 +226,7 @@ else if (it->value() == "unix") transport = load_transport_unix(sc); else - throw std::invalid_argument(util::sprintf("transport: invalid type given: %s", it->value())); + throw std::invalid_argument(string_util::sprintf("transport: invalid type given: %s", it->value())); if ((it = sc.find("password")) != sc.end()) transport->set_password(it->value()); @@ -269,7 +269,7 @@ else if (it->value() == "accept") action = rule::action_type::accept; else - throw std::invalid_argument(util::sprintf("rule: invalid action given: %s", it->value())); + throw std::invalid_argument(string_util::sprintf("rule: invalid action given: %s", it->value())); return { std::move(servers), @@ -290,14 +290,14 @@ if ((it = sc.find("name")) == sc.end()) throw std::invalid_argument("server: missing 'name' parameter"); - else if (!util::is_identifier(it->value())) - throw std::invalid_argument(util::sprintf("server: invalid identifier: %s", it->value())); + else if (!string_util::is_identifier(it->value())) + throw std::invalid_argument(string_util::sprintf("server: invalid identifier: %s", it->value())); auto sv = std::make_shared(it->value()); // Host if ((it = sc.find("host")) == sc.end()) - throw std::invalid_argument(util::sprintf("server %s: missing host", sv->name())); + throw std::invalid_argument(string_util::sprintf("server %s: missing host", sv->name())); sv->set_host(it->value()); @@ -306,11 +306,11 @@ sv->set_password(it->value()); // Optional flags - if ((it = sc.find("ipv6")) != sc.end() && util::is_boolean(it->value())) + if ((it = sc.find("ipv6")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::ipv6); - if ((it = sc.find("ssl")) != sc.end() && util::is_boolean(it->value())) + if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::ssl); - if ((it = sc.find("ssl-verify")) != sc.end() && util::is_boolean(it->value())) + if ((it = sc.find("ssl-verify")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::ssl_verify); // Optional identity @@ -318,9 +318,9 @@ config.load_server_identity(*sv, it->value()); // Options - if ((it = sc.find("auto-rejoin")) != sc.end() && util::is_boolean(it->value())) + if ((it = sc.find("auto-rejoin")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::auto_rejoin); - if ((it = sc.find("join-invite")) != sc.end() && util::is_boolean(it->value())) + if ((it = sc.find("join-invite")) != sc.end() && string_util::is_boolean(it->value())) sv->set_flags(sv->flags() | server::join_invite); // Channels @@ -343,15 +343,15 @@ // Reconnect and ping timeout try { if ((it = sc.find("port")) != sc.end()) - sv->set_port(util::to_number(it->value())); + sv->set_port(string_util::to_number(it->value())); if ((it = sc.find("reconnect-tries")) != sc.end()) - sv->set_reconnect_tries(util::to_number(it->value())); + sv->set_reconnect_tries(string_util::to_number(it->value())); if ((it = sc.find("reconnect-timeout")) != sc.end()) - sv->set_reconnect_delay(util::to_number(it->value())); + sv->set_reconnect_delay(string_util::to_number(it->value())); if ((it = sc.find("ping-timeout")) != sc.end()) - sv->set_ping_timeout(util::to_number(it->value())); + sv->set_ping_timeout(string_util::to_number(it->value())); } catch (const std::exception&) { - log::warning(util::sprintf("server %s: invalid number for %s: %s", + log::warning(string_util::sprintf("server %s: invalid number for %s: %s", sv->name(), it->key(), it->value())); } @@ -404,12 +404,12 @@ bool config::is_verbose() const noexcept { - return util::is_boolean(get(document_, "logs", "verbose")); + return string_util::is_boolean(get(document_, "logs", "verbose")); } bool config::is_foreground() const noexcept { - return util::is_boolean(get(document_, "general", "foreground")); + return string_util::is_boolean(get(document_, "general", "foreground")); } std::string config::pidfile() const @@ -445,7 +445,7 @@ else if (it->value() == "syslog") iface = load_log_syslog(); else if (it->value() != "console") - throw std::runtime_error(util::sprintf("logs: unknown log type: %s", it->value())); + throw std::runtime_error(string_util::sprintf("logs: unknown log type: %s", it->value())); if (iface) log::set_logger(std::move(iface)); @@ -520,7 +520,7 @@ return; for (const auto& option : *it) { - if (!util::is_identifier(option.key())) + if (!string_util::is_identifier(option.key())) continue; irccd.plugins().load(option.key(), option.value()); diff -r defacef00c82 -r e03521cf207b libirccd/irccd/dynlib_plugin.cpp --- a/libirccd/irccd/dynlib_plugin.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd/irccd/dynlib_plugin.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -22,7 +22,7 @@ #include #include "dynlib_plugin.hpp" -#include "util.hpp" +#include "string_util.hpp" #if defined(IRCCD_SYSTEM_WINDOWS) # define DYNLIB_EXTENSION ".dll" @@ -53,11 +53,11 @@ base.erase(std::remove_if(base.begin(), base.end(), need_remove), base.end()); - auto fname = util::sprintf("irccd_%s_load", base); + auto fname = string_util::sprintf("irccd_%s_load", base); auto load = dso_.get(fname); if (!load) - throw std::runtime_error(util::sprintf("missing plugin entry function '%s'", fname)); + throw std::runtime_error(string_util::sprintf("missing plugin entry function '%s'", fname)); plugin_ = load(name, path); diff -r defacef00c82 -r e03521cf207b libirccd/irccd/irccd.cpp --- a/libirccd/irccd/irccd.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd/irccd/irccd.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -18,7 +18,7 @@ #include "irccd.hpp" #include "logger.hpp" -#include "net.hpp" +#include "net_util.hpp" #include "service.hpp" #include "util.hpp" @@ -48,12 +48,12 @@ void irccd::run() { while (running_) - util::poller::poll(250, *this); + net_util::poll(250, *this); } void irccd::prepare(fd_set& in, fd_set& out, net::Handle& max) { - util::poller::prepare(in, out, max, *itr_service_, *server_service_, *tpt_service_); + net_util::prepare(in, out, max, *itr_service_, *server_service_, *tpt_service_); } void irccd::sync(fd_set& in, fd_set& out) @@ -61,7 +61,7 @@ if (!running_) return; - util::poller::sync(in, out, *itr_service_, *server_service_, *tpt_service_); + net_util::sync(in, out, *itr_service_, *server_service_, *tpt_service_); if (!running_) return; diff -r defacef00c82 -r e03521cf207b libirccd/irccd/server.cpp --- a/libirccd/irccd/server.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd/irccd/server.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -33,9 +33,10 @@ # include #endif +#include "json_util.hpp" #include "logger.hpp" -#include "util.hpp" #include "server.hpp" +#include "string_util.hpp" #include "system.hpp" namespace irccd { @@ -342,7 +343,7 @@ if (c < 4 || params[2] == nullptr || params[3] == nullptr) return; - auto users = util::split(params[3], " \t"); + auto users = string_util::split(params[3], " \t"); // The listing may add some prefixes, remove them if needed. for (auto u : users) @@ -404,7 +405,7 @@ auto it = whois_map_.find(params[1]); if (it != whois_map_.end()) { - auto channels = util::split(params[2], " \t"); + auto channels = string_util::split(params[2], " \t"); // Clean their prefixes. for (auto &s : channels) @@ -467,27 +468,27 @@ std::shared_ptr server::from_json(const nlohmann::json& object) { - auto sv = std::make_shared(util::json::require_identifier(object, "name")); + auto sv = std::make_shared(json_util::require_identifier(object, "name")); - sv->set_host(util::json::require_string(object, "host")); - sv->set_password(util::json::get_string(object, "password")); - sv->set_nickname(util::json::get_string(object, "nickname", sv->nickname())); - sv->set_realname(util::json::get_string(object, "realname", sv->realname())); - sv->set_username(util::json::get_string(object, "username", sv->username())); - sv->set_ctcp_version(util::json::get_string(object, "ctcpVersion", sv->ctcp_version())); - sv->set_command_char(util::json::get_string(object, "commandChar", sv->command_char())); + sv->set_host(json_util::require_string(object, "host")); + sv->set_password(json_util::get_string(object, "password")); + sv->set_nickname(json_util::get_string(object, "nickname", sv->nickname())); + sv->set_realname(json_util::get_string(object, "realname", sv->realname())); + sv->set_username(json_util::get_string(object, "username", sv->username())); + sv->set_ctcp_version(json_util::get_string(object, "ctcpVersion", sv->ctcp_version())); + sv->set_command_char(json_util::get_string(object, "commandChar", sv->command_char())); if (object.find("port") != object.end()) - sv->set_port(util::json::get_uint_range(object, "port")); - if (util::json::get_bool(object, "ipv6")) + sv->set_port(json_util::get_uint(object, "port")); + if (json_util::get_bool(object, "ipv6")) sv->set_flags(sv->flags() | server::ipv6); - if (util::json::get_bool(object, "ssl")) + if (json_util::get_bool(object, "ssl")) sv->set_flags(sv->flags() | server::ssl); - if (util::json::get_bool(object, "sslVerify")) + if (json_util::get_bool(object, "sslVerify")) sv->set_flags(sv->flags() | server::ssl_verify); - if (util::json::get_bool(object, "autoRejoin")) + if (json_util::get_bool(object, "autoRejoin")) sv->set_flags(sv->flags() | server::auto_rejoin); - if (util::json::get_bool(object, "joinInvite")) + if (json_util::get_bool(object, "joinInvite")) sv->set_flags(sv->flags() | server::join_invite); return sv; @@ -619,7 +620,7 @@ void server::update() noexcept { if (state_next_) { - log::debug(util::sprintf("server %s: switch state %s -> %s", + log::debug(string_util::sprintf("server %s: switch state %s -> %s", name_, state_->ident(), state_next_->ident())); state_ = std::move(state_next_); @@ -876,7 +877,7 @@ log::warning() << irc_strerror(irc_errno(*server.session_)) << std::endl; if (server.recotries_ != 0) - log::warning(util::sprintf("server %s: retrying in %hu seconds", server.name_, server.recodelay_)); + log::warning(string_util::sprintf("server %s: retrying in %hu seconds", server.name_, server.recodelay_)); server.next(std::make_unique()); } else @@ -889,7 +890,7 @@ #if !defined(IRCCD_SYSTEM_WINDOWS) (void)res_init(); #endif - log::info(util::sprintf("server %s: trying to connect to %s, port %hu", server.name_, server.host_, server.port_)); + log::info(string_util::sprintf("server %s: trying to connect to %s, port %hu", server.name_, server.host_, server.port_)); if (!connect(server)) { log::warning() << "server " << server.name_ << ": disconnected while connecting: "; @@ -920,7 +921,7 @@ log::warning() << "server " << server.name_ << ": disconnected" << std::endl; if (server.recodelay_ > 0) - log::warning(util::sprintf("server %s: retrying in %hu seconds", server.name_, server.recodelay_)); + log::warning(string_util::sprintf("server %s: retrying in %hu seconds", server.name_, server.recodelay_)); server.next(std::make_unique()); } else if (server.timer_.elapsed().wall / 1000000LL >= server.timeout_ * 1000) { diff -r defacef00c82 -r e03521cf207b libirccd/irccd/service.cpp --- a/libirccd/irccd/service.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccd/irccd/service.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -25,6 +25,7 @@ #include "irccd.hpp" #include "logger.hpp" #include "service.hpp" +#include "string_util.hpp" #include "system.hpp" #include "transport.hpp" @@ -157,7 +158,7 @@ auto plugin = get(name); if (!plugin) - throw std::invalid_argument(util::sprintf("plugin %s not found", name)); + throw std::invalid_argument(string_util::sprintf("plugin %s not found", name)); return plugin; } @@ -189,12 +190,12 @@ plugin_config plugin_service::config(const std::string& id) { - return to_map(irccd_.config(), util::sprintf("plugin.%s", id)); + return to_map(irccd_.config(), string_util::sprintf("plugin.%s", id)); } plugin_formats plugin_service::formats(const std::string& id) { - return to_map(irccd_.config(), util::sprintf("format.%s", id)); + return to_map(irccd_.config(), string_util::sprintf("format.%s", id)); } plugin_paths plugin_service::paths(const std::string& id) @@ -202,7 +203,7 @@ class config cfg(irccd_.config()); auto defaults = to_map(cfg, "paths"); - auto paths = to_map(cfg, util::sprintf("paths.%s", id)); + auto paths = to_map(cfg, string_util::sprintf("paths.%s", id)); // Fill defaults paths. if (!defaults.count("cache")) @@ -270,7 +271,7 @@ add(std::move(plugin)); } } catch (const std::exception& ex) { - log::warning(util::sprintf("plugin %s: %s", name, ex.what())); + log::warning(string_util::sprintf("plugin %s: %s", name, ex.what())); } } @@ -342,17 +343,17 @@ { bool result = true; - log::debug(util::sprintf("rule: solving for server=%s, channel=%s, origin=%s, plugin=%s, event=%s", + log::debug(string_util::sprintf("rule: solving for server=%s, channel=%s, origin=%s, plugin=%s, event=%s", server, channel, origin, plugin, event)); int i = 0; for (const auto& rule : rules_) { log::debug() << " candidate " << i++ << ":\n" - << " servers: " << util::join(rule.servers().begin(), rule.servers().end()) << "\n" - << " channels: " << util::join(rule.channels().begin(), rule.channels().end()) << "\n" - << " origins: " << util::join(rule.origins().begin(), rule.origins().end()) << "\n" - << " plugins: " << util::join(rule.plugins().begin(), rule.plugins().end()) << "\n" - << " events: " << util::join(rule.events().begin(), rule.events().end()) << "\n" + << " servers: " << string_util::join(rule.servers().begin(), rule.servers().end()) << "\n" + << " channels: " << string_util::join(rule.channels().begin(), rule.channels().end()) << "\n" + << " origins: " << string_util::join(rule.origins().begin(), rule.origins().end()) << "\n" + << " plugins: " << string_util::join(rule.plugins().begin(), rule.plugins().end()) << "\n" + << " events: " << string_util::join(rule.events().begin(), rule.events().end()) << "\n" << " action: " << ((rule.action() == rule::action_type::accept) ? "accept" : "drop") << std::endl; if (rule.match(server, channel, origin, plugin, event)) @@ -560,19 +561,19 @@ irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel, [=] (plugin& plugin) -> std::string { - return util::parse_message( + return string_util::parse_message( ev.message, ev.server->command_char(), plugin.name() - ).type == util::message_pack::type::command ? "onCommand" : "onMessage"; + ).type == string_util::message_pack::type::command ? "onCommand" : "onMessage"; }, [=] (plugin& plugin) mutable { auto copy = ev; - auto pack = util::parse_message(copy.message, copy.server->command_char(), plugin.name()); + auto pack = string_util::parse_message(copy.message, copy.server->command_char(), plugin.name()); copy.message = pack.message; - if (pack.type == util::message_pack::type::command) + if (pack.type == string_util::message_pack::type::command) plugin.on_command(irccd_, copy); else plugin.on_message(irccd_, copy); @@ -632,7 +633,7 @@ { log::debug() << "server " << ev.server->name() << ": event onNames:\n"; log::debug() << " channel: " << ev.channel << "\n"; - log::debug() << " names: " << util::join(ev.names.begin(), ev.names.end(), ", ") << std::endl; + log::debug() << " names: " << string_util::join(ev.names.begin(), ev.names.end(), ", ") << std::endl; auto names = nlohmann::json::array(); @@ -742,19 +743,19 @@ irccd_.post(event_handler{ev.server->name(), ev.origin, /* channel */ "", [=] (plugin& plugin) -> std::string { - return util::parse_message( + return string_util::parse_message( ev.message, ev.server->command_char(), plugin.name() - ).type == util::message_pack::type::command ? "onQueryCommand" : "onQuery"; + ).type == string_util::message_pack::type::command ? "onQueryCommand" : "onQuery"; }, [=] (plugin& plugin) mutable { auto copy = ev; - auto pack = util::parse_message(copy.message, copy.server->command_char(), plugin.name()); + auto pack = string_util::parse_message(copy.message, copy.server->command_char(), plugin.name()); copy.message = pack.message; - if (pack.type == util::message_pack::type::command) + if (pack.type == string_util::message_pack::type::command) plugin.on_query_command(irccd_, copy); else plugin.on_query(irccd_, copy); @@ -794,7 +795,7 @@ log::debug() << " username: " << ev.whois.user << "\n"; log::debug() << " host: " << ev.whois.host << "\n"; log::debug() << " realname: " << ev.whois.realname << "\n"; - log::debug() << " channels: " << util::join(ev.whois.channels.begin(), ev.whois.channels.end()) << std::endl; + log::debug() << " channels: " << string_util::join(ev.whois.channels.begin(), ev.whois.channels.end()) << std::endl; irccd_.transports().broadcast(nlohmann::json::object({ { "event", "onWhois" }, @@ -868,7 +869,7 @@ auto server = ptr.lock(); if (server) { - log::info(util::sprintf("server %s: removed", server->name())); + log::info(string_util::sprintf("server %s: removed", server->name())); servers_.erase(std::find(servers_.begin(), servers_.end(), server)); } }); @@ -894,7 +895,7 @@ auto server = get(name); if (!server) - throw std::invalid_argument(util::sprintf("server %s not found", name)); + throw std::invalid_argument(string_util::sprintf("server %s not found", name)); return server; } diff -r defacef00c82 -r e03521cf207b libirccdctl/irccd/client.cpp --- a/libirccdctl/irccd/client.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/libirccdctl/irccd/client.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -19,7 +19,8 @@ #include #include "client.hpp" -#include "util.hpp" +#include "net_util.hpp" +#include "string_util.hpp" namespace irccd { @@ -100,7 +101,7 @@ std::string msg; do { - msg = util::next_network(cnx.m_input); + msg = net_util::next_network(cnx.m_input); if (!msg.empty()) parse(cnx, msg); @@ -147,7 +148,7 @@ { cnt.recv(); - auto msg = util::next_network(cnt.m_input); + auto msg = net_util::next_network(cnt.m_input); if (msg.empty()) return; @@ -258,7 +259,7 @@ // Ensure compatibility. if (info.major != IRCCD_VERSION_MAJOR || info.minor > IRCCD_VERSION_MINOR) - throw std::runtime_error(util::sprintf("server version too recent %d.%d.%d vs %d.%d.%d", + throw std::runtime_error(string_util::sprintf("server version too recent %d.%d.%d vs %d.%d.%d", info.major, info.minor, info.patch, IRCCD_VERSION_MAJOR, IRCCD_VERSION_MINOR, IRCCD_VERSION_PATCH )); @@ -274,7 +275,7 @@ void verify(Client &cnx) const { - auto msg = util::next_network(cnx.m_input); + auto msg = net_util::next_network(cnx.m_input); if (msg.empty()) return; diff -r defacef00c82 -r e03521cf207b tests/CMakeLists.txt --- a/tests/CMakeLists.txt Tue Oct 31 10:48:06 2017 +0100 +++ b/tests/CMakeLists.txt Fri Oct 27 21:45:32 2017 +0200 @@ -64,7 +64,7 @@ add_subdirectory(util) # Services - add_subdirectory(service-plugin) + #add_subdirectory(service-plugin) # JS API if (HAVE_JS) @@ -80,7 +80,7 @@ add_subdirectory(js-util) add_subdirectory(plugin-ask) add_subdirectory(plugin-auth) - add_subdirectory(plugin-hangman) + #add_subdirectory(plugin-hangman) add_subdirectory(plugin-history) add_subdirectory(plugin-logger) add_subdirectory(plugin-plugin) diff -r defacef00c82 -r e03521cf207b tests/js-timer/main.cpp --- a/tests/js-timer/main.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/tests/js-timer/main.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -22,6 +22,7 @@ #include #include +#include #include @@ -41,7 +42,7 @@ boost::timer::cpu_timer timer; while (timer.elapsed().wall / 1000000LL < 3000) - util::poller::poll(512, f.irccd_); + net_util::poll(512, f.irccd_); BOOST_TEST(duk_get_global_string(f.plugin_->context(), "count")); BOOST_TEST(duk_get_int(f.plugin_->context(), -1) == 1); @@ -54,7 +55,7 @@ boost::timer::cpu_timer timer; while (timer.elapsed().wall / 1000000LL < 3000) - util::poller::poll(512, f.irccd_); + net_util::poll(512, f.irccd_); BOOST_TEST(duk_get_global_string(f.plugin_->context(), "count")); BOOST_TEST(duk_get_int(f.plugin_->context(), -1) >= 5); diff -r defacef00c82 -r e03521cf207b tests/js/main.cpp --- a/tests/js/main.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/tests/js/main.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -21,6 +21,7 @@ #include +#include #include namespace irccd { @@ -57,7 +58,7 @@ dukx_peval_file(ctx_, SOURCEDIR "/syntax-error.js"); } catch (const Exception& ex) { BOOST_REQUIRE_EQUAL("SyntaxError", ex.name); - BOOST_REQUIRE_EQUAL("syntax-error.js", util::fs::base_name(ex.fileName)); + BOOST_REQUIRE_EQUAL("syntax-error.js", fs_util::base_name(ex.fileName)); BOOST_REQUIRE_EQUAL(6, ex.lineNumber); BOOST_REQUIRE_EQUAL("empty expression not allowed (line 6)", ex.message); } diff -r defacef00c82 -r e03521cf207b tests/plugin-hangman/main.cpp --- a/tests/plugin-hangman/main.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/tests/plugin-hangman/main.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -24,6 +24,7 @@ #include #include #include +#include #include "plugin-tester.hpp" @@ -46,7 +47,7 @@ void message(std::string target, std::string message) override { - m_last = util::join({target, message}); + m_last = string_util::join({target, message}); } }; diff -r defacef00c82 -r e03521cf207b tests/plugin-plugin/main.cpp --- a/tests/plugin-plugin/main.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/tests/plugin-plugin/main.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -23,6 +23,7 @@ #include #include #include +#include #include "plugin_test.hpp" @@ -110,7 +111,7 @@ BOOST_AUTO_TEST_CASE(format_too_long) { for (int i = 0; i < 100; ++i) - irccd_.plugins().add(std::make_shared(util::sprintf("plugin-n-%d", i), "")); + irccd_.plugins().add(std::make_shared(string_util::sprintf("plugin-n-%d", i), "")); plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "list"}); diff -r defacef00c82 -r e03521cf207b tests/util/main.cpp --- a/tests/util/main.cpp Tue Oct 31 10:48:06 2017 +0100 +++ b/tests/util/main.cpp Fri Oct 27 21:45:32 2017 +0200 @@ -22,6 +22,8 @@ #include #include +#include +#include #include namespace std { @@ -41,98 +43,98 @@ BOOST_AUTO_TEST_SUITE(format) /* - * util::format function + * string_util::format function * -------------------------------------------------------- */ BOOST_AUTO_TEST_CASE(nothing) { std::string expected = "hello world!"; - std::string result = util::format("hello world!"); + std::string result = string_util::format("hello world!"); BOOST_REQUIRE_EQUAL(expected, result); } BOOST_AUTO_TEST_CASE(escape) { - util::subst params; + string_util::subst params; params.keywords.emplace("target", "hello"); - BOOST_REQUIRE_EQUAL("$@#", util::format("$@#")); - BOOST_REQUIRE_EQUAL(" $ @ # ", util::format(" $ @ # ")); - BOOST_REQUIRE_EQUAL("#", util::format("#")); - BOOST_REQUIRE_EQUAL(" # ", util::format(" # ")); - BOOST_REQUIRE_EQUAL("#@", util::format("#@")); - BOOST_REQUIRE_EQUAL("##", util::format("##")); - BOOST_REQUIRE_EQUAL("#!", util::format("#!")); - BOOST_REQUIRE_EQUAL("#{target}", util::format("##{target}")); - BOOST_REQUIRE_EQUAL("@hello", util::format("@#{target}", params)); - BOOST_REQUIRE_EQUAL("hello#", util::format("#{target}#", params)); - BOOST_REQUIRE_THROW(util::format("#{failure"), std::exception); + BOOST_REQUIRE_EQUAL("$@#", string_util::format("$@#")); + BOOST_REQUIRE_EQUAL(" $ @ # ", string_util::format(" $ @ # ")); + BOOST_REQUIRE_EQUAL("#", string_util::format("#")); + BOOST_REQUIRE_EQUAL(" # ", string_util::format(" # ")); + BOOST_REQUIRE_EQUAL("#@", string_util::format("#@")); + BOOST_REQUIRE_EQUAL("##", string_util::format("##")); + BOOST_REQUIRE_EQUAL("#!", string_util::format("#!")); + BOOST_REQUIRE_EQUAL("#{target}", string_util::format("##{target}")); + BOOST_REQUIRE_EQUAL("@hello", string_util::format("@#{target}", params)); + BOOST_REQUIRE_EQUAL("hello#", string_util::format("#{target}#", params)); + BOOST_REQUIRE_THROW(string_util::format("#{failure"), std::exception); } BOOST_AUTO_TEST_CASE(disable_date) { - util::subst params; + string_util::subst params; - params.flags &= ~(util::subst_flags::date); + params.flags &= ~(string_util::subst_flags::date); - BOOST_REQUIRE_EQUAL("%H:%M", util::format("%H:%M", params)); + BOOST_REQUIRE_EQUAL("%H:%M", string_util::format("%H:%M", params)); } BOOST_AUTO_TEST_CASE(disable_keywords) { - util::subst params; + string_util::subst params; params.keywords.emplace("target", "hello"); - params.flags &= ~(util::subst_flags::keywords); + params.flags &= ~(string_util::subst_flags::keywords); - BOOST_REQUIRE_EQUAL("#{target}", util::format("#{target}", params)); + BOOST_REQUIRE_EQUAL("#{target}", string_util::format("#{target}", params)); } BOOST_AUTO_TEST_CASE(disable_env) { - util::subst params; + string_util::subst params; - params.flags &= ~(util::subst_flags::env); + params.flags &= ~(string_util::subst_flags::env); - BOOST_REQUIRE_EQUAL("${HOME}", util::format("${HOME}", params)); + BOOST_REQUIRE_EQUAL("${HOME}", string_util::format("${HOME}", params)); } BOOST_AUTO_TEST_CASE(keyword_simple) { - util::subst params; + string_util::subst params; params.keywords.insert({"target", "irccd"}); std::string expected = "hello irccd!"; - std::string result = util::format("hello #{target}!", params); + std::string result = string_util::format("hello #{target}!", params); BOOST_REQUIRE_EQUAL(expected, result); } BOOST_AUTO_TEST_CASE(keyword_multiple) { - util::subst params; + string_util::subst params; params.keywords.insert({"target", "irccd"}); params.keywords.insert({"source", "nightmare"}); std::string expected = "hello irccd from nightmare!"; - std::string result = util::format("hello #{target} from #{source}!", params); + std::string result = string_util::format("hello #{target} from #{source}!", params); BOOST_REQUIRE_EQUAL(expected, result); } BOOST_AUTO_TEST_CASE(keyword_adj_twice) { - util::subst params; + string_util::subst params; params.keywords.insert({"target", "irccd"}); std::string expected = "hello irccdirccd!"; - std::string result = util::format("hello #{target}#{target}!", params); + std::string result = string_util::format("hello #{target}#{target}!", params); BOOST_REQUIRE_EQUAL(expected, result); } @@ -140,7 +142,7 @@ BOOST_AUTO_TEST_CASE(keyword_missing) { std::string expected = "hello !"; - std::string result = util::format("hello #{target}!"); + std::string result = string_util::format("hello #{target}!"); BOOST_REQUIRE_EQUAL(expected, result); } @@ -151,7 +153,7 @@ if (!home.empty()) { std::string expected = "my home is " + home; - std::string result = util::format("my home is ${HOME}"); + std::string result = string_util::format("my home is ${HOME}"); BOOST_REQUIRE_EQUAL(expected, result); } @@ -160,7 +162,7 @@ BOOST_AUTO_TEST_CASE(env_missing) { std::string expected = "value is "; - std::string result = util::format("value is ${HOPE_THIS_VAR_NOT_EXIST}"); + std::string result = string_util::format("value is ${HOPE_THIS_VAR_NOT_EXIST}"); BOOST_REQUIRE_EQUAL(expected, result); } @@ -168,7 +170,7 @@ BOOST_AUTO_TEST_SUITE_END() /* - * util::split function + * string_util::split function * -------------------------------------------------------- */ @@ -179,7 +181,7 @@ BOOST_AUTO_TEST_CASE(simple) { list expected { "a", "b" }; - list result = util::split("a;b", ";"); + list result = string_util::split("a;b", ";"); BOOST_REQUIRE_EQUAL(expected, result); } @@ -187,7 +189,7 @@ BOOST_AUTO_TEST_CASE(cut) { list expected { "msg", "#staff", "foo bar baz" }; - list result = util::split("msg;#staff;foo bar baz", ";", 3); + list result = string_util::split("msg;#staff;foo bar baz", ";", 3); BOOST_REQUIRE_EQUAL(expected, result); } @@ -195,7 +197,7 @@ BOOST_AUTO_TEST_SUITE_END() /* - * util::strip function + * string_util::strip function * -------------------------------------------------------- */ @@ -204,7 +206,7 @@ BOOST_AUTO_TEST_CASE(left) { std::string value = " 123"; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("123", result); } @@ -212,7 +214,7 @@ BOOST_AUTO_TEST_CASE(right) { std::string value = "123 "; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("123", result); } @@ -220,7 +222,7 @@ BOOST_AUTO_TEST_CASE(both) { std::string value = " 123 "; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("123", result); } @@ -228,7 +230,7 @@ BOOST_AUTO_TEST_CASE(none) { std::string value = "without"; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("without", result); } @@ -236,7 +238,7 @@ BOOST_AUTO_TEST_CASE(betweenEmpty) { std::string value = "one list"; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("one list", result); } @@ -244,7 +246,7 @@ BOOST_AUTO_TEST_CASE(betweenLeft) { std::string value = " space at left"; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("space at left", result); } @@ -252,7 +254,7 @@ BOOST_AUTO_TEST_CASE(betweenRight) { std::string value = "space at right "; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("space at right", result); } @@ -260,7 +262,7 @@ BOOST_AUTO_TEST_CASE(betweenBoth) { std::string value = " space at both "; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("space at both", result); } @@ -268,7 +270,7 @@ BOOST_AUTO_TEST_CASE(empty) { std::string value = " "; - std::string result = util::strip(value); + std::string result = string_util::strip(value); BOOST_REQUIRE_EQUAL("", result); } @@ -276,7 +278,7 @@ BOOST_AUTO_TEST_SUITE_END() /* - * util::join function + * string_util::join function * -------------------------------------------------------- */ @@ -285,7 +287,7 @@ BOOST_AUTO_TEST_CASE(empty) { std::string expected = ""; - std::string result = util::join({}); + std::string result = string_util::join({}); BOOST_REQUIRE_EQUAL(expected, result); } @@ -293,7 +295,7 @@ BOOST_AUTO_TEST_CASE(one) { std::string expected = "1"; - std::string result = util::join({1}); + std::string result = string_util::join({1}); BOOST_REQUIRE_EQUAL(expected, result); } @@ -301,7 +303,7 @@ BOOST_AUTO_TEST_CASE(two) { std::string expected = "1:2"; - std::string result = util::join({1, 2}); + std::string result = string_util::join({1, 2}); BOOST_REQUIRE_EQUAL(expected, result); } @@ -309,7 +311,7 @@ BOOST_AUTO_TEST_CASE(delimiterString) { std::string expected = "1;;2;;3"; - std::string result = util::join({1, 2, 3}, ";;"); + std::string result = string_util::join({1, 2, 3}, ";;"); BOOST_REQUIRE_EQUAL(expected, result); } @@ -317,7 +319,7 @@ BOOST_AUTO_TEST_CASE(delimiterChar) { std::string expected = "1@2@3@4"; - std::string result = util::join({1, 2, 3, 4}, '@'); + std::string result = string_util::join({1, 2, 3, 4}, '@'); BOOST_REQUIRE_EQUAL(expected, result); } @@ -325,7 +327,7 @@ BOOST_AUTO_TEST_SUITE_END() /* - * util::is_identifier function + * string_util::is_identifier function * -------------------------------------------------------- */ @@ -333,26 +335,26 @@ BOOST_AUTO_TEST_CASE(correct) { - BOOST_REQUIRE(util::is_identifier("localhost")); - BOOST_REQUIRE(util::is_identifier("localhost2")); - BOOST_REQUIRE(util::is_identifier("localhost2-4_")); + BOOST_REQUIRE(string_util::is_identifier("localhost")); + BOOST_REQUIRE(string_util::is_identifier("localhost2")); + BOOST_REQUIRE(string_util::is_identifier("localhost2-4_")); } BOOST_AUTO_TEST_CASE(incorrect) { - BOOST_REQUIRE(!util::is_identifier("")); - BOOST_REQUIRE(!util::is_identifier("localhost with spaces")); - BOOST_REQUIRE(!util::is_identifier("localhost*")); - BOOST_REQUIRE(!util::is_identifier("&&")); - BOOST_REQUIRE(!util::is_identifier("@'")); - BOOST_REQUIRE(!util::is_identifier("##")); - BOOST_REQUIRE(!util::is_identifier("===++")); + BOOST_REQUIRE(!string_util::is_identifier("")); + BOOST_REQUIRE(!string_util::is_identifier("localhost with spaces")); + BOOST_REQUIRE(!string_util::is_identifier("localhost*")); + BOOST_REQUIRE(!string_util::is_identifier("&&")); + BOOST_REQUIRE(!string_util::is_identifier("@'")); + BOOST_REQUIRE(!string_util::is_identifier("##")); + BOOST_REQUIRE(!string_util::is_identifier("===++")); } BOOST_AUTO_TEST_SUITE_END() /* - * util::is_boolean function + * string_util::is_boolean function * -------------------------------------------------------- */ @@ -361,39 +363,39 @@ BOOST_AUTO_TEST_CASE(correct) { // true - BOOST_REQUIRE(util::is_boolean("true")); - BOOST_REQUIRE(util::is_boolean("True")); - BOOST_REQUIRE(util::is_boolean("TRUE")); - BOOST_REQUIRE(util::is_boolean("TruE")); + BOOST_REQUIRE(string_util::is_boolean("true")); + BOOST_REQUIRE(string_util::is_boolean("True")); + BOOST_REQUIRE(string_util::is_boolean("TRUE")); + BOOST_REQUIRE(string_util::is_boolean("TruE")); // yes - BOOST_REQUIRE(util::is_boolean("yes")); - BOOST_REQUIRE(util::is_boolean("Yes")); - BOOST_REQUIRE(util::is_boolean("YES")); - BOOST_REQUIRE(util::is_boolean("YeS")); + BOOST_REQUIRE(string_util::is_boolean("yes")); + BOOST_REQUIRE(string_util::is_boolean("Yes")); + BOOST_REQUIRE(string_util::is_boolean("YES")); + BOOST_REQUIRE(string_util::is_boolean("YeS")); // on - BOOST_REQUIRE(util::is_boolean("on")); - BOOST_REQUIRE(util::is_boolean("On")); - BOOST_REQUIRE(util::is_boolean("oN")); - BOOST_REQUIRE(util::is_boolean("ON")); + BOOST_REQUIRE(string_util::is_boolean("on")); + BOOST_REQUIRE(string_util::is_boolean("On")); + BOOST_REQUIRE(string_util::is_boolean("oN")); + BOOST_REQUIRE(string_util::is_boolean("ON")); // 1 - BOOST_REQUIRE(util::is_boolean("1")); + BOOST_REQUIRE(string_util::is_boolean("1")); } BOOST_AUTO_TEST_CASE(incorrect) { - BOOST_REQUIRE(!util::is_boolean("false")); - BOOST_REQUIRE(!util::is_boolean("lol")); - BOOST_REQUIRE(!util::is_boolean("")); - BOOST_REQUIRE(!util::is_boolean("0")); + BOOST_REQUIRE(!string_util::is_boolean("false")); + BOOST_REQUIRE(!string_util::is_boolean("lol")); + BOOST_REQUIRE(!string_util::is_boolean("")); + BOOST_REQUIRE(!string_util::is_boolean("0")); } BOOST_AUTO_TEST_SUITE_END() /* - * util::is_number function + * string_util::is_number function * -------------------------------------------------------- */ @@ -401,21 +403,21 @@ BOOST_AUTO_TEST_CASE(correct) { - BOOST_REQUIRE(util::is_number("123")); - BOOST_REQUIRE(util::is_number("-123")); - BOOST_REQUIRE(util::is_number("123.67")); + BOOST_REQUIRE(string_util::is_number("123")); + BOOST_REQUIRE(string_util::is_number("-123")); + BOOST_REQUIRE(string_util::is_number("123.67")); } BOOST_AUTO_TEST_CASE(incorrect) { - BOOST_REQUIRE(!util::is_number("lol")); - BOOST_REQUIRE(!util::is_number("this is not a number")); + BOOST_REQUIRE(!string_util::is_number("lol")); + BOOST_REQUIRE(!string_util::is_number("this is not a number")); } BOOST_AUTO_TEST_SUITE_END() /* - * util::to_number function + * string_util::to_number function * ------------------------------------------------------------------ */ @@ -424,44 +426,44 @@ BOOST_AUTO_TEST_CASE(correct) { /* unsigned */ - BOOST_REQUIRE_EQUAL(50u, util::to_number("50")); - BOOST_REQUIRE_EQUAL(5000u, util::to_number("5000")); - BOOST_REQUIRE_EQUAL(50000u, util::to_number("50000")); - BOOST_REQUIRE_EQUAL(500000u, util::to_number("500000")); + BOOST_REQUIRE_EQUAL(50u, string_util::to_number("50")); + BOOST_REQUIRE_EQUAL(5000u, string_util::to_number("5000")); + BOOST_REQUIRE_EQUAL(50000u, string_util::to_number("50000")); + BOOST_REQUIRE_EQUAL(500000u, string_util::to_number("500000")); /* signed */ - BOOST_REQUIRE_EQUAL(-50, util::to_number("-50")); - BOOST_REQUIRE_EQUAL(-500, util::to_number("-500")); - BOOST_REQUIRE_EQUAL(-5000, util::to_number("-5000")); - BOOST_REQUIRE_EQUAL(-50000, util::to_number("-50000")); + BOOST_REQUIRE_EQUAL(-50, string_util::to_number("-50")); + BOOST_REQUIRE_EQUAL(-500, string_util::to_number("-500")); + BOOST_REQUIRE_EQUAL(-5000, string_util::to_number("-5000")); + BOOST_REQUIRE_EQUAL(-50000, string_util::to_number("-50000")); } BOOST_AUTO_TEST_CASE(incorrect) { /* unsigned */ - BOOST_REQUIRE_THROW(util::to_number("300"), std::out_of_range); - BOOST_REQUIRE_THROW(util::to_number("80000"), std::out_of_range); - BOOST_REQUIRE_THROW(util::to_number("-125"), std::out_of_range); - BOOST_REQUIRE_THROW(util::to_number("-25000"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("300"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("80000"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("-125"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("-25000"), std::out_of_range); /* signed */ - BOOST_REQUIRE_THROW(util::to_number("300"), std::out_of_range); - BOOST_REQUIRE_THROW(util::to_number("80000"), std::out_of_range); - BOOST_REQUIRE_THROW(util::to_number("-300"), std::out_of_range); - BOOST_REQUIRE_THROW(util::to_number("-80000"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("300"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("80000"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("-300"), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("-80000"), std::out_of_range); /* not numbers */ - BOOST_REQUIRE_THROW(util::to_number("nonono"), std::invalid_argument); + BOOST_REQUIRE_THROW(string_util::to_number("nonono"), std::invalid_argument); /* custom ranges */ - BOOST_REQUIRE_THROW(util::to_number("50", 0, 10), std::out_of_range); - BOOST_REQUIRE_THROW(util::to_number("-50", -10, 10), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("50", 0, 10), std::out_of_range); + BOOST_REQUIRE_THROW(string_util::to_number("-50", -10, 10), std::out_of_range); } BOOST_AUTO_TEST_SUITE_END() /* - * util::fs::find function (name) + * fs_util::find function (name) * ------------------------------------------------------------------ */ @@ -469,8 +471,8 @@ BOOST_AUTO_TEST_CASE(not_recursive) { - auto file1 = util::fs::find(TESTS_BINARY_DIR "/root", "file-1.txt", false); - auto file2 = util::fs::find(TESTS_BINARY_DIR "/root", "file-2.txt", false); + auto file1 = fs_util::find(TESTS_BINARY_DIR "/root", "file-1.txt", false); + auto file2 = fs_util::find(TESTS_BINARY_DIR "/root", "file-2.txt", false); BOOST_TEST(file1.find("file-1.txt") != std::string::npos); BOOST_TEST(file2.empty()); @@ -478,8 +480,8 @@ BOOST_AUTO_TEST_CASE(recursive) { - auto file1 = util::fs::find(TESTS_BINARY_DIR "/root", "file-1.txt", true); - auto file2 = util::fs::find(TESTS_BINARY_DIR "/root", "file-2.txt", true); + auto file1 = fs_util::find(TESTS_BINARY_DIR "/root", "file-1.txt", true); + auto file2 = fs_util::find(TESTS_BINARY_DIR "/root", "file-2.txt", true); BOOST_TEST(file1.find("file-1.txt") != std::string::npos); BOOST_TEST(file2.find("file-2.txt") != std::string::npos); @@ -488,7 +490,7 @@ BOOST_AUTO_TEST_SUITE_END() /* - * util::fs::find function (regex) + * fs_util::find function (regex) * ------------------------------------------------------------------ */ @@ -498,7 +500,7 @@ { const std::regex regex("file-[12]\\.txt"); - auto file = util::fs::find(TESTS_BINARY_DIR "/root", regex, false); + auto file = fs_util::find(TESTS_BINARY_DIR "/root", regex, false); BOOST_TEST(file.find("file-1.txt") != std::string::npos); } @@ -507,7 +509,7 @@ { const std::regex regex("file-[12]\\.txt"); - auto file = util::fs::find(TESTS_BINARY_DIR "/root/level-a", regex, true); + auto file = fs_util::find(TESTS_BINARY_DIR "/root/level-a", regex, true); BOOST_TEST(file.find("file-2.txt") != std::string::npos); }