# HG changeset patch # User David Demelier # Date 1510871488 -3600 # Node ID b3a0f61a35fe27bfdeb18f85f66e97f5f84effa8 # Parent 9daccaeedcceae7c20670c89f30168b525e18933 Irccdctl: rename module to jsapi, closes #727 diff -r 9daccaeedcce -r b3a0f61a35fe irccd/main.cpp --- a/irccd/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/irccd/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -43,18 +43,18 @@ #include "irccd.hpp" #if defined(HAVE_JS) -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include "js_plugin.hpp" +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include #endif namespace irccd { @@ -333,17 +333,17 @@ #if defined(HAVE_JS) auto loader = std::make_unique(*instance); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); instance->plugins().add_loader(std::move(loader)); #endif diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/CMakeLists.txt --- a/libirccd-js/CMakeLists.txt Thu Nov 16 23:12:45 2017 +0100 +++ b/libirccd-js/CMakeLists.txt Thu Nov 16 23:31:28 2017 +0100 @@ -22,40 +22,40 @@ set( HEADERS - ${libirccd-js_SOURCE_DIR}/irccd/duktape.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_directory_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_elapsed_timer_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_file_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_irccd_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_logger_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_plugin_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_server_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_system_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_timer_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_unicode_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_util_module.hpp - ${libirccd-js_SOURCE_DIR}/irccd/js_plugin.hpp - ${libirccd-js_SOURCE_DIR}/irccd/timer.hpp - ${libirccd-js_SOURCE_DIR}/irccd/unicode.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/duktape.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/directory_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/elapsed_timer_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/file_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/irccd_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/logger_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/plugin_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/server_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/system_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/timer_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/unicode_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/util_jsapi.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/js_plugin.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/timer.hpp + ${libirccd-js_SOURCE_DIR}/irccd/js/unicode.hpp ) set( SOURCES - ${libirccd-js_SOURCE_DIR}/irccd/js_directory_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_elapsed_timer_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_file_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_irccd_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_logger_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_plugin_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_server_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_system_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_timer_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_unicode_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_util_module.cpp - ${libirccd-js_SOURCE_DIR}/irccd/js_plugin.cpp - ${libirccd-js_SOURCE_DIR}/irccd/timer.cpp - ${libirccd-js_SOURCE_DIR}/irccd/unicode.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/directory_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/elapsed_timer_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/file_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/irccd_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/logger_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/plugin_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/server_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/system_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/timer_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/unicode_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/util_jsapi.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/js_plugin.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/timer.cpp + ${libirccd-js_SOURCE_DIR}/irccd/js/unicode.cpp ) irccd_define_library( diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/duktape.hpp --- a/libirccd-js/irccd/duktape.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,512 +0,0 @@ -/* - * duktape.hpp -- Duktape extras - * - * Copyright (c) 2016-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_DUKTAPE_HPP -#define IRCCD_DUKTAPE_HPP - -/** - * \file duktape.hpp - * \brief Bring some extras to Duktape C library. - * \author David Demelier - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace irccd { - -/** - * \brief Stack sanity checker. - * - * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor - * will examinate if the stack size matches the user expected size. - * - * When compiled with NDEBUG, this class does nothing. - * - * To use it, just declare an lvalue at the beginning of your function. - */ -class StackAssert { -#if !defined(NDEBUG) -private: - duk_context *m_context; - unsigned m_expected; - unsigned m_begin; -#endif - -public: - /** - * Create the stack checker. - * - * No-op if NDEBUG is set. - * - * \param ctx the context - * \param expected the size expected relative to the already existing values - */ - inline StackAssert(duk_context *ctx, unsigned expected = 0) noexcept -#if !defined(NDEBUG) - : m_context(ctx) - , m_expected(expected) - , m_begin(static_cast(duk_get_top(ctx))) -#endif - { -#if defined(NDEBUG) - (void)ctx; - (void)expected; -#endif - } - - /** - * Verify the expected size. - * - * No-op if NDEBUG is set. - */ - inline ~StackAssert() noexcept - { -#if !defined(NDEBUG) - if (static_cast(duk_get_top(m_context)) - m_begin != m_expected) { - std::fprintf(stderr, "Corrupt stack detection in StackAssert:\n"); - std::fprintf(stderr, " Size at start: %u\n", m_begin); - std::fprintf(stderr, " Size at end: %d\n", duk_get_top(m_context)); - std::fprintf(stderr, " Expected (user): %u\n", m_expected); - std::fprintf(stderr, " Expected (adjusted): %u\n", m_expected + m_begin); - std::fprintf(stderr, " Number of stale values: %u\n", duk_get_top(m_context) - m_begin - m_expected); - std::abort(); - } -#endif - } -}; - -/** - * \brief Error description. - * - * This class fills the fields got in an Error object. - */ -class Exception : public std::exception { -public: - std::string name; //!< name of error - std::string message; //!< error message - std::string stack; //!< stack if available - std::string fileName; //!< filename if applicable - int lineNumber{0}; //!< line number if applicable - - /** - * Get the error message. This effectively returns message field. - * - * \return the message - */ - const char *what() const noexcept override - { - return message.c_str(); - } -}; - -/** - * \brief RAII based Duktape handler. - * - * This class is implicitly convertible to duk_context for convenience. - */ -class UniqueContext { -private: - using Deleter = void (*)(duk_context *); - using Handle = std::unique_ptr; - - Handle m_handle; - - UniqueContext(const UniqueContext &) = delete; - UniqueContext &operator=(const UniqueContext &) = delete; - -public: - /** - * Create default context. - */ - inline UniqueContext() - : m_handle(duk_create_heap_default(), duk_destroy_heap) - { - } - - /** - * Default move constructor. - */ - UniqueContext(UniqueContext &&) noexcept = default; - - /** - * Convert the context to the native Duktape/C type. - * - * \return the duk_context - */ - inline operator duk_context *() noexcept - { - return m_handle.get(); - } - - /** - * Convert the context to the native Duktape/C type. - * - * \return the duk_context - */ - inline operator duk_context *() const noexcept - { - return m_handle.get(); - } - - /** - * Default move assignment operator. - * - * \return this - */ - UniqueContext &operator=(UniqueContext &&) noexcept = delete; -}; - -/** - * \brief Base ECMAScript error class. - * \warning Override the function create for your own exceptions - */ -class Error { -private: - int m_type{DUK_ERR_ERROR}; - std::string m_message; - -protected: - /** - * Constructor with a type of error specified, specially designed for derived errors. - * - * \param type of error (e.g. DUK_ERR_ERROR) - * \param message the message - */ - inline Error(int type, std::string message) noexcept - : m_type(type) - , m_message(std::move(message)) - { - } - -public: - /** - * Constructor with a message. - * - * \param message the message - */ - inline Error(std::string message) noexcept - : m_message(std::move(message)) - { - } - - /** - * Create the exception on the stack. - * - * \note the default implementation search for the global variables - * \param ctx the context - */ - virtual void raise(duk_context *ctx) const - { - duk_error(ctx, m_type, "%s", m_message.c_str()); - } -}; - -/** - * \brief Error in eval() function. - */ -class EvalError : public Error { -public: - /** - * Construct an EvalError. - * - * \param message the message - */ - inline EvalError(std::string message) noexcept - : Error(DUK_ERR_EVAL_ERROR, std::move(message)) - { - } -}; - -/** - * \brief Value is out of range. - */ -class RangeError : public Error { -public: - /** - * Construct an RangeError. - * - * \param message the message - */ - inline RangeError(std::string message) noexcept - : Error(DUK_ERR_RANGE_ERROR, std::move(message)) - { - } -}; - -/** - * \brief Trying to use a variable that does not exist. - */ -class ReferenceError : public Error { -public: - /** - * Construct an ReferenceError. - * - * \param message the message - */ - inline ReferenceError(std::string message) noexcept - : Error(DUK_ERR_REFERENCE_ERROR, std::move(message)) - { - } -}; - -/** - * \brief Syntax error in the script. - */ -class SyntaxError : public Error { -public: - /** - * Construct an SyntaxError. - * - * \param message the message - */ - inline SyntaxError(std::string message) noexcept - : Error(DUK_ERR_SYNTAX_ERROR, std::move(message)) - { - } -}; - -/** - * \brief Invalid type given. - */ -class TypeError : public Error { -public: - /** - * Construct an TypeError. - * - * \param message the message - */ - inline TypeError(std::string message) noexcept - : Error(DUK_ERR_TYPE_ERROR, std::move(message)) - { - } -}; - -/** - * \brief URI manipulation failure. - */ -class URIError : public Error { -public: - /** - * Construct an URIError. - * - * \param message the message - */ - inline URIError(std::string message) noexcept - : Error(DUK_ERR_URI_ERROR, std::move(message)) - { - } -}; - -/** - * Get the error object when a JavaScript error has been thrown (e.g. eval failure). - * - * \param ctx the context - * \param index the index - * \param pop if true, also remove the exception from the stack - * \return the information - */ -inline Exception dukx_exception(duk_context *ctx, int index, bool pop = true) -{ - Exception ex; - - index = duk_normalize_index(ctx, index); - - duk_get_prop_string(ctx, index, "name"); - ex.name = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "message"); - ex.message = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "fileName"); - ex.fileName = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "lineNumber"); - ex.lineNumber = duk_to_int(ctx, -1); - duk_get_prop_string(ctx, index, "stack"); - ex.stack = duk_to_string(ctx, -1); - duk_pop_n(ctx, 5); - - if (pop) - duk_remove(ctx, index); - - return ex; -} - -/** - * Enumerate an object or an array at the specified index. - * - * \param ctx the context - * \param index the object or array index - * \param flags the optional flags to pass to duk_enum - * \param getvalue set to true if you want to extract the value - * \param func the function to call for each properties - */ -template -void dukx_enumerate(duk_context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func) -{ - duk_enum(ctx, index, flags); - - while (duk_next(ctx, -1, getvalue)) { - func(ctx); - duk_pop_n(ctx, 1 + (getvalue ? 1 : 0)); - } - - duk_pop(ctx); -} - -/** - * Throw an ECMAScript exception. - * - * \param ctx the context - * \param ex the exception - */ -template -void dukx_throw(duk_context *ctx, const Exception &ex) -{ - ex.raise(ctx); -} - -/** - * Get a string, return 0 if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ -inline std::string dukx_get_std_string(duk_context *ctx, int index) -{ - duk_size_t size; - const char *text = duk_get_lstring(ctx, index, &size); - - return std::string(text, size); -} - -/** - * Require a string, throws a JavaScript exception if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ -inline std::string dukx_require_std_string(duk_context *ctx, int index) -{ - duk_size_t size; - const char *text = duk_require_lstring(ctx, index, &size); - - return std::string(text, size); -} - -/** - * Push a C++ string. - * - * \param ctx the context - * \param str the string - */ -inline void dukx_push_std_string(duk_context *ctx, const std::string &str) -{ - duk_push_lstring(ctx, str.data(), str.length()); -} - -/** - * Get an array. - * - * \param ctx the context - * \param index the array index - * \param get the conversion function (e.g. duk_get_int) - */ -template -auto dukx_get_array(duk_context *ctx, duk_idx_t index, Getter &&get) -{ - using T = decltype(get(ctx, 0)); - - std::vector result; - std::size_t length = duk_get_length(ctx, index); - - for (std::size_t i = 0; i < length; ++i) { - duk_get_prop_index(ctx, -1, i); - result.push_back(get(ctx, -1)); - duk_pop(ctx); - } - - return result; -} - -/** - * Push an array. - * - * \param ctx the context - * \param values the values - * \param push the function to push values - */ -template -void dukx_push_array(duk_context *ctx, const std::vector &values, Pusher &&push) -{ - duk_push_array(ctx); - - int i = 0; - for (auto x : values) { - push(ctx, x); - duk_put_prop_index(ctx, -2, i++); - } -} - -/** - * Replace the removed duk_peval_string with one throwing exception. - * - * \param ctx the context - * \param path the path to the file - * \throw Exception on errors - */ -inline void dukx_peval_file(duk_context* ctx, const std::string& path) -{ - std::ifstream input(path); - - if (!input) { - Exception ex; - - ex.name = "Error"; - ex.message = std::strerror(errno); - ex.fileName = path; - - throw ex; - } - - std::string data(std::istreambuf_iterator(input), {}); - - if (duk_peval_lstring(ctx, data.c_str(), data.length()) != 0) { - auto ex = dukx_exception(ctx, -1); - - ex.fileName = path; - - throw ex; - } -} - -} // !irccd - -#endif // !IRCCD_DUKTAPE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/directory_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/directory_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,330 @@ +/* + * directory_jsapi.cpp -- Irccd.Directory API + * + * 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 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "directory_jsapi.hpp" +#include "irccd_jsapi.hpp" +#include "js_plugin.hpp" + +namespace fs = boost::filesystem; + +namespace irccd { + +namespace { + +std::string path(duk_context *ctx) +{ + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, "path"); + + if (duk_get_type(ctx, -1) != DUK_TYPE_STRING) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Directory object"); + + auto ret = dukx_get_std_string(ctx, -1); + + if (ret.empty()) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path"); + + duk_pop_n(ctx, 2); + + return ret; +} + +/* + * Generic find function for: + * + * - Directory.find + * - Directory.prototype.find + * + * The patternIndex is the argument where to test if the argument is a regex or + * a string. + */ +duk_ret_t find(duk_context* ctx, std::string base, bool recursive, int pattern_index) +{ + try { + std::string path; + + if (duk_is_string(ctx, pattern_index)) + 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"); + auto is_regex = duk_instanceof(ctx, pattern_index, -1); + duk_pop(ctx); + + if (is_regex) { + duk_get_prop_string(ctx, pattern_index, "source"); + auto pattern = duk_to_string(ctx, -1); + duk_pop(ctx); + + 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"); + } + + if (path.empty()) + return 0; + + dukx_push_std_string(ctx, path); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 1; +} + +/* + * Generic remove function for: + * + * - Directory.remove + * - Directory.prototype.remove + */ +duk_ret_t remove(duk_context* ctx, const std::string& path, bool recursive) +{ + boost::system::error_code ec; + + if (!boost::filesystem::is_directory(path, ec) || ec) + dukx_throw(ctx, system_error(EINVAL, "not a directory")); + + if (!recursive) + boost::filesystem::remove(path, ec); + else + boost::filesystem::remove_all(path, ec); + + return 0; +} + +/* + * Method: Directory.find(pattern, recursive) + * -------------------------------------------------------- + * + * Synonym of Directory.find(path, pattern, recursive) but the path is taken + * from the directory object. + * + * Arguments: + * - pattern, the regular expression or file name, + * - recursive, set to true to search recursively (default: false). + * Returns: + * The path to the file or undefined if not found. + * Throws: + * - Any exception on error. + */ +duk_ret_t method_find(duk_context* ctx) +{ + return find(ctx, path(ctx), duk_get_boolean(ctx, 1), 0); +} + +/* + * Method: Directory.remove(recursive) + * -------------------------------------------------------- + * + * Synonym of Directory.remove(recursive) but the path is taken from the + * directory object. + * + * Arguments: + * - recursive, recursively or not (default: false). + * Throws: + * - Any exception on error. + */ +duk_ret_t method_remove(duk_context* ctx) +{ + return remove(ctx, path(ctx), duk_get_boolean(ctx, 0)); +} + +const duk_function_list_entry methods[] = { + { "find", method_find, DUK_VARARGS }, + { "remove", method_remove, 1 }, + { nullptr, nullptr, 0 } +}; + +/* + * Directory "static" functions + * ------------------------------------------------------------------ + */ + +/* + * Function: Irccd.Directory(path) [constructor] + * -------------------------------------------------------- + * + * Opens and read the directory at the specified path. + * + * Arguments: + * - path, the path to the directory, + * Throws: + * - Any exception on error + */ +duk_ret_t constructor(duk_context* ctx) +{ + if (!duk_is_constructor_call(ctx)) + return 0; + + try { + auto path = duk_require_string(ctx, 0); + + if (!boost::filesystem::is_directory(path)) + dukx_throw(ctx, system_error(EINVAL, "not a directory")); + + duk_push_this(ctx); + + // 'entries' property. + duk_push_string(ctx, "entries"); + duk_push_array(ctx); + + unsigned i = 0; + for (const auto& entry : boost::filesystem::directory_iterator(path)) { + duk_push_object(ctx); + dukx_push_std_string(ctx, entry.path().filename().string()); + duk_put_prop_string(ctx, -2, "name"); + duk_push_int(ctx, entry.status().type()); + duk_put_prop_string(ctx, -2, "type"); + duk_put_prop_index(ctx, -2, i++); + } + + duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); + + // 'path' property. + duk_push_string(ctx, "path"); + dukx_push_std_string(ctx, path); + duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); + } catch (const std::exception& ex) { + dukx_throw(ctx, system_error(errno, ex.what())); + } + + return 0; +} + +/* + * Function: irccd.Directory.find(path, pattern, recursive) + * -------------------------------------------------------- + * + * Find an entry by a pattern or a regular expression. + * + * Arguments: + * - path, the base path, + * - pattern, the regular expression or file name, + * - recursive, set to true to search recursively (default: false). + * Returns: + * The path to the file or undefined on errors or not found. + */ +duk_ret_t func_find(duk_context* ctx) +{ + return find(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 2), 1); +} + +/* + * Function: irccd.Directory.remove(path, recursive) + * -------------------------------------------------------- + * + * Remove the directory optionally recursively. + * + * Arguments: + * - path, the path to the directory, + * - recursive, recursively or not (default: false). + * Throws: + * - Any exception on error. + */ +duk_ret_t func_remove(duk_context *ctx) +{ + return remove(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 1)); +} + +/* + * Function: irccd.Directory.mkdir(path, mode = 0700) + * -------------------------------------------------------- + * + * Create a directory specified by path. It will create needed subdirectories + * just like you have invoked mkdir -p. + * + * Arguments: + * - path, the path to the directory, + * Throws: + * - Any exception on error. + */ +duk_ret_t func_mkdir(duk_context *ctx) +{ + try { + boost::filesystem::create_directories(duk_require_string(ctx, 0)); + } catch (const std::exception &ex) { + dukx_throw(ctx, system_error(errno, ex.what())); + } + + return 0; +} + +const duk_function_list_entry functions[] = { + { "find", func_find, DUK_VARARGS }, + { "mkdir", func_mkdir, DUK_VARARGS }, + { "remove", func_remove, DUK_VARARGS }, + { nullptr, nullptr, 0 } +}; + +const duk_number_list_entry constants[] = { + { "TypeFile", static_cast(fs::regular_file) }, + { "TypeDir", static_cast(fs::directory_file) }, + { "TypeLink", static_cast(fs::symlink_file) }, + { "TypeBlock", static_cast(fs::block_file) }, + { "TypeCharacter", static_cast(fs::character_file) }, + { "TypeFifo", static_cast(fs::fifo_file) }, + { "TypeSocket", static_cast(fs::socket_file) }, + { "TypeUnknown", static_cast(fs::type_unknown) }, + { nullptr, 0 } +}; + +} // !namespace + +std::string directory_jsapi::name() const +{ + return "Irccd.Directory"; +} + +void directory_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_c_function(plugin->context(), constructor, 2); + duk_put_number_list(plugin->context(), -1, constants); + duk_put_function_list(plugin->context(), -1, functions); + +#if defined(IRCCD_SYSTEM_WINDOWS) + duk_push_string(plugin->context(), "\\"); +#else + duk_push_string(plugin->context(), "/"); +#endif + + duk_put_prop_string(plugin->context(), -2, "separator"); + + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, methods); + duk_put_prop_string(plugin->context(), -2, "prototype"); + duk_put_prop_string(plugin->context(), -2, "Directory"); + duk_pop(plugin->context()); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/directory_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/directory_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,50 @@ +/* + * directory_jsapi.hpp -- Irccd.Directory API + * + * 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_JS_DIRECTORY_JSAPI_HPP +#define IRCCD_JS_DIRECTORY_JSAPI_HPP + +/** + * \file directory_jsapi.hpp + * \brief Irccd.Directory Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Irccd.Directory Javascript API. + * \ingroup jsapi + */ +class directory_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +} // !irccd + +#endif // !IRCCD_JS_DIRECTORY_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/duktape.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/duktape.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,512 @@ +/* + * duktape.hpp -- Duktape extras + * + * Copyright (c) 2016-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_DUKTAPE_HPP +#define IRCCD_DUKTAPE_HPP + +/** + * \file duktape.hpp + * \brief Bring some extras to Duktape C library. + * \author David Demelier + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace irccd { + +/** + * \brief Stack sanity checker. + * + * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor + * will examinate if the stack size matches the user expected size. + * + * When compiled with NDEBUG, this class does nothing. + * + * To use it, just declare an lvalue at the beginning of your function. + */ +class StackAssert { +#if !defined(NDEBUG) +private: + duk_context *m_context; + unsigned m_expected; + unsigned m_begin; +#endif + +public: + /** + * Create the stack checker. + * + * No-op if NDEBUG is set. + * + * \param ctx the context + * \param expected the size expected relative to the already existing values + */ + inline StackAssert(duk_context *ctx, unsigned expected = 0) noexcept +#if !defined(NDEBUG) + : m_context(ctx) + , m_expected(expected) + , m_begin(static_cast(duk_get_top(ctx))) +#endif + { +#if defined(NDEBUG) + (void)ctx; + (void)expected; +#endif + } + + /** + * Verify the expected size. + * + * No-op if NDEBUG is set. + */ + inline ~StackAssert() noexcept + { +#if !defined(NDEBUG) + if (static_cast(duk_get_top(m_context)) - m_begin != m_expected) { + std::fprintf(stderr, "Corrupt stack detection in StackAssert:\n"); + std::fprintf(stderr, " Size at start: %u\n", m_begin); + std::fprintf(stderr, " Size at end: %d\n", duk_get_top(m_context)); + std::fprintf(stderr, " Expected (user): %u\n", m_expected); + std::fprintf(stderr, " Expected (adjusted): %u\n", m_expected + m_begin); + std::fprintf(stderr, " Number of stale values: %u\n", duk_get_top(m_context) - m_begin - m_expected); + std::abort(); + } +#endif + } +}; + +/** + * \brief Error description. + * + * This class fills the fields got in an Error object. + */ +class Exception : public std::exception { +public: + std::string name; //!< name of error + std::string message; //!< error message + std::string stack; //!< stack if available + std::string fileName; //!< filename if applicable + int lineNumber{0}; //!< line number if applicable + + /** + * Get the error message. This effectively returns message field. + * + * \return the message + */ + const char *what() const noexcept override + { + return message.c_str(); + } +}; + +/** + * \brief RAII based Duktape handler. + * + * This class is implicitly convertible to duk_context for convenience. + */ +class UniqueContext { +private: + using Deleter = void (*)(duk_context *); + using Handle = std::unique_ptr; + + Handle m_handle; + + UniqueContext(const UniqueContext &) = delete; + UniqueContext &operator=(const UniqueContext &) = delete; + +public: + /** + * Create default context. + */ + inline UniqueContext() + : m_handle(duk_create_heap_default(), duk_destroy_heap) + { + } + + /** + * Default move constructor. + */ + UniqueContext(UniqueContext &&) noexcept = default; + + /** + * Convert the context to the native Duktape/C type. + * + * \return the duk_context + */ + inline operator duk_context *() noexcept + { + return m_handle.get(); + } + + /** + * Convert the context to the native Duktape/C type. + * + * \return the duk_context + */ + inline operator duk_context *() const noexcept + { + return m_handle.get(); + } + + /** + * Default move assignment operator. + * + * \return this + */ + UniqueContext &operator=(UniqueContext &&) noexcept = delete; +}; + +/** + * \brief Base ECMAScript error class. + * \warning Override the function create for your own exceptions + */ +class Error { +private: + int m_type{DUK_ERR_ERROR}; + std::string m_message; + +protected: + /** + * Constructor with a type of error specified, specially designed for derived errors. + * + * \param type of error (e.g. DUK_ERR_ERROR) + * \param message the message + */ + inline Error(int type, std::string message) noexcept + : m_type(type) + , m_message(std::move(message)) + { + } + +public: + /** + * Constructor with a message. + * + * \param message the message + */ + inline Error(std::string message) noexcept + : m_message(std::move(message)) + { + } + + /** + * Create the exception on the stack. + * + * \note the default implementation search for the global variables + * \param ctx the context + */ + virtual void raise(duk_context *ctx) const + { + duk_error(ctx, m_type, "%s", m_message.c_str()); + } +}; + +/** + * \brief Error in eval() function. + */ +class EvalError : public Error { +public: + /** + * Construct an EvalError. + * + * \param message the message + */ + inline EvalError(std::string message) noexcept + : Error(DUK_ERR_EVAL_ERROR, std::move(message)) + { + } +}; + +/** + * \brief Value is out of range. + */ +class RangeError : public Error { +public: + /** + * Construct an RangeError. + * + * \param message the message + */ + inline RangeError(std::string message) noexcept + : Error(DUK_ERR_RANGE_ERROR, std::move(message)) + { + } +}; + +/** + * \brief Trying to use a variable that does not exist. + */ +class ReferenceError : public Error { +public: + /** + * Construct an ReferenceError. + * + * \param message the message + */ + inline ReferenceError(std::string message) noexcept + : Error(DUK_ERR_REFERENCE_ERROR, std::move(message)) + { + } +}; + +/** + * \brief Syntax error in the script. + */ +class SyntaxError : public Error { +public: + /** + * Construct an SyntaxError. + * + * \param message the message + */ + inline SyntaxError(std::string message) noexcept + : Error(DUK_ERR_SYNTAX_ERROR, std::move(message)) + { + } +}; + +/** + * \brief Invalid type given. + */ +class TypeError : public Error { +public: + /** + * Construct an TypeError. + * + * \param message the message + */ + inline TypeError(std::string message) noexcept + : Error(DUK_ERR_TYPE_ERROR, std::move(message)) + { + } +}; + +/** + * \brief URI manipulation failure. + */ +class URIError : public Error { +public: + /** + * Construct an URIError. + * + * \param message the message + */ + inline URIError(std::string message) noexcept + : Error(DUK_ERR_URI_ERROR, std::move(message)) + { + } +}; + +/** + * Get the error object when a JavaScript error has been thrown (e.g. eval failure). + * + * \param ctx the context + * \param index the index + * \param pop if true, also remove the exception from the stack + * \return the information + */ +inline Exception dukx_exception(duk_context *ctx, int index, bool pop = true) +{ + Exception ex; + + index = duk_normalize_index(ctx, index); + + duk_get_prop_string(ctx, index, "name"); + ex.name = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "message"); + ex.message = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "fileName"); + ex.fileName = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "lineNumber"); + ex.lineNumber = duk_to_int(ctx, -1); + duk_get_prop_string(ctx, index, "stack"); + ex.stack = duk_to_string(ctx, -1); + duk_pop_n(ctx, 5); + + if (pop) + duk_remove(ctx, index); + + return ex; +} + +/** + * Enumerate an object or an array at the specified index. + * + * \param ctx the context + * \param index the object or array index + * \param flags the optional flags to pass to duk_enum + * \param getvalue set to true if you want to extract the value + * \param func the function to call for each properties + */ +template +void dukx_enumerate(duk_context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func) +{ + duk_enum(ctx, index, flags); + + while (duk_next(ctx, -1, getvalue)) { + func(ctx); + duk_pop_n(ctx, 1 + (getvalue ? 1 : 0)); + } + + duk_pop(ctx); +} + +/** + * Throw an ECMAScript exception. + * + * \param ctx the context + * \param ex the exception + */ +template +void dukx_throw(duk_context *ctx, const Exception &ex) +{ + ex.raise(ctx); +} + +/** + * Get a string, return 0 if not a string. + * + * \param ctx the context + * \param index the index + * \return the string + */ +inline std::string dukx_get_std_string(duk_context *ctx, int index) +{ + duk_size_t size; + const char *text = duk_get_lstring(ctx, index, &size); + + return std::string(text, size); +} + +/** + * Require a string, throws a JavaScript exception if not a string. + * + * \param ctx the context + * \param index the index + * \return the string + */ +inline std::string dukx_require_std_string(duk_context *ctx, int index) +{ + duk_size_t size; + const char *text = duk_require_lstring(ctx, index, &size); + + return std::string(text, size); +} + +/** + * Push a C++ string. + * + * \param ctx the context + * \param str the string + */ +inline void dukx_push_std_string(duk_context *ctx, const std::string &str) +{ + duk_push_lstring(ctx, str.data(), str.length()); +} + +/** + * Get an array. + * + * \param ctx the context + * \param index the array index + * \param get the conversion function (e.g. duk_get_int) + */ +template +auto dukx_get_array(duk_context *ctx, duk_idx_t index, Getter &&get) +{ + using T = decltype(get(ctx, 0)); + + std::vector result; + std::size_t length = duk_get_length(ctx, index); + + for (std::size_t i = 0; i < length; ++i) { + duk_get_prop_index(ctx, -1, i); + result.push_back(get(ctx, -1)); + duk_pop(ctx); + } + + return result; +} + +/** + * Push an array. + * + * \param ctx the context + * \param values the values + * \param push the function to push values + */ +template +void dukx_push_array(duk_context *ctx, const std::vector &values, Pusher &&push) +{ + duk_push_array(ctx); + + int i = 0; + for (auto x : values) { + push(ctx, x); + duk_put_prop_index(ctx, -2, i++); + } +} + +/** + * Replace the removed duk_peval_string with one throwing exception. + * + * \param ctx the context + * \param path the path to the file + * \throw Exception on errors + */ +inline void dukx_peval_file(duk_context* ctx, const std::string& path) +{ + std::ifstream input(path); + + if (!input) { + Exception ex; + + ex.name = "Error"; + ex.message = std::strerror(errno); + ex.fileName = path; + + throw ex; + } + + std::string data(std::istreambuf_iterator(input), {}); + + if (duk_peval_lstring(ctx, data.c_str(), data.length()) != 0) { + auto ex = dukx_exception(ctx, -1); + + ex.fileName = path; + + throw ex; + } +} + +} // !irccd + +#endif // !IRCCD_DUKTAPE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/elapsed_timer_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/elapsed_timer_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,148 @@ +/* + * elapsed_timer_jsapi.cpp -- Irccd.ElapsedTimer API + * + * 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 + +#include "elapsed_timer_jsapi.hpp" +#include "js_plugin.hpp" + +namespace irccd { + +namespace { + +const char* signature("\xff""\xff""irccd-elapsed-timer-ptr"); + +boost::timer::cpu_timer* self(duk_context* ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature); + auto ptr = static_cast(duk_to_pointer(ctx, -1)); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object"); + + return ptr; +} + +/* + * Method: ElapsedTimer.pause + * ------------------------------------------------------------------ + * + * Pause the timer, without resetting the current elapsed time stored. + */ +duk_ret_t pause(duk_context* ctx) +{ + self(ctx)->stop(); + + return 0; +} + +/* + * Method: ElapsedTimer.restart + * ------------------------------------------------------------------ + * + * Restart the timer without resetting the current elapsed time. + */ +duk_ret_t restart(duk_context* ctx) +{ + self(ctx)->resume(); + + return 0; +} + +/* + * Method: ElapsedTimer.elapsed + * ------------------------------------------------------------------ + * + * Get the number of elapsed milliseconds. + * + * Returns: + * The time elapsed. + */ +duk_ret_t elapsed(duk_context* ctx) +{ + duk_push_uint(ctx, self(ctx)->elapsed().wall / 1000000LL); + + return 1; +} + +/* + * Function: Irccd.ElapsedTimer [constructor] + * ------------------------------------------------------------------ + * + * Construct a new ElapsedTimer object. + */ +duk_ret_t constructor(duk_context* ctx) +{ + duk_push_this(ctx); + duk_push_pointer(ctx, new boost::timer::cpu_timer); + duk_put_prop_string(ctx, -2, signature); + duk_pop(ctx); + + return 0; +} + +/* + * Function: Irccd.ElapsedTimer [destructor] + * ------------------------------------------------------------------ + * + * Delete the property. + */ +duk_ret_t destructor(duk_context* ctx) +{ + duk_get_prop_string(ctx, 0, signature); + delete static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, signature); + + return 0; +} + +const duk_function_list_entry methods[] = { + { "elapsed", elapsed, 0 }, + { "pause", pause, 0 }, + { "restart", restart, 0 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +std::string elapsed_timer_jsapi::name() const +{ + return "Irccd.ElapsedTimer"; +} + +void elapsed_timer_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_c_function(plugin->context(), constructor, 0); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, methods); + duk_push_c_function(plugin->context(), destructor, 1); + duk_set_finalizer(plugin->context(), -2); + duk_put_prop_string(plugin->context(), -2, "prototype"); + duk_put_prop_string(plugin->context(), -2, "ElapsedTimer"); + duk_pop(plugin->context()); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/elapsed_timer_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/elapsed_timer_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,50 @@ +/* + * elapsed_timer_jsapi.hpp -- Irccd.ElapsedTimer API + * + * 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_JS_ELAPSED_TIMER_JSAPI_HPP +#define IRCCD_JS_ELAPSED_TIMER_JSAPI_HPP + +/** + * \file elapsed_timer_jsapi.hpp + * \brief Irccd.ElapsedTimer Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Irccd.ElapsedTimer Javascript API. + * \ingroup Javascript jsapi + */ +class elapsed_timer_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +} // !irccd + +#endif // !IRCCD_JS_ELAPSED_TIMER_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/file_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/file_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,700 @@ +/* + * file_jsapi.cpp -- Irccd.File API + * + * 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 + +#include +#include +#include +#include +#include + +#include + +#if defined(HAVE_STAT) +# include +# include +#endif + +#include + +#include "file_jsapi.hpp" +#include "irccd_jsapi.hpp" +#include "js_plugin.hpp" + +namespace irccd { + +namespace { + +const char *signature("\xff""\xff""irccd-file-ptr"); +const char *prototype("\xff""\xff""irccd-file-prototype"); + +#if defined(HAVE_STAT) + +/* + * push_stat + * ------------------------------------------------------------------ + */ + +void push_stat(duk_context* ctx, const struct stat& st) +{ + StackAssert sa(ctx, 1); + + duk_push_object(ctx); + +#if defined(HAVE_STAT_ST_ATIME) + duk_push_int(ctx, st.st_atime); + duk_put_prop_string(ctx, -2, "atime"); +#endif +#if defined(HAVE_STAT_ST_BLKSIZE) + duk_push_int(ctx, st.st_blksize); + duk_put_prop_string(ctx, -2, "blksize"); +#endif +#if defined(HAVE_STAT_ST_BLOCKS) + duk_push_int(ctx, st.st_blocks); + duk_put_prop_string(ctx, -2, "blocks"); +#endif +#if defined(HAVE_STAT_ST_CTIME) + duk_push_int(ctx, st.st_ctime); + duk_put_prop_string(ctx, -2, "ctime"); +#endif +#if defined(HAVE_STAT_ST_DEV) + duk_push_int(ctx, st.st_dev); + duk_put_prop_string(ctx, -2, "dev"); +#endif +#if defined(HAVE_STAT_ST_GID) + duk_push_int(ctx, st.st_gid); + duk_put_prop_string(ctx, -2, "gid"); +#endif +#if defined(HAVE_STAT_ST_INO) + duk_push_int(ctx, st.st_ino); + duk_put_prop_string(ctx, -2, "ino"); +#endif +#if defined(HAVE_STAT_ST_MODE) + duk_push_int(ctx, st.st_mode); + duk_put_prop_string(ctx, -2, "mode"); +#endif +#if defined(HAVE_STAT_ST_MTIME) + duk_push_int(ctx, st.st_mtime); + duk_put_prop_string(ctx, -2, "mtime"); +#endif +#if defined(HAVE_STAT_ST_NLINK) + duk_push_int(ctx, st.st_nlink); + duk_put_prop_string(ctx, -2, "nlink"); +#endif +#if defined(HAVE_STAT_ST_RDEV) + duk_push_int(ctx, st.st_rdev); + duk_put_prop_string(ctx, -2, "rdev"); +#endif +#if defined(HAVE_STAT_ST_SIZE) + duk_push_int(ctx, st.st_size); + duk_put_prop_string(ctx, -2, "size"); +#endif +#if defined(HAVE_STAT_ST_UID) + duk_push_int(ctx, st.st_uid); + duk_put_prop_string(ctx, -2, "uid"); +#endif +} + +#endif // !HAVE_STAT + +// Remove trailing \r for CRLF line style. +inline std::string clear_crlf(std::string input) +{ + if (input.length() > 0 && input.back() == '\r') + input.pop_back(); + + return input; +} + +file* self(duk_context* ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature); + auto ptr = static_cast(duk_to_pointer(ctx, -1)); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); + + return ptr; +} + +/* + * File methods. + * ------------------------------------------------------------------ + */ + +/* + * Method: File.basename() + * -------------------------------------------------------- + * + * Synonym of `irccd.File.basename(path)` but with the path from the file. + * + * duk_ret_turns: + * The base name. + */ +duk_ret_t method_basename(duk_context* ctx) +{ + dukx_push_std_string(ctx, fs_util::base_name(self(ctx)->path())); + + return 1; +} + +/* + * Method: File.close() + * -------------------------------------------------------- + * + * Force close of the file, automatically called when object is collected. + */ +duk_ret_t method_close(duk_context* ctx) +{ + self(ctx)->close(); + + return 0; +} + +/* + * Method: File.dirname() + * -------------------------------------------------------- + * + * Synonym of `irccd.File.dirname(path)` but with the path from the file. + * + * duk_ret_turns: + * The directory name. + */ +duk_ret_t method_dirname(duk_context* ctx) +{ + dukx_push_std_string(ctx, fs_util::dir_name(self(ctx)->path())); + + return 1; +} + +/* + * Method: File.lines() + * -------------------------------------------------------- + * + * Read all lines and return an array. + * + * duk_ret_turns: + * An array with all lines. + * Throws + * - Any exception on error. + */ +duk_ret_t method_lines(duk_context* ctx) +{ + duk_push_array(ctx); + + std::FILE* fp = self(ctx)->handle(); + std::string buffer; + std::array data; + std::int32_t i = 0; + + while (std::fgets(&data[0], data.size(), fp) != nullptr) { + buffer += data.data(); + + auto pos = buffer.find('\n'); + + if (pos != std::string::npos) { + dukx_push_std_string(ctx, clear_crlf(buffer.substr(0, pos))); + duk_put_prop_index(ctx, -2, i++); + + buffer.erase(0, pos + 1); + } + } + + // Maybe an error in the stream. + if (std::ferror(fp)) + dukx_throw(ctx, system_error()); + + // Missing '\n' in end of file. + if (!buffer.empty()) { + dukx_push_std_string(ctx, clear_crlf(buffer)); + duk_put_prop_index(ctx, -2, i++); + } + + return 1; +} + +/* + * Method: File.read(amount) + * -------------------------------------------------------- + * + * Read the specified amount of characters or the whole file. + * + * Arguments: + * - amount, the amount of characters or -1 to read all (Optional, default: -1). + * duk_ret_turns: + * The string. + * Throws: + * - Any exception on error. + */ +duk_ret_t method_read(duk_context* ctx) +{ + auto file = self(ctx); + auto amount = duk_is_number(ctx, 0) ? duk_get_int(ctx, 0) : -1; + + if (amount == 0 || file->handle() == nullptr) + return 0; + + try { + std::string data; + std::size_t total = 0; + + if (amount < 0) { + std::array buffer; + std::size_t nread; + + while ((nread = std::fread(&buffer[0], sizeof (buffer[0]), buffer.size(), file->handle())) > 0) { + if (std::ferror(file->handle())) + dukx_throw(ctx, system_error()); + + std::copy(buffer.begin(), buffer.begin() + nread, std::back_inserter(data)); + total += nread; + } + } else { + data.resize((std::size_t)amount); + total = std::fread(&data[0], sizeof (data[0]), (std::size_t)amount, file->handle()); + + if (std::ferror(file->handle())) + dukx_throw(ctx, system_error()); + + data.resize(total); + } + + dukx_push_std_string(ctx, data); + } catch (const std::exception&) { + dukx_throw(ctx, system_error()); + } + + return 1; +} + +/* + * Method: File.readline() + * -------------------------------------------------------- + * + * Read the next line available. + * + * duk_ret_turns: + * The next line or undefined if eof. + * Throws: + * - Any exception on error. + */ +duk_ret_t method_readline(duk_context* ctx) +{ + std::FILE* fp = self(ctx)->handle(); + std::string result; + + if (fp == nullptr || std::feof(fp)) + return 0; + for (int ch; (ch = std::fgetc(fp)) != EOF && ch != '\n'; ) + result += (char)ch; + if (std::ferror(fp)) + dukx_throw(ctx, system_error()); + + dukx_push_std_string(ctx, clear_crlf(result)); + + return 1; +} + +/* + * Method: File.remove() + * -------------------------------------------------------- + * + * Synonym of File.remove(path) but with the path from the file. + * + * Throws: + * - Any exception on error. + */ +duk_ret_t method_remove(duk_context* ctx) +{ + if (::remove(self(ctx)->path().c_str()) < 0) + dukx_throw(ctx, system_error()); + + return 0; +} + +/* + * Method: File.seek(type, amount) + * -------------------------------------------------------- + * + * Sets the position in the file. + * + * Arguments: + * - type, the type of setting (File.SeekSet, File.SeekCur, File.SeekSet), + * - amount, the new offset. + * Throws: + * - Any exception on error. + */ +duk_ret_t method_seek(duk_context* ctx) +{ + auto fp = self(ctx)->handle(); + auto type = duk_require_int(ctx, 0); + auto amount = duk_require_int(ctx, 1); + + if (fp != nullptr && std::fseek(fp, amount, type) != 0) + dukx_throw(ctx, system_error()); + + return 0; +} + +#if defined(HAVE_STAT) + +/* + * Method: File.stat() [optional] + * -------------------------------------------------------- + * + * Synonym of File.stat(path) but with the path from the file. + * + * duk_ret_turns: + * The stat information. + * Throws: + * - Any exception on error. + */ +duk_ret_t method_stat(duk_context* ctx) +{ + auto file = self(ctx); + struct stat st; + + if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0) + dukx_throw(ctx, system_error()); + else + push_stat(ctx, st); + + return 1; +} + +#endif // !HAVE_STAT + +/* + * Method: File.tell() + * -------------------------------------------------------- + * + * Get the actual position in the file. + * + * duk_ret_turns: + * The position. + * Throws: + * - Any exception on error. + */ +duk_ret_t method_tell(duk_context* ctx) +{ + auto fp = self(ctx)->handle(); + long pos; + + if (fp == nullptr) + return 0; + + if ((pos = std::ftell(fp)) == -1L) + dukx_throw(ctx, system_error()); + else + duk_push_int(ctx, pos); + + return 1; +} + +/* + * Method: File.write(data) + * -------------------------------------------------------- + * + * Write some characters to the file. + * + * Arguments: + * - data, the character to write. + * duk_ret_turns: + * The number of bytes written. + * Throws: + * - Any exception on error. + */ +duk_ret_t method_write(duk_context* ctx) +{ + std::FILE* fp = self(ctx)->handle(); + std::string data = duk_require_string(ctx, 0); + + if (fp == nullptr) + return 0; + + auto nwritten = std::fwrite(data.c_str(), 1, data.length(), fp); + + if (std::ferror(fp)) + dukx_throw(ctx, system_error()); + + duk_push_uint(ctx, nwritten); + + return 1; +} + +const duk_function_list_entry methods[] = { + { "basename", method_basename, 0 }, + { "close", method_close, 0 }, + { "dirname", method_dirname, 0 }, + { "lines", method_lines, 0 }, + { "read", method_read, 1 }, + { "readline", method_readline, 0 }, + { "remove", method_remove, 0 }, + { "seek", method_seek, 2 }, +#if defined(HAVE_STAT) + { "stat", method_stat, 0 }, +#endif + { "tell", method_tell, 0 }, + { "write", method_write, 1 }, + { nullptr, nullptr, 0 } +}; + +/* + * File "static" functions + * ------------------------------------------------------------------ + */ + +/* + * Function: Irccd.File(path, mode) [constructor] + * -------------------------------------------------------- + * + * Open a file specified by path with the specified mode. + * + * Arguments: + * - path, the path to the file, + * - mode, the mode string. + * Throws: + * - Any exception on error. + */ +duk_ret_t constructor(duk_context* ctx) +{ + if (!duk_is_constructor_call(ctx)) + return 0; + + try { + dukx_new_file(ctx, new file(duk_require_string(ctx, 0), duk_require_string(ctx, 1))); + } catch (const std::exception &) { + dukx_throw(ctx, system_error()); + } + + return 0; +} + +/* + * Function: Irccd.File() [destructor] + * ------------------------------------------------------------------ + * + * Delete the property. + */ +duk_ret_t destructor(duk_context* ctx) +{ + duk_get_prop_string(ctx, 0, signature); + delete static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, signature); + + return 0; +} + +/* + * Function: Irccd.File.basename(path) + * -------------------------------------------------------- + * + * duk_ret_turn the file basename as specified in `basename(3)` C function. + * + * Arguments: + * - path, the path to the file. + * duk_ret_turns: + * The base name. + */ +duk_ret_t function_basename(duk_context* ctx) +{ + dukx_push_std_string(ctx, fs_util::base_name(duk_require_string(ctx, 0))); + + return 1; +} + +/* + * Function: Irccd.File.dirname(path) + * -------------------------------------------------------- + * + * duk_ret_turn the file directory name as specified in `dirname(3)` C function. + * + * Arguments: + * - path, the path to the file. + * duk_ret_turns: + * The directory name. + */ +duk_ret_t function_dirname(duk_context* ctx) +{ + dukx_push_std_string(ctx, fs_util::dir_name(duk_require_string(ctx, 0))); + + return 1; +} + +/* + * Function: Irccd.File.exists(path) + * -------------------------------------------------------- + * + * Check if the file exists. + * + * Arguments: + * - path, the path to the file. + * duk_ret_turns: + * True if exists. + * Throws: + * - Any exception if we don't have access. + */ +duk_ret_t function_exists(duk_context* ctx) +{ + try { + duk_push_boolean(ctx, boost::filesystem::exists(duk_require_string(ctx, 0))); + } catch (...) { + duk_push_boolean(ctx, false); + } + + return 1; +} + +/* + * function Irccd.File.remove(path) + * -------------------------------------------------------- + * + * Remove the file at the specified path. + * + * Arguments: + * - path, the path to the file. + * Throws: + * - Any exception on error. + */ +duk_ret_t function_remove(duk_context* ctx) +{ + if (::remove(duk_require_string(ctx, 0)) < 0) + dukx_throw(ctx, system_error()); + + return 0; +} + +#if defined(HAVE_STAT) + +/* + * function Irccd.File.stat(path) [optional] + * -------------------------------------------------------- + * + * Get file information at the specified path. + * + * Arguments: + * - path, the path to the file. + * duk_ret_turns: + * The stat information. + * Throws: + * - Any exception on error. + */ +duk_ret_t function_stat(duk_context* ctx) +{ + struct stat st; + + if (::stat(duk_require_string(ctx, 0), &st) < 0) + dukx_throw(ctx, system_error()); + + push_stat(ctx, st); + + return 1; +} + +#endif // !HAVE_STAT + +const duk_function_list_entry functions[] = { + { "basename", function_basename, 1 }, + { "dirname", function_dirname, 1 }, + { "exists", function_exists, 1 }, + { "remove", function_remove, 1 }, +#if defined(HAVE_STAT) + { "stat", function_stat, 1 }, +#endif + { nullptr, nullptr, 0 } +}; + +const duk_number_list_entry constants[] = { + { "SeekCur", SEEK_CUR }, + { "SeekEnd", SEEK_END }, + { "SeekSet", SEEK_SET }, + { nullptr, 0 } +}; + +} // !namespace + +std::string file_jsapi::name() const +{ + return "Irccd.File"; +} + +void file_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_c_function(plugin->context(), constructor, 2); + duk_put_number_list(plugin->context(), -1, constants); + duk_put_function_list(plugin->context(), -1, functions); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, methods); + duk_push_c_function(plugin->context(), destructor, 1); + duk_set_finalizer(plugin->context(), -2); + duk_dup(plugin->context(), -1); + duk_put_global_string(plugin->context(), prototype); + duk_put_prop_string(plugin->context(), -2, "prototype"); + duk_put_prop_string(plugin->context(), -2, "File"); + duk_pop(plugin->context()); +} + +void dukx_new_file(duk_context* ctx, file* fp) +{ + assert(ctx); + assert(fp); + + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_push_pointer(ctx, fp); + duk_put_prop_string(ctx, -2, signature); + duk_pop(ctx); +} + +void dukx_push_file(duk_context* ctx, file* fp) +{ + assert(ctx); + assert(fp); + + StackAssert sa(ctx, 1); + + duk_push_object(ctx); + duk_push_pointer(ctx, fp); + duk_put_prop_string(ctx, -2, signature); + duk_get_global_string(ctx, prototype); + duk_set_prototype(ctx, -2); +} + +file* dukx_require_file(duk_context* ctx, duk_idx_t index) +{ + if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, signature)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); + + duk_get_prop_string(ctx, index, signature); + auto fp = static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return fp; +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/file_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/file_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,183 @@ +/* + * file_jsapi.hpp -- Irccd.File API + * + * 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_JS_FILE_JSAPI_HPP +#define IRCCD_JS_FILE_JSAPI_HPP + +/** + * \file file_jsapi.hpp + * \brief Irccd.File Javascript API. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Object for Javascript to perform I/O. + * + * This class can be constructed to Javascript. + * + * It is used in: + * + * - Irccd.File [constructor] + * - Irccd.System.popen (optional) + */ +class file { +private: + file(const file&) = delete; + file& operator=(const file&) = delete; + + file(file&&) = delete; + file& operator=(file&&) = delete; + +private: + std::string path_; + std::FILE* stream_; + std::function destructor_; + +public: + /** + * Construct a file specified by path + * + * \param path the path + * \param mode the mode string (for std::fopen) + * \throw std::runtime_error on failures + */ + inline file(std::string path, const std::string& mode) + : path_(std::move(path)) + , destructor_([] (std::FILE* fp) { std::fclose(fp); }) + { + if ((stream_ = std::fopen(path_.c_str(), mode.c_str())) == nullptr) + throw std::runtime_error(std::strerror(errno)); + } + + /** + * Construct a file from a already created FILE pointer (e.g. popen). + * + * The class takes ownership of fp and will close it. + * + * \pre destructor must not be null + * \param fp the file pointer + * \param destructor the function to close fp (e.g. std::fclose) + */ + inline file(std::FILE* fp, std::function destructor) noexcept + : stream_(fp) + , destructor_(std::move(destructor)) + { + assert(destructor_ != nullptr); + } + + /** + * Closes the file. + */ + virtual ~file() noexcept + { + close(); + } + + /** + * Get the path. + * + * \return the path + * \warning empty when constructed from the FILE constructor + */ + inline const std::string& path() const noexcept + { + return path_; + } + + /** + * Get the handle. + * + * \return the handle or nullptr if the stream was closed + */ + inline std::FILE* handle() noexcept + { + return stream_; + } + + /** + * Force close, can be safely called multiple times. + */ + inline void close() noexcept + { + if (stream_) { + destructor_(stream_); + stream_ = nullptr; + } + } +}; + +/** + * \brief Irccd.File Javascript API. + * \ingroup jsapi + */ +class file_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +/** + * Construct the file as this. + * + * The object prototype takes ownership of fp and will be deleted once + * collected. + * + * \pre fp != nullptr + * \param ctx the the context + * \param fp the file + */ +void dukx_new_file(duk_context* ctx, file* fp); + +/** + * Push a file. + * + * \pre fp != nullptr + * \param ctx the the context + * \param fp the file + */ +void dukx_push_file(duk_context* ctx, file* fp); + +/** + * Require a file. Raises a JavaScript error if not a File. + * + * \param ctx the context + * \param index the index + */ +file* dukx_require_file(duk_context* ctx, duk_idx_t index); + +} // !irccd + +#endif // !IRCCD_JS_FILE_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/irccd_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/irccd_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,232 @@ +/* + * irccd_jsapi.cpp -- Irccd API + * + * 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 + +#include +#include +#include + +#include "irccd_jsapi.hpp" +#include "js_plugin.hpp" + +namespace irccd { + +namespace { + +const std::unordered_map errors{ + { "E2BIG", E2BIG }, + { "EACCES", EACCES }, + { "EADDRINUSE", EADDRINUSE }, + { "EADDRNOTAVAIL", EADDRNOTAVAIL }, + { "EAFNOSUPPORT", EAFNOSUPPORT }, + { "EAGAIN", EAGAIN }, + { "EALREADY", EALREADY }, + { "EBADF", EBADF }, +#if defined(EBADMSG) + { "EBADMSG", EBADMSG }, +#endif + { "EBUSY", EBUSY }, + { "ECANCELED", ECANCELED }, + { "ECHILD", ECHILD }, + { "ECONNABORTED", ECONNABORTED }, + { "ECONNREFUSED", ECONNREFUSED }, + { "ECONNRESET", ECONNRESET }, + { "EDEADLK", EDEADLK }, + { "EDESTADDRREQ", EDESTADDRREQ }, + { "EDOM", EDOM }, + { "EEXIST", EEXIST }, + { "EFAULT", EFAULT }, + { "EFBIG", EFBIG }, + { "EHOSTUNREACH", EHOSTUNREACH }, +#if defined(EIDRM) + { "EIDRM", EIDRM }, +#endif + { "EILSEQ", EILSEQ }, + { "EINPROGRESS", EINPROGRESS }, + { "EINTR", EINTR }, + { "EINVAL", EINVAL }, + { "EIO", EIO }, + { "EISCONN", EISCONN }, + { "EISDIR", EISDIR }, + { "ELOOP", ELOOP }, + { "EMFILE", EMFILE }, + { "EMLINK", EMLINK }, + { "EMSGSIZE", EMSGSIZE }, + { "ENAMETOOLONG", ENAMETOOLONG }, + { "ENETDOWN", ENETDOWN }, + { "ENETRESET", ENETRESET }, + { "ENETUNREACH", ENETUNREACH }, + { "ENFILE", ENFILE }, + { "ENOBUFS", ENOBUFS }, +#if defined(ENODATA) + { "ENODATA", ENODATA }, +#endif + { "ENODEV", ENODEV }, + { "ENOENT", ENOENT }, + { "ENOEXEC", ENOEXEC }, + { "ENOLCK", ENOLCK }, +#if defined(ENOLINK) + { "ENOLINK", ENOLINK }, +#endif + { "ENOMEM", ENOMEM }, +#if defined(ENOMSG) + { "ENOMSG", ENOMSG }, +#endif + { "ENOPROTOOPT", ENOPROTOOPT }, + { "ENOSPC", ENOSPC }, +#if defined(ENOSR) + { "ENOSR", ENOSR }, +#endif +#if defined(ENOSTR) + { "ENOSTR", ENOSTR }, +#endif + { "ENOSYS", ENOSYS }, + { "ENOTCONN", ENOTCONN }, + { "ENOTDIR", ENOTDIR }, + { "ENOTEMPTY", ENOTEMPTY }, +#if defined(ENOTRECOVERABLE) + { "ENOTRECOVERABLE", ENOTRECOVERABLE }, +#endif + { "ENOTSOCK", ENOTSOCK }, + { "ENOTSUP", ENOTSUP }, + { "ENOTTY", ENOTTY }, + { "ENXIO", ENXIO }, + { "EOPNOTSUPP", EOPNOTSUPP }, + { "EOVERFLOW", EOVERFLOW }, + { "EOWNERDEAD", EOWNERDEAD }, + { "EPERM", EPERM }, + { "EPIPE", EPIPE }, + { "EPROTO", EPROTO }, + { "EPROTONOSUPPORT", EPROTONOSUPPORT }, + { "EPROTOTYPE", EPROTOTYPE }, + { "ERANGE", ERANGE }, + { "EROFS", EROFS }, + { "ESPIPE", ESPIPE }, + { "ESRCH", ESRCH }, +#if defined(ETIME) + { "ETIME", ETIME }, +#endif + { "ETIMEDOUT", ETIMEDOUT }, +#if defined(ETXTBSY) + { "ETXTBSY", ETXTBSY }, +#endif + { "EWOULDBLOCK", EWOULDBLOCK }, + { "EXDEV", EXDEV } +}; + +duk_ret_t constructor(duk_context* ctx) +{ + duk_push_this(ctx); + duk_push_int(ctx, duk_require_int(ctx, 0)); + duk_put_prop_string(ctx, -2, "errno"); + duk_push_string(ctx, duk_require_string(ctx, 1)); + duk_put_prop_string(ctx, -2, "message"); + duk_push_string(ctx, "SystemError"); + duk_put_prop_string(ctx, -2, "name"); + duk_pop(ctx); + + return 0; +} + +} // !namespace + +system_error::system_error() + : errno_(errno) + , message_(std::strerror(errno_)) +{ +} + +system_error::system_error(int e, std::string message) + : errno_(e) + , message_(std::move(message)) +{ +} + +void system_error::raise(duk_context *ctx) const +{ + StackAssert sa(ctx, 0); + + duk_get_global_string(ctx, "Irccd"); + duk_get_prop_string(ctx, -1, "SystemError"); + duk_remove(ctx, -2); + duk_push_int(ctx, errno_); + dukx_push_std_string(ctx, message_); + duk_new(ctx, 2); + duk_throw(ctx); +} + +std::string irccd_jsapi::name() const +{ + return "Irccd"; +} + +void irccd_jsapi::load(irccd& irccd, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + // irccd. + duk_push_object(plugin->context()); + + // Version. + duk_push_object(plugin->context()); + duk_push_int(plugin->context(), IRCCD_VERSION_MAJOR); + duk_put_prop_string(plugin->context(), -2, "major"); + duk_push_int(plugin->context(), IRCCD_VERSION_MINOR); + duk_put_prop_string(plugin->context(), -2, "minor"); + duk_push_int(plugin->context(), IRCCD_VERSION_PATCH); + duk_put_prop_string(plugin->context(), -2, "patch"); + duk_put_prop_string(plugin->context(), -2, "version"); + + // Create the system_error that inherits from Error. + duk_push_c_function(plugin->context(), constructor, 2); + + // Put errno codes into the irccd.system_error object. + for (const auto& pair : errors) { + duk_push_int(plugin->context(), pair.second); + duk_put_prop_string(plugin->context(), -2, pair.first.c_str()); + } + + duk_push_object(plugin->context()); + duk_get_global_string(plugin->context(), "Error"); + duk_get_prop_string(plugin->context(), -1, "prototype"); + duk_remove(plugin->context(), -2); + duk_set_prototype(plugin->context(), -2); + duk_put_prop_string(plugin->context(), -2, "prototype"); + duk_put_prop_string(plugin->context(), -2, "SystemError"); + + // Set irccd as global. + duk_put_global_string(plugin->context(), "Irccd"); + + // Store global instance. + duk_push_pointer(plugin->context(), &irccd); + duk_put_global_string(plugin->context(), "\xff""\xff""irccd-ref"); +} + +irccd& dukx_get_irccd(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_get_global_string(ctx, "\xff""\xff""irccd-ref"); + auto ptr = static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return *ptr; +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/irccd_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/irccd_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,92 @@ +/* + * irccd_jsapi.hpp -- Irccd API + * + * 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_JS_IRCCD_JSAPI_HPP +#define IRCCD_JS_IRCCD_JSAPI_HPP + +/** + * \file irccd_jsapi.hpp + * \brief irccd Javascript API. + */ + +#include +#include +#include + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Custom Javascript exception for system error. + */ +class system_error { +private: + int errno_; + std::string message_; + +public: + /** + * Create a system error from the current errno value. + */ + system_error(); + + /** + * Create a system error with the given errno and message. + * + * \param e the errno number + * \param message the message + */ + system_error(int e, std::string message); + + /** + * Raise the SystemError Javascript exception. + * + * \param ctx the context + */ + void raise(duk_context* ctx) const; +}; + +/** + * \brief Irccd Javascript API. + * \ingroup jsapi + */ +class irccd_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +/** + * Get irccd instance stored in this context. + * + * \param ctx the context + * \return the irccd reference + */ +irccd& dukx_get_irccd(duk_context* ctx); + +} // !irccd + +#endif // !IRCCD_JS_IRCCD_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/js_plugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/js_plugin.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,397 @@ +/* + * plugin-js.cpp -- Javascript plugins for irccd + * + * 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 +#include +#include +#include +#include + +#include "irccd.hpp" +#include "logger.hpp" +//#include "plugin_module.hpp" +//#include "server_module.hpp" +#include "js_plugin.hpp" +#include "service.hpp" +#include "server_jsapi.hpp" +//#include "timer.hpp" + +namespace irccd { + +const std::string js_plugin::config_property{"\xff""\xff""irccd-plugin-config"}; +const std::string js_plugin::format_property{"\xff""\xff""irccd-plugin-format"}; +const std::string js_plugin::paths_property{"\xff""\xff""irccd-plugin-paths"}; + +std::unordered_map js_plugin::get_table(const std::string& name) const +{ + StackAssert sa(context_); + std::unordered_map result; + + duk_get_global_string(context_, name.c_str()); + dukx_enumerate(context_, -1, 0, true, [&] (auto ctx) { + result.emplace(duk_to_string(ctx, -2), duk_to_string(ctx, -1)); + }); + duk_pop(context_); + + return result; +} + +void js_plugin::put_table(const std::string& name, const std::unordered_map& vars) +{ + StackAssert sa(context_); + + duk_get_global_string(context_, name.c_str()); + + for (const auto &pair : vars) { + dukx_push_std_string(context_, pair.second); + duk_put_prop_string(context_, -2, pair.first.c_str()); + } + + duk_pop(context_); +} + +void js_plugin::call(const std::string& name, unsigned nargs) +{ + duk_get_global_string(context_, name.c_str()); + + if (duk_get_type(context_, -1) == DUK_TYPE_UNDEFINED) + // Function not defined, remove the undefined value and all arguments. + duk_pop_n(context_, nargs + 1); + else { + // Call the function and discard the result. + duk_insert(context_, -nargs - 1); + + if (duk_pcall(context_, nargs) != 0) + throw dukx_exception(context_, -1, true); + + duk_pop(context_); + } +} + +js_plugin::js_plugin(std::string name, std::string path) + : plugin(name, path) +{ + StackAssert sa(context_); + + /* + * Create two special tables for configuration and formats, they are + * referenced later as + * + * - Irccd.Plugin.config + * - Irccd.Plugin.format + * - Irccd.Plugin.paths + * + * In js_plugin_module.cpp. + */ + duk_push_object(context_); + duk_put_global_string(context_, config_property.c_str()); + duk_push_object(context_); + duk_put_global_string(context_, format_property.c_str()); + duk_push_object(context_); + duk_put_global_string(context_, paths_property.c_str()); + + duk_push_pointer(context_, this); + duk_put_global_string(context_, "\xff""\xff""plugin"); + dukx_push_std_string(context_, name); + duk_put_global_string(context_, "\xff""\xff""name"); + dukx_push_std_string(context_, path); + duk_put_global_string(context_, "\xff""\xff""path"); +} + +void js_plugin::open() +{ + std::ifstream input(path()); + + if (!input) + throw std::runtime_error(std::strerror(errno)); + + std::string data( + std::istreambuf_iterator(input.rdbuf()), + std::istreambuf_iterator() + ); + + if (duk_peval_string(context_, data.c_str())) + throw dukx_exception(context_, -1); + + // Read metadata. + duk_get_global_string(context_, "info"); + + if (duk_get_type(context_, -1) == DUK_TYPE_OBJECT) { + duk_get_prop_string(context_, -1, "author"); + set_author(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : author()); + duk_get_prop_string(context_, -2, "license"); + set_license(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : license()); + duk_get_prop_string(context_, -3, "summary"); + set_summary(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : summary()); + duk_get_prop_string(context_, -4, "version"); + set_version(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : version()); + duk_pop_n(context_, 4); + } + + duk_pop(context_); +} + +void js_plugin::on_channel_mode(irccd& , const channel_mode_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.mode); + dukx_push_std_string(context_, event.argument); + call("onChannelMode", 5); +} + +void js_plugin::on_channel_notice(irccd& , const channel_notice_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.message); + call("onChannelNotice", 4); +} + +void js_plugin::on_command(irccd& , const message_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.message); + call("onCommand", 4); +} + +void js_plugin::on_connect(irccd& , const connect_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + call("onConnect", 1); +} + +void js_plugin::on_invite(irccd& , const invite_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + call("onInvite", 3); +} + +void js_plugin::on_join(irccd& , const join_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + call("onJoin", 3); +} + +void js_plugin::on_kick(irccd& , const kick_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.target); + dukx_push_std_string(context_, event.reason); + call("onKick", 5); +} + +void js_plugin::on_load(irccd&) +{ + StackAssert sa(context_); + + call("onLoad", 0); +} + +void js_plugin::on_message(irccd& , const message_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.message); + call("onMessage", 4); +} + +void js_plugin::on_me(irccd& , const me_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.message); + call("onMe", 4); +} + +void js_plugin::on_mode(irccd& , const mode_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.mode); + call("onMode", 3); +} + +void js_plugin::on_names(irccd& , const names_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.channel); + dukx_push_array(context_, event.names, dukx_push_std_string); + call("onNames", 3); +} + +void js_plugin::on_nick(irccd& , const nick_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.nickname); + call("onNick", 3); +} + +void js_plugin::on_notice(irccd& , const notice_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.message); + call("onNotice", 3); +} + +void js_plugin::on_part(irccd& , const part_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.reason); + call("onPart", 4); +} + +void js_plugin::on_query(irccd& , const query_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.message); + call("onQuery", 3); +} + +void js_plugin::on_query_command(irccd& , const query_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.message); + call("onQueryCommand", 3); +} + +void js_plugin::on_reload(irccd& ) +{ + StackAssert sa(context_); + + call("onReload"); +} + +void js_plugin::on_topic(irccd& , const topic_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + dukx_push_std_string(context_, event.origin); + dukx_push_std_string(context_, event.channel); + dukx_push_std_string(context_, event.topic); + call("onTopic", 4); +} + +void js_plugin::on_unload(irccd& ) +{ + StackAssert sa(context_); + + call("onUnload"); +} + +void js_plugin::on_whois(irccd& , const whois_event &event) +{ + StackAssert sa(context_); + + dukx_push_server(context_, std::move(event.server)); + duk_push_object(context_); + dukx_push_std_string(context_, event.whois.nick); + duk_put_prop_string(context_, -2, "nickname"); + dukx_push_std_string(context_, event.whois.user); + duk_put_prop_string(context_, -2, "username"); + dukx_push_std_string(context_, event.whois.realname); + duk_put_prop_string(context_, -2, "realname"); + dukx_push_std_string(context_, event.whois.host); + duk_put_prop_string(context_, -2, "host"); + dukx_push_array(context_, event.whois.channels, dukx_push_std_string); + duk_put_prop_string(context_, -2, "channels"); + call("onWhois", 2); +} + +js_plugin_loader::js_plugin_loader(irccd& irccd) noexcept + : plugin_loader({}, { ".js" }) + , irccd_(irccd) +{ +} + +js_plugin_loader::~js_plugin_loader() noexcept = default; + +std::shared_ptr js_plugin_loader::open(const std::string& id, + const std::string& path) noexcept +{ + if (path.rfind(".js") == std::string::npos) + return nullptr; + + try { + auto plugin = std::make_shared(id, path); + + for (const auto& mod : modules_) + mod->load(irccd_, plugin); + + plugin->open(); + + return plugin; + } catch (const std::exception &ex) { + log::warning() << "plugin " << id << ": " << ex.what() << std::endl; + } + + return nullptr; +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/js_plugin.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/js_plugin.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,297 @@ +/* + * js_plugin.hpp -- JavaScript plugins for irccd + * + * 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_JS_PLUGIN_HPP +#define IRCCD_JS_PLUGIN_HPP + +/** + * \file js_plugin.hpp + * \brief JavaScript plugins for irccd. + */ + +#include + +#include "duktape.hpp" +#include "plugin.hpp" + +namespace irccd { + +class jsapi; + +/** + * \brief JavaScript plugins for irccd. + * \ingroup plugins + */ +class js_plugin : public plugin { +public: + /** + * Global property where to read/write plugin configuration (object). + */ + static const std::string config_property; + + /** + * Global property where to read/write plugin formats (object). + */ + static const std::string format_property; + + /** + * Global property where paths are defined (object). + */ + static const std::string paths_property; + +private: + // JavaScript context + UniqueContext context_; + + // Private helpers. + std::unordered_map get_table(const std::string&) const; + void put_table(const std::string&, const std::unordered_map&); + void call(const std::string&, unsigned = 0); + +public: + /** + * Constructor. + * + * \param name the plugin name + * \param path the path to the plugin + */ + js_plugin(std::string name, std::string path); + + /** + * Access the Duktape context. + * + * \return the context + */ + inline UniqueContext& context() noexcept + { + return context_; + } + + /** + * Open the script file associated. + */ + void open(); + + /** + * \copydoc Plugin::config + */ + plugin_config config() override + { + return get_table(config_property); + } + + /** + * \copydoc Plugin::setConfig + */ + void set_config(plugin_config config) override + { + put_table(config_property, config); + } + + /** + * \copydoc Plugin::formats + */ + plugin_formats formats() override + { + return get_table(format_property); + } + + /** + * \copydoc Plugin::setFormats + */ + void set_formats(plugin_formats formats) override + { + put_table(format_property, formats); + } + + /** + * \copydoc Plugin::paths + */ + plugin_paths paths() override + { + return get_table(paths_property); + } + + /** + * \copydoc Plugin::set_paths + */ + void set_paths(plugin_paths paths) override + { + put_table(paths_property, std::move(paths)); + } + + /** + * \copydoc Plugin::on_command + */ + void on_command(irccd& irccd, const message_event& event) override; + + /** + * \copydoc Plugin::on_connect + */ + void on_connect(irccd& irccd, const connect_event& event) override; + + /** + * \copydoc Plugin::on_channel_mode + */ + void on_channel_mode(irccd& irccd, const channel_mode_event& event) override; + + /** + * \copydoc Plugin::on_channel_notice + */ + void on_channel_notice(irccd& irccd, const channel_notice_event& event) override; + + /** + * \copydoc Plugin::on_invite + */ + void on_invite(irccd& irccd, const invite_event& event) override; + + /** + * \copydoc Plugin::on_join + */ + void on_join(irccd& irccd, const join_event& event) override; + + /** + * \copydoc Plugin::on_kick + */ + void on_kick(irccd& irccd, const kick_event& event) override; + + /** + * \copydoc Plugin::on_load + */ + void on_load(irccd& irccd) override; + + /** + * \copydoc Plugin::on_message + */ + void on_message(irccd& irccd, const message_event& event) override; + + /** + * \copydoc Plugin::on_me + */ + void on_me(irccd& irccd, const me_event& event) override; + + /** + * \copydoc Plugin::on_mode + */ + void on_mode(irccd& irccd, const mode_event& event) override; + + /** + * \copydoc Plugin::on_names + */ + void on_names(irccd& irccd, const names_event& event) override; + + /** + * \copydoc Plugin::on_nick + */ + void on_nick(irccd& irccd, const nick_event& event) override; + + /** + * \copydoc Plugin::on_notice + */ + void on_notice(irccd& irccd, const notice_event& event) override; + + /** + * \copydoc Plugin::on_part + */ + void on_part(irccd& irccd, const part_event& event) override; + + /** + * \copydoc Plugin::on_query + */ + void on_query(irccd& irccd, const query_event& event) override; + + /** + * \copydoc Plugin::on_query_command + */ + void on_query_command(irccd& irccd, const query_event& event) override; + + /** + * \copydoc Plugin::on_reload + */ + void on_reload(irccd& irccd) override; + + /** + * \copydoc Plugin::on_topic + */ + void on_topic(irccd& irccd, const topic_event& event) override; + + /** + * \copydoc Plugin::on_unload + */ + void on_unload(irccd& irccd) override; + + /** + * \copydoc Plugin::on_whois + */ + void on_whois(irccd& irccd, const whois_event& event) override; +}; + +/** + * \brief Implementation for searching Javascript plugins. + */ +class js_plugin_loader : public plugin_loader { +public: + using modules_t = std::vector>; + +private: + irccd& irccd_; + modules_t modules_; + +public: + /** + * Constructor. + * + * \param irccd the irccd instance + */ + js_plugin_loader(irccd& irccd) noexcept; + + /** + * Destructor defaulted. + */ + ~js_plugin_loader() noexcept; + + /** + * Get the list of modules. + * + * \return the modules + */ + inline const modules_t& modules() const noexcept + { + return modules_; + } + + /** + * Overloaded function. + * + * \return the modules + */ + inline modules_t& modules() noexcept + { + return modules_; + } + + /** + * \copydoc PluginLoader::open + */ + std::shared_ptr open(const std::string& id, + const std::string& path) noexcept override; +}; + +} // !irccd + +#endif // !IRCCD_PLUGIN_JS_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,75 @@ +/* + * jsapi.hpp -- Javascript API module + * + * 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_JS_JSAPI_HPP +#define IRCCD_JS_JSAPI_HPP + +/** + * \file jsapi.hpp + * \brief Javascript API module. + */ + +/** + * \defgroup Javascript modules. + * \brief Modules for the Javascript API. + */ + +#include +#include + +#include "duktape.hpp" + +namespace irccd { + +class irccd; +class js_plugin; + +/** + * \brief Javascript API module. + */ +class jsapi { +public: + /** + * Default constructor. + */ + jsapi() noexcept = default; + + /** + * Virtual destructor defaulted. + */ + virtual ~jsapi() noexcept = default; + + /** + * Get the module name. + * + * \return the name + */ + virtual std::string name() const = 0; + + /** + * Load the module into the Javascript plugin. + * + * \param irccd the irccd instance + * \param plugin the plugin + */ + virtual void load(irccd& irccd, std::shared_ptr plugin) = 0; +}; + +} // !irccd + +#endif // !IRCCD_JS_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/logger_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/logger_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,103 @@ +/* + * logger_jsapi.cpp -- Irccd.Logger API + * + * 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 + +#include "js_plugin.hpp" +#include "logger_jsapi.hpp" +#include "plugin_jsapi.hpp" + +namespace irccd { + +namespace { + +duk_ret_t print(duk_context* ctx, std::ostream &out) +{ + out << "plugin " << dukx_get_plugin(ctx)->name() << ": " << duk_require_string(ctx, 0) << std::endl; + + return 0; +} + +/* + * Function: Irccd.Logger.info(message) + * -------------------------------------------------------- + * + * Write a verbose message. + * + * Arguments: + * - message, the message. + */ +duk_ret_t info(duk_context* ctx) +{ + return print(ctx, log::info()); +} + +/* + * Function: irccd.Logger.warning(message) + * -------------------------------------------------------- + * + * Write a warning message. + * + * Arguments: + * - message, the warning. + */ +duk_ret_t warning(duk_context* ctx) +{ + return print(ctx, log::warning()); +} + +/* + * Function: Logger.debug(message) + * -------------------------------------------------------- + * + * Write a debug message, only shown if irccd is compiled in debug. + * + * Arguments: + * - message, the message. + */ +duk_ret_t debug(duk_context* ctx) +{ + return print(ctx, log::debug()); +} + +const duk_function_list_entry functions[] = { + { "info", info, 1 }, + { "warning", warning, 1 }, + { "debug", debug, 1 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +std::string logger_jsapi::name() const +{ + return "Irccd.Logger"; +} + +void logger_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, functions); + duk_put_prop_string(plugin->context(), -2, "Logger"); + duk_pop(plugin->context()); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/logger_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/logger_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,50 @@ +/* + * logger_jsapi.hpp -- Irccd.Logger API + * + * 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_JS_LOGGER_JSAPI_HPP +#define IRCCD_JS_LOGGER_JSAPI_HPP + +/** + * \file logger_jsapi.hpp + * \brief Irccd.Logger Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief irccd.Logger Javascript API. + * \ingroup jsapi + */ +class logger_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc Module::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +} // !irccd + +#endif // !IRCCD_JS_LOGGER_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/plugin_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/plugin_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,385 @@ +/* + * plugin_jsapi.cpp -- Irccd.Plugin API + * + * 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 +#include + +#include "irccd_jsapi.hpp" +#include "js_plugin.hpp" +#include "plugin_jsapi.hpp" + +namespace irccd { + +namespace { + +const char plugin_ref[] = "\xff""\xff""irccd-plugin-ptr"; + +/* + * wrap + * ------------------------------------------------------------------ + * + * Wrap function for these functions because they all takes the same arguments. + * + * - load, + * - reload, + * - unload. + */ +template +duk_idx_t wrap(duk_context* ctx, int nret, Func&& func) +{ + std::string name = duk_require_string(ctx, 0); + + try { + func(dukx_get_irccd(ctx), name); + } catch (const std::out_of_range &ex) { + dukx_throw(ctx, ReferenceError(ex.what())); + } catch (const std::exception &ex) { + dukx_throw(ctx, Error(ex.what())); + } + + return nret; +} + +/* + * set + * ------------------------------------------------------------------ + * + * This setter is used to replace the Irccd.Plugin.(config|format|paths) + * property when the plugin assign a new one. + * + * Because the plugin configuration always has higher priority, when a new + * object is assigned to 'config' or to the 'format' property, the plugin + * configuration is merged to the assigned one, adding or replacing any values. + * + * Example: + * + * Plugin 'xyz' does: + * + * Irccd.Plugin.config = { + * mode: "simple", + * level: "123" + * }; + * + * The user configuration is: + * + * [plugin.xyz] + * mode = "hard" + * path = "/var" + * + * The final user table looks like this: + * + * Irccd.Plugin.Config = { + * mode: "hard", + * level: "123", + * path: "/var" + * }; + */ +duk_ret_t set(duk_context* ctx, const std::string& name) +{ + if (!duk_is_object(ctx, 0)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name.c_str()); + + // Merge old table with new one. + duk_get_global_string(ctx, name.c_str()); + duk_enum(ctx, -1, 0); + + while (duk_next(ctx, -1, true)) + duk_put_prop(ctx, 0); + + // Pop enum and old table. + duk_pop_2(ctx); + + // Replace the old table with the new assigned one. + duk_put_global_string(ctx, name.c_str()); + + return 0; +} + +/* + * get + * ------------------------------------------------------------------ + * + * Get the Irccd.Plugin.(config|format|paths) property. + */ +duk_ret_t get(duk_context* ctx, const std::string& name) +{ + duk_get_global_string(ctx, name.c_str()); + + return 1; +} + +/* + * set_config + * ------------------------------------------------------------------ + * + * Wrap setter for Irccd.Plugin.config property. + */ +duk_ret_t set_config(duk_context* ctx) +{ + return set(ctx, js_plugin::config_property); +} + +/* + * get_config + * ------------------------------------------------------------------ + * + * Wrap getter for Irccd.Plugin.config property. + */ +duk_ret_t get_config(duk_context* ctx) +{ + return get(ctx, js_plugin::config_property); +} + +/* + * set_format + * ------------------------------------------------------------------ + * + * Wrap setter for Irccd.Plugin.format property. + */ +duk_ret_t set_format(duk_context* ctx) +{ + return set(ctx, js_plugin::format_property); +} + +/* + * get_format + * ------------------------------------------------------------------ + * + * Wrap getter for Irccd.Plugin.format property. + */ +duk_ret_t get_format(duk_context* ctx) +{ + return get(ctx, js_plugin::format_property); +} + +/* + * set_paths + * ------------------------------------------------------------------ + * + * Wrap setter for Irccd.Plugin.format property. + */ +duk_ret_t set_paths(duk_context* ctx) +{ + return set(ctx, js_plugin::paths_property); +} + +/* + * get_paths + * ------------------------------------------------------------------ + * + * Wrap getter for Irccd.Plugin.format property. + */ +duk_ret_t get_paths(duk_context* ctx) +{ + return get(ctx, js_plugin::paths_property); +} + +/* + * Function: Irccd.Plugin.info([name]) + * ------------------------------------------------------------------ + * + * Get information about a plugin. + * + * The returned object as the following properties: + * + * - name: (string) the plugin identifier, + * - author: (string) the author, + * - license: (string) the license, + * - summary: (string) a short description, + * - version: (string) the version + * + * Arguments: + * - name, the plugin identifier, if not specified the current plugin is + * selected. + * Returns: + * The plugin information or undefined if the plugin was not found. + */ +duk_idx_t info(duk_context* ctx) +{ + std::shared_ptr plugin; + + if (duk_get_top(ctx) >= 1) + plugin = dukx_get_irccd(ctx).plugins().get(duk_require_string(ctx, 0)); + else + plugin = dukx_get_plugin(ctx); + + if (!plugin) + return 0; + + duk_push_object(ctx); + dukx_push_std_string(ctx, plugin->name()); + duk_put_prop_string(ctx, -2, "name"); + dukx_push_std_string(ctx, plugin->author()); + duk_put_prop_string(ctx, -2, "author"); + dukx_push_std_string(ctx, plugin->license()); + duk_put_prop_string(ctx, -2, "license"); + dukx_push_std_string(ctx, plugin->summary()); + duk_put_prop_string(ctx, -2, "summary"); + dukx_push_std_string(ctx, plugin->version()); + duk_put_prop_string(ctx, -2, "version"); + + return 1; +} + +/* + * Function: Irccd.Plugin.list() + * ------------------------------------------------------------------ + * + * Get the list of plugins, the array returned contains all plugin names. + * + * Returns: + * The list of all plugin names. + */ +duk_idx_t list(duk_context* ctx) +{ + dukx_push_array(ctx, dukx_get_irccd(ctx).plugins().list(), [] (auto ctx, auto plugin) { + dukx_push_std_string(ctx, plugin->name()); + }); + + return 1; +} + +/* + * Function: Irccd.Plugin.load(name) + * ------------------------------------------------------------------ + * + * Load a plugin by name. This function will search through the standard + * directories. + * + * Arguments: + * - name, the plugin identifier. + * Throws: + * - Error on errors, + * - ReferenceError if the plugin was not found. + */ +duk_idx_t load(duk_context* ctx) +{ + return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) { + irccd.plugins().load(name); + }); +} + +/* + * Function: Irccd.Plugin.reload(name) + * ------------------------------------------------------------------ + * + * Reload a plugin by name. + * + * Arguments: + * - name, the plugin identifier. + * Throws: + * - Error on errors, + * - ReferenceError if the plugin was not found. + */ +duk_idx_t reload(duk_context* ctx) +{ + return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) { + irccd.plugins().reload(name); + }); +} + +/* + * Function: Irccd.Plugin.unload(name) + * ------------------------------------------------------------------ + * + * Unload a plugin by name. + * + * Arguments: + * - name, the plugin identifier. + * Throws: + * - Error on errors, + * - ReferenceError if the plugin was not found. + */ +duk_idx_t unload(duk_context* ctx) +{ + return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) { + irccd.plugins().unload(name); + }); +} + +const duk_function_list_entry functions[] = { + { "info", info, DUK_VARARGS }, + { "list", list, 0 }, + { "load", load, 1 }, + { "reload", reload, 1 }, + { "unload", unload, 1 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +std::string plugin_jsapi::name() const +{ + return "Irccd.Plugin"; +} + +void plugin_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_push_pointer(plugin->context(), new std::weak_ptr(plugin)); + duk_push_object(plugin->context()); + duk_push_c_function(plugin->context(), [] (auto ctx) -> duk_ret_t { + duk_get_global_string(ctx, plugin_ref); + delete static_cast*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_push_null(ctx); + duk_put_global_string(ctx, plugin_ref); + return 0; + }, 1); + duk_set_finalizer(plugin->context(), -2); + duk_put_global_string(plugin->context(), "\xff""\xff""dummy-shared-ptr"); + duk_put_global_string(plugin->context(), plugin_ref); + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, functions); + + // 'config' property. + duk_push_string(plugin->context(), "config"); + duk_push_c_function(plugin->context(), get_config, 0); + duk_push_c_function(plugin->context(), set_config, 1); + duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + + // 'format' property. + duk_push_string(plugin->context(), "format"); + duk_push_c_function(plugin->context(), get_format, 0); + duk_push_c_function(plugin->context(), set_format, 1); + duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + + // 'format' property. + duk_push_string(plugin->context(), "paths"); + duk_push_c_function(plugin->context(), get_paths, 0); + duk_push_c_function(plugin->context(), set_paths, 1); + duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + + duk_put_prop_string(plugin->context(), -2, "Plugin"); + duk_pop(plugin->context()); +} + +std::shared_ptr dukx_get_plugin(duk_context* ctx) +{ + StackAssert sa(ctx); + + duk_get_global_string(ctx, plugin_ref); + auto plugin = static_cast*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return plugin->lock(); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/plugin_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/plugin_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,58 @@ +/* + * plugin_jsapi.hpp -- Irccd.Plugin API + * + * 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_JS_PLUGIN_JSAPI_HPP +#define IRCCD_JS_PLUGIN_JSAPI_HPP + +/** + * \file plugin_jsapi.hpp + * \brief Irccd.Plugin Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Irccd.Plugin Javascript API. + * \ingroup jsapi + */ +class plugin_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc Module::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +/** + * Access the plugin stored in this context. + * + * \param ctx the context + * \return the plugin + */ +std::shared_ptr dukx_get_plugin(duk_context* ctx); + +} // !irccd + +#endif // !IRCCD_JS_PLUGIN_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/server_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/server_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,581 @@ +/* + * server_jsapi.cpp -- Irccd.Server API + * + * 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 +#include +#include + +#include +#include +#include + +#include "irccd_jsapi.hpp" +#include "js_plugin.hpp" +#include "server_jsapi.hpp" + +namespace irccd { + +namespace { + +const char *signature("\xff""\xff""irccd-server-ptr"); +const char *prototype("\xff""\xff""irccd-server-prototype"); + +std::shared_ptr self(duk_context* ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); + + return *static_cast*>(ptr); +} + +/* + * Method: Server.cmode(channel, mode) + * ------------------------------------------------------------------ + * + * Change a channel mode. + * + * Arguments: + * - channel, the channel, + * - mode, the mode. + */ +duk_ret_t cmode(duk_context* ctx) +{ + self(ctx)->cmode(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.cnotice(channel, message) + * ------------------------------------------------------------------ + * + * Send a channel notice. + * + * Arguments: + * - channel, the channel, + * - message, the message. + */ +duk_ret_t cnotice(duk_context* ctx) +{ + self(ctx)->cnotice(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.info() + * ------------------------------------------------------------------ + * + * Get the server information as an object containing the following properties: + * + * name: the server unique name + * host: the host name + * port: the port number + * ssl: true if using ssl + * sslVerify: true if ssl was verified + * channels: an array of all channels + */ +duk_ret_t info(duk_context* ctx) +{ + auto server = self(ctx); + + duk_push_object(ctx); + dukx_push_std_string(ctx, server->name()); + duk_put_prop_string(ctx, -2, "name"); + dukx_push_std_string(ctx, server->host()); + duk_put_prop_string(ctx, -2, "host"); + duk_push_int(ctx, server->port()); + duk_put_prop_string(ctx, -2, "port"); + duk_push_boolean(ctx, server->flags() & server::ssl); + duk_put_prop_string(ctx, -2, "ssl"); + duk_push_boolean(ctx, server->flags() & server::ssl_verify); + duk_put_prop_string(ctx, -2, "sslVerify"); + dukx_push_std_string(ctx, server->command_char()); + duk_put_prop_string(ctx, -2, "commandChar"); + dukx_push_std_string(ctx, server->realname()); + duk_put_prop_string(ctx, -2, "realname"); + dukx_push_std_string(ctx, server->nickname()); + duk_put_prop_string(ctx, -2, "nickname"); + dukx_push_std_string(ctx, server->username()); + duk_put_prop_string(ctx, -2, "username"); + dukx_push_array(ctx, server->channels(), [&] (auto ctx, auto channel) { + dukx_push_std_string(ctx, channel); + }); + duk_put_prop_string(ctx, -2, "channels"); + + return 1; +} + +/* + * Method: Server.invite(target, channel) + * ------------------------------------------------------------------ + * + * Invite someone to a channel. + * + * Arguments: + * - target, the target to invite, + * - channel, the channel. + */ +duk_ret_t invite(duk_context* ctx) +{ + self(ctx)->invite(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.join(channel, password = undefined) + * ------------------------------------------------------------------ + * + * Join a channel with an optional password. + * + * Arguments: + * - channel, the channel to join, + * - password, the password or undefined to not use. + */ +duk_ret_t join(duk_context* ctx) +{ + self(ctx)->join(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.kick(target, channel, reason = undefined) + * ------------------------------------------------------------------ + * + * Kick someone from a channel. + * + * Arguments: + * - target, the target to kick, + * - channel, the channel, + * - reason, the optional reason or undefined to not set. + */ +duk_ret_t kick(duk_context* ctx) +{ + self(ctx)->kick(duk_require_string(ctx, 0), duk_require_string(ctx, 1), dukx_get_std_string(ctx, 2)); + + return 0; +} + +/* + * Method: Server.me(target, message) + * ------------------------------------------------------------------ + * + * Send a CTCP Action. + * + * Arguments: + * - target, the target or a channel, + * - message, the message. + */ +duk_ret_t me(duk_context* ctx) +{ + self(ctx)->me(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.message(target, message) + * ------------------------------------------------------------------ + * + * Send a message. + * + * Arguments: + * - target, the target or a channel, + * - message, the message. + */ +duk_ret_t message(duk_context* ctx) +{ + self(ctx)->message(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.mode(mode) + * ------------------------------------------------------------------ + * + * Change your mode. + * + * Arguments: + * - mode, the new mode. + */ +duk_ret_t mode(duk_context* ctx) +{ + self(ctx)->mode(duk_require_string(ctx, 0)); + + return 0; +} + +/* + * Method: Server.names(channel) + * ------------------------------------------------------------------ + * + * Get the list of names from a channel. + * + * Arguments: + * - channel, the channel. + */ +duk_ret_t names(duk_context* ctx) +{ + self(ctx)->names(duk_require_string(ctx, 0)); + + return 0; +} + +/* + * Method: Server.nick(nickname) + * ------------------------------------------------------------------ + * + * Change the nickname. + * + * Arguments: + * - nickname, the nickname. + */ +duk_ret_t nick(duk_context* ctx) +{ + self(ctx)->set_nickname(duk_require_string(ctx, 0)); + + return 0; +} + +/* + * Method: Server.notice(target, message) + * ------------------------------------------------------------------ + * + * Send a private notice. + * + * Arguments: + * - target, the target, + * - message, the notice message. + */ +duk_ret_t notice(duk_context* ctx) +{ + self(ctx)->notice(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.part(channel, reason = undefined) + * ------------------------------------------------------------------ + * + * Leave a channel. + * + * Arguments: + * - channel, the channel to leave, + * - reason, the optional reason, keep undefined for portability. + */ +duk_ret_t part(duk_context* ctx) +{ + self(ctx)->part(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.send(raw) + * ------------------------------------------------------------------ + * + * Send a raw message to the IRC server. + * + * Arguments: + * - raw, the raw message (without terminators). + */ +duk_ret_t send(duk_context* ctx) +{ + self(ctx)->send(duk_require_string(ctx, 0)); + + return 0; +} + +/* + * Method: Server.topic(channel, topic) + * ------------------------------------------------------------------ + * + * Change a channel topic. + * + * Arguments: + * - channel, the channel, + * - topic, the new topic. + */ +duk_ret_t topic(duk_context* ctx) +{ + self(ctx)->topic(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + return 0; +} + +/* + * Method: Server.whois(target) + * ------------------------------------------------------------------ + * + * Get whois information. + * + * Arguments: + * - target, the target. + */ +duk_ret_t whois(duk_context* ctx) +{ + self(ctx)->whois(duk_require_string(ctx, 0)); + + return 0; +} + +/* + * Method: Server.toString() + * ------------------------------------------------------------------ + * + * Convert the object to std::string, convenience for adding the object + * as property key. + * + * duk_ret_turns: + * The server name (unique). + */ +duk_ret_t toString(duk_context* ctx) +{ + dukx_push_std_string(ctx, self(ctx)->name()); + + return 1; +} + +/* + * Function: Irccd.Server(params) [constructor] + * ------------------------------------------------------------------ + * + * Construct a new server. + * + * Params must be filled with the following properties: + * + * name: the name, + * host: the host, + * ipv6: true to use ipv6, (Optional: default false) + * port: the port number, (Optional: default 6667) + * password: the password, (Optional: default none) + * channels: array of channels (Optiona: default empty) + * ssl: true to use ssl, (Optional: default false) + * sslVerify: true to verify (Optional: default true) + * nickname: "nickname", (Optional, default: irccd) + * username: "user name", (Optional, default: irccd) + * realname: "real name", (Optional, default: IRC Client Daemon) + * commandChar: "!", (Optional, the command char, default: "!") + */ +duk_ret_t constructor(duk_context* ctx) +{ + if (!duk_is_constructor_call(ctx)) + return 0; + + duk_check_type(ctx, 0, DUK_TYPE_OBJECT); + + try { + auto json = duk_json_encode(ctx, 0); + auto s = server::from_json(nlohmann::json::parse(json)); + + duk_push_this(ctx); + duk_push_pointer(ctx, new std::shared_ptr(std::move(s))); + duk_put_prop_string(ctx, -2, signature); + duk_pop(ctx); + } catch (const std::exception& ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +/* + * Function: Irccd.Server() [destructor] + * ------------------------------------------------------------------ + * + * Delete the property. + */ +duk_ret_t destructor(duk_context* ctx) +{ + duk_get_prop_string(ctx, 0, signature); + delete static_cast*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, signature); + + return 0; +} + +/* + * Function: Irccd.Server.add(s) + * ------------------------------------------------------------------ + * + * Register a new server to the irccd instance. + * + * Arguments: + * - s, the server to add. + */ +duk_ret_t add(duk_context* ctx) +{ + dukx_get_irccd(ctx).servers().add(dukx_require_server(ctx, 0)); + + return 0; +} + +/* + * Function: Irccd.Server.find(name) + * ------------------------------------------------------------------ + * + * Find a server by name. + * + * Arguments: + * - name, the server name + * duk_ret_turns: + * The server object or undefined if not found. + */ +duk_ret_t find(duk_context* ctx) +{ + auto server = dukx_get_irccd(ctx).servers().get(duk_require_string(ctx, 0)); + + if (!server) + return 0; + + dukx_push_server(ctx, server); + + return 1; +} + +/* + * Function: Irccd.Server.list() + * ------------------------------------------------------------------ + * + * Get the map of all loaded servers. + * + * duk_ret_turns: + * An object with string-to-servers pairs. + */ +duk_ret_t list(duk_context* ctx) +{ + duk_push_object(ctx); + + for (const auto &server : dukx_get_irccd(ctx).servers().servers()) { + dukx_push_server(ctx, server); + duk_put_prop_string(ctx, -2, server->name().c_str()); + } + + return 1; +} + +/* + * Function: irccd.Server.remove(name) + * ------------------------------------------------------------------ + * + * Remove a server from the irccd instance. You can pass the server object since + * it's coercible to a string. + * + * Arguments: + * - name the server name. + */ +duk_ret_t remove(duk_context* ctx) +{ + dukx_get_irccd(ctx).servers().remove(duk_require_string(ctx, 0)); + + return 0; +} + +const duk_function_list_entry methods[] = { + { "cmode", cmode, 2 }, + { "cnotice", cnotice, 2 }, + { "info", info, 0 }, + { "invite", invite, 2 }, + { "join", join, DUK_VARARGS }, + { "kick", kick, DUK_VARARGS }, + { "me", me, 2 }, + { "message", message, 2 }, + { "mode", mode, 1 }, + { "names", names, 1 }, + { "nick", nick, 1 }, + { "notice", notice, 2 }, + { "part", part, DUK_VARARGS }, + { "send", send, 1 }, + { "topic", topic, 2 }, + { "whois", whois, 1 }, + { "toString", toString, 0 }, + { nullptr, nullptr, 0 } +}; + +const duk_function_list_entry functions[] = { + { "add", add, 1 }, + { "find", find, 1 }, + { "list", list, 0 }, + { "remove", remove, 1 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +std::string server_jsapi::name() const +{ + return "Irccd.Server"; +} + +void server_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_c_function(plugin->context(), constructor, 1); + duk_put_function_list(plugin->context(), -1, functions); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, methods); + duk_push_c_function(plugin->context(), destructor, 1); + duk_set_finalizer(plugin->context(), -2); + duk_dup_top(plugin->context()); + duk_put_global_string(plugin->context(), prototype); + duk_put_prop_string(plugin->context(), -2, "prototype"); + duk_put_prop_string(plugin->context(), -2, "Server"); + duk_pop(plugin->context()); +} + +void dukx_push_server(duk_context* ctx, std::shared_ptr server) +{ + assert(ctx); + assert(server); + + StackAssert sa(ctx, 1); + + duk_push_object(ctx); + duk_push_pointer(ctx, new std::shared_ptr(std::move(server))); + duk_put_prop_string(ctx, -2, signature); + duk_get_global_string(ctx, prototype); + duk_set_prototype(ctx, -2); +} + +std::shared_ptr dukx_require_server(duk_context* ctx, duk_idx_t index) +{ + if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, signature)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); + + duk_get_prop_string(ctx, index, signature); + auto file = *static_cast *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return file; +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/server_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/server_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,69 @@ +/* + * server_jsapi.hpp -- Irccd.Server API + * + * 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_JS_SERVER_JSAPI_HPP +#define IRCCD_JS_SERVER_JSAPI_HPP + +/** + * \file mod-server.hpp + * \brief irccd.Server Javascript API. + */ + +#include "jsapi.hpp" +#include "server.hpp" + +namespace irccd { + +/** + * \brief irccd.Server Javascript API. + * \ingroup jsapi + */ +class server_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +/** + * Push a server. + * + * \pre server != nullptr + * \param ctx the context + * \param server the server + */ +void dukx_push_server(duk_context* ctx, std::shared_ptr server); + +/** + * Require a server. Raise a Javascript error if not a Server. + * + * \param ctx the context + * \param index the index + * \return the server + */ +std::shared_ptr dukx_require_server(duk_context* ctx, duk_idx_t index); + +} // !irccd + +#endif // !IRCCD_JS_SERVER_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/system_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/system_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,244 @@ +/* + * system_jsapi.cpp -- Irccd.System API + * + * 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 + +#include +#include +#include + +#if defined(HAVE_POPEN) +# include +#endif + +#include + +#include "file_jsapi.hpp" +#include "irccd_jsapi.hpp" +#include "js_plugin.hpp" +#include "system_jsapi.hpp" + +namespace irccd { + +namespace { + +/* + * Function: irccd.System.env(key) + * ------------------------------------------------------------------ + * + * Get an environment system variable. + * + * Arguments: + * - key, the environment variable. + * Returns: + * The value. + */ +duk_ret_t env(duk_context* ctx) +{ + dukx_push_std_string(ctx, sys::env(dukx_get_std_string(ctx, 0))); + + return 1; +} + +/* + * Function: irccd.System.exec(cmd) + * ------------------------------------------------------------------ + * + * Execute a system command. + * + * Arguments: + * - cmd, the command to execute. + */ +duk_ret_t exec(duk_context* ctx) +{ + std::system(duk_get_string(ctx, 0)); + + return 0; +} + +/* + * Function: irccd.System.home() + * ------------------------------------------------------------------ + * + * Get the operating system user's home. + * + * Returns: + * The user home directory. + */ +duk_ret_t home(duk_context* ctx) +{ + dukx_push_std_string(ctx, sys::home()); + + return 1; +} + +/* + * Function: irccd.System.name() + * ------------------------------------------------------------------ + * + * Get the operating system name. + * + * Returns: + * The system name. + */ +duk_ret_t name(duk_context* ctx) +{ + dukx_push_std_string(ctx, sys::name()); + + return 1; +} + +#if defined(HAVE_POPEN) + +/* + * Function: irccd.System.popen(cmd, mode) [optional] + * ------------------------------------------------------------------ + * + * Wrapper for popen(3) if the function is available. + * + * Arguments: + * - cmd, the command to execute, + * - mode, the mode (e.g. "r"). + * Returns: + * A irccd.File object. + * Throws + * - irccd.system_error on failures. + */ +duk_ret_t popen(duk_context* ctx) +{ + auto fp = ::popen(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); + + if (fp == nullptr) + dukx_throw(ctx, system_error()); + + dukx_push_file(ctx, new file(fp, [] (auto fp) { ::pclose(fp); })); + + return 1; +} + +#endif // !HAVE_POPEN + +/* + * Function: irccd.System.sleep(delay) + * ------------------------------------------------------------------ + * + * Sleep the main loop for the specific delay in seconds. + */ +duk_ret_t sleep(duk_context* ctx) +{ + std::this_thread::sleep_for(std::chrono::seconds(duk_get_int(ctx, 0))); + + return 0; +} + +/* + * Function: irccd.System.ticks() + * ------------------------------------------------------------------ + * + * Get the number of milliseconds since irccd was started. + * + * Returns: + * The number of milliseconds. + */ +duk_ret_t ticks(duk_context* ctx) +{ + duk_push_int(ctx, sys::ticks()); + + return 1; +} + +/* + * Function: irccd.System.usleep(delay) + * ------------------------------------------------------------------ + * + * Sleep the main loop for the specific delay in microseconds. + */ +duk_ret_t usleep(duk_context* ctx) +{ + std::this_thread::sleep_for(std::chrono::microseconds(duk_get_int(ctx, 0))); + + return 0; +} + +/* + * Function: irccd.System.uptime() + * ------------------------------------------------------------------ + * + * Get the system uptime. + * + * Returns: + * The system uptime. + */ +duk_ret_t uptime(duk_context* ctx) +{ + duk_push_int(ctx, sys::uptime()); + + return 0; +} + +/* + * Function: irccd.System.version() + * ------------------------------------------------------------------ + * + * Get the operating system version. + * + * Returns: + * The system version. + */ +duk_ret_t version(duk_context* ctx) +{ + dukx_push_std_string(ctx, sys::version()); + + return 1; +} + +const duk_function_list_entry functions[] = { + { "env", env, 1 }, + { "exec", exec, 1 }, + { "home", home, 0 }, + { "name", name, 0 }, +#if defined(HAVE_POPEN) + { "popen", popen, 2 }, +#endif + { "sleep", sleep, 1 }, + { "ticks", ticks, 0 }, + { "uptime", uptime, 0 }, + { "usleep", usleep, 1 }, + { "version", version, 0 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +std::string system_jsapi::name() const +{ + return "Irccd.System"; +} + +void system_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, functions); + duk_put_prop_string(plugin->context(), -2, "System"); + duk_pop(plugin->context()); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/system_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/system_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,50 @@ +/* + * system_jsapi.hpp -- Irccd.System API + * + * 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_JS_SYSTEM_JSAPI_HPP +#define IRCCD_JS_SYSTEM_JSAPI_HPP + +/** + * \file system_jsapi.hpp + * \brief Irccd.System Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Irccd.System Javascript API. + * \ingroup jsapi + */ +class system_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +} // !irccd + +#endif // !IRCCD_JS_SYSTEM_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/timer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/timer.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,104 @@ +/* + * timer.cpp -- threaded timers + * + * 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 +#include + +#include + +#include "timer.hpp" + +namespace irccd { + +void timer::run() +{ + while (state_ != state::stopped) { + std::unique_lock lock(mutex_); + + // Wait in case the timer is paused. + condition_.wait(lock, [&] () { + return state_ == state::running; + }); + + if (state_ != state::running) + continue; + + // Wait the timer delay or the interrupt. + condition_.wait_for(lock, std::chrono::milliseconds(delay_), [&] () { + return state_ != state::running; + }); + + if (state_ == state::running) { + // Signal process. + on_signal(); + + if (type_ == type::single) + state_ = state::stopped; + } + } + + on_end(); +} + +timer::timer(type type, unsigned delay) noexcept + : type_(type) + , delay_(delay) + , thread_(std::bind(&timer::run, this)) +{ +} + +timer::~timer() +{ + assert(state_ != state::running); + + try { + { + std::lock_guard lk(mutex_); + + state_ = state::stopped; + condition_.notify_one(); + } + + thread_.join(); + } catch (...) { + } +} + +void timer::start() +{ + assert(state_ != state::running); + + { + std::lock_guard lk(mutex_); + state_ = state::running; + } + + condition_.notify_one(); +} + +void timer::stop() +{ + { + std::lock_guard lk(mutex_); + state_ = state::paused; + } + + condition_.notify_one(); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/timer.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/timer.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,154 @@ +/* + * timer.hpp -- threaded timers + * + * 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_TIMER_HPP +#define IRCCD_TIMER_HPP + +/** + * \file timer.hpp + * \brief Provides interval based timers for JavaScript + */ + +#include +#include +#include +#include +#include + +#include "signals.hpp" +#include "sysconfig.hpp" + +namespace irccd { + +/** + * \brief Timer class + * + * A timer is a thread object that emits a signal periodically or just one time. It is perfectly pausable and resumable + * to reuse the same object. + * + * The delay is configured in milliseconds and the user has choice to use any + * delay needed. + * + * We use a condition variable to wait for the specified delay unless the timer + * must be stopped. + */ +class timer { +public: + /** + * \brief Type of timer + */ + enum class type { + single, //!< The timer ends after execution + repeat //!< The timer loops + }; + + /** + * Signal: onSignal + * ---------------------------------------------------------- + * + * Called when the timeout expires. + */ + Signal<> on_signal; + + /** + * Signal: onEnd + * ---------------------------------------------------------- + * + * Called when the timeout ends. + */ + Signal<> on_end; + +private: + enum class state { + paused, + running, + stopped + }; + + type type_; + unsigned delay_; + + // Thread management. + std::atomic state_{state::paused}; + std::mutex mutex_; + std::condition_variable condition_; + std::thread thread_; + + void run(); + +public: + /** + * Timer constructor. + * + * The timer is not started, use start(). + * + * \param type the timer type + * \param delay the delay in milliseconds + * \post isRunning() returns false + */ + timer(type type, unsigned delay) noexcept; + + /** + * Destructor, closes the thread. + * + * \pre stop() must have been called. + */ + virtual ~timer(); + + /** + * Start the thread. + * + * \pre isRunning() must return false + * \pre onSignal() must have been called + * \pre onEnd() must have been called + * \note Thread-safe + */ + void start(); + + /** + * Stop the timer, may be used by the user to stop it. + * + * \note Thread-safe + */ + void stop(); + + /** + * Get the type of timer. + * + * \return the type. + */ + inline type get_type() const noexcept + { + return type_; + } + + /** + * Tells if the timer has still a running thread. + * + * \return true if still alive + * \note Thread-safe + */ + inline bool is_running() const noexcept + { + return state_ == state::running; + } +}; + +} // !irccd + +#endif // !IRCCD_TIMER_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/timer_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/timer_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,208 @@ +/* + * timer_jsapi.cpp -- Irccd.timer API + * + * 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 +#include +#include + +#include "irccd_jsapi.hpp" +#include "js_plugin.hpp" +#include "plugin_jsapi.hpp" +#include "timer.hpp" +#include "timer_jsapi.hpp" + +namespace irccd { + +namespace { + +const char* signature("\xff""\xff""irccd-timer-ptr"); +const char* callback_table("\xff""\xff""irccd-timer-callbacks"); + +void handle_signal(irccd& instance, std::weak_ptr ptr, std::string key) +{ + auto plugin = ptr.lock(); + + if (!plugin) + return; + + instance.post([plugin, key] (irccd &) { + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), callback_table); + duk_get_prop_string(plugin->context(), -1, key.c_str()); + duk_remove(plugin->context(), -2); + + if (duk_is_callable(plugin->context(), -1)) { + if (duk_pcall(plugin->context(), 0) != 0) + log::warning(string_util::sprintf("plugin %s: %s", plugin->name(), + dukx_exception(plugin->context(), -1).stack)); + else + duk_pop(plugin->context()); + } else + duk_pop(plugin->context()); + }); +} + +std::shared_ptr self(duk_context* ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, signature); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a timer object"); + + return *static_cast*>(ptr); +} + +/* + * Method: timer.start() + * -------------------------------------------------------- + * + * Start the timer. If the timer is already started the method is a no-op. + */ +duk_ret_t start(duk_context* ctx) +{ + auto timer = self(ctx); + + if (!timer->is_running()) + timer->start(); + + return 0; +} + +/* + * Method: timer.stop() + * -------------------------------------------------------- + * + * Stop the timer. + */ +duk_ret_t stop(duk_context* ctx) +{ + auto timer = self(ctx); + + if (timer->is_running()) + timer->stop(); + + return 0; +} + +const duk_function_list_entry methods[] = { + { "start", start, 0 }, + { "stop", stop, 0 }, + { nullptr, nullptr, 0 } +}; + +/* + * Function: Irccd.timer(type, delay, callback) [constructor] + * -------------------------------------------------------- + * + * Create a new timer object. + * + * Arguments: + * - type, the type of timer (irccd.timer.Single or irccd.timer.Repeat), + * - delay, the interval in milliseconds, + * - callback, the function to call. + */ +duk_ret_t constructor(duk_context* ctx) +{ + // Check parameters. + auto type = duk_require_int(ctx, 0); + auto delay = duk_require_int(ctx, 1); + + if (type < static_cast(timer::type::single) || type > static_cast(timer::type::repeat)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type"); + if (delay < 0) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "negative delay given"); + if (!duk_is_callable(ctx, 2)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function"); + + // Construct the timer in 'this'. + auto& irccd = dukx_get_irccd(ctx); + auto tm = std::make_shared(static_cast(type), delay); + auto hash = std::to_string(reinterpret_cast(tm.get())); + + tm->on_signal.connect(std::bind(handle_signal, std::ref(irccd), + std::weak_ptr(dukx_get_plugin(ctx)), hash)); + + duk_push_this(ctx); + duk_push_pointer(ctx, new std::shared_ptr(std::move(tm))); + duk_put_prop_string(ctx, -2, signature); + duk_push_string(ctx, hash.c_str()); + duk_put_prop_string(ctx, -2, "\xff""\xff""timer-key"); + duk_push_c_function(ctx, [] (duk_context* ctx) -> duk_ret_t { + StackAssert sa(ctx); + + duk_get_prop_string(ctx, 0, "\xff""\xff""timer-key"); + auto hash = duk_get_string(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, 0, signature); + static_cast*>(duk_to_pointer(ctx, -1))->get()->stop(); + delete static_cast*>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_get_global_string(ctx, callback_table); + duk_del_prop_string(ctx, -1, hash); + duk_pop(ctx); + log::debug("plugin: timer destroyed"); + + return 0; + }, 1); + duk_set_finalizer(ctx, -2); + + // Save a callback function into the callback table. + duk_get_global_string(ctx, callback_table); + duk_dup(ctx, 2); + duk_put_prop_string(ctx, -2, hash.c_str()); + duk_pop(ctx); + + return 0; +} + +const duk_number_list_entry constants[] = { + { "Single", static_cast(timer::type::single) }, + { "Repeat", static_cast(timer::type::repeat) }, + { nullptr, 0 } +}; + +} // !namespace + +std::string timer_jsapi::name() const +{ + return "Irccd.Timer"; +} + +void timer_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_c_function(plugin->context(), constructor, 3); + duk_put_number_list(plugin->context(), -1, constants); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, methods); + duk_put_prop_string(plugin->context(), -2, "prototype"); + duk_put_prop_string(plugin->context(), -2, "Timer"); + duk_pop(plugin->context()); + duk_push_object(plugin->context()); + duk_put_global_string(plugin->context(), callback_table); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/timer_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/timer_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,50 @@ +/* + * timer_jsapi.hpp -- Irccd.Timer API + * + * 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_JS_TIMER_JSAPI_HPP +#define IRCCD_JS_TIMER_JSAPI_HPP + +/** + * \file timer_jsapi + * \brief Irccd.Timer Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Irccd.Timer Javascript API. + * \ingroup jsapi + */ +class timer_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +} // !irccd + +#endif // !IRCCD_JS_TIMER_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/unicode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/unicode.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,4796 @@ +/* + * unicode.cpp -- UTF-8 to UTF-32 conversions and various operations + * + * 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 "unicode.hpp" + +/* + * The following code has been generated from Go mkrunetype adapted to our + * needs. + */ + +namespace irccd { + +namespace unicode { + +#define nelem(x) (sizeof (x) / sizeof ((x)[0])) + +namespace { + +const char32_t *rbsearch(char32_t c, const char32_t *t, int n, int ne) noexcept +{ + const char32_t *p; + int m; + + while (n > 1) { + m = n >> 1; + p = t + m * ne; + + if (c >= p[0]) { + t = p; + n = n - m; + } else + n = m; + } + + if (n && c >= t[0]) + return t; + + return nullptr; +} + +} // !namespace + +namespace { + +const char32_t isspacer[] = { + 0x0009, 0x000d, + 0x0020, 0x0020, + 0x0085, 0x0085, + 0x00a0, 0x00a0, + 0x1680, 0x1680, + 0x2000, 0x200a, + 0x2028, 0x2029, + 0x202f, 0x202f, + 0x205f, 0x205f, + 0x3000, 0x3000, + 0xfeff, 0xfeff, +}; + +} // !namespace + +bool isspace(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, isspacer, nelem (isspacer)/2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + return false; +} + +namespace { + +const char32_t isdigitr[] = { + 0x0030, 0x0039, + 0x0660, 0x0669, + 0x06f0, 0x06f9, + 0x07c0, 0x07c9, + 0x0966, 0x096f, + 0x09e6, 0x09ef, + 0x0a66, 0x0a6f, + 0x0ae6, 0x0aef, + 0x0b66, 0x0b6f, + 0x0be6, 0x0bef, + 0x0c66, 0x0c6f, + 0x0ce6, 0x0cef, + 0x0d66, 0x0d6f, + 0x0de6, 0x0def, + 0x0e50, 0x0e59, + 0x0ed0, 0x0ed9, + 0x0f20, 0x0f29, + 0x1040, 0x1049, + 0x1090, 0x1099, + 0x17e0, 0x17e9, + 0x1810, 0x1819, + 0x1946, 0x194f, + 0x19d0, 0x19d9, + 0x1a80, 0x1a89, + 0x1a90, 0x1a99, + 0x1b50, 0x1b59, + 0x1bb0, 0x1bb9, + 0x1c40, 0x1c49, + 0x1c50, 0x1c59, + 0xa620, 0xa629, + 0xa8d0, 0xa8d9, + 0xa900, 0xa909, + 0xa9d0, 0xa9d9, + 0xa9f0, 0xa9f9, + 0xaa50, 0xaa59, + 0xabf0, 0xabf9, + 0xff10, 0xff19, + 0x104a0, 0x104a9, + 0x11066, 0x1106f, + 0x110f0, 0x110f9, + 0x11136, 0x1113f, + 0x111d0, 0x111d9, + 0x112f0, 0x112f9, + 0x114d0, 0x114d9, + 0x11650, 0x11659, + 0x116c0, 0x116c9, + 0x118e0, 0x118e9, + 0x16a60, 0x16a69, + 0x16b50, 0x16b59, + 0x1d7ce, 0x1d7ff, +}; + +} // !namespace + +bool isdigit(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, isdigitr, nelem (isdigitr)/2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + return false; +} + +namespace { + +const char32_t isalphar[] = { + 0x0041, 0x005a, + 0x0061, 0x007a, + 0x00c0, 0x00d6, + 0x00d8, 0x00f6, + 0x00f8, 0x02c1, + 0x02c6, 0x02d1, + 0x02e0, 0x02e4, + 0x0370, 0x0374, + 0x0376, 0x0377, + 0x037a, 0x037d, + 0x0388, 0x038a, + 0x038e, 0x03a1, + 0x03a3, 0x03f5, + 0x03f7, 0x0481, + 0x048a, 0x052f, + 0x0531, 0x0556, + 0x0561, 0x0587, + 0x05d0, 0x05ea, + 0x05f0, 0x05f2, + 0x0620, 0x064a, + 0x066e, 0x066f, + 0x0671, 0x06d3, + 0x06e5, 0x06e6, + 0x06ee, 0x06ef, + 0x06fa, 0x06fc, + 0x0712, 0x072f, + 0x074d, 0x07a5, + 0x07ca, 0x07ea, + 0x07f4, 0x07f5, + 0x0800, 0x0815, + 0x0840, 0x0858, + 0x08a0, 0x08b2, + 0x0904, 0x0939, + 0x0958, 0x0961, + 0x0971, 0x0980, + 0x0985, 0x098c, + 0x098f, 0x0990, + 0x0993, 0x09a8, + 0x09aa, 0x09b0, + 0x09b6, 0x09b9, + 0x09dc, 0x09dd, + 0x09df, 0x09e1, + 0x09f0, 0x09f1, + 0x0a05, 0x0a0a, + 0x0a0f, 0x0a10, + 0x0a13, 0x0a28, + 0x0a2a, 0x0a30, + 0x0a32, 0x0a33, + 0x0a35, 0x0a36, + 0x0a38, 0x0a39, + 0x0a59, 0x0a5c, + 0x0a72, 0x0a74, + 0x0a85, 0x0a8d, + 0x0a8f, 0x0a91, + 0x0a93, 0x0aa8, + 0x0aaa, 0x0ab0, + 0x0ab2, 0x0ab3, + 0x0ab5, 0x0ab9, + 0x0ae0, 0x0ae1, + 0x0b05, 0x0b0c, + 0x0b0f, 0x0b10, + 0x0b13, 0x0b28, + 0x0b2a, 0x0b30, + 0x0b32, 0x0b33, + 0x0b35, 0x0b39, + 0x0b5c, 0x0b5d, + 0x0b5f, 0x0b61, + 0x0b85, 0x0b8a, + 0x0b8e, 0x0b90, + 0x0b92, 0x0b95, + 0x0b99, 0x0b9a, + 0x0b9e, 0x0b9f, + 0x0ba3, 0x0ba4, + 0x0ba8, 0x0baa, + 0x0bae, 0x0bb9, + 0x0c05, 0x0c0c, + 0x0c0e, 0x0c10, + 0x0c12, 0x0c28, + 0x0c2a, 0x0c39, + 0x0c58, 0x0c59, + 0x0c60, 0x0c61, + 0x0c85, 0x0c8c, + 0x0c8e, 0x0c90, + 0x0c92, 0x0ca8, + 0x0caa, 0x0cb3, + 0x0cb5, 0x0cb9, + 0x0ce0, 0x0ce1, + 0x0cf1, 0x0cf2, + 0x0d05, 0x0d0c, + 0x0d0e, 0x0d10, + 0x0d12, 0x0d3a, + 0x0d60, 0x0d61, + 0x0d7a, 0x0d7f, + 0x0d85, 0x0d96, + 0x0d9a, 0x0db1, + 0x0db3, 0x0dbb, + 0x0dc0, 0x0dc6, + 0x0e01, 0x0e30, + 0x0e32, 0x0e33, + 0x0e40, 0x0e46, + 0x0e81, 0x0e82, + 0x0e87, 0x0e88, + 0x0e94, 0x0e97, + 0x0e99, 0x0e9f, + 0x0ea1, 0x0ea3, + 0x0eaa, 0x0eab, + 0x0ead, 0x0eb0, + 0x0eb2, 0x0eb3, + 0x0ec0, 0x0ec4, + 0x0edc, 0x0edf, + 0x0f40, 0x0f47, + 0x0f49, 0x0f6c, + 0x0f88, 0x0f8c, + 0x1000, 0x102a, + 0x1050, 0x1055, + 0x105a, 0x105d, + 0x1065, 0x1066, + 0x106e, 0x1070, + 0x1075, 0x1081, + 0x10a0, 0x10c5, + 0x10d0, 0x10fa, + 0x10fc, 0x1248, + 0x124a, 0x124d, + 0x1250, 0x1256, + 0x125a, 0x125d, + 0x1260, 0x1288, + 0x128a, 0x128d, + 0x1290, 0x12b0, + 0x12b2, 0x12b5, + 0x12b8, 0x12be, + 0x12c2, 0x12c5, + 0x12c8, 0x12d6, + 0x12d8, 0x1310, + 0x1312, 0x1315, + 0x1318, 0x135a, + 0x1380, 0x138f, + 0x13a0, 0x13f4, + 0x1401, 0x166c, + 0x166f, 0x167f, + 0x1681, 0x169a, + 0x16a0, 0x16ea, + 0x16f1, 0x16f8, + 0x1700, 0x170c, + 0x170e, 0x1711, + 0x1720, 0x1731, + 0x1740, 0x1751, + 0x1760, 0x176c, + 0x176e, 0x1770, + 0x1780, 0x17b3, + 0x1820, 0x1877, + 0x1880, 0x18a8, + 0x18b0, 0x18f5, + 0x1900, 0x191e, + 0x1950, 0x196d, + 0x1970, 0x1974, + 0x1980, 0x19ab, + 0x19c1, 0x19c7, + 0x1a00, 0x1a16, + 0x1a20, 0x1a54, + 0x1b05, 0x1b33, + 0x1b45, 0x1b4b, + 0x1b83, 0x1ba0, + 0x1bae, 0x1baf, + 0x1bba, 0x1be5, + 0x1c00, 0x1c23, + 0x1c4d, 0x1c4f, + 0x1c5a, 0x1c7d, + 0x1ce9, 0x1cec, + 0x1cee, 0x1cf1, + 0x1cf5, 0x1cf6, + 0x1d00, 0x1dbf, + 0x1e00, 0x1f15, + 0x1f18, 0x1f1d, + 0x1f20, 0x1f45, + 0x1f48, 0x1f4d, + 0x1f50, 0x1f57, + 0x1f5f, 0x1f7d, + 0x1f80, 0x1fb4, + 0x1fb6, 0x1fbc, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fcc, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fdb, + 0x1fe0, 0x1fec, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ffc, + 0x2090, 0x209c, + 0x210a, 0x2113, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x212f, 0x2139, + 0x213c, 0x213f, + 0x2145, 0x2149, + 0x2183, 0x2184, + 0x2c00, 0x2c2e, + 0x2c30, 0x2c5e, + 0x2c60, 0x2ce4, + 0x2ceb, 0x2cee, + 0x2cf2, 0x2cf3, + 0x2d00, 0x2d25, + 0x2d30, 0x2d67, + 0x2d80, 0x2d96, + 0x2da0, 0x2da6, + 0x2da8, 0x2dae, + 0x2db0, 0x2db6, + 0x2db8, 0x2dbe, + 0x2dc0, 0x2dc6, + 0x2dc8, 0x2dce, + 0x2dd0, 0x2dd6, + 0x2dd8, 0x2dde, + 0x3005, 0x3006, + 0x3031, 0x3035, + 0x303b, 0x303c, + 0x3041, 0x3096, + 0x309d, 0x309f, + 0x30a1, 0x30fa, + 0x30fc, 0x30ff, + 0x3105, 0x312d, + 0x3131, 0x318e, + 0x31a0, 0x31ba, + 0x31f0, 0x31ff, + 0x3400, 0x4db5, + 0x4e00, 0x9fcc, + 0xa000, 0xa48c, + 0xa4d0, 0xa4fd, + 0xa500, 0xa60c, + 0xa610, 0xa61f, + 0xa62a, 0xa62b, + 0xa640, 0xa66e, + 0xa67f, 0xa69d, + 0xa6a0, 0xa6e5, + 0xa717, 0xa71f, + 0xa722, 0xa788, + 0xa78b, 0xa78e, + 0xa790, 0xa7ad, + 0xa7b0, 0xa7b1, + 0xa7f7, 0xa801, + 0xa803, 0xa805, + 0xa807, 0xa80a, + 0xa80c, 0xa822, + 0xa840, 0xa873, + 0xa882, 0xa8b3, + 0xa8f2, 0xa8f7, + 0xa90a, 0xa925, + 0xa930, 0xa946, + 0xa960, 0xa97c, + 0xa984, 0xa9b2, + 0xa9e0, 0xa9e4, + 0xa9e6, 0xa9ef, + 0xa9fa, 0xa9fe, + 0xaa00, 0xaa28, + 0xaa40, 0xaa42, + 0xaa44, 0xaa4b, + 0xaa60, 0xaa76, + 0xaa7e, 0xaaaf, + 0xaab5, 0xaab6, + 0xaab9, 0xaabd, + 0xaadb, 0xaadd, + 0xaae0, 0xaaea, + 0xaaf2, 0xaaf4, + 0xab01, 0xab06, + 0xab09, 0xab0e, + 0xab11, 0xab16, + 0xab20, 0xab26, + 0xab28, 0xab2e, + 0xab30, 0xab5a, + 0xab5c, 0xab5f, + 0xab64, 0xab65, + 0xabc0, 0xabe2, + 0xac00, 0xd7a3, + 0xd7b0, 0xd7c6, + 0xd7cb, 0xd7fb, + 0xf900, 0xfa6d, + 0xfa70, 0xfad9, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xfb1f, 0xfb28, + 0xfb2a, 0xfb36, + 0xfb38, 0xfb3c, + 0xfb40, 0xfb41, + 0xfb43, 0xfb44, + 0xfb46, 0xfbb1, + 0xfbd3, 0xfd3d, + 0xfd50, 0xfd8f, + 0xfd92, 0xfdc7, + 0xfdf0, 0xfdfb, + 0xfe70, 0xfe74, + 0xfe76, 0xfefc, + 0xff21, 0xff3a, + 0xff41, 0xff5a, + 0xff66, 0xffbe, + 0xffc2, 0xffc7, + 0xffca, 0xffcf, + 0xffd2, 0xffd7, + 0xffda, 0xffdc, + 0x10000, 0x1000b, + 0x1000d, 0x10026, + 0x10028, 0x1003a, + 0x1003c, 0x1003d, + 0x1003f, 0x1004d, + 0x10050, 0x1005d, + 0x10080, 0x100fa, + 0x10280, 0x1029c, + 0x102a0, 0x102d0, + 0x10300, 0x1031f, + 0x10330, 0x10340, + 0x10342, 0x10349, + 0x10350, 0x10375, + 0x10380, 0x1039d, + 0x103a0, 0x103c3, + 0x103c8, 0x103cf, + 0x10400, 0x1049d, + 0x10500, 0x10527, + 0x10530, 0x10563, + 0x10600, 0x10736, + 0x10740, 0x10755, + 0x10760, 0x10767, + 0x10800, 0x10805, + 0x1080a, 0x10835, + 0x10837, 0x10838, + 0x1083f, 0x10855, + 0x10860, 0x10876, + 0x10880, 0x1089e, + 0x10900, 0x10915, + 0x10920, 0x10939, + 0x10980, 0x109b7, + 0x109be, 0x109bf, + 0x10a10, 0x10a13, + 0x10a15, 0x10a17, + 0x10a19, 0x10a33, + 0x10a60, 0x10a7c, + 0x10a80, 0x10a9c, + 0x10ac0, 0x10ac7, + 0x10ac9, 0x10ae4, + 0x10b00, 0x10b35, + 0x10b40, 0x10b55, + 0x10b60, 0x10b72, + 0x10b80, 0x10b91, + 0x10c00, 0x10c48, + 0x11003, 0x11037, + 0x11083, 0x110af, + 0x110d0, 0x110e8, + 0x11103, 0x11126, + 0x11150, 0x11172, + 0x11183, 0x111b2, + 0x111c1, 0x111c4, + 0x11200, 0x11211, + 0x11213, 0x1122b, + 0x112b0, 0x112de, + 0x11305, 0x1130c, + 0x1130f, 0x11310, + 0x11313, 0x11328, + 0x1132a, 0x11330, + 0x11332, 0x11333, + 0x11335, 0x11339, + 0x1135d, 0x11361, + 0x11480, 0x114af, + 0x114c4, 0x114c5, + 0x11580, 0x115ae, + 0x11600, 0x1162f, + 0x11680, 0x116aa, + 0x118a0, 0x118df, + 0x11ac0, 0x11af8, + 0x12000, 0x12398, + 0x13000, 0x1342e, + 0x16800, 0x16a38, + 0x16a40, 0x16a5e, + 0x16ad0, 0x16aed, + 0x16b00, 0x16b2f, + 0x16b40, 0x16b43, + 0x16b63, 0x16b77, + 0x16b7d, 0x16b8f, + 0x16f00, 0x16f44, + 0x16f93, 0x16f9f, + 0x1b000, 0x1b001, + 0x1bc00, 0x1bc6a, + 0x1bc70, 0x1bc7c, + 0x1bc80, 0x1bc88, + 0x1bc90, 0x1bc99, + 0x1d400, 0x1d454, + 0x1d456, 0x1d49c, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d51e, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d552, 0x1d6a5, + 0x1d6a8, 0x1d6c0, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6fa, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d734, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d76e, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d7a8, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7cb, + 0x1e800, 0x1e8c4, + 0x1ee00, 0x1ee03, + 0x1ee05, 0x1ee1f, + 0x1ee21, 0x1ee22, + 0x1ee29, 0x1ee32, + 0x1ee34, 0x1ee37, + 0x1ee4d, 0x1ee4f, + 0x1ee51, 0x1ee52, + 0x1ee61, 0x1ee62, + 0x1ee67, 0x1ee6a, + 0x1ee6c, 0x1ee72, + 0x1ee74, 0x1ee77, + 0x1ee79, 0x1ee7c, + 0x1ee80, 0x1ee89, + 0x1ee8b, 0x1ee9b, + 0x1eea1, 0x1eea3, + 0x1eea5, 0x1eea9, + 0x1eeab, 0x1eebb, + 0x20000, 0x2a6d6, + 0x2a700, 0x2b734, + 0x2b740, 0x2b81d, + 0x2f800, 0x2fa1d, +}; + +} // !namespace + +namespace { + +const char32_t isalphas[] = { + 0x00aa, + 0x00b5, + 0x00ba, + 0x02ec, + 0x02ee, + 0x037f, + 0x0386, + 0x038c, + 0x0559, + 0x06d5, + 0x06ff, + 0x0710, + 0x07b1, + 0x07fa, + 0x081a, + 0x0824, + 0x0828, + 0x093d, + 0x0950, + 0x09b2, + 0x09bd, + 0x09ce, + 0x0a5e, + 0x0abd, + 0x0ad0, + 0x0b3d, + 0x0b71, + 0x0b83, + 0x0b9c, + 0x0bd0, + 0x0c3d, + 0x0cbd, + 0x0cde, + 0x0d3d, + 0x0d4e, + 0x0dbd, + 0x0e84, + 0x0e8a, + 0x0e8d, + 0x0ea5, + 0x0ea7, + 0x0ebd, + 0x0ec6, + 0x0f00, + 0x103f, + 0x1061, + 0x108e, + 0x10c7, + 0x10cd, + 0x1258, + 0x12c0, + 0x17d7, + 0x17dc, + 0x18aa, + 0x1aa7, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1fbe, + 0x2071, + 0x207f, + 0x2102, + 0x2107, + 0x2115, + 0x2124, + 0x2126, + 0x2128, + 0x214e, + 0x2d27, + 0x2d2d, + 0x2d6f, + 0x2e2f, + 0xa8fb, + 0xa9cf, + 0xaa7a, + 0xaab1, + 0xaac0, + 0xaac2, + 0xfb1d, + 0xfb3e, + 0x10808, + 0x1083c, + 0x10a00, + 0x11176, + 0x111da, + 0x1133d, + 0x114c7, + 0x11644, + 0x118ff, + 0x16f50, + 0x1d4a2, + 0x1d4bb, + 0x1d546, + 0x1ee24, + 0x1ee27, + 0x1ee39, + 0x1ee3b, + 0x1ee42, + 0x1ee47, + 0x1ee49, + 0x1ee4b, + 0x1ee54, + 0x1ee57, + 0x1ee59, + 0x1ee5b, + 0x1ee5d, + 0x1ee5f, + 0x1ee64, + 0x1ee7e, +}; + +} // !namespace + +bool isalpha(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, isalphar, nelem (isalphar)/2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = rbsearch(c, isalphas, nelem (isalphas), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t isupperr[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03d2, 0x03d4, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x210b, 0x210d, + 0x2110, 0x2112, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x2130, 0x2133, + 0x213e, 0x213f, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xa7aa, 0xa7ad, + 0xa7b0, 0xa7b1, + 0xff21, 0xff3a, + 0x10400, 0x10427, + 0x118a0, 0x118bf, + 0x1d400, 0x1d419, + 0x1d434, 0x1d44d, + 0x1d468, 0x1d481, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b5, + 0x1d4d0, 0x1d4e9, + 0x1d504, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d538, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d56c, 0x1d585, + 0x1d5a0, 0x1d5b9, + 0x1d5d4, 0x1d5ed, + 0x1d608, 0x1d621, + 0x1d63c, 0x1d655, + 0x1d670, 0x1d689, + 0x1d6a8, 0x1d6c0, + 0x1d6e2, 0x1d6fa, + 0x1d71c, 0x1d734, + 0x1d756, 0x1d76e, + 0x1d790, 0x1d7a8, +}; + +} // !namespace + +namespace { + +const char32_t isuppers[] = { + 0x0100, + 0x0102, + 0x0104, + 0x0106, + 0x0108, + 0x010a, + 0x010c, + 0x010e, + 0x0110, + 0x0112, + 0x0114, + 0x0116, + 0x0118, + 0x011a, + 0x011c, + 0x011e, + 0x0120, + 0x0122, + 0x0124, + 0x0126, + 0x0128, + 0x012a, + 0x012c, + 0x012e, + 0x0130, + 0x0132, + 0x0134, + 0x0136, + 0x0139, + 0x013b, + 0x013d, + 0x013f, + 0x0141, + 0x0143, + 0x0145, + 0x0147, + 0x014a, + 0x014c, + 0x014e, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x015a, + 0x015c, + 0x015e, + 0x0160, + 0x0162, + 0x0164, + 0x0166, + 0x0168, + 0x016a, + 0x016c, + 0x016e, + 0x0170, + 0x0172, + 0x0174, + 0x0176, + 0x017b, + 0x017d, + 0x0184, + 0x01a2, + 0x01a4, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c4, + 0x01c7, + 0x01ca, + 0x01cd, + 0x01cf, + 0x01d1, + 0x01d3, + 0x01d5, + 0x01d7, + 0x01d9, + 0x01db, + 0x01de, + 0x01e0, + 0x01e2, + 0x01e4, + 0x01e6, + 0x01e8, + 0x01ea, + 0x01ec, + 0x01ee, + 0x01f1, + 0x01f4, + 0x01fa, + 0x01fc, + 0x01fe, + 0x0200, + 0x0202, + 0x0204, + 0x0206, + 0x0208, + 0x020a, + 0x020c, + 0x020e, + 0x0210, + 0x0212, + 0x0214, + 0x0216, + 0x0218, + 0x021a, + 0x021c, + 0x021e, + 0x0220, + 0x0222, + 0x0224, + 0x0226, + 0x0228, + 0x022a, + 0x022c, + 0x022e, + 0x0230, + 0x0232, + 0x0241, + 0x0248, + 0x024a, + 0x024c, + 0x024e, + 0x0370, + 0x0372, + 0x0376, + 0x037f, + 0x0386, + 0x038c, + 0x03cf, + 0x03d8, + 0x03da, + 0x03dc, + 0x03de, + 0x03e0, + 0x03e2, + 0x03e4, + 0x03e6, + 0x03e8, + 0x03ea, + 0x03ec, + 0x03ee, + 0x03f4, + 0x03f7, + 0x0460, + 0x0462, + 0x0464, + 0x0466, + 0x0468, + 0x046a, + 0x046c, + 0x046e, + 0x0470, + 0x0472, + 0x0474, + 0x0476, + 0x0478, + 0x047a, + 0x047c, + 0x047e, + 0x0480, + 0x048a, + 0x048c, + 0x048e, + 0x0490, + 0x0492, + 0x0494, + 0x0496, + 0x0498, + 0x049a, + 0x049c, + 0x049e, + 0x04a0, + 0x04a2, + 0x04a4, + 0x04a6, + 0x04a8, + 0x04aa, + 0x04ac, + 0x04ae, + 0x04b0, + 0x04b2, + 0x04b4, + 0x04b6, + 0x04b8, + 0x04ba, + 0x04bc, + 0x04be, + 0x04c3, + 0x04c5, + 0x04c7, + 0x04c9, + 0x04cb, + 0x04cd, + 0x04d0, + 0x04d2, + 0x04d4, + 0x04d6, + 0x04d8, + 0x04da, + 0x04dc, + 0x04de, + 0x04e0, + 0x04e2, + 0x04e4, + 0x04e6, + 0x04e8, + 0x04ea, + 0x04ec, + 0x04ee, + 0x04f0, + 0x04f2, + 0x04f4, + 0x04f6, + 0x04f8, + 0x04fa, + 0x04fc, + 0x04fe, + 0x0500, + 0x0502, + 0x0504, + 0x0506, + 0x0508, + 0x050a, + 0x050c, + 0x050e, + 0x0510, + 0x0512, + 0x0514, + 0x0516, + 0x0518, + 0x051a, + 0x051c, + 0x051e, + 0x0520, + 0x0522, + 0x0524, + 0x0526, + 0x0528, + 0x052a, + 0x052c, + 0x052e, + 0x10c7, + 0x10cd, + 0x1e00, + 0x1e02, + 0x1e04, + 0x1e06, + 0x1e08, + 0x1e0a, + 0x1e0c, + 0x1e0e, + 0x1e10, + 0x1e12, + 0x1e14, + 0x1e16, + 0x1e18, + 0x1e1a, + 0x1e1c, + 0x1e1e, + 0x1e20, + 0x1e22, + 0x1e24, + 0x1e26, + 0x1e28, + 0x1e2a, + 0x1e2c, + 0x1e2e, + 0x1e30, + 0x1e32, + 0x1e34, + 0x1e36, + 0x1e38, + 0x1e3a, + 0x1e3c, + 0x1e3e, + 0x1e40, + 0x1e42, + 0x1e44, + 0x1e46, + 0x1e48, + 0x1e4a, + 0x1e4c, + 0x1e4e, + 0x1e50, + 0x1e52, + 0x1e54, + 0x1e56, + 0x1e58, + 0x1e5a, + 0x1e5c, + 0x1e5e, + 0x1e60, + 0x1e62, + 0x1e64, + 0x1e66, + 0x1e68, + 0x1e6a, + 0x1e6c, + 0x1e6e, + 0x1e70, + 0x1e72, + 0x1e74, + 0x1e76, + 0x1e78, + 0x1e7a, + 0x1e7c, + 0x1e7e, + 0x1e80, + 0x1e82, + 0x1e84, + 0x1e86, + 0x1e88, + 0x1e8a, + 0x1e8c, + 0x1e8e, + 0x1e90, + 0x1e92, + 0x1e94, + 0x1e9e, + 0x1ea0, + 0x1ea2, + 0x1ea4, + 0x1ea6, + 0x1ea8, + 0x1eaa, + 0x1eac, + 0x1eae, + 0x1eb0, + 0x1eb2, + 0x1eb4, + 0x1eb6, + 0x1eb8, + 0x1eba, + 0x1ebc, + 0x1ebe, + 0x1ec0, + 0x1ec2, + 0x1ec4, + 0x1ec6, + 0x1ec8, + 0x1eca, + 0x1ecc, + 0x1ece, + 0x1ed0, + 0x1ed2, + 0x1ed4, + 0x1ed6, + 0x1ed8, + 0x1eda, + 0x1edc, + 0x1ede, + 0x1ee0, + 0x1ee2, + 0x1ee4, + 0x1ee6, + 0x1ee8, + 0x1eea, + 0x1eec, + 0x1eee, + 0x1ef0, + 0x1ef2, + 0x1ef4, + 0x1ef6, + 0x1ef8, + 0x1efa, + 0x1efc, + 0x1efe, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1f5f, + 0x2102, + 0x2107, + 0x2115, + 0x2124, + 0x2126, + 0x2128, + 0x2145, + 0x2183, + 0x2c60, + 0x2c67, + 0x2c69, + 0x2c6b, + 0x2c72, + 0x2c75, + 0x2c82, + 0x2c84, + 0x2c86, + 0x2c88, + 0x2c8a, + 0x2c8c, + 0x2c8e, + 0x2c90, + 0x2c92, + 0x2c94, + 0x2c96, + 0x2c98, + 0x2c9a, + 0x2c9c, + 0x2c9e, + 0x2ca0, + 0x2ca2, + 0x2ca4, + 0x2ca6, + 0x2ca8, + 0x2caa, + 0x2cac, + 0x2cae, + 0x2cb0, + 0x2cb2, + 0x2cb4, + 0x2cb6, + 0x2cb8, + 0x2cba, + 0x2cbc, + 0x2cbe, + 0x2cc0, + 0x2cc2, + 0x2cc4, + 0x2cc6, + 0x2cc8, + 0x2cca, + 0x2ccc, + 0x2cce, + 0x2cd0, + 0x2cd2, + 0x2cd4, + 0x2cd6, + 0x2cd8, + 0x2cda, + 0x2cdc, + 0x2cde, + 0x2ce0, + 0x2ce2, + 0x2ceb, + 0x2ced, + 0x2cf2, + 0xa640, + 0xa642, + 0xa644, + 0xa646, + 0xa648, + 0xa64a, + 0xa64c, + 0xa64e, + 0xa650, + 0xa652, + 0xa654, + 0xa656, + 0xa658, + 0xa65a, + 0xa65c, + 0xa65e, + 0xa660, + 0xa662, + 0xa664, + 0xa666, + 0xa668, + 0xa66a, + 0xa66c, + 0xa680, + 0xa682, + 0xa684, + 0xa686, + 0xa688, + 0xa68a, + 0xa68c, + 0xa68e, + 0xa690, + 0xa692, + 0xa694, + 0xa696, + 0xa698, + 0xa69a, + 0xa722, + 0xa724, + 0xa726, + 0xa728, + 0xa72a, + 0xa72c, + 0xa72e, + 0xa732, + 0xa734, + 0xa736, + 0xa738, + 0xa73a, + 0xa73c, + 0xa73e, + 0xa740, + 0xa742, + 0xa744, + 0xa746, + 0xa748, + 0xa74a, + 0xa74c, + 0xa74e, + 0xa750, + 0xa752, + 0xa754, + 0xa756, + 0xa758, + 0xa75a, + 0xa75c, + 0xa75e, + 0xa760, + 0xa762, + 0xa764, + 0xa766, + 0xa768, + 0xa76a, + 0xa76c, + 0xa76e, + 0xa779, + 0xa77b, + 0xa780, + 0xa782, + 0xa784, + 0xa786, + 0xa78b, + 0xa78d, + 0xa790, + 0xa792, + 0xa796, + 0xa798, + 0xa79a, + 0xa79c, + 0xa79e, + 0xa7a0, + 0xa7a2, + 0xa7a4, + 0xa7a6, + 0xa7a8, + 0x1d49c, + 0x1d4a2, + 0x1d546, + 0x1d7ca, +}; + +} // !namespace + +bool isupper(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, isupperr, nelem (isupperr)/2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = rbsearch(c, isuppers, nelem (isuppers), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t islowerr[] = { + 0x0061, 0x007a, + 0x00df, 0x00f6, + 0x00f8, 0x00ff, + 0x0137, 0x0138, + 0x0148, 0x0149, + 0x017e, 0x0180, + 0x018c, 0x018d, + 0x0199, 0x019b, + 0x01aa, 0x01ab, + 0x01b9, 0x01ba, + 0x01bd, 0x01bf, + 0x01dc, 0x01dd, + 0x01ef, 0x01f0, + 0x0233, 0x0239, + 0x023f, 0x0240, + 0x024f, 0x0293, + 0x0295, 0x02af, + 0x037b, 0x037d, + 0x03ac, 0x03ce, + 0x03d0, 0x03d1, + 0x03d5, 0x03d7, + 0x03ef, 0x03f3, + 0x03fb, 0x03fc, + 0x0430, 0x045f, + 0x04ce, 0x04cf, + 0x0561, 0x0587, + 0x1d00, 0x1d2b, + 0x1d6b, 0x1d77, + 0x1d79, 0x1d9a, + 0x1e95, 0x1e9d, + 0x1eff, 0x1f07, + 0x1f10, 0x1f15, + 0x1f20, 0x1f27, + 0x1f30, 0x1f37, + 0x1f40, 0x1f45, + 0x1f50, 0x1f57, + 0x1f60, 0x1f67, + 0x1f70, 0x1f7d, + 0x1f80, 0x1f87, + 0x1f90, 0x1f97, + 0x1fa0, 0x1fa7, + 0x1fb0, 0x1fb4, + 0x1fb6, 0x1fb7, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fc7, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fd7, + 0x1fe0, 0x1fe7, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ff7, + 0x210e, 0x210f, + 0x213c, 0x213d, + 0x2146, 0x2149, + 0x2170, 0x217f, + 0x24d0, 0x24e9, + 0x2c30, 0x2c5e, + 0x2c65, 0x2c66, + 0x2c73, 0x2c74, + 0x2c76, 0x2c7b, + 0x2ce3, 0x2ce4, + 0x2d00, 0x2d25, + 0xa72f, 0xa731, + 0xa771, 0xa778, + 0xa793, 0xa795, + 0xab30, 0xab5a, + 0xab64, 0xab65, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xff41, 0xff5a, + 0x10428, 0x1044f, + 0x118c0, 0x118df, + 0x1d41a, 0x1d433, + 0x1d44e, 0x1d454, + 0x1d456, 0x1d467, + 0x1d482, 0x1d49b, + 0x1d4b6, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d4cf, + 0x1d4ea, 0x1d503, + 0x1d51e, 0x1d537, + 0x1d552, 0x1d56b, + 0x1d586, 0x1d59f, + 0x1d5ba, 0x1d5d3, + 0x1d5ee, 0x1d607, + 0x1d622, 0x1d63b, + 0x1d656, 0x1d66f, + 0x1d68a, 0x1d6a5, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6e1, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d71b, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d755, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d78f, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7c9, +}; + +} // !namespace + +namespace { + +const char32_t islowers[] = { + 0x00b5, + 0x0101, + 0x0103, + 0x0105, + 0x0107, + 0x0109, + 0x010b, + 0x010d, + 0x010f, + 0x0111, + 0x0113, + 0x0115, + 0x0117, + 0x0119, + 0x011b, + 0x011d, + 0x011f, + 0x0121, + 0x0123, + 0x0125, + 0x0127, + 0x0129, + 0x012b, + 0x012d, + 0x012f, + 0x0131, + 0x0133, + 0x0135, + 0x013a, + 0x013c, + 0x013e, + 0x0140, + 0x0142, + 0x0144, + 0x0146, + 0x014b, + 0x014d, + 0x014f, + 0x0151, + 0x0153, + 0x0155, + 0x0157, + 0x0159, + 0x015b, + 0x015d, + 0x015f, + 0x0161, + 0x0163, + 0x0165, + 0x0167, + 0x0169, + 0x016b, + 0x016d, + 0x016f, + 0x0171, + 0x0173, + 0x0175, + 0x0177, + 0x017a, + 0x017c, + 0x0183, + 0x0185, + 0x0188, + 0x0192, + 0x0195, + 0x019e, + 0x01a1, + 0x01a3, + 0x01a5, + 0x01a8, + 0x01ad, + 0x01b0, + 0x01b4, + 0x01b6, + 0x01c6, + 0x01c9, + 0x01cc, + 0x01ce, + 0x01d0, + 0x01d2, + 0x01d4, + 0x01d6, + 0x01d8, + 0x01da, + 0x01df, + 0x01e1, + 0x01e3, + 0x01e5, + 0x01e7, + 0x01e9, + 0x01eb, + 0x01ed, + 0x01f3, + 0x01f5, + 0x01f9, + 0x01fb, + 0x01fd, + 0x01ff, + 0x0201, + 0x0203, + 0x0205, + 0x0207, + 0x0209, + 0x020b, + 0x020d, + 0x020f, + 0x0211, + 0x0213, + 0x0215, + 0x0217, + 0x0219, + 0x021b, + 0x021d, + 0x021f, + 0x0221, + 0x0223, + 0x0225, + 0x0227, + 0x0229, + 0x022b, + 0x022d, + 0x022f, + 0x0231, + 0x023c, + 0x0242, + 0x0247, + 0x0249, + 0x024b, + 0x024d, + 0x0371, + 0x0373, + 0x0377, + 0x0390, + 0x03d9, + 0x03db, + 0x03dd, + 0x03df, + 0x03e1, + 0x03e3, + 0x03e5, + 0x03e7, + 0x03e9, + 0x03eb, + 0x03ed, + 0x03f5, + 0x03f8, + 0x0461, + 0x0463, + 0x0465, + 0x0467, + 0x0469, + 0x046b, + 0x046d, + 0x046f, + 0x0471, + 0x0473, + 0x0475, + 0x0477, + 0x0479, + 0x047b, + 0x047d, + 0x047f, + 0x0481, + 0x048b, + 0x048d, + 0x048f, + 0x0491, + 0x0493, + 0x0495, + 0x0497, + 0x0499, + 0x049b, + 0x049d, + 0x049f, + 0x04a1, + 0x04a3, + 0x04a5, + 0x04a7, + 0x04a9, + 0x04ab, + 0x04ad, + 0x04af, + 0x04b1, + 0x04b3, + 0x04b5, + 0x04b7, + 0x04b9, + 0x04bb, + 0x04bd, + 0x04bf, + 0x04c2, + 0x04c4, + 0x04c6, + 0x04c8, + 0x04ca, + 0x04cc, + 0x04d1, + 0x04d3, + 0x04d5, + 0x04d7, + 0x04d9, + 0x04db, + 0x04dd, + 0x04df, + 0x04e1, + 0x04e3, + 0x04e5, + 0x04e7, + 0x04e9, + 0x04eb, + 0x04ed, + 0x04ef, + 0x04f1, + 0x04f3, + 0x04f5, + 0x04f7, + 0x04f9, + 0x04fb, + 0x04fd, + 0x04ff, + 0x0501, + 0x0503, + 0x0505, + 0x0507, + 0x0509, + 0x050b, + 0x050d, + 0x050f, + 0x0511, + 0x0513, + 0x0515, + 0x0517, + 0x0519, + 0x051b, + 0x051d, + 0x051f, + 0x0521, + 0x0523, + 0x0525, + 0x0527, + 0x0529, + 0x052b, + 0x052d, + 0x052f, + 0x1e01, + 0x1e03, + 0x1e05, + 0x1e07, + 0x1e09, + 0x1e0b, + 0x1e0d, + 0x1e0f, + 0x1e11, + 0x1e13, + 0x1e15, + 0x1e17, + 0x1e19, + 0x1e1b, + 0x1e1d, + 0x1e1f, + 0x1e21, + 0x1e23, + 0x1e25, + 0x1e27, + 0x1e29, + 0x1e2b, + 0x1e2d, + 0x1e2f, + 0x1e31, + 0x1e33, + 0x1e35, + 0x1e37, + 0x1e39, + 0x1e3b, + 0x1e3d, + 0x1e3f, + 0x1e41, + 0x1e43, + 0x1e45, + 0x1e47, + 0x1e49, + 0x1e4b, + 0x1e4d, + 0x1e4f, + 0x1e51, + 0x1e53, + 0x1e55, + 0x1e57, + 0x1e59, + 0x1e5b, + 0x1e5d, + 0x1e5f, + 0x1e61, + 0x1e63, + 0x1e65, + 0x1e67, + 0x1e69, + 0x1e6b, + 0x1e6d, + 0x1e6f, + 0x1e71, + 0x1e73, + 0x1e75, + 0x1e77, + 0x1e79, + 0x1e7b, + 0x1e7d, + 0x1e7f, + 0x1e81, + 0x1e83, + 0x1e85, + 0x1e87, + 0x1e89, + 0x1e8b, + 0x1e8d, + 0x1e8f, + 0x1e91, + 0x1e93, + 0x1e9f, + 0x1ea1, + 0x1ea3, + 0x1ea5, + 0x1ea7, + 0x1ea9, + 0x1eab, + 0x1ead, + 0x1eaf, + 0x1eb1, + 0x1eb3, + 0x1eb5, + 0x1eb7, + 0x1eb9, + 0x1ebb, + 0x1ebd, + 0x1ebf, + 0x1ec1, + 0x1ec3, + 0x1ec5, + 0x1ec7, + 0x1ec9, + 0x1ecb, + 0x1ecd, + 0x1ecf, + 0x1ed1, + 0x1ed3, + 0x1ed5, + 0x1ed7, + 0x1ed9, + 0x1edb, + 0x1edd, + 0x1edf, + 0x1ee1, + 0x1ee3, + 0x1ee5, + 0x1ee7, + 0x1ee9, + 0x1eeb, + 0x1eed, + 0x1eef, + 0x1ef1, + 0x1ef3, + 0x1ef5, + 0x1ef7, + 0x1ef9, + 0x1efb, + 0x1efd, + 0x1fbe, + 0x210a, + 0x2113, + 0x212f, + 0x2134, + 0x2139, + 0x214e, + 0x2184, + 0x2c61, + 0x2c68, + 0x2c6a, + 0x2c6c, + 0x2c71, + 0x2c81, + 0x2c83, + 0x2c85, + 0x2c87, + 0x2c89, + 0x2c8b, + 0x2c8d, + 0x2c8f, + 0x2c91, + 0x2c93, + 0x2c95, + 0x2c97, + 0x2c99, + 0x2c9b, + 0x2c9d, + 0x2c9f, + 0x2ca1, + 0x2ca3, + 0x2ca5, + 0x2ca7, + 0x2ca9, + 0x2cab, + 0x2cad, + 0x2caf, + 0x2cb1, + 0x2cb3, + 0x2cb5, + 0x2cb7, + 0x2cb9, + 0x2cbb, + 0x2cbd, + 0x2cbf, + 0x2cc1, + 0x2cc3, + 0x2cc5, + 0x2cc7, + 0x2cc9, + 0x2ccb, + 0x2ccd, + 0x2ccf, + 0x2cd1, + 0x2cd3, + 0x2cd5, + 0x2cd7, + 0x2cd9, + 0x2cdb, + 0x2cdd, + 0x2cdf, + 0x2ce1, + 0x2cec, + 0x2cee, + 0x2cf3, + 0x2d27, + 0x2d2d, + 0xa641, + 0xa643, + 0xa645, + 0xa647, + 0xa649, + 0xa64b, + 0xa64d, + 0xa64f, + 0xa651, + 0xa653, + 0xa655, + 0xa657, + 0xa659, + 0xa65b, + 0xa65d, + 0xa65f, + 0xa661, + 0xa663, + 0xa665, + 0xa667, + 0xa669, + 0xa66b, + 0xa66d, + 0xa681, + 0xa683, + 0xa685, + 0xa687, + 0xa689, + 0xa68b, + 0xa68d, + 0xa68f, + 0xa691, + 0xa693, + 0xa695, + 0xa697, + 0xa699, + 0xa69b, + 0xa723, + 0xa725, + 0xa727, + 0xa729, + 0xa72b, + 0xa72d, + 0xa733, + 0xa735, + 0xa737, + 0xa739, + 0xa73b, + 0xa73d, + 0xa73f, + 0xa741, + 0xa743, + 0xa745, + 0xa747, + 0xa749, + 0xa74b, + 0xa74d, + 0xa74f, + 0xa751, + 0xa753, + 0xa755, + 0xa757, + 0xa759, + 0xa75b, + 0xa75d, + 0xa75f, + 0xa761, + 0xa763, + 0xa765, + 0xa767, + 0xa769, + 0xa76b, + 0xa76d, + 0xa76f, + 0xa77a, + 0xa77c, + 0xa77f, + 0xa781, + 0xa783, + 0xa785, + 0xa787, + 0xa78c, + 0xa78e, + 0xa791, + 0xa797, + 0xa799, + 0xa79b, + 0xa79d, + 0xa79f, + 0xa7a1, + 0xa7a3, + 0xa7a5, + 0xa7a7, + 0xa7a9, + 0xa7fa, + 0x1d4bb, + 0x1d7cb, +}; + +} // !namespace + +bool islower(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, islowerr, nelem (islowerr)/2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = rbsearch(c, islowers, nelem (islowers), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t istitler[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xa7aa, 0xa7ad, + 0xa7b0, 0xa7b1, + 0xff21, 0xff3a, + 0x10400, 0x10427, + 0x118a0, 0x118bf, +}; + +} // !namespace + +namespace { + +const char32_t istitles[] = { + 0x0100, + 0x0102, + 0x0104, + 0x0106, + 0x0108, + 0x010a, + 0x010c, + 0x010e, + 0x0110, + 0x0112, + 0x0114, + 0x0116, + 0x0118, + 0x011a, + 0x011c, + 0x011e, + 0x0120, + 0x0122, + 0x0124, + 0x0126, + 0x0128, + 0x012a, + 0x012c, + 0x012e, + 0x0132, + 0x0134, + 0x0136, + 0x0139, + 0x013b, + 0x013d, + 0x013f, + 0x0141, + 0x0143, + 0x0145, + 0x0147, + 0x014a, + 0x014c, + 0x014e, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x015a, + 0x015c, + 0x015e, + 0x0160, + 0x0162, + 0x0164, + 0x0166, + 0x0168, + 0x016a, + 0x016c, + 0x016e, + 0x0170, + 0x0172, + 0x0174, + 0x0176, + 0x017b, + 0x017d, + 0x0184, + 0x01a2, + 0x01a4, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c5, + 0x01c8, + 0x01cb, + 0x01cd, + 0x01cf, + 0x01d1, + 0x01d3, + 0x01d5, + 0x01d7, + 0x01d9, + 0x01db, + 0x01de, + 0x01e0, + 0x01e2, + 0x01e4, + 0x01e6, + 0x01e8, + 0x01ea, + 0x01ec, + 0x01ee, + 0x01f2, + 0x01f4, + 0x01fa, + 0x01fc, + 0x01fe, + 0x0200, + 0x0202, + 0x0204, + 0x0206, + 0x0208, + 0x020a, + 0x020c, + 0x020e, + 0x0210, + 0x0212, + 0x0214, + 0x0216, + 0x0218, + 0x021a, + 0x021c, + 0x021e, + 0x0220, + 0x0222, + 0x0224, + 0x0226, + 0x0228, + 0x022a, + 0x022c, + 0x022e, + 0x0230, + 0x0232, + 0x0241, + 0x0248, + 0x024a, + 0x024c, + 0x024e, + 0x0370, + 0x0372, + 0x0376, + 0x037f, + 0x0386, + 0x038c, + 0x03cf, + 0x03d8, + 0x03da, + 0x03dc, + 0x03de, + 0x03e0, + 0x03e2, + 0x03e4, + 0x03e6, + 0x03e8, + 0x03ea, + 0x03ec, + 0x03ee, + 0x03f7, + 0x0460, + 0x0462, + 0x0464, + 0x0466, + 0x0468, + 0x046a, + 0x046c, + 0x046e, + 0x0470, + 0x0472, + 0x0474, + 0x0476, + 0x0478, + 0x047a, + 0x047c, + 0x047e, + 0x0480, + 0x048a, + 0x048c, + 0x048e, + 0x0490, + 0x0492, + 0x0494, + 0x0496, + 0x0498, + 0x049a, + 0x049c, + 0x049e, + 0x04a0, + 0x04a2, + 0x04a4, + 0x04a6, + 0x04a8, + 0x04aa, + 0x04ac, + 0x04ae, + 0x04b0, + 0x04b2, + 0x04b4, + 0x04b6, + 0x04b8, + 0x04ba, + 0x04bc, + 0x04be, + 0x04c3, + 0x04c5, + 0x04c7, + 0x04c9, + 0x04cb, + 0x04cd, + 0x04d0, + 0x04d2, + 0x04d4, + 0x04d6, + 0x04d8, + 0x04da, + 0x04dc, + 0x04de, + 0x04e0, + 0x04e2, + 0x04e4, + 0x04e6, + 0x04e8, + 0x04ea, + 0x04ec, + 0x04ee, + 0x04f0, + 0x04f2, + 0x04f4, + 0x04f6, + 0x04f8, + 0x04fa, + 0x04fc, + 0x04fe, + 0x0500, + 0x0502, + 0x0504, + 0x0506, + 0x0508, + 0x050a, + 0x050c, + 0x050e, + 0x0510, + 0x0512, + 0x0514, + 0x0516, + 0x0518, + 0x051a, + 0x051c, + 0x051e, + 0x0520, + 0x0522, + 0x0524, + 0x0526, + 0x0528, + 0x052a, + 0x052c, + 0x052e, + 0x10c7, + 0x10cd, + 0x1e00, + 0x1e02, + 0x1e04, + 0x1e06, + 0x1e08, + 0x1e0a, + 0x1e0c, + 0x1e0e, + 0x1e10, + 0x1e12, + 0x1e14, + 0x1e16, + 0x1e18, + 0x1e1a, + 0x1e1c, + 0x1e1e, + 0x1e20, + 0x1e22, + 0x1e24, + 0x1e26, + 0x1e28, + 0x1e2a, + 0x1e2c, + 0x1e2e, + 0x1e30, + 0x1e32, + 0x1e34, + 0x1e36, + 0x1e38, + 0x1e3a, + 0x1e3c, + 0x1e3e, + 0x1e40, + 0x1e42, + 0x1e44, + 0x1e46, + 0x1e48, + 0x1e4a, + 0x1e4c, + 0x1e4e, + 0x1e50, + 0x1e52, + 0x1e54, + 0x1e56, + 0x1e58, + 0x1e5a, + 0x1e5c, + 0x1e5e, + 0x1e60, + 0x1e62, + 0x1e64, + 0x1e66, + 0x1e68, + 0x1e6a, + 0x1e6c, + 0x1e6e, + 0x1e70, + 0x1e72, + 0x1e74, + 0x1e76, + 0x1e78, + 0x1e7a, + 0x1e7c, + 0x1e7e, + 0x1e80, + 0x1e82, + 0x1e84, + 0x1e86, + 0x1e88, + 0x1e8a, + 0x1e8c, + 0x1e8e, + 0x1e90, + 0x1e92, + 0x1e94, + 0x1ea0, + 0x1ea2, + 0x1ea4, + 0x1ea6, + 0x1ea8, + 0x1eaa, + 0x1eac, + 0x1eae, + 0x1eb0, + 0x1eb2, + 0x1eb4, + 0x1eb6, + 0x1eb8, + 0x1eba, + 0x1ebc, + 0x1ebe, + 0x1ec0, + 0x1ec2, + 0x1ec4, + 0x1ec6, + 0x1ec8, + 0x1eca, + 0x1ecc, + 0x1ece, + 0x1ed0, + 0x1ed2, + 0x1ed4, + 0x1ed6, + 0x1ed8, + 0x1eda, + 0x1edc, + 0x1ede, + 0x1ee0, + 0x1ee2, + 0x1ee4, + 0x1ee6, + 0x1ee8, + 0x1eea, + 0x1eec, + 0x1eee, + 0x1ef0, + 0x1ef2, + 0x1ef4, + 0x1ef6, + 0x1ef8, + 0x1efa, + 0x1efc, + 0x1efe, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1f5f, + 0x2132, + 0x2183, + 0x2c60, + 0x2c67, + 0x2c69, + 0x2c6b, + 0x2c72, + 0x2c75, + 0x2c82, + 0x2c84, + 0x2c86, + 0x2c88, + 0x2c8a, + 0x2c8c, + 0x2c8e, + 0x2c90, + 0x2c92, + 0x2c94, + 0x2c96, + 0x2c98, + 0x2c9a, + 0x2c9c, + 0x2c9e, + 0x2ca0, + 0x2ca2, + 0x2ca4, + 0x2ca6, + 0x2ca8, + 0x2caa, + 0x2cac, + 0x2cae, + 0x2cb0, + 0x2cb2, + 0x2cb4, + 0x2cb6, + 0x2cb8, + 0x2cba, + 0x2cbc, + 0x2cbe, + 0x2cc0, + 0x2cc2, + 0x2cc4, + 0x2cc6, + 0x2cc8, + 0x2cca, + 0x2ccc, + 0x2cce, + 0x2cd0, + 0x2cd2, + 0x2cd4, + 0x2cd6, + 0x2cd8, + 0x2cda, + 0x2cdc, + 0x2cde, + 0x2ce0, + 0x2ce2, + 0x2ceb, + 0x2ced, + 0x2cf2, + 0xa640, + 0xa642, + 0xa644, + 0xa646, + 0xa648, + 0xa64a, + 0xa64c, + 0xa64e, + 0xa650, + 0xa652, + 0xa654, + 0xa656, + 0xa658, + 0xa65a, + 0xa65c, + 0xa65e, + 0xa660, + 0xa662, + 0xa664, + 0xa666, + 0xa668, + 0xa66a, + 0xa66c, + 0xa680, + 0xa682, + 0xa684, + 0xa686, + 0xa688, + 0xa68a, + 0xa68c, + 0xa68e, + 0xa690, + 0xa692, + 0xa694, + 0xa696, + 0xa698, + 0xa69a, + 0xa722, + 0xa724, + 0xa726, + 0xa728, + 0xa72a, + 0xa72c, + 0xa72e, + 0xa732, + 0xa734, + 0xa736, + 0xa738, + 0xa73a, + 0xa73c, + 0xa73e, + 0xa740, + 0xa742, + 0xa744, + 0xa746, + 0xa748, + 0xa74a, + 0xa74c, + 0xa74e, + 0xa750, + 0xa752, + 0xa754, + 0xa756, + 0xa758, + 0xa75a, + 0xa75c, + 0xa75e, + 0xa760, + 0xa762, + 0xa764, + 0xa766, + 0xa768, + 0xa76a, + 0xa76c, + 0xa76e, + 0xa779, + 0xa77b, + 0xa780, + 0xa782, + 0xa784, + 0xa786, + 0xa78b, + 0xa78d, + 0xa790, + 0xa792, + 0xa796, + 0xa798, + 0xa79a, + 0xa79c, + 0xa79e, + 0xa7a0, + 0xa7a2, + 0xa7a4, + 0xa7a6, + 0xa7a8, +}; + +} // !namespace + +bool istitle(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, istitler, nelem (istitler)/2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = rbsearch(c, istitles, nelem (istitles), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +namespace { + +const char32_t toupperr[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, + 0x118c0, 0x118df, 1048544, +}; + +} // !namespace + +namespace { + +const char32_t touppers[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0101, 1048575, + 0x0103, 1048575, + 0x0105, 1048575, + 0x0107, 1048575, + 0x0109, 1048575, + 0x010b, 1048575, + 0x010d, 1048575, + 0x010f, 1048575, + 0x0111, 1048575, + 0x0113, 1048575, + 0x0115, 1048575, + 0x0117, 1048575, + 0x0119, 1048575, + 0x011b, 1048575, + 0x011d, 1048575, + 0x011f, 1048575, + 0x0121, 1048575, + 0x0123, 1048575, + 0x0125, 1048575, + 0x0127, 1048575, + 0x0129, 1048575, + 0x012b, 1048575, + 0x012d, 1048575, + 0x012f, 1048575, + 0x0131, 1048344, + 0x0133, 1048575, + 0x0135, 1048575, + 0x0137, 1048575, + 0x013a, 1048575, + 0x013c, 1048575, + 0x013e, 1048575, + 0x0140, 1048575, + 0x0142, 1048575, + 0x0144, 1048575, + 0x0146, 1048575, + 0x0148, 1048575, + 0x014b, 1048575, + 0x014d, 1048575, + 0x014f, 1048575, + 0x0151, 1048575, + 0x0153, 1048575, + 0x0155, 1048575, + 0x0157, 1048575, + 0x0159, 1048575, + 0x015b, 1048575, + 0x015d, 1048575, + 0x015f, 1048575, + 0x0161, 1048575, + 0x0163, 1048575, + 0x0165, 1048575, + 0x0167, 1048575, + 0x0169, 1048575, + 0x016b, 1048575, + 0x016d, 1048575, + 0x016f, 1048575, + 0x0171, 1048575, + 0x0173, 1048575, + 0x0175, 1048575, + 0x0177, 1048575, + 0x017a, 1048575, + 0x017c, 1048575, + 0x017e, 1048575, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0183, 1048575, + 0x0185, 1048575, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a1, 1048575, + 0x01a3, 1048575, + 0x01a5, 1048575, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b4, 1048575, + 0x01b6, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c5, 1048575, + 0x01c6, 1048574, + 0x01c8, 1048575, + 0x01c9, 1048574, + 0x01cb, 1048575, + 0x01cc, 1048574, + 0x01ce, 1048575, + 0x01d0, 1048575, + 0x01d2, 1048575, + 0x01d4, 1048575, + 0x01d6, 1048575, + 0x01d8, 1048575, + 0x01da, 1048575, + 0x01dc, 1048575, + 0x01dd, 1048497, + 0x01df, 1048575, + 0x01e1, 1048575, + 0x01e3, 1048575, + 0x01e5, 1048575, + 0x01e7, 1048575, + 0x01e9, 1048575, + 0x01eb, 1048575, + 0x01ed, 1048575, + 0x01ef, 1048575, + 0x01f2, 1048575, + 0x01f3, 1048574, + 0x01f5, 1048575, + 0x01f9, 1048575, + 0x01fb, 1048575, + 0x01fd, 1048575, + 0x01ff, 1048575, + 0x0201, 1048575, + 0x0203, 1048575, + 0x0205, 1048575, + 0x0207, 1048575, + 0x0209, 1048575, + 0x020b, 1048575, + 0x020d, 1048575, + 0x020f, 1048575, + 0x0211, 1048575, + 0x0213, 1048575, + 0x0215, 1048575, + 0x0217, 1048575, + 0x0219, 1048575, + 0x021b, 1048575, + 0x021d, 1048575, + 0x021f, 1048575, + 0x0223, 1048575, + 0x0225, 1048575, + 0x0227, 1048575, + 0x0229, 1048575, + 0x022b, 1048575, + 0x022d, 1048575, + 0x022f, 1048575, + 0x0231, 1048575, + 0x0233, 1048575, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0247, 1048575, + 0x0249, 1048575, + 0x024b, 1048575, + 0x024d, 1048575, + 0x024f, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x025c, 1090895, + 0x0260, 1048371, + 0x0261, 1090891, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0266, 1090884, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026c, 1090881, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0287, 1090858, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x029e, 1090834, + 0x0345, 1048660, + 0x0371, 1048575, + 0x0373, 1048575, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03d9, 1048575, + 0x03db, 1048575, + 0x03dd, 1048575, + 0x03df, 1048575, + 0x03e1, 1048575, + 0x03e3, 1048575, + 0x03e5, 1048575, + 0x03e7, 1048575, + 0x03e9, 1048575, + 0x03eb, 1048575, + 0x03ed, 1048575, + 0x03ef, 1048575, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f3, 1048460, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x0461, 1048575, + 0x0463, 1048575, + 0x0465, 1048575, + 0x0467, 1048575, + 0x0469, 1048575, + 0x046b, 1048575, + 0x046d, 1048575, + 0x046f, 1048575, + 0x0471, 1048575, + 0x0473, 1048575, + 0x0475, 1048575, + 0x0477, 1048575, + 0x0479, 1048575, + 0x047b, 1048575, + 0x047d, 1048575, + 0x047f, 1048575, + 0x0481, 1048575, + 0x048b, 1048575, + 0x048d, 1048575, + 0x048f, 1048575, + 0x0491, 1048575, + 0x0493, 1048575, + 0x0495, 1048575, + 0x0497, 1048575, + 0x0499, 1048575, + 0x049b, 1048575, + 0x049d, 1048575, + 0x049f, 1048575, + 0x04a1, 1048575, + 0x04a3, 1048575, + 0x04a5, 1048575, + 0x04a7, 1048575, + 0x04a9, 1048575, + 0x04ab, 1048575, + 0x04ad, 1048575, + 0x04af, 1048575, + 0x04b1, 1048575, + 0x04b3, 1048575, + 0x04b5, 1048575, + 0x04b7, 1048575, + 0x04b9, 1048575, + 0x04bb, 1048575, + 0x04bd, 1048575, + 0x04bf, 1048575, + 0x04c2, 1048575, + 0x04c4, 1048575, + 0x04c6, 1048575, + 0x04c8, 1048575, + 0x04ca, 1048575, + 0x04cc, 1048575, + 0x04ce, 1048575, + 0x04cf, 1048561, + 0x04d1, 1048575, + 0x04d3, 1048575, + 0x04d5, 1048575, + 0x04d7, 1048575, + 0x04d9, 1048575, + 0x04db, 1048575, + 0x04dd, 1048575, + 0x04df, 1048575, + 0x04e1, 1048575, + 0x04e3, 1048575, + 0x04e5, 1048575, + 0x04e7, 1048575, + 0x04e9, 1048575, + 0x04eb, 1048575, + 0x04ed, 1048575, + 0x04ef, 1048575, + 0x04f1, 1048575, + 0x04f3, 1048575, + 0x04f5, 1048575, + 0x04f7, 1048575, + 0x04f9, 1048575, + 0x04fb, 1048575, + 0x04fd, 1048575, + 0x04ff, 1048575, + 0x0501, 1048575, + 0x0503, 1048575, + 0x0505, 1048575, + 0x0507, 1048575, + 0x0509, 1048575, + 0x050b, 1048575, + 0x050d, 1048575, + 0x050f, 1048575, + 0x0511, 1048575, + 0x0513, 1048575, + 0x0515, 1048575, + 0x0517, 1048575, + 0x0519, 1048575, + 0x051b, 1048575, + 0x051d, 1048575, + 0x051f, 1048575, + 0x0521, 1048575, + 0x0523, 1048575, + 0x0525, 1048575, + 0x0527, 1048575, + 0x0529, 1048575, + 0x052b, 1048575, + 0x052d, 1048575, + 0x052f, 1048575, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e01, 1048575, + 0x1e03, 1048575, + 0x1e05, 1048575, + 0x1e07, 1048575, + 0x1e09, 1048575, + 0x1e0b, 1048575, + 0x1e0d, 1048575, + 0x1e0f, 1048575, + 0x1e11, 1048575, + 0x1e13, 1048575, + 0x1e15, 1048575, + 0x1e17, 1048575, + 0x1e19, 1048575, + 0x1e1b, 1048575, + 0x1e1d, 1048575, + 0x1e1f, 1048575, + 0x1e21, 1048575, + 0x1e23, 1048575, + 0x1e25, 1048575, + 0x1e27, 1048575, + 0x1e29, 1048575, + 0x1e2b, 1048575, + 0x1e2d, 1048575, + 0x1e2f, 1048575, + 0x1e31, 1048575, + 0x1e33, 1048575, + 0x1e35, 1048575, + 0x1e37, 1048575, + 0x1e39, 1048575, + 0x1e3b, 1048575, + 0x1e3d, 1048575, + 0x1e3f, 1048575, + 0x1e41, 1048575, + 0x1e43, 1048575, + 0x1e45, 1048575, + 0x1e47, 1048575, + 0x1e49, 1048575, + 0x1e4b, 1048575, + 0x1e4d, 1048575, + 0x1e4f, 1048575, + 0x1e51, 1048575, + 0x1e53, 1048575, + 0x1e55, 1048575, + 0x1e57, 1048575, + 0x1e59, 1048575, + 0x1e5b, 1048575, + 0x1e5d, 1048575, + 0x1e5f, 1048575, + 0x1e61, 1048575, + 0x1e63, 1048575, + 0x1e65, 1048575, + 0x1e67, 1048575, + 0x1e69, 1048575, + 0x1e6b, 1048575, + 0x1e6d, 1048575, + 0x1e6f, 1048575, + 0x1e71, 1048575, + 0x1e73, 1048575, + 0x1e75, 1048575, + 0x1e77, 1048575, + 0x1e79, 1048575, + 0x1e7b, 1048575, + 0x1e7d, 1048575, + 0x1e7f, 1048575, + 0x1e81, 1048575, + 0x1e83, 1048575, + 0x1e85, 1048575, + 0x1e87, 1048575, + 0x1e89, 1048575, + 0x1e8b, 1048575, + 0x1e8d, 1048575, + 0x1e8f, 1048575, + 0x1e91, 1048575, + 0x1e93, 1048575, + 0x1e95, 1048575, + 0x1e9b, 1048517, + 0x1ea1, 1048575, + 0x1ea3, 1048575, + 0x1ea5, 1048575, + 0x1ea7, 1048575, + 0x1ea9, 1048575, + 0x1eab, 1048575, + 0x1ead, 1048575, + 0x1eaf, 1048575, + 0x1eb1, 1048575, + 0x1eb3, 1048575, + 0x1eb5, 1048575, + 0x1eb7, 1048575, + 0x1eb9, 1048575, + 0x1ebb, 1048575, + 0x1ebd, 1048575, + 0x1ebf, 1048575, + 0x1ec1, 1048575, + 0x1ec3, 1048575, + 0x1ec5, 1048575, + 0x1ec7, 1048575, + 0x1ec9, 1048575, + 0x1ecb, 1048575, + 0x1ecd, 1048575, + 0x1ecf, 1048575, + 0x1ed1, 1048575, + 0x1ed3, 1048575, + 0x1ed5, 1048575, + 0x1ed7, 1048575, + 0x1ed9, 1048575, + 0x1edb, 1048575, + 0x1edd, 1048575, + 0x1edf, 1048575, + 0x1ee1, 1048575, + 0x1ee3, 1048575, + 0x1ee5, 1048575, + 0x1ee7, 1048575, + 0x1ee9, 1048575, + 0x1eeb, 1048575, + 0x1eed, 1048575, + 0x1eef, 1048575, + 0x1ef1, 1048575, + 0x1ef3, 1048575, + 0x1ef5, 1048575, + 0x1ef7, 1048575, + 0x1ef9, 1048575, + 0x1efb, 1048575, + 0x1efd, 1048575, + 0x1eff, 1048575, + 0x1f51, 1048584, + 0x1f53, 1048584, + 0x1f55, 1048584, + 0x1f57, 1048584, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c68, 1048575, + 0x2c6a, 1048575, + 0x2c6c, 1048575, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0x2c81, 1048575, + 0x2c83, 1048575, + 0x2c85, 1048575, + 0x2c87, 1048575, + 0x2c89, 1048575, + 0x2c8b, 1048575, + 0x2c8d, 1048575, + 0x2c8f, 1048575, + 0x2c91, 1048575, + 0x2c93, 1048575, + 0x2c95, 1048575, + 0x2c97, 1048575, + 0x2c99, 1048575, + 0x2c9b, 1048575, + 0x2c9d, 1048575, + 0x2c9f, 1048575, + 0x2ca1, 1048575, + 0x2ca3, 1048575, + 0x2ca5, 1048575, + 0x2ca7, 1048575, + 0x2ca9, 1048575, + 0x2cab, 1048575, + 0x2cad, 1048575, + 0x2caf, 1048575, + 0x2cb1, 1048575, + 0x2cb3, 1048575, + 0x2cb5, 1048575, + 0x2cb7, 1048575, + 0x2cb9, 1048575, + 0x2cbb, 1048575, + 0x2cbd, 1048575, + 0x2cbf, 1048575, + 0x2cc1, 1048575, + 0x2cc3, 1048575, + 0x2cc5, 1048575, + 0x2cc7, 1048575, + 0x2cc9, 1048575, + 0x2ccb, 1048575, + 0x2ccd, 1048575, + 0x2ccf, 1048575, + 0x2cd1, 1048575, + 0x2cd3, 1048575, + 0x2cd5, 1048575, + 0x2cd7, 1048575, + 0x2cd9, 1048575, + 0x2cdb, 1048575, + 0x2cdd, 1048575, + 0x2cdf, 1048575, + 0x2ce1, 1048575, + 0x2ce3, 1048575, + 0x2cec, 1048575, + 0x2cee, 1048575, + 0x2cf3, 1048575, + 0x2d27, 1041312, + 0x2d2d, 1041312, + 0xa641, 1048575, + 0xa643, 1048575, + 0xa645, 1048575, + 0xa647, 1048575, + 0xa649, 1048575, + 0xa64b, 1048575, + 0xa64d, 1048575, + 0xa64f, 1048575, + 0xa651, 1048575, + 0xa653, 1048575, + 0xa655, 1048575, + 0xa657, 1048575, + 0xa659, 1048575, + 0xa65b, 1048575, + 0xa65d, 1048575, + 0xa65f, 1048575, + 0xa661, 1048575, + 0xa663, 1048575, + 0xa665, 1048575, + 0xa667, 1048575, + 0xa669, 1048575, + 0xa66b, 1048575, + 0xa66d, 1048575, + 0xa681, 1048575, + 0xa683, 1048575, + 0xa685, 1048575, + 0xa687, 1048575, + 0xa689, 1048575, + 0xa68b, 1048575, + 0xa68d, 1048575, + 0xa68f, 1048575, + 0xa691, 1048575, + 0xa693, 1048575, + 0xa695, 1048575, + 0xa697, 1048575, + 0xa699, 1048575, + 0xa69b, 1048575, + 0xa723, 1048575, + 0xa725, 1048575, + 0xa727, 1048575, + 0xa729, 1048575, + 0xa72b, 1048575, + 0xa72d, 1048575, + 0xa72f, 1048575, + 0xa733, 1048575, + 0xa735, 1048575, + 0xa737, 1048575, + 0xa739, 1048575, + 0xa73b, 1048575, + 0xa73d, 1048575, + 0xa73f, 1048575, + 0xa741, 1048575, + 0xa743, 1048575, + 0xa745, 1048575, + 0xa747, 1048575, + 0xa749, 1048575, + 0xa74b, 1048575, + 0xa74d, 1048575, + 0xa74f, 1048575, + 0xa751, 1048575, + 0xa753, 1048575, + 0xa755, 1048575, + 0xa757, 1048575, + 0xa759, 1048575, + 0xa75b, 1048575, + 0xa75d, 1048575, + 0xa75f, 1048575, + 0xa761, 1048575, + 0xa763, 1048575, + 0xa765, 1048575, + 0xa767, 1048575, + 0xa769, 1048575, + 0xa76b, 1048575, + 0xa76d, 1048575, + 0xa76f, 1048575, + 0xa77a, 1048575, + 0xa77c, 1048575, + 0xa77f, 1048575, + 0xa781, 1048575, + 0xa783, 1048575, + 0xa785, 1048575, + 0xa787, 1048575, + 0xa78c, 1048575, + 0xa791, 1048575, + 0xa793, 1048575, + 0xa797, 1048575, + 0xa799, 1048575, + 0xa79b, 1048575, + 0xa79d, 1048575, + 0xa79f, 1048575, + 0xa7a1, 1048575, + 0xa7a3, 1048575, + 0xa7a5, 1048575, + 0xa7a7, 1048575, + 0xa7a9, 1048575, +}; + +} // !namespace + +char32_t toupper(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, toupperr, nelem (toupperr)/3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = rbsearch(c, touppers, nelem (touppers)/2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +namespace { + +const char32_t tolowerr[] = { + 0x0041, 0x005a, 1048608, + 0x00c0, 0x00d6, 1048608, + 0x00d8, 0x00de, 1048608, + 0x0189, 0x018a, 1048781, + 0x01b1, 0x01b2, 1048793, + 0x0388, 0x038a, 1048613, + 0x038e, 0x038f, 1048639, + 0x0391, 0x03a1, 1048608, + 0x03a3, 0x03ab, 1048608, + 0x03fd, 0x03ff, 1048446, + 0x0400, 0x040f, 1048656, + 0x0410, 0x042f, 1048608, + 0x0531, 0x0556, 1048624, + 0x10a0, 0x10c5, 1055840, + 0x1f08, 0x1f0f, 1048568, + 0x1f18, 0x1f1d, 1048568, + 0x1f28, 0x1f2f, 1048568, + 0x1f38, 0x1f3f, 1048568, + 0x1f48, 0x1f4d, 1048568, + 0x1f68, 0x1f6f, 1048568, + 0x1f88, 0x1f8f, 1048568, + 0x1f98, 0x1f9f, 1048568, + 0x1fa8, 0x1faf, 1048568, + 0x1fb8, 0x1fb9, 1048568, + 0x1fba, 0x1fbb, 1048502, + 0x1fc8, 0x1fcb, 1048490, + 0x1fd8, 0x1fd9, 1048568, + 0x1fda, 0x1fdb, 1048476, + 0x1fe8, 0x1fe9, 1048568, + 0x1fea, 0x1feb, 1048464, + 0x1ff8, 0x1ff9, 1048448, + 0x1ffa, 0x1ffb, 1048450, + 0x2160, 0x216f, 1048592, + 0x24b6, 0x24cf, 1048602, + 0x2c00, 0x2c2e, 1048624, + 0x2c7e, 0x2c7f, 1037761, + 0xff21, 0xff3a, 1048608, + 0x10400, 0x10427, 1048616, + 0x118a0, 0x118bf, 1048608, +}; + +} // !namespace + +namespace { + +const char32_t tolowers[] = { + 0x0100, 1048577, + 0x0102, 1048577, + 0x0104, 1048577, + 0x0106, 1048577, + 0x0108, 1048577, + 0x010a, 1048577, + 0x010c, 1048577, + 0x010e, 1048577, + 0x0110, 1048577, + 0x0112, 1048577, + 0x0114, 1048577, + 0x0116, 1048577, + 0x0118, 1048577, + 0x011a, 1048577, + 0x011c, 1048577, + 0x011e, 1048577, + 0x0120, 1048577, + 0x0122, 1048577, + 0x0124, 1048577, + 0x0126, 1048577, + 0x0128, 1048577, + 0x012a, 1048577, + 0x012c, 1048577, + 0x012e, 1048577, + 0x0130, 1048377, + 0x0132, 1048577, + 0x0134, 1048577, + 0x0136, 1048577, + 0x0139, 1048577, + 0x013b, 1048577, + 0x013d, 1048577, + 0x013f, 1048577, + 0x0141, 1048577, + 0x0143, 1048577, + 0x0145, 1048577, + 0x0147, 1048577, + 0x014a, 1048577, + 0x014c, 1048577, + 0x014e, 1048577, + 0x0150, 1048577, + 0x0152, 1048577, + 0x0154, 1048577, + 0x0156, 1048577, + 0x0158, 1048577, + 0x015a, 1048577, + 0x015c, 1048577, + 0x015e, 1048577, + 0x0160, 1048577, + 0x0162, 1048577, + 0x0164, 1048577, + 0x0166, 1048577, + 0x0168, 1048577, + 0x016a, 1048577, + 0x016c, 1048577, + 0x016e, 1048577, + 0x0170, 1048577, + 0x0172, 1048577, + 0x0174, 1048577, + 0x0176, 1048577, + 0x0178, 1048455, + 0x0179, 1048577, + 0x017b, 1048577, + 0x017d, 1048577, + 0x0181, 1048786, + 0x0182, 1048577, + 0x0184, 1048577, + 0x0186, 1048782, + 0x0187, 1048577, + 0x018b, 1048577, + 0x018e, 1048655, + 0x018f, 1048778, + 0x0190, 1048779, + 0x0191, 1048577, + 0x0193, 1048781, + 0x0194, 1048783, + 0x0196, 1048787, + 0x0197, 1048785, + 0x0198, 1048577, + 0x019c, 1048787, + 0x019d, 1048789, + 0x019f, 1048790, + 0x01a0, 1048577, + 0x01a2, 1048577, + 0x01a4, 1048577, + 0x01a6, 1048794, + 0x01a7, 1048577, + 0x01a9, 1048794, + 0x01ac, 1048577, + 0x01ae, 1048794, + 0x01af, 1048577, + 0x01b3, 1048577, + 0x01b5, 1048577, + 0x01b7, 1048795, + 0x01b8, 1048577, + 0x01bc, 1048577, + 0x01c4, 1048578, + 0x01c5, 1048577, + 0x01c7, 1048578, + 0x01c8, 1048577, + 0x01ca, 1048578, + 0x01cb, 1048577, + 0x01cd, 1048577, + 0x01cf, 1048577, + 0x01d1, 1048577, + 0x01d3, 1048577, + 0x01d5, 1048577, + 0x01d7, 1048577, + 0x01d9, 1048577, + 0x01db, 1048577, + 0x01de, 1048577, + 0x01e0, 1048577, + 0x01e2, 1048577, + 0x01e4, 1048577, + 0x01e6, 1048577, + 0x01e8, 1048577, + 0x01ea, 1048577, + 0x01ec, 1048577, + 0x01ee, 1048577, + 0x01f1, 1048578, + 0x01f2, 1048577, + 0x01f4, 1048577, + 0x01f6, 1048479, + 0x01f7, 1048520, + 0x01f8, 1048577, + 0x01fa, 1048577, + 0x01fc, 1048577, + 0x01fe, 1048577, + 0x0200, 1048577, + 0x0202, 1048577, + 0x0204, 1048577, + 0x0206, 1048577, + 0x0208, 1048577, + 0x020a, 1048577, + 0x020c, 1048577, + 0x020e, 1048577, + 0x0210, 1048577, + 0x0212, 1048577, + 0x0214, 1048577, + 0x0216, 1048577, + 0x0218, 1048577, + 0x021a, 1048577, + 0x021c, 1048577, + 0x021e, 1048577, + 0x0220, 1048446, + 0x0222, 1048577, + 0x0224, 1048577, + 0x0226, 1048577, + 0x0228, 1048577, + 0x022a, 1048577, + 0x022c, 1048577, + 0x022e, 1048577, + 0x0230, 1048577, + 0x0232, 1048577, + 0x023a, 1059371, + 0x023b, 1048577, + 0x023d, 1048413, + 0x023e, 1059368, + 0x0241, 1048577, + 0x0243, 1048381, + 0x0244, 1048645, + 0x0245, 1048647, + 0x0246, 1048577, + 0x0248, 1048577, + 0x024a, 1048577, + 0x024c, 1048577, + 0x024e, 1048577, + 0x0370, 1048577, + 0x0372, 1048577, + 0x0376, 1048577, + 0x037f, 1048692, + 0x0386, 1048614, + 0x038c, 1048640, + 0x03cf, 1048584, + 0x03d8, 1048577, + 0x03da, 1048577, + 0x03dc, 1048577, + 0x03de, 1048577, + 0x03e0, 1048577, + 0x03e2, 1048577, + 0x03e4, 1048577, + 0x03e6, 1048577, + 0x03e8, 1048577, + 0x03ea, 1048577, + 0x03ec, 1048577, + 0x03ee, 1048577, + 0x03f4, 1048516, + 0x03f7, 1048577, + 0x03f9, 1048569, + 0x03fa, 1048577, + 0x0460, 1048577, + 0x0462, 1048577, + 0x0464, 1048577, + 0x0466, 1048577, + 0x0468, 1048577, + 0x046a, 1048577, + 0x046c, 1048577, + 0x046e, 1048577, + 0x0470, 1048577, + 0x0472, 1048577, + 0x0474, 1048577, + 0x0476, 1048577, + 0x0478, 1048577, + 0x047a, 1048577, + 0x047c, 1048577, + 0x047e, 1048577, + 0x0480, 1048577, + 0x048a, 1048577, + 0x048c, 1048577, + 0x048e, 1048577, + 0x0490, 1048577, + 0x0492, 1048577, + 0x0494, 1048577, + 0x0496, 1048577, + 0x0498, 1048577, + 0x049a, 1048577, + 0x049c, 1048577, + 0x049e, 1048577, + 0x04a0, 1048577, + 0x04a2, 1048577, + 0x04a4, 1048577, + 0x04a6, 1048577, + 0x04a8, 1048577, + 0x04aa, 1048577, + 0x04ac, 1048577, + 0x04ae, 1048577, + 0x04b0, 1048577, + 0x04b2, 1048577, + 0x04b4, 1048577, + 0x04b6, 1048577, + 0x04b8, 1048577, + 0x04ba, 1048577, + 0x04bc, 1048577, + 0x04be, 1048577, + 0x04c0, 1048591, + 0x04c1, 1048577, + 0x04c3, 1048577, + 0x04c5, 1048577, + 0x04c7, 1048577, + 0x04c9, 1048577, + 0x04cb, 1048577, + 0x04cd, 1048577, + 0x04d0, 1048577, + 0x04d2, 1048577, + 0x04d4, 1048577, + 0x04d6, 1048577, + 0x04d8, 1048577, + 0x04da, 1048577, + 0x04dc, 1048577, + 0x04de, 1048577, + 0x04e0, 1048577, + 0x04e2, 1048577, + 0x04e4, 1048577, + 0x04e6, 1048577, + 0x04e8, 1048577, + 0x04ea, 1048577, + 0x04ec, 1048577, + 0x04ee, 1048577, + 0x04f0, 1048577, + 0x04f2, 1048577, + 0x04f4, 1048577, + 0x04f6, 1048577, + 0x04f8, 1048577, + 0x04fa, 1048577, + 0x04fc, 1048577, + 0x04fe, 1048577, + 0x0500, 1048577, + 0x0502, 1048577, + 0x0504, 1048577, + 0x0506, 1048577, + 0x0508, 1048577, + 0x050a, 1048577, + 0x050c, 1048577, + 0x050e, 1048577, + 0x0510, 1048577, + 0x0512, 1048577, + 0x0514, 1048577, + 0x0516, 1048577, + 0x0518, 1048577, + 0x051a, 1048577, + 0x051c, 1048577, + 0x051e, 1048577, + 0x0520, 1048577, + 0x0522, 1048577, + 0x0524, 1048577, + 0x0526, 1048577, + 0x0528, 1048577, + 0x052a, 1048577, + 0x052c, 1048577, + 0x052e, 1048577, + 0x10c7, 1055840, + 0x10cd, 1055840, + 0x1e00, 1048577, + 0x1e02, 1048577, + 0x1e04, 1048577, + 0x1e06, 1048577, + 0x1e08, 1048577, + 0x1e0a, 1048577, + 0x1e0c, 1048577, + 0x1e0e, 1048577, + 0x1e10, 1048577, + 0x1e12, 1048577, + 0x1e14, 1048577, + 0x1e16, 1048577, + 0x1e18, 1048577, + 0x1e1a, 1048577, + 0x1e1c, 1048577, + 0x1e1e, 1048577, + 0x1e20, 1048577, + 0x1e22, 1048577, + 0x1e24, 1048577, + 0x1e26, 1048577, + 0x1e28, 1048577, + 0x1e2a, 1048577, + 0x1e2c, 1048577, + 0x1e2e, 1048577, + 0x1e30, 1048577, + 0x1e32, 1048577, + 0x1e34, 1048577, + 0x1e36, 1048577, + 0x1e38, 1048577, + 0x1e3a, 1048577, + 0x1e3c, 1048577, + 0x1e3e, 1048577, + 0x1e40, 1048577, + 0x1e42, 1048577, + 0x1e44, 1048577, + 0x1e46, 1048577, + 0x1e48, 1048577, + 0x1e4a, 1048577, + 0x1e4c, 1048577, + 0x1e4e, 1048577, + 0x1e50, 1048577, + 0x1e52, 1048577, + 0x1e54, 1048577, + 0x1e56, 1048577, + 0x1e58, 1048577, + 0x1e5a, 1048577, + 0x1e5c, 1048577, + 0x1e5e, 1048577, + 0x1e60, 1048577, + 0x1e62, 1048577, + 0x1e64, 1048577, + 0x1e66, 1048577, + 0x1e68, 1048577, + 0x1e6a, 1048577, + 0x1e6c, 1048577, + 0x1e6e, 1048577, + 0x1e70, 1048577, + 0x1e72, 1048577, + 0x1e74, 1048577, + 0x1e76, 1048577, + 0x1e78, 1048577, + 0x1e7a, 1048577, + 0x1e7c, 1048577, + 0x1e7e, 1048577, + 0x1e80, 1048577, + 0x1e82, 1048577, + 0x1e84, 1048577, + 0x1e86, 1048577, + 0x1e88, 1048577, + 0x1e8a, 1048577, + 0x1e8c, 1048577, + 0x1e8e, 1048577, + 0x1e90, 1048577, + 0x1e92, 1048577, + 0x1e94, 1048577, + 0x1e9e, 1040961, + 0x1ea0, 1048577, + 0x1ea2, 1048577, + 0x1ea4, 1048577, + 0x1ea6, 1048577, + 0x1ea8, 1048577, + 0x1eaa, 1048577, + 0x1eac, 1048577, + 0x1eae, 1048577, + 0x1eb0, 1048577, + 0x1eb2, 1048577, + 0x1eb4, 1048577, + 0x1eb6, 1048577, + 0x1eb8, 1048577, + 0x1eba, 1048577, + 0x1ebc, 1048577, + 0x1ebe, 1048577, + 0x1ec0, 1048577, + 0x1ec2, 1048577, + 0x1ec4, 1048577, + 0x1ec6, 1048577, + 0x1ec8, 1048577, + 0x1eca, 1048577, + 0x1ecc, 1048577, + 0x1ece, 1048577, + 0x1ed0, 1048577, + 0x1ed2, 1048577, + 0x1ed4, 1048577, + 0x1ed6, 1048577, + 0x1ed8, 1048577, + 0x1eda, 1048577, + 0x1edc, 1048577, + 0x1ede, 1048577, + 0x1ee0, 1048577, + 0x1ee2, 1048577, + 0x1ee4, 1048577, + 0x1ee6, 1048577, + 0x1ee8, 1048577, + 0x1eea, 1048577, + 0x1eec, 1048577, + 0x1eee, 1048577, + 0x1ef0, 1048577, + 0x1ef2, 1048577, + 0x1ef4, 1048577, + 0x1ef6, 1048577, + 0x1ef8, 1048577, + 0x1efa, 1048577, + 0x1efc, 1048577, + 0x1efe, 1048577, + 0x1f59, 1048568, + 0x1f5b, 1048568, + 0x1f5d, 1048568, + 0x1f5f, 1048568, + 0x1fbc, 1048567, + 0x1fcc, 1048567, + 0x1fec, 1048569, + 0x1ffc, 1048567, + 0x2126, 1041059, + 0x212a, 1040193, + 0x212b, 1040314, + 0x2132, 1048604, + 0x2183, 1048577, + 0x2c60, 1048577, + 0x2c62, 1037833, + 0x2c63, 1044762, + 0x2c64, 1037849, + 0x2c67, 1048577, + 0x2c69, 1048577, + 0x2c6b, 1048577, + 0x2c6d, 1037796, + 0x2c6e, 1037827, + 0x2c6f, 1037793, + 0x2c70, 1037794, + 0x2c72, 1048577, + 0x2c75, 1048577, + 0x2c80, 1048577, + 0x2c82, 1048577, + 0x2c84, 1048577, + 0x2c86, 1048577, + 0x2c88, 1048577, + 0x2c8a, 1048577, + 0x2c8c, 1048577, + 0x2c8e, 1048577, + 0x2c90, 1048577, + 0x2c92, 1048577, + 0x2c94, 1048577, + 0x2c96, 1048577, + 0x2c98, 1048577, + 0x2c9a, 1048577, + 0x2c9c, 1048577, + 0x2c9e, 1048577, + 0x2ca0, 1048577, + 0x2ca2, 1048577, + 0x2ca4, 1048577, + 0x2ca6, 1048577, + 0x2ca8, 1048577, + 0x2caa, 1048577, + 0x2cac, 1048577, + 0x2cae, 1048577, + 0x2cb0, 1048577, + 0x2cb2, 1048577, + 0x2cb4, 1048577, + 0x2cb6, 1048577, + 0x2cb8, 1048577, + 0x2cba, 1048577, + 0x2cbc, 1048577, + 0x2cbe, 1048577, + 0x2cc0, 1048577, + 0x2cc2, 1048577, + 0x2cc4, 1048577, + 0x2cc6, 1048577, + 0x2cc8, 1048577, + 0x2cca, 1048577, + 0x2ccc, 1048577, + 0x2cce, 1048577, + 0x2cd0, 1048577, + 0x2cd2, 1048577, + 0x2cd4, 1048577, + 0x2cd6, 1048577, + 0x2cd8, 1048577, + 0x2cda, 1048577, + 0x2cdc, 1048577, + 0x2cde, 1048577, + 0x2ce0, 1048577, + 0x2ce2, 1048577, + 0x2ceb, 1048577, + 0x2ced, 1048577, + 0x2cf2, 1048577, + 0xa640, 1048577, + 0xa642, 1048577, + 0xa644, 1048577, + 0xa646, 1048577, + 0xa648, 1048577, + 0xa64a, 1048577, + 0xa64c, 1048577, + 0xa64e, 1048577, + 0xa650, 1048577, + 0xa652, 1048577, + 0xa654, 1048577, + 0xa656, 1048577, + 0xa658, 1048577, + 0xa65a, 1048577, + 0xa65c, 1048577, + 0xa65e, 1048577, + 0xa660, 1048577, + 0xa662, 1048577, + 0xa664, 1048577, + 0xa666, 1048577, + 0xa668, 1048577, + 0xa66a, 1048577, + 0xa66c, 1048577, + 0xa680, 1048577, + 0xa682, 1048577, + 0xa684, 1048577, + 0xa686, 1048577, + 0xa688, 1048577, + 0xa68a, 1048577, + 0xa68c, 1048577, + 0xa68e, 1048577, + 0xa690, 1048577, + 0xa692, 1048577, + 0xa694, 1048577, + 0xa696, 1048577, + 0xa698, 1048577, + 0xa69a, 1048577, + 0xa722, 1048577, + 0xa724, 1048577, + 0xa726, 1048577, + 0xa728, 1048577, + 0xa72a, 1048577, + 0xa72c, 1048577, + 0xa72e, 1048577, + 0xa732, 1048577, + 0xa734, 1048577, + 0xa736, 1048577, + 0xa738, 1048577, + 0xa73a, 1048577, + 0xa73c, 1048577, + 0xa73e, 1048577, + 0xa740, 1048577, + 0xa742, 1048577, + 0xa744, 1048577, + 0xa746, 1048577, + 0xa748, 1048577, + 0xa74a, 1048577, + 0xa74c, 1048577, + 0xa74e, 1048577, + 0xa750, 1048577, + 0xa752, 1048577, + 0xa754, 1048577, + 0xa756, 1048577, + 0xa758, 1048577, + 0xa75a, 1048577, + 0xa75c, 1048577, + 0xa75e, 1048577, + 0xa760, 1048577, + 0xa762, 1048577, + 0xa764, 1048577, + 0xa766, 1048577, + 0xa768, 1048577, + 0xa76a, 1048577, + 0xa76c, 1048577, + 0xa76e, 1048577, + 0xa779, 1048577, + 0xa77b, 1048577, + 0xa77d, 1013244, + 0xa77e, 1048577, + 0xa780, 1048577, + 0xa782, 1048577, + 0xa784, 1048577, + 0xa786, 1048577, + 0xa78b, 1048577, + 0xa78d, 1006296, + 0xa790, 1048577, + 0xa792, 1048577, + 0xa796, 1048577, + 0xa798, 1048577, + 0xa79a, 1048577, + 0xa79c, 1048577, + 0xa79e, 1048577, + 0xa7a0, 1048577, + 0xa7a2, 1048577, + 0xa7a4, 1048577, + 0xa7a6, 1048577, + 0xa7a8, 1048577, + 0xa7aa, 1006268, + 0xa7ab, 1006257, + 0xa7ac, 1006261, + 0xa7ad, 1006271, + 0xa7b0, 1006318, + 0xa7b1, 1006294, +}; + +} // !namespace + +char32_t tolower(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, tolowerr, nelem (tolowerr)/3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = rbsearch(c, tolowers, nelem (tolowers)/2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +namespace { + +const char32_t totitler[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, + 0x118c0, 0x118df, 1048544, +}; + +} // !namespace + +namespace { + +const char32_t totitles[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0101, 1048575, + 0x0103, 1048575, + 0x0105, 1048575, + 0x0107, 1048575, + 0x0109, 1048575, + 0x010b, 1048575, + 0x010d, 1048575, + 0x010f, 1048575, + 0x0111, 1048575, + 0x0113, 1048575, + 0x0115, 1048575, + 0x0117, 1048575, + 0x0119, 1048575, + 0x011b, 1048575, + 0x011d, 1048575, + 0x011f, 1048575, + 0x0121, 1048575, + 0x0123, 1048575, + 0x0125, 1048575, + 0x0127, 1048575, + 0x0129, 1048575, + 0x012b, 1048575, + 0x012d, 1048575, + 0x012f, 1048575, + 0x0131, 1048344, + 0x0133, 1048575, + 0x0135, 1048575, + 0x0137, 1048575, + 0x013a, 1048575, + 0x013c, 1048575, + 0x013e, 1048575, + 0x0140, 1048575, + 0x0142, 1048575, + 0x0144, 1048575, + 0x0146, 1048575, + 0x0148, 1048575, + 0x014b, 1048575, + 0x014d, 1048575, + 0x014f, 1048575, + 0x0151, 1048575, + 0x0153, 1048575, + 0x0155, 1048575, + 0x0157, 1048575, + 0x0159, 1048575, + 0x015b, 1048575, + 0x015d, 1048575, + 0x015f, 1048575, + 0x0161, 1048575, + 0x0163, 1048575, + 0x0165, 1048575, + 0x0167, 1048575, + 0x0169, 1048575, + 0x016b, 1048575, + 0x016d, 1048575, + 0x016f, 1048575, + 0x0171, 1048575, + 0x0173, 1048575, + 0x0175, 1048575, + 0x0177, 1048575, + 0x017a, 1048575, + 0x017c, 1048575, + 0x017e, 1048575, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0183, 1048575, + 0x0185, 1048575, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a1, 1048575, + 0x01a3, 1048575, + 0x01a5, 1048575, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b4, 1048575, + 0x01b6, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c4, 1048577, + 0x01c6, 1048575, + 0x01c7, 1048577, + 0x01c9, 1048575, + 0x01ca, 1048577, + 0x01cc, 1048575, + 0x01ce, 1048575, + 0x01d0, 1048575, + 0x01d2, 1048575, + 0x01d4, 1048575, + 0x01d6, 1048575, + 0x01d8, 1048575, + 0x01da, 1048575, + 0x01dc, 1048575, + 0x01dd, 1048497, + 0x01df, 1048575, + 0x01e1, 1048575, + 0x01e3, 1048575, + 0x01e5, 1048575, + 0x01e7, 1048575, + 0x01e9, 1048575, + 0x01eb, 1048575, + 0x01ed, 1048575, + 0x01ef, 1048575, + 0x01f1, 1048577, + 0x01f3, 1048575, + 0x01f5, 1048575, + 0x01f9, 1048575, + 0x01fb, 1048575, + 0x01fd, 1048575, + 0x01ff, 1048575, + 0x0201, 1048575, + 0x0203, 1048575, + 0x0205, 1048575, + 0x0207, 1048575, + 0x0209, 1048575, + 0x020b, 1048575, + 0x020d, 1048575, + 0x020f, 1048575, + 0x0211, 1048575, + 0x0213, 1048575, + 0x0215, 1048575, + 0x0217, 1048575, + 0x0219, 1048575, + 0x021b, 1048575, + 0x021d, 1048575, + 0x021f, 1048575, + 0x0223, 1048575, + 0x0225, 1048575, + 0x0227, 1048575, + 0x0229, 1048575, + 0x022b, 1048575, + 0x022d, 1048575, + 0x022f, 1048575, + 0x0231, 1048575, + 0x0233, 1048575, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0247, 1048575, + 0x0249, 1048575, + 0x024b, 1048575, + 0x024d, 1048575, + 0x024f, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x025c, 1090895, + 0x0260, 1048371, + 0x0261, 1090891, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0266, 1090884, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026c, 1090881, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0287, 1090858, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x029e, 1090834, + 0x0345, 1048660, + 0x0371, 1048575, + 0x0373, 1048575, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03d9, 1048575, + 0x03db, 1048575, + 0x03dd, 1048575, + 0x03df, 1048575, + 0x03e1, 1048575, + 0x03e3, 1048575, + 0x03e5, 1048575, + 0x03e7, 1048575, + 0x03e9, 1048575, + 0x03eb, 1048575, + 0x03ed, 1048575, + 0x03ef, 1048575, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f3, 1048460, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x0461, 1048575, + 0x0463, 1048575, + 0x0465, 1048575, + 0x0467, 1048575, + 0x0469, 1048575, + 0x046b, 1048575, + 0x046d, 1048575, + 0x046f, 1048575, + 0x0471, 1048575, + 0x0473, 1048575, + 0x0475, 1048575, + 0x0477, 1048575, + 0x0479, 1048575, + 0x047b, 1048575, + 0x047d, 1048575, + 0x047f, 1048575, + 0x0481, 1048575, + 0x048b, 1048575, + 0x048d, 1048575, + 0x048f, 1048575, + 0x0491, 1048575, + 0x0493, 1048575, + 0x0495, 1048575, + 0x0497, 1048575, + 0x0499, 1048575, + 0x049b, 1048575, + 0x049d, 1048575, + 0x049f, 1048575, + 0x04a1, 1048575, + 0x04a3, 1048575, + 0x04a5, 1048575, + 0x04a7, 1048575, + 0x04a9, 1048575, + 0x04ab, 1048575, + 0x04ad, 1048575, + 0x04af, 1048575, + 0x04b1, 1048575, + 0x04b3, 1048575, + 0x04b5, 1048575, + 0x04b7, 1048575, + 0x04b9, 1048575, + 0x04bb, 1048575, + 0x04bd, 1048575, + 0x04bf, 1048575, + 0x04c2, 1048575, + 0x04c4, 1048575, + 0x04c6, 1048575, + 0x04c8, 1048575, + 0x04ca, 1048575, + 0x04cc, 1048575, + 0x04ce, 1048575, + 0x04cf, 1048561, + 0x04d1, 1048575, + 0x04d3, 1048575, + 0x04d5, 1048575, + 0x04d7, 1048575, + 0x04d9, 1048575, + 0x04db, 1048575, + 0x04dd, 1048575, + 0x04df, 1048575, + 0x04e1, 1048575, + 0x04e3, 1048575, + 0x04e5, 1048575, + 0x04e7, 1048575, + 0x04e9, 1048575, + 0x04eb, 1048575, + 0x04ed, 1048575, + 0x04ef, 1048575, + 0x04f1, 1048575, + 0x04f3, 1048575, + 0x04f5, 1048575, + 0x04f7, 1048575, + 0x04f9, 1048575, + 0x04fb, 1048575, + 0x04fd, 1048575, + 0x04ff, 1048575, + 0x0501, 1048575, + 0x0503, 1048575, + 0x0505, 1048575, + 0x0507, 1048575, + 0x0509, 1048575, + 0x050b, 1048575, + 0x050d, 1048575, + 0x050f, 1048575, + 0x0511, 1048575, + 0x0513, 1048575, + 0x0515, 1048575, + 0x0517, 1048575, + 0x0519, 1048575, + 0x051b, 1048575, + 0x051d, 1048575, + 0x051f, 1048575, + 0x0521, 1048575, + 0x0523, 1048575, + 0x0525, 1048575, + 0x0527, 1048575, + 0x0529, 1048575, + 0x052b, 1048575, + 0x052d, 1048575, + 0x052f, 1048575, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e01, 1048575, + 0x1e03, 1048575, + 0x1e05, 1048575, + 0x1e07, 1048575, + 0x1e09, 1048575, + 0x1e0b, 1048575, + 0x1e0d, 1048575, + 0x1e0f, 1048575, + 0x1e11, 1048575, + 0x1e13, 1048575, + 0x1e15, 1048575, + 0x1e17, 1048575, + 0x1e19, 1048575, + 0x1e1b, 1048575, + 0x1e1d, 1048575, + 0x1e1f, 1048575, + 0x1e21, 1048575, + 0x1e23, 1048575, + 0x1e25, 1048575, + 0x1e27, 1048575, + 0x1e29, 1048575, + 0x1e2b, 1048575, + 0x1e2d, 1048575, + 0x1e2f, 1048575, + 0x1e31, 1048575, + 0x1e33, 1048575, + 0x1e35, 1048575, + 0x1e37, 1048575, + 0x1e39, 1048575, + 0x1e3b, 1048575, + 0x1e3d, 1048575, + 0x1e3f, 1048575, + 0x1e41, 1048575, + 0x1e43, 1048575, + 0x1e45, 1048575, + 0x1e47, 1048575, + 0x1e49, 1048575, + 0x1e4b, 1048575, + 0x1e4d, 1048575, + 0x1e4f, 1048575, + 0x1e51, 1048575, + 0x1e53, 1048575, + 0x1e55, 1048575, + 0x1e57, 1048575, + 0x1e59, 1048575, + 0x1e5b, 1048575, + 0x1e5d, 1048575, + 0x1e5f, 1048575, + 0x1e61, 1048575, + 0x1e63, 1048575, + 0x1e65, 1048575, + 0x1e67, 1048575, + 0x1e69, 1048575, + 0x1e6b, 1048575, + 0x1e6d, 1048575, + 0x1e6f, 1048575, + 0x1e71, 1048575, + 0x1e73, 1048575, + 0x1e75, 1048575, + 0x1e77, 1048575, + 0x1e79, 1048575, + 0x1e7b, 1048575, + 0x1e7d, 1048575, + 0x1e7f, 1048575, + 0x1e81, 1048575, + 0x1e83, 1048575, + 0x1e85, 1048575, + 0x1e87, 1048575, + 0x1e89, 1048575, + 0x1e8b, 1048575, + 0x1e8d, 1048575, + 0x1e8f, 1048575, + 0x1e91, 1048575, + 0x1e93, 1048575, + 0x1e95, 1048575, + 0x1e9b, 1048517, + 0x1ea1, 1048575, + 0x1ea3, 1048575, + 0x1ea5, 1048575, + 0x1ea7, 1048575, + 0x1ea9, 1048575, + 0x1eab, 1048575, + 0x1ead, 1048575, + 0x1eaf, 1048575, + 0x1eb1, 1048575, + 0x1eb3, 1048575, + 0x1eb5, 1048575, + 0x1eb7, 1048575, + 0x1eb9, 1048575, + 0x1ebb, 1048575, + 0x1ebd, 1048575, + 0x1ebf, 1048575, + 0x1ec1, 1048575, + 0x1ec3, 1048575, + 0x1ec5, 1048575, + 0x1ec7, 1048575, + 0x1ec9, 1048575, + 0x1ecb, 1048575, + 0x1ecd, 1048575, + 0x1ecf, 1048575, + 0x1ed1, 1048575, + 0x1ed3, 1048575, + 0x1ed5, 1048575, + 0x1ed7, 1048575, + 0x1ed9, 1048575, + 0x1edb, 1048575, + 0x1edd, 1048575, + 0x1edf, 1048575, + 0x1ee1, 1048575, + 0x1ee3, 1048575, + 0x1ee5, 1048575, + 0x1ee7, 1048575, + 0x1ee9, 1048575, + 0x1eeb, 1048575, + 0x1eed, 1048575, + 0x1eef, 1048575, + 0x1ef1, 1048575, + 0x1ef3, 1048575, + 0x1ef5, 1048575, + 0x1ef7, 1048575, + 0x1ef9, 1048575, + 0x1efb, 1048575, + 0x1efd, 1048575, + 0x1eff, 1048575, + 0x1f51, 1048584, + 0x1f53, 1048584, + 0x1f55, 1048584, + 0x1f57, 1048584, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c68, 1048575, + 0x2c6a, 1048575, + 0x2c6c, 1048575, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0x2c81, 1048575, + 0x2c83, 1048575, + 0x2c85, 1048575, + 0x2c87, 1048575, + 0x2c89, 1048575, + 0x2c8b, 1048575, + 0x2c8d, 1048575, + 0x2c8f, 1048575, + 0x2c91, 1048575, + 0x2c93, 1048575, + 0x2c95, 1048575, + 0x2c97, 1048575, + 0x2c99, 1048575, + 0x2c9b, 1048575, + 0x2c9d, 1048575, + 0x2c9f, 1048575, + 0x2ca1, 1048575, + 0x2ca3, 1048575, + 0x2ca5, 1048575, + 0x2ca7, 1048575, + 0x2ca9, 1048575, + 0x2cab, 1048575, + 0x2cad, 1048575, + 0x2caf, 1048575, + 0x2cb1, 1048575, + 0x2cb3, 1048575, + 0x2cb5, 1048575, + 0x2cb7, 1048575, + 0x2cb9, 1048575, + 0x2cbb, 1048575, + 0x2cbd, 1048575, + 0x2cbf, 1048575, + 0x2cc1, 1048575, + 0x2cc3, 1048575, + 0x2cc5, 1048575, + 0x2cc7, 1048575, + 0x2cc9, 1048575, + 0x2ccb, 1048575, + 0x2ccd, 1048575, + 0x2ccf, 1048575, + 0x2cd1, 1048575, + 0x2cd3, 1048575, + 0x2cd5, 1048575, + 0x2cd7, 1048575, + 0x2cd9, 1048575, + 0x2cdb, 1048575, + 0x2cdd, 1048575, + 0x2cdf, 1048575, + 0x2ce1, 1048575, + 0x2ce3, 1048575, + 0x2cec, 1048575, + 0x2cee, 1048575, + 0x2cf3, 1048575, + 0x2d27, 1041312, + 0x2d2d, 1041312, + 0xa641, 1048575, + 0xa643, 1048575, + 0xa645, 1048575, + 0xa647, 1048575, + 0xa649, 1048575, + 0xa64b, 1048575, + 0xa64d, 1048575, + 0xa64f, 1048575, + 0xa651, 1048575, + 0xa653, 1048575, + 0xa655, 1048575, + 0xa657, 1048575, + 0xa659, 1048575, + 0xa65b, 1048575, + 0xa65d, 1048575, + 0xa65f, 1048575, + 0xa661, 1048575, + 0xa663, 1048575, + 0xa665, 1048575, + 0xa667, 1048575, + 0xa669, 1048575, + 0xa66b, 1048575, + 0xa66d, 1048575, + 0xa681, 1048575, + 0xa683, 1048575, + 0xa685, 1048575, + 0xa687, 1048575, + 0xa689, 1048575, + 0xa68b, 1048575, + 0xa68d, 1048575, + 0xa68f, 1048575, + 0xa691, 1048575, + 0xa693, 1048575, + 0xa695, 1048575, + 0xa697, 1048575, + 0xa699, 1048575, + 0xa69b, 1048575, + 0xa723, 1048575, + 0xa725, 1048575, + 0xa727, 1048575, + 0xa729, 1048575, + 0xa72b, 1048575, + 0xa72d, 1048575, + 0xa72f, 1048575, + 0xa733, 1048575, + 0xa735, 1048575, + 0xa737, 1048575, + 0xa739, 1048575, + 0xa73b, 1048575, + 0xa73d, 1048575, + 0xa73f, 1048575, + 0xa741, 1048575, + 0xa743, 1048575, + 0xa745, 1048575, + 0xa747, 1048575, + 0xa749, 1048575, + 0xa74b, 1048575, + 0xa74d, 1048575, + 0xa74f, 1048575, + 0xa751, 1048575, + 0xa753, 1048575, + 0xa755, 1048575, + 0xa757, 1048575, + 0xa759, 1048575, + 0xa75b, 1048575, + 0xa75d, 1048575, + 0xa75f, 1048575, + 0xa761, 1048575, + 0xa763, 1048575, + 0xa765, 1048575, + 0xa767, 1048575, + 0xa769, 1048575, + 0xa76b, 1048575, + 0xa76d, 1048575, + 0xa76f, 1048575, + 0xa77a, 1048575, + 0xa77c, 1048575, + 0xa77f, 1048575, + 0xa781, 1048575, + 0xa783, 1048575, + 0xa785, 1048575, + 0xa787, 1048575, + 0xa78c, 1048575, + 0xa791, 1048575, + 0xa793, 1048575, + 0xa797, 1048575, + 0xa799, 1048575, + 0xa79b, 1048575, + 0xa79d, 1048575, + 0xa79f, 1048575, + 0xa7a1, 1048575, + 0xa7a3, 1048575, + 0xa7a5, 1048575, + 0xa7a7, 1048575, + 0xa7a9, 1048575, +}; + +} // !namespace + +char32_t totitle(char32_t c) noexcept +{ + const char32_t *p; + + p = rbsearch(c, totitler, nelem (totitler)/3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = rbsearch(c, totitles, nelem (totitles)/2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +void encode(char32_t c, char res[5]) noexcept +{ + switch (nbytesPoint(c)) { + case 1: + res[0] = static_cast(c); + res[1] = '\0'; + break; + case 2: + res[0] = 0xC0 | ((c >> 6) & 0x1F); + res[1] = 0x80 | (c & 0x3F); + res[2] = '\0'; + break; + case 3: + res[0] = 0xE0 | ((c >> 12) & 0xF ); + res[1] = 0x80 | ((c >> 6) & 0x3F); + res[2] = 0x80 | (c & 0x3F); + res[3] = '\0'; + break; + case 4: + res[0] = 0xF0 | ((c >> 18) & 0x7 ); + res[1] = 0x80 | ((c >> 12) & 0x3F); + res[2] = 0x80 | ((c >> 6) & 0x3F); + res[3] = 0x80 | (c & 0x3F); + res[4] = '\0'; + break; + default: + break; + } +} + +void decode(char32_t &c, const char *res) noexcept +{ + c = 0; + + switch (nbytesUtf8(res[0])) { + case 1: + c = res[0]; + break; + case 2: + c = (res[0] & 0x1f) << 6; + c |= (res[1] & 0x3f); + break; + case 3: + c = (res[0] & 0x0f) << 12; + c |= (res[1] & 0x3f) << 6; + c |= (res[2] & 0x3f); + break; + case 4: + c = (res[0] & 0x07) << 16; + c |= (res[1] & 0x3f) << 12; + c |= (res[2] & 0x3f) << 6; + c |= (res[3] & 0x3f); + default: + break; + } +} + +int nbytesUtf8(char c) noexcept +{ + if (static_cast(c) <= 127) + return 1; + if ((c & 0xE0) == 0xC0) + return 2; + if ((c & 0xF0) == 0xE0) + return 3; + if ((c & 0xF8) == 0xF0) + return 4; + + return -1; +} + +int nbytesPoint(char32_t c) noexcept +{ + if (c <= 0x7F) + return 1; + if (c <= 0x7FF) + return 2; + if (c <= 0xFFFF) + return 3; + if (c <= 0x1FFFFF) + return 4; + + return -1; +} + +unsigned length(const std::string &str) +{ + unsigned total = 0; + + forEach(str, [&] (char32_t) { + ++ total; + }); + + return total; +} + +std::string toUtf8(const std::u32string &array) +{ + std::string res; + + for (size_t i = 0; i < array.size(); ++i) { + char tmp[5]; + int size = nbytesPoint(array[i]); + + if (size < 0) + throw std::invalid_argument("invalid sequence"); + + encode(array[i], tmp); + res.insert(res.length(), tmp); + } + + return res; +} + +std::u32string toUtf32(const std::string &str) +{ + std::u32string res; + + forEach(str, [&] (char32_t code) { + res.push_back(code); + }); + + return res; +} + +} // !unicode + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/unicode.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/unicode.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,273 @@ +/* + * unicode.hpp -- UTF-8 to UTF-32 conversions and various operations + * + * 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_UNICODE_HPP +#define IRCCD_UNICODE_HPP + +/** + * \file unicode.hpp + * \brief UTF-8 to UTF-32 conversions + * \author David Demelier + * \warning These files are auto-generated! + */ + +#include +#include + +namespace irccd { + +/** + * \brief Unicode namespace. + */ +namespace unicode { + +/** + * Encode the unicode code point into multibyte string. + * + * \param point the unicode code point + * \param res the output buffer + */ +void encode(char32_t point, char res[5]) noexcept; + +/** + * Decode the multibyte buffer into an unicode code point. + * + * \param c the code point destination + * \param res the multibyte string. + */ +void decode(char32_t &c, const char *res) noexcept; + +/** + * Get the number of bytes for the first multi byte character from a + * utf-8 string. + * + * This can be used to iterate a valid UTF-8 string to jump to the next + * real character. + * + * \param c the first multi byte character + * \return the number of bytes [1-4] or -1 if invalid + */ +int nbytesUtf8(char c) noexcept; + +/** + * Get the number of bytes for the unicode point. + * + * \param point the unicode point + * \return the number of bytes [1-4] or -1 if invalid + */ +int nbytesPoint(char32_t point) noexcept; + +/** + * Get real number of character in a string. + * + * \param str the string + * \return the length + * \throw std::invalid_argument on invalid sequence + */ +unsigned length(const std::string &str); + +/** + * Iterate over all real characters in the UTF-8 string. + * + * The function must have the following signature: + * void f(char ch) + * + * \param str the UTF-8 string + * \param function the function callback + * \throw std::invalid_argument on invalid sequence + */ +template +void forEach(const std::string &str, Func function) +{ + for (size_t i = 0; i < str.size(); ) { + char32_t point = 0; + int size = nbytesUtf8(str[i]); + + if (size < 0) + throw std::invalid_argument("invalid sequence"); + + decode(point, str.data() + i); + function(point); + + i += size; + } +} + +/** + * Convert a UTF-32 string to UTF-8 string. + * + * \param array the UTF-32 string + * \return the UTF-8 string + * \throw std::invalid_argument on invalid sequence + */ +std::string toUtf8(const std::u32string &array); + +/** + * Convert a UTF-8 string to UTF-32 string. + * + * \param str the UTF-8 string + * \return the UTF-32 string + * \throw std::invalid_argument on invalid sequence + */ +std::u32string toUtf32(const std::string &str); + +/** + * Check if the unicode character is space. + * + * \param c the character + * \return true if space + */ +bool isspace(char32_t c) noexcept; + +/** + * Check if the unicode character is digit. + * + * \param c the character + * \return true if digit + */ +bool isdigit(char32_t c) noexcept; + +/** + * Check if the unicode character is alpha category. + * + * \param c the character + * \return true if alpha + */ +bool isalpha(char32_t c) noexcept; + +/** + * Check if the unicode character is upper case. + * + * \param c the character + * \return true if upper case + */ +bool isupper(char32_t c) noexcept; + +/** + * Check if the unicode character is lower case. + * + * \param c the character + * \return true if lower case + */ +bool islower(char32_t c) noexcept; + +/** + * Check if the unicode character is title case. + * + * \param c the character + * \return true if title case + */ +bool istitle(char32_t c) noexcept; + +/** + * Convert to upper case. + * + * \param c the character + * \return the upper case character + */ +char32_t toupper(char32_t c) noexcept; + +/** + * Convert to lower case. + * + * \param c the character + * \return the lower case character + */ +char32_t tolower(char32_t c) noexcept; + +/** + * Convert to title case. + * + * \param c the character + * \return the title case character + */ +char32_t totitle(char32_t c) noexcept; + +/** + * Convert the UTF-32 string to upper case. + * + * \param str the str + * \return the upper case string + */ +inline std::u32string toupper(std::u32string str) +{ + for (size_t i = 0; i < str.size(); ++i) + str[i] = toupper(str[i]); + + return str; +} + +/** + * Convert the UTF-8 string to upper case. + * + * \param str the str + * \return the upper case string + * \warning very slow at the moment + */ +inline std::string toupper(const std::string &str) +{ + std::string result; + char buffer[5]; + + forEach(str, [&] (char32_t code) { + encode(toupper(code), buffer); + result += buffer; + }); + + return result; +} + +/** + * Convert the UTF-32 string to lower case. + * + * \param str the str + * \return the lower case string + */ +inline std::u32string tolower(std::u32string str) +{ + for (size_t i = 0; i < str.size(); ++i) + str[i] = tolower(str[i]); + + return str; +} + +/** + * Convert the UTF-8 string to lower case. + * + * \param str the str + * \return the lower case string + * \warning very slow at the moment + */ +inline std::string tolower(const std::string &str) +{ + std::string result; + char buffer[5]; + + forEach(str, [&] (char32_t code) { + encode(tolower(code), buffer); + result += buffer; + }); + + return result; +} + +} // !unicode + +} // !irccd + +#endif // !IRCCD_UNICODE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/unicode_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/unicode_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,151 @@ +/* + * unicode_jsapi.cpp -- Irccd.Unicode API + * + * 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 "js_plugin.hpp" +#include "unicode.hpp" +#include "unicode_jsapi.hpp" + +namespace irccd { + +namespace { + +/* + * Function: Irccd.Unicode.isDigit(code) + * -------------------------------------------------------- + * + * Arguments: + * - code, the code point. + * Returns: + * True if the code is in the digit category. + */ +duk_ret_t is_digit(duk_context* ctx) +{ + duk_push_boolean(ctx, unicode::isdigit(duk_get_int(ctx, 0))); + + return 1; +} + +/* + * Function: Irccd.Unicode.isLetter(code) + * -------------------------------------------------------- + * + * Arguments: + * - code, the code point. + * Returns: + * True if the code is in the letter category. + */ +duk_ret_t is_letter(duk_context* ctx) +{ + duk_push_boolean(ctx, unicode::isalpha(duk_get_int(ctx, 0))); + + return 1; +} + +/* + * Function: Irccd.Unicode.isLower(code) + * -------------------------------------------------------- + * + * Arguments: + * - code, the code point. + * Returns: + * True if the code is lower case. + */ +duk_ret_t is_lower(duk_context* ctx) +{ + duk_push_boolean(ctx, unicode::islower(duk_get_int(ctx, 0))); + + return 1; +} + +/* + * Function: Irccd.Unicode.isSpace(code) + * -------------------------------------------------------- + * + * Arguments: + * - code, the code point. + * Returns: + * True if the code is in the space category. + */ +duk_ret_t is_space(duk_context* ctx) +{ + duk_push_boolean(ctx, unicode::isspace(duk_get_int(ctx, 0))); + + return 1; +} + +/* + * Function: Irccd.Unicode.isTitle(code) + * -------------------------------------------------------- + * + * Arguments: + * - code, the code point. + * Returns: + * True if the code is title case. + */ +duk_ret_t is_title(duk_context* ctx) +{ + duk_push_boolean(ctx, unicode::istitle(duk_get_int(ctx, 0))); + + return 1; +} + +/* + * Function: Irccd.Unicode.isUpper(code) + * -------------------------------------------------------- + * + * Arguments: + * - code, the code point. + * Returns: + * True if the code is upper case. + */ +duk_ret_t is_upper(duk_context* ctx) +{ + duk_push_boolean(ctx, unicode::isupper(duk_get_int(ctx, 0))); + + return 1; +} + +const duk_function_list_entry functions[] = { + { "isDigit", is_digit, 1 }, + { "isLetter", is_letter, 1 }, + { "isLower", is_lower, 1 }, + { "isSpace", is_space, 1 }, + { "isTitle", is_title, 1 }, + { "isUpper", is_upper, 1 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +std::string unicode_jsapi::name() const +{ + return "Irccd.Unicode"; +} + +void unicode_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, functions); + duk_put_prop_string(plugin->context(), -2, "Unicode"); + duk_pop(plugin->context()); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/unicode_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/unicode_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,50 @@ +/* + * unicode_jsapi.hpp -- Irccd.Unicode API + * + * 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_JS_UNICODE_JSAPI_HPP +#define IRCCD_JS_UNICODE_JSAPI_HPP + +/** + * \file unicode_jsapi.hpp + * \brief Irccd.Unicode Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Irccd.Unicode Javascript API. + * \ingroup jsapi + */ +class unicode_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +} // !irccd + +#endif // !IRCCD_JS_UNICODE_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/util_jsapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/util_jsapi.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,300 @@ +/* + * util_jsapi.cpp -- Irccd.Util API + * + * 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 + +#include + +#include + +#include "js_plugin.hpp" +#include "util_jsapi.hpp" + +namespace irccd { + +namespace { + +/* + * Read parameters for irccd.Util.format function, the object is defined as + * following: + * + * { + * date: the date object + * flags: the flags (not implemented yet) + * field1: a field to substitute in #{} pattern + * field2: a field to substitute in #{} pattern + * fieldn: ... + * } + */ +string_util::subst get_subst(duk_context* ctx, int index) +{ + string_util::subst params; + + if (!duk_is_object(ctx, index)) + return params; + + dukx_enumerate(ctx, index, 0, true, [&] (auto) { + if (dukx_get_std_string(ctx, -2) == "date") + params.time = static_cast(duk_get_number(ctx, -1) / 1000); + else + params.keywords.insert({dukx_get_std_string(ctx, -2), dukx_get_std_string(ctx, -1)}); + }); + + return params; +} + +/* + * split (for Irccd.Util.cut) + * ------------------------------------------------------------------ + * + * Extract individual tokens in array or a whole string as a std:::vector. + */ +std::vector split(duk_context* ctx) +{ + duk_require_type_mask(ctx, 0, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_STRING); + + std::vector result; + std::string pattern = " \t\n"; + + if (duk_is_string(ctx, 0)) + 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 = string_util::split(duk_to_string(ctx, -1), pattern); + + result.insert(result.end(), tmp.begin(), tmp.end()); + duk_pop_2(ctx); + } + } + + return result; +} + +/* + * limit (for Irccd.Util.cut) + * ------------------------------------------------------------------ + * + * Get the maxl/maxc argument. + * + * The argument value is the default and also used as the result returned. + */ +int limit(duk_context* ctx, int index, const char* name, int value) +{ + if (duk_get_top(ctx) < index || !duk_is_number(ctx, index)) + 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); + + return value; +} + +/* + * lines (for Irccd.Util.cut) + * ------------------------------------------------------------------ + * + * Build a list of lines. + * + * Several cases possible: + * + * - s is the current line + * - abc is the token to add + * + * s = "" (new line) + * s -> "abc" + * + * s = "hello world" (enough room) + * s -> "hello world abc" + * + * s = "hello world" (not enough room: maxc is smaller) + * s+1 = "abc" + */ +std::vector lines(duk_context* ctx, const std::vector& tokens, int maxc) +{ + std::vector result{""}; + + for (const auto& s : tokens) { + if (s.length() > static_cast(maxc)) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "word '%s' could not fit in maxc limit (%d)", s.c_str(), maxc); + + // Compute the length required (prepend a space if needed) + auto required = s.length() + (result.back().empty() ? 0 : 1); + + if (result.back().length() + required > static_cast(maxc)) + result.push_back(s); + else { + if (!result.back().empty()) + result.back() += ' '; + + result.back() += s; + } + } + + return result; +} + +/* + * Function: Irccd.Util.cut(data, maxc, maxl) + * -------------------------------------------------------- + * + * Cut a piece of data into several lines. + * + * The argument data is a string or a list of strings. In any case, all strings + * are first splitted by spaces and trimmed. This ensure that useless + * whitespaces are discarded. + * + * The argument maxc controls the maximum of characters allowed per line, it can + * be a positive integer. If undefined is given, a default of 72 is used. + * + * The argument maxl controls the maximum of lines allowed. It can be a positive + * integer or undefined for an infinite list. + * + * If maxl is used as a limit and the data can not fit within the bounds, + * undefined is returned. + * + * An empty list may be returned if empty strings were found. + * + * Arguments: + * - data, a string or an array of strings, + * - maxc, max number of colums (Optional, default: 72), + * - maxl, max number of lines (Optional, default: undefined). + * Returns: + * A list of strings ready to be sent or undefined if the data is too big. + * Throws: + * - RangeError if maxl or maxc are negative numbers, + * - RangeError if one word length was bigger than maxc, + * - TypeError if data is not a string or a list of strings. + */ +duk_ret_t cut(duk_context* ctx) +{ + auto list = lines(ctx, split(ctx), limit(ctx, 1, "maxc", 72)); + auto maxl = limit(ctx, 2, "maxl", INT_MAX); + + if (list.size() > static_cast(maxl)) + return 0; + + // Empty list but lines() returns at least one. + if (list.size() == 1 && list[0].empty()) { + duk_push_array(ctx); + return 1; + } + + dukx_push_array(ctx, list, dukx_push_std_string); + + return 1; +} + +/* + * Function: Irccd.Util.format(text, parameters) + * -------------------------------------------------------- + * + * Format a string with templates. + * + * Arguments: + * - input, the text to update, + * - params, the parameters. + * Returns: + * The converted text. + */ +duk_ret_t format(duk_context* ctx) +{ + try { + 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())); + } + + return 1; +} + +/* + * Function: Irccd.Util.splituser(ident) + * -------------------------------------------------------- + * + * Return the nickname part from a full username. + * + * Arguments: + * - ident, the full identity. + * Returns: + * The nickname. + */ +duk_ret_t splituser(duk_context* ctx) +{ + auto target = duk_require_string(ctx, 0); + char nick[32] = {0}; + + irc_target_get_nick(target, nick, sizeof (nick) -1); + duk_push_string(ctx, nick); + + return 1; +} + +/* + * Function: Irccd.Util.splithost(ident) + * -------------------------------------------------------- + * + * Return the hostname part from a full username. + * + * Arguments: + * - ident, the full identity. + * Returns: + * The hostname. + */ +duk_ret_t splithost(duk_context* ctx) +{ + auto target = duk_require_string(ctx, 0); + char host[32] = {0}; + + irc_target_get_host(target, host, sizeof (host) -1); + duk_push_string(ctx, host); + + return 1; +} + +const duk_function_list_entry functions[] = { + { "cut", cut, DUK_VARARGS }, + { "format", format, DUK_VARARGS }, + { "splituser", splituser, 1 }, + { "splithost", splithost, 1 }, + { nullptr, nullptr, 0 } +}; + +} // !namespace + +std::string util_jsapi::name() const +{ + return "Irccd.Util"; +} + +void util_jsapi::load(irccd&, std::shared_ptr plugin) +{ + StackAssert sa(plugin->context()); + + duk_get_global_string(plugin->context(), "Irccd"); + duk_push_object(plugin->context()); + duk_put_function_list(plugin->context(), -1, functions); + duk_put_prop_string(plugin->context(), -2, "Util"); + duk_pop(plugin->context()); +} + +} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js/util_jsapi.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd-js/irccd/js/util_jsapi.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -0,0 +1,50 @@ +/* + * util_jsapi.hpp -- Irccd.Util API + * + * 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_JS_UTIL_JSAPI_HPP +#define IRCCD_JS_UTIL_JSAPI_HPP + +/** + * \file util_jsapi.hpp + * \brief Irccd.Util Javascript API. + */ + +#include "jsapi.hpp" + +namespace irccd { + +/** + * \brief Irccd.Util Javascript API. + * \ingroup jsapi + */ +class util_jsapi : public jsapi { +public: + /** + * \copydoc jsapi::name + */ + std::string name() const override; + + /** + * \copydoc jsapi::load + */ + void load(irccd& irccd, std::shared_ptr plugin) override; +}; + +} // !irccd + +#endif // !IRCCD_JS_UTIL_JSAPI_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_directory_module.cpp --- a/libirccd-js/irccd/js_directory_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,329 +0,0 @@ -/* - * js_directory_module.cpp -- irccd.Directory API - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "fs_util.hpp" -#include "duktape.hpp" -#include "js_directory_module.hpp" -#include "js_irccd_module.hpp" -#include "js_plugin.hpp" -#include "sysconfig.hpp" - -namespace fs = boost::filesystem; - -namespace irccd { - -namespace { - -std::string path(duk_context *ctx) -{ - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, "path"); - - if (duk_get_type(ctx, -1) != DUK_TYPE_STRING) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Directory object"); - - auto ret = dukx_get_std_string(ctx, -1); - - if (ret.empty()) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path"); - - duk_pop_n(ctx, 2); - - return ret; -} - -/* - * Generic find function for: - * - * - Directory.find - * - Directory.prototype.find - * - * The patternIndex is the argument where to test if the argument is a regex or - * a string. - */ -duk_ret_t find(duk_context* ctx, std::string base, bool recursive, int pattern_index) -{ - try { - std::string path; - - if (duk_is_string(ctx, pattern_index)) - 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"); - auto is_regex = duk_instanceof(ctx, pattern_index, -1); - duk_pop(ctx); - - if (is_regex) { - duk_get_prop_string(ctx, pattern_index, "source"); - auto pattern = duk_to_string(ctx, -1); - duk_pop(ctx); - - 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"); - } - - if (path.empty()) - return 0; - - dukx_push_std_string(ctx, path); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 1; -} - -/* - * Generic remove function for: - * - * - Directory.remove - * - Directory.prototype.remove - */ -duk_ret_t remove(duk_context* ctx, const std::string& path, bool recursive) -{ - boost::system::error_code ec; - - if (!boost::filesystem::is_directory(path, ec) || ec) - dukx_throw(ctx, system_error(EINVAL, "not a directory")); - - if (!recursive) - boost::filesystem::remove(path, ec); - else - boost::filesystem::remove_all(path, ec); - - return 0; -} - -/* - * Method: Directory.find(pattern, recursive) - * -------------------------------------------------------- - * - * Synonym of Directory.find(path, pattern, recursive) but the path is taken - * from the directory object. - * - * Arguments: - * - pattern, the regular expression or file name, - * - recursive, set to true to search recursively (default: false). - * Returns: - * The path to the file or undefined if not found. - * Throws: - * - Any exception on error. - */ -duk_ret_t method_find(duk_context* ctx) -{ - return find(ctx, path(ctx), duk_get_boolean(ctx, 1), 0); -} - -/* - * Method: Directory.remove(recursive) - * -------------------------------------------------------- - * - * Synonym of Directory.remove(recursive) but the path is taken from the - * directory object. - * - * Arguments: - * - recursive, recursively or not (default: false). - * Throws: - * - Any exception on error. - */ -duk_ret_t method_remove(duk_context* ctx) -{ - return remove(ctx, path(ctx), duk_get_boolean(ctx, 0)); -} - -const duk_function_list_entry methods[] = { - { "find", method_find, DUK_VARARGS }, - { "remove", method_remove, 1 }, - { nullptr, nullptr, 0 } -}; - -/* - * Directory "static" functions - * ------------------------------------------------------------------ - */ - -/* - * Function: Irccd.Directory(path) [constructor] - * -------------------------------------------------------- - * - * Opens and read the directory at the specified path. - * - * Arguments: - * - path, the path to the directory, - * Throws: - * - Any exception on error - */ -duk_ret_t constructor(duk_context* ctx) -{ - if (!duk_is_constructor_call(ctx)) - return 0; - - try { - auto path = duk_require_string(ctx, 0); - - if (!boost::filesystem::is_directory(path)) - dukx_throw(ctx, system_error(EINVAL, "not a directory")); - - duk_push_this(ctx); - - // 'entries' property. - duk_push_string(ctx, "entries"); - duk_push_array(ctx); - - unsigned i = 0; - for (const auto& entry : boost::filesystem::directory_iterator(path)) { - duk_push_object(ctx); - dukx_push_std_string(ctx, entry.path().filename().string()); - duk_put_prop_string(ctx, -2, "name"); - duk_push_int(ctx, entry.status().type()); - duk_put_prop_string(ctx, -2, "type"); - duk_put_prop_index(ctx, -2, i++); - } - - duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); - - // 'path' property. - duk_push_string(ctx, "path"); - dukx_push_std_string(ctx, path); - duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); - } catch (const std::exception& ex) { - dukx_throw(ctx, system_error(errno, ex.what())); - } - - return 0; -} - -/* - * Function: irccd.Directory.find(path, pattern, recursive) - * -------------------------------------------------------- - * - * Find an entry by a pattern or a regular expression. - * - * Arguments: - * - path, the base path, - * - pattern, the regular expression or file name, - * - recursive, set to true to search recursively (default: false). - * Returns: - * The path to the file or undefined on errors or not found. - */ -duk_ret_t func_find(duk_context* ctx) -{ - return find(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 2), 1); -} - -/* - * Function: irccd.Directory.remove(path, recursive) - * -------------------------------------------------------- - * - * Remove the directory optionally recursively. - * - * Arguments: - * - path, the path to the directory, - * - recursive, recursively or not (default: false). - * Throws: - * - Any exception on error. - */ -duk_ret_t func_remove(duk_context *ctx) -{ - return remove(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 1)); -} - -/* - * Function: irccd.Directory.mkdir(path, mode = 0700) - * -------------------------------------------------------- - * - * Create a directory specified by path. It will create needed subdirectories - * just like you have invoked mkdir -p. - * - * Arguments: - * - path, the path to the directory, - * Throws: - * - Any exception on error. - */ -duk_ret_t func_mkdir(duk_context *ctx) -{ - try { - boost::filesystem::create_directories(duk_require_string(ctx, 0)); - } catch (const std::exception &ex) { - dukx_throw(ctx, system_error(errno, ex.what())); - } - - return 0; -} - -const duk_function_list_entry functions[] = { - { "find", func_find, DUK_VARARGS }, - { "mkdir", func_mkdir, DUK_VARARGS }, - { "remove", func_remove, DUK_VARARGS }, - { nullptr, nullptr, 0 } -}; - -const duk_number_list_entry constants[] = { - { "TypeFile", static_cast(fs::regular_file) }, - { "TypeDir", static_cast(fs::directory_file) }, - { "TypeLink", static_cast(fs::symlink_file) }, - { "TypeBlock", static_cast(fs::block_file) }, - { "TypeCharacter", static_cast(fs::character_file) }, - { "TypeFifo", static_cast(fs::fifo_file) }, - { "TypeSocket", static_cast(fs::socket_file) }, - { "TypeUnknown", static_cast(fs::type_unknown) }, - { nullptr, 0 } -}; - -} // !namespace - -js_directory_module::js_directory_module() noexcept - : module("Irccd.Directory") -{ -} - -void js_directory_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_c_function(plugin->context(), constructor, 2); - duk_put_number_list(plugin->context(), -1, constants); - duk_put_function_list(plugin->context(), -1, functions); - -#if defined(IRCCD_SYSTEM_WINDOWS) - duk_push_string(plugin->context(), "\\"); -#else - duk_push_string(plugin->context(), "/"); -#endif - - duk_put_prop_string(plugin->context(), -2, "separator"); - - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, methods); - duk_put_prop_string(plugin->context(), -2, "prototype"); - duk_put_prop_string(plugin->context(), -2, "Directory"); - duk_pop(plugin->context()); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_directory_module.hpp --- a/libirccd-js/irccd/js_directory_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_directory_module.hpp -- irccd.Directory API - * - * 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_JS_DIRECTORY_MODULE_HPP -#define IRCCD_JS_DIRECTORY_MODULE_HPP - -/** - * \file mod-directory.hpp - * \brief irccd.Directory JavaScript API. - */ - -#include "module.hpp" - -namespace irccd { - -/** - * \brief irccd.Directory JavaScript API. - * \ingroup modules - */ -class js_directory_module : public module { -public: - /** - * Constructor. - */ - js_directory_module() noexcept; - - /** - * \copydoc Module::load - */ - void load(irccd &irccd, std::shared_ptr plugin) override; -}; - -} // !irccd - -#endif // !IRCCD_JS_DIRECTORY_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_elapsed_timer_module.cpp --- a/libirccd-js/irccd/js_elapsed_timer_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * js_elapsed_timer_module.cpp -- Irccd.ElapsedTimer API - * - * 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 - -#include - -#include "js_elapsed_timer_module.hpp" - -namespace irccd { - -namespace { - -const char* signature("\xff""\xff""irccd-elapsed-timer-ptr"); - -boost::timer::cpu_timer* self(duk_context* ctx) -{ - StackAssert sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature); - auto ptr = static_cast(duk_to_pointer(ctx, -1)); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object"); - - return ptr; -} - -/* - * Method: ElapsedTimer.pause - * ------------------------------------------------------------------ - * - * Pause the timer, without resetting the current elapsed time stored. - */ -duk_ret_t pause(duk_context* ctx) -{ - self(ctx)->stop(); - - return 0; -} - -/* - * Method: ElapsedTimer.restart - * ------------------------------------------------------------------ - * - * Restart the timer without resetting the current elapsed time. - */ -duk_ret_t restart(duk_context* ctx) -{ - self(ctx)->resume(); - - return 0; -} - -/* - * Method: ElapsedTimer.elapsed - * ------------------------------------------------------------------ - * - * Get the number of elapsed milliseconds. - * - * Returns: - * The time elapsed. - */ -duk_ret_t elapsed(duk_context* ctx) -{ - duk_push_uint(ctx, self(ctx)->elapsed().wall / 1000000LL); - - return 1; -} - -/* - * Function: Irccd.ElapsedTimer [constructor] - * ------------------------------------------------------------------ - * - * Construct a new ElapsedTimer object. - */ -duk_ret_t constructor(duk_context* ctx) -{ - duk_push_this(ctx); - duk_push_pointer(ctx, new boost::timer::cpu_timer); - duk_put_prop_string(ctx, -2, signature); - duk_pop(ctx); - - return 0; -} - -/* - * Function: Irccd.ElapsedTimer [destructor] - * ------------------------------------------------------------------ - * - * Delete the property. - */ -duk_ret_t destructor(duk_context* ctx) -{ - duk_get_prop_string(ctx, 0, signature); - delete static_cast(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_del_prop_string(ctx, 0, signature); - - return 0; -} - -const duk_function_list_entry methods[] = { - { "elapsed", elapsed, 0 }, - { "pause", pause, 0 }, - { "restart", restart, 0 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -js_elapsed_timer_module::js_elapsed_timer_module() noexcept - : module("Irccd.ElapsedTimer") -{ -} - -void js_elapsed_timer_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_c_function(plugin->context(), constructor, 0); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, methods); - duk_push_c_function(plugin->context(), destructor, 1); - duk_set_finalizer(plugin->context(), -2); - duk_put_prop_string(plugin->context(), -2, "prototype"); - duk_put_prop_string(plugin->context(), -2, "ElapsedTimer"); - duk_pop(plugin->context()); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_elapsed_timer_module.hpp --- a/libirccd-js/irccd/js_elapsed_timer_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_elapsed_timer_module.hpp -- irccd.ElapsedTimer API - * - * 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_JS_ELAPSED_TIMER_MODULE_HPP -#define IRCCD_JS_ELAPSED_TIMER_MODULE_HPP - -/** - * \file js_elapsed_timer_module.hpp - * \brief irccd.ElapsedTimer JavaScript API. - */ - -#include "module.hpp" - -namespace irccd { - -/** - * \brief Irccd.ElapsedTimer JavaScript API. - * \ingroup Javascript modules - */ -class js_elapsed_timer_module : public module { -public: - /** - * Constructor. - */ - js_elapsed_timer_module() noexcept; - - /** - * \copydoc module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -} // !irccd - -#endif // !IRCCD_JS_ELAPSED_TIMER_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_file_module.cpp --- a/libirccd-js/irccd/js_file_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,700 +0,0 @@ -/* - * js_file_module.cpp -- Irccd.File API - * - * 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 -#include -#include -#include -#include - -#include - -#include - -#if defined(HAVE_STAT) -# include -# include -#endif - -#include - -#include "fs_util.hpp" -#include "js_file_module.hpp" -#include "js_irccd_module.hpp" - -namespace irccd { - -namespace { - -const char *signature("\xff""\xff""irccd-file-ptr"); -const char *prototype("\xff""\xff""irccd-file-prototype"); - -#if defined(HAVE_STAT) - -/* - * push_stat - * ------------------------------------------------------------------ - */ - -void push_stat(duk_context* ctx, const struct stat& st) -{ - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - -#if defined(HAVE_STAT_ST_ATIME) - duk_push_int(ctx, st.st_atime); - duk_put_prop_string(ctx, -2, "atime"); -#endif -#if defined(HAVE_STAT_ST_BLKSIZE) - duk_push_int(ctx, st.st_blksize); - duk_put_prop_string(ctx, -2, "blksize"); -#endif -#if defined(HAVE_STAT_ST_BLOCKS) - duk_push_int(ctx, st.st_blocks); - duk_put_prop_string(ctx, -2, "blocks"); -#endif -#if defined(HAVE_STAT_ST_CTIME) - duk_push_int(ctx, st.st_ctime); - duk_put_prop_string(ctx, -2, "ctime"); -#endif -#if defined(HAVE_STAT_ST_DEV) - duk_push_int(ctx, st.st_dev); - duk_put_prop_string(ctx, -2, "dev"); -#endif -#if defined(HAVE_STAT_ST_GID) - duk_push_int(ctx, st.st_gid); - duk_put_prop_string(ctx, -2, "gid"); -#endif -#if defined(HAVE_STAT_ST_INO) - duk_push_int(ctx, st.st_ino); - duk_put_prop_string(ctx, -2, "ino"); -#endif -#if defined(HAVE_STAT_ST_MODE) - duk_push_int(ctx, st.st_mode); - duk_put_prop_string(ctx, -2, "mode"); -#endif -#if defined(HAVE_STAT_ST_MTIME) - duk_push_int(ctx, st.st_mtime); - duk_put_prop_string(ctx, -2, "mtime"); -#endif -#if defined(HAVE_STAT_ST_NLINK) - duk_push_int(ctx, st.st_nlink); - duk_put_prop_string(ctx, -2, "nlink"); -#endif -#if defined(HAVE_STAT_ST_RDEV) - duk_push_int(ctx, st.st_rdev); - duk_put_prop_string(ctx, -2, "rdev"); -#endif -#if defined(HAVE_STAT_ST_SIZE) - duk_push_int(ctx, st.st_size); - duk_put_prop_string(ctx, -2, "size"); -#endif -#if defined(HAVE_STAT_ST_UID) - duk_push_int(ctx, st.st_uid); - duk_put_prop_string(ctx, -2, "uid"); -#endif -} - -#endif // !HAVE_STAT - -// Remove trailing \r for CRLF line style. -inline std::string clear_crlf(std::string input) -{ - if (input.length() > 0 && input.back() == '\r') - input.pop_back(); - - return input; -} - -file* self(duk_context* ctx) -{ - StackAssert sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature); - auto ptr = static_cast(duk_to_pointer(ctx, -1)); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); - - return ptr; -} - -/* - * File methods. - * ------------------------------------------------------------------ - */ - -/* - * Method: File.basename() - * -------------------------------------------------------- - * - * Synonym of `irccd.File.basename(path)` but with the path from the file. - * - * duk_ret_turns: - * The base name. - */ -duk_ret_t method_basename(duk_context* ctx) -{ - dukx_push_std_string(ctx, fs_util::base_name(self(ctx)->path())); - - return 1; -} - -/* - * Method: File.close() - * -------------------------------------------------------- - * - * Force close of the file, automatically called when object is collected. - */ -duk_ret_t method_close(duk_context* ctx) -{ - self(ctx)->close(); - - return 0; -} - -/* - * Method: File.dirname() - * -------------------------------------------------------- - * - * Synonym of `irccd.File.dirname(path)` but with the path from the file. - * - * duk_ret_turns: - * The directory name. - */ -duk_ret_t method_dirname(duk_context* ctx) -{ - dukx_push_std_string(ctx, fs_util::dir_name(self(ctx)->path())); - - return 1; -} - -/* - * Method: File.lines() - * -------------------------------------------------------- - * - * Read all lines and return an array. - * - * duk_ret_turns: - * An array with all lines. - * Throws - * - Any exception on error. - */ -duk_ret_t method_lines(duk_context* ctx) -{ - duk_push_array(ctx); - - std::FILE* fp = self(ctx)->handle(); - std::string buffer; - std::array data; - std::int32_t i = 0; - - while (std::fgets(&data[0], data.size(), fp) != nullptr) { - buffer += data.data(); - - auto pos = buffer.find('\n'); - - if (pos != std::string::npos) { - dukx_push_std_string(ctx, clear_crlf(buffer.substr(0, pos))); - duk_put_prop_index(ctx, -2, i++); - - buffer.erase(0, pos + 1); - } - } - - // Maybe an error in the stream. - if (std::ferror(fp)) - dukx_throw(ctx, system_error()); - - // Missing '\n' in end of file. - if (!buffer.empty()) { - dukx_push_std_string(ctx, clear_crlf(buffer)); - duk_put_prop_index(ctx, -2, i++); - } - - return 1; -} - -/* - * Method: File.read(amount) - * -------------------------------------------------------- - * - * Read the specified amount of characters or the whole file. - * - * Arguments: - * - amount, the amount of characters or -1 to read all (Optional, default: -1). - * duk_ret_turns: - * The string. - * Throws: - * - Any exception on error. - */ -duk_ret_t method_read(duk_context* ctx) -{ - auto file = self(ctx); - auto amount = duk_is_number(ctx, 0) ? duk_get_int(ctx, 0) : -1; - - if (amount == 0 || file->handle() == nullptr) - return 0; - - try { - std::string data; - std::size_t total = 0; - - if (amount < 0) { - std::array buffer; - std::size_t nread; - - while ((nread = std::fread(&buffer[0], sizeof (buffer[0]), buffer.size(), file->handle())) > 0) { - if (std::ferror(file->handle())) - dukx_throw(ctx, system_error()); - - std::copy(buffer.begin(), buffer.begin() + nread, std::back_inserter(data)); - total += nread; - } - } else { - data.resize((std::size_t)amount); - total = std::fread(&data[0], sizeof (data[0]), (std::size_t)amount, file->handle()); - - if (std::ferror(file->handle())) - dukx_throw(ctx, system_error()); - - data.resize(total); - } - - dukx_push_std_string(ctx, data); - } catch (const std::exception&) { - dukx_throw(ctx, system_error()); - } - - return 1; -} - -/* - * Method: File.readline() - * -------------------------------------------------------- - * - * Read the next line available. - * - * duk_ret_turns: - * The next line or undefined if eof. - * Throws: - * - Any exception on error. - */ -duk_ret_t method_readline(duk_context* ctx) -{ - std::FILE* fp = self(ctx)->handle(); - std::string result; - - if (fp == nullptr || std::feof(fp)) - return 0; - for (int ch; (ch = std::fgetc(fp)) != EOF && ch != '\n'; ) - result += (char)ch; - if (std::ferror(fp)) - dukx_throw(ctx, system_error()); - - dukx_push_std_string(ctx, clear_crlf(result)); - - return 1; -} - -/* - * Method: File.remove() - * -------------------------------------------------------- - * - * Synonym of File.remove(path) but with the path from the file. - * - * Throws: - * - Any exception on error. - */ -duk_ret_t method_remove(duk_context* ctx) -{ - if (::remove(self(ctx)->path().c_str()) < 0) - dukx_throw(ctx, system_error()); - - return 0; -} - -/* - * Method: File.seek(type, amount) - * -------------------------------------------------------- - * - * Sets the position in the file. - * - * Arguments: - * - type, the type of setting (File.SeekSet, File.SeekCur, File.SeekSet), - * - amount, the new offset. - * Throws: - * - Any exception on error. - */ -duk_ret_t method_seek(duk_context* ctx) -{ - auto fp = self(ctx)->handle(); - auto type = duk_require_int(ctx, 0); - auto amount = duk_require_int(ctx, 1); - - if (fp != nullptr && std::fseek(fp, amount, type) != 0) - dukx_throw(ctx, system_error()); - - return 0; -} - -#if defined(HAVE_STAT) - -/* - * Method: File.stat() [optional] - * -------------------------------------------------------- - * - * Synonym of File.stat(path) but with the path from the file. - * - * duk_ret_turns: - * The stat information. - * Throws: - * - Any exception on error. - */ -duk_ret_t method_stat(duk_context* ctx) -{ - auto file = self(ctx); - struct stat st; - - if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0) - dukx_throw(ctx, system_error()); - else - push_stat(ctx, st); - - return 1; -} - -#endif // !HAVE_STAT - -/* - * Method: File.tell() - * -------------------------------------------------------- - * - * Get the actual position in the file. - * - * duk_ret_turns: - * The position. - * Throws: - * - Any exception on error. - */ -duk_ret_t method_tell(duk_context* ctx) -{ - auto fp = self(ctx)->handle(); - long pos; - - if (fp == nullptr) - return 0; - - if ((pos = std::ftell(fp)) == -1L) - dukx_throw(ctx, system_error()); - else - duk_push_int(ctx, pos); - - return 1; -} - -/* - * Method: File.write(data) - * -------------------------------------------------------- - * - * Write some characters to the file. - * - * Arguments: - * - data, the character to write. - * duk_ret_turns: - * The number of bytes written. - * Throws: - * - Any exception on error. - */ -duk_ret_t method_write(duk_context* ctx) -{ - std::FILE* fp = self(ctx)->handle(); - std::string data = duk_require_string(ctx, 0); - - if (fp == nullptr) - return 0; - - auto nwritten = std::fwrite(data.c_str(), 1, data.length(), fp); - - if (std::ferror(fp)) - dukx_throw(ctx, system_error()); - - duk_push_uint(ctx, nwritten); - - return 1; -} - -const duk_function_list_entry methods[] = { - { "basename", method_basename, 0 }, - { "close", method_close, 0 }, - { "dirname", method_dirname, 0 }, - { "lines", method_lines, 0 }, - { "read", method_read, 1 }, - { "readline", method_readline, 0 }, - { "remove", method_remove, 0 }, - { "seek", method_seek, 2 }, -#if defined(HAVE_STAT) - { "stat", method_stat, 0 }, -#endif - { "tell", method_tell, 0 }, - { "write", method_write, 1 }, - { nullptr, nullptr, 0 } -}; - -/* - * File "static" functions - * ------------------------------------------------------------------ - */ - -/* - * Function: Irccd.File(path, mode) [constructor] - * -------------------------------------------------------- - * - * Open a file specified by path with the specified mode. - * - * Arguments: - * - path, the path to the file, - * - mode, the mode string. - * Throws: - * - Any exception on error. - */ -duk_ret_t constructor(duk_context* ctx) -{ - if (!duk_is_constructor_call(ctx)) - return 0; - - try { - dukx_new_file(ctx, new file(duk_require_string(ctx, 0), duk_require_string(ctx, 1))); - } catch (const std::exception &) { - dukx_throw(ctx, system_error()); - } - - return 0; -} - -/* - * Function: Irccd.File() [destructor] - * ------------------------------------------------------------------ - * - * Delete the property. - */ -duk_ret_t destructor(duk_context* ctx) -{ - duk_get_prop_string(ctx, 0, signature); - delete static_cast(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_del_prop_string(ctx, 0, signature); - - return 0; -} - -/* - * Function: Irccd.File.basename(path) - * -------------------------------------------------------- - * - * duk_ret_turn the file basename as specified in `basename(3)` C function. - * - * Arguments: - * - path, the path to the file. - * duk_ret_turns: - * The base name. - */ -duk_ret_t function_basename(duk_context* ctx) -{ - dukx_push_std_string(ctx, fs_util::base_name(duk_require_string(ctx, 0))); - - return 1; -} - -/* - * Function: Irccd.File.dirname(path) - * -------------------------------------------------------- - * - * duk_ret_turn the file directory name as specified in `dirname(3)` C function. - * - * Arguments: - * - path, the path to the file. - * duk_ret_turns: - * The directory name. - */ -duk_ret_t function_dirname(duk_context* ctx) -{ - dukx_push_std_string(ctx, fs_util::dir_name(duk_require_string(ctx, 0))); - - return 1; -} - -/* - * Function: Irccd.File.exists(path) - * -------------------------------------------------------- - * - * Check if the file exists. - * - * Arguments: - * - path, the path to the file. - * duk_ret_turns: - * True if exists. - * Throws: - * - Any exception if we don't have access. - */ -duk_ret_t function_exists(duk_context* ctx) -{ - try { - duk_push_boolean(ctx, boost::filesystem::exists(duk_require_string(ctx, 0))); - } catch (...) { - duk_push_boolean(ctx, false); - } - - return 1; -} - -/* - * function Irccd.File.remove(path) - * -------------------------------------------------------- - * - * Remove the file at the specified path. - * - * Arguments: - * - path, the path to the file. - * Throws: - * - Any exception on error. - */ -duk_ret_t function_remove(duk_context* ctx) -{ - if (::remove(duk_require_string(ctx, 0)) < 0) - dukx_throw(ctx, system_error()); - - return 0; -} - -#if defined(HAVE_STAT) - -/* - * function Irccd.File.stat(path) [optional] - * -------------------------------------------------------- - * - * Get file information at the specified path. - * - * Arguments: - * - path, the path to the file. - * duk_ret_turns: - * The stat information. - * Throws: - * - Any exception on error. - */ -duk_ret_t function_stat(duk_context* ctx) -{ - struct stat st; - - if (::stat(duk_require_string(ctx, 0), &st) < 0) - dukx_throw(ctx, system_error()); - - push_stat(ctx, st); - - return 1; -} - -#endif // !HAVE_STAT - -const duk_function_list_entry functions[] = { - { "basename", function_basename, 1 }, - { "dirname", function_dirname, 1 }, - { "exists", function_exists, 1 }, - { "remove", function_remove, 1 }, -#if defined(HAVE_STAT) - { "stat", function_stat, 1 }, -#endif - { nullptr, nullptr, 0 } -}; - -const duk_number_list_entry constants[] = { - { "SeekCur", SEEK_CUR }, - { "SeekEnd", SEEK_END }, - { "SeekSet", SEEK_SET }, - { nullptr, 0 } -}; - -} // !namespace - -js_file_module::js_file_module() noexcept - : module("Irccd.File") -{ -} - -void js_file_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_c_function(plugin->context(), constructor, 2); - duk_put_number_list(plugin->context(), -1, constants); - duk_put_function_list(plugin->context(), -1, functions); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, methods); - duk_push_c_function(plugin->context(), destructor, 1); - duk_set_finalizer(plugin->context(), -2); - duk_dup(plugin->context(), -1); - duk_put_global_string(plugin->context(), prototype); - duk_put_prop_string(plugin->context(), -2, "prototype"); - duk_put_prop_string(plugin->context(), -2, "File"); - duk_pop(plugin->context()); -} - -void dukx_new_file(duk_context* ctx, file* fp) -{ - assert(ctx); - assert(fp); - - StackAssert sa(ctx); - - duk_push_this(ctx); - duk_push_pointer(ctx, fp); - duk_put_prop_string(ctx, -2, signature); - duk_pop(ctx); -} - -void dukx_push_file(duk_context* ctx, file* fp) -{ - assert(ctx); - assert(fp); - - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - duk_push_pointer(ctx, fp); - duk_put_prop_string(ctx, -2, signature); - duk_get_global_string(ctx, prototype); - duk_set_prototype(ctx, -2); -} - -file* dukx_require_file(duk_context* ctx, duk_idx_t index) -{ - if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, signature)) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); - - duk_get_prop_string(ctx, index, signature); - auto fp = static_cast(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return fp; -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_file_module.hpp --- a/libirccd-js/irccd/js_file_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ -/* - * js_file_module.hpp -- Irccd.File API - * - * 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_JS_FILE_MODULE_HPP -#define IRCCD_JS_FILE_MODULE_HPP - -/** - * \file js_file_module.hpp - * \brief Irccd.File JavaScript API. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "duktape.hpp" -#include "module.hpp" - -namespace irccd { - -/** - * \brief Object for Javascript to perform I/O. - * - * This class can be constructed to Javascript. - * - * It is used in: - * - * - Irccd.File [constructor] - * - Irccd.System.popen (optional) - */ -class file { -private: - file(const file&) = delete; - file& operator=(const file&) = delete; - - file(file&&) = delete; - file& operator=(file&&) = delete; - -private: - std::string path_; - std::FILE *stream_; - std::function destructor_; - -public: - /** - * Construct a file specified by path - * - * \param path the path - * \param mode the mode string (for std::fopen) - * \throw std::runtime_error on failures - */ - inline file(std::string path, const std::string& mode) - : path_(std::move(path)) - , destructor_([] (std::FILE* fp) { std::fclose(fp); }) - { - if ((stream_ = std::fopen(path_.c_str(), mode.c_str())) == nullptr) - throw std::runtime_error(std::strerror(errno)); - } - - /** - * Construct a file from a already created FILE pointer (e.g. popen). - * - * The class takes ownership of fp and will close it. - * - * \pre destructor must not be null - * \param fp the file pointer - * \param destructor the function to close fp (e.g. std::fclose) - */ - inline file(std::FILE* fp, std::function destructor) noexcept - : stream_(fp) - , destructor_(std::move(destructor)) - { - assert(destructor_ != nullptr); - } - - /** - * Closes the file. - */ - virtual ~file() noexcept - { - close(); - } - - /** - * Get the path. - * - * \return the path - * \warning empty when constructed from the FILE constructor - */ - inline const std::string& path() const noexcept - { - return path_; - } - - /** - * Get the handle. - * - * \return the handle or nullptr if the stream was closed - */ - inline std::FILE* handle() noexcept - { - return stream_; - } - - /** - * Force close, can be safely called multiple times. - */ - inline void close() noexcept - { - if (stream_) { - destructor_(stream_); - stream_ = nullptr; - } - } -}; - -/** - * \brief Irccd.File JavaScript API. - * \ingroup modules - */ -class js_file_module : public module { -public: - /** - * Constructor. - */ - js_file_module() noexcept; - - /** - * \copydoc Module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -/** - * Construct the file as this. - * - * The object prototype takes ownership of fp and will be deleted once - * collected. - * - * \pre fp != nullptr - * \param ctx the the context - * \param fp the file - */ -IRCCD_EXPORT void dukx_new_file(duk_context* ctx, file* fp); - -/** - * Push a file. - * - * \pre fp != nullptr - * \param ctx the the context - * \param fp the file - */ -IRCCD_EXPORT void dukx_push_file(duk_context* ctx, file* fp); - -/** - * Require a file. Raises a JavaScript error if not a File. - * - * \param ctx the context - * \param index the index - */ -IRCCD_EXPORT file* dukx_require_file(duk_context* ctx, duk_idx_t index); - -} // !irccd - -#endif // !IRCCD_JS_FILE_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_irccd_module.cpp --- a/libirccd-js/irccd/js_irccd_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* - * js_irccd_module.cpp -- Irccd API - * - * 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 -#include -#include - -#include -#include - -#include "js_irccd_module.hpp" - -namespace irccd { - -namespace { - -const std::unordered_map errors{ - { "E2BIG", E2BIG }, - { "EACCES", EACCES }, - { "EADDRINUSE", EADDRINUSE }, - { "EADDRNOTAVAIL", EADDRNOTAVAIL }, - { "EAFNOSUPPORT", EAFNOSUPPORT }, - { "EAGAIN", EAGAIN }, - { "EALREADY", EALREADY }, - { "EBADF", EBADF }, -#if defined(EBADMSG) - { "EBADMSG", EBADMSG }, -#endif - { "EBUSY", EBUSY }, - { "ECANCELED", ECANCELED }, - { "ECHILD", ECHILD }, - { "ECONNABORTED", ECONNABORTED }, - { "ECONNREFUSED", ECONNREFUSED }, - { "ECONNRESET", ECONNRESET }, - { "EDEADLK", EDEADLK }, - { "EDESTADDRREQ", EDESTADDRREQ }, - { "EDOM", EDOM }, - { "EEXIST", EEXIST }, - { "EFAULT", EFAULT }, - { "EFBIG", EFBIG }, - { "EHOSTUNREACH", EHOSTUNREACH }, -#if defined(EIDRM) - { "EIDRM", EIDRM }, -#endif - { "EILSEQ", EILSEQ }, - { "EINPROGRESS", EINPROGRESS }, - { "EINTR", EINTR }, - { "EINVAL", EINVAL }, - { "EIO", EIO }, - { "EISCONN", EISCONN }, - { "EISDIR", EISDIR }, - { "ELOOP", ELOOP }, - { "EMFILE", EMFILE }, - { "EMLINK", EMLINK }, - { "EMSGSIZE", EMSGSIZE }, - { "ENAMETOOLONG", ENAMETOOLONG }, - { "ENETDOWN", ENETDOWN }, - { "ENETRESET", ENETRESET }, - { "ENETUNREACH", ENETUNREACH }, - { "ENFILE", ENFILE }, - { "ENOBUFS", ENOBUFS }, -#if defined(ENODATA) - { "ENODATA", ENODATA }, -#endif - { "ENODEV", ENODEV }, - { "ENOENT", ENOENT }, - { "ENOEXEC", ENOEXEC }, - { "ENOLCK", ENOLCK }, -#if defined(ENOLINK) - { "ENOLINK", ENOLINK }, -#endif - { "ENOMEM", ENOMEM }, -#if defined(ENOMSG) - { "ENOMSG", ENOMSG }, -#endif - { "ENOPROTOOPT", ENOPROTOOPT }, - { "ENOSPC", ENOSPC }, -#if defined(ENOSR) - { "ENOSR", ENOSR }, -#endif -#if defined(ENOSTR) - { "ENOSTR", ENOSTR }, -#endif - { "ENOSYS", ENOSYS }, - { "ENOTCONN", ENOTCONN }, - { "ENOTDIR", ENOTDIR }, - { "ENOTEMPTY", ENOTEMPTY }, -#if defined(ENOTRECOVERABLE) - { "ENOTRECOVERABLE", ENOTRECOVERABLE }, -#endif - { "ENOTSOCK", ENOTSOCK }, - { "ENOTSUP", ENOTSUP }, - { "ENOTTY", ENOTTY }, - { "ENXIO", ENXIO }, - { "EOPNOTSUPP", EOPNOTSUPP }, - { "EOVERFLOW", EOVERFLOW }, - { "EOWNERDEAD", EOWNERDEAD }, - { "EPERM", EPERM }, - { "EPIPE", EPIPE }, - { "EPROTO", EPROTO }, - { "EPROTONOSUPPORT", EPROTONOSUPPORT }, - { "EPROTOTYPE", EPROTOTYPE }, - { "ERANGE", ERANGE }, - { "EROFS", EROFS }, - { "ESPIPE", ESPIPE }, - { "ESRCH", ESRCH }, -#if defined(ETIME) - { "ETIME", ETIME }, -#endif - { "ETIMEDOUT", ETIMEDOUT }, -#if defined(ETXTBSY) - { "ETXTBSY", ETXTBSY }, -#endif - { "EWOULDBLOCK", EWOULDBLOCK }, - { "EXDEV", EXDEV } -}; - -duk_ret_t constructor(duk_context* ctx) -{ - duk_push_this(ctx); - duk_push_int(ctx, duk_require_int(ctx, 0)); - duk_put_prop_string(ctx, -2, "errno"); - duk_push_string(ctx, duk_require_string(ctx, 1)); - duk_put_prop_string(ctx, -2, "message"); - duk_push_string(ctx, "SystemError"); - duk_put_prop_string(ctx, -2, "name"); - duk_pop(ctx); - - return 0; -} - -} // !namespace - -system_error::system_error() - : errno_(errno) - , message_(std::strerror(errno_)) -{ -} - -system_error::system_error(int e, std::string message) - : errno_(e) - , message_(std::move(message)) -{ -} - -void system_error::raise(duk_context *ctx) const -{ - StackAssert sa(ctx, 0); - - duk_get_global_string(ctx, "Irccd"); - duk_get_prop_string(ctx, -1, "SystemError"); - duk_remove(ctx, -2); - duk_push_int(ctx, errno_); - dukx_push_std_string(ctx, message_); - duk_new(ctx, 2); - duk_throw(ctx); -} - -js_irccd_module::js_irccd_module() noexcept - : module("Irccd") -{ -} - -void js_irccd_module::load(irccd& irccd, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - // irccd. - duk_push_object(plugin->context()); - - // Version. - duk_push_object(plugin->context()); - duk_push_int(plugin->context(), IRCCD_VERSION_MAJOR); - duk_put_prop_string(plugin->context(), -2, "major"); - duk_push_int(plugin->context(), IRCCD_VERSION_MINOR); - duk_put_prop_string(plugin->context(), -2, "minor"); - duk_push_int(plugin->context(), IRCCD_VERSION_PATCH); - duk_put_prop_string(plugin->context(), -2, "patch"); - duk_put_prop_string(plugin->context(), -2, "version"); - - // Create the system_error that inherits from Error. - duk_push_c_function(plugin->context(), constructor, 2); - - // Put errno codes into the irccd.system_error object. - for (const auto& pair : errors) { - duk_push_int(plugin->context(), pair.second); - duk_put_prop_string(plugin->context(), -2, pair.first.c_str()); - } - - duk_push_object(plugin->context()); - duk_get_global_string(plugin->context(), "Error"); - duk_get_prop_string(plugin->context(), -1, "prototype"); - duk_remove(plugin->context(), -2); - duk_set_prototype(plugin->context(), -2); - duk_put_prop_string(plugin->context(), -2, "prototype"); - duk_put_prop_string(plugin->context(), -2, "SystemError"); - - // Set irccd as global. - duk_put_global_string(plugin->context(), "Irccd"); - - // Store global instance. - duk_push_pointer(plugin->context(), &irccd); - duk_put_global_string(plugin->context(), "\xff""\xff""irccd-ref"); -} - -irccd& dukx_get_irccd(duk_context *ctx) -{ - StackAssert sa(ctx); - - duk_get_global_string(ctx, "\xff""\xff""irccd-ref"); - auto ptr = static_cast(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return *ptr; -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_irccd_module.hpp --- a/libirccd-js/irccd/js_irccd_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * js_irccd_module.hpp -- Irccd API - * - * 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_JS_IRCCD_MODULE_HPP -#define IRCCD_JS_IRCCD_MODULE_HPP - -/** - * \file js_irccd_module.hpp - * \brief irccd JavaScript API. - */ - -#include -#include -#include - -#include "duktape.hpp" -#include "module.hpp" - -namespace irccd { - -/** - * \brief Custom JavaScript exception for system error. - */ -class system_error { -private: - int errno_; - std::string message_; - -public: - /** - * Create a system error from the current errno value. - */ - system_error(); - - /** - * Create a system error with the given errno and message. - * - * \param e the errno number - * \param message the message - */ - system_error(int e, std::string message); - - /** - * Raise the SystemError Javascript exception. - * - * \param ctx the context - */ - void raise(duk_context* ctx) const; -}; - -/** - * \brief Irccd JavaScript API. - * \ingroup modules - */ -class js_irccd_module : public module { -public: - /** - * Constructor. - */ - js_irccd_module() noexcept; - - /** - * \copydoc module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -/** - * Get irccd instance stored in this context. - * - * \param ctx the context - * \return the irccd reference - */ -irccd& dukx_get_irccd(duk_context* ctx); - -} // !irccd - -#endif // !IRCCD_JS_IRCCD_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_logger_module.cpp --- a/libirccd-js/irccd/js_logger_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * js_logger_module.cpp -- Irccd.Logger API - * - * 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 - -#include "js_plugin.hpp" -#include "js_logger_module.hpp" -#include "js_plugin_module.hpp" - -namespace irccd { - -namespace { - -duk_ret_t print(duk_context* ctx, std::ostream &out) -{ - out << "plugin " << dukx_get_plugin(ctx)->name() << ": " << duk_require_string(ctx, 0) << std::endl; - - return 0; -} - -/* - * Function: Irccd.Logger.info(message) - * -------------------------------------------------------- - * - * Write a verbose message. - * - * Arguments: - * - message, the message. - */ -duk_ret_t info(duk_context* ctx) -{ - return print(ctx, log::info()); -} - -/* - * Function: irccd.Logger.warning(message) - * -------------------------------------------------------- - * - * Write a warning message. - * - * Arguments: - * - message, the warning. - */ -duk_ret_t warning(duk_context* ctx) -{ - return print(ctx, log::warning()); -} - -/* - * Function: Logger.debug(message) - * -------------------------------------------------------- - * - * Write a debug message, only shown if irccd is compiled in debug. - * - * Arguments: - * - message, the message. - */ -duk_ret_t debug(duk_context* ctx) -{ - return print(ctx, log::debug()); -} - -const duk_function_list_entry functions[] = { - { "info", info, 1 }, - { "warning", warning, 1 }, - { "debug", debug, 1 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -js_logger_module::js_logger_module() noexcept - : module("Irccd.Logger") -{ -} - -void js_logger_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, functions); - duk_put_prop_string(plugin->context(), -2, "Logger"); - duk_pop(plugin->context()); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_logger_module.hpp --- a/libirccd-js/irccd/js_logger_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_logger_module.hpp -- Irccd.Logger API - * - * 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_JS_LOGGER_MODULE_HPP -#define IRCCD_JS_LOGGER_MODULE_HPP - -/** - * \file js_logger_module.hpp - * \brief Irccd.Logger JavaScript API. - */ - -#include "module.hpp" - -namespace irccd { - -/** - * \brief irccd.Logger JavaScript API. - * \ingroup modules - */ -class js_logger_module : public module { -public: - /** - * Constructor. - */ - js_logger_module() noexcept; - - /** - * \copydoc Module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -} // !irccd - -#endif // !IRCCD_JS_LOGGER_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_plugin.cpp --- a/libirccd-js/irccd/js_plugin.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,403 +0,0 @@ -/* - * plugin-js.cpp -- JavaScript plugins for irccd - * - * 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 -#include -#include -#include -#include - -#include "irccd.hpp" -#include "logger.hpp" -#include "js_plugin_module.hpp" -#include "js_server_module.hpp" -#include "js_plugin.hpp" -#include "service.hpp" -#include "timer.hpp" - -namespace irccd { - -const std::string js_plugin::config_property{"\xff""\xff""irccd-plugin-config"}; -const std::string js_plugin::format_property{"\xff""\xff""irccd-plugin-format"}; -const std::string js_plugin::paths_property{"\xff""\xff""irccd-plugin-paths"}; - -std::unordered_map js_plugin::get_table(const std::string& name) const -{ - StackAssert sa(context_); - std::unordered_map result; - - duk_get_global_string(context_, name.c_str()); - dukx_enumerate(context_, -1, 0, true, [&] (auto ctx) { - result.emplace(duk_to_string(ctx, -2), duk_to_string(ctx, -1)); - }); - duk_pop(context_); - - return result; -} - -void js_plugin::put_table(const std::string& name, const std::unordered_map& vars) -{ - StackAssert sa(context_); - - duk_get_global_string(context_, name.c_str()); - - for (const auto &pair : vars) { - dukx_push_std_string(context_, pair.second); - duk_put_prop_string(context_, -2, pair.first.c_str()); - } - - duk_pop(context_); -} - -void js_plugin::call(const std::string& name, unsigned nargs) -{ - duk_get_global_string(context_, name.c_str()); - - if (duk_get_type(context_, -1) == DUK_TYPE_UNDEFINED) - // Function not defined, remove the undefined value and all arguments. - duk_pop_n(context_, nargs + 1); - else { - // Call the function and discard the result. - duk_insert(context_, -nargs - 1); - - if (duk_pcall(context_, nargs) != 0) - throw dukx_exception(context_, -1, true); - - duk_pop(context_); - } -} - -js_plugin::js_plugin(std::string name, std::string path) - : plugin(name, path) -{ - StackAssert sa(context_); - - /* - * Create two special tables for configuration and formats, they are - * referenced later as - * - * - Irccd.Plugin.config - * - Irccd.Plugin.format - * - Irccd.Plugin.paths - * - * In js_plugin_module.cpp. - */ - duk_push_object(context_); - duk_put_global_string(context_, config_property.c_str()); - duk_push_object(context_); - duk_put_global_string(context_, format_property.c_str()); - duk_push_object(context_); - duk_put_global_string(context_, paths_property.c_str()); - - duk_push_pointer(context_, this); - duk_put_global_string(context_, "\xff""\xff""plugin"); - dukx_push_std_string(context_, name); - duk_put_global_string(context_, "\xff""\xff""name"); - dukx_push_std_string(context_, path); - duk_put_global_string(context_, "\xff""\xff""path"); -} - -void js_plugin::open() -{ - std::ifstream input(path()); - - if (!input) - throw std::runtime_error(std::strerror(errno)); - - std::string data( - std::istreambuf_iterator(input.rdbuf()), - std::istreambuf_iterator() - ); - - if (duk_peval_string(context_, data.c_str())) - throw dukx_exception(context_, -1); - - // Read metadata. - duk_get_global_string(context_, "info"); - - if (duk_get_type(context_, -1) == DUK_TYPE_OBJECT) { - duk_get_prop_string(context_, -1, "author"); - set_author(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : author()); - duk_get_prop_string(context_, -2, "license"); - set_license(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : license()); - duk_get_prop_string(context_, -3, "summary"); - set_summary(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : summary()); - duk_get_prop_string(context_, -4, "version"); - set_version(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : version()); - duk_pop_n(context_, 4); - } - - duk_pop(context_); -} - -void js_plugin::on_channel_mode(irccd& , const channel_mode_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.mode); - dukx_push_std_string(context_, event.argument); - call("onChannelMode", 5); -} - -void js_plugin::on_channel_notice(irccd& , const channel_notice_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.message); - call("onChannelNotice", 4); -} - -void js_plugin::on_command(irccd& , const message_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.message); - call("onCommand", 4); -} - -void js_plugin::on_connect(irccd& , const connect_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - call("onConnect", 1); -} - -void js_plugin::on_invite(irccd& , const invite_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - call("onInvite", 3); -} - -void js_plugin::on_join(irccd& , const join_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - call("onJoin", 3); -} - -void js_plugin::on_kick(irccd& , const kick_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.target); - dukx_push_std_string(context_, event.reason); - call("onKick", 5); -} - -void js_plugin::on_load(irccd&) -{ - StackAssert sa(context_); - - call("onLoad", 0); -} - -void js_plugin::on_message(irccd& , const message_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.message); - call("onMessage", 4); -} - -void js_plugin::on_me(irccd& , const me_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.message); - call("onMe", 4); -} - -void js_plugin::on_mode(irccd& , const mode_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.mode); - call("onMode", 3); -} - -void js_plugin::on_names(irccd& , const names_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.channel); - dukx_push_array(context_, event.names, dukx_push_std_string); - call("onNames", 3); -} - -void js_plugin::on_nick(irccd& , const nick_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.nickname); - call("onNick", 3); -} - -void js_plugin::on_notice(irccd& , const notice_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.message); - call("onNotice", 3); -} - -void js_plugin::on_part(irccd& , const part_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.reason); - call("onPart", 4); -} - -void js_plugin::on_query(irccd& , const query_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.message); - call("onQuery", 3); -} - -void js_plugin::on_query_command(irccd& , const query_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.message); - call("onQueryCommand", 3); -} - -void js_plugin::on_reload(irccd& ) -{ - StackAssert sa(context_); - - call("onReload"); -} - -void js_plugin::on_topic(irccd& , const topic_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - dukx_push_std_string(context_, event.origin); - dukx_push_std_string(context_, event.channel); - dukx_push_std_string(context_, event.topic); - call("onTopic", 4); -} - -void js_plugin::on_unload(irccd& ) -{ - StackAssert sa(context_); - - call("onUnload"); -} - -void js_plugin::on_whois(irccd& , const whois_event &event) -{ - StackAssert sa(context_); - - dukx_push_server(context_, std::move(event.server)); - duk_push_object(context_); - dukx_push_std_string(context_, event.whois.nick); - duk_put_prop_string(context_, -2, "nickname"); - dukx_push_std_string(context_, event.whois.user); - duk_put_prop_string(context_, -2, "username"); - dukx_push_std_string(context_, event.whois.realname); - duk_put_prop_string(context_, -2, "realname"); - dukx_push_std_string(context_, event.whois.host); - duk_put_prop_string(context_, -2, "host"); - dukx_push_array(context_, event.whois.channels, dukx_push_std_string); - duk_put_prop_string(context_, -2, "channels"); - call("onWhois", 2); -} - -js_plugin_loader::js_plugin_loader(irccd& irccd) noexcept - : plugin_loader({}, { ".js" }) - , irccd_(irccd) -{ -} - -js_plugin_loader::~js_plugin_loader() noexcept = default; - -void js_plugin_loader::add_module(std::unique_ptr module) -{ - assert(module); - - modules_.push_back(std::move(module)); -} - -std::shared_ptr js_plugin_loader::open(const std::string& id, - const std::string& path) noexcept -{ - if (path.rfind(".js") == std::string::npos) - return nullptr; - - try { - auto plugin = std::make_shared(id, path); - - for (const auto& mod : modules_) - mod->load(irccd_, plugin); - - plugin->open(); - - return plugin; - } catch (const std::exception &ex) { - log::warning() << "plugin " << id << ": " << ex.what() << std::endl; - } - - return nullptr; -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_plugin.hpp --- a/libirccd-js/irccd/js_plugin.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ -/* - * js_plugin.hpp -- JavaScript plugins for irccd - * - * 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_JS_PLUGIN_HPP -#define IRCCD_JS_PLUGIN_HPP - -/** - * \file js_plugin.hpp - * \brief JavaScript plugins for irccd. - */ - -#include - -#include "duktape.hpp" -#include "plugin.hpp" - -namespace irccd { - -class module; - -/** - * \brief JavaScript plugins for irccd. - * \ingroup plugins - */ -class js_plugin : public plugin { -public: - /** - * List of modules to enable. - */ - using modules_t = std::vector>; - - /** - * Global property where to read/write plugin configuration (object). - */ - static const std::string config_property; - - /** - * Global property where to read/write plugin formats (object). - */ - static const std::string format_property; - - /** - * Global property where paths are defined (object). - */ - static const std::string paths_property; - -private: - // JavaScript context - UniqueContext context_; - - // Private helpers. - std::unordered_map get_table(const std::string&) const; - void put_table(const std::string&, const std::unordered_map&); - void call(const std::string&, unsigned = 0); - -public: - /** - * Constructor. - * - * \param name the plugin name - * \param path the path to the plugin - */ - js_plugin(std::string name, std::string path); - - /** - * Access the Duktape context. - * - * \return the context - */ - inline UniqueContext& context() noexcept - { - return context_; - } - - /** - * Open the script file associated. - */ - void open(); - - /** - * \copydoc Plugin::config - */ - plugin_config config() override - { - return get_table(config_property); - } - - /** - * \copydoc Plugin::setConfig - */ - void set_config(plugin_config config) override - { - put_table(config_property, config); - } - - /** - * \copydoc Plugin::formats - */ - plugin_formats formats() override - { - return get_table(format_property); - } - - /** - * \copydoc Plugin::setFormats - */ - void set_formats(plugin_formats formats) override - { - put_table(format_property, formats); - } - - /** - * \copydoc Plugin::paths - */ - plugin_paths paths() override - { - return get_table(paths_property); - } - - /** - * \copydoc Plugin::set_paths - */ - void set_paths(plugin_paths paths) override - { - put_table(paths_property, std::move(paths)); - } - - /** - * \copydoc Plugin::on_command - */ - void on_command(irccd& irccd, const message_event& event) override; - - /** - * \copydoc Plugin::on_connect - */ - void on_connect(irccd& irccd, const connect_event& event) override; - - /** - * \copydoc Plugin::on_channel_mode - */ - void on_channel_mode(irccd& irccd, const channel_mode_event& event) override; - - /** - * \copydoc Plugin::on_channel_notice - */ - void on_channel_notice(irccd& irccd, const channel_notice_event& event) override; - - /** - * \copydoc Plugin::on_invite - */ - void on_invite(irccd& irccd, const invite_event& event) override; - - /** - * \copydoc Plugin::on_join - */ - void on_join(irccd& irccd, const join_event& event) override; - - /** - * \copydoc Plugin::on_kick - */ - void on_kick(irccd& irccd, const kick_event& event) override; - - /** - * \copydoc Plugin::on_load - */ - void on_load(irccd& irccd) override; - - /** - * \copydoc Plugin::on_message - */ - void on_message(irccd& irccd, const message_event& event) override; - - /** - * \copydoc Plugin::on_me - */ - void on_me(irccd& irccd, const me_event& event) override; - - /** - * \copydoc Plugin::on_mode - */ - void on_mode(irccd& irccd, const mode_event& event) override; - - /** - * \copydoc Plugin::on_names - */ - void on_names(irccd& irccd, const names_event& event) override; - - /** - * \copydoc Plugin::on_nick - */ - void on_nick(irccd& irccd, const nick_event& event) override; - - /** - * \copydoc Plugin::on_notice - */ - void on_notice(irccd& irccd, const notice_event& event) override; - - /** - * \copydoc Plugin::on_part - */ - void on_part(irccd& irccd, const part_event& event) override; - - /** - * \copydoc Plugin::on_query - */ - void on_query(irccd& irccd, const query_event& event) override; - - /** - * \copydoc Plugin::on_query_command - */ - void on_query_command(irccd& irccd, const query_event& event) override; - - /** - * \copydoc Plugin::on_reload - */ - void on_reload(irccd& irccd) override; - - /** - * \copydoc Plugin::on_topic - */ - void on_topic(irccd& irccd, const topic_event& event) override; - - /** - * \copydoc Plugin::on_unload - */ - void on_unload(irccd& irccd) override; - - /** - * \copydoc Plugin::on_whois - */ - void on_whois(irccd& irccd, const whois_event& event) override; -}; - -/** - * \brief Implementation for searching Javascript plugins. - */ -class js_plugin_loader : public plugin_loader { -public: - using modules_t = std::vector>; - -private: - irccd& irccd_; - modules_t modules_; - -public: - /** - * Constructor. - * - * \param irccd the irccd instance - */ - js_plugin_loader(irccd& irccd) noexcept; - - /** - * Destructor defaulted. - */ - ~js_plugin_loader() noexcept; - - /** - * Get the list of modules. - * - * \return the modules - */ - inline const modules_t& modules() const noexcept - { - return modules_; - } - - /** - * Overloaded function. - * - * \return the modules - */ - inline modules_t& modules() noexcept - { - return modules_; - } - - /** - * Register a new module for loading new plugins. - * - * \deprecated use modules() instead - * \param module the module to add - */ - void add_module(std::unique_ptr module); - - /** - * \copydoc PluginLoader::open - */ - std::shared_ptr open(const std::string& id, - const std::string& path) noexcept override; -}; - -} // !irccd - -#endif // !IRCCD_PLUGIN_JS_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_plugin_module.cpp --- a/libirccd-js/irccd/js_plugin_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,385 +0,0 @@ -/* - * js_plugin_module.cpp -- Irccd.Plugin API - * - * 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 -#include - -#include "js_irccd_module.hpp" -#include "js_plugin.hpp" -#include "js_plugin_module.hpp" - -namespace irccd { - -namespace { - -const char plugin_ref[] = "\xff""\xff""irccd-plugin-ptr"; - -/* - * wrap - * ------------------------------------------------------------------ - * - * Wrap function for these functions because they all takes the same arguments. - * - * - load, - * - reload, - * - unload. - */ -template -duk_idx_t wrap(duk_context* ctx, int nret, Func&& func) -{ - std::string name = duk_require_string(ctx, 0); - - try { - func(dukx_get_irccd(ctx), name); - } catch (const std::out_of_range &ex) { - dukx_throw(ctx, ReferenceError(ex.what())); - } catch (const std::exception &ex) { - dukx_throw(ctx, Error(ex.what())); - } - - return nret; -} - -/* - * set - * ------------------------------------------------------------------ - * - * This setter is used to replace the Irccd.Plugin.(config|format|paths) - * property when the plugin assign a new one. - * - * Because the plugin configuration always has higher priority, when a new - * object is assigned to 'config' or to the 'format' property, the plugin - * configuration is merged to the assigned one, adding or replacing any values. - * - * Example: - * - * Plugin 'xyz' does: - * - * Irccd.Plugin.config = { - * mode: "simple", - * level: "123" - * }; - * - * The user configuration is: - * - * [plugin.xyz] - * mode = "hard" - * path = "/var" - * - * The final user table looks like this: - * - * Irccd.Plugin.Config = { - * mode: "hard", - * level: "123", - * path: "/var" - * }; - */ -duk_ret_t set(duk_context* ctx, const std::string& name) -{ - if (!duk_is_object(ctx, 0)) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name.c_str()); - - // Merge old table with new one. - duk_get_global_string(ctx, name.c_str()); - duk_enum(ctx, -1, 0); - - while (duk_next(ctx, -1, true)) - duk_put_prop(ctx, 0); - - // Pop enum and old table. - duk_pop_2(ctx); - - // Replace the old table with the new assigned one. - duk_put_global_string(ctx, name.c_str()); - - return 0; -} - -/* - * get - * ------------------------------------------------------------------ - * - * Get the Irccd.Plugin.(config|format|paths) property. - */ -duk_ret_t get(duk_context* ctx, const std::string& name) -{ - duk_get_global_string(ctx, name.c_str()); - - return 1; -} - -/* - * set_config - * ------------------------------------------------------------------ - * - * Wrap setter for Irccd.Plugin.config property. - */ -duk_ret_t set_config(duk_context* ctx) -{ - return set(ctx, js_plugin::config_property); -} - -/* - * get_config - * ------------------------------------------------------------------ - * - * Wrap getter for Irccd.Plugin.config property. - */ -duk_ret_t get_config(duk_context* ctx) -{ - return get(ctx, js_plugin::config_property); -} - -/* - * set_format - * ------------------------------------------------------------------ - * - * Wrap setter for Irccd.Plugin.format property. - */ -duk_ret_t set_format(duk_context* ctx) -{ - return set(ctx, js_plugin::format_property); -} - -/* - * get_format - * ------------------------------------------------------------------ - * - * Wrap getter for Irccd.Plugin.format property. - */ -duk_ret_t get_format(duk_context* ctx) -{ - return get(ctx, js_plugin::format_property); -} - -/* - * set_paths - * ------------------------------------------------------------------ - * - * Wrap setter for Irccd.Plugin.format property. - */ -duk_ret_t set_paths(duk_context* ctx) -{ - return set(ctx, js_plugin::paths_property); -} - -/* - * get_paths - * ------------------------------------------------------------------ - * - * Wrap getter for Irccd.Plugin.format property. - */ -duk_ret_t get_paths(duk_context* ctx) -{ - return get(ctx, js_plugin::paths_property); -} - -/* - * Function: Irccd.Plugin.info([name]) - * ------------------------------------------------------------------ - * - * Get information about a plugin. - * - * The returned object as the following properties: - * - * - name: (string) the plugin identifier, - * - author: (string) the author, - * - license: (string) the license, - * - summary: (string) a short description, - * - version: (string) the version - * - * Arguments: - * - name, the plugin identifier, if not specified the current plugin is - * selected. - * Returns: - * The plugin information or undefined if the plugin was not found. - */ -duk_idx_t info(duk_context* ctx) -{ - std::shared_ptr plugin; - - if (duk_get_top(ctx) >= 1) - plugin = dukx_get_irccd(ctx).plugins().get(duk_require_string(ctx, 0)); - else - plugin = dukx_get_plugin(ctx); - - if (!plugin) - return 0; - - duk_push_object(ctx); - dukx_push_std_string(ctx, plugin->name()); - duk_put_prop_string(ctx, -2, "name"); - dukx_push_std_string(ctx, plugin->author()); - duk_put_prop_string(ctx, -2, "author"); - dukx_push_std_string(ctx, plugin->license()); - duk_put_prop_string(ctx, -2, "license"); - dukx_push_std_string(ctx, plugin->summary()); - duk_put_prop_string(ctx, -2, "summary"); - dukx_push_std_string(ctx, plugin->version()); - duk_put_prop_string(ctx, -2, "version"); - - return 1; -} - -/* - * Function: Irccd.Plugin.list() - * ------------------------------------------------------------------ - * - * Get the list of plugins, the array returned contains all plugin names. - * - * Returns: - * The list of all plugin names. - */ -duk_idx_t list(duk_context* ctx) -{ - dukx_push_array(ctx, dukx_get_irccd(ctx).plugins().list(), [] (auto ctx, auto plugin) { - dukx_push_std_string(ctx, plugin->name()); - }); - - return 1; -} - -/* - * Function: Irccd.Plugin.load(name) - * ------------------------------------------------------------------ - * - * Load a plugin by name. This function will search through the standard - * directories. - * - * Arguments: - * - name, the plugin identifier. - * Throws: - * - Error on errors, - * - ReferenceError if the plugin was not found. - */ -duk_idx_t load(duk_context* ctx) -{ - return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) { - irccd.plugins().load(name); - }); -} - -/* - * Function: Irccd.Plugin.reload(name) - * ------------------------------------------------------------------ - * - * Reload a plugin by name. - * - * Arguments: - * - name, the plugin identifier. - * Throws: - * - Error on errors, - * - ReferenceError if the plugin was not found. - */ -duk_idx_t reload(duk_context* ctx) -{ - return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) { - irccd.plugins().reload(name); - }); -} - -/* - * Function: Irccd.Plugin.unload(name) - * ------------------------------------------------------------------ - * - * Unload a plugin by name. - * - * Arguments: - * - name, the plugin identifier. - * Throws: - * - Error on errors, - * - ReferenceError if the plugin was not found. - */ -duk_idx_t unload(duk_context* ctx) -{ - return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) { - irccd.plugins().unload(name); - }); -} - -const duk_function_list_entry functions[] = { - { "info", info, DUK_VARARGS }, - { "list", list, 0 }, - { "load", load, 1 }, - { "reload", reload, 1 }, - { "unload", unload, 1 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -js_plugin_module::js_plugin_module() noexcept - : module("Irccd.Plugin") -{ -} - -void js_plugin_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_push_pointer(plugin->context(), new std::weak_ptr(plugin)); - duk_push_object(plugin->context()); - duk_push_c_function(plugin->context(), [] (auto ctx) -> duk_ret_t { - duk_get_global_string(ctx, plugin_ref); - delete static_cast*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_push_null(ctx); - duk_put_global_string(ctx, plugin_ref); - return 0; - }, 1); - duk_set_finalizer(plugin->context(), -2); - duk_put_global_string(plugin->context(), "\xff""\xff""dummy-shared-ptr"); - duk_put_global_string(plugin->context(), plugin_ref); - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, functions); - - // 'config' property. - duk_push_string(plugin->context(), "config"); - duk_push_c_function(plugin->context(), get_config, 0); - duk_push_c_function(plugin->context(), set_config, 1); - duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); - - // 'format' property. - duk_push_string(plugin->context(), "format"); - duk_push_c_function(plugin->context(), get_format, 0); - duk_push_c_function(plugin->context(), set_format, 1); - duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); - - // 'format' property. - duk_push_string(plugin->context(), "paths"); - duk_push_c_function(plugin->context(), get_paths, 0); - duk_push_c_function(plugin->context(), set_paths, 1); - duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); - - duk_put_prop_string(plugin->context(), -2, "Plugin"); - duk_pop(plugin->context()); -} - -std::shared_ptr dukx_get_plugin(duk_context* ctx) -{ - StackAssert sa(ctx); - - duk_get_global_string(ctx, plugin_ref); - auto plugin = static_cast*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return plugin->lock(); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_plugin_module.hpp --- a/libirccd-js/irccd/js_plugin_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * js_plugin_module.hpp -- Irccd.Plugin API - * - * 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_JS_PLUGIN_MODULE_HPP -#define IRCCD_JS_PLUGIN_MODULE_HPP - -/** - * \file js_plugin_module.hpp - * \brief Irccd.Plugin JavaScript API. - */ - -#include "duktape.hpp" -#include "module.hpp" - -namespace irccd { - -/** - * \brief Irccd.Plugin JavaScript API. - * \ingroup modules - */ -class js_plugin_module : public module { -public: - /** - * Irccd.Plugin. - */ - js_plugin_module() noexcept; - - /** - * \copydoc Module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -/** - * Access the plugin stored in this context. - * - * \param ctx the context - * \return the plugin - */ -std::shared_ptr dukx_get_plugin(duk_context* ctx); - -} // !irccd - -#endif // !IRCCD_JS_PLUGIN_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_server_module.cpp --- a/libirccd-js/irccd/js_server_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,581 +0,0 @@ -/* - * js_server_module.cpp -- Irccd.Server API - * - * 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 -#include -#include - -#include -#include -#include -#include - -#include "js_irccd_module.hpp" -#include "js_server_module.hpp" - -namespace irccd { - -namespace { - -const char *signature("\xff""\xff""irccd-server-ptr"); -const char *prototype("\xff""\xff""irccd-server-prototype"); - -std::shared_ptr self(duk_context* ctx) -{ - StackAssert sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); - - return *static_cast*>(ptr); -} - -/* - * Method: Server.cmode(channel, mode) - * ------------------------------------------------------------------ - * - * Change a channel mode. - * - * Arguments: - * - channel, the channel, - * - mode, the mode. - */ -duk_ret_t cmode(duk_context* ctx) -{ - self(ctx)->cmode(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.cnotice(channel, message) - * ------------------------------------------------------------------ - * - * Send a channel notice. - * - * Arguments: - * - channel, the channel, - * - message, the message. - */ -duk_ret_t cnotice(duk_context* ctx) -{ - self(ctx)->cnotice(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.info() - * ------------------------------------------------------------------ - * - * Get the server information as an object containing the following properties: - * - * name: the server unique name - * host: the host name - * port: the port number - * ssl: true if using ssl - * sslVerify: true if ssl was verified - * channels: an array of all channels - */ -duk_ret_t info(duk_context* ctx) -{ - auto server = self(ctx); - - duk_push_object(ctx); - dukx_push_std_string(ctx, server->name()); - duk_put_prop_string(ctx, -2, "name"); - dukx_push_std_string(ctx, server->host()); - duk_put_prop_string(ctx, -2, "host"); - duk_push_int(ctx, server->port()); - duk_put_prop_string(ctx, -2, "port"); - duk_push_boolean(ctx, server->flags() & server::ssl); - duk_put_prop_string(ctx, -2, "ssl"); - duk_push_boolean(ctx, server->flags() & server::ssl_verify); - duk_put_prop_string(ctx, -2, "sslVerify"); - dukx_push_std_string(ctx, server->command_char()); - duk_put_prop_string(ctx, -2, "commandChar"); - dukx_push_std_string(ctx, server->realname()); - duk_put_prop_string(ctx, -2, "realname"); - dukx_push_std_string(ctx, server->nickname()); - duk_put_prop_string(ctx, -2, "nickname"); - dukx_push_std_string(ctx, server->username()); - duk_put_prop_string(ctx, -2, "username"); - dukx_push_array(ctx, server->channels(), [&] (auto ctx, auto channel) { - dukx_push_std_string(ctx, channel); - }); - duk_put_prop_string(ctx, -2, "channels"); - - return 1; -} - -/* - * Method: Server.invite(target, channel) - * ------------------------------------------------------------------ - * - * Invite someone to a channel. - * - * Arguments: - * - target, the target to invite, - * - channel, the channel. - */ -duk_ret_t invite(duk_context* ctx) -{ - self(ctx)->invite(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.join(channel, password = undefined) - * ------------------------------------------------------------------ - * - * Join a channel with an optional password. - * - * Arguments: - * - channel, the channel to join, - * - password, the password or undefined to not use. - */ -duk_ret_t join(duk_context* ctx) -{ - self(ctx)->join(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.kick(target, channel, reason = undefined) - * ------------------------------------------------------------------ - * - * Kick someone from a channel. - * - * Arguments: - * - target, the target to kick, - * - channel, the channel, - * - reason, the optional reason or undefined to not set. - */ -duk_ret_t kick(duk_context* ctx) -{ - self(ctx)->kick(duk_require_string(ctx, 0), duk_require_string(ctx, 1), dukx_get_std_string(ctx, 2)); - - return 0; -} - -/* - * Method: Server.me(target, message) - * ------------------------------------------------------------------ - * - * Send a CTCP Action. - * - * Arguments: - * - target, the target or a channel, - * - message, the message. - */ -duk_ret_t me(duk_context* ctx) -{ - self(ctx)->me(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.message(target, message) - * ------------------------------------------------------------------ - * - * Send a message. - * - * Arguments: - * - target, the target or a channel, - * - message, the message. - */ -duk_ret_t message(duk_context* ctx) -{ - self(ctx)->message(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.mode(mode) - * ------------------------------------------------------------------ - * - * Change your mode. - * - * Arguments: - * - mode, the new mode. - */ -duk_ret_t mode(duk_context* ctx) -{ - self(ctx)->mode(duk_require_string(ctx, 0)); - - return 0; -} - -/* - * Method: Server.names(channel) - * ------------------------------------------------------------------ - * - * Get the list of names from a channel. - * - * Arguments: - * - channel, the channel. - */ -duk_ret_t names(duk_context* ctx) -{ - self(ctx)->names(duk_require_string(ctx, 0)); - - return 0; -} - -/* - * Method: Server.nick(nickname) - * ------------------------------------------------------------------ - * - * Change the nickname. - * - * Arguments: - * - nickname, the nickname. - */ -duk_ret_t nick(duk_context* ctx) -{ - self(ctx)->set_nickname(duk_require_string(ctx, 0)); - - return 0; -} - -/* - * Method: Server.notice(target, message) - * ------------------------------------------------------------------ - * - * Send a private notice. - * - * Arguments: - * - target, the target, - * - message, the notice message. - */ -duk_ret_t notice(duk_context* ctx) -{ - self(ctx)->notice(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.part(channel, reason = undefined) - * ------------------------------------------------------------------ - * - * Leave a channel. - * - * Arguments: - * - channel, the channel to leave, - * - reason, the optional reason, keep undefined for portability. - */ -duk_ret_t part(duk_context* ctx) -{ - self(ctx)->part(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.send(raw) - * ------------------------------------------------------------------ - * - * Send a raw message to the IRC server. - * - * Arguments: - * - raw, the raw message (without terminators). - */ -duk_ret_t send(duk_context* ctx) -{ - self(ctx)->send(duk_require_string(ctx, 0)); - - return 0; -} - -/* - * Method: Server.topic(channel, topic) - * ------------------------------------------------------------------ - * - * Change a channel topic. - * - * Arguments: - * - channel, the channel, - * - topic, the new topic. - */ -duk_ret_t topic(duk_context* ctx) -{ - self(ctx)->topic(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - return 0; -} - -/* - * Method: Server.whois(target) - * ------------------------------------------------------------------ - * - * Get whois information. - * - * Arguments: - * - target, the target. - */ -duk_ret_t whois(duk_context* ctx) -{ - self(ctx)->whois(duk_require_string(ctx, 0)); - - return 0; -} - -/* - * Method: Server.toString() - * ------------------------------------------------------------------ - * - * Convert the object to std::string, convenience for adding the object - * as property key. - * - * duk_ret_turns: - * The server name (unique). - */ -duk_ret_t toString(duk_context* ctx) -{ - dukx_push_std_string(ctx, self(ctx)->name()); - - return 1; -} - -/* - * Function: Irccd.Server(params) [constructor] - * ------------------------------------------------------------------ - * - * Construct a new server. - * - * Params must be filled with the following properties: - * - * name: the name, - * host: the host, - * ipv6: true to use ipv6, (Optional: default false) - * port: the port number, (Optional: default 6667) - * password: the password, (Optional: default none) - * channels: array of channels (Optiona: default empty) - * ssl: true to use ssl, (Optional: default false) - * sslVerify: true to verify (Optional: default true) - * nickname: "nickname", (Optional, default: irccd) - * username: "user name", (Optional, default: irccd) - * realname: "real name", (Optional, default: IRC Client Daemon) - * commandChar: "!", (Optional, the command char, default: "!") - */ -duk_ret_t constructor(duk_context* ctx) -{ - if (!duk_is_constructor_call(ctx)) - return 0; - - duk_check_type(ctx, 0, DUK_TYPE_OBJECT); - - try { - auto json = duk_json_encode(ctx, 0); - auto s = server::from_json(nlohmann::json::parse(json)); - - duk_push_this(ctx); - duk_push_pointer(ctx, new std::shared_ptr(std::move(s))); - duk_put_prop_string(ctx, -2, signature); - duk_pop(ctx); - } catch (const std::exception& ex) { - duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -/* - * Function: Irccd.Server() [destructor] - * ------------------------------------------------------------------ - * - * Delete the property. - */ -duk_ret_t destructor(duk_context* ctx) -{ - duk_get_prop_string(ctx, 0, signature); - delete static_cast*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_del_prop_string(ctx, 0, signature); - - return 0; -} - -/* - * Function: Irccd.Server.add(s) - * ------------------------------------------------------------------ - * - * Register a new server to the irccd instance. - * - * Arguments: - * - s, the server to add. - */ -duk_ret_t add(duk_context* ctx) -{ - dukx_get_irccd(ctx).servers().add(dukx_require_server(ctx, 0)); - - return 0; -} - -/* - * Function: Irccd.Server.find(name) - * ------------------------------------------------------------------ - * - * Find a server by name. - * - * Arguments: - * - name, the server name - * duk_ret_turns: - * The server object or undefined if not found. - */ -duk_ret_t find(duk_context* ctx) -{ - auto server = dukx_get_irccd(ctx).servers().get(duk_require_string(ctx, 0)); - - if (!server) - return 0; - - dukx_push_server(ctx, server); - - return 1; -} - -/* - * Function: Irccd.Server.list() - * ------------------------------------------------------------------ - * - * Get the map of all loaded servers. - * - * duk_ret_turns: - * An object with string-to-servers pairs. - */ -duk_ret_t list(duk_context* ctx) -{ - duk_push_object(ctx); - - for (const auto &server : dukx_get_irccd(ctx).servers().servers()) { - dukx_push_server(ctx, server); - duk_put_prop_string(ctx, -2, server->name().c_str()); - } - - return 1; -} - -/* - * Function: irccd.Server.remove(name) - * ------------------------------------------------------------------ - * - * Remove a server from the irccd instance. You can pass the server object since - * it's coercible to a string. - * - * Arguments: - * - name the server name. - */ -duk_ret_t remove(duk_context* ctx) -{ - dukx_get_irccd(ctx).servers().remove(duk_require_string(ctx, 0)); - - return 0; -} - -const duk_function_list_entry methods[] = { - { "cmode", cmode, 2 }, - { "cnotice", cnotice, 2 }, - { "info", info, 0 }, - { "invite", invite, 2 }, - { "join", join, DUK_VARARGS }, - { "kick", kick, DUK_VARARGS }, - { "me", me, 2 }, - { "message", message, 2 }, - { "mode", mode, 1 }, - { "names", names, 1 }, - { "nick", nick, 1 }, - { "notice", notice, 2 }, - { "part", part, DUK_VARARGS }, - { "send", send, 1 }, - { "topic", topic, 2 }, - { "whois", whois, 1 }, - { "toString", toString, 0 }, - { nullptr, nullptr, 0 } -}; - -const duk_function_list_entry functions[] = { - { "add", add, 1 }, - { "find", find, 1 }, - { "list", list, 0 }, - { "remove", remove, 1 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -js_server_module::js_server_module() noexcept - : module("Irccd.Server") -{ -} - -void js_server_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_c_function(plugin->context(), constructor, 1); - duk_put_function_list(plugin->context(), -1, functions); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, methods); - duk_push_c_function(plugin->context(), destructor, 1); - duk_set_finalizer(plugin->context(), -2); - duk_dup_top(plugin->context()); - duk_put_global_string(plugin->context(), prototype); - duk_put_prop_string(plugin->context(), -2, "prototype"); - duk_put_prop_string(plugin->context(), -2, "Server"); - duk_pop(plugin->context()); -} - -void dukx_push_server(duk_context* ctx, std::shared_ptr server) -{ - assert(ctx); - assert(server); - - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - duk_push_pointer(ctx, new std::shared_ptr(std::move(server))); - duk_put_prop_string(ctx, -2, signature); - duk_get_global_string(ctx, prototype); - duk_set_prototype(ctx, -2); -} - -std::shared_ptr dukx_require_server(duk_context* ctx, duk_idx_t index) -{ - if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, signature)) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); - - duk_get_prop_string(ctx, index, signature); - auto file = *static_cast *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return file; -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_server_module.hpp --- a/libirccd-js/irccd/js_server_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * js_server_module.hpp -- Irccd.Server API - * - * 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_JS_SERVER_MODULE_HPP -#define IRCCD_JS_SERVER_MODULE_HPP - -/** - * \file mod-server.hpp - * \brief irccd.Server JavaScript API. - */ - -#include "duktape.hpp" -#include "module.hpp" -#include "server.hpp" - -namespace irccd { - -/** - * \brief irccd.Server JavaScript API. - * \ingroup modules - */ -class js_server_module : public module { -public: - /** - * irccd.Server. - */ - js_server_module() noexcept; - - /** - * \copydoc Module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -/** - * Push a server. - * - * \pre server != nullptr - * \param ctx the context - * \param server the server - */ -void dukx_push_server(duk_context* ctx, std::shared_ptr server); - -/** - * Require a server. Raise a JavaScript error if not a Server. - * - * \param ctx the context - * \param index the index - * \return the server - */ -std::shared_ptr dukx_require_server(duk_context* ctx, duk_idx_t index); - -} // !irccd - -#endif // !IRCCD_JS_SERVER_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_system_module.cpp --- a/libirccd-js/irccd/js_system_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,244 +0,0 @@ -/* - * js_system_module.cpp -- Irccd.System API - * - * 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 -#include -#include - -#include - -#if defined(HAVE_POPEN) -# include -#endif - -#include -#include - -#include "js_file_module.hpp" -#include "js_irccd_module.hpp" -#include "js_system_module.hpp" - -namespace irccd { - -namespace { - -/* - * Function: irccd.System.env(key) - * ------------------------------------------------------------------ - * - * Get an environment system variable. - * - * Arguments: - * - key, the environment variable. - * Returns: - * The value. - */ -duk_ret_t env(duk_context* ctx) -{ - dukx_push_std_string(ctx, sys::env(dukx_get_std_string(ctx, 0))); - - return 1; -} - -/* - * Function: irccd.System.exec(cmd) - * ------------------------------------------------------------------ - * - * Execute a system command. - * - * Arguments: - * - cmd, the command to execute. - */ -duk_ret_t exec(duk_context* ctx) -{ - std::system(duk_get_string(ctx, 0)); - - return 0; -} - -/* - * Function: irccd.System.home() - * ------------------------------------------------------------------ - * - * Get the operating system user's home. - * - * Returns: - * The user home directory. - */ -duk_ret_t home(duk_context* ctx) -{ - dukx_push_std_string(ctx, sys::home()); - - return 1; -} - -/* - * Function: irccd.System.name() - * ------------------------------------------------------------------ - * - * Get the operating system name. - * - * Returns: - * The system name. - */ -duk_ret_t name(duk_context* ctx) -{ - dukx_push_std_string(ctx, sys::name()); - - return 1; -} - -#if defined(HAVE_POPEN) - -/* - * Function: irccd.System.popen(cmd, mode) [optional] - * ------------------------------------------------------------------ - * - * Wrapper for popen(3) if the function is available. - * - * Arguments: - * - cmd, the command to execute, - * - mode, the mode (e.g. "r"). - * Returns: - * A irccd.File object. - * Throws - * - irccd.system_error on failures. - */ -duk_ret_t popen(duk_context* ctx) -{ - auto fp = ::popen(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); - - if (fp == nullptr) - dukx_throw(ctx, system_error()); - - dukx_push_file(ctx, new file(fp, [] (auto fp) { ::pclose(fp); })); - - return 1; -} - -#endif // !HAVE_POPEN - -/* - * Function: irccd.System.sleep(delay) - * ------------------------------------------------------------------ - * - * Sleep the main loop for the specific delay in seconds. - */ -duk_ret_t sleep(duk_context* ctx) -{ - std::this_thread::sleep_for(std::chrono::seconds(duk_get_int(ctx, 0))); - - return 0; -} - -/* - * Function: irccd.System.ticks() - * ------------------------------------------------------------------ - * - * Get the number of milliseconds since irccd was started. - * - * Returns: - * The number of milliseconds. - */ -duk_ret_t ticks(duk_context* ctx) -{ - duk_push_int(ctx, sys::ticks()); - - return 1; -} - -/* - * Function: irccd.System.usleep(delay) - * ------------------------------------------------------------------ - * - * Sleep the main loop for the specific delay in microseconds. - */ -duk_ret_t usleep(duk_context* ctx) -{ - std::this_thread::sleep_for(std::chrono::microseconds(duk_get_int(ctx, 0))); - - return 0; -} - -/* - * Function: irccd.System.uptime() - * ------------------------------------------------------------------ - * - * Get the system uptime. - * - * Returns: - * The system uptime. - */ -duk_ret_t uptime(duk_context* ctx) -{ - duk_push_int(ctx, sys::uptime()); - - return 0; -} - -/* - * Function: irccd.System.version() - * ------------------------------------------------------------------ - * - * Get the operating system version. - * - * Returns: - * The system version. - */ -duk_ret_t version(duk_context* ctx) -{ - dukx_push_std_string(ctx, sys::version()); - - return 1; -} - -const duk_function_list_entry functions[] = { - { "env", env, 1 }, - { "exec", exec, 1 }, - { "home", home, 0 }, - { "name", name, 0 }, -#if defined(HAVE_POPEN) - { "popen", popen, 2 }, -#endif - { "sleep", sleep, 1 }, - { "ticks", ticks, 0 }, - { "uptime", uptime, 0 }, - { "usleep", usleep, 1 }, - { "version", version, 0 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -js_system_module::js_system_module() noexcept - : module("Irccd.System") -{ -} - -void js_system_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, functions); - duk_put_prop_string(plugin->context(), -2, "System"); - duk_pop(plugin->context()); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_system_module.hpp --- a/libirccd-js/irccd/js_system_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_system_module.hpp -- Irccd.System API - * - * 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_JS_SYSTEM_MODULE_HPP -#define IRCCD_JS_SYSTEM_MODULE_HPP - -/** - * \file mod-system.hpp - * \brief irccd.System JavaScript API. - */ - -#include "module.hpp" - -namespace irccd { - -/** - * \brief irccd.System JavaScript API. - * \ingroup modules - */ -class js_system_module : public module { -public: - /** - * irccd.System. - */ - js_system_module() noexcept; - - /** - * \copydoc Module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -} // !irccd - -#endif // !IRCCD_JS_SYSTEM_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_timer_module.cpp --- a/libirccd-js/irccd/js_timer_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,208 +0,0 @@ -/* - * js_timer_module.cpp -- Irccd.timer API - * - * 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 -#include -#include -#include -#include - -#include "js_irccd_module.hpp" -#include "js_plugin_module.hpp" -#include "js_timer_module.hpp" - -namespace irccd { - -namespace { - -const char* signature("\xff""\xff""irccd-timer-ptr"); -const char* callback_table("\xff""\xff""irccd-timer-callbacks"); - -void handle_signal(irccd& instance, std::weak_ptr ptr, std::string key) -{ - auto plugin = ptr.lock(); - - if (!plugin) - return; - - instance.post([plugin, key] (irccd &) { - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), callback_table); - duk_get_prop_string(plugin->context(), -1, key.c_str()); - duk_remove(plugin->context(), -2); - - if (duk_is_callable(plugin->context(), -1)) { - if (duk_pcall(plugin->context(), 0) != 0) - log::warning(string_util::sprintf("plugin %s: %s", plugin->name(), - dukx_exception(plugin->context(), -1).stack)); - else - duk_pop(plugin->context()); - } else - duk_pop(plugin->context()); - }); -} - -std::shared_ptr self(duk_context* ctx) -{ - StackAssert sa(ctx); - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, signature); - auto ptr = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!ptr) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a timer object"); - - return *static_cast*>(ptr); -} - -/* - * Method: timer.start() - * -------------------------------------------------------- - * - * Start the timer. If the timer is already started the method is a no-op. - */ -duk_ret_t start(duk_context* ctx) -{ - auto timer = self(ctx); - - if (!timer->is_running()) - timer->start(); - - return 0; -} - -/* - * Method: timer.stop() - * -------------------------------------------------------- - * - * Stop the timer. - */ -duk_ret_t stop(duk_context* ctx) -{ - auto timer = self(ctx); - - if (timer->is_running()) - timer->stop(); - - return 0; -} - -const duk_function_list_entry methods[] = { - { "start", start, 0 }, - { "stop", stop, 0 }, - { nullptr, nullptr, 0 } -}; - -/* - * Function: Irccd.timer(type, delay, callback) [constructor] - * -------------------------------------------------------- - * - * Create a new timer object. - * - * Arguments: - * - type, the type of timer (irccd.timer.Single or irccd.timer.Repeat), - * - delay, the interval in milliseconds, - * - callback, the function to call. - */ -duk_ret_t constructor(duk_context* ctx) -{ - // Check parameters. - auto type = duk_require_int(ctx, 0); - auto delay = duk_require_int(ctx, 1); - - if (type < static_cast(timer::type::single) || type > static_cast(timer::type::repeat)) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type"); - if (delay < 0) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "negative delay given"); - if (!duk_is_callable(ctx, 2)) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function"); - - // Construct the timer in 'this'. - auto& irccd = dukx_get_irccd(ctx); - auto tm = std::make_shared(static_cast(type), delay); - auto hash = std::to_string(reinterpret_cast(tm.get())); - - tm->on_signal.connect(std::bind(handle_signal, std::ref(irccd), - std::weak_ptr(dukx_get_plugin(ctx)), hash)); - - duk_push_this(ctx); - duk_push_pointer(ctx, new std::shared_ptr(std::move(tm))); - duk_put_prop_string(ctx, -2, signature); - duk_push_string(ctx, hash.c_str()); - duk_put_prop_string(ctx, -2, "\xff""\xff""timer-key"); - duk_push_c_function(ctx, [] (duk_context* ctx) -> duk_ret_t { - StackAssert sa(ctx); - - duk_get_prop_string(ctx, 0, "\xff""\xff""timer-key"); - auto hash = duk_get_string(ctx, -1); - duk_pop(ctx); - duk_get_prop_string(ctx, 0, signature); - static_cast*>(duk_to_pointer(ctx, -1))->get()->stop(); - delete static_cast*>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_get_global_string(ctx, callback_table); - duk_del_prop_string(ctx, -1, hash); - duk_pop(ctx); - log::debug("plugin: timer destroyed"); - - return 0; - }, 1); - duk_set_finalizer(ctx, -2); - - // Save a callback function into the callback table. - duk_get_global_string(ctx, callback_table); - duk_dup(ctx, 2); - duk_put_prop_string(ctx, -2, hash.c_str()); - duk_pop(ctx); - - return 0; -} - -const duk_number_list_entry constants[] = { - { "Single", static_cast(timer::type::single) }, - { "Repeat", static_cast(timer::type::repeat) }, - { nullptr, 0 } -}; - -} // !namespace - -js_timer_module::js_timer_module() noexcept - : module("Irccd.timer") -{ -} - -void js_timer_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_c_function(plugin->context(), constructor, 3); - duk_put_number_list(plugin->context(), -1, constants); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, methods); - duk_put_prop_string(plugin->context(), -2, "prototype"); - duk_put_prop_string(plugin->context(), -2, "Timer"); - duk_pop(plugin->context()); - duk_push_object(plugin->context()); - duk_put_global_string(plugin->context(), callback_table); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_timer_module.hpp --- a/libirccd-js/irccd/js_timer_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_timer_module.hpp -- Irccd.Timer API - * - * 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_JS_TIMER_MODULE_HPP -#define IRCCD_JS_TIMER_MODULE_HPP - -/** - * \file js_timer_module - * \brief irccd.Timer JavaScript API. - */ - -#include "module.hpp" - -namespace irccd { - -/** - * \brief Irccd.Timer JavaScript API. - * \ingroup modules - */ -class js_timer_module : public module { -public: - /** - * Constructor. - */ - js_timer_module() noexcept; - - /** - * \copydoc module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -} // !irccd - -#endif // !IRCCD_MOD_TIMER_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_unicode_module.cpp --- a/libirccd-js/irccd/js_unicode_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* - * js_unicode_module.cpp -- Irccd.Unicode API - * - * 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 - -#include "duktape.hpp" -#include "js_unicode_module.hpp" -#include "unicode.hpp" - -namespace irccd { - -namespace { - -/* - * Function: Irccd.Unicode.isDigit(code) - * -------------------------------------------------------- - * - * Arguments: - * - code, the code point. - * Returns: - * True if the code is in the digit category. - */ -duk_ret_t is_digit(duk_context* ctx) -{ - duk_push_boolean(ctx, unicode::isdigit(duk_get_int(ctx, 0))); - - return 1; -} - -/* - * Function: Irccd.Unicode.isLetter(code) - * -------------------------------------------------------- - * - * Arguments: - * - code, the code point. - * Returns: - * True if the code is in the letter category. - */ -duk_ret_t is_letter(duk_context* ctx) -{ - duk_push_boolean(ctx, unicode::isalpha(duk_get_int(ctx, 0))); - - return 1; -} - -/* - * Function: Irccd.Unicode.isLower(code) - * -------------------------------------------------------- - * - * Arguments: - * - code, the code point. - * Returns: - * True if the code is lower case. - */ -duk_ret_t is_lower(duk_context* ctx) -{ - duk_push_boolean(ctx, unicode::islower(duk_get_int(ctx, 0))); - - return 1; -} - -/* - * Function: Irccd.Unicode.isSpace(code) - * -------------------------------------------------------- - * - * Arguments: - * - code, the code point. - * Returns: - * True if the code is in the space category. - */ -duk_ret_t is_space(duk_context* ctx) -{ - duk_push_boolean(ctx, unicode::isspace(duk_get_int(ctx, 0))); - - return 1; -} - -/* - * Function: Irccd.Unicode.isTitle(code) - * -------------------------------------------------------- - * - * Arguments: - * - code, the code point. - * Returns: - * True if the code is title case. - */ -duk_ret_t is_title(duk_context* ctx) -{ - duk_push_boolean(ctx, unicode::istitle(duk_get_int(ctx, 0))); - - return 1; -} - -/* - * Function: Irccd.Unicode.isUpper(code) - * -------------------------------------------------------- - * - * Arguments: - * - code, the code point. - * Returns: - * True if the code is upper case. - */ -duk_ret_t is_upper(duk_context* ctx) -{ - duk_push_boolean(ctx, unicode::isupper(duk_get_int(ctx, 0))); - - return 1; -} - -const duk_function_list_entry functions[] = { - { "isDigit", is_digit, 1 }, - { "isLetter", is_letter, 1 }, - { "isLower", is_lower, 1 }, - { "isSpace", is_space, 1 }, - { "isTitle", is_title, 1 }, - { "isUpper", is_upper, 1 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -js_unicode_module::js_unicode_module() noexcept - : module("Irccd.Unicode") -{ -} - -void js_unicode_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, functions); - duk_put_prop_string(plugin->context(), -2, "Unicode"); - duk_pop(plugin->context()); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_unicode_module.hpp --- a/libirccd-js/irccd/js_unicode_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_unicode_module.hpp -- Irccd.Unicode API - * - * 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_JS_UNICODE_MODULE_HPP -#define IRCCD_JS_UNICODE_MODULE_HPP - -/** - * \file js_unicode_module.hpp - * \brief irccd.Unicode JavaScript API. - */ - -#include "module.hpp" - -namespace irccd { - -/** - * \brief Irccd.Unicode JavaScript API. - * \ingroup modules - */ -class js_unicode_module : public module { -public: - /** - * Constructor. - */ - js_unicode_module() noexcept; - - /** - * \copydoc Module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -} // !irccd - -#endif // !IRCCD_JS_UNICODE_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_util_module.cpp --- a/libirccd-js/irccd/js_util_module.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,300 +0,0 @@ -/* - * js_util_module.cpp -- Irccd.Util API - * - * 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 - -#include - -#include - -#include "js_util_module.hpp" -#include "js_plugin.hpp" - -namespace irccd { - -namespace { - -/* - * Read parameters for irccd.Util.format function, the object is defined as - * following: - * - * { - * date: the date object - * flags: the flags (not implemented yet) - * field1: a field to substitute in #{} pattern - * field2: a field to substitute in #{} pattern - * fieldn: ... - * } - */ -string_util::subst get_subst(duk_context* ctx, int index) -{ - string_util::subst params; - - if (!duk_is_object(ctx, index)) - return params; - - dukx_enumerate(ctx, index, 0, true, [&] (auto) { - if (dukx_get_std_string(ctx, -2) == "date") - params.time = static_cast(duk_get_number(ctx, -1) / 1000); - else - params.keywords.insert({dukx_get_std_string(ctx, -2), dukx_get_std_string(ctx, -1)}); - }); - - return params; -} - -/* - * split (for Irccd.Util.cut) - * ------------------------------------------------------------------ - * - * Extract individual tokens in array or a whole string as a std:::vector. - */ -std::vector split(duk_context* ctx) -{ - duk_require_type_mask(ctx, 0, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_STRING); - - std::vector result; - std::string pattern = " \t\n"; - - if (duk_is_string(ctx, 0)) - 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 = string_util::split(duk_to_string(ctx, -1), pattern); - - result.insert(result.end(), tmp.begin(), tmp.end()); - duk_pop_2(ctx); - } - } - - return result; -} - -/* - * limit (for Irccd.Util.cut) - * ------------------------------------------------------------------ - * - * Get the maxl/maxc argument. - * - * The argument value is the default and also used as the result returned. - */ -int limit(duk_context* ctx, int index, const char* name, int value) -{ - if (duk_get_top(ctx) < index || !duk_is_number(ctx, index)) - 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); - - return value; -} - -/* - * lines (for Irccd.Util.cut) - * ------------------------------------------------------------------ - * - * Build a list of lines. - * - * Several cases possible: - * - * - s is the current line - * - abc is the token to add - * - * s = "" (new line) - * s -> "abc" - * - * s = "hello world" (enough room) - * s -> "hello world abc" - * - * s = "hello world" (not enough room: maxc is smaller) - * s+1 = "abc" - */ -std::vector lines(duk_context* ctx, const std::vector& tokens, int maxc) -{ - std::vector result{""}; - - for (const auto& s : tokens) { - if (s.length() > static_cast(maxc)) - duk_error(ctx, DUK_ERR_RANGE_ERROR, "word '%s' could not fit in maxc limit (%d)", s.c_str(), maxc); - - // Compute the length required (prepend a space if needed) - auto required = s.length() + (result.back().empty() ? 0 : 1); - - if (result.back().length() + required > static_cast(maxc)) - result.push_back(s); - else { - if (!result.back().empty()) - result.back() += ' '; - - result.back() += s; - } - } - - return result; -} - -/* - * Function: Irccd.Util.cut(data, maxc, maxl) - * -------------------------------------------------------- - * - * Cut a piece of data into several lines. - * - * The argument data is a string or a list of strings. In any case, all strings - * are first splitted by spaces and trimmed. This ensure that useless - * whitespaces are discarded. - * - * The argument maxc controls the maximum of characters allowed per line, it can - * be a positive integer. If undefined is given, a default of 72 is used. - * - * The argument maxl controls the maximum of lines allowed. It can be a positive - * integer or undefined for an infinite list. - * - * If maxl is used as a limit and the data can not fit within the bounds, - * undefined is returned. - * - * An empty list may be returned if empty strings were found. - * - * Arguments: - * - data, a string or an array of strings, - * - maxc, max number of colums (Optional, default: 72), - * - maxl, max number of lines (Optional, default: undefined). - * Returns: - * A list of strings ready to be sent or undefined if the data is too big. - * Throws: - * - RangeError if maxl or maxc are negative numbers, - * - RangeError if one word length was bigger than maxc, - * - TypeError if data is not a string or a list of strings. - */ -duk_ret_t cut(duk_context* ctx) -{ - auto list = lines(ctx, split(ctx), limit(ctx, 1, "maxc", 72)); - auto maxl = limit(ctx, 2, "maxl", INT_MAX); - - if (list.size() > static_cast(maxl)) - return 0; - - // Empty list but lines() returns at least one. - if (list.size() == 1 && list[0].empty()) { - duk_push_array(ctx); - return 1; - } - - dukx_push_array(ctx, list, dukx_push_std_string); - - return 1; -} - -/* - * Function: Irccd.Util.format(text, parameters) - * -------------------------------------------------------- - * - * Format a string with templates. - * - * Arguments: - * - input, the text to update, - * - params, the parameters. - * Returns: - * The converted text. - */ -duk_ret_t format(duk_context* ctx) -{ - try { - 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())); - } - - return 1; -} - -/* - * Function: Irccd.Util.splituser(ident) - * -------------------------------------------------------- - * - * Return the nickname part from a full username. - * - * Arguments: - * - ident, the full identity. - * Returns: - * The nickname. - */ -duk_ret_t splituser(duk_context* ctx) -{ - auto target = duk_require_string(ctx, 0); - char nick[32] = {0}; - - irc_target_get_nick(target, nick, sizeof (nick) -1); - duk_push_string(ctx, nick); - - return 1; -} - -/* - * Function: Irccd.Util.splithost(ident) - * -------------------------------------------------------- - * - * Return the hostname part from a full username. - * - * Arguments: - * - ident, the full identity. - * Returns: - * The hostname. - */ -duk_ret_t splithost(duk_context* ctx) -{ - auto target = duk_require_string(ctx, 0); - char host[32] = {0}; - - irc_target_get_host(target, host, sizeof (host) -1); - duk_push_string(ctx, host); - - return 1; -} - -const duk_function_list_entry functions[] = { - { "cut", cut, DUK_VARARGS }, - { "format", format, DUK_VARARGS }, - { "splituser", splituser, 1 }, - { "splithost", splithost, 1 }, - { nullptr, nullptr, 0 } -}; - -} // !namespace - -js_util_module::js_util_module() noexcept - : module("Irccd.Util") -{ -} - -void js_util_module::load(irccd&, std::shared_ptr plugin) -{ - StackAssert sa(plugin->context()); - - duk_get_global_string(plugin->context(), "Irccd"); - duk_push_object(plugin->context()); - duk_put_function_list(plugin->context(), -1, functions); - duk_put_prop_string(plugin->context(), -2, "Util"); - duk_pop(plugin->context()); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/js_util_module.hpp --- a/libirccd-js/irccd/js_util_module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * js_util_module.hpp -- Irccd.Util API - * - * 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_JS_UTIL_MODULE_HPP -#define IRCCD_JS_UTIL_MODULE_HPP - -/** - * \file js_util_module.hpp - * \brief irccd.Util JavaScript API. - */ - -#include "module.hpp" - -namespace irccd { - -/** - * \brief Irccd.Util JavaScript API. - * \ingroup modules - */ -class js_util_module : public module { -public: - /** - * Constructor. - */ - js_util_module() noexcept; - - /** - * \copydoc module::load - */ - void load(irccd& irccd, std::shared_ptr plugin) override; -}; - -} // !irccd - -#endif // !IRCCD_MOD_UTIL_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/module.hpp --- a/libirccd-js/irccd/module.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * module.hpp -- JavaScript API module - * - * 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_MODULE_HPP -#define IRCCD_MODULE_HPP - -/** - * \file module.hpp - * \brief Javascript API module. - */ - -/** - * \defgroup Javascript modules. - * \brief Modules for the JavaScript API. - */ - -#include -#include -#include - -#include "sysconfig.hpp" -#include "util.hpp" - -namespace irccd { - -class irccd; -class js_plugin; - -/** - * \brief JavaScript API module. - */ -class module { -private: - std::string name_; - -public: - /** - * Default constructor. - * - * \pre !name.empty() - */ - inline module(std::string name) noexcept - : name_(std::move(name)) - { - assert(!name_.empty()); - } - - /** - * Virtual destructor defaulted. - */ - virtual ~module() noexcept = default; - - /** - * Get the module name. - * - * \return the name - */ - inline const std::string& name() const noexcept - { - return name_; - } - - /** - * Load the module into the JavaScript plugin. - * - * \param irccd the irccd instance - * \param plugin the plugin - */ - virtual void load(irccd& irccd, std::shared_ptr plugin) - { - util::unused(irccd, plugin); - } -}; - -} // !irccd - -#endif // !IRCCD_MODULE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/timer.cpp --- a/libirccd-js/irccd/timer.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * timer.cpp -- threaded timers - * - * 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 -#include - -#include - -#include "timer.hpp" - -namespace irccd { - -void timer::run() -{ - while (state_ != state::stopped) { - std::unique_lock lock(mutex_); - - // Wait in case the timer is paused. - condition_.wait(lock, [&] () { - return state_ == state::running; - }); - - if (state_ != state::running) - continue; - - // Wait the timer delay or the interrupt. - condition_.wait_for(lock, std::chrono::milliseconds(delay_), [&] () { - return state_ != state::running; - }); - - if (state_ == state::running) { - // Signal process. - on_signal(); - - if (type_ == type::single) - state_ = state::stopped; - } - } - - on_end(); -} - -timer::timer(type type, unsigned delay) noexcept - : type_(type) - , delay_(delay) - , thread_(std::bind(&timer::run, this)) -{ -} - -timer::~timer() -{ - assert(state_ != state::running); - - try { - { - std::lock_guard lk(mutex_); - - state_ = state::stopped; - condition_.notify_one(); - } - - thread_.join(); - } catch (...) { - } -} - -void timer::start() -{ - assert(state_ != state::running); - - { - std::lock_guard lk(mutex_); - state_ = state::running; - } - - condition_.notify_one(); -} - -void timer::stop() -{ - { - std::lock_guard lk(mutex_); - state_ = state::paused; - } - - condition_.notify_one(); -} - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/timer.hpp --- a/libirccd-js/irccd/timer.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * timer.hpp -- threaded timers - * - * 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_TIMER_HPP -#define IRCCD_TIMER_HPP - -/** - * \file timer.hpp - * \brief Provides interval based timers for JavaScript - */ - -#include -#include -#include -#include -#include - -#include "signals.hpp" -#include "sysconfig.hpp" - -namespace irccd { - -/** - * \brief Timer class - * - * A timer is a thread object that emits a signal periodically or just one time. It is perfectly pausable and resumable - * to reuse the same object. - * - * The delay is configured in milliseconds and the user has choice to use any - * delay needed. - * - * We use a condition variable to wait for the specified delay unless the timer - * must be stopped. - */ -class timer { -public: - /** - * \brief Type of timer - */ - enum class type { - single, //!< The timer ends after execution - repeat //!< The timer loops - }; - - /** - * Signal: onSignal - * ---------------------------------------------------------- - * - * Called when the timeout expires. - */ - Signal<> on_signal; - - /** - * Signal: onEnd - * ---------------------------------------------------------- - * - * Called when the timeout ends. - */ - Signal<> on_end; - -private: - enum class state { - paused, - running, - stopped - }; - - type type_; - unsigned delay_; - - // Thread management. - std::atomic state_{state::paused}; - std::mutex mutex_; - std::condition_variable condition_; - std::thread thread_; - - void run(); - -public: - /** - * Timer constructor. - * - * The timer is not started, use start(). - * - * \param type the timer type - * \param delay the delay in milliseconds - * \post isRunning() returns false - */ - timer(type type, unsigned delay) noexcept; - - /** - * Destructor, closes the thread. - * - * \pre stop() must have been called. - */ - virtual ~timer(); - - /** - * Start the thread. - * - * \pre isRunning() must return false - * \pre onSignal() must have been called - * \pre onEnd() must have been called - * \note Thread-safe - */ - void start(); - - /** - * Stop the timer, may be used by the user to stop it. - * - * \note Thread-safe - */ - void stop(); - - /** - * Get the type of timer. - * - * \return the type. - */ - inline type get_type() const noexcept - { - return type_; - } - - /** - * Tells if the timer has still a running thread. - * - * \return true if still alive - * \note Thread-safe - */ - inline bool is_running() const noexcept - { - return state_ == state::running; - } -}; - -} // !irccd - -#endif // !IRCCD_TIMER_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/unicode.cpp --- a/libirccd-js/irccd/unicode.cpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4796 +0,0 @@ -/* - * unicode.cpp -- UTF-8 to UTF-32 conversions and various operations - * - * 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 "unicode.hpp" - -/* - * The following code has been generated from Go mkrunetype adapted to our - * needs. - */ - -namespace irccd { - -namespace unicode { - -#define nelem(x) (sizeof (x) / sizeof ((x)[0])) - -namespace { - -const char32_t *rbsearch(char32_t c, const char32_t *t, int n, int ne) noexcept -{ - const char32_t *p; - int m; - - while (n > 1) { - m = n >> 1; - p = t + m * ne; - - if (c >= p[0]) { - t = p; - n = n - m; - } else - n = m; - } - - if (n && c >= t[0]) - return t; - - return nullptr; -} - -} // !namespace - -namespace { - -const char32_t isspacer[] = { - 0x0009, 0x000d, - 0x0020, 0x0020, - 0x0085, 0x0085, - 0x00a0, 0x00a0, - 0x1680, 0x1680, - 0x2000, 0x200a, - 0x2028, 0x2029, - 0x202f, 0x202f, - 0x205f, 0x205f, - 0x3000, 0x3000, - 0xfeff, 0xfeff, -}; - -} // !namespace - -bool isspace(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, isspacer, nelem (isspacer)/2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - return false; -} - -namespace { - -const char32_t isdigitr[] = { - 0x0030, 0x0039, - 0x0660, 0x0669, - 0x06f0, 0x06f9, - 0x07c0, 0x07c9, - 0x0966, 0x096f, - 0x09e6, 0x09ef, - 0x0a66, 0x0a6f, - 0x0ae6, 0x0aef, - 0x0b66, 0x0b6f, - 0x0be6, 0x0bef, - 0x0c66, 0x0c6f, - 0x0ce6, 0x0cef, - 0x0d66, 0x0d6f, - 0x0de6, 0x0def, - 0x0e50, 0x0e59, - 0x0ed0, 0x0ed9, - 0x0f20, 0x0f29, - 0x1040, 0x1049, - 0x1090, 0x1099, - 0x17e0, 0x17e9, - 0x1810, 0x1819, - 0x1946, 0x194f, - 0x19d0, 0x19d9, - 0x1a80, 0x1a89, - 0x1a90, 0x1a99, - 0x1b50, 0x1b59, - 0x1bb0, 0x1bb9, - 0x1c40, 0x1c49, - 0x1c50, 0x1c59, - 0xa620, 0xa629, - 0xa8d0, 0xa8d9, - 0xa900, 0xa909, - 0xa9d0, 0xa9d9, - 0xa9f0, 0xa9f9, - 0xaa50, 0xaa59, - 0xabf0, 0xabf9, - 0xff10, 0xff19, - 0x104a0, 0x104a9, - 0x11066, 0x1106f, - 0x110f0, 0x110f9, - 0x11136, 0x1113f, - 0x111d0, 0x111d9, - 0x112f0, 0x112f9, - 0x114d0, 0x114d9, - 0x11650, 0x11659, - 0x116c0, 0x116c9, - 0x118e0, 0x118e9, - 0x16a60, 0x16a69, - 0x16b50, 0x16b59, - 0x1d7ce, 0x1d7ff, -}; - -} // !namespace - -bool isdigit(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, isdigitr, nelem (isdigitr)/2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - return false; -} - -namespace { - -const char32_t isalphar[] = { - 0x0041, 0x005a, - 0x0061, 0x007a, - 0x00c0, 0x00d6, - 0x00d8, 0x00f6, - 0x00f8, 0x02c1, - 0x02c6, 0x02d1, - 0x02e0, 0x02e4, - 0x0370, 0x0374, - 0x0376, 0x0377, - 0x037a, 0x037d, - 0x0388, 0x038a, - 0x038e, 0x03a1, - 0x03a3, 0x03f5, - 0x03f7, 0x0481, - 0x048a, 0x052f, - 0x0531, 0x0556, - 0x0561, 0x0587, - 0x05d0, 0x05ea, - 0x05f0, 0x05f2, - 0x0620, 0x064a, - 0x066e, 0x066f, - 0x0671, 0x06d3, - 0x06e5, 0x06e6, - 0x06ee, 0x06ef, - 0x06fa, 0x06fc, - 0x0712, 0x072f, - 0x074d, 0x07a5, - 0x07ca, 0x07ea, - 0x07f4, 0x07f5, - 0x0800, 0x0815, - 0x0840, 0x0858, - 0x08a0, 0x08b2, - 0x0904, 0x0939, - 0x0958, 0x0961, - 0x0971, 0x0980, - 0x0985, 0x098c, - 0x098f, 0x0990, - 0x0993, 0x09a8, - 0x09aa, 0x09b0, - 0x09b6, 0x09b9, - 0x09dc, 0x09dd, - 0x09df, 0x09e1, - 0x09f0, 0x09f1, - 0x0a05, 0x0a0a, - 0x0a0f, 0x0a10, - 0x0a13, 0x0a28, - 0x0a2a, 0x0a30, - 0x0a32, 0x0a33, - 0x0a35, 0x0a36, - 0x0a38, 0x0a39, - 0x0a59, 0x0a5c, - 0x0a72, 0x0a74, - 0x0a85, 0x0a8d, - 0x0a8f, 0x0a91, - 0x0a93, 0x0aa8, - 0x0aaa, 0x0ab0, - 0x0ab2, 0x0ab3, - 0x0ab5, 0x0ab9, - 0x0ae0, 0x0ae1, - 0x0b05, 0x0b0c, - 0x0b0f, 0x0b10, - 0x0b13, 0x0b28, - 0x0b2a, 0x0b30, - 0x0b32, 0x0b33, - 0x0b35, 0x0b39, - 0x0b5c, 0x0b5d, - 0x0b5f, 0x0b61, - 0x0b85, 0x0b8a, - 0x0b8e, 0x0b90, - 0x0b92, 0x0b95, - 0x0b99, 0x0b9a, - 0x0b9e, 0x0b9f, - 0x0ba3, 0x0ba4, - 0x0ba8, 0x0baa, - 0x0bae, 0x0bb9, - 0x0c05, 0x0c0c, - 0x0c0e, 0x0c10, - 0x0c12, 0x0c28, - 0x0c2a, 0x0c39, - 0x0c58, 0x0c59, - 0x0c60, 0x0c61, - 0x0c85, 0x0c8c, - 0x0c8e, 0x0c90, - 0x0c92, 0x0ca8, - 0x0caa, 0x0cb3, - 0x0cb5, 0x0cb9, - 0x0ce0, 0x0ce1, - 0x0cf1, 0x0cf2, - 0x0d05, 0x0d0c, - 0x0d0e, 0x0d10, - 0x0d12, 0x0d3a, - 0x0d60, 0x0d61, - 0x0d7a, 0x0d7f, - 0x0d85, 0x0d96, - 0x0d9a, 0x0db1, - 0x0db3, 0x0dbb, - 0x0dc0, 0x0dc6, - 0x0e01, 0x0e30, - 0x0e32, 0x0e33, - 0x0e40, 0x0e46, - 0x0e81, 0x0e82, - 0x0e87, 0x0e88, - 0x0e94, 0x0e97, - 0x0e99, 0x0e9f, - 0x0ea1, 0x0ea3, - 0x0eaa, 0x0eab, - 0x0ead, 0x0eb0, - 0x0eb2, 0x0eb3, - 0x0ec0, 0x0ec4, - 0x0edc, 0x0edf, - 0x0f40, 0x0f47, - 0x0f49, 0x0f6c, - 0x0f88, 0x0f8c, - 0x1000, 0x102a, - 0x1050, 0x1055, - 0x105a, 0x105d, - 0x1065, 0x1066, - 0x106e, 0x1070, - 0x1075, 0x1081, - 0x10a0, 0x10c5, - 0x10d0, 0x10fa, - 0x10fc, 0x1248, - 0x124a, 0x124d, - 0x1250, 0x1256, - 0x125a, 0x125d, - 0x1260, 0x1288, - 0x128a, 0x128d, - 0x1290, 0x12b0, - 0x12b2, 0x12b5, - 0x12b8, 0x12be, - 0x12c2, 0x12c5, - 0x12c8, 0x12d6, - 0x12d8, 0x1310, - 0x1312, 0x1315, - 0x1318, 0x135a, - 0x1380, 0x138f, - 0x13a0, 0x13f4, - 0x1401, 0x166c, - 0x166f, 0x167f, - 0x1681, 0x169a, - 0x16a0, 0x16ea, - 0x16f1, 0x16f8, - 0x1700, 0x170c, - 0x170e, 0x1711, - 0x1720, 0x1731, - 0x1740, 0x1751, - 0x1760, 0x176c, - 0x176e, 0x1770, - 0x1780, 0x17b3, - 0x1820, 0x1877, - 0x1880, 0x18a8, - 0x18b0, 0x18f5, - 0x1900, 0x191e, - 0x1950, 0x196d, - 0x1970, 0x1974, - 0x1980, 0x19ab, - 0x19c1, 0x19c7, - 0x1a00, 0x1a16, - 0x1a20, 0x1a54, - 0x1b05, 0x1b33, - 0x1b45, 0x1b4b, - 0x1b83, 0x1ba0, - 0x1bae, 0x1baf, - 0x1bba, 0x1be5, - 0x1c00, 0x1c23, - 0x1c4d, 0x1c4f, - 0x1c5a, 0x1c7d, - 0x1ce9, 0x1cec, - 0x1cee, 0x1cf1, - 0x1cf5, 0x1cf6, - 0x1d00, 0x1dbf, - 0x1e00, 0x1f15, - 0x1f18, 0x1f1d, - 0x1f20, 0x1f45, - 0x1f48, 0x1f4d, - 0x1f50, 0x1f57, - 0x1f5f, 0x1f7d, - 0x1f80, 0x1fb4, - 0x1fb6, 0x1fbc, - 0x1fc2, 0x1fc4, - 0x1fc6, 0x1fcc, - 0x1fd0, 0x1fd3, - 0x1fd6, 0x1fdb, - 0x1fe0, 0x1fec, - 0x1ff2, 0x1ff4, - 0x1ff6, 0x1ffc, - 0x2090, 0x209c, - 0x210a, 0x2113, - 0x2119, 0x211d, - 0x212a, 0x212d, - 0x212f, 0x2139, - 0x213c, 0x213f, - 0x2145, 0x2149, - 0x2183, 0x2184, - 0x2c00, 0x2c2e, - 0x2c30, 0x2c5e, - 0x2c60, 0x2ce4, - 0x2ceb, 0x2cee, - 0x2cf2, 0x2cf3, - 0x2d00, 0x2d25, - 0x2d30, 0x2d67, - 0x2d80, 0x2d96, - 0x2da0, 0x2da6, - 0x2da8, 0x2dae, - 0x2db0, 0x2db6, - 0x2db8, 0x2dbe, - 0x2dc0, 0x2dc6, - 0x2dc8, 0x2dce, - 0x2dd0, 0x2dd6, - 0x2dd8, 0x2dde, - 0x3005, 0x3006, - 0x3031, 0x3035, - 0x303b, 0x303c, - 0x3041, 0x3096, - 0x309d, 0x309f, - 0x30a1, 0x30fa, - 0x30fc, 0x30ff, - 0x3105, 0x312d, - 0x3131, 0x318e, - 0x31a0, 0x31ba, - 0x31f0, 0x31ff, - 0x3400, 0x4db5, - 0x4e00, 0x9fcc, - 0xa000, 0xa48c, - 0xa4d0, 0xa4fd, - 0xa500, 0xa60c, - 0xa610, 0xa61f, - 0xa62a, 0xa62b, - 0xa640, 0xa66e, - 0xa67f, 0xa69d, - 0xa6a0, 0xa6e5, - 0xa717, 0xa71f, - 0xa722, 0xa788, - 0xa78b, 0xa78e, - 0xa790, 0xa7ad, - 0xa7b0, 0xa7b1, - 0xa7f7, 0xa801, - 0xa803, 0xa805, - 0xa807, 0xa80a, - 0xa80c, 0xa822, - 0xa840, 0xa873, - 0xa882, 0xa8b3, - 0xa8f2, 0xa8f7, - 0xa90a, 0xa925, - 0xa930, 0xa946, - 0xa960, 0xa97c, - 0xa984, 0xa9b2, - 0xa9e0, 0xa9e4, - 0xa9e6, 0xa9ef, - 0xa9fa, 0xa9fe, - 0xaa00, 0xaa28, - 0xaa40, 0xaa42, - 0xaa44, 0xaa4b, - 0xaa60, 0xaa76, - 0xaa7e, 0xaaaf, - 0xaab5, 0xaab6, - 0xaab9, 0xaabd, - 0xaadb, 0xaadd, - 0xaae0, 0xaaea, - 0xaaf2, 0xaaf4, - 0xab01, 0xab06, - 0xab09, 0xab0e, - 0xab11, 0xab16, - 0xab20, 0xab26, - 0xab28, 0xab2e, - 0xab30, 0xab5a, - 0xab5c, 0xab5f, - 0xab64, 0xab65, - 0xabc0, 0xabe2, - 0xac00, 0xd7a3, - 0xd7b0, 0xd7c6, - 0xd7cb, 0xd7fb, - 0xf900, 0xfa6d, - 0xfa70, 0xfad9, - 0xfb00, 0xfb06, - 0xfb13, 0xfb17, - 0xfb1f, 0xfb28, - 0xfb2a, 0xfb36, - 0xfb38, 0xfb3c, - 0xfb40, 0xfb41, - 0xfb43, 0xfb44, - 0xfb46, 0xfbb1, - 0xfbd3, 0xfd3d, - 0xfd50, 0xfd8f, - 0xfd92, 0xfdc7, - 0xfdf0, 0xfdfb, - 0xfe70, 0xfe74, - 0xfe76, 0xfefc, - 0xff21, 0xff3a, - 0xff41, 0xff5a, - 0xff66, 0xffbe, - 0xffc2, 0xffc7, - 0xffca, 0xffcf, - 0xffd2, 0xffd7, - 0xffda, 0xffdc, - 0x10000, 0x1000b, - 0x1000d, 0x10026, - 0x10028, 0x1003a, - 0x1003c, 0x1003d, - 0x1003f, 0x1004d, - 0x10050, 0x1005d, - 0x10080, 0x100fa, - 0x10280, 0x1029c, - 0x102a0, 0x102d0, - 0x10300, 0x1031f, - 0x10330, 0x10340, - 0x10342, 0x10349, - 0x10350, 0x10375, - 0x10380, 0x1039d, - 0x103a0, 0x103c3, - 0x103c8, 0x103cf, - 0x10400, 0x1049d, - 0x10500, 0x10527, - 0x10530, 0x10563, - 0x10600, 0x10736, - 0x10740, 0x10755, - 0x10760, 0x10767, - 0x10800, 0x10805, - 0x1080a, 0x10835, - 0x10837, 0x10838, - 0x1083f, 0x10855, - 0x10860, 0x10876, - 0x10880, 0x1089e, - 0x10900, 0x10915, - 0x10920, 0x10939, - 0x10980, 0x109b7, - 0x109be, 0x109bf, - 0x10a10, 0x10a13, - 0x10a15, 0x10a17, - 0x10a19, 0x10a33, - 0x10a60, 0x10a7c, - 0x10a80, 0x10a9c, - 0x10ac0, 0x10ac7, - 0x10ac9, 0x10ae4, - 0x10b00, 0x10b35, - 0x10b40, 0x10b55, - 0x10b60, 0x10b72, - 0x10b80, 0x10b91, - 0x10c00, 0x10c48, - 0x11003, 0x11037, - 0x11083, 0x110af, - 0x110d0, 0x110e8, - 0x11103, 0x11126, - 0x11150, 0x11172, - 0x11183, 0x111b2, - 0x111c1, 0x111c4, - 0x11200, 0x11211, - 0x11213, 0x1122b, - 0x112b0, 0x112de, - 0x11305, 0x1130c, - 0x1130f, 0x11310, - 0x11313, 0x11328, - 0x1132a, 0x11330, - 0x11332, 0x11333, - 0x11335, 0x11339, - 0x1135d, 0x11361, - 0x11480, 0x114af, - 0x114c4, 0x114c5, - 0x11580, 0x115ae, - 0x11600, 0x1162f, - 0x11680, 0x116aa, - 0x118a0, 0x118df, - 0x11ac0, 0x11af8, - 0x12000, 0x12398, - 0x13000, 0x1342e, - 0x16800, 0x16a38, - 0x16a40, 0x16a5e, - 0x16ad0, 0x16aed, - 0x16b00, 0x16b2f, - 0x16b40, 0x16b43, - 0x16b63, 0x16b77, - 0x16b7d, 0x16b8f, - 0x16f00, 0x16f44, - 0x16f93, 0x16f9f, - 0x1b000, 0x1b001, - 0x1bc00, 0x1bc6a, - 0x1bc70, 0x1bc7c, - 0x1bc80, 0x1bc88, - 0x1bc90, 0x1bc99, - 0x1d400, 0x1d454, - 0x1d456, 0x1d49c, - 0x1d49e, 0x1d49f, - 0x1d4a5, 0x1d4a6, - 0x1d4a9, 0x1d4ac, - 0x1d4ae, 0x1d4b9, - 0x1d4bd, 0x1d4c3, - 0x1d4c5, 0x1d505, - 0x1d507, 0x1d50a, - 0x1d50d, 0x1d514, - 0x1d516, 0x1d51c, - 0x1d51e, 0x1d539, - 0x1d53b, 0x1d53e, - 0x1d540, 0x1d544, - 0x1d54a, 0x1d550, - 0x1d552, 0x1d6a5, - 0x1d6a8, 0x1d6c0, - 0x1d6c2, 0x1d6da, - 0x1d6dc, 0x1d6fa, - 0x1d6fc, 0x1d714, - 0x1d716, 0x1d734, - 0x1d736, 0x1d74e, - 0x1d750, 0x1d76e, - 0x1d770, 0x1d788, - 0x1d78a, 0x1d7a8, - 0x1d7aa, 0x1d7c2, - 0x1d7c4, 0x1d7cb, - 0x1e800, 0x1e8c4, - 0x1ee00, 0x1ee03, - 0x1ee05, 0x1ee1f, - 0x1ee21, 0x1ee22, - 0x1ee29, 0x1ee32, - 0x1ee34, 0x1ee37, - 0x1ee4d, 0x1ee4f, - 0x1ee51, 0x1ee52, - 0x1ee61, 0x1ee62, - 0x1ee67, 0x1ee6a, - 0x1ee6c, 0x1ee72, - 0x1ee74, 0x1ee77, - 0x1ee79, 0x1ee7c, - 0x1ee80, 0x1ee89, - 0x1ee8b, 0x1ee9b, - 0x1eea1, 0x1eea3, - 0x1eea5, 0x1eea9, - 0x1eeab, 0x1eebb, - 0x20000, 0x2a6d6, - 0x2a700, 0x2b734, - 0x2b740, 0x2b81d, - 0x2f800, 0x2fa1d, -}; - -} // !namespace - -namespace { - -const char32_t isalphas[] = { - 0x00aa, - 0x00b5, - 0x00ba, - 0x02ec, - 0x02ee, - 0x037f, - 0x0386, - 0x038c, - 0x0559, - 0x06d5, - 0x06ff, - 0x0710, - 0x07b1, - 0x07fa, - 0x081a, - 0x0824, - 0x0828, - 0x093d, - 0x0950, - 0x09b2, - 0x09bd, - 0x09ce, - 0x0a5e, - 0x0abd, - 0x0ad0, - 0x0b3d, - 0x0b71, - 0x0b83, - 0x0b9c, - 0x0bd0, - 0x0c3d, - 0x0cbd, - 0x0cde, - 0x0d3d, - 0x0d4e, - 0x0dbd, - 0x0e84, - 0x0e8a, - 0x0e8d, - 0x0ea5, - 0x0ea7, - 0x0ebd, - 0x0ec6, - 0x0f00, - 0x103f, - 0x1061, - 0x108e, - 0x10c7, - 0x10cd, - 0x1258, - 0x12c0, - 0x17d7, - 0x17dc, - 0x18aa, - 0x1aa7, - 0x1f59, - 0x1f5b, - 0x1f5d, - 0x1fbe, - 0x2071, - 0x207f, - 0x2102, - 0x2107, - 0x2115, - 0x2124, - 0x2126, - 0x2128, - 0x214e, - 0x2d27, - 0x2d2d, - 0x2d6f, - 0x2e2f, - 0xa8fb, - 0xa9cf, - 0xaa7a, - 0xaab1, - 0xaac0, - 0xaac2, - 0xfb1d, - 0xfb3e, - 0x10808, - 0x1083c, - 0x10a00, - 0x11176, - 0x111da, - 0x1133d, - 0x114c7, - 0x11644, - 0x118ff, - 0x16f50, - 0x1d4a2, - 0x1d4bb, - 0x1d546, - 0x1ee24, - 0x1ee27, - 0x1ee39, - 0x1ee3b, - 0x1ee42, - 0x1ee47, - 0x1ee49, - 0x1ee4b, - 0x1ee54, - 0x1ee57, - 0x1ee59, - 0x1ee5b, - 0x1ee5d, - 0x1ee5f, - 0x1ee64, - 0x1ee7e, -}; - -} // !namespace - -bool isalpha(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, isalphar, nelem (isalphar)/2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, isalphas, nelem (isalphas), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t isupperr[] = { - 0x0041, 0x005a, - 0x00c0, 0x00d6, - 0x00d8, 0x00de, - 0x0178, 0x0179, - 0x0181, 0x0182, - 0x0186, 0x0187, - 0x0189, 0x018b, - 0x018e, 0x0191, - 0x0193, 0x0194, - 0x0196, 0x0198, - 0x019c, 0x019d, - 0x019f, 0x01a0, - 0x01a6, 0x01a7, - 0x01ae, 0x01af, - 0x01b1, 0x01b3, - 0x01b7, 0x01b8, - 0x01f6, 0x01f8, - 0x023a, 0x023b, - 0x023d, 0x023e, - 0x0243, 0x0246, - 0x0388, 0x038a, - 0x038e, 0x038f, - 0x0391, 0x03a1, - 0x03a3, 0x03ab, - 0x03d2, 0x03d4, - 0x03f9, 0x03fa, - 0x03fd, 0x042f, - 0x04c0, 0x04c1, - 0x0531, 0x0556, - 0x10a0, 0x10c5, - 0x1f08, 0x1f0f, - 0x1f18, 0x1f1d, - 0x1f28, 0x1f2f, - 0x1f38, 0x1f3f, - 0x1f48, 0x1f4d, - 0x1f68, 0x1f6f, - 0x1f88, 0x1f8f, - 0x1f98, 0x1f9f, - 0x1fa8, 0x1faf, - 0x1fb8, 0x1fbc, - 0x1fc8, 0x1fcc, - 0x1fd8, 0x1fdb, - 0x1fe8, 0x1fec, - 0x1ff8, 0x1ffc, - 0x210b, 0x210d, - 0x2110, 0x2112, - 0x2119, 0x211d, - 0x212a, 0x212d, - 0x2130, 0x2133, - 0x213e, 0x213f, - 0x2160, 0x216f, - 0x24b6, 0x24cf, - 0x2c00, 0x2c2e, - 0x2c62, 0x2c64, - 0x2c6d, 0x2c70, - 0x2c7e, 0x2c80, - 0xa77d, 0xa77e, - 0xa7aa, 0xa7ad, - 0xa7b0, 0xa7b1, - 0xff21, 0xff3a, - 0x10400, 0x10427, - 0x118a0, 0x118bf, - 0x1d400, 0x1d419, - 0x1d434, 0x1d44d, - 0x1d468, 0x1d481, - 0x1d49e, 0x1d49f, - 0x1d4a5, 0x1d4a6, - 0x1d4a9, 0x1d4ac, - 0x1d4ae, 0x1d4b5, - 0x1d4d0, 0x1d4e9, - 0x1d504, 0x1d505, - 0x1d507, 0x1d50a, - 0x1d50d, 0x1d514, - 0x1d516, 0x1d51c, - 0x1d538, 0x1d539, - 0x1d53b, 0x1d53e, - 0x1d540, 0x1d544, - 0x1d54a, 0x1d550, - 0x1d56c, 0x1d585, - 0x1d5a0, 0x1d5b9, - 0x1d5d4, 0x1d5ed, - 0x1d608, 0x1d621, - 0x1d63c, 0x1d655, - 0x1d670, 0x1d689, - 0x1d6a8, 0x1d6c0, - 0x1d6e2, 0x1d6fa, - 0x1d71c, 0x1d734, - 0x1d756, 0x1d76e, - 0x1d790, 0x1d7a8, -}; - -} // !namespace - -namespace { - -const char32_t isuppers[] = { - 0x0100, - 0x0102, - 0x0104, - 0x0106, - 0x0108, - 0x010a, - 0x010c, - 0x010e, - 0x0110, - 0x0112, - 0x0114, - 0x0116, - 0x0118, - 0x011a, - 0x011c, - 0x011e, - 0x0120, - 0x0122, - 0x0124, - 0x0126, - 0x0128, - 0x012a, - 0x012c, - 0x012e, - 0x0130, - 0x0132, - 0x0134, - 0x0136, - 0x0139, - 0x013b, - 0x013d, - 0x013f, - 0x0141, - 0x0143, - 0x0145, - 0x0147, - 0x014a, - 0x014c, - 0x014e, - 0x0150, - 0x0152, - 0x0154, - 0x0156, - 0x0158, - 0x015a, - 0x015c, - 0x015e, - 0x0160, - 0x0162, - 0x0164, - 0x0166, - 0x0168, - 0x016a, - 0x016c, - 0x016e, - 0x0170, - 0x0172, - 0x0174, - 0x0176, - 0x017b, - 0x017d, - 0x0184, - 0x01a2, - 0x01a4, - 0x01a9, - 0x01ac, - 0x01b5, - 0x01bc, - 0x01c4, - 0x01c7, - 0x01ca, - 0x01cd, - 0x01cf, - 0x01d1, - 0x01d3, - 0x01d5, - 0x01d7, - 0x01d9, - 0x01db, - 0x01de, - 0x01e0, - 0x01e2, - 0x01e4, - 0x01e6, - 0x01e8, - 0x01ea, - 0x01ec, - 0x01ee, - 0x01f1, - 0x01f4, - 0x01fa, - 0x01fc, - 0x01fe, - 0x0200, - 0x0202, - 0x0204, - 0x0206, - 0x0208, - 0x020a, - 0x020c, - 0x020e, - 0x0210, - 0x0212, - 0x0214, - 0x0216, - 0x0218, - 0x021a, - 0x021c, - 0x021e, - 0x0220, - 0x0222, - 0x0224, - 0x0226, - 0x0228, - 0x022a, - 0x022c, - 0x022e, - 0x0230, - 0x0232, - 0x0241, - 0x0248, - 0x024a, - 0x024c, - 0x024e, - 0x0370, - 0x0372, - 0x0376, - 0x037f, - 0x0386, - 0x038c, - 0x03cf, - 0x03d8, - 0x03da, - 0x03dc, - 0x03de, - 0x03e0, - 0x03e2, - 0x03e4, - 0x03e6, - 0x03e8, - 0x03ea, - 0x03ec, - 0x03ee, - 0x03f4, - 0x03f7, - 0x0460, - 0x0462, - 0x0464, - 0x0466, - 0x0468, - 0x046a, - 0x046c, - 0x046e, - 0x0470, - 0x0472, - 0x0474, - 0x0476, - 0x0478, - 0x047a, - 0x047c, - 0x047e, - 0x0480, - 0x048a, - 0x048c, - 0x048e, - 0x0490, - 0x0492, - 0x0494, - 0x0496, - 0x0498, - 0x049a, - 0x049c, - 0x049e, - 0x04a0, - 0x04a2, - 0x04a4, - 0x04a6, - 0x04a8, - 0x04aa, - 0x04ac, - 0x04ae, - 0x04b0, - 0x04b2, - 0x04b4, - 0x04b6, - 0x04b8, - 0x04ba, - 0x04bc, - 0x04be, - 0x04c3, - 0x04c5, - 0x04c7, - 0x04c9, - 0x04cb, - 0x04cd, - 0x04d0, - 0x04d2, - 0x04d4, - 0x04d6, - 0x04d8, - 0x04da, - 0x04dc, - 0x04de, - 0x04e0, - 0x04e2, - 0x04e4, - 0x04e6, - 0x04e8, - 0x04ea, - 0x04ec, - 0x04ee, - 0x04f0, - 0x04f2, - 0x04f4, - 0x04f6, - 0x04f8, - 0x04fa, - 0x04fc, - 0x04fe, - 0x0500, - 0x0502, - 0x0504, - 0x0506, - 0x0508, - 0x050a, - 0x050c, - 0x050e, - 0x0510, - 0x0512, - 0x0514, - 0x0516, - 0x0518, - 0x051a, - 0x051c, - 0x051e, - 0x0520, - 0x0522, - 0x0524, - 0x0526, - 0x0528, - 0x052a, - 0x052c, - 0x052e, - 0x10c7, - 0x10cd, - 0x1e00, - 0x1e02, - 0x1e04, - 0x1e06, - 0x1e08, - 0x1e0a, - 0x1e0c, - 0x1e0e, - 0x1e10, - 0x1e12, - 0x1e14, - 0x1e16, - 0x1e18, - 0x1e1a, - 0x1e1c, - 0x1e1e, - 0x1e20, - 0x1e22, - 0x1e24, - 0x1e26, - 0x1e28, - 0x1e2a, - 0x1e2c, - 0x1e2e, - 0x1e30, - 0x1e32, - 0x1e34, - 0x1e36, - 0x1e38, - 0x1e3a, - 0x1e3c, - 0x1e3e, - 0x1e40, - 0x1e42, - 0x1e44, - 0x1e46, - 0x1e48, - 0x1e4a, - 0x1e4c, - 0x1e4e, - 0x1e50, - 0x1e52, - 0x1e54, - 0x1e56, - 0x1e58, - 0x1e5a, - 0x1e5c, - 0x1e5e, - 0x1e60, - 0x1e62, - 0x1e64, - 0x1e66, - 0x1e68, - 0x1e6a, - 0x1e6c, - 0x1e6e, - 0x1e70, - 0x1e72, - 0x1e74, - 0x1e76, - 0x1e78, - 0x1e7a, - 0x1e7c, - 0x1e7e, - 0x1e80, - 0x1e82, - 0x1e84, - 0x1e86, - 0x1e88, - 0x1e8a, - 0x1e8c, - 0x1e8e, - 0x1e90, - 0x1e92, - 0x1e94, - 0x1e9e, - 0x1ea0, - 0x1ea2, - 0x1ea4, - 0x1ea6, - 0x1ea8, - 0x1eaa, - 0x1eac, - 0x1eae, - 0x1eb0, - 0x1eb2, - 0x1eb4, - 0x1eb6, - 0x1eb8, - 0x1eba, - 0x1ebc, - 0x1ebe, - 0x1ec0, - 0x1ec2, - 0x1ec4, - 0x1ec6, - 0x1ec8, - 0x1eca, - 0x1ecc, - 0x1ece, - 0x1ed0, - 0x1ed2, - 0x1ed4, - 0x1ed6, - 0x1ed8, - 0x1eda, - 0x1edc, - 0x1ede, - 0x1ee0, - 0x1ee2, - 0x1ee4, - 0x1ee6, - 0x1ee8, - 0x1eea, - 0x1eec, - 0x1eee, - 0x1ef0, - 0x1ef2, - 0x1ef4, - 0x1ef6, - 0x1ef8, - 0x1efa, - 0x1efc, - 0x1efe, - 0x1f59, - 0x1f5b, - 0x1f5d, - 0x1f5f, - 0x2102, - 0x2107, - 0x2115, - 0x2124, - 0x2126, - 0x2128, - 0x2145, - 0x2183, - 0x2c60, - 0x2c67, - 0x2c69, - 0x2c6b, - 0x2c72, - 0x2c75, - 0x2c82, - 0x2c84, - 0x2c86, - 0x2c88, - 0x2c8a, - 0x2c8c, - 0x2c8e, - 0x2c90, - 0x2c92, - 0x2c94, - 0x2c96, - 0x2c98, - 0x2c9a, - 0x2c9c, - 0x2c9e, - 0x2ca0, - 0x2ca2, - 0x2ca4, - 0x2ca6, - 0x2ca8, - 0x2caa, - 0x2cac, - 0x2cae, - 0x2cb0, - 0x2cb2, - 0x2cb4, - 0x2cb6, - 0x2cb8, - 0x2cba, - 0x2cbc, - 0x2cbe, - 0x2cc0, - 0x2cc2, - 0x2cc4, - 0x2cc6, - 0x2cc8, - 0x2cca, - 0x2ccc, - 0x2cce, - 0x2cd0, - 0x2cd2, - 0x2cd4, - 0x2cd6, - 0x2cd8, - 0x2cda, - 0x2cdc, - 0x2cde, - 0x2ce0, - 0x2ce2, - 0x2ceb, - 0x2ced, - 0x2cf2, - 0xa640, - 0xa642, - 0xa644, - 0xa646, - 0xa648, - 0xa64a, - 0xa64c, - 0xa64e, - 0xa650, - 0xa652, - 0xa654, - 0xa656, - 0xa658, - 0xa65a, - 0xa65c, - 0xa65e, - 0xa660, - 0xa662, - 0xa664, - 0xa666, - 0xa668, - 0xa66a, - 0xa66c, - 0xa680, - 0xa682, - 0xa684, - 0xa686, - 0xa688, - 0xa68a, - 0xa68c, - 0xa68e, - 0xa690, - 0xa692, - 0xa694, - 0xa696, - 0xa698, - 0xa69a, - 0xa722, - 0xa724, - 0xa726, - 0xa728, - 0xa72a, - 0xa72c, - 0xa72e, - 0xa732, - 0xa734, - 0xa736, - 0xa738, - 0xa73a, - 0xa73c, - 0xa73e, - 0xa740, - 0xa742, - 0xa744, - 0xa746, - 0xa748, - 0xa74a, - 0xa74c, - 0xa74e, - 0xa750, - 0xa752, - 0xa754, - 0xa756, - 0xa758, - 0xa75a, - 0xa75c, - 0xa75e, - 0xa760, - 0xa762, - 0xa764, - 0xa766, - 0xa768, - 0xa76a, - 0xa76c, - 0xa76e, - 0xa779, - 0xa77b, - 0xa780, - 0xa782, - 0xa784, - 0xa786, - 0xa78b, - 0xa78d, - 0xa790, - 0xa792, - 0xa796, - 0xa798, - 0xa79a, - 0xa79c, - 0xa79e, - 0xa7a0, - 0xa7a2, - 0xa7a4, - 0xa7a6, - 0xa7a8, - 0x1d49c, - 0x1d4a2, - 0x1d546, - 0x1d7ca, -}; - -} // !namespace - -bool isupper(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, isupperr, nelem (isupperr)/2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, isuppers, nelem (isuppers), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t islowerr[] = { - 0x0061, 0x007a, - 0x00df, 0x00f6, - 0x00f8, 0x00ff, - 0x0137, 0x0138, - 0x0148, 0x0149, - 0x017e, 0x0180, - 0x018c, 0x018d, - 0x0199, 0x019b, - 0x01aa, 0x01ab, - 0x01b9, 0x01ba, - 0x01bd, 0x01bf, - 0x01dc, 0x01dd, - 0x01ef, 0x01f0, - 0x0233, 0x0239, - 0x023f, 0x0240, - 0x024f, 0x0293, - 0x0295, 0x02af, - 0x037b, 0x037d, - 0x03ac, 0x03ce, - 0x03d0, 0x03d1, - 0x03d5, 0x03d7, - 0x03ef, 0x03f3, - 0x03fb, 0x03fc, - 0x0430, 0x045f, - 0x04ce, 0x04cf, - 0x0561, 0x0587, - 0x1d00, 0x1d2b, - 0x1d6b, 0x1d77, - 0x1d79, 0x1d9a, - 0x1e95, 0x1e9d, - 0x1eff, 0x1f07, - 0x1f10, 0x1f15, - 0x1f20, 0x1f27, - 0x1f30, 0x1f37, - 0x1f40, 0x1f45, - 0x1f50, 0x1f57, - 0x1f60, 0x1f67, - 0x1f70, 0x1f7d, - 0x1f80, 0x1f87, - 0x1f90, 0x1f97, - 0x1fa0, 0x1fa7, - 0x1fb0, 0x1fb4, - 0x1fb6, 0x1fb7, - 0x1fc2, 0x1fc4, - 0x1fc6, 0x1fc7, - 0x1fd0, 0x1fd3, - 0x1fd6, 0x1fd7, - 0x1fe0, 0x1fe7, - 0x1ff2, 0x1ff4, - 0x1ff6, 0x1ff7, - 0x210e, 0x210f, - 0x213c, 0x213d, - 0x2146, 0x2149, - 0x2170, 0x217f, - 0x24d0, 0x24e9, - 0x2c30, 0x2c5e, - 0x2c65, 0x2c66, - 0x2c73, 0x2c74, - 0x2c76, 0x2c7b, - 0x2ce3, 0x2ce4, - 0x2d00, 0x2d25, - 0xa72f, 0xa731, - 0xa771, 0xa778, - 0xa793, 0xa795, - 0xab30, 0xab5a, - 0xab64, 0xab65, - 0xfb00, 0xfb06, - 0xfb13, 0xfb17, - 0xff41, 0xff5a, - 0x10428, 0x1044f, - 0x118c0, 0x118df, - 0x1d41a, 0x1d433, - 0x1d44e, 0x1d454, - 0x1d456, 0x1d467, - 0x1d482, 0x1d49b, - 0x1d4b6, 0x1d4b9, - 0x1d4bd, 0x1d4c3, - 0x1d4c5, 0x1d4cf, - 0x1d4ea, 0x1d503, - 0x1d51e, 0x1d537, - 0x1d552, 0x1d56b, - 0x1d586, 0x1d59f, - 0x1d5ba, 0x1d5d3, - 0x1d5ee, 0x1d607, - 0x1d622, 0x1d63b, - 0x1d656, 0x1d66f, - 0x1d68a, 0x1d6a5, - 0x1d6c2, 0x1d6da, - 0x1d6dc, 0x1d6e1, - 0x1d6fc, 0x1d714, - 0x1d716, 0x1d71b, - 0x1d736, 0x1d74e, - 0x1d750, 0x1d755, - 0x1d770, 0x1d788, - 0x1d78a, 0x1d78f, - 0x1d7aa, 0x1d7c2, - 0x1d7c4, 0x1d7c9, -}; - -} // !namespace - -namespace { - -const char32_t islowers[] = { - 0x00b5, - 0x0101, - 0x0103, - 0x0105, - 0x0107, - 0x0109, - 0x010b, - 0x010d, - 0x010f, - 0x0111, - 0x0113, - 0x0115, - 0x0117, - 0x0119, - 0x011b, - 0x011d, - 0x011f, - 0x0121, - 0x0123, - 0x0125, - 0x0127, - 0x0129, - 0x012b, - 0x012d, - 0x012f, - 0x0131, - 0x0133, - 0x0135, - 0x013a, - 0x013c, - 0x013e, - 0x0140, - 0x0142, - 0x0144, - 0x0146, - 0x014b, - 0x014d, - 0x014f, - 0x0151, - 0x0153, - 0x0155, - 0x0157, - 0x0159, - 0x015b, - 0x015d, - 0x015f, - 0x0161, - 0x0163, - 0x0165, - 0x0167, - 0x0169, - 0x016b, - 0x016d, - 0x016f, - 0x0171, - 0x0173, - 0x0175, - 0x0177, - 0x017a, - 0x017c, - 0x0183, - 0x0185, - 0x0188, - 0x0192, - 0x0195, - 0x019e, - 0x01a1, - 0x01a3, - 0x01a5, - 0x01a8, - 0x01ad, - 0x01b0, - 0x01b4, - 0x01b6, - 0x01c6, - 0x01c9, - 0x01cc, - 0x01ce, - 0x01d0, - 0x01d2, - 0x01d4, - 0x01d6, - 0x01d8, - 0x01da, - 0x01df, - 0x01e1, - 0x01e3, - 0x01e5, - 0x01e7, - 0x01e9, - 0x01eb, - 0x01ed, - 0x01f3, - 0x01f5, - 0x01f9, - 0x01fb, - 0x01fd, - 0x01ff, - 0x0201, - 0x0203, - 0x0205, - 0x0207, - 0x0209, - 0x020b, - 0x020d, - 0x020f, - 0x0211, - 0x0213, - 0x0215, - 0x0217, - 0x0219, - 0x021b, - 0x021d, - 0x021f, - 0x0221, - 0x0223, - 0x0225, - 0x0227, - 0x0229, - 0x022b, - 0x022d, - 0x022f, - 0x0231, - 0x023c, - 0x0242, - 0x0247, - 0x0249, - 0x024b, - 0x024d, - 0x0371, - 0x0373, - 0x0377, - 0x0390, - 0x03d9, - 0x03db, - 0x03dd, - 0x03df, - 0x03e1, - 0x03e3, - 0x03e5, - 0x03e7, - 0x03e9, - 0x03eb, - 0x03ed, - 0x03f5, - 0x03f8, - 0x0461, - 0x0463, - 0x0465, - 0x0467, - 0x0469, - 0x046b, - 0x046d, - 0x046f, - 0x0471, - 0x0473, - 0x0475, - 0x0477, - 0x0479, - 0x047b, - 0x047d, - 0x047f, - 0x0481, - 0x048b, - 0x048d, - 0x048f, - 0x0491, - 0x0493, - 0x0495, - 0x0497, - 0x0499, - 0x049b, - 0x049d, - 0x049f, - 0x04a1, - 0x04a3, - 0x04a5, - 0x04a7, - 0x04a9, - 0x04ab, - 0x04ad, - 0x04af, - 0x04b1, - 0x04b3, - 0x04b5, - 0x04b7, - 0x04b9, - 0x04bb, - 0x04bd, - 0x04bf, - 0x04c2, - 0x04c4, - 0x04c6, - 0x04c8, - 0x04ca, - 0x04cc, - 0x04d1, - 0x04d3, - 0x04d5, - 0x04d7, - 0x04d9, - 0x04db, - 0x04dd, - 0x04df, - 0x04e1, - 0x04e3, - 0x04e5, - 0x04e7, - 0x04e9, - 0x04eb, - 0x04ed, - 0x04ef, - 0x04f1, - 0x04f3, - 0x04f5, - 0x04f7, - 0x04f9, - 0x04fb, - 0x04fd, - 0x04ff, - 0x0501, - 0x0503, - 0x0505, - 0x0507, - 0x0509, - 0x050b, - 0x050d, - 0x050f, - 0x0511, - 0x0513, - 0x0515, - 0x0517, - 0x0519, - 0x051b, - 0x051d, - 0x051f, - 0x0521, - 0x0523, - 0x0525, - 0x0527, - 0x0529, - 0x052b, - 0x052d, - 0x052f, - 0x1e01, - 0x1e03, - 0x1e05, - 0x1e07, - 0x1e09, - 0x1e0b, - 0x1e0d, - 0x1e0f, - 0x1e11, - 0x1e13, - 0x1e15, - 0x1e17, - 0x1e19, - 0x1e1b, - 0x1e1d, - 0x1e1f, - 0x1e21, - 0x1e23, - 0x1e25, - 0x1e27, - 0x1e29, - 0x1e2b, - 0x1e2d, - 0x1e2f, - 0x1e31, - 0x1e33, - 0x1e35, - 0x1e37, - 0x1e39, - 0x1e3b, - 0x1e3d, - 0x1e3f, - 0x1e41, - 0x1e43, - 0x1e45, - 0x1e47, - 0x1e49, - 0x1e4b, - 0x1e4d, - 0x1e4f, - 0x1e51, - 0x1e53, - 0x1e55, - 0x1e57, - 0x1e59, - 0x1e5b, - 0x1e5d, - 0x1e5f, - 0x1e61, - 0x1e63, - 0x1e65, - 0x1e67, - 0x1e69, - 0x1e6b, - 0x1e6d, - 0x1e6f, - 0x1e71, - 0x1e73, - 0x1e75, - 0x1e77, - 0x1e79, - 0x1e7b, - 0x1e7d, - 0x1e7f, - 0x1e81, - 0x1e83, - 0x1e85, - 0x1e87, - 0x1e89, - 0x1e8b, - 0x1e8d, - 0x1e8f, - 0x1e91, - 0x1e93, - 0x1e9f, - 0x1ea1, - 0x1ea3, - 0x1ea5, - 0x1ea7, - 0x1ea9, - 0x1eab, - 0x1ead, - 0x1eaf, - 0x1eb1, - 0x1eb3, - 0x1eb5, - 0x1eb7, - 0x1eb9, - 0x1ebb, - 0x1ebd, - 0x1ebf, - 0x1ec1, - 0x1ec3, - 0x1ec5, - 0x1ec7, - 0x1ec9, - 0x1ecb, - 0x1ecd, - 0x1ecf, - 0x1ed1, - 0x1ed3, - 0x1ed5, - 0x1ed7, - 0x1ed9, - 0x1edb, - 0x1edd, - 0x1edf, - 0x1ee1, - 0x1ee3, - 0x1ee5, - 0x1ee7, - 0x1ee9, - 0x1eeb, - 0x1eed, - 0x1eef, - 0x1ef1, - 0x1ef3, - 0x1ef5, - 0x1ef7, - 0x1ef9, - 0x1efb, - 0x1efd, - 0x1fbe, - 0x210a, - 0x2113, - 0x212f, - 0x2134, - 0x2139, - 0x214e, - 0x2184, - 0x2c61, - 0x2c68, - 0x2c6a, - 0x2c6c, - 0x2c71, - 0x2c81, - 0x2c83, - 0x2c85, - 0x2c87, - 0x2c89, - 0x2c8b, - 0x2c8d, - 0x2c8f, - 0x2c91, - 0x2c93, - 0x2c95, - 0x2c97, - 0x2c99, - 0x2c9b, - 0x2c9d, - 0x2c9f, - 0x2ca1, - 0x2ca3, - 0x2ca5, - 0x2ca7, - 0x2ca9, - 0x2cab, - 0x2cad, - 0x2caf, - 0x2cb1, - 0x2cb3, - 0x2cb5, - 0x2cb7, - 0x2cb9, - 0x2cbb, - 0x2cbd, - 0x2cbf, - 0x2cc1, - 0x2cc3, - 0x2cc5, - 0x2cc7, - 0x2cc9, - 0x2ccb, - 0x2ccd, - 0x2ccf, - 0x2cd1, - 0x2cd3, - 0x2cd5, - 0x2cd7, - 0x2cd9, - 0x2cdb, - 0x2cdd, - 0x2cdf, - 0x2ce1, - 0x2cec, - 0x2cee, - 0x2cf3, - 0x2d27, - 0x2d2d, - 0xa641, - 0xa643, - 0xa645, - 0xa647, - 0xa649, - 0xa64b, - 0xa64d, - 0xa64f, - 0xa651, - 0xa653, - 0xa655, - 0xa657, - 0xa659, - 0xa65b, - 0xa65d, - 0xa65f, - 0xa661, - 0xa663, - 0xa665, - 0xa667, - 0xa669, - 0xa66b, - 0xa66d, - 0xa681, - 0xa683, - 0xa685, - 0xa687, - 0xa689, - 0xa68b, - 0xa68d, - 0xa68f, - 0xa691, - 0xa693, - 0xa695, - 0xa697, - 0xa699, - 0xa69b, - 0xa723, - 0xa725, - 0xa727, - 0xa729, - 0xa72b, - 0xa72d, - 0xa733, - 0xa735, - 0xa737, - 0xa739, - 0xa73b, - 0xa73d, - 0xa73f, - 0xa741, - 0xa743, - 0xa745, - 0xa747, - 0xa749, - 0xa74b, - 0xa74d, - 0xa74f, - 0xa751, - 0xa753, - 0xa755, - 0xa757, - 0xa759, - 0xa75b, - 0xa75d, - 0xa75f, - 0xa761, - 0xa763, - 0xa765, - 0xa767, - 0xa769, - 0xa76b, - 0xa76d, - 0xa76f, - 0xa77a, - 0xa77c, - 0xa77f, - 0xa781, - 0xa783, - 0xa785, - 0xa787, - 0xa78c, - 0xa78e, - 0xa791, - 0xa797, - 0xa799, - 0xa79b, - 0xa79d, - 0xa79f, - 0xa7a1, - 0xa7a3, - 0xa7a5, - 0xa7a7, - 0xa7a9, - 0xa7fa, - 0x1d4bb, - 0x1d7cb, -}; - -} // !namespace - -bool islower(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, islowerr, nelem (islowerr)/2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, islowers, nelem (islowers), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t istitler[] = { - 0x0041, 0x005a, - 0x00c0, 0x00d6, - 0x00d8, 0x00de, - 0x0178, 0x0179, - 0x0181, 0x0182, - 0x0186, 0x0187, - 0x0189, 0x018b, - 0x018e, 0x0191, - 0x0193, 0x0194, - 0x0196, 0x0198, - 0x019c, 0x019d, - 0x019f, 0x01a0, - 0x01a6, 0x01a7, - 0x01ae, 0x01af, - 0x01b1, 0x01b3, - 0x01b7, 0x01b8, - 0x01f6, 0x01f8, - 0x023a, 0x023b, - 0x023d, 0x023e, - 0x0243, 0x0246, - 0x0388, 0x038a, - 0x038e, 0x038f, - 0x0391, 0x03a1, - 0x03a3, 0x03ab, - 0x03f9, 0x03fa, - 0x03fd, 0x042f, - 0x04c0, 0x04c1, - 0x0531, 0x0556, - 0x10a0, 0x10c5, - 0x1f08, 0x1f0f, - 0x1f18, 0x1f1d, - 0x1f28, 0x1f2f, - 0x1f38, 0x1f3f, - 0x1f48, 0x1f4d, - 0x1f68, 0x1f6f, - 0x1f88, 0x1f8f, - 0x1f98, 0x1f9f, - 0x1fa8, 0x1faf, - 0x1fb8, 0x1fbc, - 0x1fc8, 0x1fcc, - 0x1fd8, 0x1fdb, - 0x1fe8, 0x1fec, - 0x1ff8, 0x1ffc, - 0x2160, 0x216f, - 0x24b6, 0x24cf, - 0x2c00, 0x2c2e, - 0x2c62, 0x2c64, - 0x2c6d, 0x2c70, - 0x2c7e, 0x2c80, - 0xa77d, 0xa77e, - 0xa7aa, 0xa7ad, - 0xa7b0, 0xa7b1, - 0xff21, 0xff3a, - 0x10400, 0x10427, - 0x118a0, 0x118bf, -}; - -} // !namespace - -namespace { - -const char32_t istitles[] = { - 0x0100, - 0x0102, - 0x0104, - 0x0106, - 0x0108, - 0x010a, - 0x010c, - 0x010e, - 0x0110, - 0x0112, - 0x0114, - 0x0116, - 0x0118, - 0x011a, - 0x011c, - 0x011e, - 0x0120, - 0x0122, - 0x0124, - 0x0126, - 0x0128, - 0x012a, - 0x012c, - 0x012e, - 0x0132, - 0x0134, - 0x0136, - 0x0139, - 0x013b, - 0x013d, - 0x013f, - 0x0141, - 0x0143, - 0x0145, - 0x0147, - 0x014a, - 0x014c, - 0x014e, - 0x0150, - 0x0152, - 0x0154, - 0x0156, - 0x0158, - 0x015a, - 0x015c, - 0x015e, - 0x0160, - 0x0162, - 0x0164, - 0x0166, - 0x0168, - 0x016a, - 0x016c, - 0x016e, - 0x0170, - 0x0172, - 0x0174, - 0x0176, - 0x017b, - 0x017d, - 0x0184, - 0x01a2, - 0x01a4, - 0x01a9, - 0x01ac, - 0x01b5, - 0x01bc, - 0x01c5, - 0x01c8, - 0x01cb, - 0x01cd, - 0x01cf, - 0x01d1, - 0x01d3, - 0x01d5, - 0x01d7, - 0x01d9, - 0x01db, - 0x01de, - 0x01e0, - 0x01e2, - 0x01e4, - 0x01e6, - 0x01e8, - 0x01ea, - 0x01ec, - 0x01ee, - 0x01f2, - 0x01f4, - 0x01fa, - 0x01fc, - 0x01fe, - 0x0200, - 0x0202, - 0x0204, - 0x0206, - 0x0208, - 0x020a, - 0x020c, - 0x020e, - 0x0210, - 0x0212, - 0x0214, - 0x0216, - 0x0218, - 0x021a, - 0x021c, - 0x021e, - 0x0220, - 0x0222, - 0x0224, - 0x0226, - 0x0228, - 0x022a, - 0x022c, - 0x022e, - 0x0230, - 0x0232, - 0x0241, - 0x0248, - 0x024a, - 0x024c, - 0x024e, - 0x0370, - 0x0372, - 0x0376, - 0x037f, - 0x0386, - 0x038c, - 0x03cf, - 0x03d8, - 0x03da, - 0x03dc, - 0x03de, - 0x03e0, - 0x03e2, - 0x03e4, - 0x03e6, - 0x03e8, - 0x03ea, - 0x03ec, - 0x03ee, - 0x03f7, - 0x0460, - 0x0462, - 0x0464, - 0x0466, - 0x0468, - 0x046a, - 0x046c, - 0x046e, - 0x0470, - 0x0472, - 0x0474, - 0x0476, - 0x0478, - 0x047a, - 0x047c, - 0x047e, - 0x0480, - 0x048a, - 0x048c, - 0x048e, - 0x0490, - 0x0492, - 0x0494, - 0x0496, - 0x0498, - 0x049a, - 0x049c, - 0x049e, - 0x04a0, - 0x04a2, - 0x04a4, - 0x04a6, - 0x04a8, - 0x04aa, - 0x04ac, - 0x04ae, - 0x04b0, - 0x04b2, - 0x04b4, - 0x04b6, - 0x04b8, - 0x04ba, - 0x04bc, - 0x04be, - 0x04c3, - 0x04c5, - 0x04c7, - 0x04c9, - 0x04cb, - 0x04cd, - 0x04d0, - 0x04d2, - 0x04d4, - 0x04d6, - 0x04d8, - 0x04da, - 0x04dc, - 0x04de, - 0x04e0, - 0x04e2, - 0x04e4, - 0x04e6, - 0x04e8, - 0x04ea, - 0x04ec, - 0x04ee, - 0x04f0, - 0x04f2, - 0x04f4, - 0x04f6, - 0x04f8, - 0x04fa, - 0x04fc, - 0x04fe, - 0x0500, - 0x0502, - 0x0504, - 0x0506, - 0x0508, - 0x050a, - 0x050c, - 0x050e, - 0x0510, - 0x0512, - 0x0514, - 0x0516, - 0x0518, - 0x051a, - 0x051c, - 0x051e, - 0x0520, - 0x0522, - 0x0524, - 0x0526, - 0x0528, - 0x052a, - 0x052c, - 0x052e, - 0x10c7, - 0x10cd, - 0x1e00, - 0x1e02, - 0x1e04, - 0x1e06, - 0x1e08, - 0x1e0a, - 0x1e0c, - 0x1e0e, - 0x1e10, - 0x1e12, - 0x1e14, - 0x1e16, - 0x1e18, - 0x1e1a, - 0x1e1c, - 0x1e1e, - 0x1e20, - 0x1e22, - 0x1e24, - 0x1e26, - 0x1e28, - 0x1e2a, - 0x1e2c, - 0x1e2e, - 0x1e30, - 0x1e32, - 0x1e34, - 0x1e36, - 0x1e38, - 0x1e3a, - 0x1e3c, - 0x1e3e, - 0x1e40, - 0x1e42, - 0x1e44, - 0x1e46, - 0x1e48, - 0x1e4a, - 0x1e4c, - 0x1e4e, - 0x1e50, - 0x1e52, - 0x1e54, - 0x1e56, - 0x1e58, - 0x1e5a, - 0x1e5c, - 0x1e5e, - 0x1e60, - 0x1e62, - 0x1e64, - 0x1e66, - 0x1e68, - 0x1e6a, - 0x1e6c, - 0x1e6e, - 0x1e70, - 0x1e72, - 0x1e74, - 0x1e76, - 0x1e78, - 0x1e7a, - 0x1e7c, - 0x1e7e, - 0x1e80, - 0x1e82, - 0x1e84, - 0x1e86, - 0x1e88, - 0x1e8a, - 0x1e8c, - 0x1e8e, - 0x1e90, - 0x1e92, - 0x1e94, - 0x1ea0, - 0x1ea2, - 0x1ea4, - 0x1ea6, - 0x1ea8, - 0x1eaa, - 0x1eac, - 0x1eae, - 0x1eb0, - 0x1eb2, - 0x1eb4, - 0x1eb6, - 0x1eb8, - 0x1eba, - 0x1ebc, - 0x1ebe, - 0x1ec0, - 0x1ec2, - 0x1ec4, - 0x1ec6, - 0x1ec8, - 0x1eca, - 0x1ecc, - 0x1ece, - 0x1ed0, - 0x1ed2, - 0x1ed4, - 0x1ed6, - 0x1ed8, - 0x1eda, - 0x1edc, - 0x1ede, - 0x1ee0, - 0x1ee2, - 0x1ee4, - 0x1ee6, - 0x1ee8, - 0x1eea, - 0x1eec, - 0x1eee, - 0x1ef0, - 0x1ef2, - 0x1ef4, - 0x1ef6, - 0x1ef8, - 0x1efa, - 0x1efc, - 0x1efe, - 0x1f59, - 0x1f5b, - 0x1f5d, - 0x1f5f, - 0x2132, - 0x2183, - 0x2c60, - 0x2c67, - 0x2c69, - 0x2c6b, - 0x2c72, - 0x2c75, - 0x2c82, - 0x2c84, - 0x2c86, - 0x2c88, - 0x2c8a, - 0x2c8c, - 0x2c8e, - 0x2c90, - 0x2c92, - 0x2c94, - 0x2c96, - 0x2c98, - 0x2c9a, - 0x2c9c, - 0x2c9e, - 0x2ca0, - 0x2ca2, - 0x2ca4, - 0x2ca6, - 0x2ca8, - 0x2caa, - 0x2cac, - 0x2cae, - 0x2cb0, - 0x2cb2, - 0x2cb4, - 0x2cb6, - 0x2cb8, - 0x2cba, - 0x2cbc, - 0x2cbe, - 0x2cc0, - 0x2cc2, - 0x2cc4, - 0x2cc6, - 0x2cc8, - 0x2cca, - 0x2ccc, - 0x2cce, - 0x2cd0, - 0x2cd2, - 0x2cd4, - 0x2cd6, - 0x2cd8, - 0x2cda, - 0x2cdc, - 0x2cde, - 0x2ce0, - 0x2ce2, - 0x2ceb, - 0x2ced, - 0x2cf2, - 0xa640, - 0xa642, - 0xa644, - 0xa646, - 0xa648, - 0xa64a, - 0xa64c, - 0xa64e, - 0xa650, - 0xa652, - 0xa654, - 0xa656, - 0xa658, - 0xa65a, - 0xa65c, - 0xa65e, - 0xa660, - 0xa662, - 0xa664, - 0xa666, - 0xa668, - 0xa66a, - 0xa66c, - 0xa680, - 0xa682, - 0xa684, - 0xa686, - 0xa688, - 0xa68a, - 0xa68c, - 0xa68e, - 0xa690, - 0xa692, - 0xa694, - 0xa696, - 0xa698, - 0xa69a, - 0xa722, - 0xa724, - 0xa726, - 0xa728, - 0xa72a, - 0xa72c, - 0xa72e, - 0xa732, - 0xa734, - 0xa736, - 0xa738, - 0xa73a, - 0xa73c, - 0xa73e, - 0xa740, - 0xa742, - 0xa744, - 0xa746, - 0xa748, - 0xa74a, - 0xa74c, - 0xa74e, - 0xa750, - 0xa752, - 0xa754, - 0xa756, - 0xa758, - 0xa75a, - 0xa75c, - 0xa75e, - 0xa760, - 0xa762, - 0xa764, - 0xa766, - 0xa768, - 0xa76a, - 0xa76c, - 0xa76e, - 0xa779, - 0xa77b, - 0xa780, - 0xa782, - 0xa784, - 0xa786, - 0xa78b, - 0xa78d, - 0xa790, - 0xa792, - 0xa796, - 0xa798, - 0xa79a, - 0xa79c, - 0xa79e, - 0xa7a0, - 0xa7a2, - 0xa7a4, - 0xa7a6, - 0xa7a8, -}; - -} // !namespace - -bool istitle(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, istitler, nelem (istitler)/2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = rbsearch(c, istitles, nelem (istitles), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -namespace { - -const char32_t toupperr[] = { - 0x0061, 0x007a, 1048544, - 0x00e0, 0x00f6, 1048544, - 0x00f8, 0x00fe, 1048544, - 0x023f, 0x0240, 1059391, - 0x0256, 0x0257, 1048371, - 0x028a, 0x028b, 1048359, - 0x037b, 0x037d, 1048706, - 0x03ad, 0x03af, 1048539, - 0x03b1, 0x03c1, 1048544, - 0x03c3, 0x03cb, 1048544, - 0x03cd, 0x03ce, 1048513, - 0x0430, 0x044f, 1048544, - 0x0450, 0x045f, 1048496, - 0x0561, 0x0586, 1048528, - 0x1f00, 0x1f07, 1048584, - 0x1f10, 0x1f15, 1048584, - 0x1f20, 0x1f27, 1048584, - 0x1f30, 0x1f37, 1048584, - 0x1f40, 0x1f45, 1048584, - 0x1f60, 0x1f67, 1048584, - 0x1f70, 0x1f71, 1048650, - 0x1f72, 0x1f75, 1048662, - 0x1f76, 0x1f77, 1048676, - 0x1f78, 0x1f79, 1048704, - 0x1f7a, 0x1f7b, 1048688, - 0x1f7c, 0x1f7d, 1048702, - 0x1f80, 0x1f87, 1048584, - 0x1f90, 0x1f97, 1048584, - 0x1fa0, 0x1fa7, 1048584, - 0x1fb0, 0x1fb1, 1048584, - 0x1fd0, 0x1fd1, 1048584, - 0x1fe0, 0x1fe1, 1048584, - 0x2170, 0x217f, 1048560, - 0x24d0, 0x24e9, 1048550, - 0x2c30, 0x2c5e, 1048528, - 0x2d00, 0x2d25, 1041312, - 0xff41, 0xff5a, 1048544, - 0x10428, 0x1044f, 1048536, - 0x118c0, 0x118df, 1048544, -}; - -} // !namespace - -namespace { - -const char32_t touppers[] = { - 0x00b5, 1049319, - 0x00ff, 1048697, - 0x0101, 1048575, - 0x0103, 1048575, - 0x0105, 1048575, - 0x0107, 1048575, - 0x0109, 1048575, - 0x010b, 1048575, - 0x010d, 1048575, - 0x010f, 1048575, - 0x0111, 1048575, - 0x0113, 1048575, - 0x0115, 1048575, - 0x0117, 1048575, - 0x0119, 1048575, - 0x011b, 1048575, - 0x011d, 1048575, - 0x011f, 1048575, - 0x0121, 1048575, - 0x0123, 1048575, - 0x0125, 1048575, - 0x0127, 1048575, - 0x0129, 1048575, - 0x012b, 1048575, - 0x012d, 1048575, - 0x012f, 1048575, - 0x0131, 1048344, - 0x0133, 1048575, - 0x0135, 1048575, - 0x0137, 1048575, - 0x013a, 1048575, - 0x013c, 1048575, - 0x013e, 1048575, - 0x0140, 1048575, - 0x0142, 1048575, - 0x0144, 1048575, - 0x0146, 1048575, - 0x0148, 1048575, - 0x014b, 1048575, - 0x014d, 1048575, - 0x014f, 1048575, - 0x0151, 1048575, - 0x0153, 1048575, - 0x0155, 1048575, - 0x0157, 1048575, - 0x0159, 1048575, - 0x015b, 1048575, - 0x015d, 1048575, - 0x015f, 1048575, - 0x0161, 1048575, - 0x0163, 1048575, - 0x0165, 1048575, - 0x0167, 1048575, - 0x0169, 1048575, - 0x016b, 1048575, - 0x016d, 1048575, - 0x016f, 1048575, - 0x0171, 1048575, - 0x0173, 1048575, - 0x0175, 1048575, - 0x0177, 1048575, - 0x017a, 1048575, - 0x017c, 1048575, - 0x017e, 1048575, - 0x017f, 1048276, - 0x0180, 1048771, - 0x0183, 1048575, - 0x0185, 1048575, - 0x0188, 1048575, - 0x018c, 1048575, - 0x0192, 1048575, - 0x0195, 1048673, - 0x0199, 1048575, - 0x019a, 1048739, - 0x019e, 1048706, - 0x01a1, 1048575, - 0x01a3, 1048575, - 0x01a5, 1048575, - 0x01a8, 1048575, - 0x01ad, 1048575, - 0x01b0, 1048575, - 0x01b4, 1048575, - 0x01b6, 1048575, - 0x01b9, 1048575, - 0x01bd, 1048575, - 0x01bf, 1048632, - 0x01c5, 1048575, - 0x01c6, 1048574, - 0x01c8, 1048575, - 0x01c9, 1048574, - 0x01cb, 1048575, - 0x01cc, 1048574, - 0x01ce, 1048575, - 0x01d0, 1048575, - 0x01d2, 1048575, - 0x01d4, 1048575, - 0x01d6, 1048575, - 0x01d8, 1048575, - 0x01da, 1048575, - 0x01dc, 1048575, - 0x01dd, 1048497, - 0x01df, 1048575, - 0x01e1, 1048575, - 0x01e3, 1048575, - 0x01e5, 1048575, - 0x01e7, 1048575, - 0x01e9, 1048575, - 0x01eb, 1048575, - 0x01ed, 1048575, - 0x01ef, 1048575, - 0x01f2, 1048575, - 0x01f3, 1048574, - 0x01f5, 1048575, - 0x01f9, 1048575, - 0x01fb, 1048575, - 0x01fd, 1048575, - 0x01ff, 1048575, - 0x0201, 1048575, - 0x0203, 1048575, - 0x0205, 1048575, - 0x0207, 1048575, - 0x0209, 1048575, - 0x020b, 1048575, - 0x020d, 1048575, - 0x020f, 1048575, - 0x0211, 1048575, - 0x0213, 1048575, - 0x0215, 1048575, - 0x0217, 1048575, - 0x0219, 1048575, - 0x021b, 1048575, - 0x021d, 1048575, - 0x021f, 1048575, - 0x0223, 1048575, - 0x0225, 1048575, - 0x0227, 1048575, - 0x0229, 1048575, - 0x022b, 1048575, - 0x022d, 1048575, - 0x022f, 1048575, - 0x0231, 1048575, - 0x0233, 1048575, - 0x023c, 1048575, - 0x0242, 1048575, - 0x0247, 1048575, - 0x0249, 1048575, - 0x024b, 1048575, - 0x024d, 1048575, - 0x024f, 1048575, - 0x0250, 1059359, - 0x0251, 1059356, - 0x0252, 1059358, - 0x0253, 1048366, - 0x0254, 1048370, - 0x0259, 1048374, - 0x025b, 1048373, - 0x025c, 1090895, - 0x0260, 1048371, - 0x0261, 1090891, - 0x0263, 1048369, - 0x0265, 1090856, - 0x0266, 1090884, - 0x0268, 1048367, - 0x0269, 1048365, - 0x026b, 1059319, - 0x026c, 1090881, - 0x026f, 1048365, - 0x0271, 1059325, - 0x0272, 1048363, - 0x0275, 1048362, - 0x027d, 1059303, - 0x0280, 1048358, - 0x0283, 1048358, - 0x0287, 1090858, - 0x0288, 1048358, - 0x0289, 1048507, - 0x028c, 1048505, - 0x0292, 1048357, - 0x029e, 1090834, - 0x0345, 1048660, - 0x0371, 1048575, - 0x0373, 1048575, - 0x0377, 1048575, - 0x03ac, 1048538, - 0x03c2, 1048545, - 0x03cc, 1048512, - 0x03d0, 1048514, - 0x03d1, 1048519, - 0x03d5, 1048529, - 0x03d6, 1048522, - 0x03d7, 1048568, - 0x03d9, 1048575, - 0x03db, 1048575, - 0x03dd, 1048575, - 0x03df, 1048575, - 0x03e1, 1048575, - 0x03e3, 1048575, - 0x03e5, 1048575, - 0x03e7, 1048575, - 0x03e9, 1048575, - 0x03eb, 1048575, - 0x03ed, 1048575, - 0x03ef, 1048575, - 0x03f0, 1048490, - 0x03f1, 1048496, - 0x03f2, 1048583, - 0x03f3, 1048460, - 0x03f5, 1048480, - 0x03f8, 1048575, - 0x03fb, 1048575, - 0x0461, 1048575, - 0x0463, 1048575, - 0x0465, 1048575, - 0x0467, 1048575, - 0x0469, 1048575, - 0x046b, 1048575, - 0x046d, 1048575, - 0x046f, 1048575, - 0x0471, 1048575, - 0x0473, 1048575, - 0x0475, 1048575, - 0x0477, 1048575, - 0x0479, 1048575, - 0x047b, 1048575, - 0x047d, 1048575, - 0x047f, 1048575, - 0x0481, 1048575, - 0x048b, 1048575, - 0x048d, 1048575, - 0x048f, 1048575, - 0x0491, 1048575, - 0x0493, 1048575, - 0x0495, 1048575, - 0x0497, 1048575, - 0x0499, 1048575, - 0x049b, 1048575, - 0x049d, 1048575, - 0x049f, 1048575, - 0x04a1, 1048575, - 0x04a3, 1048575, - 0x04a5, 1048575, - 0x04a7, 1048575, - 0x04a9, 1048575, - 0x04ab, 1048575, - 0x04ad, 1048575, - 0x04af, 1048575, - 0x04b1, 1048575, - 0x04b3, 1048575, - 0x04b5, 1048575, - 0x04b7, 1048575, - 0x04b9, 1048575, - 0x04bb, 1048575, - 0x04bd, 1048575, - 0x04bf, 1048575, - 0x04c2, 1048575, - 0x04c4, 1048575, - 0x04c6, 1048575, - 0x04c8, 1048575, - 0x04ca, 1048575, - 0x04cc, 1048575, - 0x04ce, 1048575, - 0x04cf, 1048561, - 0x04d1, 1048575, - 0x04d3, 1048575, - 0x04d5, 1048575, - 0x04d7, 1048575, - 0x04d9, 1048575, - 0x04db, 1048575, - 0x04dd, 1048575, - 0x04df, 1048575, - 0x04e1, 1048575, - 0x04e3, 1048575, - 0x04e5, 1048575, - 0x04e7, 1048575, - 0x04e9, 1048575, - 0x04eb, 1048575, - 0x04ed, 1048575, - 0x04ef, 1048575, - 0x04f1, 1048575, - 0x04f3, 1048575, - 0x04f5, 1048575, - 0x04f7, 1048575, - 0x04f9, 1048575, - 0x04fb, 1048575, - 0x04fd, 1048575, - 0x04ff, 1048575, - 0x0501, 1048575, - 0x0503, 1048575, - 0x0505, 1048575, - 0x0507, 1048575, - 0x0509, 1048575, - 0x050b, 1048575, - 0x050d, 1048575, - 0x050f, 1048575, - 0x0511, 1048575, - 0x0513, 1048575, - 0x0515, 1048575, - 0x0517, 1048575, - 0x0519, 1048575, - 0x051b, 1048575, - 0x051d, 1048575, - 0x051f, 1048575, - 0x0521, 1048575, - 0x0523, 1048575, - 0x0525, 1048575, - 0x0527, 1048575, - 0x0529, 1048575, - 0x052b, 1048575, - 0x052d, 1048575, - 0x052f, 1048575, - 0x1d79, 1083908, - 0x1d7d, 1052390, - 0x1e01, 1048575, - 0x1e03, 1048575, - 0x1e05, 1048575, - 0x1e07, 1048575, - 0x1e09, 1048575, - 0x1e0b, 1048575, - 0x1e0d, 1048575, - 0x1e0f, 1048575, - 0x1e11, 1048575, - 0x1e13, 1048575, - 0x1e15, 1048575, - 0x1e17, 1048575, - 0x1e19, 1048575, - 0x1e1b, 1048575, - 0x1e1d, 1048575, - 0x1e1f, 1048575, - 0x1e21, 1048575, - 0x1e23, 1048575, - 0x1e25, 1048575, - 0x1e27, 1048575, - 0x1e29, 1048575, - 0x1e2b, 1048575, - 0x1e2d, 1048575, - 0x1e2f, 1048575, - 0x1e31, 1048575, - 0x1e33, 1048575, - 0x1e35, 1048575, - 0x1e37, 1048575, - 0x1e39, 1048575, - 0x1e3b, 1048575, - 0x1e3d, 1048575, - 0x1e3f, 1048575, - 0x1e41, 1048575, - 0x1e43, 1048575, - 0x1e45, 1048575, - 0x1e47, 1048575, - 0x1e49, 1048575, - 0x1e4b, 1048575, - 0x1e4d, 1048575, - 0x1e4f, 1048575, - 0x1e51, 1048575, - 0x1e53, 1048575, - 0x1e55, 1048575, - 0x1e57, 1048575, - 0x1e59, 1048575, - 0x1e5b, 1048575, - 0x1e5d, 1048575, - 0x1e5f, 1048575, - 0x1e61, 1048575, - 0x1e63, 1048575, - 0x1e65, 1048575, - 0x1e67, 1048575, - 0x1e69, 1048575, - 0x1e6b, 1048575, - 0x1e6d, 1048575, - 0x1e6f, 1048575, - 0x1e71, 1048575, - 0x1e73, 1048575, - 0x1e75, 1048575, - 0x1e77, 1048575, - 0x1e79, 1048575, - 0x1e7b, 1048575, - 0x1e7d, 1048575, - 0x1e7f, 1048575, - 0x1e81, 1048575, - 0x1e83, 1048575, - 0x1e85, 1048575, - 0x1e87, 1048575, - 0x1e89, 1048575, - 0x1e8b, 1048575, - 0x1e8d, 1048575, - 0x1e8f, 1048575, - 0x1e91, 1048575, - 0x1e93, 1048575, - 0x1e95, 1048575, - 0x1e9b, 1048517, - 0x1ea1, 1048575, - 0x1ea3, 1048575, - 0x1ea5, 1048575, - 0x1ea7, 1048575, - 0x1ea9, 1048575, - 0x1eab, 1048575, - 0x1ead, 1048575, - 0x1eaf, 1048575, - 0x1eb1, 1048575, - 0x1eb3, 1048575, - 0x1eb5, 1048575, - 0x1eb7, 1048575, - 0x1eb9, 1048575, - 0x1ebb, 1048575, - 0x1ebd, 1048575, - 0x1ebf, 1048575, - 0x1ec1, 1048575, - 0x1ec3, 1048575, - 0x1ec5, 1048575, - 0x1ec7, 1048575, - 0x1ec9, 1048575, - 0x1ecb, 1048575, - 0x1ecd, 1048575, - 0x1ecf, 1048575, - 0x1ed1, 1048575, - 0x1ed3, 1048575, - 0x1ed5, 1048575, - 0x1ed7, 1048575, - 0x1ed9, 1048575, - 0x1edb, 1048575, - 0x1edd, 1048575, - 0x1edf, 1048575, - 0x1ee1, 1048575, - 0x1ee3, 1048575, - 0x1ee5, 1048575, - 0x1ee7, 1048575, - 0x1ee9, 1048575, - 0x1eeb, 1048575, - 0x1eed, 1048575, - 0x1eef, 1048575, - 0x1ef1, 1048575, - 0x1ef3, 1048575, - 0x1ef5, 1048575, - 0x1ef7, 1048575, - 0x1ef9, 1048575, - 0x1efb, 1048575, - 0x1efd, 1048575, - 0x1eff, 1048575, - 0x1f51, 1048584, - 0x1f53, 1048584, - 0x1f55, 1048584, - 0x1f57, 1048584, - 0x1fb3, 1048585, - 0x1fbe, 1041371, - 0x1fc3, 1048585, - 0x1fe5, 1048583, - 0x1ff3, 1048585, - 0x214e, 1048548, - 0x2184, 1048575, - 0x2c61, 1048575, - 0x2c65, 1037781, - 0x2c66, 1037784, - 0x2c68, 1048575, - 0x2c6a, 1048575, - 0x2c6c, 1048575, - 0x2c73, 1048575, - 0x2c76, 1048575, - 0x2c81, 1048575, - 0x2c83, 1048575, - 0x2c85, 1048575, - 0x2c87, 1048575, - 0x2c89, 1048575, - 0x2c8b, 1048575, - 0x2c8d, 1048575, - 0x2c8f, 1048575, - 0x2c91, 1048575, - 0x2c93, 1048575, - 0x2c95, 1048575, - 0x2c97, 1048575, - 0x2c99, 1048575, - 0x2c9b, 1048575, - 0x2c9d, 1048575, - 0x2c9f, 1048575, - 0x2ca1, 1048575, - 0x2ca3, 1048575, - 0x2ca5, 1048575, - 0x2ca7, 1048575, - 0x2ca9, 1048575, - 0x2cab, 1048575, - 0x2cad, 1048575, - 0x2caf, 1048575, - 0x2cb1, 1048575, - 0x2cb3, 1048575, - 0x2cb5, 1048575, - 0x2cb7, 1048575, - 0x2cb9, 1048575, - 0x2cbb, 1048575, - 0x2cbd, 1048575, - 0x2cbf, 1048575, - 0x2cc1, 1048575, - 0x2cc3, 1048575, - 0x2cc5, 1048575, - 0x2cc7, 1048575, - 0x2cc9, 1048575, - 0x2ccb, 1048575, - 0x2ccd, 1048575, - 0x2ccf, 1048575, - 0x2cd1, 1048575, - 0x2cd3, 1048575, - 0x2cd5, 1048575, - 0x2cd7, 1048575, - 0x2cd9, 1048575, - 0x2cdb, 1048575, - 0x2cdd, 1048575, - 0x2cdf, 1048575, - 0x2ce1, 1048575, - 0x2ce3, 1048575, - 0x2cec, 1048575, - 0x2cee, 1048575, - 0x2cf3, 1048575, - 0x2d27, 1041312, - 0x2d2d, 1041312, - 0xa641, 1048575, - 0xa643, 1048575, - 0xa645, 1048575, - 0xa647, 1048575, - 0xa649, 1048575, - 0xa64b, 1048575, - 0xa64d, 1048575, - 0xa64f, 1048575, - 0xa651, 1048575, - 0xa653, 1048575, - 0xa655, 1048575, - 0xa657, 1048575, - 0xa659, 1048575, - 0xa65b, 1048575, - 0xa65d, 1048575, - 0xa65f, 1048575, - 0xa661, 1048575, - 0xa663, 1048575, - 0xa665, 1048575, - 0xa667, 1048575, - 0xa669, 1048575, - 0xa66b, 1048575, - 0xa66d, 1048575, - 0xa681, 1048575, - 0xa683, 1048575, - 0xa685, 1048575, - 0xa687, 1048575, - 0xa689, 1048575, - 0xa68b, 1048575, - 0xa68d, 1048575, - 0xa68f, 1048575, - 0xa691, 1048575, - 0xa693, 1048575, - 0xa695, 1048575, - 0xa697, 1048575, - 0xa699, 1048575, - 0xa69b, 1048575, - 0xa723, 1048575, - 0xa725, 1048575, - 0xa727, 1048575, - 0xa729, 1048575, - 0xa72b, 1048575, - 0xa72d, 1048575, - 0xa72f, 1048575, - 0xa733, 1048575, - 0xa735, 1048575, - 0xa737, 1048575, - 0xa739, 1048575, - 0xa73b, 1048575, - 0xa73d, 1048575, - 0xa73f, 1048575, - 0xa741, 1048575, - 0xa743, 1048575, - 0xa745, 1048575, - 0xa747, 1048575, - 0xa749, 1048575, - 0xa74b, 1048575, - 0xa74d, 1048575, - 0xa74f, 1048575, - 0xa751, 1048575, - 0xa753, 1048575, - 0xa755, 1048575, - 0xa757, 1048575, - 0xa759, 1048575, - 0xa75b, 1048575, - 0xa75d, 1048575, - 0xa75f, 1048575, - 0xa761, 1048575, - 0xa763, 1048575, - 0xa765, 1048575, - 0xa767, 1048575, - 0xa769, 1048575, - 0xa76b, 1048575, - 0xa76d, 1048575, - 0xa76f, 1048575, - 0xa77a, 1048575, - 0xa77c, 1048575, - 0xa77f, 1048575, - 0xa781, 1048575, - 0xa783, 1048575, - 0xa785, 1048575, - 0xa787, 1048575, - 0xa78c, 1048575, - 0xa791, 1048575, - 0xa793, 1048575, - 0xa797, 1048575, - 0xa799, 1048575, - 0xa79b, 1048575, - 0xa79d, 1048575, - 0xa79f, 1048575, - 0xa7a1, 1048575, - 0xa7a3, 1048575, - 0xa7a5, 1048575, - 0xa7a7, 1048575, - 0xa7a9, 1048575, -}; - -} // !namespace - -char32_t toupper(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, toupperr, nelem (toupperr)/3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = rbsearch(c, touppers, nelem (touppers)/2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -namespace { - -const char32_t tolowerr[] = { - 0x0041, 0x005a, 1048608, - 0x00c0, 0x00d6, 1048608, - 0x00d8, 0x00de, 1048608, - 0x0189, 0x018a, 1048781, - 0x01b1, 0x01b2, 1048793, - 0x0388, 0x038a, 1048613, - 0x038e, 0x038f, 1048639, - 0x0391, 0x03a1, 1048608, - 0x03a3, 0x03ab, 1048608, - 0x03fd, 0x03ff, 1048446, - 0x0400, 0x040f, 1048656, - 0x0410, 0x042f, 1048608, - 0x0531, 0x0556, 1048624, - 0x10a0, 0x10c5, 1055840, - 0x1f08, 0x1f0f, 1048568, - 0x1f18, 0x1f1d, 1048568, - 0x1f28, 0x1f2f, 1048568, - 0x1f38, 0x1f3f, 1048568, - 0x1f48, 0x1f4d, 1048568, - 0x1f68, 0x1f6f, 1048568, - 0x1f88, 0x1f8f, 1048568, - 0x1f98, 0x1f9f, 1048568, - 0x1fa8, 0x1faf, 1048568, - 0x1fb8, 0x1fb9, 1048568, - 0x1fba, 0x1fbb, 1048502, - 0x1fc8, 0x1fcb, 1048490, - 0x1fd8, 0x1fd9, 1048568, - 0x1fda, 0x1fdb, 1048476, - 0x1fe8, 0x1fe9, 1048568, - 0x1fea, 0x1feb, 1048464, - 0x1ff8, 0x1ff9, 1048448, - 0x1ffa, 0x1ffb, 1048450, - 0x2160, 0x216f, 1048592, - 0x24b6, 0x24cf, 1048602, - 0x2c00, 0x2c2e, 1048624, - 0x2c7e, 0x2c7f, 1037761, - 0xff21, 0xff3a, 1048608, - 0x10400, 0x10427, 1048616, - 0x118a0, 0x118bf, 1048608, -}; - -} // !namespace - -namespace { - -const char32_t tolowers[] = { - 0x0100, 1048577, - 0x0102, 1048577, - 0x0104, 1048577, - 0x0106, 1048577, - 0x0108, 1048577, - 0x010a, 1048577, - 0x010c, 1048577, - 0x010e, 1048577, - 0x0110, 1048577, - 0x0112, 1048577, - 0x0114, 1048577, - 0x0116, 1048577, - 0x0118, 1048577, - 0x011a, 1048577, - 0x011c, 1048577, - 0x011e, 1048577, - 0x0120, 1048577, - 0x0122, 1048577, - 0x0124, 1048577, - 0x0126, 1048577, - 0x0128, 1048577, - 0x012a, 1048577, - 0x012c, 1048577, - 0x012e, 1048577, - 0x0130, 1048377, - 0x0132, 1048577, - 0x0134, 1048577, - 0x0136, 1048577, - 0x0139, 1048577, - 0x013b, 1048577, - 0x013d, 1048577, - 0x013f, 1048577, - 0x0141, 1048577, - 0x0143, 1048577, - 0x0145, 1048577, - 0x0147, 1048577, - 0x014a, 1048577, - 0x014c, 1048577, - 0x014e, 1048577, - 0x0150, 1048577, - 0x0152, 1048577, - 0x0154, 1048577, - 0x0156, 1048577, - 0x0158, 1048577, - 0x015a, 1048577, - 0x015c, 1048577, - 0x015e, 1048577, - 0x0160, 1048577, - 0x0162, 1048577, - 0x0164, 1048577, - 0x0166, 1048577, - 0x0168, 1048577, - 0x016a, 1048577, - 0x016c, 1048577, - 0x016e, 1048577, - 0x0170, 1048577, - 0x0172, 1048577, - 0x0174, 1048577, - 0x0176, 1048577, - 0x0178, 1048455, - 0x0179, 1048577, - 0x017b, 1048577, - 0x017d, 1048577, - 0x0181, 1048786, - 0x0182, 1048577, - 0x0184, 1048577, - 0x0186, 1048782, - 0x0187, 1048577, - 0x018b, 1048577, - 0x018e, 1048655, - 0x018f, 1048778, - 0x0190, 1048779, - 0x0191, 1048577, - 0x0193, 1048781, - 0x0194, 1048783, - 0x0196, 1048787, - 0x0197, 1048785, - 0x0198, 1048577, - 0x019c, 1048787, - 0x019d, 1048789, - 0x019f, 1048790, - 0x01a0, 1048577, - 0x01a2, 1048577, - 0x01a4, 1048577, - 0x01a6, 1048794, - 0x01a7, 1048577, - 0x01a9, 1048794, - 0x01ac, 1048577, - 0x01ae, 1048794, - 0x01af, 1048577, - 0x01b3, 1048577, - 0x01b5, 1048577, - 0x01b7, 1048795, - 0x01b8, 1048577, - 0x01bc, 1048577, - 0x01c4, 1048578, - 0x01c5, 1048577, - 0x01c7, 1048578, - 0x01c8, 1048577, - 0x01ca, 1048578, - 0x01cb, 1048577, - 0x01cd, 1048577, - 0x01cf, 1048577, - 0x01d1, 1048577, - 0x01d3, 1048577, - 0x01d5, 1048577, - 0x01d7, 1048577, - 0x01d9, 1048577, - 0x01db, 1048577, - 0x01de, 1048577, - 0x01e0, 1048577, - 0x01e2, 1048577, - 0x01e4, 1048577, - 0x01e6, 1048577, - 0x01e8, 1048577, - 0x01ea, 1048577, - 0x01ec, 1048577, - 0x01ee, 1048577, - 0x01f1, 1048578, - 0x01f2, 1048577, - 0x01f4, 1048577, - 0x01f6, 1048479, - 0x01f7, 1048520, - 0x01f8, 1048577, - 0x01fa, 1048577, - 0x01fc, 1048577, - 0x01fe, 1048577, - 0x0200, 1048577, - 0x0202, 1048577, - 0x0204, 1048577, - 0x0206, 1048577, - 0x0208, 1048577, - 0x020a, 1048577, - 0x020c, 1048577, - 0x020e, 1048577, - 0x0210, 1048577, - 0x0212, 1048577, - 0x0214, 1048577, - 0x0216, 1048577, - 0x0218, 1048577, - 0x021a, 1048577, - 0x021c, 1048577, - 0x021e, 1048577, - 0x0220, 1048446, - 0x0222, 1048577, - 0x0224, 1048577, - 0x0226, 1048577, - 0x0228, 1048577, - 0x022a, 1048577, - 0x022c, 1048577, - 0x022e, 1048577, - 0x0230, 1048577, - 0x0232, 1048577, - 0x023a, 1059371, - 0x023b, 1048577, - 0x023d, 1048413, - 0x023e, 1059368, - 0x0241, 1048577, - 0x0243, 1048381, - 0x0244, 1048645, - 0x0245, 1048647, - 0x0246, 1048577, - 0x0248, 1048577, - 0x024a, 1048577, - 0x024c, 1048577, - 0x024e, 1048577, - 0x0370, 1048577, - 0x0372, 1048577, - 0x0376, 1048577, - 0x037f, 1048692, - 0x0386, 1048614, - 0x038c, 1048640, - 0x03cf, 1048584, - 0x03d8, 1048577, - 0x03da, 1048577, - 0x03dc, 1048577, - 0x03de, 1048577, - 0x03e0, 1048577, - 0x03e2, 1048577, - 0x03e4, 1048577, - 0x03e6, 1048577, - 0x03e8, 1048577, - 0x03ea, 1048577, - 0x03ec, 1048577, - 0x03ee, 1048577, - 0x03f4, 1048516, - 0x03f7, 1048577, - 0x03f9, 1048569, - 0x03fa, 1048577, - 0x0460, 1048577, - 0x0462, 1048577, - 0x0464, 1048577, - 0x0466, 1048577, - 0x0468, 1048577, - 0x046a, 1048577, - 0x046c, 1048577, - 0x046e, 1048577, - 0x0470, 1048577, - 0x0472, 1048577, - 0x0474, 1048577, - 0x0476, 1048577, - 0x0478, 1048577, - 0x047a, 1048577, - 0x047c, 1048577, - 0x047e, 1048577, - 0x0480, 1048577, - 0x048a, 1048577, - 0x048c, 1048577, - 0x048e, 1048577, - 0x0490, 1048577, - 0x0492, 1048577, - 0x0494, 1048577, - 0x0496, 1048577, - 0x0498, 1048577, - 0x049a, 1048577, - 0x049c, 1048577, - 0x049e, 1048577, - 0x04a0, 1048577, - 0x04a2, 1048577, - 0x04a4, 1048577, - 0x04a6, 1048577, - 0x04a8, 1048577, - 0x04aa, 1048577, - 0x04ac, 1048577, - 0x04ae, 1048577, - 0x04b0, 1048577, - 0x04b2, 1048577, - 0x04b4, 1048577, - 0x04b6, 1048577, - 0x04b8, 1048577, - 0x04ba, 1048577, - 0x04bc, 1048577, - 0x04be, 1048577, - 0x04c0, 1048591, - 0x04c1, 1048577, - 0x04c3, 1048577, - 0x04c5, 1048577, - 0x04c7, 1048577, - 0x04c9, 1048577, - 0x04cb, 1048577, - 0x04cd, 1048577, - 0x04d0, 1048577, - 0x04d2, 1048577, - 0x04d4, 1048577, - 0x04d6, 1048577, - 0x04d8, 1048577, - 0x04da, 1048577, - 0x04dc, 1048577, - 0x04de, 1048577, - 0x04e0, 1048577, - 0x04e2, 1048577, - 0x04e4, 1048577, - 0x04e6, 1048577, - 0x04e8, 1048577, - 0x04ea, 1048577, - 0x04ec, 1048577, - 0x04ee, 1048577, - 0x04f0, 1048577, - 0x04f2, 1048577, - 0x04f4, 1048577, - 0x04f6, 1048577, - 0x04f8, 1048577, - 0x04fa, 1048577, - 0x04fc, 1048577, - 0x04fe, 1048577, - 0x0500, 1048577, - 0x0502, 1048577, - 0x0504, 1048577, - 0x0506, 1048577, - 0x0508, 1048577, - 0x050a, 1048577, - 0x050c, 1048577, - 0x050e, 1048577, - 0x0510, 1048577, - 0x0512, 1048577, - 0x0514, 1048577, - 0x0516, 1048577, - 0x0518, 1048577, - 0x051a, 1048577, - 0x051c, 1048577, - 0x051e, 1048577, - 0x0520, 1048577, - 0x0522, 1048577, - 0x0524, 1048577, - 0x0526, 1048577, - 0x0528, 1048577, - 0x052a, 1048577, - 0x052c, 1048577, - 0x052e, 1048577, - 0x10c7, 1055840, - 0x10cd, 1055840, - 0x1e00, 1048577, - 0x1e02, 1048577, - 0x1e04, 1048577, - 0x1e06, 1048577, - 0x1e08, 1048577, - 0x1e0a, 1048577, - 0x1e0c, 1048577, - 0x1e0e, 1048577, - 0x1e10, 1048577, - 0x1e12, 1048577, - 0x1e14, 1048577, - 0x1e16, 1048577, - 0x1e18, 1048577, - 0x1e1a, 1048577, - 0x1e1c, 1048577, - 0x1e1e, 1048577, - 0x1e20, 1048577, - 0x1e22, 1048577, - 0x1e24, 1048577, - 0x1e26, 1048577, - 0x1e28, 1048577, - 0x1e2a, 1048577, - 0x1e2c, 1048577, - 0x1e2e, 1048577, - 0x1e30, 1048577, - 0x1e32, 1048577, - 0x1e34, 1048577, - 0x1e36, 1048577, - 0x1e38, 1048577, - 0x1e3a, 1048577, - 0x1e3c, 1048577, - 0x1e3e, 1048577, - 0x1e40, 1048577, - 0x1e42, 1048577, - 0x1e44, 1048577, - 0x1e46, 1048577, - 0x1e48, 1048577, - 0x1e4a, 1048577, - 0x1e4c, 1048577, - 0x1e4e, 1048577, - 0x1e50, 1048577, - 0x1e52, 1048577, - 0x1e54, 1048577, - 0x1e56, 1048577, - 0x1e58, 1048577, - 0x1e5a, 1048577, - 0x1e5c, 1048577, - 0x1e5e, 1048577, - 0x1e60, 1048577, - 0x1e62, 1048577, - 0x1e64, 1048577, - 0x1e66, 1048577, - 0x1e68, 1048577, - 0x1e6a, 1048577, - 0x1e6c, 1048577, - 0x1e6e, 1048577, - 0x1e70, 1048577, - 0x1e72, 1048577, - 0x1e74, 1048577, - 0x1e76, 1048577, - 0x1e78, 1048577, - 0x1e7a, 1048577, - 0x1e7c, 1048577, - 0x1e7e, 1048577, - 0x1e80, 1048577, - 0x1e82, 1048577, - 0x1e84, 1048577, - 0x1e86, 1048577, - 0x1e88, 1048577, - 0x1e8a, 1048577, - 0x1e8c, 1048577, - 0x1e8e, 1048577, - 0x1e90, 1048577, - 0x1e92, 1048577, - 0x1e94, 1048577, - 0x1e9e, 1040961, - 0x1ea0, 1048577, - 0x1ea2, 1048577, - 0x1ea4, 1048577, - 0x1ea6, 1048577, - 0x1ea8, 1048577, - 0x1eaa, 1048577, - 0x1eac, 1048577, - 0x1eae, 1048577, - 0x1eb0, 1048577, - 0x1eb2, 1048577, - 0x1eb4, 1048577, - 0x1eb6, 1048577, - 0x1eb8, 1048577, - 0x1eba, 1048577, - 0x1ebc, 1048577, - 0x1ebe, 1048577, - 0x1ec0, 1048577, - 0x1ec2, 1048577, - 0x1ec4, 1048577, - 0x1ec6, 1048577, - 0x1ec8, 1048577, - 0x1eca, 1048577, - 0x1ecc, 1048577, - 0x1ece, 1048577, - 0x1ed0, 1048577, - 0x1ed2, 1048577, - 0x1ed4, 1048577, - 0x1ed6, 1048577, - 0x1ed8, 1048577, - 0x1eda, 1048577, - 0x1edc, 1048577, - 0x1ede, 1048577, - 0x1ee0, 1048577, - 0x1ee2, 1048577, - 0x1ee4, 1048577, - 0x1ee6, 1048577, - 0x1ee8, 1048577, - 0x1eea, 1048577, - 0x1eec, 1048577, - 0x1eee, 1048577, - 0x1ef0, 1048577, - 0x1ef2, 1048577, - 0x1ef4, 1048577, - 0x1ef6, 1048577, - 0x1ef8, 1048577, - 0x1efa, 1048577, - 0x1efc, 1048577, - 0x1efe, 1048577, - 0x1f59, 1048568, - 0x1f5b, 1048568, - 0x1f5d, 1048568, - 0x1f5f, 1048568, - 0x1fbc, 1048567, - 0x1fcc, 1048567, - 0x1fec, 1048569, - 0x1ffc, 1048567, - 0x2126, 1041059, - 0x212a, 1040193, - 0x212b, 1040314, - 0x2132, 1048604, - 0x2183, 1048577, - 0x2c60, 1048577, - 0x2c62, 1037833, - 0x2c63, 1044762, - 0x2c64, 1037849, - 0x2c67, 1048577, - 0x2c69, 1048577, - 0x2c6b, 1048577, - 0x2c6d, 1037796, - 0x2c6e, 1037827, - 0x2c6f, 1037793, - 0x2c70, 1037794, - 0x2c72, 1048577, - 0x2c75, 1048577, - 0x2c80, 1048577, - 0x2c82, 1048577, - 0x2c84, 1048577, - 0x2c86, 1048577, - 0x2c88, 1048577, - 0x2c8a, 1048577, - 0x2c8c, 1048577, - 0x2c8e, 1048577, - 0x2c90, 1048577, - 0x2c92, 1048577, - 0x2c94, 1048577, - 0x2c96, 1048577, - 0x2c98, 1048577, - 0x2c9a, 1048577, - 0x2c9c, 1048577, - 0x2c9e, 1048577, - 0x2ca0, 1048577, - 0x2ca2, 1048577, - 0x2ca4, 1048577, - 0x2ca6, 1048577, - 0x2ca8, 1048577, - 0x2caa, 1048577, - 0x2cac, 1048577, - 0x2cae, 1048577, - 0x2cb0, 1048577, - 0x2cb2, 1048577, - 0x2cb4, 1048577, - 0x2cb6, 1048577, - 0x2cb8, 1048577, - 0x2cba, 1048577, - 0x2cbc, 1048577, - 0x2cbe, 1048577, - 0x2cc0, 1048577, - 0x2cc2, 1048577, - 0x2cc4, 1048577, - 0x2cc6, 1048577, - 0x2cc8, 1048577, - 0x2cca, 1048577, - 0x2ccc, 1048577, - 0x2cce, 1048577, - 0x2cd0, 1048577, - 0x2cd2, 1048577, - 0x2cd4, 1048577, - 0x2cd6, 1048577, - 0x2cd8, 1048577, - 0x2cda, 1048577, - 0x2cdc, 1048577, - 0x2cde, 1048577, - 0x2ce0, 1048577, - 0x2ce2, 1048577, - 0x2ceb, 1048577, - 0x2ced, 1048577, - 0x2cf2, 1048577, - 0xa640, 1048577, - 0xa642, 1048577, - 0xa644, 1048577, - 0xa646, 1048577, - 0xa648, 1048577, - 0xa64a, 1048577, - 0xa64c, 1048577, - 0xa64e, 1048577, - 0xa650, 1048577, - 0xa652, 1048577, - 0xa654, 1048577, - 0xa656, 1048577, - 0xa658, 1048577, - 0xa65a, 1048577, - 0xa65c, 1048577, - 0xa65e, 1048577, - 0xa660, 1048577, - 0xa662, 1048577, - 0xa664, 1048577, - 0xa666, 1048577, - 0xa668, 1048577, - 0xa66a, 1048577, - 0xa66c, 1048577, - 0xa680, 1048577, - 0xa682, 1048577, - 0xa684, 1048577, - 0xa686, 1048577, - 0xa688, 1048577, - 0xa68a, 1048577, - 0xa68c, 1048577, - 0xa68e, 1048577, - 0xa690, 1048577, - 0xa692, 1048577, - 0xa694, 1048577, - 0xa696, 1048577, - 0xa698, 1048577, - 0xa69a, 1048577, - 0xa722, 1048577, - 0xa724, 1048577, - 0xa726, 1048577, - 0xa728, 1048577, - 0xa72a, 1048577, - 0xa72c, 1048577, - 0xa72e, 1048577, - 0xa732, 1048577, - 0xa734, 1048577, - 0xa736, 1048577, - 0xa738, 1048577, - 0xa73a, 1048577, - 0xa73c, 1048577, - 0xa73e, 1048577, - 0xa740, 1048577, - 0xa742, 1048577, - 0xa744, 1048577, - 0xa746, 1048577, - 0xa748, 1048577, - 0xa74a, 1048577, - 0xa74c, 1048577, - 0xa74e, 1048577, - 0xa750, 1048577, - 0xa752, 1048577, - 0xa754, 1048577, - 0xa756, 1048577, - 0xa758, 1048577, - 0xa75a, 1048577, - 0xa75c, 1048577, - 0xa75e, 1048577, - 0xa760, 1048577, - 0xa762, 1048577, - 0xa764, 1048577, - 0xa766, 1048577, - 0xa768, 1048577, - 0xa76a, 1048577, - 0xa76c, 1048577, - 0xa76e, 1048577, - 0xa779, 1048577, - 0xa77b, 1048577, - 0xa77d, 1013244, - 0xa77e, 1048577, - 0xa780, 1048577, - 0xa782, 1048577, - 0xa784, 1048577, - 0xa786, 1048577, - 0xa78b, 1048577, - 0xa78d, 1006296, - 0xa790, 1048577, - 0xa792, 1048577, - 0xa796, 1048577, - 0xa798, 1048577, - 0xa79a, 1048577, - 0xa79c, 1048577, - 0xa79e, 1048577, - 0xa7a0, 1048577, - 0xa7a2, 1048577, - 0xa7a4, 1048577, - 0xa7a6, 1048577, - 0xa7a8, 1048577, - 0xa7aa, 1006268, - 0xa7ab, 1006257, - 0xa7ac, 1006261, - 0xa7ad, 1006271, - 0xa7b0, 1006318, - 0xa7b1, 1006294, -}; - -} // !namespace - -char32_t tolower(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, tolowerr, nelem (tolowerr)/3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = rbsearch(c, tolowers, nelem (tolowers)/2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -namespace { - -const char32_t totitler[] = { - 0x0061, 0x007a, 1048544, - 0x00e0, 0x00f6, 1048544, - 0x00f8, 0x00fe, 1048544, - 0x023f, 0x0240, 1059391, - 0x0256, 0x0257, 1048371, - 0x028a, 0x028b, 1048359, - 0x037b, 0x037d, 1048706, - 0x03ad, 0x03af, 1048539, - 0x03b1, 0x03c1, 1048544, - 0x03c3, 0x03cb, 1048544, - 0x03cd, 0x03ce, 1048513, - 0x0430, 0x044f, 1048544, - 0x0450, 0x045f, 1048496, - 0x0561, 0x0586, 1048528, - 0x1f00, 0x1f07, 1048584, - 0x1f10, 0x1f15, 1048584, - 0x1f20, 0x1f27, 1048584, - 0x1f30, 0x1f37, 1048584, - 0x1f40, 0x1f45, 1048584, - 0x1f60, 0x1f67, 1048584, - 0x1f70, 0x1f71, 1048650, - 0x1f72, 0x1f75, 1048662, - 0x1f76, 0x1f77, 1048676, - 0x1f78, 0x1f79, 1048704, - 0x1f7a, 0x1f7b, 1048688, - 0x1f7c, 0x1f7d, 1048702, - 0x1f80, 0x1f87, 1048584, - 0x1f90, 0x1f97, 1048584, - 0x1fa0, 0x1fa7, 1048584, - 0x1fb0, 0x1fb1, 1048584, - 0x1fd0, 0x1fd1, 1048584, - 0x1fe0, 0x1fe1, 1048584, - 0x2170, 0x217f, 1048560, - 0x24d0, 0x24e9, 1048550, - 0x2c30, 0x2c5e, 1048528, - 0x2d00, 0x2d25, 1041312, - 0xff41, 0xff5a, 1048544, - 0x10428, 0x1044f, 1048536, - 0x118c0, 0x118df, 1048544, -}; - -} // !namespace - -namespace { - -const char32_t totitles[] = { - 0x00b5, 1049319, - 0x00ff, 1048697, - 0x0101, 1048575, - 0x0103, 1048575, - 0x0105, 1048575, - 0x0107, 1048575, - 0x0109, 1048575, - 0x010b, 1048575, - 0x010d, 1048575, - 0x010f, 1048575, - 0x0111, 1048575, - 0x0113, 1048575, - 0x0115, 1048575, - 0x0117, 1048575, - 0x0119, 1048575, - 0x011b, 1048575, - 0x011d, 1048575, - 0x011f, 1048575, - 0x0121, 1048575, - 0x0123, 1048575, - 0x0125, 1048575, - 0x0127, 1048575, - 0x0129, 1048575, - 0x012b, 1048575, - 0x012d, 1048575, - 0x012f, 1048575, - 0x0131, 1048344, - 0x0133, 1048575, - 0x0135, 1048575, - 0x0137, 1048575, - 0x013a, 1048575, - 0x013c, 1048575, - 0x013e, 1048575, - 0x0140, 1048575, - 0x0142, 1048575, - 0x0144, 1048575, - 0x0146, 1048575, - 0x0148, 1048575, - 0x014b, 1048575, - 0x014d, 1048575, - 0x014f, 1048575, - 0x0151, 1048575, - 0x0153, 1048575, - 0x0155, 1048575, - 0x0157, 1048575, - 0x0159, 1048575, - 0x015b, 1048575, - 0x015d, 1048575, - 0x015f, 1048575, - 0x0161, 1048575, - 0x0163, 1048575, - 0x0165, 1048575, - 0x0167, 1048575, - 0x0169, 1048575, - 0x016b, 1048575, - 0x016d, 1048575, - 0x016f, 1048575, - 0x0171, 1048575, - 0x0173, 1048575, - 0x0175, 1048575, - 0x0177, 1048575, - 0x017a, 1048575, - 0x017c, 1048575, - 0x017e, 1048575, - 0x017f, 1048276, - 0x0180, 1048771, - 0x0183, 1048575, - 0x0185, 1048575, - 0x0188, 1048575, - 0x018c, 1048575, - 0x0192, 1048575, - 0x0195, 1048673, - 0x0199, 1048575, - 0x019a, 1048739, - 0x019e, 1048706, - 0x01a1, 1048575, - 0x01a3, 1048575, - 0x01a5, 1048575, - 0x01a8, 1048575, - 0x01ad, 1048575, - 0x01b0, 1048575, - 0x01b4, 1048575, - 0x01b6, 1048575, - 0x01b9, 1048575, - 0x01bd, 1048575, - 0x01bf, 1048632, - 0x01c4, 1048577, - 0x01c6, 1048575, - 0x01c7, 1048577, - 0x01c9, 1048575, - 0x01ca, 1048577, - 0x01cc, 1048575, - 0x01ce, 1048575, - 0x01d0, 1048575, - 0x01d2, 1048575, - 0x01d4, 1048575, - 0x01d6, 1048575, - 0x01d8, 1048575, - 0x01da, 1048575, - 0x01dc, 1048575, - 0x01dd, 1048497, - 0x01df, 1048575, - 0x01e1, 1048575, - 0x01e3, 1048575, - 0x01e5, 1048575, - 0x01e7, 1048575, - 0x01e9, 1048575, - 0x01eb, 1048575, - 0x01ed, 1048575, - 0x01ef, 1048575, - 0x01f1, 1048577, - 0x01f3, 1048575, - 0x01f5, 1048575, - 0x01f9, 1048575, - 0x01fb, 1048575, - 0x01fd, 1048575, - 0x01ff, 1048575, - 0x0201, 1048575, - 0x0203, 1048575, - 0x0205, 1048575, - 0x0207, 1048575, - 0x0209, 1048575, - 0x020b, 1048575, - 0x020d, 1048575, - 0x020f, 1048575, - 0x0211, 1048575, - 0x0213, 1048575, - 0x0215, 1048575, - 0x0217, 1048575, - 0x0219, 1048575, - 0x021b, 1048575, - 0x021d, 1048575, - 0x021f, 1048575, - 0x0223, 1048575, - 0x0225, 1048575, - 0x0227, 1048575, - 0x0229, 1048575, - 0x022b, 1048575, - 0x022d, 1048575, - 0x022f, 1048575, - 0x0231, 1048575, - 0x0233, 1048575, - 0x023c, 1048575, - 0x0242, 1048575, - 0x0247, 1048575, - 0x0249, 1048575, - 0x024b, 1048575, - 0x024d, 1048575, - 0x024f, 1048575, - 0x0250, 1059359, - 0x0251, 1059356, - 0x0252, 1059358, - 0x0253, 1048366, - 0x0254, 1048370, - 0x0259, 1048374, - 0x025b, 1048373, - 0x025c, 1090895, - 0x0260, 1048371, - 0x0261, 1090891, - 0x0263, 1048369, - 0x0265, 1090856, - 0x0266, 1090884, - 0x0268, 1048367, - 0x0269, 1048365, - 0x026b, 1059319, - 0x026c, 1090881, - 0x026f, 1048365, - 0x0271, 1059325, - 0x0272, 1048363, - 0x0275, 1048362, - 0x027d, 1059303, - 0x0280, 1048358, - 0x0283, 1048358, - 0x0287, 1090858, - 0x0288, 1048358, - 0x0289, 1048507, - 0x028c, 1048505, - 0x0292, 1048357, - 0x029e, 1090834, - 0x0345, 1048660, - 0x0371, 1048575, - 0x0373, 1048575, - 0x0377, 1048575, - 0x03ac, 1048538, - 0x03c2, 1048545, - 0x03cc, 1048512, - 0x03d0, 1048514, - 0x03d1, 1048519, - 0x03d5, 1048529, - 0x03d6, 1048522, - 0x03d7, 1048568, - 0x03d9, 1048575, - 0x03db, 1048575, - 0x03dd, 1048575, - 0x03df, 1048575, - 0x03e1, 1048575, - 0x03e3, 1048575, - 0x03e5, 1048575, - 0x03e7, 1048575, - 0x03e9, 1048575, - 0x03eb, 1048575, - 0x03ed, 1048575, - 0x03ef, 1048575, - 0x03f0, 1048490, - 0x03f1, 1048496, - 0x03f2, 1048583, - 0x03f3, 1048460, - 0x03f5, 1048480, - 0x03f8, 1048575, - 0x03fb, 1048575, - 0x0461, 1048575, - 0x0463, 1048575, - 0x0465, 1048575, - 0x0467, 1048575, - 0x0469, 1048575, - 0x046b, 1048575, - 0x046d, 1048575, - 0x046f, 1048575, - 0x0471, 1048575, - 0x0473, 1048575, - 0x0475, 1048575, - 0x0477, 1048575, - 0x0479, 1048575, - 0x047b, 1048575, - 0x047d, 1048575, - 0x047f, 1048575, - 0x0481, 1048575, - 0x048b, 1048575, - 0x048d, 1048575, - 0x048f, 1048575, - 0x0491, 1048575, - 0x0493, 1048575, - 0x0495, 1048575, - 0x0497, 1048575, - 0x0499, 1048575, - 0x049b, 1048575, - 0x049d, 1048575, - 0x049f, 1048575, - 0x04a1, 1048575, - 0x04a3, 1048575, - 0x04a5, 1048575, - 0x04a7, 1048575, - 0x04a9, 1048575, - 0x04ab, 1048575, - 0x04ad, 1048575, - 0x04af, 1048575, - 0x04b1, 1048575, - 0x04b3, 1048575, - 0x04b5, 1048575, - 0x04b7, 1048575, - 0x04b9, 1048575, - 0x04bb, 1048575, - 0x04bd, 1048575, - 0x04bf, 1048575, - 0x04c2, 1048575, - 0x04c4, 1048575, - 0x04c6, 1048575, - 0x04c8, 1048575, - 0x04ca, 1048575, - 0x04cc, 1048575, - 0x04ce, 1048575, - 0x04cf, 1048561, - 0x04d1, 1048575, - 0x04d3, 1048575, - 0x04d5, 1048575, - 0x04d7, 1048575, - 0x04d9, 1048575, - 0x04db, 1048575, - 0x04dd, 1048575, - 0x04df, 1048575, - 0x04e1, 1048575, - 0x04e3, 1048575, - 0x04e5, 1048575, - 0x04e7, 1048575, - 0x04e9, 1048575, - 0x04eb, 1048575, - 0x04ed, 1048575, - 0x04ef, 1048575, - 0x04f1, 1048575, - 0x04f3, 1048575, - 0x04f5, 1048575, - 0x04f7, 1048575, - 0x04f9, 1048575, - 0x04fb, 1048575, - 0x04fd, 1048575, - 0x04ff, 1048575, - 0x0501, 1048575, - 0x0503, 1048575, - 0x0505, 1048575, - 0x0507, 1048575, - 0x0509, 1048575, - 0x050b, 1048575, - 0x050d, 1048575, - 0x050f, 1048575, - 0x0511, 1048575, - 0x0513, 1048575, - 0x0515, 1048575, - 0x0517, 1048575, - 0x0519, 1048575, - 0x051b, 1048575, - 0x051d, 1048575, - 0x051f, 1048575, - 0x0521, 1048575, - 0x0523, 1048575, - 0x0525, 1048575, - 0x0527, 1048575, - 0x0529, 1048575, - 0x052b, 1048575, - 0x052d, 1048575, - 0x052f, 1048575, - 0x1d79, 1083908, - 0x1d7d, 1052390, - 0x1e01, 1048575, - 0x1e03, 1048575, - 0x1e05, 1048575, - 0x1e07, 1048575, - 0x1e09, 1048575, - 0x1e0b, 1048575, - 0x1e0d, 1048575, - 0x1e0f, 1048575, - 0x1e11, 1048575, - 0x1e13, 1048575, - 0x1e15, 1048575, - 0x1e17, 1048575, - 0x1e19, 1048575, - 0x1e1b, 1048575, - 0x1e1d, 1048575, - 0x1e1f, 1048575, - 0x1e21, 1048575, - 0x1e23, 1048575, - 0x1e25, 1048575, - 0x1e27, 1048575, - 0x1e29, 1048575, - 0x1e2b, 1048575, - 0x1e2d, 1048575, - 0x1e2f, 1048575, - 0x1e31, 1048575, - 0x1e33, 1048575, - 0x1e35, 1048575, - 0x1e37, 1048575, - 0x1e39, 1048575, - 0x1e3b, 1048575, - 0x1e3d, 1048575, - 0x1e3f, 1048575, - 0x1e41, 1048575, - 0x1e43, 1048575, - 0x1e45, 1048575, - 0x1e47, 1048575, - 0x1e49, 1048575, - 0x1e4b, 1048575, - 0x1e4d, 1048575, - 0x1e4f, 1048575, - 0x1e51, 1048575, - 0x1e53, 1048575, - 0x1e55, 1048575, - 0x1e57, 1048575, - 0x1e59, 1048575, - 0x1e5b, 1048575, - 0x1e5d, 1048575, - 0x1e5f, 1048575, - 0x1e61, 1048575, - 0x1e63, 1048575, - 0x1e65, 1048575, - 0x1e67, 1048575, - 0x1e69, 1048575, - 0x1e6b, 1048575, - 0x1e6d, 1048575, - 0x1e6f, 1048575, - 0x1e71, 1048575, - 0x1e73, 1048575, - 0x1e75, 1048575, - 0x1e77, 1048575, - 0x1e79, 1048575, - 0x1e7b, 1048575, - 0x1e7d, 1048575, - 0x1e7f, 1048575, - 0x1e81, 1048575, - 0x1e83, 1048575, - 0x1e85, 1048575, - 0x1e87, 1048575, - 0x1e89, 1048575, - 0x1e8b, 1048575, - 0x1e8d, 1048575, - 0x1e8f, 1048575, - 0x1e91, 1048575, - 0x1e93, 1048575, - 0x1e95, 1048575, - 0x1e9b, 1048517, - 0x1ea1, 1048575, - 0x1ea3, 1048575, - 0x1ea5, 1048575, - 0x1ea7, 1048575, - 0x1ea9, 1048575, - 0x1eab, 1048575, - 0x1ead, 1048575, - 0x1eaf, 1048575, - 0x1eb1, 1048575, - 0x1eb3, 1048575, - 0x1eb5, 1048575, - 0x1eb7, 1048575, - 0x1eb9, 1048575, - 0x1ebb, 1048575, - 0x1ebd, 1048575, - 0x1ebf, 1048575, - 0x1ec1, 1048575, - 0x1ec3, 1048575, - 0x1ec5, 1048575, - 0x1ec7, 1048575, - 0x1ec9, 1048575, - 0x1ecb, 1048575, - 0x1ecd, 1048575, - 0x1ecf, 1048575, - 0x1ed1, 1048575, - 0x1ed3, 1048575, - 0x1ed5, 1048575, - 0x1ed7, 1048575, - 0x1ed9, 1048575, - 0x1edb, 1048575, - 0x1edd, 1048575, - 0x1edf, 1048575, - 0x1ee1, 1048575, - 0x1ee3, 1048575, - 0x1ee5, 1048575, - 0x1ee7, 1048575, - 0x1ee9, 1048575, - 0x1eeb, 1048575, - 0x1eed, 1048575, - 0x1eef, 1048575, - 0x1ef1, 1048575, - 0x1ef3, 1048575, - 0x1ef5, 1048575, - 0x1ef7, 1048575, - 0x1ef9, 1048575, - 0x1efb, 1048575, - 0x1efd, 1048575, - 0x1eff, 1048575, - 0x1f51, 1048584, - 0x1f53, 1048584, - 0x1f55, 1048584, - 0x1f57, 1048584, - 0x1fb3, 1048585, - 0x1fbe, 1041371, - 0x1fc3, 1048585, - 0x1fe5, 1048583, - 0x1ff3, 1048585, - 0x214e, 1048548, - 0x2184, 1048575, - 0x2c61, 1048575, - 0x2c65, 1037781, - 0x2c66, 1037784, - 0x2c68, 1048575, - 0x2c6a, 1048575, - 0x2c6c, 1048575, - 0x2c73, 1048575, - 0x2c76, 1048575, - 0x2c81, 1048575, - 0x2c83, 1048575, - 0x2c85, 1048575, - 0x2c87, 1048575, - 0x2c89, 1048575, - 0x2c8b, 1048575, - 0x2c8d, 1048575, - 0x2c8f, 1048575, - 0x2c91, 1048575, - 0x2c93, 1048575, - 0x2c95, 1048575, - 0x2c97, 1048575, - 0x2c99, 1048575, - 0x2c9b, 1048575, - 0x2c9d, 1048575, - 0x2c9f, 1048575, - 0x2ca1, 1048575, - 0x2ca3, 1048575, - 0x2ca5, 1048575, - 0x2ca7, 1048575, - 0x2ca9, 1048575, - 0x2cab, 1048575, - 0x2cad, 1048575, - 0x2caf, 1048575, - 0x2cb1, 1048575, - 0x2cb3, 1048575, - 0x2cb5, 1048575, - 0x2cb7, 1048575, - 0x2cb9, 1048575, - 0x2cbb, 1048575, - 0x2cbd, 1048575, - 0x2cbf, 1048575, - 0x2cc1, 1048575, - 0x2cc3, 1048575, - 0x2cc5, 1048575, - 0x2cc7, 1048575, - 0x2cc9, 1048575, - 0x2ccb, 1048575, - 0x2ccd, 1048575, - 0x2ccf, 1048575, - 0x2cd1, 1048575, - 0x2cd3, 1048575, - 0x2cd5, 1048575, - 0x2cd7, 1048575, - 0x2cd9, 1048575, - 0x2cdb, 1048575, - 0x2cdd, 1048575, - 0x2cdf, 1048575, - 0x2ce1, 1048575, - 0x2ce3, 1048575, - 0x2cec, 1048575, - 0x2cee, 1048575, - 0x2cf3, 1048575, - 0x2d27, 1041312, - 0x2d2d, 1041312, - 0xa641, 1048575, - 0xa643, 1048575, - 0xa645, 1048575, - 0xa647, 1048575, - 0xa649, 1048575, - 0xa64b, 1048575, - 0xa64d, 1048575, - 0xa64f, 1048575, - 0xa651, 1048575, - 0xa653, 1048575, - 0xa655, 1048575, - 0xa657, 1048575, - 0xa659, 1048575, - 0xa65b, 1048575, - 0xa65d, 1048575, - 0xa65f, 1048575, - 0xa661, 1048575, - 0xa663, 1048575, - 0xa665, 1048575, - 0xa667, 1048575, - 0xa669, 1048575, - 0xa66b, 1048575, - 0xa66d, 1048575, - 0xa681, 1048575, - 0xa683, 1048575, - 0xa685, 1048575, - 0xa687, 1048575, - 0xa689, 1048575, - 0xa68b, 1048575, - 0xa68d, 1048575, - 0xa68f, 1048575, - 0xa691, 1048575, - 0xa693, 1048575, - 0xa695, 1048575, - 0xa697, 1048575, - 0xa699, 1048575, - 0xa69b, 1048575, - 0xa723, 1048575, - 0xa725, 1048575, - 0xa727, 1048575, - 0xa729, 1048575, - 0xa72b, 1048575, - 0xa72d, 1048575, - 0xa72f, 1048575, - 0xa733, 1048575, - 0xa735, 1048575, - 0xa737, 1048575, - 0xa739, 1048575, - 0xa73b, 1048575, - 0xa73d, 1048575, - 0xa73f, 1048575, - 0xa741, 1048575, - 0xa743, 1048575, - 0xa745, 1048575, - 0xa747, 1048575, - 0xa749, 1048575, - 0xa74b, 1048575, - 0xa74d, 1048575, - 0xa74f, 1048575, - 0xa751, 1048575, - 0xa753, 1048575, - 0xa755, 1048575, - 0xa757, 1048575, - 0xa759, 1048575, - 0xa75b, 1048575, - 0xa75d, 1048575, - 0xa75f, 1048575, - 0xa761, 1048575, - 0xa763, 1048575, - 0xa765, 1048575, - 0xa767, 1048575, - 0xa769, 1048575, - 0xa76b, 1048575, - 0xa76d, 1048575, - 0xa76f, 1048575, - 0xa77a, 1048575, - 0xa77c, 1048575, - 0xa77f, 1048575, - 0xa781, 1048575, - 0xa783, 1048575, - 0xa785, 1048575, - 0xa787, 1048575, - 0xa78c, 1048575, - 0xa791, 1048575, - 0xa793, 1048575, - 0xa797, 1048575, - 0xa799, 1048575, - 0xa79b, 1048575, - 0xa79d, 1048575, - 0xa79f, 1048575, - 0xa7a1, 1048575, - 0xa7a3, 1048575, - 0xa7a5, 1048575, - 0xa7a7, 1048575, - 0xa7a9, 1048575, -}; - -} // !namespace - -char32_t totitle(char32_t c) noexcept -{ - const char32_t *p; - - p = rbsearch(c, totitler, nelem (totitler)/3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = rbsearch(c, totitles, nelem (totitles)/2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -void encode(char32_t c, char res[5]) noexcept -{ - switch (nbytesPoint(c)) { - case 1: - res[0] = static_cast(c); - res[1] = '\0'; - break; - case 2: - res[0] = 0xC0 | ((c >> 6) & 0x1F); - res[1] = 0x80 | (c & 0x3F); - res[2] = '\0'; - break; - case 3: - res[0] = 0xE0 | ((c >> 12) & 0xF ); - res[1] = 0x80 | ((c >> 6) & 0x3F); - res[2] = 0x80 | (c & 0x3F); - res[3] = '\0'; - break; - case 4: - res[0] = 0xF0 | ((c >> 18) & 0x7 ); - res[1] = 0x80 | ((c >> 12) & 0x3F); - res[2] = 0x80 | ((c >> 6) & 0x3F); - res[3] = 0x80 | (c & 0x3F); - res[4] = '\0'; - break; - default: - break; - } -} - -void decode(char32_t &c, const char *res) noexcept -{ - c = 0; - - switch (nbytesUtf8(res[0])) { - case 1: - c = res[0]; - break; - case 2: - c = (res[0] & 0x1f) << 6; - c |= (res[1] & 0x3f); - break; - case 3: - c = (res[0] & 0x0f) << 12; - c |= (res[1] & 0x3f) << 6; - c |= (res[2] & 0x3f); - break; - case 4: - c = (res[0] & 0x07) << 16; - c |= (res[1] & 0x3f) << 12; - c |= (res[2] & 0x3f) << 6; - c |= (res[3] & 0x3f); - default: - break; - } -} - -int nbytesUtf8(char c) noexcept -{ - if (static_cast(c) <= 127) - return 1; - if ((c & 0xE0) == 0xC0) - return 2; - if ((c & 0xF0) == 0xE0) - return 3; - if ((c & 0xF8) == 0xF0) - return 4; - - return -1; -} - -int nbytesPoint(char32_t c) noexcept -{ - if (c <= 0x7F) - return 1; - if (c <= 0x7FF) - return 2; - if (c <= 0xFFFF) - return 3; - if (c <= 0x1FFFFF) - return 4; - - return -1; -} - -unsigned length(const std::string &str) -{ - unsigned total = 0; - - forEach(str, [&] (char32_t) { - ++ total; - }); - - return total; -} - -std::string toUtf8(const std::u32string &array) -{ - std::string res; - - for (size_t i = 0; i < array.size(); ++i) { - char tmp[5]; - int size = nbytesPoint(array[i]); - - if (size < 0) - throw std::invalid_argument("invalid sequence"); - - encode(array[i], tmp); - res.insert(res.length(), tmp); - } - - return res; -} - -std::u32string toUtf32(const std::string &str) -{ - std::u32string res; - - forEach(str, [&] (char32_t code) { - res.push_back(code); - }); - - return res; -} - -} // !unicode - -} // !irccd diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-js/irccd/unicode.hpp --- a/libirccd-js/irccd/unicode.hpp Thu Nov 16 23:12:45 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,273 +0,0 @@ -/* - * unicode.hpp -- UTF-8 to UTF-32 conversions and various operations - * - * 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_UNICODE_HPP -#define IRCCD_UNICODE_HPP - -/** - * \file unicode.hpp - * \brief UTF-8 to UTF-32 conversions - * \author David Demelier - * \warning These files are auto-generated! - */ - -#include -#include - -namespace irccd { - -/** - * \brief Unicode namespace. - */ -namespace unicode { - -/** - * Encode the unicode code point into multibyte string. - * - * \param point the unicode code point - * \param res the output buffer - */ -void encode(char32_t point, char res[5]) noexcept; - -/** - * Decode the multibyte buffer into an unicode code point. - * - * \param c the code point destination - * \param res the multibyte string. - */ -void decode(char32_t &c, const char *res) noexcept; - -/** - * Get the number of bytes for the first multi byte character from a - * utf-8 string. - * - * This can be used to iterate a valid UTF-8 string to jump to the next - * real character. - * - * \param c the first multi byte character - * \return the number of bytes [1-4] or -1 if invalid - */ -int nbytesUtf8(char c) noexcept; - -/** - * Get the number of bytes for the unicode point. - * - * \param point the unicode point - * \return the number of bytes [1-4] or -1 if invalid - */ -int nbytesPoint(char32_t point) noexcept; - -/** - * Get real number of character in a string. - * - * \param str the string - * \return the length - * \throw std::invalid_argument on invalid sequence - */ -unsigned length(const std::string &str); - -/** - * Iterate over all real characters in the UTF-8 string. - * - * The function must have the following signature: - * void f(char ch) - * - * \param str the UTF-8 string - * \param function the function callback - * \throw std::invalid_argument on invalid sequence - */ -template -void forEach(const std::string &str, Func function) -{ - for (size_t i = 0; i < str.size(); ) { - char32_t point = 0; - int size = nbytesUtf8(str[i]); - - if (size < 0) - throw std::invalid_argument("invalid sequence"); - - decode(point, str.data() + i); - function(point); - - i += size; - } -} - -/** - * Convert a UTF-32 string to UTF-8 string. - * - * \param array the UTF-32 string - * \return the UTF-8 string - * \throw std::invalid_argument on invalid sequence - */ -std::string toUtf8(const std::u32string &array); - -/** - * Convert a UTF-8 string to UTF-32 string. - * - * \param str the UTF-8 string - * \return the UTF-32 string - * \throw std::invalid_argument on invalid sequence - */ -std::u32string toUtf32(const std::string &str); - -/** - * Check if the unicode character is space. - * - * \param c the character - * \return true if space - */ -bool isspace(char32_t c) noexcept; - -/** - * Check if the unicode character is digit. - * - * \param c the character - * \return true if digit - */ -bool isdigit(char32_t c) noexcept; - -/** - * Check if the unicode character is alpha category. - * - * \param c the character - * \return true if alpha - */ -bool isalpha(char32_t c) noexcept; - -/** - * Check if the unicode character is upper case. - * - * \param c the character - * \return true if upper case - */ -bool isupper(char32_t c) noexcept; - -/** - * Check if the unicode character is lower case. - * - * \param c the character - * \return true if lower case - */ -bool islower(char32_t c) noexcept; - -/** - * Check if the unicode character is title case. - * - * \param c the character - * \return true if title case - */ -bool istitle(char32_t c) noexcept; - -/** - * Convert to upper case. - * - * \param c the character - * \return the upper case character - */ -char32_t toupper(char32_t c) noexcept; - -/** - * Convert to lower case. - * - * \param c the character - * \return the lower case character - */ -char32_t tolower(char32_t c) noexcept; - -/** - * Convert to title case. - * - * \param c the character - * \return the title case character - */ -char32_t totitle(char32_t c) noexcept; - -/** - * Convert the UTF-32 string to upper case. - * - * \param str the str - * \return the upper case string - */ -inline std::u32string toupper(std::u32string str) -{ - for (size_t i = 0; i < str.size(); ++i) - str[i] = toupper(str[i]); - - return str; -} - -/** - * Convert the UTF-8 string to upper case. - * - * \param str the str - * \return the upper case string - * \warning very slow at the moment - */ -inline std::string toupper(const std::string &str) -{ - std::string result; - char buffer[5]; - - forEach(str, [&] (char32_t code) { - encode(toupper(code), buffer); - result += buffer; - }); - - return result; -} - -/** - * Convert the UTF-32 string to lower case. - * - * \param str the str - * \return the lower case string - */ -inline std::u32string tolower(std::u32string str) -{ - for (size_t i = 0; i < str.size(); ++i) - str[i] = tolower(str[i]); - - return str; -} - -/** - * Convert the UTF-8 string to lower case. - * - * \param str the str - * \return the lower case string - * \warning very slow at the moment - */ -inline std::string tolower(const std::string &str) -{ - std::string result; - char buffer[5]; - - forEach(str, [&] (char32_t code) { - encode(tolower(code), buffer); - result += buffer; - }); - - return result; -} - -} // !unicode - -} // !irccd - -#endif // !IRCCD_UNICODE_HPP diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-test/irccd/js_test.hpp --- a/libirccd-test/irccd/js_test.hpp Thu Nov 16 23:12:45 2017 +0100 +++ b/libirccd-test/irccd/js_test.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -25,8 +25,9 @@ */ #include -#include -#include + +#include +#include #include "journal_server.hpp" @@ -66,7 +67,7 @@ , server_(new journal_server("test")) { // Irccd is mandatory at the moment. - add(); + add(); add(); plugin_->open(); diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-test/irccd/plugin_test.cpp --- a/libirccd-test/irccd/plugin_test.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/libirccd-test/irccd/plugin_test.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -18,21 +18,22 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "plugin_test.hpp" namespace irccd { @@ -48,17 +49,17 @@ irccd_.plugins().add(plugin_); irccd_.servers().add(server_); - js_irccd_module().load(irccd_, plugin_); - js_directory_module().load(irccd_, plugin_); - js_elapsed_timer_module().load(irccd_, plugin_); - js_file_module().load(irccd_, plugin_); - js_logger_module().load(irccd_, plugin_); - js_plugin_module().load(irccd_, plugin_); - js_server_module().load(irccd_, plugin_); - js_system_module().load(irccd_, plugin_); - js_timer_module().load(irccd_, plugin_); - js_unicode_module().load(irccd_, plugin_); - js_util_module().load(irccd_, plugin_); + irccd_jsapi().load(irccd_, plugin_); + directory_jsapi().load(irccd_, plugin_); + elapsed_timer_jsapi().load(irccd_, plugin_); + file_jsapi().load(irccd_, plugin_); + logger_jsapi().load(irccd_, plugin_); + plugin_jsapi().load(irccd_, plugin_); + server_jsapi().load(irccd_, plugin_); + system_jsapi().load(irccd_, plugin_); + timer_jsapi().load(irccd_, plugin_); + unicode_jsapi().load(irccd_, plugin_); + util_jsapi().load(irccd_, plugin_); plugin_->open(); } diff -r 9daccaeedcce -r b3a0f61a35fe libirccd-test/irccd/plugin_test.hpp --- a/libirccd-test/irccd/plugin_test.hpp Thu Nov 16 23:12:45 2017 +0100 +++ b/libirccd-test/irccd/plugin_test.hpp Thu Nov 16 23:31:28 2017 +0100 @@ -24,8 +24,9 @@ * \brief test fixture helper for Javascript plugins. */ +#include + #include "irccd.hpp" -#include "js_plugin.hpp" #include "journal_server.hpp" namespace irccd { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-directory/main.cpp --- a/tests/js-directory/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-directory/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -19,17 +19,13 @@ #define BOOST_TEST_MODULE "Directory Javascript API" #include -#include +#include #include namespace irccd { -class directory_test : public js_test { -public: -}; - -BOOST_FIXTURE_TEST_SUITE(js_directory_suite, directory_test) +BOOST_FIXTURE_TEST_SUITE(directory_jsapi_suite, js_test) BOOST_AUTO_TEST_CASE(constructor) { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-elapsedtimer/main.cpp --- a/tests/js-elapsedtimer/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-elapsedtimer/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -21,7 +21,7 @@ #include -#include +#include #include @@ -29,7 +29,7 @@ namespace irccd { -BOOST_FIXTURE_TEST_SUITE(js_elapsed_timer_suite, js_test) +BOOST_FIXTURE_TEST_SUITE(elapsed_timer_jsapi_suite, js_test) BOOST_AUTO_TEST_CASE(standard) { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-file/main.cpp --- a/tests/js-file/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-file/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -21,13 +21,13 @@ #include -#include +#include #include namespace irccd { -BOOST_FIXTURE_TEST_SUITE(js_file_suite, js_test) +BOOST_FIXTURE_TEST_SUITE(file_jsapi_suite, js_test) BOOST_AUTO_TEST_CASE(function_basename) { @@ -55,7 +55,7 @@ if (duk_peval_string(plugin_->context(), "result = Irccd.File.exists(directory + '/file.txt')")) throw dukx_exception(plugin_->context(), -1); - + BOOST_TEST(duk_get_global_string(plugin_->context(), "result")); BOOST_TEST(duk_get_boolean(plugin_->context(), -1)); } @@ -64,7 +64,7 @@ { if (duk_peval_string(plugin_->context(), "result = Irccd.File.exists('file_which_does_not_exist.txt')")) throw dukx_exception(plugin_->context(), -1); - + BOOST_TEST(duk_get_global_string(plugin_->context(), "result")); BOOST_TEST(!duk_get_boolean(plugin_->context(), -1)); } diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-irccd/main.cpp --- a/tests/js-irccd/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-irccd/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -23,7 +23,7 @@ namespace irccd { -BOOST_FIXTURE_TEST_SUITE(js_irccd_suite, js_test) +BOOST_FIXTURE_TEST_SUITE(irccd_jsapi_suite, js_test) BOOST_AUTO_TEST_CASE(version) { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-logger/main.cpp --- a/tests/js-logger/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-logger/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -20,14 +20,15 @@ #include #include -#include -#include + +#include +#include #include namespace irccd { -class logger_test : public js_test { +class logger_test : public js_test { protected: std::string line_info; std::string line_warning; @@ -66,7 +67,7 @@ } }; -BOOST_FIXTURE_TEST_SUITE(js_logger_suite, logger_test) +BOOST_FIXTURE_TEST_SUITE(logger_jsapi_suite, logger_test) BOOST_AUTO_TEST_CASE(info) { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-plugin/main.cpp --- a/tests/js-plugin/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-plugin/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -21,9 +21,10 @@ #include #include -#include -#include -#include + +#include +#include +#include namespace irccd { @@ -36,8 +37,8 @@ { plugin_ = std::make_unique(std::move(name), std::move(path)); - js_irccd_module().load(irccd_, plugin_); - js_plugin_module().load(irccd_, plugin_); + irccd_jsapi().load(irccd_, plugin_); + plugin_jsapi().load(irccd_, plugin_); plugin_->open(); } @@ -103,8 +104,8 @@ auto loader = std::make_unique(irccd_); - loader->add_module(std::make_unique()); - loader->add_module(std::make_unique()); + loader->modules().push_back(std::make_unique()); + loader->modules().push_back(std::make_unique()); irccd_.plugins().add_loader(std::move(loader)); } diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-system/main.cpp --- a/tests/js-system/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-system/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -20,17 +20,18 @@ #include #include -#include -#include #include +#include +#include + #include namespace irccd { -using fixture = js_test; +using fixture = js_test; -BOOST_FIXTURE_TEST_SUITE(js_system_suite, fixture) +BOOST_FIXTURE_TEST_SUITE(system_jsapi_suite, fixture) BOOST_AUTO_TEST_CASE(home) { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-timer/main.cpp --- a/tests/js-timer/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-timer/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -20,20 +20,21 @@ #include #include -#include -#include #include +#include +#include + #include namespace irccd { -class fixture : public js_test { +class fixture : public js_test { public: using js_test::js_test; }; -BOOST_FIXTURE_TEST_SUITE(js_timer_suite, fixture) +BOOST_FIXTURE_TEST_SUITE(timer_jsapi_suite, fixture) BOOST_AUTO_TEST_CASE(single) { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-unicode/main.cpp --- a/tests/js-unicode/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-unicode/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -23,13 +23,13 @@ #define BOOST_TEST_MODULE "Unicode Javascript API" #include -#include +#include #include namespace irccd { -BOOST_FIXTURE_TEST_SUITE(js_unicode_suite, js_test) +BOOST_FIXTURE_TEST_SUITE(unicode_jsapi_suite, js_test) BOOST_AUTO_TEST_CASE(is_letter) { diff -r 9daccaeedcce -r b3a0f61a35fe tests/js-util/main.cpp --- a/tests/js-util/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js-util/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -19,13 +19,13 @@ #define BOOST_TEST_MODULE "Unicode Javascript API" #include -#include +#include #include namespace irccd { -BOOST_FIXTURE_TEST_SUITE(js_util_suite, js_test) +BOOST_FIXTURE_TEST_SUITE(util_jsapi_suite, js_test) /* * Irccd.Util misc. diff -r 9daccaeedcce -r b3a0f61a35fe tests/js/main.cpp --- a/tests/js/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/js/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -19,7 +19,7 @@ #define BOOST_TEST_MODULE "Javascript" #include -#include +#include #include #include diff -r 9daccaeedcce -r b3a0f61a35fe tests/timer/main.cpp --- a/tests/timer/main.cpp Thu Nov 16 23:12:45 2017 +0100 +++ b/tests/timer/main.cpp Thu Nov 16 23:31:28 2017 +0100 @@ -20,7 +20,7 @@ #include #include -#include +#include using namespace std::chrono_literals;