Mercurial > irccd
changeset 965:a518664b20a0
irccd: move javascript API from library to frontend
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 29 Jan 2021 15:03:23 +0100 |
parents | 0dd6afe7386d |
children | 8172399babb7 |
files | irccd/CMakeLists.txt irccd/dl-plugin.c irccd/dl-plugin.h irccd/js-plugin.c irccd/js-plugin.h irccd/jsapi-chrono.c irccd/jsapi-chrono.h irccd/jsapi-directory.c irccd/jsapi-directory.h irccd/jsapi-file.c irccd/jsapi-file.h irccd/jsapi-irccd.c irccd/jsapi-irccd.h irccd/jsapi-logger.c irccd/jsapi-logger.h irccd/jsapi-plugin.c irccd/jsapi-plugin.h irccd/jsapi-server.c irccd/jsapi-server.h irccd/jsapi-system.c irccd/jsapi-system.h irccd/jsapi-timer.c irccd/jsapi-timer.h irccd/jsapi-unicode.c irccd/jsapi-unicode.h irccd/jsapi-util.c irccd/jsapi-util.h irccd/main.c irccd/unicode.c irccd/unicode.h lib/CMakeLists.txt lib/irccd/dl-plugin.c lib/irccd/dl-plugin.h lib/irccd/js-plugin.c lib/irccd/js-plugin.h lib/irccd/jsapi-chrono.c lib/irccd/jsapi-chrono.h lib/irccd/jsapi-directory.c lib/irccd/jsapi-directory.h lib/irccd/jsapi-file.c lib/irccd/jsapi-file.h lib/irccd/jsapi-irccd.c lib/irccd/jsapi-irccd.h lib/irccd/jsapi-logger.c lib/irccd/jsapi-logger.h lib/irccd/jsapi-plugin.c lib/irccd/jsapi-plugin.h lib/irccd/jsapi-server.c lib/irccd/jsapi-server.h lib/irccd/jsapi-system.c lib/irccd/jsapi-system.h lib/irccd/jsapi-timer.c lib/irccd/jsapi-timer.h lib/irccd/jsapi-unicode.c lib/irccd/jsapi-unicode.h lib/irccd/jsapi-util.c lib/irccd/jsapi-util.h lib/irccd/plugin.c lib/irccd/unicode.c lib/irccd/unicode.h tests/CMakeLists.txt tests/test-jsapi-chrono.c tests/test-jsapi-directory.c tests/test-jsapi-file.c tests/test-jsapi-irccd.c tests/test-jsapi-system.c tests/test-jsapi-unicode.c tests/test-jsapi-util.c |
diffstat | 68 files changed, 9804 insertions(+), 9771 deletions(-) [+] |
line wrap: on
line diff
--- a/irccd/CMakeLists.txt Fri Jan 29 13:50:44 2021 +0100 +++ b/irccd/CMakeLists.txt Fri Jan 29 15:03:23 2021 +0100 @@ -17,5 +17,55 @@ # project(irccd) -add_executable(irccd main.c) -target_link_libraries(irccd libirccd) + +set( + SOURCES + ${irccd_SOURCE_DIR}/dl-plugin.c + ${irccd_SOURCE_DIR}/dl-plugin.h +) + +if (IRCCD_WITH_JS) + list( + APPEND SOURCES + ${irccd_SOURCE_DIR}/js-plugin.c + ${irccd_SOURCE_DIR}/js-plugin.h + ${irccd_SOURCE_DIR}/jsapi-chrono.c + ${irccd_SOURCE_DIR}/jsapi-chrono.h + ${irccd_SOURCE_DIR}/jsapi-directory.c + ${irccd_SOURCE_DIR}/jsapi-directory.h + ${irccd_SOURCE_DIR}/jsapi-file.c + ${irccd_SOURCE_DIR}/jsapi-file.h + ${irccd_SOURCE_DIR}/jsapi-irccd.c + ${irccd_SOURCE_DIR}/jsapi-irccd.h + ${irccd_SOURCE_DIR}/jsapi-logger.c + ${irccd_SOURCE_DIR}/jsapi-logger.h + ${irccd_SOURCE_DIR}/jsapi-plugin.c + ${irccd_SOURCE_DIR}/jsapi-plugin.h + ${irccd_SOURCE_DIR}/jsapi-server.c + ${irccd_SOURCE_DIR}/jsapi-server.h + ${irccd_SOURCE_DIR}/jsapi-system.c + ${irccd_SOURCE_DIR}/jsapi-system.h + ${irccd_SOURCE_DIR}/jsapi-timer.c + ${irccd_SOURCE_DIR}/jsapi-timer.h + ${irccd_SOURCE_DIR}/jsapi-unicode.c + ${irccd_SOURCE_DIR}/jsapi-unicode.h + ${irccd_SOURCE_DIR}/jsapi-util.c + ${irccd_SOURCE_DIR}/jsapi-util.h + ${irccd_SOURCE_DIR}/unicode.c + ${irccd_SOURCE_DIR}/unicode.h + ) +endif () + +# This is required for unit tests. +add_library(irccd-fe OBJECT ${SOURCES}) +target_link_libraries(irccd-fe libirccd) +target_include_directories(irccd-fe PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>) + +if (IRCCD_WITH_JS) + target_link_libraries(irccd-fe libirccd-duktape) +endif () + +add_executable(irccd ${irccd_SOURCE_DIR}/main.c) +target_link_libraries(irccd irccd-fe) + +source_group(TREE ${irccd_SOURCE_DIR} FILES ${SOURCES})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/dl-plugin.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,267 @@ +/* + * dl-plugin.c -- native C plugins for irccd + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <sys/stat.h> +#include <assert.h> +#include <ctype.h> +#include <dlfcn.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <config.h> + +#include <irccd/log.h> +#include <irccd/plugin.h> +#include <irccd/util.h> + +#include "dl-plugin.h" + +#define INVOKE(pg, name, sig, ...) \ +do { \ + struct self *self = pg->data; \ + sig fn; \ + \ + if (self->handle && (fn = dlsym(self->handle, symbol(self, name)))) \ + return fn(__VA_ARGS__); \ +} while (0) + +struct self { + struct irc_plugin plugin; + char prefix[32]; + void *handle; +}; + +typedef const char * (*get_option_fn)(const char *); +typedef const char * (*get_path_fn)(const char *); +typedef const char * (*get_template_fn)(const char *); +typedef const char ** (*get_options_fn)(void); +typedef const char ** (*get_paths_fn)(void); +typedef const char ** (*get_templates_fn)(void); +typedef void (*event_fn)(const struct irc_event *); +typedef void (*load_fn)(void); +typedef void (*reload_fn)(void); +typedef void (*unload_fn)(void); +typedef void (*set_option_fn)(const char *, const char *); +typedef void (*set_path_fn)(const char *, const char *); +typedef void (*set_template_fn)(const char *, const char *); + +static const char * +symbol(const struct self *self, const char *func) +{ + static char sym[128]; + + snprintf(sym, sizeof (sym), "%s_%s",self->prefix, func); + + return sym; +} + +static void +set_template(struct irc_plugin *plg, const char *key, const char *value) +{ + INVOKE(plg, "set_template", set_template_fn, key, value); +} + +static const char * +get_template(struct irc_plugin *plg, const char *key) +{ + INVOKE(plg, "get_template", get_template_fn, key); + + return NULL; +} + +static const char ** +get_templates(struct irc_plugin *plg) +{ + INVOKE(plg, "get_templates", get_templates_fn); + + return NULL; +} + +static void +set_path(struct irc_plugin *plg, const char *key, const char *value) +{ + INVOKE(plg, "set_path", set_path_fn, key, value); +} + +static const char * +get_path(struct irc_plugin *plg, const char *key) +{ + INVOKE(plg, "get_path", get_path_fn, key); + + return NULL; +} + +static const char ** +get_paths(struct irc_plugin *plg) +{ + INVOKE(plg, "get_paths", get_paths_fn); + + return NULL; +} + +static void +set_option(struct irc_plugin *plg, const char *key, const char *value) +{ + INVOKE(plg, "set_option", set_option_fn, key, value); +} + +static const char * +get_option(struct irc_plugin *plg, const char *key) +{ + INVOKE(plg, "get_option", get_option_fn, key); + + return NULL; +} + +static const char ** +get_options(struct irc_plugin *plg) +{ + INVOKE(plg, "get_options", get_options_fn); + + return NULL; +} + +static void +load(struct irc_plugin *plg) +{ + INVOKE(plg, "load", load_fn); +} + +static void +reload(struct irc_plugin *plg) +{ + INVOKE(plg, "reload", reload_fn); +} + +static void +unload(struct irc_plugin *plg) +{ + INVOKE(plg, "unload", unload_fn); +} + +static void +handle(struct irc_plugin *plg, const struct irc_event *ev) +{ + INVOKE(plg, "event", event_fn, ev); +} + +static void +finish(struct irc_plugin *plg) +{ + struct self *self = plg->data; + + if (self->handle) + dlclose(self->handle); + + free(self); + memset(self, 0, sizeof (*self)); +} + +static struct self * +init(const char *path) +{ + struct self self; + struct stat st; + + /* + * It's not possible to get the exact error code when loading a plugin + * using dlopen, since we're trying a lot of files that potentially not + * exist we check presence before even though there's a possible + * condition but at least we can print an error message if there are + * other errors than missing file. + */ + if (stat(path, &st) < 0 && errno == ENOENT) + return NULL; + + if (!(self.handle = dlopen(path, RTLD_NOW))) { + irc_log_warn("plugin: %s: %s", path, dlerror()); + return NULL; + } + + /* Compute prefix name */ + strlcpy(self.prefix, irc_util_basename(path), sizeof (self.prefix)); + + /* Remove plugin extension. */ + self.prefix[strcspn(self.prefix, ".")] = '\0'; + + /* Remove every invalid identifiers. */ + for (char *p = self.prefix; *p; ++p) + if (!isalnum(*p)) + *p = '_'; + + return irc_util_memdup(&self, sizeof (self)); +} + +static struct irc_plugin * +wrap_open(struct irc_plugin_loader *ldr, const char *path) +{ + (void)ldr; + + return dl_plugin_open(path); +} + +struct irc_plugin * +dl_plugin_open(const char *path) +{ + struct self *self; + + if (!(self = init(path))) + return false; + + /* Data and all callbacks. */ + self->plugin.data = self; + self->plugin.set_template = set_template; + self->plugin.get_template = get_template; + self->plugin.get_templates = get_templates; + self->plugin.set_path = set_path; + self->plugin.get_path = get_path; + self->plugin.get_paths = get_paths; + self->plugin.set_option = set_option; + self->plugin.get_option = get_option; + self->plugin.get_options = get_options; + self->plugin.load = load; + self->plugin.reload = reload; + self->plugin.unload = unload; + self->plugin.handle = handle; + self->plugin.finish = finish; + + return &self->plugin; +} + +struct irc_plugin_loader * +dl_plugin_loader_new(void) +{ + struct irc_plugin_loader *ldr; + + ldr = irc_util_calloc(1, sizeof (*ldr)); + ldr->open = wrap_open; + +#if defined(_WIN32) + strlcpy(ldr->extensions, "dll", sizeof (ldr->extensions)); +#elif defined(__APPLE__) + strlcpy(ldr->extensions, "so:dylib", sizeof (ldr->extensions)); +#else + strlcpy(ldr->extensions, "so", sizeof (ldr->extensions)); +#endif + + strlcpy(ldr->paths, IRCCD_LIBDIR "/irccd", sizeof (ldr->paths)); + + return ldr; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/dl-plugin.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,31 @@ +/* + * dl-plugin.c -- native C plugins for irccd + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_DL_PLUGIN_H +#define IRCCD_DL_PLUGIN_H + +struct irc_plugin; +struct irc_plugin_loader; + +struct irc_plugin * +dl_plugin_open(const char *); + +struct irc_plugin_loader * +dl_plugin_loader_new(void); + +#endif /* !IRCCD_DL_PLUGIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/js-plugin.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,584 @@ +/* + * jsapi-plugin.c -- Javascript plugins + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <sys/stat.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> + +#include <irccd/channel.h> +#include <irccd/event.h> +#include <irccd/log.h> +#include <irccd/plugin.h> +#include <irccd/server.h> +#include <irccd/util.h> + +#include "js-plugin.h" +#include "jsapi-chrono.h" +#include "jsapi-directory.h" +#include "jsapi-file.h" +#include "jsapi-irccd.h" +#include "jsapi-logger.h" +#include "jsapi-plugin.h" +#include "jsapi-plugin.h" +#include "jsapi-server.h" +#include "jsapi-system.h" +#include "jsapi-timer.h" +#include "jsapi-unicode.h" +#include "jsapi-util.h" + + +struct self { + struct irc_plugin plugin; + duk_context *ctx; + char **options; + char **templates; + char **paths; + char *license; + char *version; + char *author; + char *description; +}; + +static void +freelist(char **table) +{ + if (!table) + return; + + for (char **p = table; *p; ++p) + free(*p); + + free(table); +} + +static char * +metadata(duk_context *ctx, const char *name) +{ + char *ret = NULL; + + duk_get_global_string(ctx, "info"); + + if (duk_get_type(ctx, -1) == DUK_TYPE_OBJECT) { + duk_get_prop_string(ctx, -1, name); + + if (duk_get_type(ctx, -1) == DUK_TYPE_STRING) + ret = irc_util_strdup(duk_get_string(ctx, -1)); + + duk_pop(ctx); + } + + duk_pop(ctx); + + return ret ? ret : irc_util_strdup("unknown"); +} + +static void +push_names(duk_context *ctx, const struct irc_event *ev) +{ + const char *token; + char *p = ev->names.names; + + duk_push_array(ctx); + + for (size_t i = 0; (token = strtok_r(p, " ", &p)); ++i) { + irc_server_strip(ev->server, &token, NULL, NULL); + duk_push_string(ctx, token); + duk_put_prop_index(ctx, -2, i); + } +} + +static void +push_whois(duk_context *ctx, const struct irc_event *ev) +{ + const char *token; + char *p = ev->whois.channels; + + duk_push_object(ctx); + duk_push_string(ctx, ev->whois.nickname); + duk_put_prop_string(ctx, -2, "nickname"); + duk_push_string(ctx, ev->whois.username); + duk_put_prop_string(ctx, -2, "username"); + duk_push_string(ctx, ev->whois.realname); + duk_put_prop_string(ctx, -2, "realname"); + duk_push_string(ctx, ev->whois.hostname); + duk_put_prop_string(ctx, -2, "hostname"); + duk_push_array(ctx); + for (size_t i = 0; (token = strtok_r(p, " ", &p)); ++i) { + char mode = 0, prefix = 0; + + irc_server_strip(ev->server, &token, &mode, &prefix); + duk_push_object(ctx); + duk_push_string(ctx, token); + duk_put_prop_string(ctx, -2, "channel"); + duk_push_sprintf(ctx, "%c", mode); + duk_put_prop_string(ctx, -2, "mode"); + duk_push_sprintf(ctx, "%c", prefix); + duk_put_prop_string(ctx, -2, "prefix"); + duk_put_prop_index(ctx, -2, i); + } + duk_put_prop_string(ctx, -2, "channels"); +} + +static const char ** +get_table(duk_context *ctx, const char *name, char ***ptable) +{ + char **list; + size_t listsz; + + duk_get_global_string(ctx, name); + + if (!(listsz = duk_get_length(ctx, -1))) { + duk_pop(ctx); + return NULL; + } + + list = irc_util_calloc(listsz + 1, sizeof (char *)); + + duk_enum(ctx, -1, 0); + + for (size_t i = 0; i < listsz && duk_next(ctx, -1, true); ++i) { + list[i] = irc_util_strdup(duk_to_string(ctx, -2)); + duk_pop_n(ctx, 2); + } + + duk_pop_n(ctx, 2); + + freelist(*ptable); + *ptable = list; + + return (const char **)list; +} + +static void +set_key_value(duk_context *ctx, const char *table, const char *key, const char *value) +{ + duk_get_global_string(ctx, table); + duk_push_string(ctx, value); + duk_put_prop_string(ctx, -2, key); + duk_pop(ctx); +} + +static const char * +get_value(duk_context *ctx, const char *table, const char *key) +{ + const char *ret; + + duk_get_global_string(ctx, table); + duk_get_prop_string(ctx, -1, key); + ret = duk_to_string(ctx, -1); + duk_pop_n(ctx, 2); + + return ret; +} + +static void +set_template(struct irc_plugin *plg, const char *key, const char *value) +{ + struct self *js = plg->data; + + set_key_value(js->ctx, JSAPI_PLUGIN_PROP_TEMPLATES, key, value); +} + +static const char * +get_template(struct irc_plugin *plg, const char *key) +{ + struct self *js = plg->data; + + return get_value(js->ctx, JSAPI_PLUGIN_PROP_TEMPLATES, key); +} + +static const char ** +get_templates(struct irc_plugin *plg) +{ + struct self *js = plg->data; + + return get_table(js->ctx, JSAPI_PLUGIN_PROP_TEMPLATES, &js->templates); +} + +static void +set_path(struct irc_plugin *plg, const char *key, const char *value) +{ + struct self *js = plg->data; + + set_key_value(js->ctx, JSAPI_PLUGIN_PROP_PATHS, key, value); +} + +static const char * +get_path(struct irc_plugin *plg, const char *key) +{ + struct self *js = plg->data; + + return get_value(js->ctx, JSAPI_PLUGIN_PROP_PATHS, key); +} + +static const char ** +get_paths(struct irc_plugin *plg) +{ + struct self *js = plg->data; + + return get_table(js->ctx, JSAPI_PLUGIN_PROP_PATHS, &js->paths); +} + +static void +set_option(struct irc_plugin *plg, const char *key, const char *value) +{ + struct self *js = plg->data; + + set_key_value(js->ctx, JSAPI_PLUGIN_PROP_OPTIONS, key, value); +} + +static const char * +get_option(struct irc_plugin *plg, const char *key) +{ + struct self *js = plg->data; + + return get_value(js->ctx, JSAPI_PLUGIN_PROP_OPTIONS, key); +} + +static const char ** +get_options(struct irc_plugin *plg) +{ + struct self *js = plg->data; + + return get_table(js->ctx, JSAPI_PLUGIN_PROP_OPTIONS, &js->options); +} + +static void +vcall(struct irc_plugin *plg, const char *function, const char *fmt, va_list ap) +{ + struct self *self = plg->data; + int nargs = 0; + + duk_get_global_string(self->ctx, function); + + if (!duk_is_function(self->ctx, -1)) { + duk_pop(self->ctx); + return; + } + + for (const char *f = fmt; *f; ++f) { + void (*push)(duk_context *, void *); + + switch (*f) { + case 'S': + jsapi_server_push(self->ctx, va_arg(ap, struct irc_server *)); + break; + case 's': + duk_push_string(self->ctx, va_arg(ap, const char *)); + break; + case 'x': + push = va_arg(ap, void (*)(duk_context *, void *)); + push(self->ctx, va_arg(ap, void *)); + break; + default: + continue; + } + + ++nargs; + } + + if (duk_pcall(self->ctx, nargs) != 0) + irc_log_warn("plugin %s: %s\n", duk_to_string(self->ctx, -1)); + + duk_pop(self->ctx); +} + +static void +call(struct irc_plugin *plg, const char *function, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vcall(plg, function, fmt, ap); + va_end(ap); +} + +static void +handle(struct irc_plugin *plg, const struct irc_event *ev) +{ + (void)plg; + (void)ev; + + switch (ev->type) { + case IRC_EVENT_COMMAND: + call(plg, "onCommand", "Ss ss", ev->server, ev->message.origin, + ev->message.channel, ev->message.message); + break; + case IRC_EVENT_CONNECT: + call(plg, "onConnect", "S", ev->server); + break; + case IRC_EVENT_DISCONNECT: + call(plg, "onDisconnect", "S", ev->server); + break; + case IRC_EVENT_INVITE: + call(plg, "onInvite", "Ss s", ev->server, ev->invite.origin, + ev->invite.channel); + break; + case IRC_EVENT_JOIN: + call(plg, "onJoin", "Ss s", ev->server, ev->join.origin, + ev->join.channel); + break; + case IRC_EVENT_KICK: + call(plg, "onKick", "Ss sss", ev->server, ev->kick.origin, + ev->kick.channel, ev->kick.target, ev->kick.reason); + break; + case IRC_EVENT_ME: + call(plg, "onMe", "Ss ss", ev->server, ev->message.origin, + ev->message.channel, ev->message.message); + break; + case IRC_EVENT_MESSAGE: + call(plg, "onMessage", "Ss ss", ev->server, ev->message.origin, + ev->message.channel, ev->message.message); + break; + case IRC_EVENT_MODE: + call(plg, "onMode", "Ss sss ss", ev->server, ev->mode.origin, + ev->mode.channel, ev->mode.mode, ev->mode.limit, + ev->mode.user, ev->mode.mask); + break; + case IRC_EVENT_NAMES: + call(plg, "onNames", "Ss x", ev->server, ev->names.channel, + push_names, ev); + break; + case IRC_EVENT_NICK: + call(plg, "onNick", "Ss s", ev->server, ev->nick.origin, + ev->nick.nickname); + break; + case IRC_EVENT_NOTICE: + call(plg, "onNotice", "Ss ss", ev->server, ev->notice.origin, + ev->notice.channel, ev->notice.notice); + break; + case IRC_EVENT_PART: + call(plg, "onPart", "Ss ss", ev->server, ev->part.origin, + ev->part.channel, ev->part.reason); + break; + case IRC_EVENT_TOPIC: + call(plg, "onTopic", "Ss ss", ev->server, ev->topic.origin, + ev->topic.channel, ev->topic.topic); + break; + case IRC_EVENT_WHOIS: + call(plg, "onWhois", "Sx", ev->server, push_whois, ev); + break; + default: + break; + } +} + +static char * +eat(const char *path) +{ + int fd = -1; + char *ret = NULL; + struct stat st; + + if ((fd = open(path, O_RDONLY)) < 0) + goto err; + if (fstat(fd, &st) < 0) + goto err; + if (!(ret = calloc(1, st.st_size + 1))) + goto err; + if (read(fd, ret, st.st_size) != st.st_size) + goto err; + + close(fd); + + return ret; + +err: + if (fd != -1) + close(fd); + + free(ret); + + return false; +} + +static void * +wrap_malloc(void *udata, size_t size) +{ + (void)udata; + + return irc_util_malloc(size); +} + +static void * +wrap_realloc(void *udata, void *ptr, size_t size) +{ + (void)udata; + + return irc_util_realloc(ptr, size); +} + +static void +wrap_free(void *udata, void *ptr) +{ + (void)udata; + + free(ptr); +} + +static struct self * +init(const char *path, const char *script) +{ + struct self *js; + + js = irc_util_calloc(1, sizeof (*js)); + js->ctx = duk_create_heap(wrap_malloc, wrap_realloc, wrap_free, NULL, NULL); + + jsapi_load(js->ctx); + jsapi_chrono_load(js->ctx); + jsapi_directory_load(js->ctx); + jsapi_file_load(js->ctx); + jsapi_logger_load(js->ctx); + jsapi_plugin_load(js->ctx, &js->plugin); + jsapi_server_load(js->ctx); + jsapi_system_load(js->ctx); + jsapi_timer_load(js->ctx); + jsapi_unicode_load(js->ctx); + jsapi_util_load(js->ctx); + + if (duk_peval_string(js->ctx, script) != 0) { + irc_log_warn("plugin: %s: %s", path, duk_to_string(js->ctx, -1)); + duk_destroy_heap(js->ctx); + free(js); + return NULL; + } + + js->plugin.license = js->license = metadata(js->ctx, "license"); + js->plugin.version = js->version = metadata(js->ctx, "version"); + js->plugin.author = js->author = metadata(js->ctx, "author"); + js->plugin.description = js->description = metadata(js->ctx, "summary"); + + return js; +} + +static void +load(struct irc_plugin *plg) +{ + call(plg, "onLoad", ""); +} + +static void +reload(struct irc_plugin *plg) +{ + call(plg, "onReload", ""); +} + +static void +unload(struct irc_plugin *plg) +{ + call(plg, "onUnload", ""); +} + +static void +finish(struct irc_plugin *plg) +{ + struct self *self = plg->data; + + if (self->ctx) + duk_destroy_heap(self->ctx); + + freelist(self->options); + freelist(self->templates); + freelist(self->paths); + + free(self->license); + free(self->version); + free(self->author); + free(self->description); + free(self); +} + +static struct irc_plugin * +wrap_open(struct irc_plugin_loader *ldr, const char *path) +{ + (void)ldr; + + return js_plugin_open(path); +} + +duk_context * +js_plugin_get_context(struct irc_plugin *js) +{ + struct self *self = js->data; + + return self->ctx; +} + +struct irc_plugin * +js_plugin_open(const char *path) +{ + assert(path); + + char *script = NULL; + struct self *self; + + /* + * Duktape can't open script from file path so we need to read the + * whole script at once. + */ + if (!(script = eat(path))) { + if (errno != ENOENT) + irc_log_warn("irccd: %s: %s", path, strerror(errno)); + + return NULL; + } + + /* Init already log errors. */ + if (!(self = init(path, script))) { + free(script); + return NULL; + } + + self->plugin.data = self; + self->plugin.set_template = set_template; + self->plugin.get_template = get_template; + self->plugin.get_templates = get_templates; + self->plugin.set_path = set_path; + self->plugin.get_path = get_path; + self->plugin.get_paths = get_paths; + self->plugin.set_option = set_option; + self->plugin.get_option = get_option; + self->plugin.get_options = get_options; + self->plugin.load = load; + self->plugin.reload = reload; + self->plugin.unload = unload; + self->plugin.handle = handle; + self->plugin.finish = finish; + + /* No longer needed. */ + free(script); + + return &self->plugin; +} + +struct irc_plugin_loader * +js_plugin_loader_new(void) +{ + struct irc_plugin_loader *ldr; + + ldr = irc_util_calloc(1, sizeof (*ldr)); + ldr->open = wrap_open; + strlcpy(ldr->extensions, "js", sizeof (ldr->extensions)); + strlcpy(ldr->paths, IRCCD_LIBDIR "/irccd", sizeof (ldr->paths)); + + return ldr; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/js-plugin.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,35 @@ +/* + * js-plugin.h -- Javascript plugins + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_H +#define IRCCD_JS_PLUGIN_H + +#include <duktape.h> + +struct irc_plugin; + +duk_context * +js_plugin_get_context(struct irc_plugin *); + +struct irc_plugin * +js_plugin_open(const char *); + +struct irc_plugin_loader * +js_plugin_loader_new(void); + +#endif /* !IRCCD_JS_PLUGIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-chrono.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,120 @@ +/* + * jsapi-chrono.c -- Irccd.Chrono API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <stdbool.h> +#include <time.h> + +#include <duktape.h> + +#include <irccd/util.h> + +#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Chrono") + +struct timer { + struct timespec start; +}; + +static struct timer * +self(duk_context *ctx) +{ + struct timer *self; + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, SIGNATURE); + self = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!self) + (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Chrono object"); + + return self; +} + +static duk_ret_t +Chrono_prototype_elapsed(duk_context *ctx) +{ + struct timer *timer = self(ctx); + struct timespec now = {0}; + + timespec_get(&now, TIME_UTC); + + duk_push_uint(ctx, + ((now.tv_sec * 1000) - (timer->start.tv_sec * 1000)) + + ((now.tv_nsec / 1000000) - (timer->start.tv_nsec / 1000000))); + + return 1; +} + +static duk_ret_t +Chrono_prototype_reset(duk_context *ctx) +{ + timespec_get(&self(ctx)->start, TIME_UTC); + + return 0; +} + +static duk_ret_t +Chrono_constructor(duk_context *ctx) +{ + struct timer *timer; + + timer = irc_util_calloc(1, sizeof (*timer)); + timespec_get(&timer->start, TIME_UTC); + + duk_push_this(ctx); + duk_push_pointer(ctx, timer); + duk_put_prop_string(ctx, -2, SIGNATURE); + + /* this.elapsed property. */ + duk_push_string(ctx, "elapsed"); + duk_push_c_function(ctx, Chrono_prototype_elapsed, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_pop(ctx); + + return 0; +} + +static duk_ret_t +Chrono_destructor(duk_context *ctx) +{ + duk_get_prop_string(ctx, 0, SIGNATURE); + free(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, SIGNATURE); + + return 0; +} + +static const duk_function_list_entry methods[] = { + { "reset", Chrono_prototype_reset, 0 }, + { NULL, NULL, 0 } +}; + +void +jsapi_chrono_load(duk_context *ctx) +{ + duk_get_global_string(ctx, "Irccd"); + duk_push_c_function(ctx, Chrono_constructor, 0); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_push_c_function(ctx, Chrono_destructor, 1); + duk_set_finalizer(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Chrono"); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-chrono.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,27 @@ +/* + * jsapi-chrono.h -- Irccd.Chrono API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_CHRONO_H +#define IRCCD_JSAPI_CHRONO_H + +#include <duktape.h> + +void +jsapi_chrono_load(duk_context *); + +#endif /* !IRCCD_JSAPI_CHRONO_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-directory.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,425 @@ +/* + * jsapi-directory.c -- Irccd.Directory API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <sys/stat.h> +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <regex.h> +#include <stdbool.h> +#include <unistd.h> + +#if defined(_WIN32) +# include <windows.h> +#endif + +#include <duktape.h> + +#include "jsapi-system.h" + +enum { + LIST_DOT = (1 << 0), + LIST_DOT_DOT = (1 << 1) +}; + +struct cursor { + char path[PATH_MAX]; + char entry[FILENAME_MAX]; + bool recursive; + void *data; + bool (*fn)(const struct cursor *); +}; + +struct finder { + union { + const char *pattern; + regex_t regex; + }; + struct cursor curs; + void (*finish)(struct finder *); +}; + +static int +recursedir(int dirfd, struct cursor *cs) +{ + DIR *dp; + struct dirent *entry; + struct stat st; + size_t entrylen; + int childfd, ret = 0; + + if (!(dp = fdopendir(dirfd))) + return -1; + + while ((entry = readdir(dp))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + if (fstatat(dirfd, entry->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + continue; + + entrylen = strlen(entry->d_name); + + /* + * Append full path for the given entry. + * e.g. /foo/bar/ -> /foo/bar/quux.txt + */ + strlcat(cs->path, entry->d_name, sizeof (cs->path)); + + /* Go recursively if it's a directory and activated. */ + if (S_ISDIR(st.st_mode) && cs->recursive) { + strlcat(cs->path, "/", sizeof (cs->path)); + + entrylen += 1; + + if ((childfd = openat(dirfd, entry->d_name, O_RDONLY | O_DIRECTORY)) < 0) + continue; + if ((ret = recursedir(childfd, cs))) { + close(childfd); + goto stop; + } + + close(childfd); + } + + strlcpy(cs->entry, entry->d_name, sizeof (cs->entry)); + + if (cs->fn(cs)) { + ret = 1; + goto stop; + } + + cs->path[strlen(cs->path) - entrylen] = '\0'; + } +stop: + closedir(dp); + + return ret; +} + +static int +recurse(const char *path, struct cursor *cs) +{ + int fd, ret; + size_t pathlen; + + if ((fd = open(path, O_RDONLY | O_DIRECTORY)) < 0) + return -1; + + pathlen = strlen(path); + + if (strlcpy(cs->path, path, sizeof (cs->path)) >= sizeof (cs->path)) + return errno = ENOMEM, -1; + if (cs->path[pathlen - 1] != '/' && strlcat(cs->path, "/", sizeof (cs->path)) >= sizeof (cs->path)) + return errno = ENOMEM, -1; + + ret = recursedir(fd, cs); + close(fd); + + return ret; +} + +static inline const char * +path(duk_context *ctx) +{ + const char *ret; + + 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"); + + ret = duk_get_string(ctx, -1); + + if (!ret || !ret[0]) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path"); + + duk_pop_n(ctx, 2); + + return ret; +} + +static bool +find_regex(const struct cursor *curs) +{ + const struct finder *fd = curs->data; + + return regexec(&fd->regex, curs->entry, 0, NULL, 0) == 0; +} + +static bool +find_name(const struct cursor *curs) +{ + const struct finder *fd = curs->data; + + return strcmp(curs->entry, fd->pattern) == 0; +} + +static void +find_regex_finish(struct finder *fd) +{ + regfree(&fd->regex); +} + +static int +find_helper(duk_context *ctx, const char *base, bool recursive, int pattern_index) +{ + struct finder finder = { + .curs = { + .recursive = recursive, + .data = &finder, + } + }; + int status; + + if (duk_is_string(ctx, pattern_index)) { + finder.pattern = duk_get_string(ctx, pattern_index); + finder.curs.fn = find_name; + } else { + /* Check if it's a RegExp object. */ + duk_get_global_string(ctx, "RegExp"); + + if (!duk_instanceof(ctx, pattern_index, -1)) + /* TODO: better error. */ + return duk_error(ctx, DUK_ERR_TYPE_ERROR, "pattern arg error"); + + duk_get_prop_string(ctx, pattern_index, "source"); + + if (regcomp(&finder.regex, duk_to_string(ctx, -1), REG_EXTENDED) != 0) + return duk_error(ctx, DUK_ERR_ERROR, "RegExp error"); + + finder.curs.fn = find_regex; + finder.finish = find_regex_finish; + duk_pop_n(ctx, 2); + } + + status = recurse(base, &finder.curs); + + if (finder.finish) + finder.finish(&finder); + + if (status == 1) + duk_push_string(ctx, finder.curs.path); + else + duk_push_null(ctx); + + return 1; +} + +static bool +rm(const struct cursor *curs) +{ + return remove(curs->path), false; +} + +static int +rm_helper(duk_context *ctx, const char *base, bool recursive) +{ + struct stat st; + struct cursor curs = { + .recursive = true, + .fn = rm + }; + + if (stat(base, &st) < 0) + return jsapi_system_raise(ctx), 0; + else if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return jsapi_system_raise(ctx), 0; + } + + if (recursive) + recurse(base, &curs); + + remove(base); + + return 0; +} + +static inline void +mkpath(duk_context *ctx, const char *path) +{ +#ifdef _WIN32 + /* TODO: convert code to errno. */ + if (!CreateDirectoryA(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { + errno = EPERM; + jsapi_system_raise(ctx); +#else + if (mkdir(path, 0755) < 0 && errno != EEXIST) + jsapi_system_raise(ctx); +#endif +} + +static inline char * +normalize(char *str) +{ + for (char *p = str; *p; ++p) + if (*p == '\\') + *p = '/'; + + return str; +} + +static int +Directory_prototype_find(duk_context *ctx) +{ + return find_helper(ctx, path(ctx), duk_opt_boolean(ctx, 1, false), 0); +} + +static int +Directory_prototype_remove(duk_context *ctx) +{ + return rm_helper(ctx, path(ctx), duk_opt_boolean(ctx, 0, false)); +} + +static int +Directory_constructor(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + const int flags = duk_opt_int(ctx, 1, 0); + DIR *dp; + struct dirent *entry; + + if (!duk_is_constructor_call(ctx)) + return 0; + + duk_push_this(ctx); + + /* this.entries property. */ + duk_push_string(ctx, "entries"); + duk_push_array(ctx); + + if (!(dp = opendir(path))) + jsapi_system_raise(ctx); + + for (int i = 0; (entry = readdir(dp)); ) { + if (strcmp(entry->d_name, ".") == 0 && !(flags & LIST_DOT)) + continue; + if (strcmp(entry->d_name, "..") == 0 && !(flags & LIST_DOT_DOT)) + continue; + + duk_push_object(ctx); + duk_push_string(ctx, entry->d_name); + duk_put_prop_string(ctx, -2, "name"); + duk_push_int(ctx, entry->d_type); + duk_put_prop_string(ctx, -2, "type"); + duk_put_prop_index(ctx, -2, i++); + } + + closedir(dp); + duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); + + /* this.path property. */ + duk_push_string(ctx, "path"); + duk_push_string(ctx, path); + duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); + duk_pop(ctx); + + return 0; +} + +static duk_ret_t +Directory_find(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + bool recursive = duk_opt_boolean(ctx, 2, false); + + return find_helper(ctx, path, recursive, 1); +} + +static duk_ret_t +Directory_remove(duk_context* ctx) +{ + return rm_helper(ctx, duk_require_string(ctx, 0), duk_opt_boolean(ctx, 1, false)); +} + +static duk_ret_t +Directory_mkdir(duk_context* ctx) +{ + char path[PATH_MAX], *p; + + /* Copy the directory to normalize and iterate over '/'. */ + strlcpy(path, duk_require_string(ctx, 0), sizeof (path)); + normalize(path); + +#if defined(_WIN32) + /* Remove drive letter that we don't need. */ + if ((p = strchr(path, ':'))) + ++p; + else + p = path; +#else + p = path; +#endif + + for (p = p + 1; *p; ++p) { + if (*p == '/') { + *p = 0; + mkpath(ctx, path); + *p = '/'; + } + } + + mkpath(ctx, path); + + return 0; +} + +static const duk_function_list_entry methods[] = { + { "find", Directory_prototype_find, DUK_VARARGS }, + { "remove", Directory_prototype_remove, 1 }, + { NULL, NULL, 0 } +}; + +static const duk_function_list_entry functions[] = { + { "find", Directory_find, DUK_VARARGS }, + { "mkdir", Directory_mkdir, DUK_VARARGS }, + { "remove", Directory_remove, DUK_VARARGS }, + { NULL, NULL, 0 } +}; + +static const duk_number_list_entry constants[] = { + { "Dot", LIST_DOT }, + { "DotDot", LIST_DOT_DOT }, + { "TypeFile", DT_REG }, + { "TypeDir", DT_DIR }, + { "TypeLink", DT_LNK }, + { "TypeBlock", DT_BLK }, + { "TypeCharacter", DT_CHR }, + { "TypeFifo", DT_FIFO }, + { "TypeSocket", DT_SOCK }, + { "TypeUnknown", DT_UNKNOWN }, + { NULL, 0 } +}; + +void +jsapi_directory_load(duk_context *ctx) +{ + assert(ctx); + + duk_get_global_string(ctx, "Irccd"); + duk_push_c_function(ctx, Directory_constructor, 2); + duk_put_number_list(ctx, -1, constants); + duk_put_function_list(ctx, -1, functions); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Directory"); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-directory.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,27 @@ +/* + * jsapi-directory.h -- Irccd.Directory API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_DIRECTORY_H +#define IRCCD_JSAPI_DIRECTORY_H + +#include <duktape.h> + +void +jsapi_directory_load(duk_context *); + +#endif /* !IRCCD_JSAPI_DIRECTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-file.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,521 @@ +/* + * jsapi-file.c -- Irccd.File API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <compat.h> + +#include <sys/stat.h> +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> + +#include <duktape.h> + +#include <irccd/util.h> + +#include "jsapi-file.h" +#include "jsapi-system.h" + +#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.File") +#define PROTOTYPE DUK_HIDDEN_SYMBOL("Irccd.File.prototype") + +struct file { + char path[PATH_MAX]; + FILE *fp; + int (*finalizer)(FILE *); +}; + +static int +read_until_eof(duk_context *ctx, struct file *file) +{ + char *ret = NULL, *newret, buf[BUFSIZ]; + size_t retsz = 0, nread; + + /* + * This function is shared with popen which can not be used with stat + * so read the file by small piece of chunks and concat them until we + * reach the end. + */ + while ((nread = fread(buf, 1, sizeof (buf), file->fp)) > 0) { + if (!(newret = realloc(ret, retsz + nread))) { + free(ret); + jsapi_system_raise(ctx); + } + + ret = newret; + memcpy(ret + retsz, buf, nread); + retsz += nread; + } + + if (ferror(file->fp)) { + free(ret); + jsapi_system_raise(ctx); + } + + duk_push_lstring(ctx, ret, retsz); + free(ret); + + return 1; +} + +static int +read_amount(duk_context *ctx, struct file *file, unsigned int amount) +{ + char *ret; + size_t nread; + + if (!(ret = malloc(amount))) + jsapi_system_raise(ctx); + + if ((nread = fread(ret, 1, amount, file->fp)) <= 0 || ferror(file->fp)) { + free(ret); + jsapi_system_raise(ctx); + } + + duk_push_lstring(ctx, ret, nread); + free(ret); + + return 1; +} + +static void +push_stat(duk_context *ctx, const struct stat *st) +{ + duk_push_object(ctx); + +#if defined(COMPAT_HAVE_STAT_ST_ATIME) + duk_push_int(ctx, st->st_atime); + duk_put_prop_string(ctx, -2, "atime"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_BLKSIZE) + duk_push_int(ctx, st->st_blksize); + duk_put_prop_string(ctx, -2, "blksize"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_BLOCKS) + duk_push_int(ctx, st->st_blocks); + duk_put_prop_string(ctx, -2, "blocks"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_CTIME) + duk_push_int(ctx, st->st_ctime); + duk_put_prop_string(ctx, -2, "ctime"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_DEV) + duk_push_int(ctx, st->st_dev); + duk_put_prop_string(ctx, -2, "dev"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_GID) + duk_push_int(ctx, st->st_gid); + duk_put_prop_string(ctx, -2, "gid"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_INO) + duk_push_int(ctx, st->st_ino); + duk_put_prop_string(ctx, -2, "ino"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_MODE) + duk_push_int(ctx, st->st_mode); + duk_put_prop_string(ctx, -2, "mode"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_MTIME) + duk_push_int(ctx, st->st_mtime); + duk_put_prop_string(ctx, -2, "mtime"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_NLINK) + duk_push_int(ctx, st->st_nlink); + duk_put_prop_string(ctx, -2, "nlink"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_RDEV) + duk_push_int(ctx, st->st_rdev); + duk_put_prop_string(ctx, -2, "rdev"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_SIZE) + duk_push_int(ctx, st->st_size); + duk_put_prop_string(ctx, -2, "size"); +#endif +#if defined(COMPAT_HAVE_STAT_ST_UID) + duk_push_int(ctx, st->st_uid); + duk_put_prop_string(ctx, -2, "uid"); +#endif +} + +static struct file * +self(duk_context *ctx) +{ + struct file *file; + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, SIGNATURE); + file = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!file) + (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); + + return file; +} + +static duk_ret_t +File_prototype_basename(duk_context *ctx) +{ + const struct file *file = self(ctx); + + duk_push_string(ctx, irc_util_basename(file->path)); + + return 1; +} + +static duk_ret_t +File_prototype_close(duk_context *ctx) +{ + struct file *file = self(ctx); + + if (file->fp) { + file->finalizer(file->fp); + file->fp = NULL; + } + + return 0; +} + +static duk_ret_t +File_prototype_dirname(duk_context *ctx) +{ + const struct file *file = self(ctx); + + duk_push_string(ctx, irc_util_dirname(file->path)); + + return 1; +} + +static duk_ret_t +File_prototype_lines(duk_context *ctx) +{ + struct file *file = self(ctx); + char *line = NULL; + size_t linesz = 0; + + if (!file->fp) { + errno = EBADF; + jsapi_system_raise(ctx); + } + + duk_push_array(ctx); + + for (int i = 0; getline(&line, &linesz, file->fp) >= 0; ++i) { + line[strcspn(line, "\r\n")] = 0; + + duk_push_string(ctx, line); + duk_put_prop_index(ctx, -2, i); + } + + free(line); + + if (ferror(file->fp)) + jsapi_system_raise(ctx); + + return 1; +} + +static duk_ret_t +File_prototype_read(duk_context *ctx) +{ + struct file *file = self(ctx); + unsigned int amount = duk_opt_uint(ctx, 0, -1); + + if (!file->fp) { + errno = EBADF; + jsapi_system_raise(ctx); + } + + return amount == -1U + ? read_until_eof(ctx, file) + : read_amount(ctx, file, amount); +} + +static duk_ret_t +File_prototype_readline(duk_context *ctx) +{ + const struct file *file = self(ctx); + char *line = NULL; + size_t linesz = 0; + + if (!file->fp) { + errno = EBADF; + jsapi_system_raise(ctx); + } + + if (getline(&line, &linesz, file->fp) < 0) { + free(line); + + if (feof(file->fp)) + return 0; + + jsapi_system_raise(ctx); + } + + line[strcspn(line, "\r\n")] = 0; + duk_push_string(ctx, line); + free(line); + + return 1; +} + +static duk_ret_t +File_prototype_remove(duk_context *ctx) +{ + if (remove(self(ctx)->path) < 0) + jsapi_system_raise(ctx); + + return 0; +} + +static duk_ret_t +File_prototype_seek(duk_context *ctx) +{ + const struct file *file = self(ctx); + const int type = duk_require_int(ctx, 0); + const long offset = duk_require_int(ctx, 1); + + if (!file->fp || fseek(file->fp, offset, type) < 0) + jsapi_system_raise(ctx); + + return 0; +} + +static duk_ret_t +File_prototype_stat(duk_context *ctx) +{ + const struct file *file = self(ctx); + struct stat st; + + if (!file->fp || fstat(fileno(file->fp), &st) < 0) + jsapi_system_raise(ctx); + + push_stat(ctx, &st); + + return 0; +} + +static duk_ret_t +File_prototype_tell(duk_context *ctx) +{ + const struct file *file = self(ctx); + long position; + + if (!file->fp || (position = ftell(file->fp)) < 0) + return jsapi_system_raise(ctx), 0; + + duk_push_number(ctx, position); + + return 1; +} + +static duk_ret_t +File_prototype_write(duk_context *ctx) +{ + const struct file *file = self(ctx); + size_t datasz = 0, written; + const char *data = duk_require_lstring(ctx, 0, &datasz); + + if (!file->fp) + jsapi_system_raise(ctx); + + written = fwrite(data, 1, datasz, file->fp); + + if (ferror(file->fp)) + jsapi_system_raise(ctx); + + duk_push_uint(ctx, written); + + return 1; +} + +static duk_ret_t +File_constructor(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + const char *mode = duk_require_string(ctx, 1); + FILE *fp; + struct file *file; + + if (!duk_is_constructor_call(ctx)) + return 0; + + if (!(fp = fopen(path, mode))) + jsapi_system_raise(ctx); + + file = irc_util_calloc(1, sizeof (*file)); + file->fp = fp; + file->finalizer = fclose; + strlcpy(file->path, path, sizeof (file->path)); + + duk_push_this(ctx); + duk_push_pointer(ctx, file); + duk_put_prop_string(ctx, -2, SIGNATURE); + duk_pop(ctx); + + return 0; +} + +static duk_ret_t +File_destructor(duk_context *ctx) +{ + struct file *file; + + duk_get_prop_string(ctx, 0, SIGNATURE); + + if ((file = duk_to_pointer(ctx, -1)) && file->fp) { + file->finalizer(file->fp); + file->fp = NULL; + free(file); + } + + duk_pop(ctx); + duk_del_prop_string(ctx, 0, SIGNATURE); + + return 0; +} + +static duk_ret_t +File_basename(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + + duk_push_string(ctx, irc_util_basename(path)); + + return 1; +} + +static duk_ret_t +File_dirname(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + + duk_push_string(ctx, irc_util_dirname(path)); + + return 1; +} + +static duk_ret_t +File_exists(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + struct stat st; + + duk_push_boolean(ctx, stat(path, &st) == 0); + + return 1; +} + +static duk_ret_t +File_remove(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + + if (remove(path) < 0) + jsapi_system_raise(ctx); + + return 0; +} + +static duk_ret_t +File_stat(duk_context *ctx) +{ + const char *path = duk_require_string(ctx, 0); + struct stat st; + + if (stat(path, &st) < 0) + jsapi_system_raise(ctx); + + push_stat(ctx, &st); + + return 0; +} + +static const duk_function_list_entry methods[] = { + { "basename", File_prototype_basename, 0 }, + { "close", File_prototype_close, 0 }, + { "dirname", File_prototype_dirname, 0 }, + { "lines", File_prototype_lines, 0 }, + { "read", File_prototype_read, 1 }, + { "readline", File_prototype_readline, 0 }, + { "remove", File_prototype_remove, 0 }, + { "seek", File_prototype_seek, 2 }, + { "stat", File_prototype_stat, 0 }, + { "tell", File_prototype_tell, 0 }, + { "write", File_prototype_write, 1 }, + { NULL, NULL, 0 } +}; + +static const duk_function_list_entry functions[] = { + { "basename", File_basename, 1 }, + { "dirname", File_dirname, 1 }, + { "exists", File_exists, 1 }, + { "remove", File_remove, 1 }, + { "stat", File_stat, 1 }, + { NULL, NULL, 0 } +}; + +static const duk_number_list_entry constants[] = { + { "SeekCur", SEEK_CUR }, + { "SeekEnd", SEEK_END }, + { "SeekSet", SEEK_SET }, + { NULL, 0 } +}; + +void +jsapi_file_load(duk_context *ctx) +{ + assert(ctx); + + duk_get_global_string(ctx, "Irccd"); + duk_push_c_function(ctx, File_constructor, 2); + duk_put_number_list(ctx, -1, constants); + duk_put_function_list(ctx, -1, functions); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_push_c_function(ctx, File_destructor, 1); + duk_set_finalizer(ctx, -2); + duk_dup(ctx, -1); + duk_put_global_string(ctx, PROTOTYPE); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "File"); + duk_pop(ctx); +} + +void +jsapi_file_push(duk_context *ctx, const char *path, FILE *fp, int (*finalizer)(FILE *)) +{ + assert(ctx); + assert(fp); + assert(finalizer); + + struct file file = { + .fp = fp, + .finalizer = finalizer + }; + + if (path) + strlcpy(file.path, path, sizeof (file.path)); + + duk_push_object(ctx); + duk_push_pointer(ctx, irc_util_memdup(&file, sizeof (file))); + duk_put_prop_string(ctx, -2, SIGNATURE); + duk_get_global_string(ctx, PROTOTYPE); + duk_set_prototype(ctx, -2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-file.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,30 @@ +/* + * jsapi-file.h -- Irccd.File API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_FILE_H +#define IRCCD_JSAPI_FILE_H + +#include <duktape.h> + +void +jsapi_file_load(duk_context *); + +void +jsapi_file_push(duk_context *, const char *, FILE *, int (*)(FILE *)); + +#endif /* !IRCCD_JSAPI_FILE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-irccd.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,334 @@ +/* + * jsapi-irccd.c -- Irccd API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <errno.h> +#include <string.h> + +#include <duktape.h> + +#include <irccd/util.h> + +#include "config.h" + +static int +SystemError_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; +} + +/* {{{ Constants for errno. */ + +static const struct { + const char *name; + int value; +} errors[] = { +#if defined(E2BIG) + { "E2BIG", E2BIG }, +#endif +#if defined(EACCES) + { "EACCES", EACCES }, +#endif +#if defined(EADDRINUSE) + { "EADDRINUSE", EADDRINUSE }, +#endif +#if defined(EADDRNOTAVAIL) + { "EADDRNOTAVAIL", EADDRNOTAVAIL }, +#endif +#if defined(EAFNOSUPPORT) + { "EAFNOSUPPORT", EAFNOSUPPORT }, +#endif +#if defined(EAGAIN) + { "EAGAIN", EAGAIN }, +#endif +#if defined(EALREADY) + { "EALREADY", EALREADY }, +#endif +#if defined(EBADF) + { "EBADF", EBADF }, +#endif +#if defined(EBADMSG) + { "EBADMSG", EBADMSG }, +#endif +#if defined(EBUSY) + { "EBUSY", EBUSY }, +#endif +#if defined(ECANCELED) + { "ECANCELED", ECANCELED }, +#endif +#if defined(ECHILD) + { "ECHILD", ECHILD }, +#endif +#if defined(ECONNABORTED) + { "ECONNABORTED", ECONNABORTED }, +#endif +#if defined(ECONNREFUSED) + { "ECONNREFUSED", ECONNREFUSED }, +#endif +#if defined(ECONNREFUSED) + { "ECONNRESET", ECONNRESET }, +#endif +#if defined(EDEADLK) + { "EDEADLK", EDEADLK }, +#endif +#if defined(EDESTADDRREQ) + { "EDESTADDRREQ", EDESTADDRREQ }, +#endif +#if defined(EDOM) + { "EDOM", EDOM }, +#endif +#if defined(EEXIST) + { "EEXIST", EEXIST }, +#endif +#if defined(EFAULT) + { "EFAULT", EFAULT }, +#endif +#if defined(EFBIG) + { "EFBIG", EFBIG }, +#endif +#if defined(EHOSTUNREACH) + { "EHOSTUNREACH", EHOSTUNREACH }, +#endif +#if defined(EIDRM) + { "EIDRM", EIDRM }, +#endif +#if defined(EILSEQ) + { "EILSEQ", EILSEQ }, +#endif +#if defined(EINPROGRESS) + { "EINPROGRESS", EINPROGRESS }, +#endif +#if defined(EINTR) + { "EINTR", EINTR }, +#endif +#if defined(EINVAL) + { "EINVAL", EINVAL }, +#endif +#if defined(EIO) + { "EIO", EIO }, +#endif +#if defined(EISCONN) + { "EISCONN", EISCONN }, +#endif +#if defined(EISDIR) + { "EISDIR", EISDIR }, +#endif +#if defined(ELOOP) + { "ELOOP", ELOOP }, +#endif +#if defined(EMFILE) + { "EMFILE", EMFILE }, +#endif +#if defined(EMLINK) + { "EMLINK", EMLINK }, +#endif +#if defined(EMSGSIZE) + { "EMSGSIZE", EMSGSIZE }, +#endif +#if defined(ENAMETOOLONG) + { "ENAMETOOLONG", ENAMETOOLONG }, +#endif +#if defined(ENETDOWN) + { "ENETDOWN", ENETDOWN }, +#endif +#if defined(ENETRESET) + { "ENETRESET", ENETRESET }, +#endif +#if defined(ENETUNREACH) + { "ENETUNREACH", ENETUNREACH }, +#endif +#if defined(ENFILE) + { "ENFILE", ENFILE }, +#endif +#if defined(ENOBUFS) + { "ENOBUFS", ENOBUFS }, +#endif +#if defined(ENODATA) + { "ENODATA", ENODATA }, +#endif +#if defined(ENODEV) + { "ENODEV", ENODEV }, +#endif +#if defined(ENOENT) + { "ENOENT", ENOENT }, +#endif +#if defined(ENOEXEC) + { "ENOEXEC", ENOEXEC }, +#endif +#if defined(ENOLCK) + { "ENOLCK", ENOLCK }, +#endif +#if defined(ENOLINK) + { "ENOLINK", ENOLINK }, +#endif +#if defined(ENOMEM) + { "ENOMEM", ENOMEM }, +#endif +#if defined(ENOMSG) + { "ENOMSG", ENOMSG }, +#endif +#if defined(ENOPROTOOPT) + { "ENOPROTOOPT", ENOPROTOOPT }, +#endif +#if defined(ENOSPC) + { "ENOSPC", ENOSPC }, +#endif +#if defined(ENOSR) + { "ENOSR", ENOSR }, +#endif +#if defined(ENOSTR) + { "ENOSTR", ENOSTR }, +#endif +#if defined(ENOSYS) + { "ENOSYS", ENOSYS }, +#endif +#if defined(ENOTCONN) + { "ENOTCONN", ENOTCONN }, +#endif +#if defined(ENOTDIR) + { "ENOTDIR", ENOTDIR }, +#endif +#if defined(ENOTEMPTY) + { "ENOTEMPTY", ENOTEMPTY }, +#endif +#if defined(ENOTRECOVERABLE) + { "ENOTRECOVERABLE", ENOTRECOVERABLE }, +#endif +#if defined(ENOTSOCK) + { "ENOTSOCK", ENOTSOCK }, +#endif +#if defined(ENOTSUP) + { "ENOTSUP", ENOTSUP }, +#endif +#if defined(ENOTTY) + { "ENOTTY", ENOTTY }, +#endif +#if defined(ENXIO) + { "ENXIO", ENXIO }, +#endif +#if defined(EOPNOTSUPP) + { "EOPNOTSUPP", EOPNOTSUPP }, +#endif +#if defined(EOVERFLOW) + { "EOVERFLOW", EOVERFLOW }, +#endif +#if defined(EOWNERDEAD) + { "EOWNERDEAD", EOWNERDEAD }, +#endif +#if defined(EPERM) + { "EPERM", EPERM }, +#endif +#if defined(EPIPE) + { "EPIPE", EPIPE }, +#endif +#if defined(EPROTO) + { "EPROTO", EPROTO }, +#endif +#if defined(EPROTONOSUPPORT) + { "EPROTONOSUPPORT", EPROTONOSUPPORT }, +#endif +#if defined(EPROTOTYPE) + { "EPROTOTYPE", EPROTOTYPE }, +#endif +#if defined(ERANGE) + { "ERANGE", ERANGE }, +#endif +#if defined(EROFS) + { "EROFS", EROFS }, +#endif +#if defined(ESPIPE) + { "ESPIPE", ESPIPE }, +#endif +#if defined(ESRCH) + { "ESRCH", ESRCH }, +#endif +#if defined(ETIME) + { "ETIME", ETIME }, +#endif +#if defined(ETIMEDOUT) + { "ETIMEDOUT", ETIMEDOUT }, +#endif +#if defined(ETXTBSY) + { "ETXTBSY", ETXTBSY }, +#endif +#if defined(EWOULDBLOCK) + { "EWOULDBLOCK", EWOULDBLOCK }, +#endif +#if defined(EXDEV) + { "EXDEV", EXDEV } +#endif +}; + +/* }}} */ + +static int +print(duk_context *ctx) +{ + puts(duk_require_string(ctx, 0)); + + return 0; +} + +void +jsapi_load(duk_context *ctx) +{ + /* Irccd (global object) */ + duk_push_object(ctx); + + /* Irccd.version (property) */ + duk_push_object(ctx); + duk_push_int(ctx, IRCCD_VERSION_MAJOR); + duk_put_prop_string(ctx, -2, "major"); + duk_push_int(ctx, IRCCD_VERSION_MINOR); + duk_put_prop_string(ctx, -2, "minor"); + duk_push_int(ctx, IRCCD_VERSION_PATCH); + duk_put_prop_string(ctx, -2, "patch"); + duk_put_prop_string(ctx, -2, "version"); + + /* Create the system_error that inherits from Error. */ + duk_push_c_function(ctx, SystemError_constructor, 2); + + /* Put errno codes into the Irccd.SystemError object. */ + for (size_t i = 0; i < IRC_UTIL_SIZE(errors); ++i) { + duk_push_int(ctx, errors[i].value); + duk_put_prop_string(ctx, -2, errors[i].name); + } + + duk_push_object(ctx); + duk_get_global_string(ctx, "Error"); + duk_get_prop_string(ctx, -1, "prototype"); + duk_remove(ctx, -2); + duk_set_prototype(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "SystemError"); + + /* Set Irccd as global. */ + duk_put_global_string(ctx, "Irccd"); + + /* Convenient global "print" function. */ + duk_push_c_function(ctx, print, 1); + duk_put_global_string(ctx, "print"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-irccd.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,27 @@ +/* + * jsapi-irccd.h -- Irccd API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_IRCCD_H +#define IRCCD_JSAPI_IRCCD_H + +#include <duktape.h> + +void +jsapi_load(duk_context *); + +#endif /* !IRCCD_JSAPI_IRCCD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-logger.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,74 @@ +/* + * jsapi-logger.c -- Irccd.Logger API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <duktape.h> + +#include <irccd/plugin.h> +#include <irccd/log.h> + +#include "jsapi-logger.h" +#include "jsapi-plugin.h" + +#define LOG(c, f) \ +do { \ + const struct irc_plugin *p = jsapi_plugin_self(c); \ + const char *message = duk_require_string(c, 0); \ + \ + f("plugin %s: %s", p->name, message); \ +} while (0) \ + +static duk_ret_t +Logger_info(duk_context *ctx) +{ + LOG(ctx, irc_log_info); + + return 0; +} + +static duk_ret_t +Logger_warning(duk_context *ctx) +{ + LOG(ctx, irc_log_warn); + + return 0; +} + +static duk_ret_t +Logger_debug(duk_context *ctx) +{ + LOG(ctx, irc_log_debug); + + return 0; +} + +static const duk_function_list_entry functions[] = { + { "info", Logger_info, 1 }, + { "warning", Logger_warning, 1 }, + { "debug", Logger_debug, 1 }, + { NULL, NULL, 0 } +}; + +void +jsapi_logger_load(duk_context *ctx) +{ + duk_get_global_string(ctx, "Irccd"); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, functions); + duk_put_prop_string(ctx, -2, "Logger"); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-logger.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,27 @@ +/* + * jsapi-logger.h -- Irccd.Logger API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_LOGGER_H +#define IRCCD_JSAPI_LOGGER_H + +#include <duktape.h> + +void +jsapi_logger_load(duk_context *); + +#endif /* !IRCCD_JSAPI_LOGGER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-plugin.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,265 @@ +/* + * jsapi-plugin.c -- Irccd.Plugin API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <stdbool.h> + +#include <irccd/irccd.h> +#include <irccd/plugin.h> + +#include "jsapi-plugin.h" + +#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Plugin") + +/* + * set + * ------------------------------------------------------------------ + * + * This setter is used to replace the Irccd.Plugin.(config|templates|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 'templates' 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 sets: + * + * mode = "hard" + * path = "/var" + * + * The final user table looks like this: + * + * Irccd.Plugin.config = { + * mode: "hard", + * level: "123", + * path: "/var" + * }; + */ +static duk_ret_t +set(duk_context *ctx, const char *name) +{ + /* This is the object received in argument from the property setter. */ + if (!duk_is_object(ctx, 0)) + return duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name); + + /* Merge old table with new one. */ + duk_get_global_string(ctx, name); + 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); + + return 0; +} + +/* + * get + * ------------------------------------------------------------------ + * + * Get the Irccd.Plugin.(config|templates|paths) property. + */ +static duk_ret_t +get(duk_context *ctx, const char *name) +{ + duk_get_global_string(ctx, name); + + return 1; +} + +static duk_ret_t +set_config(duk_context *ctx) +{ + return set(ctx, JSAPI_PLUGIN_PROP_OPTIONS); +} + +static duk_ret_t +get_config(duk_context *ctx) +{ + return get(ctx, JSAPI_PLUGIN_PROP_OPTIONS); +} + +static duk_ret_t +set_template(duk_context *ctx) +{ + return set(ctx, JSAPI_PLUGIN_PROP_TEMPLATES); +} + +static duk_ret_t +get_template(duk_context *ctx) +{ + return get(ctx, JSAPI_PLUGIN_PROP_TEMPLATES); +} + +static duk_ret_t +set_paths(duk_context *ctx) +{ + return set(ctx, JSAPI_PLUGIN_PROP_PATHS); +} + +static duk_ret_t +get_paths(duk_context *ctx) +{ + return get(ctx, JSAPI_PLUGIN_PROP_PATHS); +} + +static struct irc_plugin * +find(duk_context *ctx) +{ + const char *name = duk_require_string(ctx, 0); + struct irc_plugin *plg = irc_bot_plugin_get(name); + + if (!plg) + (void)duk_error(ctx, DUK_ERR_REFERENCE_ERROR, "plugin %s not found", name); + + return plg; +} + +static duk_ret_t +Plugin_info(duk_context *ctx) +{ + struct irc_plugin *p; + + if (duk_get_top(ctx) >= 1) + p = find(ctx); + else + p = jsapi_plugin_self(ctx); + + if (!p) + return 0; + + duk_push_object(ctx); + duk_push_string(ctx, p->author); + duk_put_prop_string(ctx, -2, "author"); + duk_push_string(ctx, p->license); + duk_put_prop_string(ctx, -2, "license"); + duk_push_string(ctx, p->description); + duk_put_prop_string(ctx, -2, "summary"); + duk_push_string(ctx, p->version); + duk_put_prop_string(ctx, -2, "version"); + + return 1; +} + +static duk_ret_t +Plugin_list(duk_context *ctx) +{ + size_t i = 0; + struct irc_plugin *p; + + duk_push_array(ctx); + + LIST_FOREACH(p, &irc.plugins, link) { + duk_push_string(ctx, p->name); + duk_put_prop_index(ctx, -2, i++); + } + + return 1; +} + +static duk_ret_t +Plugin_load(duk_context *ctx) +{ + (void)ctx; + + return 0; +} + +static duk_ret_t +Plugin_reload(duk_context *ctx) +{ + irc_plugin_reload(find(ctx)); + + return 0; +} + +static duk_ret_t +Plugin_unload(duk_context *ctx) +{ + /* Use find so it can raise ReferenceError if not found. */ + irc_bot_plugin_remove(find(ctx)->name); + + return 0; +} + +static const duk_function_list_entry functions[] = { + { "info", Plugin_info, DUK_VARARGS }, + { "list", Plugin_list, 0 }, + { "load", Plugin_load, 1 }, + { "reload", Plugin_reload, 1 }, + { "unload", Plugin_unload, 1 }, + { NULL, NULL, 0 } +}; + +void +jsapi_plugin_load(duk_context *ctx, struct irc_plugin *p) +{ + /* Store plugin. */ + duk_push_pointer(ctx, p); + duk_put_global_string(ctx, SIGNATURE); + + duk_get_global_string(ctx, "Irccd"); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, functions); + + /* 'config' property. */ + duk_push_string(ctx, "config"); + duk_push_c_function(ctx, get_config, 0); + duk_push_c_function(ctx, set_config, 1); + duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + + /* 'templates' property. */ + duk_push_string(ctx, "templates"); + duk_push_c_function(ctx, get_template, 0); + duk_push_c_function(ctx, set_template, 1); + duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + + /* 'paths' property. */ + duk_push_string(ctx, "paths"); + duk_push_c_function(ctx, get_paths, 0); + duk_push_c_function(ctx, set_paths, 1); + duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + + duk_put_prop_string(ctx, -2, "Plugin"); + duk_pop(ctx); +} + +struct irc_plugin * +jsapi_plugin_self(duk_context *ctx) +{ + struct irc_plugin *p; + + duk_get_global_string(ctx, SIGNATURE); + p = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + return p; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-plugin.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,36 @@ +/* + * jsapi-plugin.h -- Javascript plugins + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_PLUGIN_H +#define IRCCD_JSAPI_PLUGIN_H + +#include <duktape.h> + +#define JSAPI_PLUGIN_PROP_OPTIONS DUK_HIDDEN_SYMBOL("options") +#define JSAPI_PLUGIN_PROP_TEMPLATES DUK_HIDDEN_SYMBOL("templates") +#define JSAPI_PLUGIN_PROP_PATHS DUK_HIDDEN_SYMBOL("paths") + +struct irc_plugin; + +void +jsapi_plugin_load(duk_context *, struct irc_plugin *); + +struct irc_plugin * +jsapi_plugin_self(duk_context *); + +#endif /* !IRCCD_JSAPI_PLUGIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-server.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,601 @@ +/* + * jsapi-server.c -- Irccd.Server API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <assert.h> + +#include <duktape.h> + +#include <irccd/channel.h> +#include <irccd/irccd.h> +#include <irccd/server.h> +#include <irccd/util.h> + +#include "jsapi-server.h" + +#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Server") +#define PROTOTYPE DUK_HIDDEN_SYMBOL("Irccd.Server.prototype") + +static struct irc_server * +self(duk_context *ctx) +{ + struct irc_server *sv; + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, SIGNATURE); + sv = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!sv) + (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); + + return sv; +} + +static struct irc_server * +require(duk_context *ctx, duk_idx_t index) +{ + struct irc_server *sv; + + if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, SIGNATURE)) + (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); + + duk_get_prop_string(ctx, index, SIGNATURE); + sv = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + return sv; +} + +static inline unsigned short +get_port(duk_context *ctx) +{ + unsigned short port; + + duk_get_prop_string(ctx, 0, "port"); + + if (!duk_is_number(ctx, -1)) + (void)duk_error(ctx, DUK_ERR_ERROR, "invalid 'port' property"); + + port = duk_to_int(ctx, -1); + duk_pop(ctx); + + return port; +} + +static inline const char * +get_string(duk_context *ctx, const char *n) +{ + const char *ret; + + duk_get_prop_string(ctx, 0, n); + + if (!duk_is_string(ctx, -1)) + (void)duk_error(ctx, DUK_ERR_ERROR, "invalid or missing '%s' property", n); + + ret = duk_to_string(ctx, -1); + duk_pop(ctx); + + return ret; +} + +static inline void +get_ip(duk_context *ctx, struct irc_server *s) +{ + enum irc_server_flags flags = IRC_SERVER_FLAGS_IPV4 | + IRC_SERVER_FLAGS_IPV6; + + duk_get_prop_string(ctx, 0, "ipv4"); + duk_get_prop_string(ctx, 0, "ipv6"); + + if (duk_is_boolean(ctx, -1) && !duk_to_boolean(ctx, -1)) + flags &= ~(IRC_SERVER_FLAGS_IPV4); + if (duk_is_boolean(ctx, -2) && !duk_to_boolean(ctx, -2)) + flags &= ~(IRC_SERVER_FLAGS_IPV6); + + s->flags |= flags; + duk_pop_n(ctx, 2); +} + +static inline void +get_ssl(duk_context *ctx, struct irc_server *s) +{ + duk_get_prop_string(ctx, 0, "ssl"); + + if (duk_is_boolean(ctx, -1) && duk_to_boolean(ctx, -1)) + s->flags |= IRC_SERVER_FLAGS_SSL; + + duk_pop(ctx); +} + +static inline void +get_channels(duk_context *ctx, struct irc_server *s) +{ + duk_get_prop_string(ctx, 0, "channels"); + + for (duk_enum(ctx, -1, 0); duk_next(ctx, -1, true); ) { + duk_get_prop_string(ctx, -1, "name"); + duk_get_prop_string(ctx, -2, "password"); + + if (!duk_is_string(ctx, -2)) + (void)duk_error(ctx, DUK_ERR_ERROR, "invalid channel 'name' property"); + + irc_server_join(s, duk_to_string(ctx, -2), duk_opt_string(ctx, -1, NULL)); + duk_pop_n(ctx, 4); + } + + duk_pop_n(ctx, 2); +} + +static duk_ret_t +Server_prototype_info(duk_context *ctx) +{ + const struct irc_server *s = self(ctx); + const struct irc_channel *c; + const struct irc_channel_user *u; + size_t ci = 0, ui = 0; + + duk_push_object(ctx); + duk_push_string(ctx, s->name); + duk_put_prop_string(ctx, -2, "name"); + duk_push_string(ctx, s->conn.hostname); + duk_put_prop_string(ctx, -2, "hostname"); + duk_push_uint(ctx, s->conn.port); + duk_put_prop_string(ctx, -2, "port"); + duk_push_boolean(ctx, s->flags & IRC_SERVER_FLAGS_SSL); + duk_put_prop_string(ctx, -2, "ssl"); + duk_push_string(ctx, s->commandchar); + duk_put_prop_string(ctx, -2, "commandChar"); + duk_push_string(ctx, s->ident.realname); + duk_put_prop_string(ctx, -2, "realname"); + duk_push_string(ctx, s->ident.nickname); + duk_put_prop_string(ctx, -2, "nickname"); + duk_push_string(ctx, s->ident.username); + duk_put_prop_string(ctx, -2, "username"); + + duk_push_array(ctx); + + LIST_FOREACH(c, &s->channels, link) { + duk_push_object(ctx); + duk_push_string(ctx, c->name); + duk_put_prop_string(ctx, -2, "name"); + duk_push_boolean(ctx, c->joined); + duk_put_prop_string(ctx, -2, "joined"); + duk_push_array(ctx); + + LIST_FOREACH(u, &c->users, link) { + duk_push_object(ctx); + duk_push_string(ctx, u->nickname); + duk_put_prop_string(ctx, -2, "nickname"); + if (u->mode) + duk_push_sprintf(ctx, "%c", u->mode); + else + duk_push_null(ctx); + duk_put_prop_string(ctx, -2, "mode"); + duk_put_prop_index(ctx, -2, ui++); + } + + duk_put_prop_string(ctx, -2, "users"); + duk_put_prop_index(ctx, -2, ci++); + } + + duk_put_prop_string(ctx, -2, "channels"); + + return 1; +} + +static duk_ret_t +Server_prototype_invite(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *target = duk_require_string(ctx, 0); + const char *channel = duk_require_string(ctx, 1); + +#if 0 + if (!*target || !*channel) + throw server_error(server_error::invalid_nickname); + if (channel.empty()) + throw server_error(server_error::invalid_channel); +#endif + + duk_push_boolean(ctx, irc_server_invite(s, target, channel)); + + return 1; +} + +static duk_ret_t +Server_prototype_isSelf(duk_context *ctx) +{ + (void)ctx; +#if 0 + return wrap(ctx, [] (auto ctx) { + return duk::push(ctx, self(ctx)->is_self(duk::require<std::string>(ctx, 0))); + }); +#endif + + return 0; +} + +static duk_ret_t +Server_prototype_join(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *channel = duk_require_string(ctx, 0); + const char *password = duk_opt_string(ctx, 1, NULL); + +#if 0 + if (channel.empty()) + throw server_error(server_error::invalid_channel); +#endif + + duk_push_boolean(ctx, irc_server_join(s, channel, password)); + + return 1; +} + +static duk_ret_t +Server_prototype_kick(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *target = duk_require_string(ctx, 0); + const char *channel = duk_require_string(ctx, 1); + const char *reason = duk_opt_string(ctx, 2, NULL); + +#if 0 + if (target.empty()) + throw server_error(server_error::invalid_nickname); + if (channel.empty()) + throw server_error(server_error::invalid_channel); +#endif + + duk_push_boolean(ctx, irc_server_kick(s, target, channel, reason)); + + return 1; +} + +static duk_ret_t +Server_prototype_me(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *target = duk_require_string(ctx, 0); + const char *message = duk_require_string(ctx, 1); + +#if 0 + if (target.empty()) + throw server_error(server_error::invalid_nickname); +#endif + + duk_push_boolean(ctx, irc_server_me(s, target, message)); + + return 1; +} + +static duk_ret_t +Server_prototype_message(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *target = duk_require_string(ctx, 0); + const char *message = duk_require_string(ctx, 1); + +#if 0 + if (target.empty()) + throw server_error(server_error::invalid_nickname); +#endif + + duk_push_boolean(ctx, irc_server_message(s, target, message)); + + return 1; +} + +static duk_ret_t +Server_prototype_mode(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *channel = duk_require_string(ctx, 0); + const char *mode = duk_require_string(ctx, 1); + const char *limit = duk_opt_string(ctx, 2, NULL); + const char *user = duk_opt_string(ctx, 3, NULL); + const char *mask = duk_opt_string(ctx, 4, NULL); + +#if 0 + if (channel.empty()) + throw server_error(server_error::invalid_channel); + if (mode.empty()) + throw server_error(server_error::invalid_mode); +#endif + + duk_push_boolean(ctx, irc_server_mode(s, channel, mode, limit, user, mask)); + + return 1; +} + +static duk_ret_t +Server_prototype_names(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *channel = duk_require_string(ctx, 0); + +#if 0 + if (channel.empty()) + throw server_error(server_error::invalid_channel); +#endif + + duk_push_boolean(ctx, irc_server_names(s, channel)); + + return 1; +} + +static duk_ret_t +Server_prototype_nick(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *nickname = duk_require_string(ctx, 0); + +#if 0 + if (nickname.empty()) + throw server_error(server_error::invalid_nickname); +#endif + + duk_push_boolean(ctx, irc_server_nick(s, nickname)); + + return 1; +} + +static duk_ret_t +Server_prototype_notice(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *target = duk_require_string(ctx, 0); + const char *message = duk_opt_string(ctx, 1, NULL); + +#if 0 + if (target.empty()) + throw server_error(server_error::invalid_nickname); +#endif + + duk_push_boolean(ctx, irc_server_notice(s, target, message)); + + return 1; +} + +static duk_ret_t +Server_prototype_part(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *channel = duk_require_string(ctx, 0); + const char *reason = duk_opt_string(ctx, 1, NULL); + +#if 0 + if (channel.empty()) + throw server_error(server_error::invalid_channel); +#endif + + duk_push_boolean(ctx, irc_server_part(s, channel, reason)); + + return 1; +} + +static duk_ret_t +Server_prototype_send(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *raw = duk_require_string(ctx, 0); + +#if 0 + if (raw.empty()) + throw server_error(server_error::invalid_message); +#endif + + duk_push_boolean(ctx, irc_server_send(s, raw)); + + return 1; +} + +static duk_ret_t +Server_prototype_topic(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *channel = duk_require_string(ctx, 0); + const char *topic = duk_require_string(ctx, 1); + +#if 0 + if (channel.empty()) + throw server_error(server_error::invalid_channel); +#endif + + duk_push_boolean(ctx, irc_server_topic(s, channel, topic)); + + return 1; +} + +static duk_ret_t +Server_prototype_whois(duk_context *ctx) +{ + struct irc_server *s = self(ctx); + const char *target = duk_require_string(ctx, 0); + +#if 0 + if (target.empty()) + throw server_error(server_error::invalid_nickname); +#endif + + duk_push_boolean(ctx, irc_server_whois(s, target)); + + return 1; +} + +static duk_ret_t +Server_prototype_toString(duk_context *ctx) +{ + duk_push_string(ctx, self(ctx)->name); + + return 1; +} + +static duk_ret_t +Server_constructor(duk_context *ctx) +{ + struct irc_server *s; + + duk_require_object(ctx, 0); + + s = irc_server_new( + get_string(ctx, "name"), + get_string(ctx, "nickname"), + get_string(ctx, "username"), + get_string(ctx, "realname"), + get_string(ctx, "hostname"), + get_port(ctx) + ); + + get_ip(ctx, s); + get_ssl(ctx, s); + get_channels(ctx, s); + + irc_server_incref(s); + + duk_push_this(ctx); + duk_push_pointer(ctx, s); + duk_put_prop_string(ctx, -2, SIGNATURE); + duk_pop(ctx); + + return 0; +} + +static duk_ret_t +Server_destructor(duk_context *ctx) +{ + struct irc_server *sv; + + duk_get_prop_string(ctx, 0, SIGNATURE); + + if ((sv = duk_to_pointer(ctx, -1))) + irc_server_decref(sv); + + duk_pop(ctx); + duk_del_prop_string(ctx, 0, SIGNATURE); + + return 0; +} + +static duk_ret_t +Server_add(duk_context *ctx) +{ + irc_bot_server_add(require(ctx, 0)); + + return 0; +} + +static duk_ret_t +Server_find(duk_context *ctx) +{ + const char *name = duk_require_string(ctx, 0); + struct irc_server *s = irc_bot_server_find(name); + + if (!s) + return 0; + + jsapi_server_push(ctx, s); + + return 1; +} + +static duk_ret_t +Server_list(duk_context *ctx) +{ + struct irc_server *s; + + duk_push_object(ctx); + + LIST_FOREACH(s, &irc.servers, link) { + jsapi_server_push(ctx, s); + duk_put_prop_string(ctx, -2, s->name); + } + + return 1; +} + +static duk_ret_t +Server_remove(duk_context *ctx) +{ + irc_bot_server_remove(duk_require_string(ctx, 0)); + + return 0; +} + +static const duk_function_list_entry methods[] = { + { "info", Server_prototype_info, 0 }, + { "invite", Server_prototype_invite, 2 }, + { "isSelf", Server_prototype_isSelf, 1 }, + { "join", Server_prototype_join, DUK_VARARGS }, + { "kick", Server_prototype_kick, DUK_VARARGS }, + { "me", Server_prototype_me, 2 }, + { "message", Server_prototype_message, 2 }, + { "mode", Server_prototype_mode, 1 }, + { "names", Server_prototype_names, 1 }, + { "nick", Server_prototype_nick, 1 }, + { "notice", Server_prototype_notice, 2 }, + { "part", Server_prototype_part, DUK_VARARGS }, + { "send", Server_prototype_send, 1 }, + { "topic", Server_prototype_topic, 2 }, + { "toString", Server_prototype_toString, 0 }, + { "whois", Server_prototype_whois, 1 }, + { NULL, NULL, 0 } +}; + +static const duk_function_list_entry functions[] = { + { "add", Server_add, 1 }, + { "find", Server_find, 1 }, + { "list", Server_list, 0 }, + { "remove", Server_remove, 1 }, + { NULL, NULL, 0 } +}; + +void +jsapi_server_load(duk_context *ctx) +{ + assert(ctx); + + duk_get_global_string(ctx, "Irccd"); + + duk_push_c_function(ctx, Server_constructor, 1); + duk_put_function_list(ctx, -1, functions); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_push_c_function(ctx, Server_destructor, 1); + duk_set_finalizer(ctx, -2); + duk_dup_top(ctx); + duk_put_global_string(ctx, PROTOTYPE); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Server"); + duk_pop(ctx); +} + +void +jsapi_server_push(duk_context *ctx, struct irc_server *s) +{ + assert(ctx); + assert(s); + + irc_server_incref(s); + + duk_push_object(ctx); + duk_push_pointer(ctx, s); + duk_put_prop_string(ctx, -2, SIGNATURE); + duk_get_global_string(ctx, PROTOTYPE); + duk_set_prototype(ctx, -2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-server.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,32 @@ +/* + * jsapi-server.c -- Irccd.Server API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_SERVER_H +#define IRCCD_JSAPI_SERVER_H + +#include <duktape.h> + +struct irc_server; + +void +jsapi_server_push(duk_context *, struct irc_server *); + +void +jsapi_server_load(duk_context *); + +#endif /* IRCCD_JSAPI_SERVER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-system.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,250 @@ +/* + * jsapi-system.c -- Irccd.System API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#if defined(_WIN32) +# include <windows.h> +#elif defined(__linux__) +# include <sys/sysinfo.h> +#elif defined(__APPLE__) +# include <sys/types.h> +# include <sys/sysctl.h> +#endif + +#if !defined(_WIN32) +# include <sys/utsname.h> +#endif + +#include <duktape.h> + +#include "jsapi-file.h" +#include "jsapi-system.h" + +static duk_ret_t +nsleep(unsigned long ns) +{ + struct timespec ts = { + .tv_sec = ns / 1000000000L, + .tv_nsec = (ns % 1000000000L), + }; + + while (nanosleep(&ts, &ts) && errno == EINTR); + + return 0; +} + +static duk_ret_t +System_env(duk_context *ctx) +{ + const char *name = duk_require_string(ctx, 0); + const char *value = getenv(name); + + if (!value) + duk_push_null(ctx); + else + duk_push_string(ctx, value); + + return 1; +} + +static duk_ret_t +System_exec(duk_context *ctx) +{ + duk_push_uint(ctx, system(duk_require_string(ctx, 0))); + + return 1; +} + +static duk_ret_t +System_home(duk_context *ctx) +{ +#if defined(_WIN32) + char path[MAX_PATH] = {0}; + + SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path); + + duk_push_string(ctx, path); +#else + const char *home; + + if ((home = getenv("HOME"))) + duk_push_string(ctx, home); + else + duk_push_undefined(ctx); +#endif + + return 1; +} + +static duk_ret_t +System_name(duk_context *ctx) +{ +#if defined(__linux__) + duk_push_string(ctx, "Linux"); +#elif defined(_WIN32) + duk_push_string(ctx, "Windows"); +#elif defined(__FreeBSD__) + duk_push_string(ctx, "FreeBSD"); +#elif defined(__DragonFly__) + duk_push_string(ctx, "DragonFlyBSD"); +#elif defined(__OpenBSD__) + duk_push_string(ctx, "OpenBSD"); +#elif defined(__NetBSD__) + duk_push_string(ctx, "NetBSD"); +#elif defined(__APPLE__) + duk_push_string(ctx, "macOS"); +#elif defined(__ANDROID__) + duk_push_string(ctx, "Android"); +#elif defined(_AIX) + duk_push_string(ctx, "Aix"); +#elif defined(__HAIKU__) + duk_push_string(ctx, "Haiku"); +#elif defined(sun) + duk_push_string(ctx, "Solaris"); +#else + duk_push_string(ctx, "Unknown"); +#endif + + return 1; +} + +static duk_ret_t +System_popen(duk_context *ctx) +{ + const char *cmd = duk_require_string(ctx, 0); + const char *mode = duk_require_string(ctx, 1); + FILE *fp; + + if (!(fp = popen(cmd, mode))) + jsapi_system_raise(ctx); + + jsapi_file_push(ctx, NULL, fp, pclose); + + return 1; +} + +static duk_ret_t +System_sleep(duk_context *ctx) +{ + return nsleep(duk_require_uint(ctx, 0) * 1000000000L); +} + +static duk_ret_t +System_usleep(duk_context *ctx) +{ + return nsleep(duk_require_uint(ctx, 0) * 1000); +} + +static duk_ret_t +System_uptime(duk_context *ctx) +{ +#if defined(_WIN32) + duk_push_uint(ctx, GetTickCount64() / 1000); +#elif defined(__linux__) + struct sysinfo info; + + if (sysinfo(&info) < 0) + irc_jsapi_system_raise(ctx); + + duk_push_uint(ctx, info.uptime); +#elif defined(__APPLE__) + struct timeval boottime; + size_t length = sizeof (boottime); + int mib[2] = { CTL_KERN, KERN_BOOTTIME }; + time_t bsec, csec; + + if (sysctl(mib, 2, &boottime, &length, NULL, 0) < 0) + jsapi_system_raise(ctx); + + bsec = boottime.tv_sec; + csec = time(NULL); + + duk_push_uint(ctx, difftime(csec, bsec)); +#else + struct timespec ts; + + /* Mostly POSIX compliant (CLOCK_UPTIME isn't POSIX though). */ + if (clock_gettime(CLOCK_UPTIME, &ts) < 0) + irc_jsapi_system_raise(ctx); + + duk_push_uint(ctx, ts.tv_sec); +#endif + + return 1; +} + +static duk_ret_t +System_version(duk_context *ctx) +{ +#if defined(_WIN32) + DWORD version = GetVersion(); + DWORD major = (DWORD)(LOBYTE(LOWORD(version))); + DWORD minor = (DWORD)(HIBYTE(LOWORD(version))); + + duk_push_sprintf(ctx, "%d.%d", (int)major, (int)minor); +#else + struct utsname uts; + + if (uname(&uts) < 0) + jsapi_system_raise(ctx); + + duk_push_string(ctx, uts.release); +#endif + return 1; +} + +static const duk_function_list_entry functions[] = { + { "env", System_env, 1 }, + { "exec", System_exec, 1 }, + { "home", System_home, 0 }, + { "name", System_name, 0 }, + { "popen", System_popen, 2 }, + { "sleep", System_sleep, 1 }, + { "uptime", System_uptime, 0 }, + { "usleep", System_usleep, 1 }, + { "version", System_version, 0 }, + { NULL, NULL, 0 } +}; + +void +jsapi_system_raise(duk_context *ctx) +{ + duk_get_global_string(ctx, "Irccd"); + duk_get_prop_string(ctx, -1, "SystemError"); + duk_remove(ctx, -2); + duk_push_int(ctx, errno); + duk_push_string(ctx, strerror(errno)); + duk_new(ctx, 2); + + (void)duk_throw(ctx); +} + +void +jsapi_system_load(duk_context *ctx) +{ + duk_get_global_string(ctx, "Irccd"); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, functions); + duk_put_prop_string(ctx, -2, "System"); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-system.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,30 @@ +/* + * jsapi-system.h -- Irccd.System API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_SYSTEM_H +#define IRCCD_JSAPI_SYSTEM_H + +#include <duktape.h> + +void +jsapi_system_raise(duk_context *); + +void +jsapi_system_load(duk_context *); + +#endif /* !IRCCD_JSAPI_SYSTEM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-timer.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,325 @@ +/* + * jsapi-timer.c -- Irccd.Timer API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <pthread.h> +#include <stdbool.h> +#include <stdatomic.h> +#include <time.h> +#include <errno.h> + +#include <duktape.h> + +#include <irccd/irccd.h> +#include <irccd/log.h> +#include <irccd/util.h> + +#include "jsapi-system.h" + +#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Timer") +#define TABLE DUK_HIDDEN_SYMBOL("Irccd.Timer.callbacks") + +enum timer_type { + TIMER_REPEAT, + TIMER_ONESHOT, + TIMER_NUM +}; + +enum timer_status { + TIMER_INACTIVE, + TIMER_ACTIVE, + TIMER_MUST_STOP, + TIMER_MUST_KILL +}; + +struct timer { + enum timer_type type; + unsigned long duration; + pthread_t thr; + pthread_mutex_t mtx; + pthread_cond_t cv; + duk_context *ctx; + atomic_int status; +}; + +static void +timer_start(struct timer *); + +static void +timer_clear(struct timer *tm) +{ + tm->status = TIMER_INACTIVE; + + pthread_cond_destroy(&tm->cv); + pthread_mutex_destroy(&tm->mtx); + pthread_join(tm->thr, NULL); +} + +static void +timer_call(struct timer *tm) +{ + /* Get the function. */ + duk_push_global_stash(tm->ctx); + duk_get_prop_string(tm->ctx, -1, TABLE); + duk_remove(tm->ctx, -2); + duk_push_sprintf(tm->ctx, "%p", tm); + duk_get_prop(tm->ctx, -2); + duk_remove(tm->ctx, -2); + + if (duk_pcall(tm->ctx, 0)) + irc_log_warn("plugin: %s", duk_to_string(tm->ctx, -1)); + + duk_pop(tm->ctx); +} + +static void +timer_destroy(struct timer *tm) +{ + if (tm->status == TIMER_MUST_STOP) { + puts("timer stopped"); + timer_clear(tm); + } + if (tm->status == TIMER_MUST_KILL) { + puts("timer fully freed"); + free(tm); + } +} + +static void +timer_expired(void *data) +{ + struct timer *tm = data; + + /* Only call if I wasn't aborted (race condition) */ + if (tm->status == TIMER_ACTIVE) { + timer_clear(tm); + timer_call(tm); + + /* Start again. */ + if (tm->type == TIMER_REPEAT) + timer_start(tm); + } else + timer_destroy(tm); +} + +static void +timer_aborted(void *data) +{ + timer_destroy(data); +} + +static void * +timer_routine(void *data) +{ + struct timer *tm = data; + struct timespec ts = {0}; + int rc = 0; + + /* Prepare maximum time to wait. */ + timespec_get(&ts, TIME_UTC); + + ts.tv_sec += tm->duration / 1000; + ts.tv_nsec += (tm->duration % 1000) * 1000; + + /* Wait at most time unless I'm getting kill. */ + if (pthread_mutex_lock(&tm->mtx) != 0) + tm->status = TIMER_MUST_STOP; + + while (tm->status == TIMER_ACTIVE && rc == 0) + rc = pthread_cond_timedwait(&tm->cv, &tm->mtx, &ts); + + /* + * When the thread ends, there are several possibilities: + * + * 1. It has completed without being aborted. + * 2. It has been stopped by the user (tm->stopped is true). + * 3. The plugin is shutting down (tm->kill is true). + */ + if (rc == ETIMEDOUT && tm->status == TIMER_ACTIVE) + irc_bot_post(timer_expired, tm); + else + irc_bot_post(timer_aborted, tm); + + return NULL; +} + +static void +timer_start(struct timer *tm) +{ + if (tm->status != TIMER_INACTIVE) + return; + + tm->status = TIMER_ACTIVE; + + if (pthread_mutex_init(&tm->mtx, NULL) != 0) + goto mutex_err; + if (pthread_cond_init(&tm->cv, NULL) != 0) + goto cond_err; + if (pthread_create(&tm->thr, NULL, timer_routine, tm) != 0) + goto thread_err; + + return; + +thread_err: + pthread_cond_destroy(&tm->cv); + +cond_err: + pthread_mutex_destroy(&tm->mtx); + +mutex_err: + tm->status = TIMER_INACTIVE; + jsapi_system_raise(tm->ctx); +} + +static void +timer_stop(struct timer *tm, enum timer_status st) +{ + if (tm->status == TIMER_INACTIVE) + return; + + tm->status = st; + pthread_cond_signal(&tm->cv); +} + +static struct timer * +self(duk_context *ctx) +{ + struct timer *tm; + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, SIGNATURE); + tm = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!tm) + (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Timer object"); + + return tm; +} + +static duk_ret_t +Timer_prototype_start(duk_context *ctx) +{ + timer_start(self(ctx)); + + return 0; +} + +static duk_ret_t +Timer_prototype_stop(duk_context *ctx) +{ + timer_stop(self(ctx), TIMER_MUST_STOP); + + return 0; +} + +static duk_ret_t +Timer_destructor(duk_context *ctx) +{ + struct timer *tm; + + /* Remove timer property. */ + duk_get_prop_string(ctx, 0, SIGNATURE); + tm = duk_to_pointer(ctx, -1); + duk_pop(ctx); + duk_del_prop_string(ctx, -2, SIGNATURE); + + /* Remove callback from timer table. */ + puts("DELETE"); + duk_push_global_stash(tm->ctx); + duk_get_prop_string(tm->ctx, -1, TABLE); + duk_remove(tm->ctx, -2); + duk_push_sprintf(tm->ctx, "%p", tm); + duk_del_prop(tm->ctx, -2); + duk_pop(tm->ctx); + + /* + * Do not delete the timer itself here because the thread is + * referencing it. Stop it and let it kill itself from the main thread. + */ + if (tm) + timer_stop(tm, TIMER_MUST_KILL); + + return 0; +} + +static duk_ret_t +Timer_constructor(duk_context *ctx) +{ + struct timer *ptr, tm = { + .ctx = ctx, + }; + + if (!duk_is_constructor_call(ctx)) + return 0; + + tm.type = duk_require_int(ctx, 0); + tm.duration = duk_require_uint(ctx, 1); + + if (tm.type < 0 || tm.type >= TIMER_NUM) + return duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type"); + if (!duk_is_callable(ctx, 2)) + return duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function"); + + /* Create this. */ + duk_push_this(ctx); + duk_push_pointer(ctx, (ptr = irc_util_memdup(&tm, sizeof (tm)))); + duk_put_prop_string(ctx, -2, SIGNATURE); + duk_push_c_function(ctx, Timer_destructor, 1); + duk_set_finalizer(ctx, -2); + duk_pop(ctx); + + /* Store the function into the global table */ + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, TABLE); + duk_remove(ctx, -2); + duk_push_sprintf(ctx, "%p", ptr); + duk_dup(ctx, 2); + duk_put_prop(ctx, -3); + duk_pop(ctx); + + return 0; +} + +static const duk_function_list_entry methods[] = { + { "start", Timer_prototype_start, 0 }, + { "stop", Timer_prototype_stop, 0 }, + { NULL, NULL, 0 } +}; + +static const duk_number_list_entry constants[] = { + { "Single", TIMER_ONESHOT }, + { "Repeat", TIMER_REPEAT }, + { NULL, 0 } +}; + +void +jsapi_timer_load(duk_context *ctx) +{ + duk_get_global_string(ctx, "Irccd"); + duk_push_c_function(ctx, Timer_constructor, 3); + duk_put_number_list(ctx, -1, constants); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Timer"); + duk_pop(ctx); + duk_push_global_stash(ctx); + duk_push_object(ctx); + duk_put_prop_string(ctx, -2, TABLE); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-timer.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,27 @@ +/* + * jsapi-timer.h -- Irccd.Timer API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_TIMER_H +#define IRCCD_JSAPI_TIMER_H + +#include <duktape.h> + +void +jsapi_timer_load(duk_context *); + +#endif /* !IRCCD_JSAPI_TIMER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-unicode.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,88 @@ +/* + * jsapi-unicode.c -- Irccd.Unicode API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 "jsapi-unicode.h" +#include "unicode.h" + +static duk_ret_t +Unicode_isDigit(duk_context *ctx) +{ + duk_push_boolean(ctx, uni_isdigit(duk_get_int(ctx, 0))); + + return 1; +} + +static duk_ret_t +Unicode_isLetter(duk_context *ctx) +{ + duk_push_boolean(ctx, uni_isalpha(duk_get_int(ctx, 0))); + + return 1; +} + +static duk_ret_t +Unicode_isLower(duk_context *ctx) +{ + duk_push_boolean(ctx, uni_islower(duk_get_int(ctx, 0))); + + return 1; +} + +static duk_ret_t +Unicode_isSpace(duk_context *ctx) +{ + duk_push_boolean(ctx, uni_isspace(duk_get_int(ctx, 0))); + + return 1; +} + +static duk_ret_t +Unicode_isTitle(duk_context *ctx) +{ + duk_push_boolean(ctx, uni_istitle(duk_get_int(ctx, 0))); + + return 1; +} + +static duk_ret_t +Unicode_isUpper(duk_context *ctx) +{ + duk_push_boolean(ctx, uni_isupper(duk_get_int(ctx, 0))); + + return 1; +} + +static const duk_function_list_entry functions[] = { + { "isDigit", Unicode_isDigit, 1 }, + { "isLetter", Unicode_isLetter, 1 }, + { "isLower", Unicode_isLower, 1 }, + { "isSpace", Unicode_isSpace, 1 }, + { "isTitle", Unicode_isTitle, 1 }, + { "isUpper", Unicode_isUpper, 1 }, + { NULL, NULL, 0 } +}; + +void +jsapi_unicode_load(duk_context *ctx) +{ + duk_get_global_string(ctx, "Irccd"); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, functions); + duk_put_prop_string(ctx, -2, "Unicode"); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-unicode.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,27 @@ +/* + * jsapi-unicode.h -- Irccd.Unicode API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_UNICODE_H +#define IRCCD_JSAPI_UNICODE_H + +#include <duktape.h> + +void +jsapi_unicode_load(duk_context *); + +#endif /* !IRCCD_JSAPI_UNICODE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-util.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,317 @@ +/* + * jsapi-util.c -- Irccd.Util API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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 <compat.h> + +#include <string.h> + +#include <irccd/server.h> +#include <irccd/subst.h> +#include <irccd/util.h> + +#include "jsapi-util.h" + +struct subspack { + struct irc_subst_keyword *kw; + struct irc_subst subst; +}; + +struct string { + TAILQ_ENTRY(string) link; + char value[]; +}; + +TAILQ_HEAD(stringlist, string); + +/* + * 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: ... + * } + */ +static void +subspack_parse(duk_context *ctx, duk_idx_t index, struct subspack *pkg) +{ + memset(pkg, 0, sizeof (*pkg)); + + if (!duk_is_object(ctx, index)) + return; + + duk_enum(ctx, index, 0); + + while (duk_next(ctx, -1, true)) { + if (strcmp(duk_get_string(ctx, -2), "date") == 0) { + pkg->subst.time = duk_get_number(ctx, -1); + continue; + } + + pkg->kw = irc_util_reallocarray(pkg->kw, ++pkg->subst.keywordsz, + sizeof (*pkg->kw)); + pkg->kw[pkg->subst.keywordsz - 1].key = + irc_util_strdup(duk_opt_string(ctx, -2, "")); + pkg->kw[pkg->subst.keywordsz - 1].value = + irc_util_strdup(duk_opt_string(ctx, -1, "")); + + duk_pop_n(ctx, 2); + } + + pkg->subst.flags = IRC_SUBST_DATE | + IRC_SUBST_KEYWORDS | + IRC_SUBST_ENV | + IRC_SUBST_IRC_ATTRS; + pkg->subst.keywords = pkg->kw; +} + +static inline void +subspack_finish(struct subspack *subst) +{ + for (size_t i = 0; i < subst->subst.keywordsz; ++i) { + free((char *)subst->kw[i].key); + free((char *)subst->kw[i].value); + } + + free(subst->kw); +} + +static struct string * +string_new(const char *v) +{ + struct string *s; + const size_t len = strlen(v); + + s = irc_util_malloc(sizeof (*s) + len + 1); + strcpy(s->value, v); + + return s; +} + +static void +stringlist_finish(struct stringlist *list) +{ + struct string *s, *tmp; + + TAILQ_FOREACH_SAFE(s, list, link, tmp) + free(s); +} + +static void +stringlist_concat(struct stringlist *list, const char *value) +{ + struct string *s; + char *str = irc_util_strdup(value), *token, *p = str; + + while ((token = strtok_r(p, " \t\n", &p))) { + /* TODO: trim and check if empty. */ + s = string_new(token); + TAILQ_INSERT_TAIL(list, s, link); + } + + free(str); +} + +static void +split_from_string(duk_context *ctx, struct stringlist *list) +{ + stringlist_concat(list, duk_require_string(ctx, 0)); +} + +static void +split_from_array(duk_context *ctx, struct stringlist *list) +{ + duk_enum(ctx, 0, DUK_ENUM_ARRAY_INDICES_ONLY); + + while (duk_next(ctx, -1, 1)) { + stringlist_concat(list, duk_to_string(ctx, -1)); + duk_pop_2(ctx); + } +} + +static void +split(duk_context *ctx, duk_idx_t index, struct stringlist *list) +{ + duk_require_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_STRING); + TAILQ_INIT(list); + + if (duk_is_string(ctx, index)) + split_from_string(ctx, list); + else if (duk_is_array(ctx, index)) + split_from_array(ctx, list); +} + +static int +limit(duk_context *ctx, duk_idx_t index, const char *name, size_t value) +{ + int newvalue; + + if (duk_get_top(ctx) < index || !duk_is_number(ctx, index)) + return value; + + newvalue = duk_to_int(ctx, index); + + if (newvalue <= 0) + (void)duk_error(ctx, DUK_ERR_RANGE_ERROR, + "argument %d (%s) must be positive", index, name); + + return newvalue; +} + +static char * +join(duk_context *ctx, size_t maxc, size_t maxl, const struct stringlist *tokens) +{ + FILE *fp; + char *out = NULL; + size_t outsz = 0, linesz = 0, tokensz, lineavail = maxl; + struct string *token; + + if (!(fp = open_memstream(&out, &outsz))) + return false; + + TAILQ_FOREACH(token, tokens, link) { + tokensz = strlen(token->value); + + if (tokensz > maxc) { + fclose(fp); + duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, + "token '%s' could not fit in maxc limit (%zu)", token->value, maxc); + return NULL; + } + + /* + * If there is something at the beginning of the line, we must + * append a space. + */ + if (linesz > 0) + tokensz++; + + /* + * This token is going past the maximum of the current line so + * we append a newline character and reset the length to start + * a "new" one. + */ + if (linesz + tokensz > maxc) { + if (--lineavail == 0) { + fclose(fp); + duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "number of lines exceeds maxl (%zu)", maxl); + return NULL; + } + + fputc('\n', fp); + linesz = 0; + } + + linesz += fprintf(fp, "%s%s", linesz > 0 ? " " : "", token->value); + } + + fflush(fp); + fclose(fp); + + return out; +} + +static duk_ret_t +Util_cut(duk_context *ctx) +{ + struct stringlist tokens; + size_t maxc, maxl, i = 0; + char *lines, *line, *p; + + maxc = limit(ctx, 1, "maxc", 72); + maxl = limit(ctx, 2, "maxl", SIZE_MAX); + + /* Construct a list of words from a string or an array of strings. */ + split(ctx, 0, &tokens); + + /* Join as new lines with a limit of maximum columns and lines. */ + if (!(lines = join(ctx, maxc, maxl, &tokens))) { + stringlist_finish(&tokens); + duk_throw(ctx); + } + + duk_push_array(ctx); + + for (p = lines; (line = strtok_r(p, "\n", &p)); ) { + duk_push_string(ctx, line); + duk_put_prop_index(ctx, -2, i++); + } + + stringlist_finish(&tokens); + free(lines); + + return 1; +} + +static duk_ret_t +Util_format(duk_context *ctx) +{ + const char *str = duk_require_string(ctx, 0); + struct subspack pkg; + char buf[1024] = {0}; + + subspack_parse(ctx, 1, &pkg); + irc_subst(buf, sizeof (buf), str, &pkg.subst); + duk_push_string(ctx, buf); + subspack_finish(&pkg); + + return 1; +} + +static duk_ret_t +Util_splituser(duk_context *ctx) +{ + struct irc_server_user user; + + irc_server_split(duk_require_string(ctx, 0), &user); + duk_push_string(ctx, user.nickname); + + return 1; +} + +static duk_ret_t +Util_splithost(duk_context *ctx) +{ + struct irc_server_user user; + + irc_server_split(duk_require_string(ctx, 0), &user); + duk_push_string(ctx, user.host); + + return 1; +} + +static const duk_function_list_entry functions[] = { + { "cut", Util_cut, DUK_VARARGS }, + { "format", Util_format, DUK_VARARGS }, + { "splituser", Util_splituser, 1 }, + { "splithost", Util_splithost, 1 }, + { NULL, NULL, 0 } +}; + +void +jsapi_util_load(duk_context *ctx) +{ + duk_get_global_string(ctx, "Irccd"); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, functions); + duk_put_prop_string(ctx, -2, "Util"); + duk_pop(ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/jsapi-util.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,27 @@ +/* + * jsapi-util.h -- Irccd.Util API + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * 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_JSAPI_UTIL_H +#define IRCCD_JSAPI_UTIL_H + +#include <duktape.h> + +void +jsapi_util_load(duk_context *ctx); + +#endif /* !IRCCD_JSAPI_UTIL_H */
--- a/irccd/main.c Fri Jan 29 13:50:44 2021 +0100 +++ b/irccd/main.c Fri Jan 29 15:03:23 2021 +0100 @@ -19,16 +19,17 @@ #include <stdio.h> #include <err.h> -#include <irccd/dl-plugin.h> #include <irccd/irccd.h> #include <irccd/log.h> #include <irccd/server.h> #include <irccd/transport.h> #include <irccd/util.h> #include <irccd/plugin.h> -#include <irccd/js-plugin.h> #include <irccd/rule.h> +#include "dl-plugin.h" +#include "js-plugin.h" + static int run(int argc, char **argv) { @@ -54,8 +55,9 @@ /* TODO: temp. */ irc_log_set_verbose(true); - irc_bot_plugin_loader_add(irc_dl_plugin_loader_new()); - irc_bot_plugin_loader_add(irc_js_plugin_loader_new()); + irc_bot_plugin_loader_add(dl_plugin_loader_new()); + irc_bot_plugin_loader_add(js_plugin_loader_new()); + irc_bot_plugin_find("foo"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/unicode.c Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,4845 @@ +/* + * unicode.c -- UTF-8 to UTF-32 conversions and various operations + * + * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr> + * + * 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 <assert.h> +#include <errno.h> +#include <stdlib.h> + +#include "unicode.h" + +/* + * The following code has been generated from Go mkrunetype adapted to our + * needs. + */ + +#define nelem(x) (sizeof (x) / sizeof ((x)[0])) + +static const uint32_t * +search(uint32_t c, const uint32_t *t, int n, int ne) +{ + const uint32_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 NULL; +} + +static const uint32_t isspacer[] = { + 0x0009, 0x000d, + 0x0020, 0x0020, + 0x0085, 0x0085, + 0x00a0, 0x00a0, + 0x1680, 0x1680, + 0x2000, 0x200a, + 0x2028, 0x2029, + 0x202f, 0x202f, + 0x205f, 0x205f, + 0x3000, 0x3000, + 0xfeff, 0xfeff, +}; + +bool +uni_isspace(uint32_t c) +{ + const uint32_t *p; + + p = search(c, isspacer, nelem (isspacer) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + return false; +} + +static const uint32_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, +}; + +bool +uni_isdigit(uint32_t c) +{ + const uint32_t *p; + + p = search(c, isdigitr, nelem (isdigitr) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + return false; +} + +static const uint32_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, +}; + +static const uint32_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, +}; + +bool +uni_isalpha(uint32_t c) +{ + const uint32_t *p; + + p = search(c, isalphar, nelem (isalphar) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, isalphas, nelem (isalphas), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +static const uint32_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, +}; + +static const uint32_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, +}; + +bool +uni_isupper(uint32_t c) +{ + const uint32_t *p; + + p = search(c, isupperr, nelem (isupperr) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, isuppers, nelem (isuppers), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +static const uint32_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, +}; + +static const uint32_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, +}; + +bool +uni_islower(uint32_t c) +{ + const uint32_t *p; + + p = search(c, islowerr, nelem (islowerr) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, islowers, nelem (islowers), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +static const uint32_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, +}; + +static const uint32_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, +}; + +bool +uni_istitle(uint32_t c) +{ + const uint32_t *p; + + p = search(c, istitler, nelem (istitler) / 2, 2); + + if (p && c >= p[0] && c <= p[1]) + return true; + + p = search(c, istitles, nelem (istitles), 1); + + if (p && c == p[0]) + return true; + + return false; +} + +static const uint32_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, +}; + +static const uint32_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, +}; + +uint32_t +uni_toupper(uint32_t c) +{ + const uint32_t *p; + + p = search(c, toupperr, nelem (toupperr) / 3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = search(c, touppers, nelem (touppers) / 2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +static const uint32_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, +}; + +static const uint32_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, +}; + +uint32_t +uni_tolower(uint32_t c) +{ + const uint32_t *p; + + p = search(c, tolowerr, nelem (tolowerr) / 3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = search(c, tolowers, nelem (tolowers) / 2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +static const uint32_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, +}; + +static const uint32_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, +}; + +uint32_t +uni_totitle(uint32_t c) +{ + const uint32_t *p; + + p = search(c, totitler, nelem (totitler) / 3, 3); + + if (p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + + p = search(c, totitles, nelem (totitles) / 2, 2); + + if (p && c == p[0]) + return c + p[1] - 1048576; + + return c; +} + +size_t +uni8_encode(uint8_t dst[], size_t dstsz, uint32_t point) +{ + assert(dst); + + size_t written; + + switch ((written = uni32_sizeof(point))) { + case 1: + if (dstsz < 1) + goto erange; + + dst[0] = (uint8_t)point; + break; + case 2: + if (dstsz < 2) + goto erange; + + dst[0] = 0xC0 | ((point >> 6) & 0x1F); + dst[1] = 0x80 | (point & 0x3F); + break; + case 3: + if (dstsz < 3) + goto erange; + + dst[0] = 0xE0 | ((point >> 12) & 0xF ); + dst[1] = 0x80 | ((point >> 6) & 0x3F); + dst[2] = 0x80 | (point & 0x3F); + break; + case 4: + if (dstsz < 4) + goto erange; + + dst[0] = 0xF0 | ((point >> 18) & 0x7 ); + dst[1] = 0x80 | ((point >> 12) & 0x3F); + dst[2] = 0x80 | ((point >> 6) & 0x3F); + dst[3] = 0x80 | (point & 0x3F); + break; + default: + break; + } + + return written; + +erange: + errno = ERANGE; + + return -1; +} + +size_t +uni8_decode(const uint8_t src[], uint32_t *point) +{ + assert(src); + assert(point); + + size_t parsed; + + switch ((parsed = uni8_sizeof(*src))) { + case 1: + *point = src[0]; + break; + case 2: + if (!src[1]) + goto eilseq; + + *point = (src[0] & 0x1f) << 6; + *point |= (src[1] & 0x3f); + break; + case 3: + if (!src[1] || !src[2]) + goto eilseq; + + *point = (src[0] & 0x0f) << 12; + *point |= (src[1] & 0x3f) << 6; + *point |= (src[2] & 0x3f); + break; + case 4: + if (!src[1] || !src[2] || !src[3]) + goto eilseq; + + *point = (src[0] & 0x07) << 16; + *point |= (src[1] & 0x3f) << 12; + *point |= (src[2] & 0x3f) << 6; + *point |= (src[3] & 0x3f); + break; + default: + break; + } + + return parsed; + +eilseq: + errno = EILSEQ; + + return -1; +} + +size_t +uni8_sizeof(uint8_t c) +{ + if (c <= 127) + return 1; + if ((c & 0xE0) == 0xC0) + return 2; + if ((c & 0xF0) == 0xE0) + return 3; + if ((c & 0xF8) == 0xF0) + return 4; + + errno = EILSEQ; + return -1; +} + +size_t +uni8_length(const uint8_t src[]) +{ + assert(src); + + size_t total = 0, gap; + + while (*src) { + if ((gap = uni8_sizeof(*src)) == (size_t)-1) + return -1; + + total += gap; + src += gap; + } + + return total; +} + +size_t +uni8_to32(const uint8_t src[], uint32_t dst[], size_t dstsz) +{ + assert(src); + assert(dst); + + size_t nwritten = 0, gap; + + for (; *src && dstsz; --dstsz) { + if ((gap = uni8_decode(src, dst++)) == (size_t)-1) + return -1; + + src += gap; + ++nwritten; + } + + /* No more space to store NUL. */ + if (dstsz == 0) { + errno = ERANGE; + return -1; + } + + *dst = 0; + + return nwritten; +} + +size_t +uni32_sizeof(uint32_t c) +{ + if (c <= 0x7F) + return 1; + if (c <= 0x7FF) + return 2; + if (c <= 0xFFFF) + return 3; + if (c <= 0x1FFFFF) + return 4; + + errno = EILSEQ; + return -1; +} + +size_t +uni32_length(const uint32_t src[]) +{ + assert(src); + + size_t total = 0; + + while (*src++) + total++; + + return total; +} + +size_t +uni32_requires(const uint32_t src[]) +{ + assert(src); + + size_t total = 0, gap; + + while (*src) { + if ((gap = uni32_sizeof(*src++)) == (size_t)-1) + return -1; + if (gap >= SIZE_MAX - total) { + errno = ERANGE; + return -1; + } + + total += gap; + } + + return total; +} + +size_t +uni32_to8(const uint32_t src[], uint8_t dst[], size_t dstsz) +{ + assert(src); + assert(dst); + + size_t nwritten = 0, gap; + + while (*src && dstsz) { + if ((gap = uni8_encode(dst, dstsz, *src++)) == (size_t)-1) + return -1; + + dst += gap; + dstsz -= gap; + nwritten += gap; + } + + if (dstsz == 0) { + errno = ERANGE; + return -1; + } + + *dst = 0; + + return nwritten; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/unicode.h Fri Jan 29 15:03:23 2021 +0100 @@ -0,0 +1,80 @@ +/* + * unicode.h -- UTF-8 to UTF-32 conversions and various operations + * + * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr> + * + * 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_H +#define IRCCD_UNICODE_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +size_t +uni8_encode(uint8_t dst[], size_t dstsz, uint32_t point); + +size_t +uni8_decode(const uint8_t src[], uint32_t *point); + +size_t +uni8_sizeof(uint8_t c); + +size_t +uni8_length(const uint8_t src[]); + +size_t +uni8_to32(const uint8_t src[], uint32_t dst[], size_t dstsz); + +size_t +uni32_sizeof(uint32_t point); + +size_t +uni32_length(const uint32_t src[]); + +size_t +uni32_requires(const uint32_t src[]); + +size_t +uni32_to8(const uint32_t src[], uint8_t dst[], size_t dstsz); + +bool +uni_isalpha(uint32_t c); + +bool +uni_isdigit(uint32_t c); + +bool +uni_islower(uint32_t c); + +bool +uni_isspace(uint32_t c); + +bool +uni_istitle(uint32_t c); + +bool +uni_isupper(uint32_t c); + +uint32_t +uni_toupper(uint32_t c); + +uint32_t +uni_tolower(uint32_t c); + +uint32_t +uni_totitle(uint32_t c); + +#endif /* !IRCCD_UNICODE_H */
--- a/lib/CMakeLists.txt Fri Jan 29 13:50:44 2021 +0100 +++ b/lib/CMakeLists.txt Fri Jan 29 15:03:23 2021 +0100 @@ -26,8 +26,6 @@ irccd/config.h.in irccd/conn.c irccd/conn.h - irccd/dl-plugin.c - irccd/dl-plugin.h irccd/event.c irccd/event.h irccd/irccd.c @@ -51,38 +49,6 @@ irccd/util.h ) -if (IRCCD_WITH_JS) - list( - APPEND SOURCES - irccd/unicode.c - irccd/unicode.h - irccd/js-plugin.c - irccd/js-plugin.h - irccd/jsapi-chrono.c - irccd/jsapi-chrono.h - irccd/jsapi-directory.c - irccd/jsapi-directory.h - irccd/jsapi-file.c - irccd/jsapi-file.h - irccd/jsapi-irccd.c - irccd/jsapi-irccd.h - irccd/jsapi-logger.c - irccd/jsapi-logger.h - irccd/jsapi-plugin.c - irccd/jsapi-plugin.h - irccd/jsapi-server.c - irccd/jsapi-server.h - irccd/jsapi-system.c - irccd/jsapi-system.h - irccd/jsapi-timer.c - irccd/jsapi-timer.h - irccd/jsapi-unicode.c - irccd/jsapi-unicode.h - irccd/jsapi-util.c - irccd/jsapi-util.h - ) -endif () - configure_file( ${libirccd_SOURCE_DIR}/irccd/config.h.in ${libirccd_BINARY_DIR}/irccd/config.h @@ -102,8 +68,5 @@ if (IRCCD_WITH_SSL) target_link_libraries(libirccd OpenSSL::SSL OpenSSL::Crypto) endif () -if (IRCCD_WITH_JS) - target_link_libraries(libirccd libirccd-duktape) -endif () source_group(TREE ${libirccd_SOURCE_DIR} FILES ${SOURCES})
--- a/lib/irccd/dl-plugin.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,265 +0,0 @@ -/* - * dl-plugin.c -- native C plugins for irccd - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <sys/stat.h> -#include <assert.h> -#include <ctype.h> -#include <dlfcn.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "config.h" -#include "dl-plugin.h" -#include "log.h" -#include "plugin.h" -#include "util.h" - -#define INVOKE(pg, name, sig, ...) \ -do { \ - struct self *self = pg->data; \ - sig fn; \ - \ - if (self->handle && (fn = dlsym(self->handle, symbol(self, name)))) \ - return fn(__VA_ARGS__); \ -} while (0) - -struct self { - struct irc_plugin plugin; - char prefix[32]; - void *handle; -}; - -typedef const char * (*get_option_fn)(const char *); -typedef const char * (*get_path_fn)(const char *); -typedef const char * (*get_template_fn)(const char *); -typedef const char ** (*get_options_fn)(void); -typedef const char ** (*get_paths_fn)(void); -typedef const char ** (*get_templates_fn)(void); -typedef void (*event_fn)(const struct irc_event *); -typedef void (*load_fn)(void); -typedef void (*reload_fn)(void); -typedef void (*unload_fn)(void); -typedef void (*set_option_fn)(const char *, const char *); -typedef void (*set_path_fn)(const char *, const char *); -typedef void (*set_template_fn)(const char *, const char *); - -static const char * -symbol(const struct self *self, const char *func) -{ - static char sym[128]; - - snprintf(sym, sizeof (sym), "%s_%s",self->prefix, func); - - return sym; -} - -static void -set_template(struct irc_plugin *plg, const char *key, const char *value) -{ - INVOKE(plg, "set_template", set_template_fn, key, value); -} - -static const char * -get_template(struct irc_plugin *plg, const char *key) -{ - INVOKE(plg, "get_template", get_template_fn, key); - - return NULL; -} - -static const char ** -get_templates(struct irc_plugin *plg) -{ - INVOKE(plg, "get_templates", get_templates_fn); - - return NULL; -} - -static void -set_path(struct irc_plugin *plg, const char *key, const char *value) -{ - INVOKE(plg, "set_path", set_path_fn, key, value); -} - -static const char * -get_path(struct irc_plugin *plg, const char *key) -{ - INVOKE(plg, "get_path", get_path_fn, key); - - return NULL; -} - -static const char ** -get_paths(struct irc_plugin *plg) -{ - INVOKE(plg, "get_paths", get_paths_fn); - - return NULL; -} - -static void -set_option(struct irc_plugin *plg, const char *key, const char *value) -{ - INVOKE(plg, "set_option", set_option_fn, key, value); -} - -static const char * -get_option(struct irc_plugin *plg, const char *key) -{ - INVOKE(plg, "get_option", get_option_fn, key); - - return NULL; -} - -static const char ** -get_options(struct irc_plugin *plg) -{ - INVOKE(plg, "get_options", get_options_fn); - - return NULL; -} - -static void -load(struct irc_plugin *plg) -{ - INVOKE(plg, "load", load_fn); -} - -static void -reload(struct irc_plugin *plg) -{ - INVOKE(plg, "reload", reload_fn); -} - -static void -unload(struct irc_plugin *plg) -{ - INVOKE(plg, "unload", unload_fn); -} - -static void -handle(struct irc_plugin *plg, const struct irc_event *ev) -{ - INVOKE(plg, "event", event_fn, ev); -} - -static void -finish(struct irc_plugin *plg) -{ - struct self *self = plg->data; - - if (self->handle) - dlclose(self->handle); - - free(self); - memset(self, 0, sizeof (*self)); -} - -static struct self * -init(const char *path) -{ - struct self self; - struct stat st; - - /* - * It's not possible to get the exact error code when loading a plugin - * using dlopen, since we're trying a lot of files that potentially not - * exist we check presence before even though there's a possible - * condition but at least we can print an error message if there are - * other errors than missing file. - */ - if (stat(path, &st) < 0 && errno == ENOENT) - return NULL; - - if (!(self.handle = dlopen(path, RTLD_NOW))) { - irc_log_warn("plugin: %s: %s", path, dlerror()); - return NULL; - } - - /* Compute prefix name */ - strlcpy(self.prefix, irc_util_basename(path), sizeof (self.prefix)); - - /* Remove plugin extension. */ - self.prefix[strcspn(self.prefix, ".")] = '\0'; - - /* Remove every invalid identifiers. */ - for (char *p = self.prefix; *p; ++p) - if (!isalnum(*p)) - *p = '_'; - - return irc_util_memdup(&self, sizeof (self)); -} - -static struct irc_plugin * -wrap_open(struct irc_plugin_loader *ldr, const char *path) -{ - (void)ldr; - - return irc_dl_plugin_open(path); -} - -struct irc_plugin * -irc_dl_plugin_open(const char *path) -{ - struct self *self; - - if (!(self = init(path))) - return false; - - /* Data and all callbacks. */ - self->plugin.data = self; - self->plugin.set_template = set_template; - self->plugin.get_template = get_template; - self->plugin.get_templates = get_templates; - self->plugin.set_path = set_path; - self->plugin.get_path = get_path; - self->plugin.get_paths = get_paths; - self->plugin.set_option = set_option; - self->plugin.get_option = get_option; - self->plugin.get_options = get_options; - self->plugin.load = load; - self->plugin.reload = reload; - self->plugin.unload = unload; - self->plugin.handle = handle; - self->plugin.finish = finish; - - return &self->plugin; -} - -struct irc_plugin_loader * -irc_dl_plugin_loader_new(void) -{ - struct irc_plugin_loader *ldr; - - ldr = irc_util_calloc(1, sizeof (*ldr)); - ldr->open = wrap_open; - -#if defined(_WIN32) - strlcpy(ldr->extensions, "dll", sizeof (ldr->extensions)); -#elif defined(__APPLE__) - strlcpy(ldr->extensions, "so:dylib", sizeof (ldr->extensions)); -#else - strlcpy(ldr->extensions, "so", sizeof (ldr->extensions)); -#endif - - strlcpy(ldr->paths, IRCCD_LIBDIR "/irccd", sizeof (ldr->paths)); - - return ldr; -}
--- a/lib/irccd/dl-plugin.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * dl-plugin.c -- native C plugins for irccd - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_DL_PLUGIN_H -#define IRCCD_DL_PLUGIN_H - -struct irc_plugin; -struct irc_plugin_loader; - -#if defined(_WIN32) -# define IRC_DL_EXPORT __declspec(dllexport) -#else -# define IRC_DL_EXPORT -#endif - -struct irc_plugin * -irc_dl_plugin_open(const char *); - -struct irc_plugin_loader * -irc_dl_plugin_loader_new(void); - -#endif /* !IRCCD_DL_PLUGIN_H */
--- a/lib/irccd/js-plugin.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,559 +0,0 @@ -/* - * jsapi-plugin.c -- Javascript plugins - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <sys/stat.h> -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <stdarg.h> -#include <string.h> -#include <unistd.h> - -#include "channel.h" -#include "event.h" -#include "js-plugin.h" -#include "jsapi-chrono.h" -#include "jsapi-directory.h" -#include "jsapi-file.h" -#include "jsapi-irccd.h" -#include "jsapi-logger.h" -#include "jsapi-plugin.h" -#include "jsapi-plugin.h" -#include "jsapi-server.h" -#include "jsapi-system.h" -#include "jsapi-timer.h" -#include "jsapi-unicode.h" -#include "jsapi-util.h" -#include "log.h" -#include "plugin.h" -#include "server.h" -#include "util.h" - -static void -freelist(char **table) -{ - for (char **p = table; *p; ++p) - free(*p); - - free(table); -} - -static char * -metadata(duk_context *ctx, const char *name) -{ - char *ret = NULL; - - duk_get_global_string(ctx, "info"); - - if (duk_get_type(ctx, -1) == DUK_TYPE_OBJECT) { - duk_get_prop_string(ctx, -1, name); - - if (duk_get_type(ctx, -1) == DUK_TYPE_STRING) - ret = irc_util_strdup(duk_get_string(ctx, -1)); - - duk_pop(ctx); - } - - duk_pop(ctx); - - return ret ? ret : irc_util_strdup("unknown"); -} - -static void -push_names(duk_context *ctx, const struct irc_event *ev) -{ - const char *token; - char *p = ev->names.names; - - duk_push_array(ctx); - - for (size_t i = 0; (token = strtok_r(p, " ", &p)); ++i) { - irc_server_strip(ev->server, &token, NULL, NULL); - duk_push_string(ctx, token); - duk_put_prop_index(ctx, -2, i); - } -} - -static void -push_whois(duk_context *ctx, const struct irc_event *ev) -{ - const char *token; - char *p = ev->whois.channels; - - duk_push_object(ctx); - duk_push_string(ctx, ev->whois.nickname); - duk_put_prop_string(ctx, -2, "nickname"); - duk_push_string(ctx, ev->whois.username); - duk_put_prop_string(ctx, -2, "username"); - duk_push_string(ctx, ev->whois.realname); - duk_put_prop_string(ctx, -2, "realname"); - duk_push_string(ctx, ev->whois.hostname); - duk_put_prop_string(ctx, -2, "hostname"); - duk_push_array(ctx); - for (size_t i = 0; (token = strtok_r(p, " ", &p)); ++i) { - char mode = 0, prefix = 0; - - irc_server_strip(ev->server, &token, &mode, &prefix); - duk_push_object(ctx); - duk_push_string(ctx, token); - duk_put_prop_string(ctx, -2, "channel"); - duk_push_sprintf(ctx, "%c", mode); - duk_put_prop_string(ctx, -2, "mode"); - duk_push_sprintf(ctx, "%c", prefix); - duk_put_prop_string(ctx, -2, "prefix"); - duk_put_prop_index(ctx, -2, i); - } - duk_put_prop_string(ctx, -2, "channels"); -} - -static const char ** -get_table(duk_context *ctx, const char *name, char ***ptable) -{ - char **list; - size_t listsz; - - duk_get_global_string(ctx, name); - - if (!(listsz = duk_get_length(ctx, -1))) { - duk_pop(ctx); - return NULL; - } - - list = irc_util_calloc(listsz + 1, sizeof (char *)); - - duk_enum(ctx, -1, 0); - - for (size_t i = 0; i < listsz && duk_next(ctx, -1, true); ++i) { - list[i] = irc_util_strdup(duk_to_string(ctx, -2)); - duk_pop_n(ctx, 2); - } - - duk_pop_n(ctx, 2); - - freelist(*ptable); - *ptable = list; - - return (const char **)list; -} - -static void -set_key_value(duk_context *ctx, const char *table, const char *key, const char *value) -{ - duk_get_global_string(ctx, table); - duk_push_string(ctx, value); - duk_put_prop_string(ctx, -2, key); - duk_pop(ctx); -} - -static const char * -get_value(duk_context *ctx, const char *table, const char *key) -{ - const char *ret; - - duk_get_global_string(ctx, table); - duk_get_prop_string(ctx, -1, key); - ret = duk_to_string(ctx, -1); - duk_pop_n(ctx, 2); - - return ret; -} - -static void -set_template(struct irc_plugin *plg, const char *key, const char *value) -{ - struct irc_js_plugin_data *js = plg->data; - - set_key_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_TEMPLATES, key, value); -} - -static const char * -get_template(struct irc_plugin *plg, const char *key) -{ - struct irc_js_plugin_data *js = plg->data; - - return get_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_TEMPLATES, key); -} - -static const char ** -get_templates(struct irc_plugin *plg) -{ - struct irc_js_plugin_data *js = plg->data; - - return get_table(js->ctx, IRC_JSAPI_PLUGIN_PROP_TEMPLATES, &js->templates); -} - -static void -set_path(struct irc_plugin *plg, const char *key, const char *value) -{ - struct irc_js_plugin_data *js = plg->data; - - set_key_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_PATHS, key, value); -} - -static const char * -get_path(struct irc_plugin *plg, const char *key) -{ - struct irc_js_plugin_data *js = plg->data; - - return get_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_PATHS, key); -} - -static const char ** -get_paths(struct irc_plugin *plg) -{ - struct irc_js_plugin_data *js = plg->data; - - return get_table(js->ctx, IRC_JSAPI_PLUGIN_PROP_PATHS, &js->paths); -} - -static void -set_option(struct irc_plugin *plg, const char *key, const char *value) -{ - struct irc_js_plugin_data *js = plg->data; - - set_key_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_OPTIONS, key, value); -} - -static const char * -get_option(struct irc_plugin *plg, const char *key) -{ - struct irc_js_plugin_data *js = plg->data; - - return get_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_OPTIONS, key); -} - -static const char ** -get_options(struct irc_plugin *plg) -{ - struct irc_js_plugin_data *js = plg->data; - - return get_table(js->ctx, IRC_JSAPI_PLUGIN_PROP_OPTIONS, &js->options); -} - -static void -vcall(struct irc_plugin *plg, const char *function, const char *fmt, va_list ap) -{ - struct irc_js_plugin_data *self = plg->data; - int nargs = 0; - - duk_get_global_string(self->ctx, function); - - if (!duk_is_function(self->ctx, -1)) { - duk_pop(self->ctx); - return; - } - - for (const char *f = fmt; *f; ++f) { - void (*push)(duk_context *, void *); - - switch (*f) { - case 'S': - irc_jsapi_server_push(self->ctx, va_arg(ap, struct irc_server *)); - break; - case 's': - duk_push_string(self->ctx, va_arg(ap, const char *)); - break; - case 'x': - push = va_arg(ap, void (*)(duk_context *, void *)); - push(self->ctx, va_arg(ap, void *)); - break; - default: - continue; - } - - ++nargs; - } - - if (duk_pcall(self->ctx, nargs) != 0) - irc_log_warn("plugin %s: %s\n", duk_to_string(self->ctx, -1)); - - duk_pop(self->ctx); -} - -static void -call(struct irc_plugin *plg, const char *function, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vcall(plg, function, fmt, ap); - va_end(ap); -} - -static void -handle(struct irc_plugin *plg, const struct irc_event *ev) -{ - (void)plg; - (void)ev; - - switch (ev->type) { - case IRC_EVENT_COMMAND: - call(plg, "onCommand", "Ss ss", ev->server, ev->message.origin, - ev->message.channel, ev->message.message); - break; - case IRC_EVENT_CONNECT: - call(plg, "onConnect", "S", ev->server); - break; - case IRC_EVENT_DISCONNECT: - call(plg, "onDisconnect", "S", ev->server); - break; - case IRC_EVENT_INVITE: - call(plg, "onInvite", "Ss s", ev->server, ev->invite.origin, - ev->invite.channel); - break; - case IRC_EVENT_JOIN: - call(plg, "onJoin", "Ss s", ev->server, ev->join.origin, - ev->join.channel); - break; - case IRC_EVENT_KICK: - call(plg, "onKick", "Ss sss", ev->server, ev->kick.origin, - ev->kick.channel, ev->kick.target, ev->kick.reason); - break; - case IRC_EVENT_ME: - call(plg, "onMe", "Ss ss", ev->server, ev->message.origin, - ev->message.channel, ev->message.message); - break; - case IRC_EVENT_MESSAGE: - call(plg, "onMessage", "Ss ss", ev->server, ev->message.origin, - ev->message.channel, ev->message.message); - break; - case IRC_EVENT_MODE: - call(plg, "onMode", "Ss sss ss", ev->server, ev->mode.origin, - ev->mode.channel, ev->mode.mode, ev->mode.limit, - ev->mode.user, ev->mode.mask); - break; - case IRC_EVENT_NAMES: - call(plg, "onNames", "Ss x", ev->server, ev->names.channel, - push_names, ev); - break; - case IRC_EVENT_NICK: - call(plg, "onNick", "Ss s", ev->server, ev->nick.origin, - ev->nick.nickname); - break; - case IRC_EVENT_NOTICE: - call(plg, "onNotice", "Ss ss", ev->server, ev->notice.origin, - ev->notice.channel, ev->notice.notice); - break; - case IRC_EVENT_PART: - call(plg, "onPart", "Ss ss", ev->server, ev->part.origin, - ev->part.channel, ev->part.reason); - break; - case IRC_EVENT_TOPIC: - call(plg, "onTopic", "Ss ss", ev->server, ev->topic.origin, - ev->topic.channel, ev->topic.topic); - break; - case IRC_EVENT_WHOIS: - call(plg, "onWhois", "Sx", ev->server, push_whois, ev); - break; - default: - break; - } -} - -static char * -eat(const char *path) -{ - int fd = -1; - char *ret = NULL; - struct stat st; - - if ((fd = open(path, O_RDONLY)) < 0) - goto err; - if (fstat(fd, &st) < 0) - goto err; - if (!(ret = calloc(1, st.st_size + 1))) - goto err; - if (read(fd, ret, st.st_size) != st.st_size) - goto err; - - close(fd); - - return ret; - -err: - if (fd != -1) - close(fd); - - free(ret); - - return false; -} - -static void * -wrap_malloc(void *udata, size_t size) -{ - (void)udata; - - return irc_util_malloc(size); -} - -static void * -wrap_realloc(void *udata, void *ptr, size_t size) -{ - (void)udata; - - return irc_util_realloc(ptr, size); -} - -static void -wrap_free(void *udata, void *ptr) -{ - (void)udata; - - free(ptr); -} - -static struct irc_js_plugin_data * -init(const char *path, const char *script) -{ - struct irc_js_plugin_data *js; - - js = irc_util_calloc(1, sizeof (*js)); - js->ctx = duk_create_heap(wrap_malloc, wrap_realloc, wrap_free, NULL, NULL); - - irc_jsapi_load(js->ctx); - irc_jsapi_chrono_load(js->ctx); - irc_jsapi_directory_load(js->ctx); - irc_jsapi_file_load(js->ctx); - irc_jsapi_logger_load(js->ctx); - irc_jsapi_plugin_load(js->ctx, &js->plugin); - irc_jsapi_server_load(js->ctx); - irc_jsapi_system_load(js->ctx); - irc_jsapi_timer_load(js->ctx); - irc_jsapi_unicode_load(js->ctx); - irc_jsapi_util_load(js->ctx); - - if (duk_peval_string(js->ctx, script) != 0) { - irc_log_warn("plugin: %s: %s", path, duk_to_string(js->ctx, -1)); - duk_destroy_heap(js->ctx); - free(js); - return NULL; - } - - js->plugin.license = js->license = metadata(js->ctx, "license"); - js->plugin.version = js->version = metadata(js->ctx, "version"); - js->plugin.author = js->author = metadata(js->ctx, "author"); - js->plugin.description = js->description = metadata(js->ctx, "summary"); - - return js; -} - -static void -load(struct irc_plugin *plg) -{ - call(plg, "onLoad", ""); -} - -static void -reload(struct irc_plugin *plg) -{ - call(plg, "onReload", ""); -} - -static void -unload(struct irc_plugin *plg) -{ - call(plg, "onUnload", ""); -} - -static void -finish(struct irc_plugin *plg) -{ - struct irc_js_plugin_data *self = plg->data; - - if (self->ctx) - duk_destroy_heap(self->ctx); - - freelist(self->options); - freelist(self->templates); - freelist(self->paths); - - free(self->license); - free(self->version); - free(self->author); - free(self->description); - free(self); -} - -static struct irc_plugin * -wrap_open(struct irc_plugin_loader *ldr, const char *path) -{ - (void)ldr; - - return irc_js_plugin_open(path); -} - -struct irc_plugin * -irc_js_plugin_open(const char *path) -{ - assert(path); - - char *script = NULL; - struct irc_js_plugin_data *self; - - /* - * Duktape can't open script from file path so we need to read the - * whole script at once. - */ - if (!(script = eat(path))) { - if (errno != ENOENT) - irc_log_warn("irccd: %s: %s", path, strerror(errno)); - - return NULL; - } - - /* Init already log errors. */ - if (!(self = init(path, script))) { - free(script); - return NULL; - } - - self->plugin.data = self; - self->plugin.set_template = set_template; - self->plugin.get_template = get_template; - self->plugin.get_templates = get_templates; - self->plugin.set_path = set_path; - self->plugin.get_path = get_path; - self->plugin.get_paths = get_paths; - self->plugin.set_option = set_option; - self->plugin.get_option = get_option; - self->plugin.get_options = get_options; - self->plugin.load = load; - self->plugin.reload = reload; - self->plugin.unload = unload; - self->plugin.handle = handle; - self->plugin.finish = finish; - - /* No longer needed. */ - free(script); - - return &self->plugin; -} - -struct irc_plugin_loader * -irc_js_plugin_loader_new(void) -{ - struct irc_plugin_loader *ldr; - - ldr = irc_util_calloc(1, sizeof (*ldr)); - ldr->open = wrap_open; - strlcpy(ldr->extensions, "js", sizeof (ldr->extensions)); - strlcpy(ldr->paths, IRCCD_LIBDIR "/irccd", sizeof (ldr->paths)); - - return ldr; -}
--- a/lib/irccd/js-plugin.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * js-plugin.h -- Javascript plugins - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_H -#define IRCCD_JS_PLUGIN_H - -#include <duktape.h> - -#include "plugin.h" - -struct irc_js_plugin_data { - struct irc_plugin plugin; - duk_context *ctx; - char **options; - char **templates; - char **paths; - char *license; - char *version; - char *author; - char *description; -}; - -struct irc_plugin * -irc_js_plugin_open(const char *); - -struct irc_plugin_loader * -irc_js_plugin_loader_new(void); - -#endif /* !IRCCD_JS_PLUGIN_H */
--- a/lib/irccd/jsapi-chrono.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * jsapi-chrono.c -- Irccd.Chrono API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <stdbool.h> -#include <time.h> - -#include <duktape.h> - -#include "util.h" - -#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Chrono") - -struct timer { - struct timespec start; -}; - -static struct timer * -self(duk_context *ctx) -{ - struct timer *self; - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, SIGNATURE); - self = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!self) - (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Chrono object"); - - return self; -} - -static duk_ret_t -Chrono_prototype_elapsed(duk_context *ctx) -{ - struct timer *timer = self(ctx); - struct timespec now = {0}; - - timespec_get(&now, TIME_UTC); - - duk_push_uint(ctx, - ((now.tv_sec * 1000) - (timer->start.tv_sec * 1000)) + - ((now.tv_nsec / 1000000) - (timer->start.tv_nsec / 1000000))); - - return 1; -} - -static duk_ret_t -Chrono_prototype_reset(duk_context *ctx) -{ - timespec_get(&self(ctx)->start, TIME_UTC); - - return 0; -} - -static duk_ret_t -Chrono_constructor(duk_context *ctx) -{ - struct timer *timer; - - timer = irc_util_calloc(1, sizeof (*timer)); - timespec_get(&timer->start, TIME_UTC); - - duk_push_this(ctx); - duk_push_pointer(ctx, timer); - duk_put_prop_string(ctx, -2, SIGNATURE); - - /* this.elapsed property. */ - duk_push_string(ctx, "elapsed"); - duk_push_c_function(ctx, Chrono_prototype_elapsed, 0); - duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - duk_pop(ctx); - - return 0; -} - -static duk_ret_t -Chrono_destructor(duk_context *ctx) -{ - duk_get_prop_string(ctx, 0, SIGNATURE); - free(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_del_prop_string(ctx, 0, SIGNATURE); - - return 0; -} - -static const duk_function_list_entry methods[] = { - { "reset", Chrono_prototype_reset, 0 }, - { NULL, NULL, 0 } -}; - -void -irc_jsapi_chrono_load(duk_context *ctx) -{ - duk_get_global_string(ctx, "Irccd"); - duk_push_c_function(ctx, Chrono_constructor, 0); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_push_c_function(ctx, Chrono_destructor, 1); - duk_set_finalizer(ctx, -2); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Chrono"); - duk_pop(ctx); -}
--- a/lib/irccd/jsapi-chrono.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * jsapi-chrono.h -- Irccd.Chrono API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_CHRONO_H -#define IRCCD_JSAPI_CHRONO_H - -#include <duktape.h> - -void -irc_jsapi_chrono_load(duk_context *); - -#endif /* !IRCCD_JSAPI_CHRONO_H */
--- a/lib/irccd/jsapi-directory.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,425 +0,0 @@ -/* - * jsapi-directory.c -- Irccd.Directory API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <sys/stat.h> -#include <assert.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <regex.h> -#include <stdbool.h> -#include <unistd.h> - -#if defined(_WIN32) -# include <windows.h> -#endif - -#include <duktape.h> - -#include "jsapi-system.h" - -enum { - LIST_DOT = (1 << 0), - LIST_DOT_DOT = (1 << 1) -}; - -struct cursor { - char path[PATH_MAX]; - char entry[FILENAME_MAX]; - bool recursive; - void *data; - bool (*fn)(const struct cursor *); -}; - -struct finder { - union { - const char *pattern; - regex_t regex; - }; - struct cursor curs; - void (*finish)(struct finder *); -}; - -static int -recursedir(int dirfd, struct cursor *cs) -{ - DIR *dp; - struct dirent *entry; - struct stat st; - size_t entrylen; - int childfd, ret = 0; - - if (!(dp = fdopendir(dirfd))) - return -1; - - while ((entry = readdir(dp))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - if (fstatat(dirfd, entry->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) - continue; - - entrylen = strlen(entry->d_name); - - /* - * Append full path for the given entry. - * e.g. /foo/bar/ -> /foo/bar/quux.txt - */ - strlcat(cs->path, entry->d_name, sizeof (cs->path)); - - /* Go recursively if it's a directory and activated. */ - if (S_ISDIR(st.st_mode) && cs->recursive) { - strlcat(cs->path, "/", sizeof (cs->path)); - - entrylen += 1; - - if ((childfd = openat(dirfd, entry->d_name, O_RDONLY | O_DIRECTORY)) < 0) - continue; - if ((ret = recursedir(childfd, cs))) { - close(childfd); - goto stop; - } - - close(childfd); - } - - strlcpy(cs->entry, entry->d_name, sizeof (cs->entry)); - - if (cs->fn(cs)) { - ret = 1; - goto stop; - } - - cs->path[strlen(cs->path) - entrylen] = '\0'; - } -stop: - closedir(dp); - - return ret; -} - -static int -recurse(const char *path, struct cursor *cs) -{ - int fd, ret; - size_t pathlen; - - if ((fd = open(path, O_RDONLY | O_DIRECTORY)) < 0) - return -1; - - pathlen = strlen(path); - - if (strlcpy(cs->path, path, sizeof (cs->path)) >= sizeof (cs->path)) - return errno = ENOMEM, -1; - if (cs->path[pathlen - 1] != '/' && strlcat(cs->path, "/", sizeof (cs->path)) >= sizeof (cs->path)) - return errno = ENOMEM, -1; - - ret = recursedir(fd, cs); - close(fd); - - return ret; -} - -static inline const char * -path(duk_context *ctx) -{ - const char *ret; - - 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"); - - ret = duk_get_string(ctx, -1); - - if (!ret || !ret[0]) - duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path"); - - duk_pop_n(ctx, 2); - - return ret; -} - -static bool -find_regex(const struct cursor *curs) -{ - const struct finder *fd = curs->data; - - return regexec(&fd->regex, curs->entry, 0, NULL, 0) == 0; -} - -static bool -find_name(const struct cursor *curs) -{ - const struct finder *fd = curs->data; - - return strcmp(curs->entry, fd->pattern) == 0; -} - -static void -find_regex_finish(struct finder *fd) -{ - regfree(&fd->regex); -} - -static int -find_helper(duk_context *ctx, const char *base, bool recursive, int pattern_index) -{ - struct finder finder = { - .curs = { - .recursive = recursive, - .data = &finder, - } - }; - int status; - - if (duk_is_string(ctx, pattern_index)) { - finder.pattern = duk_get_string(ctx, pattern_index); - finder.curs.fn = find_name; - } else { - /* Check if it's a RegExp object. */ - duk_get_global_string(ctx, "RegExp"); - - if (!duk_instanceof(ctx, pattern_index, -1)) - /* TODO: better error. */ - return duk_error(ctx, DUK_ERR_TYPE_ERROR, "pattern arg error"); - - duk_get_prop_string(ctx, pattern_index, "source"); - - if (regcomp(&finder.regex, duk_to_string(ctx, -1), REG_EXTENDED) != 0) - return duk_error(ctx, DUK_ERR_ERROR, "RegExp error"); - - finder.curs.fn = find_regex; - finder.finish = find_regex_finish; - duk_pop_n(ctx, 2); - } - - status = recurse(base, &finder.curs); - - if (finder.finish) - finder.finish(&finder); - - if (status == 1) - duk_push_string(ctx, finder.curs.path); - else - duk_push_null(ctx); - - return 1; -} - -static bool -rm(const struct cursor *curs) -{ - return remove(curs->path), false; -} - -static int -rm_helper(duk_context *ctx, const char *base, bool recursive) -{ - struct stat st; - struct cursor curs = { - .recursive = true, - .fn = rm - }; - - if (stat(base, &st) < 0) - return irc_jsapi_system_raise(ctx), 0; - else if (!S_ISDIR(st.st_mode)) { - errno = ENOTDIR; - return irc_jsapi_system_raise(ctx), 0; - } - - if (recursive) - recurse(base, &curs); - - remove(base); - - return 0; -} - -static inline void -mkpath(duk_context *ctx, const char *path) -{ -#ifdef _WIN32 - /* TODO: convert code to errno. */ - if (!CreateDirectoryA(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { - errno = EPERM; - irc_jsapi_system_raise(ctx); -#else - if (mkdir(path, 0755) < 0 && errno != EEXIST) - irc_jsapi_system_raise(ctx); -#endif -} - -static inline char * -normalize(char *str) -{ - for (char *p = str; *p; ++p) - if (*p == '\\') - *p = '/'; - - return str; -} - -static int -Directory_prototype_find(duk_context *ctx) -{ - return find_helper(ctx, path(ctx), duk_opt_boolean(ctx, 1, false), 0); -} - -static int -Directory_prototype_remove(duk_context *ctx) -{ - return rm_helper(ctx, path(ctx), duk_opt_boolean(ctx, 0, false)); -} - -static int -Directory_constructor(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - const int flags = duk_opt_int(ctx, 1, 0); - DIR *dp; - struct dirent *entry; - - if (!duk_is_constructor_call(ctx)) - return 0; - - duk_push_this(ctx); - - /* this.entries property. */ - duk_push_string(ctx, "entries"); - duk_push_array(ctx); - - if (!(dp = opendir(path))) - irc_jsapi_system_raise(ctx); - - for (int i = 0; (entry = readdir(dp)); ) { - if (strcmp(entry->d_name, ".") == 0 && !(flags & LIST_DOT)) - continue; - if (strcmp(entry->d_name, "..") == 0 && !(flags & LIST_DOT_DOT)) - continue; - - duk_push_object(ctx); - duk_push_string(ctx, entry->d_name); - duk_put_prop_string(ctx, -2, "name"); - duk_push_int(ctx, entry->d_type); - duk_put_prop_string(ctx, -2, "type"); - duk_put_prop_index(ctx, -2, i++); - } - - closedir(dp); - duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); - - /* this.path property. */ - duk_push_string(ctx, "path"); - duk_push_string(ctx, path); - duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); - duk_pop(ctx); - - return 0; -} - -static duk_ret_t -Directory_find(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - bool recursive = duk_opt_boolean(ctx, 2, false); - - return find_helper(ctx, path, recursive, 1); -} - -static duk_ret_t -Directory_remove(duk_context* ctx) -{ - return rm_helper(ctx, duk_require_string(ctx, 0), duk_opt_boolean(ctx, 1, false)); -} - -static duk_ret_t -Directory_mkdir(duk_context* ctx) -{ - char path[PATH_MAX], *p; - - /* Copy the directory to normalize and iterate over '/'. */ - strlcpy(path, duk_require_string(ctx, 0), sizeof (path)); - normalize(path); - -#if defined(_WIN32) - /* Remove drive letter that we don't need. */ - if ((p = strchr(path, ':'))) - ++p; - else - p = path; -#else - p = path; -#endif - - for (p = p + 1; *p; ++p) { - if (*p == '/') { - *p = 0; - mkpath(ctx, path); - *p = '/'; - } - } - - mkpath(ctx, path); - - return 0; -} - -static const duk_function_list_entry methods[] = { - { "find", Directory_prototype_find, DUK_VARARGS }, - { "remove", Directory_prototype_remove, 1 }, - { NULL, NULL, 0 } -}; - -static const duk_function_list_entry functions[] = { - { "find", Directory_find, DUK_VARARGS }, - { "mkdir", Directory_mkdir, DUK_VARARGS }, - { "remove", Directory_remove, DUK_VARARGS }, - { NULL, NULL, 0 } -}; - -static const duk_number_list_entry constants[] = { - { "Dot", LIST_DOT }, - { "DotDot", LIST_DOT_DOT }, - { "TypeFile", DT_REG }, - { "TypeDir", DT_DIR }, - { "TypeLink", DT_LNK }, - { "TypeBlock", DT_BLK }, - { "TypeCharacter", DT_CHR }, - { "TypeFifo", DT_FIFO }, - { "TypeSocket", DT_SOCK }, - { "TypeUnknown", DT_UNKNOWN }, - { NULL, 0 } -}; - -void -irc_jsapi_directory_load(duk_context *ctx) -{ - assert(ctx); - - duk_get_global_string(ctx, "Irccd"); - duk_push_c_function(ctx, Directory_constructor, 2); - duk_put_number_list(ctx, -1, constants); - duk_put_function_list(ctx, -1, functions); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Directory"); - duk_pop(ctx); -}
--- a/lib/irccd/jsapi-directory.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * jsapi-directory.h -- Irccd.Directory API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_DIRECTORY_H -#define IRCCD_JSAPI_DIRECTORY_H - -#include <duktape.h> - -void -irc_jsapi_directory_load(duk_context *); - -#endif /* !IRCCD_JSAPI_DIRECTORY_H */
--- a/lib/irccd/jsapi-file.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,519 +0,0 @@ -/* - * jsapi-file.c -- Irccd.File API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <sys/stat.h> -#include <assert.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> - -#include <duktape.h> - -#include "compat.h" -#include "jsapi-file.h" -#include "jsapi-system.h" -#include "util.h" - -#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.File") -#define PROTOTYPE DUK_HIDDEN_SYMBOL("Irccd.File.prototype") - -struct file { - char path[PATH_MAX]; - FILE *fp; - int (*finalizer)(FILE *); -}; - -static int -read_until_eof(duk_context *ctx, struct file *file) -{ - char *ret = NULL, *newret, buf[BUFSIZ]; - size_t retsz = 0, nread; - - /* - * This function is shared with popen which can not be used with stat - * so read the file by small piece of chunks and concat them until we - * reach the end. - */ - while ((nread = fread(buf, 1, sizeof (buf), file->fp)) > 0) { - if (!(newret = realloc(ret, retsz + nread))) { - free(ret); - irc_jsapi_system_raise(ctx); - } - - ret = newret; - memcpy(ret + retsz, buf, nread); - retsz += nread; - } - - if (ferror(file->fp)) { - free(ret); - irc_jsapi_system_raise(ctx); - } - - duk_push_lstring(ctx, ret, retsz); - free(ret); - - return 1; -} - -static int -read_amount(duk_context *ctx, struct file *file, unsigned int amount) -{ - char *ret; - size_t nread; - - if (!(ret = malloc(amount))) - irc_jsapi_system_raise(ctx); - - if ((nread = fread(ret, 1, amount, file->fp)) <= 0 || ferror(file->fp)) { - free(ret); - irc_jsapi_system_raise(ctx); - } - - duk_push_lstring(ctx, ret, nread); - free(ret); - - return 1; -} - -static void -push_stat(duk_context *ctx, const struct stat *st) -{ - duk_push_object(ctx); - -#if defined(COMPAT_HAVE_STAT_ST_ATIME) - duk_push_int(ctx, st->st_atime); - duk_put_prop_string(ctx, -2, "atime"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_BLKSIZE) - duk_push_int(ctx, st->st_blksize); - duk_put_prop_string(ctx, -2, "blksize"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_BLOCKS) - duk_push_int(ctx, st->st_blocks); - duk_put_prop_string(ctx, -2, "blocks"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_CTIME) - duk_push_int(ctx, st->st_ctime); - duk_put_prop_string(ctx, -2, "ctime"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_DEV) - duk_push_int(ctx, st->st_dev); - duk_put_prop_string(ctx, -2, "dev"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_GID) - duk_push_int(ctx, st->st_gid); - duk_put_prop_string(ctx, -2, "gid"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_INO) - duk_push_int(ctx, st->st_ino); - duk_put_prop_string(ctx, -2, "ino"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_MODE) - duk_push_int(ctx, st->st_mode); - duk_put_prop_string(ctx, -2, "mode"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_MTIME) - duk_push_int(ctx, st->st_mtime); - duk_put_prop_string(ctx, -2, "mtime"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_NLINK) - duk_push_int(ctx, st->st_nlink); - duk_put_prop_string(ctx, -2, "nlink"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_RDEV) - duk_push_int(ctx, st->st_rdev); - duk_put_prop_string(ctx, -2, "rdev"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_SIZE) - duk_push_int(ctx, st->st_size); - duk_put_prop_string(ctx, -2, "size"); -#endif -#if defined(COMPAT_HAVE_STAT_ST_UID) - duk_push_int(ctx, st->st_uid); - duk_put_prop_string(ctx, -2, "uid"); -#endif -} - -static struct file * -self(duk_context *ctx) -{ - struct file *file; - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, SIGNATURE); - file = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!file) - (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); - - return file; -} - -static duk_ret_t -File_prototype_basename(duk_context *ctx) -{ - const struct file *file = self(ctx); - - duk_push_string(ctx, irc_util_basename(file->path)); - - return 1; -} - -static duk_ret_t -File_prototype_close(duk_context *ctx) -{ - struct file *file = self(ctx); - - if (file->fp) { - file->finalizer(file->fp); - file->fp = NULL; - } - - return 0; -} - -static duk_ret_t -File_prototype_dirname(duk_context *ctx) -{ - const struct file *file = self(ctx); - - duk_push_string(ctx, irc_util_dirname(file->path)); - - return 1; -} - -static duk_ret_t -File_prototype_lines(duk_context *ctx) -{ - struct file *file = self(ctx); - char *line = NULL; - size_t linesz = 0; - - if (!file->fp) { - errno = EBADF; - irc_jsapi_system_raise(ctx); - } - - duk_push_array(ctx); - - for (int i = 0; getline(&line, &linesz, file->fp) >= 0; ++i) { - line[strcspn(line, "\r\n")] = 0; - - duk_push_string(ctx, line); - duk_put_prop_index(ctx, -2, i); - } - - free(line); - - if (ferror(file->fp)) - irc_jsapi_system_raise(ctx); - - return 1; -} - -static duk_ret_t -File_prototype_read(duk_context *ctx) -{ - struct file *file = self(ctx); - unsigned int amount = duk_opt_uint(ctx, 0, -1); - - if (!file->fp) { - errno = EBADF; - irc_jsapi_system_raise(ctx); - } - - return amount == -1U - ? read_until_eof(ctx, file) - : read_amount(ctx, file, amount); -} - -static duk_ret_t -File_prototype_readline(duk_context *ctx) -{ - const struct file *file = self(ctx); - char *line = NULL; - size_t linesz = 0; - - if (!file->fp) { - errno = EBADF; - irc_jsapi_system_raise(ctx); - } - - if (getline(&line, &linesz, file->fp) < 0) { - free(line); - - if (feof(file->fp)) - return 0; - - irc_jsapi_system_raise(ctx); - } - - line[strcspn(line, "\r\n")] = 0; - duk_push_string(ctx, line); - free(line); - - return 1; -} - -static duk_ret_t -File_prototype_remove(duk_context *ctx) -{ - if (remove(self(ctx)->path) < 0) - irc_jsapi_system_raise(ctx); - - return 0; -} - -static duk_ret_t -File_prototype_seek(duk_context *ctx) -{ - const struct file *file = self(ctx); - const int type = duk_require_int(ctx, 0); - const long offset = duk_require_int(ctx, 1); - - if (!file->fp || fseek(file->fp, offset, type) < 0) - irc_jsapi_system_raise(ctx); - - return 0; -} - -static duk_ret_t -File_prototype_stat(duk_context *ctx) -{ - const struct file *file = self(ctx); - struct stat st; - - if (!file->fp || fstat(fileno(file->fp), &st) < 0) - irc_jsapi_system_raise(ctx); - - push_stat(ctx, &st); - - return 0; -} - -static duk_ret_t -File_prototype_tell(duk_context *ctx) -{ - const struct file *file = self(ctx); - long position; - - if (!file->fp || (position = ftell(file->fp)) < 0) - return irc_jsapi_system_raise(ctx), 0; - - duk_push_number(ctx, position); - - return 1; -} - -static duk_ret_t -File_prototype_write(duk_context *ctx) -{ - const struct file *file = self(ctx); - size_t datasz = 0, written; - const char *data = duk_require_lstring(ctx, 0, &datasz); - - if (!file->fp) - irc_jsapi_system_raise(ctx); - - written = fwrite(data, 1, datasz, file->fp); - - if (ferror(file->fp)) - irc_jsapi_system_raise(ctx); - - duk_push_uint(ctx, written); - - return 1; -} - -static duk_ret_t -File_constructor(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - const char *mode = duk_require_string(ctx, 1); - FILE *fp; - struct file *file; - - if (!duk_is_constructor_call(ctx)) - return 0; - - if (!(fp = fopen(path, mode))) - irc_jsapi_system_raise(ctx); - - file = irc_util_calloc(1, sizeof (*file)); - file->fp = fp; - file->finalizer = fclose; - strlcpy(file->path, path, sizeof (file->path)); - - duk_push_this(ctx); - duk_push_pointer(ctx, file); - duk_put_prop_string(ctx, -2, SIGNATURE); - duk_pop(ctx); - - return 0; -} - -static duk_ret_t -File_destructor(duk_context *ctx) -{ - struct file *file; - - duk_get_prop_string(ctx, 0, SIGNATURE); - - if ((file = duk_to_pointer(ctx, -1)) && file->fp) { - file->finalizer(file->fp); - file->fp = NULL; - free(file); - } - - duk_pop(ctx); - duk_del_prop_string(ctx, 0, SIGNATURE); - - return 0; -} - -static duk_ret_t -File_basename(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - - duk_push_string(ctx, irc_util_basename(path)); - - return 1; -} - -static duk_ret_t -File_dirname(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - - duk_push_string(ctx, irc_util_dirname(path)); - - return 1; -} - -static duk_ret_t -File_exists(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - struct stat st; - - duk_push_boolean(ctx, stat(path, &st) == 0); - - return 1; -} - -static duk_ret_t -File_remove(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - - if (remove(path) < 0) - irc_jsapi_system_raise(ctx); - - return 0; -} - -static duk_ret_t -File_stat(duk_context *ctx) -{ - const char *path = duk_require_string(ctx, 0); - struct stat st; - - if (stat(path, &st) < 0) - irc_jsapi_system_raise(ctx); - - push_stat(ctx, &st); - - return 0; -} - -static const duk_function_list_entry methods[] = { - { "basename", File_prototype_basename, 0 }, - { "close", File_prototype_close, 0 }, - { "dirname", File_prototype_dirname, 0 }, - { "lines", File_prototype_lines, 0 }, - { "read", File_prototype_read, 1 }, - { "readline", File_prototype_readline, 0 }, - { "remove", File_prototype_remove, 0 }, - { "seek", File_prototype_seek, 2 }, - { "stat", File_prototype_stat, 0 }, - { "tell", File_prototype_tell, 0 }, - { "write", File_prototype_write, 1 }, - { NULL, NULL, 0 } -}; - -static const duk_function_list_entry functions[] = { - { "basename", File_basename, 1 }, - { "dirname", File_dirname, 1 }, - { "exists", File_exists, 1 }, - { "remove", File_remove, 1 }, - { "stat", File_stat, 1 }, - { NULL, NULL, 0 } -}; - -static const duk_number_list_entry constants[] = { - { "SeekCur", SEEK_CUR }, - { "SeekEnd", SEEK_END }, - { "SeekSet", SEEK_SET }, - { NULL, 0 } -}; - -void -irc_jsapi_file_load(duk_context *ctx) -{ - assert(ctx); - - duk_get_global_string(ctx, "Irccd"); - duk_push_c_function(ctx, File_constructor, 2); - duk_put_number_list(ctx, -1, constants); - duk_put_function_list(ctx, -1, functions); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_push_c_function(ctx, File_destructor, 1); - duk_set_finalizer(ctx, -2); - duk_dup(ctx, -1); - duk_put_global_string(ctx, PROTOTYPE); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "File"); - duk_pop(ctx); -} - -void -irc_jsapi_file_push(duk_context *ctx, const char *path, FILE *fp, int (*finalizer)(FILE *)) -{ - assert(ctx); - assert(fp); - assert(finalizer); - - struct file file = { - .fp = fp, - .finalizer = finalizer - }; - - if (path) - strlcpy(file.path, path, sizeof (file.path)); - - duk_push_object(ctx); - duk_push_pointer(ctx, irc_util_memdup(&file, sizeof (file))); - duk_put_prop_string(ctx, -2, SIGNATURE); - duk_get_global_string(ctx, PROTOTYPE); - duk_set_prototype(ctx, -2); -}
--- a/lib/irccd/jsapi-file.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * jsapi-file.h -- Irccd.File API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_FILE_H -#define IRCCD_JSAPI_FILE_H - -#include <duktape.h> - -void -irc_jsapi_file_load(duk_context *); - -void -irc_jsapi_file_push(duk_context *, const char *, FILE *, int (*)(FILE *)); - -#endif /* !IRCCD_JSAPI_FILE_H */
--- a/lib/irccd/jsapi-irccd.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,333 +0,0 @@ -/* - * jsapi-irccd.c -- Irccd API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <errno.h> -#include <string.h> - -#include <duktape.h> - -#include "config.h" -#include "util.h" - -static int -SystemError_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; -} - -/* {{{ Constants for errno. */ - -static const struct { - const char *name; - int value; -} errors[] = { -#if defined(E2BIG) - { "E2BIG", E2BIG }, -#endif -#if defined(EACCES) - { "EACCES", EACCES }, -#endif -#if defined(EADDRINUSE) - { "EADDRINUSE", EADDRINUSE }, -#endif -#if defined(EADDRNOTAVAIL) - { "EADDRNOTAVAIL", EADDRNOTAVAIL }, -#endif -#if defined(EAFNOSUPPORT) - { "EAFNOSUPPORT", EAFNOSUPPORT }, -#endif -#if defined(EAGAIN) - { "EAGAIN", EAGAIN }, -#endif -#if defined(EALREADY) - { "EALREADY", EALREADY }, -#endif -#if defined(EBADF) - { "EBADF", EBADF }, -#endif -#if defined(EBADMSG) - { "EBADMSG", EBADMSG }, -#endif -#if defined(EBUSY) - { "EBUSY", EBUSY }, -#endif -#if defined(ECANCELED) - { "ECANCELED", ECANCELED }, -#endif -#if defined(ECHILD) - { "ECHILD", ECHILD }, -#endif -#if defined(ECONNABORTED) - { "ECONNABORTED", ECONNABORTED }, -#endif -#if defined(ECONNREFUSED) - { "ECONNREFUSED", ECONNREFUSED }, -#endif -#if defined(ECONNREFUSED) - { "ECONNRESET", ECONNRESET }, -#endif -#if defined(EDEADLK) - { "EDEADLK", EDEADLK }, -#endif -#if defined(EDESTADDRREQ) - { "EDESTADDRREQ", EDESTADDRREQ }, -#endif -#if defined(EDOM) - { "EDOM", EDOM }, -#endif -#if defined(EEXIST) - { "EEXIST", EEXIST }, -#endif -#if defined(EFAULT) - { "EFAULT", EFAULT }, -#endif -#if defined(EFBIG) - { "EFBIG", EFBIG }, -#endif -#if defined(EHOSTUNREACH) - { "EHOSTUNREACH", EHOSTUNREACH }, -#endif -#if defined(EIDRM) - { "EIDRM", EIDRM }, -#endif -#if defined(EILSEQ) - { "EILSEQ", EILSEQ }, -#endif -#if defined(EINPROGRESS) - { "EINPROGRESS", EINPROGRESS }, -#endif -#if defined(EINTR) - { "EINTR", EINTR }, -#endif -#if defined(EINVAL) - { "EINVAL", EINVAL }, -#endif -#if defined(EIO) - { "EIO", EIO }, -#endif -#if defined(EISCONN) - { "EISCONN", EISCONN }, -#endif -#if defined(EISDIR) - { "EISDIR", EISDIR }, -#endif -#if defined(ELOOP) - { "ELOOP", ELOOP }, -#endif -#if defined(EMFILE) - { "EMFILE", EMFILE }, -#endif -#if defined(EMLINK) - { "EMLINK", EMLINK }, -#endif -#if defined(EMSGSIZE) - { "EMSGSIZE", EMSGSIZE }, -#endif -#if defined(ENAMETOOLONG) - { "ENAMETOOLONG", ENAMETOOLONG }, -#endif -#if defined(ENETDOWN) - { "ENETDOWN", ENETDOWN }, -#endif -#if defined(ENETRESET) - { "ENETRESET", ENETRESET }, -#endif -#if defined(ENETUNREACH) - { "ENETUNREACH", ENETUNREACH }, -#endif -#if defined(ENFILE) - { "ENFILE", ENFILE }, -#endif -#if defined(ENOBUFS) - { "ENOBUFS", ENOBUFS }, -#endif -#if defined(ENODATA) - { "ENODATA", ENODATA }, -#endif -#if defined(ENODEV) - { "ENODEV", ENODEV }, -#endif -#if defined(ENOENT) - { "ENOENT", ENOENT }, -#endif -#if defined(ENOEXEC) - { "ENOEXEC", ENOEXEC }, -#endif -#if defined(ENOLCK) - { "ENOLCK", ENOLCK }, -#endif -#if defined(ENOLINK) - { "ENOLINK", ENOLINK }, -#endif -#if defined(ENOMEM) - { "ENOMEM", ENOMEM }, -#endif -#if defined(ENOMSG) - { "ENOMSG", ENOMSG }, -#endif -#if defined(ENOPROTOOPT) - { "ENOPROTOOPT", ENOPROTOOPT }, -#endif -#if defined(ENOSPC) - { "ENOSPC", ENOSPC }, -#endif -#if defined(ENOSR) - { "ENOSR", ENOSR }, -#endif -#if defined(ENOSTR) - { "ENOSTR", ENOSTR }, -#endif -#if defined(ENOSYS) - { "ENOSYS", ENOSYS }, -#endif -#if defined(ENOTCONN) - { "ENOTCONN", ENOTCONN }, -#endif -#if defined(ENOTDIR) - { "ENOTDIR", ENOTDIR }, -#endif -#if defined(ENOTEMPTY) - { "ENOTEMPTY", ENOTEMPTY }, -#endif -#if defined(ENOTRECOVERABLE) - { "ENOTRECOVERABLE", ENOTRECOVERABLE }, -#endif -#if defined(ENOTSOCK) - { "ENOTSOCK", ENOTSOCK }, -#endif -#if defined(ENOTSUP) - { "ENOTSUP", ENOTSUP }, -#endif -#if defined(ENOTTY) - { "ENOTTY", ENOTTY }, -#endif -#if defined(ENXIO) - { "ENXIO", ENXIO }, -#endif -#if defined(EOPNOTSUPP) - { "EOPNOTSUPP", EOPNOTSUPP }, -#endif -#if defined(EOVERFLOW) - { "EOVERFLOW", EOVERFLOW }, -#endif -#if defined(EOWNERDEAD) - { "EOWNERDEAD", EOWNERDEAD }, -#endif -#if defined(EPERM) - { "EPERM", EPERM }, -#endif -#if defined(EPIPE) - { "EPIPE", EPIPE }, -#endif -#if defined(EPROTO) - { "EPROTO", EPROTO }, -#endif -#if defined(EPROTONOSUPPORT) - { "EPROTONOSUPPORT", EPROTONOSUPPORT }, -#endif -#if defined(EPROTOTYPE) - { "EPROTOTYPE", EPROTOTYPE }, -#endif -#if defined(ERANGE) - { "ERANGE", ERANGE }, -#endif -#if defined(EROFS) - { "EROFS", EROFS }, -#endif -#if defined(ESPIPE) - { "ESPIPE", ESPIPE }, -#endif -#if defined(ESRCH) - { "ESRCH", ESRCH }, -#endif -#if defined(ETIME) - { "ETIME", ETIME }, -#endif -#if defined(ETIMEDOUT) - { "ETIMEDOUT", ETIMEDOUT }, -#endif -#if defined(ETXTBSY) - { "ETXTBSY", ETXTBSY }, -#endif -#if defined(EWOULDBLOCK) - { "EWOULDBLOCK", EWOULDBLOCK }, -#endif -#if defined(EXDEV) - { "EXDEV", EXDEV } -#endif -}; - -/* }}} */ - -static int -print(duk_context *ctx) -{ - puts(duk_require_string(ctx, 0)); - - return 0; -} - -void -irc_jsapi_load(duk_context *ctx) -{ - /* Irccd (global object) */ - duk_push_object(ctx); - - /* Irccd.version (property) */ - duk_push_object(ctx); - duk_push_int(ctx, IRCCD_VERSION_MAJOR); - duk_put_prop_string(ctx, -2, "major"); - duk_push_int(ctx, IRCCD_VERSION_MINOR); - duk_put_prop_string(ctx, -2, "minor"); - duk_push_int(ctx, IRCCD_VERSION_PATCH); - duk_put_prop_string(ctx, -2, "patch"); - duk_put_prop_string(ctx, -2, "version"); - - /* Create the system_error that inherits from Error. */ - duk_push_c_function(ctx, SystemError_constructor, 2); - - /* Put errno codes into the Irccd.SystemError object. */ - for (size_t i = 0; i < IRC_UTIL_SIZE(errors); ++i) { - duk_push_int(ctx, errors[i].value); - duk_put_prop_string(ctx, -2, errors[i].name); - } - - duk_push_object(ctx); - duk_get_global_string(ctx, "Error"); - duk_get_prop_string(ctx, -1, "prototype"); - duk_remove(ctx, -2); - duk_set_prototype(ctx, -2); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "SystemError"); - - /* Set Irccd as global. */ - duk_put_global_string(ctx, "Irccd"); - - /* Convenient global "print" function. */ - duk_push_c_function(ctx, print, 1); - duk_put_global_string(ctx, "print"); -}
--- a/lib/irccd/jsapi-irccd.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * jsapi-irccd.h -- Irccd API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_IRCCD_H -#define IRCCD_JSAPI_IRCCD_H - -#include <duktape.h> - -void -irc_jsapi_load(duk_context *); - -#endif /* !IRCCD_JSAPI_IRCCD_H */
--- a/lib/irccd/jsapi-logger.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * jsapi-logger.c -- Irccd.Logger API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <duktape.h> - -#include "jsapi-logger.h" -#include "jsapi-plugin.h" -#include "plugin.h" -#include "log.h" - -#define LOG(c, f) \ -do { \ - const struct irc_plugin *p = irc_jsapi_plugin_self(c); \ - const char *message = duk_require_string(c, 0); \ - \ - f("plugin %s: %s", p->name, message); \ -} while (0) \ - -static duk_ret_t -Logger_info(duk_context *ctx) -{ - LOG(ctx, irc_log_info); - - return 0; -} - -static duk_ret_t -Logger_warning(duk_context *ctx) -{ - LOG(ctx, irc_log_warn); - - return 0; -} - -static duk_ret_t -Logger_debug(duk_context *ctx) -{ - LOG(ctx, irc_log_debug); - - return 0; -} - -static const duk_function_list_entry functions[] = { - { "info", Logger_info, 1 }, - { "warning", Logger_warning, 1 }, - { "debug", Logger_debug, 1 }, - { NULL, NULL, 0 } -}; - -void -irc_jsapi_logger_load(duk_context *ctx) -{ - duk_get_global_string(ctx, "Irccd"); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, functions); - duk_put_prop_string(ctx, -2, "Logger"); - duk_pop(ctx); -}
--- a/lib/irccd/jsapi-logger.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * jsapi-logger.h -- Irccd.Logger API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_LOGGER_H -#define IRCCD_JSAPI_LOGGER_H - -#include <duktape.h> - -void -irc_jsapi_logger_load(duk_context *); - -#endif /* !IRCCD_JSAPI_LOGGER_H */
--- a/lib/irccd/jsapi-plugin.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -/* - * jsapi-plugin.c -- Irccd.Plugin API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <stdbool.h> - -#include "irccd.h" -#include "jsapi-plugin.h" -#include "plugin.h" - -#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Plugin") - -/* - * set - * ------------------------------------------------------------------ - * - * This setter is used to replace the Irccd.Plugin.(config|templates|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 'templates' 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 sets: - * - * mode = "hard" - * path = "/var" - * - * The final user table looks like this: - * - * Irccd.Plugin.config = { - * mode: "hard", - * level: "123", - * path: "/var" - * }; - */ -static duk_ret_t -set(duk_context *ctx, const char *name) -{ - /* This is the object received in argument from the property setter. */ - if (!duk_is_object(ctx, 0)) - return duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name); - - /* Merge old table with new one. */ - duk_get_global_string(ctx, name); - 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); - - return 0; -} - -/* - * get - * ------------------------------------------------------------------ - * - * Get the Irccd.Plugin.(config|templates|paths) property. - */ -static duk_ret_t -get(duk_context *ctx, const char *name) -{ - duk_get_global_string(ctx, name); - - return 1; -} - -static duk_ret_t -set_config(duk_context *ctx) -{ - return set(ctx, IRC_JSAPI_PLUGIN_PROP_OPTIONS); -} - -static duk_ret_t -get_config(duk_context *ctx) -{ - return get(ctx, IRC_JSAPI_PLUGIN_PROP_OPTIONS); -} - -static duk_ret_t -set_template(duk_context *ctx) -{ - return set(ctx, IRC_JSAPI_PLUGIN_PROP_TEMPLATES); -} - -static duk_ret_t -get_template(duk_context *ctx) -{ - return get(ctx, IRC_JSAPI_PLUGIN_PROP_TEMPLATES); -} - -static duk_ret_t -set_paths(duk_context *ctx) -{ - return set(ctx, IRC_JSAPI_PLUGIN_PROP_PATHS); -} - -static duk_ret_t -get_paths(duk_context *ctx) -{ - return get(ctx, IRC_JSAPI_PLUGIN_PROP_PATHS); -} - -static struct irc_plugin * -find(duk_context *ctx) -{ - const char *name = duk_require_string(ctx, 0); - struct irc_plugin *plg = irc_bot_plugin_get(name); - - if (!plg) - (void)duk_error(ctx, DUK_ERR_REFERENCE_ERROR, "plugin %s not found", name); - - return plg; -} - -static duk_ret_t -Plugin_info(duk_context *ctx) -{ - struct irc_plugin *p; - - if (duk_get_top(ctx) >= 1) - p = find(ctx); - else - p = irc_jsapi_plugin_self(ctx); - - if (!p) - return 0; - - duk_push_object(ctx); - duk_push_string(ctx, p->author); - duk_put_prop_string(ctx, -2, "author"); - duk_push_string(ctx, p->license); - duk_put_prop_string(ctx, -2, "license"); - duk_push_string(ctx, p->description); - duk_put_prop_string(ctx, -2, "summary"); - duk_push_string(ctx, p->version); - duk_put_prop_string(ctx, -2, "version"); - - return 1; -} - -static duk_ret_t -Plugin_list(duk_context *ctx) -{ - size_t i = 0; - struct irc_plugin *p; - - duk_push_array(ctx); - - LIST_FOREACH(p, &irc.plugins, link) { - duk_push_string(ctx, p->name); - duk_put_prop_index(ctx, -2, i++); - } - - return 1; -} - -static duk_ret_t -Plugin_load(duk_context *ctx) -{ - (void)ctx; - - return 0; -} - -static duk_ret_t -Plugin_reload(duk_context *ctx) -{ - irc_plugin_reload(find(ctx)); - - return 0; -} - -static duk_ret_t -Plugin_unload(duk_context *ctx) -{ - /* Use find so it can raise ReferenceError if not found. */ - irc_bot_plugin_remove(find(ctx)->name); - - return 0; -} - -static const duk_function_list_entry functions[] = { - { "info", Plugin_info, DUK_VARARGS }, - { "list", Plugin_list, 0 }, - { "load", Plugin_load, 1 }, - { "reload", Plugin_reload, 1 }, - { "unload", Plugin_unload, 1 }, - { NULL, NULL, 0 } -}; - -void -irc_jsapi_plugin_load(duk_context *ctx, struct irc_plugin *p) -{ - /* Store plugin. */ - duk_push_pointer(ctx, p); - duk_put_global_string(ctx, SIGNATURE); - - duk_get_global_string(ctx, "Irccd"); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, functions); - - /* 'config' property. */ - duk_push_string(ctx, "config"); - duk_push_c_function(ctx, get_config, 0); - duk_push_c_function(ctx, set_config, 1); - duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); - - /* 'templates' property. */ - duk_push_string(ctx, "templates"); - duk_push_c_function(ctx, get_template, 0); - duk_push_c_function(ctx, set_template, 1); - duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); - - /* 'paths' property. */ - duk_push_string(ctx, "paths"); - duk_push_c_function(ctx, get_paths, 0); - duk_push_c_function(ctx, set_paths, 1); - duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); - - duk_put_prop_string(ctx, -2, "Plugin"); - duk_pop(ctx); -} - -struct irc_plugin * -irc_jsapi_plugin_self(duk_context *ctx) -{ - struct irc_plugin *p; - - duk_get_global_string(ctx, SIGNATURE); - p = duk_to_pointer(ctx, -1); - duk_pop(ctx); - - return p; -}
--- a/lib/irccd/jsapi-plugin.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * jsapi-plugin.h -- Javascript plugins - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_PLUGIN_H -#define IRCCD_JSAPI_PLUGIN_H - -#include <duktape.h> - -#define IRC_JSAPI_PLUGIN_PROP_OPTIONS DUK_HIDDEN_SYMBOL("options") -#define IRC_JSAPI_PLUGIN_PROP_TEMPLATES DUK_HIDDEN_SYMBOL("templates") -#define IRC_JSAPI_PLUGIN_PROP_PATHS DUK_HIDDEN_SYMBOL("paths") - -struct irc_plugin; - -void -irc_jsapi_plugin_load(duk_context *, struct irc_plugin *); - -struct irc_plugin * -irc_jsapi_plugin_self(duk_context *); - -#endif /* !IRCCD_JSAPI_PLUGIN_H */
--- a/lib/irccd/jsapi-server.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,600 +0,0 @@ -/* - * jsapi-server.c -- Irccd.Server API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <assert.h> - -#include <duktape.h> - -#include "channel.h" -#include "irccd.h" -#include "jsapi-server.h" -#include "server.h" -#include "util.h" - -#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Server") -#define PROTOTYPE DUK_HIDDEN_SYMBOL("Irccd.Server.prototype") - -static struct irc_server * -self(duk_context *ctx) -{ - struct irc_server *sv; - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, SIGNATURE); - sv = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!sv) - (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); - - return sv; -} - -static struct irc_server * -require(duk_context *ctx, duk_idx_t index) -{ - struct irc_server *sv; - - if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, SIGNATURE)) - (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); - - duk_get_prop_string(ctx, index, SIGNATURE); - sv = duk_to_pointer(ctx, -1); - duk_pop(ctx); - - return sv; -} - -static inline unsigned short -get_port(duk_context *ctx) -{ - unsigned short port; - - duk_get_prop_string(ctx, 0, "port"); - - if (!duk_is_number(ctx, -1)) - (void)duk_error(ctx, DUK_ERR_ERROR, "invalid 'port' property"); - - port = duk_to_int(ctx, -1); - duk_pop(ctx); - - return port; -} - -static inline const char * -get_string(duk_context *ctx, const char *n) -{ - const char *ret; - - duk_get_prop_string(ctx, 0, n); - - if (!duk_is_string(ctx, -1)) - (void)duk_error(ctx, DUK_ERR_ERROR, "invalid or missing '%s' property", n); - - ret = duk_to_string(ctx, -1); - duk_pop(ctx); - - return ret; -} - -static inline void -get_ip(duk_context *ctx, struct irc_server *s) -{ - enum irc_server_flags flags = IRC_SERVER_FLAGS_IPV4 | - IRC_SERVER_FLAGS_IPV6; - - duk_get_prop_string(ctx, 0, "ipv4"); - duk_get_prop_string(ctx, 0, "ipv6"); - - if (duk_is_boolean(ctx, -1) && !duk_to_boolean(ctx, -1)) - flags &= ~(IRC_SERVER_FLAGS_IPV4); - if (duk_is_boolean(ctx, -2) && !duk_to_boolean(ctx, -2)) - flags &= ~(IRC_SERVER_FLAGS_IPV6); - - s->flags |= flags; - duk_pop_n(ctx, 2); -} - -static inline void -get_ssl(duk_context *ctx, struct irc_server *s) -{ - duk_get_prop_string(ctx, 0, "ssl"); - - if (duk_is_boolean(ctx, -1) && duk_to_boolean(ctx, -1)) - s->flags |= IRC_SERVER_FLAGS_SSL; - - duk_pop(ctx); -} - -static inline void -get_channels(duk_context *ctx, struct irc_server *s) -{ - duk_get_prop_string(ctx, 0, "channels"); - - for (duk_enum(ctx, -1, 0); duk_next(ctx, -1, true); ) { - duk_get_prop_string(ctx, -1, "name"); - duk_get_prop_string(ctx, -2, "password"); - - if (!duk_is_string(ctx, -2)) - (void)duk_error(ctx, DUK_ERR_ERROR, "invalid channel 'name' property"); - - irc_server_join(s, duk_to_string(ctx, -2), duk_opt_string(ctx, -1, NULL)); - duk_pop_n(ctx, 4); - } - - duk_pop_n(ctx, 2); -} - -static duk_ret_t -Server_prototype_info(duk_context *ctx) -{ - const struct irc_server *s = self(ctx); - const struct irc_channel *c; - const struct irc_channel_user *u; - size_t ci = 0, ui = 0; - - duk_push_object(ctx); - duk_push_string(ctx, s->name); - duk_put_prop_string(ctx, -2, "name"); - duk_push_string(ctx, s->conn.hostname); - duk_put_prop_string(ctx, -2, "hostname"); - duk_push_uint(ctx, s->conn.port); - duk_put_prop_string(ctx, -2, "port"); - duk_push_boolean(ctx, s->flags & IRC_SERVER_FLAGS_SSL); - duk_put_prop_string(ctx, -2, "ssl"); - duk_push_string(ctx, s->commandchar); - duk_put_prop_string(ctx, -2, "commandChar"); - duk_push_string(ctx, s->ident.realname); - duk_put_prop_string(ctx, -2, "realname"); - duk_push_string(ctx, s->ident.nickname); - duk_put_prop_string(ctx, -2, "nickname"); - duk_push_string(ctx, s->ident.username); - duk_put_prop_string(ctx, -2, "username"); - - duk_push_array(ctx); - - LIST_FOREACH(c, &s->channels, link) { - duk_push_object(ctx); - duk_push_string(ctx, c->name); - duk_put_prop_string(ctx, -2, "name"); - duk_push_boolean(ctx, c->joined); - duk_put_prop_string(ctx, -2, "joined"); - duk_push_array(ctx); - - LIST_FOREACH(u, &c->users, link) { - duk_push_object(ctx); - duk_push_string(ctx, u->nickname); - duk_put_prop_string(ctx, -2, "nickname"); - if (u->mode) - duk_push_sprintf(ctx, "%c", u->mode); - else - duk_push_null(ctx); - duk_put_prop_string(ctx, -2, "mode"); - duk_put_prop_index(ctx, -2, ui++); - } - - duk_put_prop_string(ctx, -2, "users"); - duk_put_prop_index(ctx, -2, ci++); - } - - duk_put_prop_string(ctx, -2, "channels"); - - return 1; -} - -static duk_ret_t -Server_prototype_invite(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *target = duk_require_string(ctx, 0); - const char *channel = duk_require_string(ctx, 1); - -#if 0 - if (!*target || !*channel) - throw server_error(server_error::invalid_nickname); - if (channel.empty()) - throw server_error(server_error::invalid_channel); -#endif - - duk_push_boolean(ctx, irc_server_invite(s, target, channel)); - - return 1; -} - -static duk_ret_t -Server_prototype_isSelf(duk_context *ctx) -{ - (void)ctx; -#if 0 - return wrap(ctx, [] (auto ctx) { - return duk::push(ctx, self(ctx)->is_self(duk::require<std::string>(ctx, 0))); - }); -#endif - - return 0; -} - -static duk_ret_t -Server_prototype_join(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *channel = duk_require_string(ctx, 0); - const char *password = duk_opt_string(ctx, 1, NULL); - -#if 0 - if (channel.empty()) - throw server_error(server_error::invalid_channel); -#endif - - duk_push_boolean(ctx, irc_server_join(s, channel, password)); - - return 1; -} - -static duk_ret_t -Server_prototype_kick(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *target = duk_require_string(ctx, 0); - const char *channel = duk_require_string(ctx, 1); - const char *reason = duk_opt_string(ctx, 2, NULL); - -#if 0 - if (target.empty()) - throw server_error(server_error::invalid_nickname); - if (channel.empty()) - throw server_error(server_error::invalid_channel); -#endif - - duk_push_boolean(ctx, irc_server_kick(s, target, channel, reason)); - - return 1; -} - -static duk_ret_t -Server_prototype_me(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *target = duk_require_string(ctx, 0); - const char *message = duk_require_string(ctx, 1); - -#if 0 - if (target.empty()) - throw server_error(server_error::invalid_nickname); -#endif - - duk_push_boolean(ctx, irc_server_me(s, target, message)); - - return 1; -} - -static duk_ret_t -Server_prototype_message(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *target = duk_require_string(ctx, 0); - const char *message = duk_require_string(ctx, 1); - -#if 0 - if (target.empty()) - throw server_error(server_error::invalid_nickname); -#endif - - duk_push_boolean(ctx, irc_server_message(s, target, message)); - - return 1; -} - -static duk_ret_t -Server_prototype_mode(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *channel = duk_require_string(ctx, 0); - const char *mode = duk_require_string(ctx, 1); - const char *limit = duk_opt_string(ctx, 2, NULL); - const char *user = duk_opt_string(ctx, 3, NULL); - const char *mask = duk_opt_string(ctx, 4, NULL); - -#if 0 - if (channel.empty()) - throw server_error(server_error::invalid_channel); - if (mode.empty()) - throw server_error(server_error::invalid_mode); -#endif - - duk_push_boolean(ctx, irc_server_mode(s, channel, mode, limit, user, mask)); - - return 1; -} - -static duk_ret_t -Server_prototype_names(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *channel = duk_require_string(ctx, 0); - -#if 0 - if (channel.empty()) - throw server_error(server_error::invalid_channel); -#endif - - duk_push_boolean(ctx, irc_server_names(s, channel)); - - return 1; -} - -static duk_ret_t -Server_prototype_nick(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *nickname = duk_require_string(ctx, 0); - -#if 0 - if (nickname.empty()) - throw server_error(server_error::invalid_nickname); -#endif - - duk_push_boolean(ctx, irc_server_nick(s, nickname)); - - return 1; -} - -static duk_ret_t -Server_prototype_notice(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *target = duk_require_string(ctx, 0); - const char *message = duk_opt_string(ctx, 1, NULL); - -#if 0 - if (target.empty()) - throw server_error(server_error::invalid_nickname); -#endif - - duk_push_boolean(ctx, irc_server_notice(s, target, message)); - - return 1; -} - -static duk_ret_t -Server_prototype_part(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *channel = duk_require_string(ctx, 0); - const char *reason = duk_opt_string(ctx, 1, NULL); - -#if 0 - if (channel.empty()) - throw server_error(server_error::invalid_channel); -#endif - - duk_push_boolean(ctx, irc_server_part(s, channel, reason)); - - return 1; -} - -static duk_ret_t -Server_prototype_send(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *raw = duk_require_string(ctx, 0); - -#if 0 - if (raw.empty()) - throw server_error(server_error::invalid_message); -#endif - - duk_push_boolean(ctx, irc_server_send(s, raw)); - - return 1; -} - -static duk_ret_t -Server_prototype_topic(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *channel = duk_require_string(ctx, 0); - const char *topic = duk_require_string(ctx, 1); - -#if 0 - if (channel.empty()) - throw server_error(server_error::invalid_channel); -#endif - - duk_push_boolean(ctx, irc_server_topic(s, channel, topic)); - - return 1; -} - -static duk_ret_t -Server_prototype_whois(duk_context *ctx) -{ - struct irc_server *s = self(ctx); - const char *target = duk_require_string(ctx, 0); - -#if 0 - if (target.empty()) - throw server_error(server_error::invalid_nickname); -#endif - - duk_push_boolean(ctx, irc_server_whois(s, target)); - - return 1; -} - -static duk_ret_t -Server_prototype_toString(duk_context *ctx) -{ - duk_push_string(ctx, self(ctx)->name); - - return 1; -} - -static duk_ret_t -Server_constructor(duk_context *ctx) -{ - struct irc_server *s; - - duk_require_object(ctx, 0); - - s = irc_server_new( - get_string(ctx, "name"), - get_string(ctx, "nickname"), - get_string(ctx, "username"), - get_string(ctx, "realname"), - get_string(ctx, "hostname"), - get_port(ctx) - ); - - get_ip(ctx, s); - get_ssl(ctx, s); - get_channels(ctx, s); - - irc_server_incref(s); - - duk_push_this(ctx); - duk_push_pointer(ctx, s); - duk_put_prop_string(ctx, -2, SIGNATURE); - duk_pop(ctx); - - return 0; -} - -static duk_ret_t -Server_destructor(duk_context *ctx) -{ - struct irc_server *sv; - - duk_get_prop_string(ctx, 0, SIGNATURE); - - if ((sv = duk_to_pointer(ctx, -1))) - irc_server_decref(sv); - - duk_pop(ctx); - duk_del_prop_string(ctx, 0, SIGNATURE); - - return 0; -} - -static duk_ret_t -Server_add(duk_context *ctx) -{ - irc_bot_server_add(require(ctx, 0)); - - return 0; -} - -static duk_ret_t -Server_find(duk_context *ctx) -{ - const char *name = duk_require_string(ctx, 0); - struct irc_server *s = irc_bot_server_find(name); - - if (!s) - return 0; - - irc_jsapi_server_push(ctx, s); - - return 1; -} - -static duk_ret_t -Server_list(duk_context *ctx) -{ - struct irc_server *s; - - duk_push_object(ctx); - - LIST_FOREACH(s, &irc.servers, link) { - irc_jsapi_server_push(ctx, s); - duk_put_prop_string(ctx, -2, s->name); - } - - return 1; -} - -static duk_ret_t -Server_remove(duk_context *ctx) -{ - irc_bot_server_remove(duk_require_string(ctx, 0)); - - return 0; -} - -static const duk_function_list_entry methods[] = { - { "info", Server_prototype_info, 0 }, - { "invite", Server_prototype_invite, 2 }, - { "isSelf", Server_prototype_isSelf, 1 }, - { "join", Server_prototype_join, DUK_VARARGS }, - { "kick", Server_prototype_kick, DUK_VARARGS }, - { "me", Server_prototype_me, 2 }, - { "message", Server_prototype_message, 2 }, - { "mode", Server_prototype_mode, 1 }, - { "names", Server_prototype_names, 1 }, - { "nick", Server_prototype_nick, 1 }, - { "notice", Server_prototype_notice, 2 }, - { "part", Server_prototype_part, DUK_VARARGS }, - { "send", Server_prototype_send, 1 }, - { "topic", Server_prototype_topic, 2 }, - { "toString", Server_prototype_toString, 0 }, - { "whois", Server_prototype_whois, 1 }, - { NULL, NULL, 0 } -}; - -static const duk_function_list_entry functions[] = { - { "add", Server_add, 1 }, - { "find", Server_find, 1 }, - { "list", Server_list, 0 }, - { "remove", Server_remove, 1 }, - { NULL, NULL, 0 } -}; - -void -irc_jsapi_server_load(duk_context *ctx) -{ - assert(ctx); - - duk_get_global_string(ctx, "Irccd"); - - duk_push_c_function(ctx, Server_constructor, 1); - duk_put_function_list(ctx, -1, functions); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_push_c_function(ctx, Server_destructor, 1); - duk_set_finalizer(ctx, -2); - duk_dup_top(ctx); - duk_put_global_string(ctx, PROTOTYPE); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Server"); - duk_pop(ctx); -} - -void -irc_jsapi_server_push(duk_context *ctx, struct irc_server *s) -{ - assert(ctx); - assert(s); - - irc_server_incref(s); - - duk_push_object(ctx); - duk_push_pointer(ctx, s); - duk_put_prop_string(ctx, -2, SIGNATURE); - duk_get_global_string(ctx, PROTOTYPE); - duk_set_prototype(ctx, -2); -}
--- a/lib/irccd/jsapi-server.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * jsapi-server.c -- Irccd.Server API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_SERVER_H -#define IRCCD_JSAPI_SERVER_H - -#include <duktape.h> - -struct irc_server; - -void -irc_jsapi_server_push(duk_context *, struct irc_server *); - -void -irc_jsapi_server_load(duk_context *); - -#endif /* IRCCD_JSAPI_SERVER_H */
--- a/lib/irccd/jsapi-system.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,250 +0,0 @@ -/* - * jsapi-system.c -- Irccd.System API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#if defined(_WIN32) -# include <windows.h> -#elif defined(__linux__) -# include <sys/sysinfo.h> -#elif defined(__APPLE__) -# include <sys/types.h> -# include <sys/sysctl.h> -#endif - -#if !defined(_WIN32) -# include <sys/utsname.h> -#endif - -#include <duktape.h> - -#include "jsapi-file.h" -#include "jsapi-system.h" - -static duk_ret_t -nsleep(unsigned long ns) -{ - struct timespec ts = { - .tv_sec = ns / 1000000000L, - .tv_nsec = (ns % 1000000000L), - }; - - while (nanosleep(&ts, &ts) && errno == EINTR); - - return 0; -} - -static duk_ret_t -System_env(duk_context *ctx) -{ - const char *name = duk_require_string(ctx, 0); - const char *value = getenv(name); - - if (!value) - duk_push_null(ctx); - else - duk_push_string(ctx, value); - - return 1; -} - -static duk_ret_t -System_exec(duk_context *ctx) -{ - duk_push_uint(ctx, system(duk_require_string(ctx, 0))); - - return 1; -} - -static duk_ret_t -System_home(duk_context *ctx) -{ -#if defined(_WIN32) - char path[MAX_PATH] = {0}; - - SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path); - - duk_push_string(ctx, path); -#else - const char *home; - - if ((home = getenv("HOME"))) - duk_push_string(ctx, home); - else - duk_push_undefined(ctx); -#endif - - return 1; -} - -static duk_ret_t -System_name(duk_context *ctx) -{ -#if defined(__linux__) - duk_push_string(ctx, "Linux"); -#elif defined(_WIN32) - duk_push_string(ctx, "Windows"); -#elif defined(__FreeBSD__) - duk_push_string(ctx, "FreeBSD"); -#elif defined(__DragonFly__) - duk_push_string(ctx, "DragonFlyBSD"); -#elif defined(__OpenBSD__) - duk_push_string(ctx, "OpenBSD"); -#elif defined(__NetBSD__) - duk_push_string(ctx, "NetBSD"); -#elif defined(__APPLE__) - duk_push_string(ctx, "macOS"); -#elif defined(__ANDROID__) - duk_push_string(ctx, "Android"); -#elif defined(_AIX) - duk_push_string(ctx, "Aix"); -#elif defined(__HAIKU__) - duk_push_string(ctx, "Haiku"); -#elif defined(sun) - duk_push_string(ctx, "Solaris"); -#else - duk_push_string(ctx, "Unknown"); -#endif - - return 1; -} - -static duk_ret_t -System_popen(duk_context *ctx) -{ - const char *cmd = duk_require_string(ctx, 0); - const char *mode = duk_require_string(ctx, 1); - FILE *fp; - - if (!(fp = popen(cmd, mode))) - irc_jsapi_system_raise(ctx); - - irc_jsapi_file_push(ctx, NULL, fp, pclose); - - return 1; -} - -static duk_ret_t -System_sleep(duk_context *ctx) -{ - return nsleep(duk_require_uint(ctx, 0) * 1000000000L); -} - -static duk_ret_t -System_usleep(duk_context *ctx) -{ - return nsleep(duk_require_uint(ctx, 0) * 1000); -} - -static duk_ret_t -System_uptime(duk_context *ctx) -{ -#if defined(_WIN32) - duk_push_uint(ctx, GetTickCount64() / 1000); -#elif defined(__linux__) - struct sysinfo info; - - if (sysinfo(&info) < 0) - irc_jsapi_system_raise(ctx); - - duk_push_uint(ctx, info.uptime); -#elif defined(__APPLE__) - struct timeval boottime; - size_t length = sizeof (boottime); - int mib[2] = { CTL_KERN, KERN_BOOTTIME }; - time_t bsec, csec; - - if (sysctl(mib, 2, &boottime, &length, NULL, 0) < 0) - irc_jsapi_system_raise(ctx); - - bsec = boottime.tv_sec; - csec = time(NULL); - - duk_push_uint(ctx, difftime(csec, bsec)); -#else - struct timespec ts; - - /* Mostly POSIX compliant (CLOCK_UPTIME isn't POSIX though). */ - if (clock_gettime(CLOCK_UPTIME, &ts) < 0) - irc_jsapi_system_raise(ctx); - - duk_push_uint(ctx, ts.tv_sec); -#endif - - return 1; -} - -static duk_ret_t -System_version(duk_context *ctx) -{ -#if defined(_WIN32) - DWORD version = GetVersion(); - DWORD major = (DWORD)(LOBYTE(LOWORD(version))); - DWORD minor = (DWORD)(HIBYTE(LOWORD(version))); - - duk_push_sprintf(ctx, "%d.%d", (int)major, (int)minor); -#else - struct utsname uts; - - if (uname(&uts) < 0) - irc_jsapi_system_raise(ctx); - - duk_push_string(ctx, uts.release); -#endif - return 1; -} - -static const duk_function_list_entry functions[] = { - { "env", System_env, 1 }, - { "exec", System_exec, 1 }, - { "home", System_home, 0 }, - { "name", System_name, 0 }, - { "popen", System_popen, 2 }, - { "sleep", System_sleep, 1 }, - { "uptime", System_uptime, 0 }, - { "usleep", System_usleep, 1 }, - { "version", System_version, 0 }, - { NULL, NULL, 0 } -}; - -void -irc_jsapi_system_raise(duk_context *ctx) -{ - duk_get_global_string(ctx, "Irccd"); - duk_get_prop_string(ctx, -1, "SystemError"); - duk_remove(ctx, -2); - duk_push_int(ctx, errno); - duk_push_string(ctx, strerror(errno)); - duk_new(ctx, 2); - - (void)duk_throw(ctx); -} - -void -irc_jsapi_system_load(duk_context *ctx) -{ - duk_get_global_string(ctx, "Irccd"); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, functions); - duk_put_prop_string(ctx, -2, "System"); - duk_pop(ctx); -}
--- a/lib/irccd/jsapi-system.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * jsapi-system.h -- Irccd.System API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_SYSTEM_H -#define IRCCD_JSAPI_SYSTEM_H - -#include <duktape.h> - -void -irc_jsapi_system_raise(duk_context *); - -void -irc_jsapi_system_load(duk_context *); - -#endif /* !IRCCD_JSAPI_SYSTEM_H */
--- a/lib/irccd/jsapi-timer.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,324 +0,0 @@ -/* - * jsapi-timer.c -- Irccd.Timer API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <pthread.h> -#include <stdbool.h> -#include <stdatomic.h> -#include <time.h> -#include <errno.h> - -#include <duktape.h> - -#include "irccd.h" -#include "jsapi-system.h" -#include "log.h" -#include "util.h" - -#define SIGNATURE DUK_HIDDEN_SYMBOL("Irccd.Timer") -#define TABLE DUK_HIDDEN_SYMBOL("Irccd.Timer.callbacks") - -enum timer_type { - TIMER_REPEAT, - TIMER_ONESHOT, - TIMER_NUM -}; - -enum timer_status { - TIMER_INACTIVE, - TIMER_ACTIVE, - TIMER_MUST_STOP, - TIMER_MUST_KILL -}; - -struct timer { - enum timer_type type; - unsigned long duration; - pthread_t thr; - pthread_mutex_t mtx; - pthread_cond_t cv; - duk_context *ctx; - atomic_int status; -}; - -static void -timer_start(struct timer *); - -static void -timer_clear(struct timer *tm) -{ - tm->status = TIMER_INACTIVE; - - pthread_cond_destroy(&tm->cv); - pthread_mutex_destroy(&tm->mtx); - pthread_join(tm->thr, NULL); -} - -static void -timer_call(struct timer *tm) -{ - /* Get the function. */ - duk_push_global_stash(tm->ctx); - duk_get_prop_string(tm->ctx, -1, TABLE); - duk_remove(tm->ctx, -2); - duk_push_sprintf(tm->ctx, "%p", tm); - duk_get_prop(tm->ctx, -2); - duk_remove(tm->ctx, -2); - - if (duk_pcall(tm->ctx, 0)) - irc_log_warn("plugin: %s", duk_to_string(tm->ctx, -1)); - - duk_pop(tm->ctx); -} - -static void -timer_destroy(struct timer *tm) -{ - if (tm->status == TIMER_MUST_STOP) { - puts("timer stopped"); - timer_clear(tm); - } - if (tm->status == TIMER_MUST_KILL) { - puts("timer fully freed"); - free(tm); - } -} - -static void -timer_expired(void *data) -{ - struct timer *tm = data; - - /* Only call if I wasn't aborted (race condition) */ - if (tm->status == TIMER_ACTIVE) { - timer_clear(tm); - timer_call(tm); - - /* Start again. */ - if (tm->type == TIMER_REPEAT) - timer_start(tm); - } else - timer_destroy(tm); -} - -static void -timer_aborted(void *data) -{ - timer_destroy(data); -} - -static void * -timer_routine(void *data) -{ - struct timer *tm = data; - struct timespec ts = {0}; - int rc = 0; - - /* Prepare maximum time to wait. */ - timespec_get(&ts, TIME_UTC); - - ts.tv_sec += tm->duration / 1000; - ts.tv_nsec += (tm->duration % 1000) * 1000; - - /* Wait at most time unless I'm getting kill. */ - if (pthread_mutex_lock(&tm->mtx) != 0) - tm->status = TIMER_MUST_STOP; - - while (tm->status == TIMER_ACTIVE && rc == 0) - rc = pthread_cond_timedwait(&tm->cv, &tm->mtx, &ts); - - /* - * When the thread ends, there are several possibilities: - * - * 1. It has completed without being aborted. - * 2. It has been stopped by the user (tm->stopped is true). - * 3. The plugin is shutting down (tm->kill is true). - */ - if (rc == ETIMEDOUT && tm->status == TIMER_ACTIVE) - irc_bot_post(timer_expired, tm); - else - irc_bot_post(timer_aborted, tm); - - return NULL; -} - -static void -timer_start(struct timer *tm) -{ - if (tm->status != TIMER_INACTIVE) - return; - - tm->status = TIMER_ACTIVE; - - if (pthread_mutex_init(&tm->mtx, NULL) != 0) - goto mutex_err; - if (pthread_cond_init(&tm->cv, NULL) != 0) - goto cond_err; - if (pthread_create(&tm->thr, NULL, timer_routine, tm) != 0) - goto thread_err; - - return; - -thread_err: - pthread_cond_destroy(&tm->cv); - -cond_err: - pthread_mutex_destroy(&tm->mtx); - -mutex_err: - tm->status = TIMER_INACTIVE; - irc_jsapi_system_raise(tm->ctx); -} - -static void -timer_stop(struct timer *tm, enum timer_status st) -{ - if (tm->status == TIMER_INACTIVE) - return; - - tm->status = st; - pthread_cond_signal(&tm->cv); -} - -static struct timer * -self(duk_context *ctx) -{ - struct timer *tm; - - duk_push_this(ctx); - duk_get_prop_string(ctx, -1, SIGNATURE); - tm = duk_to_pointer(ctx, -1); - duk_pop_2(ctx); - - if (!tm) - (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Timer object"); - - return tm; -} - -static duk_ret_t -Timer_prototype_start(duk_context *ctx) -{ - timer_start(self(ctx)); - - return 0; -} - -static duk_ret_t -Timer_prototype_stop(duk_context *ctx) -{ - timer_stop(self(ctx), TIMER_MUST_STOP); - - return 0; -} - -static duk_ret_t -Timer_destructor(duk_context *ctx) -{ - struct timer *tm; - - /* Remove timer property. */ - duk_get_prop_string(ctx, 0, SIGNATURE); - tm = duk_to_pointer(ctx, -1); - duk_pop(ctx); - duk_del_prop_string(ctx, -2, SIGNATURE); - - /* Remove callback from timer table. */ - puts("DELETE"); - duk_push_global_stash(tm->ctx); - duk_get_prop_string(tm->ctx, -1, TABLE); - duk_remove(tm->ctx, -2); - duk_push_sprintf(tm->ctx, "%p", tm); - duk_del_prop(tm->ctx, -2); - duk_pop(tm->ctx); - - /* - * Do not delete the timer itself here because the thread is - * referencing it. Stop it and let it kill itself from the main thread. - */ - if (tm) - timer_stop(tm, TIMER_MUST_KILL); - - return 0; -} - -static duk_ret_t -Timer_constructor(duk_context *ctx) -{ - struct timer *ptr, tm = { - .ctx = ctx, - }; - - if (!duk_is_constructor_call(ctx)) - return 0; - - tm.type = duk_require_int(ctx, 0); - tm.duration = duk_require_uint(ctx, 1); - - if (tm.type < 0 || tm.type >= TIMER_NUM) - return duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type"); - if (!duk_is_callable(ctx, 2)) - return duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function"); - - /* Create this. */ - duk_push_this(ctx); - duk_push_pointer(ctx, (ptr = irc_util_memdup(&tm, sizeof (tm)))); - duk_put_prop_string(ctx, -2, SIGNATURE); - duk_push_c_function(ctx, Timer_destructor, 1); - duk_set_finalizer(ctx, -2); - duk_pop(ctx); - - /* Store the function into the global table */ - duk_push_global_stash(ctx); - duk_get_prop_string(ctx, -1, TABLE); - duk_remove(ctx, -2); - duk_push_sprintf(ctx, "%p", ptr); - duk_dup(ctx, 2); - duk_put_prop(ctx, -3); - duk_pop(ctx); - - return 0; -} - -static const duk_function_list_entry methods[] = { - { "start", Timer_prototype_start, 0 }, - { "stop", Timer_prototype_stop, 0 }, - { NULL, NULL, 0 } -}; - -static const duk_number_list_entry constants[] = { - { "Single", TIMER_ONESHOT }, - { "Repeat", TIMER_REPEAT }, - { NULL, 0 } -}; - -void -irc_jsapi_timer_load(duk_context *ctx) -{ - duk_get_global_string(ctx, "Irccd"); - duk_push_c_function(ctx, Timer_constructor, 3); - duk_put_number_list(ctx, -1, constants); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, methods); - duk_put_prop_string(ctx, -2, "prototype"); - duk_put_prop_string(ctx, -2, "Timer"); - duk_pop(ctx); - duk_push_global_stash(ctx); - duk_push_object(ctx); - duk_put_prop_string(ctx, -2, TABLE); - duk_pop(ctx); -}
--- a/lib/irccd/jsapi-timer.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * jsapi-timer.h -- Irccd.Timer API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_TIMER_H -#define IRCCD_JSAPI_TIMER_H - -#include <duktape.h> - -void -irc_jsapi_timer_load(duk_context *); - -#endif /* !IRCCD_JSAPI_TIMER_H */
--- a/lib/irccd/jsapi-unicode.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * jsapi-unicode.c -- Irccd.Unicode API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 "jsapi-unicode.h" -#include "unicode.h" - -static duk_ret_t -Unicode_isDigit(duk_context *ctx) -{ - duk_push_boolean(ctx, irc_uni_isdigit(duk_get_int(ctx, 0))); - - return 1; -} - -static duk_ret_t -Unicode_isLetter(duk_context *ctx) -{ - duk_push_boolean(ctx, irc_uni_isalpha(duk_get_int(ctx, 0))); - - return 1; -} - -static duk_ret_t -Unicode_isLower(duk_context *ctx) -{ - duk_push_boolean(ctx, irc_uni_islower(duk_get_int(ctx, 0))); - - return 1; -} - -static duk_ret_t -Unicode_isSpace(duk_context *ctx) -{ - duk_push_boolean(ctx, irc_uni_isspace(duk_get_int(ctx, 0))); - - return 1; -} - -static duk_ret_t -Unicode_isTitle(duk_context *ctx) -{ - duk_push_boolean(ctx, irc_uni_istitle(duk_get_int(ctx, 0))); - - return 1; -} - -static duk_ret_t -Unicode_isUpper(duk_context *ctx) -{ - duk_push_boolean(ctx, irc_uni_isupper(duk_get_int(ctx, 0))); - - return 1; -} - -static const duk_function_list_entry functions[] = { - { "isDigit", Unicode_isDigit, 1 }, - { "isLetter", Unicode_isLetter, 1 }, - { "isLower", Unicode_isLower, 1 }, - { "isSpace", Unicode_isSpace, 1 }, - { "isTitle", Unicode_isTitle, 1 }, - { "isUpper", Unicode_isUpper, 1 }, - { NULL, NULL, 0 } -}; - -void -irc_jsapi_unicode_load(duk_context *ctx) -{ - duk_get_global_string(ctx, "Irccd"); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, functions); - duk_put_prop_string(ctx, -2, "Unicode"); - duk_pop(ctx); -}
--- a/lib/irccd/jsapi-unicode.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * jsapi-unicode.h -- Irccd.Unicode API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_UNICODE_H -#define IRCCD_JSAPI_UNICODE_H - -#include <duktape.h> - -void -irc_jsapi_unicode_load(duk_context *); - -#endif /* !IRCCD_JSAPI_UNICODE_H */
--- a/lib/irccd/jsapi-util.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,316 +0,0 @@ -/* - * jsapi-util.c -- Irccd.Util API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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 <compat.h> - -#include <string.h> - -#include "jsapi-util.h" -#include "server.h" -#include "subst.h" -#include "util.h" - -struct subspack { - struct irc_subst_keyword *kw; - struct irc_subst subst; -}; - -struct string { - TAILQ_ENTRY(string) link; - char value[]; -}; - -TAILQ_HEAD(stringlist, string); - -/* - * 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: ... - * } - */ -static void -subspack_parse(duk_context *ctx, duk_idx_t index, struct subspack *pkg) -{ - memset(pkg, 0, sizeof (*pkg)); - - if (!duk_is_object(ctx, index)) - return; - - duk_enum(ctx, index, 0); - - while (duk_next(ctx, -1, true)) { - if (strcmp(duk_get_string(ctx, -2), "date") == 0) { - pkg->subst.time = duk_get_number(ctx, -1); - continue; - } - - pkg->kw = irc_util_reallocarray(pkg->kw, ++pkg->subst.keywordsz, - sizeof (*pkg->kw)); - pkg->kw[pkg->subst.keywordsz - 1].key = - irc_util_strdup(duk_opt_string(ctx, -2, "")); - pkg->kw[pkg->subst.keywordsz - 1].value = - irc_util_strdup(duk_opt_string(ctx, -1, "")); - - duk_pop_n(ctx, 2); - } - - pkg->subst.flags = IRC_SUBST_DATE | - IRC_SUBST_KEYWORDS | - IRC_SUBST_ENV | - IRC_SUBST_IRC_ATTRS; - pkg->subst.keywords = pkg->kw; -} - -static inline void -subspack_finish(struct subspack *subst) -{ - for (size_t i = 0; i < subst->subst.keywordsz; ++i) { - free((char *)subst->kw[i].key); - free((char *)subst->kw[i].value); - } - - free(subst->kw); -} - -static struct string * -string_new(const char *v) -{ - struct string *s; - const size_t len = strlen(v); - - s = irc_util_malloc(sizeof (*s) + len + 1); - strcpy(s->value, v); - - return s; -} - -static void -stringlist_finish(struct stringlist *list) -{ - struct string *s, *tmp; - - TAILQ_FOREACH_SAFE(s, list, link, tmp) - free(s); -} - -static void -stringlist_concat(struct stringlist *list, const char *value) -{ - struct string *s; - char *str = irc_util_strdup(value), *token, *p = str; - - while ((token = strtok_r(p, " \t\n", &p))) { - /* TODO: trim and check if empty. */ - s = string_new(token); - TAILQ_INSERT_TAIL(list, s, link); - } - - free(str); -} - -static void -split_from_string(duk_context *ctx, struct stringlist *list) -{ - stringlist_concat(list, duk_require_string(ctx, 0)); -} - -static void -split_from_array(duk_context *ctx, struct stringlist *list) -{ - duk_enum(ctx, 0, DUK_ENUM_ARRAY_INDICES_ONLY); - - while (duk_next(ctx, -1, 1)) { - stringlist_concat(list, duk_to_string(ctx, -1)); - duk_pop_2(ctx); - } -} - -static void -split(duk_context *ctx, duk_idx_t index, struct stringlist *list) -{ - duk_require_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_STRING); - TAILQ_INIT(list); - - if (duk_is_string(ctx, index)) - split_from_string(ctx, list); - else if (duk_is_array(ctx, index)) - split_from_array(ctx, list); -} - -static int -limit(duk_context *ctx, duk_idx_t index, const char *name, size_t value) -{ - int newvalue; - - if (duk_get_top(ctx) < index || !duk_is_number(ctx, index)) - return value; - - newvalue = duk_to_int(ctx, index); - - if (newvalue <= 0) - (void)duk_error(ctx, DUK_ERR_RANGE_ERROR, - "argument %d (%s) must be positive", index, name); - - return newvalue; -} - -static char * -join(duk_context *ctx, size_t maxc, size_t maxl, const struct stringlist *tokens) -{ - FILE *fp; - char *out = NULL; - size_t outsz = 0, linesz = 0, tokensz, lineavail = maxl; - struct string *token; - - if (!(fp = open_memstream(&out, &outsz))) - return false; - - TAILQ_FOREACH(token, tokens, link) { - tokensz = strlen(token->value); - - if (tokensz > maxc) { - fclose(fp); - duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, - "token '%s' could not fit in maxc limit (%zu)", token->value, maxc); - return NULL; - } - - /* - * If there is something at the beginning of the line, we must - * append a space. - */ - if (linesz > 0) - tokensz++; - - /* - * This token is going past the maximum of the current line so - * we append a newline character and reset the length to start - * a "new" one. - */ - if (linesz + tokensz > maxc) { - if (--lineavail == 0) { - fclose(fp); - duk_push_error_object(ctx, DUK_ERR_RANGE_ERROR, "number of lines exceeds maxl (%zu)", maxl); - return NULL; - } - - fputc('\n', fp); - linesz = 0; - } - - linesz += fprintf(fp, "%s%s", linesz > 0 ? " " : "", token->value); - } - - fflush(fp); - fclose(fp); - - return out; -} - -static duk_ret_t -Util_cut(duk_context *ctx) -{ - struct stringlist tokens; - size_t maxc, maxl, i = 0; - char *lines, *line, *p; - - maxc = limit(ctx, 1, "maxc", 72); - maxl = limit(ctx, 2, "maxl", SIZE_MAX); - - /* Construct a list of words from a string or an array of strings. */ - split(ctx, 0, &tokens); - - /* Join as new lines with a limit of maximum columns and lines. */ - if (!(lines = join(ctx, maxc, maxl, &tokens))) { - stringlist_finish(&tokens); - duk_throw(ctx); - } - - duk_push_array(ctx); - - for (p = lines; (line = strtok_r(p, "\n", &p)); ) { - duk_push_string(ctx, line); - duk_put_prop_index(ctx, -2, i++); - } - - stringlist_finish(&tokens); - free(lines); - - return 1; -} - -static duk_ret_t -Util_format(duk_context *ctx) -{ - const char *str = duk_require_string(ctx, 0); - struct subspack pkg; - char buf[1024] = {0}; - - subspack_parse(ctx, 1, &pkg); - irc_subst(buf, sizeof (buf), str, &pkg.subst); - duk_push_string(ctx, buf); - subspack_finish(&pkg); - - return 1; -} - -static duk_ret_t -Util_splituser(duk_context *ctx) -{ - struct irc_server_user user; - - irc_server_split(duk_require_string(ctx, 0), &user); - duk_push_string(ctx, user.nickname); - - return 1; -} - -static duk_ret_t -Util_splithost(duk_context *ctx) -{ - struct irc_server_user user; - - irc_server_split(duk_require_string(ctx, 0), &user); - duk_push_string(ctx, user.host); - - return 1; -} - -static const duk_function_list_entry functions[] = { - { "cut", Util_cut, DUK_VARARGS }, - { "format", Util_format, DUK_VARARGS }, - { "splituser", Util_splituser, 1 }, - { "splithost", Util_splithost, 1 }, - { NULL, NULL, 0 } -}; - -void -irc_jsapi_util_load(duk_context *ctx) -{ - duk_get_global_string(ctx, "Irccd"); - duk_push_object(ctx); - duk_put_function_list(ctx, -1, functions); - duk_put_prop_string(ctx, -2, "Util"); - duk_pop(ctx); -}
--- a/lib/irccd/jsapi-util.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * jsapi-util.h -- Irccd.Util API - * - * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> - * - * 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_JSAPI_UTIL_H -#define IRCCD_JSAPI_UTIL_H - -#include <duktape.h> - -void -irc_jsapi_util_load(duk_context *ctx); - -#endif /* !IRCCD_JSAPI_UTIL_H */
--- a/lib/irccd/plugin.c Fri Jan 29 13:50:44 2021 +0100 +++ b/lib/irccd/plugin.c Fri Jan 29 15:03:23 2021 +0100 @@ -167,8 +167,6 @@ if (plg->finish) plg->finish(plg); - - free(plg); } struct irc_plugin *
--- a/lib/irccd/unicode.c Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4845 +0,0 @@ -/* - * unicode.c -- UTF-8 to UTF-32 conversions and various operations - * - * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr> - * - * 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 <assert.h> -#include <errno.h> -#include <stdlib.h> - -#include "unicode.h" - -/* - * The following code has been generated from Go mkrunetype adapted to our - * needs. - */ - -#define nelem(x) (sizeof (x) / sizeof ((x)[0])) - -static const uint32_t * -search(uint32_t c, const uint32_t *t, int n, int ne) -{ - const uint32_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 NULL; -} - -static const uint32_t isspacer[] = { - 0x0009, 0x000d, - 0x0020, 0x0020, - 0x0085, 0x0085, - 0x00a0, 0x00a0, - 0x1680, 0x1680, - 0x2000, 0x200a, - 0x2028, 0x2029, - 0x202f, 0x202f, - 0x205f, 0x205f, - 0x3000, 0x3000, - 0xfeff, 0xfeff, -}; - -bool -irc_uni_isspace(uint32_t c) -{ - const uint32_t *p; - - p = search(c, isspacer, nelem (isspacer) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - return false; -} - -static const uint32_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, -}; - -bool -irc_uni_isdigit(uint32_t c) -{ - const uint32_t *p; - - p = search(c, isdigitr, nelem (isdigitr) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - return false; -} - -static const uint32_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, -}; - -static const uint32_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, -}; - -bool -irc_uni_isalpha(uint32_t c) -{ - const uint32_t *p; - - p = search(c, isalphar, nelem (isalphar) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = search(c, isalphas, nelem (isalphas), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -static const uint32_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, -}; - -static const uint32_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, -}; - -bool -irc_uni_isupper(uint32_t c) -{ - const uint32_t *p; - - p = search(c, isupperr, nelem (isupperr) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = search(c, isuppers, nelem (isuppers), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -static const uint32_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, -}; - -static const uint32_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, -}; - -bool -irc_uni_islower(uint32_t c) -{ - const uint32_t *p; - - p = search(c, islowerr, nelem (islowerr) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = search(c, islowers, nelem (islowers), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -static const uint32_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, -}; - -static const uint32_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, -}; - -bool -irc_uni_istitle(uint32_t c) -{ - const uint32_t *p; - - p = search(c, istitler, nelem (istitler) / 2, 2); - - if (p && c >= p[0] && c <= p[1]) - return true; - - p = search(c, istitles, nelem (istitles), 1); - - if (p && c == p[0]) - return true; - - return false; -} - -static const uint32_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, -}; - -static const uint32_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, -}; - -uint32_t -irc_uni_toupper(uint32_t c) -{ - const uint32_t *p; - - p = search(c, toupperr, nelem (toupperr) / 3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = search(c, touppers, nelem (touppers) / 2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -static const uint32_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, -}; - -static const uint32_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, -}; - -uint32_t -irc_uni_tolower(uint32_t c) -{ - const uint32_t *p; - - p = search(c, tolowerr, nelem (tolowerr) / 3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = search(c, tolowers, nelem (tolowers) / 2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -static const uint32_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, -}; - -static const uint32_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, -}; - -uint32_t -irc_uni_totitle(uint32_t c) -{ - const uint32_t *p; - - p = search(c, totitler, nelem (totitler) / 3, 3); - - if (p && c >= p[0] && c <= p[1]) - return c + p[2] - 1048576; - - p = search(c, totitles, nelem (totitles) / 2, 2); - - if (p && c == p[0]) - return c + p[1] - 1048576; - - return c; -} - -size_t -irc_uni8_encode(uint8_t dst[], size_t dstsz, uint32_t point) -{ - assert(dst); - - size_t written; - - switch ((written = irc_uni32_sizeof(point))) { - case 1: - if (dstsz < 1) - goto erange; - - dst[0] = (uint8_t)point; - break; - case 2: - if (dstsz < 2) - goto erange; - - dst[0] = 0xC0 | ((point >> 6) & 0x1F); - dst[1] = 0x80 | (point & 0x3F); - break; - case 3: - if (dstsz < 3) - goto erange; - - dst[0] = 0xE0 | ((point >> 12) & 0xF ); - dst[1] = 0x80 | ((point >> 6) & 0x3F); - dst[2] = 0x80 | (point & 0x3F); - break; - case 4: - if (dstsz < 4) - goto erange; - - dst[0] = 0xF0 | ((point >> 18) & 0x7 ); - dst[1] = 0x80 | ((point >> 12) & 0x3F); - dst[2] = 0x80 | ((point >> 6) & 0x3F); - dst[3] = 0x80 | (point & 0x3F); - break; - default: - break; - } - - return written; - -erange: - errno = ERANGE; - - return -1; -} - -size_t -irc_uni8_decode(const uint8_t src[], uint32_t *point) -{ - assert(src); - assert(point); - - size_t parsed; - - switch ((parsed = irc_uni8_sizeof(*src))) { - case 1: - *point = src[0]; - break; - case 2: - if (!src[1]) - goto eilseq; - - *point = (src[0] & 0x1f) << 6; - *point |= (src[1] & 0x3f); - break; - case 3: - if (!src[1] || !src[2]) - goto eilseq; - - *point = (src[0] & 0x0f) << 12; - *point |= (src[1] & 0x3f) << 6; - *point |= (src[2] & 0x3f); - break; - case 4: - if (!src[1] || !src[2] || !src[3]) - goto eilseq; - - *point = (src[0] & 0x07) << 16; - *point |= (src[1] & 0x3f) << 12; - *point |= (src[2] & 0x3f) << 6; - *point |= (src[3] & 0x3f); - break; - default: - break; - } - - return parsed; - -eilseq: - errno = EILSEQ; - - return -1; -} - -size_t -irc_uni8_sizeof(uint8_t c) -{ - if (c <= 127) - return 1; - if ((c & 0xE0) == 0xC0) - return 2; - if ((c & 0xF0) == 0xE0) - return 3; - if ((c & 0xF8) == 0xF0) - return 4; - - errno = EILSEQ; - return -1; -} - -size_t -irc_uni8_length(const uint8_t src[]) -{ - assert(src); - - size_t total = 0, gap; - - while (*src) { - if ((gap = irc_uni8_sizeof(*src)) == (size_t)-1) - return -1; - - total += gap; - src += gap; - } - - return total; -} - -size_t -irc_uni8_to32(const uint8_t src[], uint32_t dst[], size_t dstsz) -{ - assert(src); - assert(dst); - - size_t nwritten = 0, gap; - - for (; *src && dstsz; --dstsz) { - if ((gap = irc_uni8_decode(src, dst++)) == (size_t)-1) - return -1; - - src += gap; - ++nwritten; - } - - /* No more space to store NUL. */ - if (dstsz == 0) { - errno = ERANGE; - return -1; - } - - *dst = 0; - - return nwritten; -} - -size_t -irc_uni32_sizeof(uint32_t c) -{ - if (c <= 0x7F) - return 1; - if (c <= 0x7FF) - return 2; - if (c <= 0xFFFF) - return 3; - if (c <= 0x1FFFFF) - return 4; - - errno = EILSEQ; - return -1; -} - -size_t -irc_uni32_length(const uint32_t src[]) -{ - assert(src); - - size_t total = 0; - - while (*src++) - total++; - - return total; -} - -size_t -irc_uni32_requires(const uint32_t src[]) -{ - assert(src); - - size_t total = 0, gap; - - while (*src) { - if ((gap = irc_uni32_sizeof(*src++)) == (size_t)-1) - return -1; - if (gap >= SIZE_MAX - total) { - errno = ERANGE; - return -1; - } - - total += gap; - } - - return total; -} - -size_t -irc_uni32_to8(const uint32_t src[], uint8_t dst[], size_t dstsz) -{ - assert(src); - assert(dst); - - size_t nwritten = 0, gap; - - while (*src && dstsz) { - if ((gap = irc_uni8_encode(dst, dstsz, *src++)) == (size_t)-1) - return -1; - - dst += gap; - dstsz -= gap; - nwritten += gap; - } - - if (dstsz == 0) { - errno = ERANGE; - return -1; - } - - *dst = 0; - - return nwritten; -}
--- a/lib/irccd/unicode.h Fri Jan 29 13:50:44 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * unicode.h -- UTF-8 to UTF-32 conversions and various operations - * - * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr> - * - * 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_H -#define IRCCD_UNICODE_H - -#include <stdbool.h> -#include <stddef.h> -#include <stdint.h> - -size_t -irc_uni8_encode(uint8_t dst[], size_t dstsz, uint32_t point); - -size_t -irc_uni8_decode(const uint8_t src[], uint32_t *point); - -size_t -irc_uni8_sizeof(uint8_t c); - -size_t -irc_uni8_length(const uint8_t src[]); - -size_t -irc_uni8_to32(const uint8_t src[], uint32_t dst[], size_t dstsz); - -size_t -irc_uni32_sizeof(uint32_t point); - -size_t -irc_uni32_length(const uint32_t src[]); - -size_t -irc_uni32_requires(const uint32_t src[]); - -size_t -irc_uni32_to8(const uint32_t src[], uint8_t dst[], size_t dstsz); - -bool -irc_uni_isalpha(uint32_t c); - -bool -irc_uni_isdigit(uint32_t c); - -bool -irc_uni_islower(uint32_t c); - -bool -irc_uni_isspace(uint32_t c); - -bool -irc_uni_istitle(uint32_t c); - -bool -irc_uni_isupper(uint32_t c); - -uint32_t -irc_uni_toupper(uint32_t c); - -uint32_t -irc_uni_tolower(uint32_t c); - -uint32_t -irc_uni_totitle(uint32_t c); - -#endif /* !IRCCD_UNICODE_H */
--- a/tests/CMakeLists.txt Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/CMakeLists.txt Fri Jan 29 15:03:23 2021 +0100 @@ -47,7 +47,7 @@ foreach (t ${TESTS}) add_executable(${t} ${t}.c) add_test(${t} ${t}) - target_link_libraries(${t} libirccd libirccd-greatest) + target_link_libraries(${t} irccd-fe libirccd-greatest) set_target_properties(${t} PROPERTIES FOLDER "tests") target_compile_definitions( ${t}
--- a/tests/test-jsapi-chrono.c Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/test-jsapi-chrono.c Fri Jan 29 15:03:23 2021 +0100 @@ -25,15 +25,15 @@ #include <irccd/plugin.h> static struct irc_plugin *plugin; -static struct irc_js_plugin_data *data; +static duk_context *ctx; static void setup(void *udata) { (void)udata; - plugin = irc_js_plugin_open(SOURCE "/data/example-plugin.js"); - data = plugin->data; + plugin = js_plugin_open(SOURCE "/data/example-plugin.js"); + ctx = js_plugin_get_context(plugin); } static void @@ -44,23 +44,23 @@ irc_plugin_finish(plugin); plugin = NULL; - data = NULL; + ctx = NULL; } GREATEST_TEST basics_simple(void) { - if (duk_peval_string(data->ctx, "timer = new Irccd.Chrono();") != 0) + if (duk_peval_string(ctx, "timer = new Irccd.Chrono();") != 0) GREATEST_FAIL(); sleep(1); - if (duk_peval_string(data->ctx, "result = timer.elapsed;") != 0) + if (duk_peval_string(ctx, "result = timer.elapsed;") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "result"); + duk_get_global_string(ctx, "result"); - GREATEST_ASSERT_IN_RANGE(1000U, duk_get_uint(data->ctx, -1), 100); + GREATEST_ASSERT_IN_RANGE(1000U, duk_get_uint(ctx, -1), 100); GREATEST_PASS(); } @@ -72,22 +72,22 @@ * start to reset its value and wait for 1s. The elapsed time must not * be greater than 1s. */ - if (duk_peval_string(data->ctx, "timer = new Irccd.Chrono()") != 0) + if (duk_peval_string(ctx, "timer = new Irccd.Chrono()") != 0) GREATEST_FAIL(); sleep(1); - if (duk_peval_string(data->ctx, "timer.reset();") != 0) + if (duk_peval_string(ctx, "timer.reset();") != 0) GREATEST_FAIL(); sleep(1); - if (duk_peval_string(data->ctx, "result = timer.elapsed") != 0) + if (duk_peval_string(ctx, "result = timer.elapsed") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "result"); + duk_get_global_string(ctx, "result"); - GREATEST_ASSERT_IN_RANGE(1000U, duk_get_uint(data->ctx, -1), 100); + GREATEST_ASSERT_IN_RANGE(1000U, duk_get_uint(ctx, -1), 100); GREATEST_PASS(); }
--- a/tests/test-jsapi-directory.c Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/test-jsapi-directory.c Fri Jan 29 15:03:23 2021 +0100 @@ -25,21 +25,21 @@ #include <irccd/plugin.h> static struct irc_plugin *plugin; -static struct irc_js_plugin_data *data; +static duk_context *ctx; static void setup(void *udata) { (void)udata; - plugin = irc_js_plugin_open(SOURCE "/data/example-plugin.js"); - data = plugin->data; + plugin = js_plugin_open(SOURCE "/data/example-plugin.js"); + ctx = js_plugin_get_context(plugin); - duk_push_string(data->ctx, SOURCE); - duk_put_global_string(data->ctx, "SOURCE"); + duk_push_string(ctx, SOURCE); + duk_put_global_string(ctx, "SOURCE"); - duk_push_string(data->ctx, BINARY); - duk_put_global_string(data->ctx, "BINARY"); + duk_push_string(ctx, BINARY); + duk_put_global_string(ctx, "BINARY"); } static void @@ -50,7 +50,7 @@ irc_plugin_finish(plugin); plugin = NULL; - data = NULL; + ctx = NULL; } GREATEST_TEST @@ -61,13 +61,13 @@ "p = d.path;" "l = d.entries.length;"; - if (duk_peval_string(data->ctx, script) != 0) + if (duk_peval_string(ctx, script) != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "l"); - GREATEST_ASSERT_EQ(3U, duk_get_uint(data->ctx, -1)); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT(duk_is_string(data->ctx, -1)); + duk_get_global_string(ctx, "l"); + GREATEST_ASSERT_EQ(3U, duk_get_uint(ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT(duk_is_string(ctx, -1)); GREATEST_PASS(); } @@ -77,36 +77,36 @@ { const char *script = "d = new Irccd.Directory(SOURCE + '/data/root');"; - if (duk_peval_string(data->ctx, script) != 0) + if (duk_peval_string(ctx, script) != 0) GREATEST_FAIL(); /* Find "lines.txt" not recursively. */ - if (duk_peval_string(data->ctx, "p = d.find('lines.txt');") != 0) + if (duk_peval_string(ctx, "p = d.find('lines.txt');") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/lines.txt", duk_get_string(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/lines.txt", duk_get_string(ctx, -1)); /* Find "unknown.txt" not recursively (not found). */ - if (duk_peval_string(data->ctx, "p = d.find('unknown.txt');") != 0) + if (duk_peval_string(ctx, "p = d.find('unknown.txt');") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT(duk_is_null(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT(duk_is_null(ctx, -1)); /* Find "file-2.txt" not recursively (exists but in sub directory). */ - if (duk_peval_string(data->ctx, "p = d.find('file-2.txt');") != 0) + if (duk_peval_string(ctx, "p = d.find('file-2.txt');") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT(duk_is_null(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT(duk_is_null(ctx, -1)); /* Find "file-2.txt" recursively. */ - if (duk_peval_string(data->ctx, "p = d.find('file-2.txt', true);") != 0) + if (duk_peval_string(ctx, "p = d.find('file-2.txt', true);") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/level-1/level-2/file-2.txt", duk_get_string(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/level-1/level-2/file-2.txt", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -119,11 +119,11 @@ /* First create an empty directory. */ mkdir(BINARY "/empty", 0700); - if (duk_peval_string(data->ctx, "d = new Irccd.Directory(BINARY + '/empty')") != 0) + if (duk_peval_string(ctx, "d = new Irccd.Directory(BINARY + '/empty')") != 0) GREATEST_FAIL(); /* Not recursive. */ - if (duk_peval_string(data->ctx, "d.remove()") != 0) + if (duk_peval_string(ctx, "d.remove()") != 0) GREATEST_FAIL(); GREATEST_ASSERT_EQ(-1, stat(BINARY "/empty", &st)); @@ -131,11 +131,11 @@ mkdir(BINARY "/notempty", 0700); mkdir(BINARY "/notempty/empty", 0700); - if (duk_peval_string(data->ctx, "d = new Irccd.Directory(BINARY + '/notempty')") != 0) + if (duk_peval_string(ctx, "d = new Irccd.Directory(BINARY + '/notempty')") != 0) GREATEST_FAIL(); /* Not recursive. */ - if (duk_peval_string(data->ctx, "d.remove(true)") != 0) + if (duk_peval_string(ctx, "d.remove(true)") != 0) GREATEST_FAIL(); GREATEST_ASSERT_EQ(-1, stat(BINARY "/notempty", &st)); @@ -156,34 +156,34 @@ free_find(void) { /* Find "lines.txt" not recursively. */ - if (duk_peval_string(data->ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'lines.txt');") != 0) { - puts(duk_to_string(data->ctx, -1)); + if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'lines.txt');") != 0) { + puts(duk_to_string(ctx, -1)); GREATEST_FAIL(); } - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/lines.txt", duk_get_string(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/lines.txt", duk_get_string(ctx, -1)); /* Find "unknown.txt" not recursively (not found). */ - if (duk_peval_string(data->ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'unknown.txt');") != 0) + if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'unknown.txt');") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT(duk_is_null(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT(duk_is_null(ctx, -1)); /* Find "file-2.txt" not recursively (exists but in sub directory). */ - if (duk_peval_string(data->ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'file-2.txt');") != 0) + if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'file-2.txt');") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT(duk_is_null(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT(duk_is_null(ctx, -1)); /* Find "file-2.txt" recursively. */ - if (duk_peval_string(data->ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'file-2.txt', true);") != 0) + if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'file-2.txt', true);") != 0) GREATEST_FAIL(); - duk_get_global_string(data->ctx, "p"); - GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/level-1/level-2/file-2.txt", duk_get_string(data->ctx, -1)); + duk_get_global_string(ctx, "p"); + GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/level-1/level-2/file-2.txt", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -197,8 +197,8 @@ mkdir(BINARY "/empty", 0700); /* Not recursive. */ - if (duk_peval_string(data->ctx, "Irccd.Directory.remove(BINARY + '/empty')") != 0) { - puts(duk_to_string(data->ctx, -1)); + if (duk_peval_string(ctx, "Irccd.Directory.remove(BINARY + '/empty')") != 0) { + puts(duk_to_string(ctx, -1)); GREATEST_FAIL(); } @@ -208,7 +208,7 @@ mkdir(BINARY "/notempty/empty", 0700); /* Not recursive. */ - if (duk_peval_string(data->ctx, "Irccd.Directory.remove(BINARY + '/notempty', true)") != 0) + if (duk_peval_string(ctx, "Irccd.Directory.remove(BINARY + '/notempty', true)") != 0) GREATEST_FAIL(); GREATEST_ASSERT_EQ(-1, stat(BINARY "/notempty", &st)); @@ -224,8 +224,8 @@ remove(BINARY "/1/2"); remove(BINARY "/1"); - if (duk_peval_string(data->ctx, "Irccd.Directory.mkdir(BINARY + '/1/2')") != 0) { - puts(duk_to_string(data->ctx, -1)); + if (duk_peval_string(ctx, "Irccd.Directory.mkdir(BINARY + '/1/2')") != 0) { + puts(duk_to_string(ctx, -1)); GREATEST_FAIL(); }
--- a/tests/test-jsapi-file.c Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/test-jsapi-file.c Fri Jan 29 15:03:23 2021 +0100 @@ -26,21 +26,21 @@ #include <irccd/plugin.h> static struct irc_plugin *plugin; -static struct irc_js_plugin_data *data; +static duk_context *ctx; static void setup(void *udata) { (void)udata; - plugin = irc_js_plugin_open(SOURCE "/data/example-plugin.js"); - data = plugin->data; + plugin = js_plugin_open(SOURCE "/data/example-plugin.js"); + ctx = js_plugin_get_context(plugin); - duk_push_string(data->ctx, SOURCE); - duk_put_global_string(data->ctx, "SOURCE"); + duk_push_string(ctx, SOURCE); + duk_put_global_string(ctx, "SOURCE"); - duk_push_string(data->ctx, BINARY); - duk_put_global_string(data->ctx, "BINARY"); + duk_push_string(ctx, BINARY); + duk_put_global_string(ctx, "BINARY"); } static void @@ -51,17 +51,17 @@ irc_plugin_finish(plugin); plugin = NULL; - data = NULL; + ctx = NULL; } GREATEST_TEST free_basename(void) { - if (duk_peval_string(data->ctx, "result = Irccd.File.basename('/usr/local/etc/irccd.conf');")) + if (duk_peval_string(ctx, "result = Irccd.File.basename('/usr/local/etc/irccd.conf');")) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("irccd.conf", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("irccd.conf", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -69,11 +69,11 @@ GREATEST_TEST free_dirname(void) { - if (duk_peval_string(data->ctx, "result = Irccd.File.dirname('/usr/local/etc/irccd.conf');")) + if (duk_peval_string(ctx, "result = Irccd.File.dirname('/usr/local/etc/irccd.conf');")) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("/usr/local/etc", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("/usr/local/etc", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -81,11 +81,11 @@ GREATEST_TEST free_exists(void) { - if (duk_peval_string(data->ctx, "result = Irccd.File.exists(SOURCE + '/data/root/file-1.txt')")) + if (duk_peval_string(ctx, "result = Irccd.File.exists(SOURCE + '/data/root/file-1.txt')")) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); GREATEST_PASS(); } @@ -93,11 +93,11 @@ GREATEST_TEST free_exists2(void) { - if (duk_peval_string(data->ctx, "result = Irccd.File.exists('file_which_does_not_exist.txt')")) + if (duk_peval_string(ctx, "result = Irccd.File.exists('file_which_does_not_exist.txt')")) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(!duk_get_boolean(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(!duk_get_boolean(ctx, -1)); GREATEST_PASS(); } @@ -113,7 +113,7 @@ fclose(fp); - if (duk_peval_string(data->ctx, "Irccd.File.remove(BINARY + '/test.bin')") != 0) + if (duk_peval_string(ctx, "Irccd.File.remove(BINARY + '/test.bin')") != 0) GREATEST_FAIL(); GREATEST_ASSERT(stat(BINARY "/test.bin", &st) < 0); @@ -135,7 +135,7 @@ GREATEST_TEST object_basename(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "result = f.basename();" ); @@ -143,8 +143,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("file-1.txt", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("file-1.txt", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -152,7 +152,7 @@ GREATEST_TEST object_basename_closed(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "f.close();" "result = f.basename();" @@ -161,8 +161,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("file-1.txt", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("file-1.txt", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -170,7 +170,7 @@ GREATEST_TEST object_dirname(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "result = f.dirname();" ); @@ -178,8 +178,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ(SOURCE "/data/root", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ(SOURCE "/data/root", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -187,7 +187,7 @@ GREATEST_TEST object_dirname_closed(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "f.close();" "result = f.dirname();" @@ -196,8 +196,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ(SOURCE "/data/root", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ(SOURCE "/data/root", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -205,21 +205,21 @@ GREATEST_TEST object_lines(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "result = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r').lines();" ); if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_EQ(3, duk_get_length(data->ctx, -1)); - GREATEST_ASSERT(duk_get_prop_index(data->ctx, -1, 0)); - GREATEST_ASSERT_STR_EQ("a", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_prop_index(data->ctx, -2, 1)); - GREATEST_ASSERT_STR_EQ("b", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_prop_index(data->ctx, -3, 2)); - GREATEST_ASSERT_STR_EQ("c", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_EQ(3, duk_get_length(ctx, -1)); + GREATEST_ASSERT(duk_get_prop_index(ctx, -1, 0)); + GREATEST_ASSERT_STR_EQ("a", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_prop_index(ctx, -2, 1)); + GREATEST_ASSERT_STR_EQ("b", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_prop_index(ctx, -3, 2)); + GREATEST_ASSERT_STR_EQ("c", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -227,7 +227,7 @@ GREATEST_TEST object_lines_closed(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {" " f = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r');" " f.close();" @@ -240,8 +240,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -249,7 +249,7 @@ GREATEST_TEST object_seek1(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "f.seek(Irccd.File.SeekSet, 6);" "result = f.read(1);" @@ -258,8 +258,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ(".", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ(".", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -267,7 +267,7 @@ GREATEST_TEST object_seek2(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "f.seek(Irccd.File.SeekSet, 2);" "f.seek(Irccd.File.SeekCur, 4);" @@ -277,8 +277,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ(".", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ(".", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -286,7 +286,7 @@ GREATEST_TEST object_seek3(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "f.seek(Irccd.File.SeekEnd, -2);" "result = f.read(1);" @@ -295,8 +295,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("t", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("t", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -304,7 +304,7 @@ GREATEST_TEST object_seek_closed(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {" " f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" " f.close();" @@ -317,8 +317,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -326,7 +326,7 @@ GREATEST_TEST object_read(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" "result = f.read();" ); @@ -334,8 +334,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("file-1.txt\n", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("file-1.txt\n", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -343,7 +343,7 @@ GREATEST_TEST object_read_closed(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {" " f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');" " f.close();" @@ -356,8 +356,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -365,7 +365,7 @@ GREATEST_TEST object_readline(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "result = [];" "f = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r');" "for (var s; s = f.readline(); ) {" @@ -374,18 +374,18 @@ ); if (ret != 0) { - puts(duk_to_string(data->ctx, -1)); + puts(duk_to_string(ctx, -1)); GREATEST_FAIL(); } - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_EQ(3, duk_get_length(data->ctx, -1)); - GREATEST_ASSERT(duk_get_prop_index(data->ctx, -1, 0)); - GREATEST_ASSERT_STR_EQ("a", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_prop_index(data->ctx, -2, 1)); - GREATEST_ASSERT_STR_EQ("b", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_prop_index(data->ctx, -3, 2)); - GREATEST_ASSERT_STR_EQ("c", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_EQ(3, duk_get_length(ctx, -1)); + GREATEST_ASSERT(duk_get_prop_index(ctx, -1, 0)); + GREATEST_ASSERT_STR_EQ("a", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_prop_index(ctx, -2, 1)); + GREATEST_ASSERT_STR_EQ("b", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_prop_index(ctx, -3, 2)); + GREATEST_ASSERT_STR_EQ("c", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -393,7 +393,7 @@ GREATEST_TEST object_readline_closed(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {" " result = [];" " f = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r');" @@ -410,10 +410,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_EQ(0, duk_get_length(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_EQ(0, duk_get_length(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(ctx, -1)); GREATEST_PASS(); }
--- a/tests/test-jsapi-irccd.c Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/test-jsapi-irccd.c Fri Jan 29 15:03:23 2021 +0100 @@ -28,15 +28,15 @@ #include <irccd/plugin.h> static struct irc_plugin *plugin; -static struct irc_js_plugin_data *data; +static duk_context *ctx; static void setup(void *udata) { (void)udata; - plugin = irc_js_plugin_open(SOURCE "/data/example-plugin.js"); - data = plugin->data; + plugin = js_plugin_open(SOURCE "/data/example-plugin.js"); + ctx = js_plugin_get_context(plugin); } static void @@ -47,14 +47,14 @@ irc_plugin_finish(plugin); plugin = NULL; - data = NULL; + ctx = NULL; } static int throw(duk_context *ctx) { errno = EINVAL; - irc_jsapi_system_raise(ctx); + jsapi_system_raise(ctx); return 0; } @@ -62,7 +62,7 @@ GREATEST_TEST basics_version(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "major = Irccd.version.major;" "minor = Irccd.version.minor;" "patch = Irccd.version.patch;" @@ -71,12 +71,12 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "major")); - GREATEST_ASSERT_EQ(IRCCD_VERSION_MAJOR, duk_get_int(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "minor")); - GREATEST_ASSERT_EQ(IRCCD_VERSION_MINOR, duk_get_int(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "patch")); - GREATEST_ASSERT_EQ(IRCCD_VERSION_PATCH, duk_get_int(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "major")); + GREATEST_ASSERT_EQ(IRCCD_VERSION_MAJOR, duk_get_int(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "minor")); + GREATEST_ASSERT_EQ(IRCCD_VERSION_MINOR, duk_get_int(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "patch")); + GREATEST_ASSERT_EQ(IRCCD_VERSION_PATCH, duk_get_int(ctx, -1)); GREATEST_PASS(); } @@ -84,7 +84,7 @@ GREATEST_TEST basics_system_error_from_js(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {" " throw new Irccd.SystemError(1, 'test');" "} catch (e) {" @@ -99,16 +99,16 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "errno")); - GREATEST_ASSERT_EQ(1, duk_get_int(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "message")); - GREATEST_ASSERT_STR_EQ("test", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "v1")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "v2")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "errno")); + GREATEST_ASSERT_EQ(1, duk_get_int(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "message")); + GREATEST_ASSERT_STR_EQ("test", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "v1")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "v2")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); GREATEST_PASS(); } @@ -116,10 +116,10 @@ GREATEST_TEST basics_system_error_from_c(void) { - duk_push_c_function(data->ctx, throw, 0); - duk_put_global_string(data->ctx, "f"); + duk_push_c_function(ctx, throw, 0); + duk_put_global_string(ctx, "f"); - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {" " f();" "} catch (e) {" @@ -133,14 +133,14 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "errno")); - GREATEST_ASSERT_EQ(EINVAL, duk_get_int(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "v1")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "v2")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "errno")); + GREATEST_ASSERT_EQ(EINVAL, duk_get_int(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("SystemError", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "v1")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "v2")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); GREATEST_PASS(); }
--- a/tests/test-jsapi-system.c Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/test-jsapi-system.c Fri Jan 29 15:03:23 2021 +0100 @@ -26,15 +26,15 @@ #include <irccd/plugin.h> static struct irc_plugin *plugin; -static struct irc_js_plugin_data *data; +static duk_context *ctx; static void setup(void *udata) { (void)udata; - plugin = irc_js_plugin_open(SOURCE "/data/example-plugin.js"); - data = plugin->data; + plugin = js_plugin_open(SOURCE "/data/example-plugin.js"); + ctx = js_plugin_get_context(plugin); } static void @@ -45,13 +45,13 @@ irc_plugin_finish(plugin); plugin = NULL; - data = NULL; + ctx = NULL; } GREATEST_TEST basics_popen(void) { - int ret = duk_peval_string(data->ctx, + int ret = duk_peval_string(ctx, "f = Irccd.System.popen(\"" IRCCD_EXECUTABLE " version\", \"r\");" "r = f.readline();" ); @@ -59,8 +59,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "r")); - GREATEST_ASSERT_STR_EQ(IRCCD_VERSION, duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "r")); + GREATEST_ASSERT_STR_EQ(IRCCD_VERSION, duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -72,7 +72,7 @@ start = time(NULL); - if (duk_peval_string(data->ctx, "Irccd.System.sleep(2)") != 0) + if (duk_peval_string(ctx, "Irccd.System.sleep(2)") != 0) GREATEST_FAIL(); now = time(NULL); @@ -89,7 +89,7 @@ start = time(NULL); - if (duk_peval_string(data->ctx, "Irccd.System.usleep(2000000)") != 0) + if (duk_peval_string(ctx, "Irccd.System.usleep(2000000)") != 0) GREATEST_FAIL(); now = time(NULL);
--- a/tests/test-jsapi-unicode.c Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/test-jsapi-unicode.c Fri Jan 29 15:03:23 2021 +0100 @@ -30,15 +30,15 @@ #include <irccd/plugin.h> static struct irc_plugin *plugin; -static struct irc_js_plugin_data *data; +static duk_context *ctx; static void setup(void *udata) { (void)udata; - plugin = irc_js_plugin_open(SOURCE "/data/example-plugin.js"); - data = plugin->data; + plugin = js_plugin_open(SOURCE "/data/example-plugin.js"); + ctx = js_plugin_get_context(plugin); } static void @@ -49,19 +49,19 @@ irc_plugin_finish(plugin); plugin = NULL; - data = NULL; + ctx = NULL; } GREATEST_TEST basics_is_letter(void) { - duk_peval_string_noresult(data->ctx, "result = Irccd.Unicode.isLetter(String('é').charCodeAt(0));"); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); + duk_peval_string_noresult(ctx, "result = Irccd.Unicode.isLetter(String('é').charCodeAt(0));"); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); - duk_peval_string_noresult(data->ctx, "result = Irccd.Unicode.isLetter(String('€').charCodeAt(0));"); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(!duk_get_boolean(data->ctx, -1)); + duk_peval_string_noresult(ctx, "result = Irccd.Unicode.isLetter(String('€').charCodeAt(0));"); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(!duk_get_boolean(ctx, -1)); GREATEST_PASS(); } @@ -69,13 +69,13 @@ GREATEST_TEST basics_is_lower(void) { - duk_peval_string_noresult(data->ctx, "result = Irccd.Unicode.isLower(String('é').charCodeAt(0));"); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); + duk_peval_string_noresult(ctx, "result = Irccd.Unicode.isLower(String('é').charCodeAt(0));"); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); - duk_peval_string_noresult(data->ctx, "result = Irccd.Unicode.isLower(String('É').charCodeAt(0));"); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(!duk_get_boolean(data->ctx, -1)); + duk_peval_string_noresult(ctx, "result = Irccd.Unicode.isLower(String('É').charCodeAt(0));"); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(!duk_get_boolean(ctx, -1)); GREATEST_PASS(); } @@ -83,13 +83,13 @@ GREATEST_TEST basics_is_upper(void) { - duk_peval_string_noresult(data->ctx, "result = Irccd.Unicode.isUpper(String('É').charCodeAt(0));"); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(duk_get_boolean(data->ctx, -1)); + duk_peval_string_noresult(ctx, "result = Irccd.Unicode.isUpper(String('É').charCodeAt(0));"); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(duk_get_boolean(ctx, -1)); - duk_peval_string_noresult(data->ctx, "result = Irccd.Unicode.isUpper(String('é').charCodeAt(0));"); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT(!duk_get_boolean(data->ctx, -1)); + duk_peval_string_noresult(ctx, "result = Irccd.Unicode.isUpper(String('é').charCodeAt(0));"); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT(!duk_get_boolean(ctx, -1)); GREATEST_PASS(); }
--- a/tests/test-jsapi-util.c Fri Jan 29 13:50:44 2021 +0100 +++ b/tests/test-jsapi-util.c Fri Jan 29 15:03:23 2021 +0100 @@ -23,15 +23,15 @@ #include <irccd/plugin.h> static struct irc_plugin *plugin; -static struct irc_js_plugin_data *data; +static duk_context *ctx; static void setup(void *udata) { (void)udata; - plugin = irc_js_plugin_open(SOURCE "/data/example-plugin.js"); - data = plugin->data; + plugin = js_plugin_open(SOURCE "/data/example-plugin.js"); + ctx = js_plugin_get_context(plugin); } static void @@ -42,17 +42,17 @@ irc_plugin_finish(plugin); plugin = NULL; - data = NULL; + ctx = NULL; } GREATEST_TEST basics_splituser(void) { - if (duk_peval_string(data->ctx, "result = Irccd.Util.splituser(\"user!~user@hyper/super/host\");") != 0) + if (duk_peval_string(ctx, "result = Irccd.Util.splituser(\"user!~user@hyper/super/host\");") != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("user", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("user", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -60,11 +60,11 @@ GREATEST_TEST basics_splithost(void) { - if (duk_peval_string(data->ctx, "result = Irccd.Util.splithost(\"user!~user@hyper/super/host\");") != 0) + if (duk_peval_string(ctx, "result = Irccd.Util.splithost(\"user!~user@hyper/super/host\");") != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("hyper/super/host", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("hyper/super/host", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -80,15 +80,15 @@ GREATEST_TEST format_simple(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "result = Irccd.Util.format(\"#{target}\", { target: \"markand\" })" ); if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "result")); - GREATEST_ASSERT_STR_EQ("markand", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "result")); + GREATEST_ASSERT_STR_EQ("markand", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -101,7 +101,7 @@ GREATEST_TEST cut_string_simple(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "lines = Irccd.Util.cut('hello world');\n" "line0 = lines[0];\n" ); @@ -109,8 +109,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line0")); - GREATEST_ASSERT_STR_EQ("hello world", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line0")); + GREATEST_ASSERT_STR_EQ("hello world", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -118,7 +118,7 @@ GREATEST_TEST cut_string_double(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "lines = Irccd.Util.cut('hello world', 5);\n" "line0 = lines[0];\n" "line1 = lines[1];\n" @@ -127,10 +127,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line0")); - GREATEST_ASSERT_STR_EQ("hello", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line1")); - GREATEST_ASSERT_STR_EQ("world", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line0")); + GREATEST_ASSERT_STR_EQ("hello", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line1")); + GREATEST_ASSERT_STR_EQ("world", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -138,7 +138,7 @@ GREATEST_TEST cut_string_dirty(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "lines = Irccd.Util.cut(' hello world ', 5);\n" "line0 = lines[0];\n" "line1 = lines[1];\n" @@ -147,10 +147,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line0")); - GREATEST_ASSERT_STR_EQ("hello", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line1")); - GREATEST_ASSERT_STR_EQ("world", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line0")); + GREATEST_ASSERT_STR_EQ("hello", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line1")); + GREATEST_ASSERT_STR_EQ("world", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -158,7 +158,7 @@ GREATEST_TEST cut_string_too_much_lines(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {" " lines = Irccd.Util.cut('abc def ghi jkl', 3, 3);" "} catch (e) {\n" @@ -170,17 +170,17 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "message")); - GREATEST_ASSERT_STR_EQ("number of lines exceeds maxl (3)", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "message")); + GREATEST_ASSERT_STR_EQ("number of lines exceeds maxl (3)", duk_get_string(ctx, -1)); GREATEST_PASS(); } GREATEST_TEST cut_string_token_too_big(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {\n" " lines = Irccd.Util.cut('hello world', 3);\n" "} catch (e) {\n" @@ -192,10 +192,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "message")); - GREATEST_ASSERT_STR_EQ("token 'hello' could not fit in maxc limit (3)", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "message")); + GREATEST_ASSERT_STR_EQ("token 'hello' could not fit in maxc limit (3)", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -203,7 +203,7 @@ GREATEST_TEST cut_string_negative_maxc(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {\n" " lines = Irccd.Util.cut('hello world', -3);\n" "} catch (e) {\n" @@ -215,10 +215,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "message")); - GREATEST_ASSERT_STR_EQ("argument 1 (maxc) must be positive", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "message")); + GREATEST_ASSERT_STR_EQ("argument 1 (maxc) must be positive", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -226,7 +226,7 @@ GREATEST_TEST cut_string_negative_maxl(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {\n" " lines = Irccd.Util.cut('hello world', undefined, -1);\n" "} catch (e) {\n" @@ -238,10 +238,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "message")); - GREATEST_ASSERT_STR_EQ("argument 2 (maxl) must be positive", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("RangeError", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "message")); + GREATEST_ASSERT_STR_EQ("argument 2 (maxl) must be positive", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -249,7 +249,7 @@ GREATEST_TEST cut_array_simple(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "lines = Irccd.Util.cut([ 'hello', 'world' ]);\n" "line0 = lines[0];\n" ); @@ -257,8 +257,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line0")); - GREATEST_ASSERT_STR_EQ("hello world", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line0")); + GREATEST_ASSERT_STR_EQ("hello world", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -266,7 +266,7 @@ GREATEST_TEST cut_array_double(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "lines = Irccd.Util.cut([ 'hello', 'world' ], 5);\n" "line0 = lines[0];\n" "line1 = lines[1];\n" @@ -275,10 +275,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line0")); - GREATEST_ASSERT_STR_EQ("hello", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line1")); - GREATEST_ASSERT_STR_EQ("world", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line0")); + GREATEST_ASSERT_STR_EQ("hello", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line1")); + GREATEST_ASSERT_STR_EQ("world", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -286,7 +286,7 @@ GREATEST_TEST cut_array_dirty(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "lines = Irccd.Util.cut([ ' ', ' hello ', ' world ', ' '], 5);\n" "line0 = lines[0];\n" "line1 = lines[1];\n" @@ -295,10 +295,10 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line0")); - GREATEST_ASSERT_STR_EQ("hello", duk_get_string(data->ctx, -1)); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "line1")); - GREATEST_ASSERT_STR_EQ("world", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line0")); + GREATEST_ASSERT_STR_EQ("hello", duk_get_string(ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "line1")); + GREATEST_ASSERT_STR_EQ("world", duk_get_string(ctx, -1)); GREATEST_PASS(); } @@ -306,7 +306,7 @@ GREATEST_TEST cut_invalid_data(void) { - const int ret = duk_peval_string(data->ctx, + const int ret = duk_peval_string(ctx, "try {\n" " lines = Irccd.Util.cut(123);\n" "} catch (e) {\n" @@ -318,8 +318,8 @@ if (ret != 0) GREATEST_FAIL(); - GREATEST_ASSERT(duk_get_global_string(data->ctx, "name")); - GREATEST_ASSERT_STR_EQ("TypeError", duk_get_string(data->ctx, -1)); + GREATEST_ASSERT(duk_get_global_string(ctx, "name")); + GREATEST_ASSERT_STR_EQ("TypeError", duk_get_string(ctx, -1)); GREATEST_PASS(); }