Mercurial > irccd
changeset 939:a62c56c8b5ca
irccd: add partially the javascript API
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 13 Jan 2021 17:18:35 +0100 |
parents | 7b74df7e8913 |
children | 94cae3129870 |
files | Makefile config.mk irccd/main.c lib/irccd/js-plugin.c lib/irccd/js-plugin.h lib/irccd/jsapi-chrono.c lib/irccd/jsapi-chrono.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/limits.h lib/irccd/plugin.h lib/irccd/server.c lib/irccd/server.h lib/irccd/unicode.c lib/irccd/unicode.h lib/irccd/util.c |
diffstat | 30 files changed, 8283 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Mon Jan 11 21:25:58 2021 +0100 +++ b/Makefile Wed Jan 13 17:18:35 2021 +0100 @@ -34,11 +34,27 @@ LIBIRCCD= lib/libirccd.a LIBIRCCD_SRCS= lib/irccd/dl-plugin.c +LIBIRCCD_SRCS+= lib/irccd/irccd.c LIBIRCCD_SRCS+= lib/irccd/log.c LIBIRCCD_SRCS+= lib/irccd/plugin.c LIBIRCCD_SRCS+= lib/irccd/server.c LIBIRCCD_SRCS+= lib/irccd/subst.c LIBIRCCD_SRCS+= lib/irccd/util.c + +ifeq (${WITH_JS},yes) +LIBIRCCD_SRCS+= lib/irccd/js-plugin.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-chrono.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-file.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-irccd.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-logger.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-plugin.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-server.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-system.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-timer.c +LIBIRCCD_SRCS+= lib/irccd/jsapi-unicode.c +LIBIRCCD_SRCS+= lib/irccd/unicode.c +endif + LIBIRCCD_OBJS= ${LIBIRCCD_SRCS:.c=.o} LIBIRCCD_DEPS= ${LIBIRCCD_SRCS:.c=.d}
--- a/config.mk Mon Jan 11 21:25:58 2021 +0100 +++ b/config.mk Wed Jan 13 17:18:35 2021 +0100 @@ -20,6 +20,9 @@ CC= cc AR= ar +CFLAGS= -g -O0 -fsanitize=address,undefined +LDFLAGS= -fsanitize=address,undefined + # Installation paths. PREFIX= /usr/local BINDIR= bin
--- a/irccd/main.c Mon Jan 11 21:25:58 2021 +0100 +++ b/irccd/main.c Wed Jan 13 17:18:35 2021 +0100 @@ -16,52 +16,48 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <poll.h> #include <stdio.h> #include <err.h> #include <irccd/event.h> +#include <irccd/irccd.h> +#include <irccd/js-plugin.h> +#include <irccd/plugin.h> +#include <irccd/log.h> #include <irccd/server.h> +static struct irc_plugin js = { + .name = "example" +}; + int main(int argc, char **argv) { struct irc_server s = { .name = "malikania", - .host = "malikania.fr", + .hostname = "malikania.fr", .port = 6667, .nickname = "circ", .username = "circ", .realname = "circ" }; - struct irc_event ev; - - struct pollfd fd; - - irc_server_connect(&s); - irc_server_join(&s, "#test", NULL); - - for (;;) { - irc_server_prepare(&s, &fd); - - if (poll(&fd, 1, -1) < 0) - err(1, "poll"); - - irc_server_flush(&s, &fd); + struct irc_server freenode = { + .name = "freenode", + .hostname = "chat.freenode.net", + .port = 6667, + .nickname = "circ", + .username = "circ", + .realname = "circ" + }; - while (irc_server_poll(&s, &ev)) { - switch (ev.type) { - case IRC_EVENT_MESSAGE: - printf("message, origin=%s,channel=%s,message=%s\n", - ev.message.origin,ev.message.channel, ev.message.message); - break; - case IRC_EVENT_ME: - printf("me, origin=%s,channel=%s,message=%s\n", - ev.me.origin,ev.me.channel, ev.me.message); - break; - default: - break; - } - } - } + irc_init(); + irc_log_set_verbose(true); + irc_server_join(&s, "#test", NULL); + //irc_server_join(&freenode, "#irccd", NULL); + irc_add_server(&s); + irc_add_server(&freenode); + if (!irc_js_plugin_open(&js, "/Users/markand/Dev/irccd-4/test.js")) + return 1; + irc_add_plugin(&js); + irc_run(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-plugin.c Wed Jan 13 17:18:35 2021 +0100 @@ -0,0 +1,500 @@ +/* + * 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 <duktape.h> + +#include "event.h" +#include "js-plugin.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 "log.h" +#include "plugin.h" +#include "util.h" + +struct self { + duk_context *ctx; + char **options; + char **templates; + char **paths; + char *license; + char *version; + char *author; + char *description; +}; + +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 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, IRC_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, IRC_JSAPI_PLUGIN_PROP_TEMPLATES, key); +} + +static const char ** +get_templates(struct irc_plugin *plg) +{ + struct self *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 self *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 self *js = plg->data; + + return get_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_PATHS, key); +} + +static const char ** +get_paths(struct irc_plugin *plg) +{ + struct self *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 self *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 self *js = plg->data; + + return get_value(js->ctx, IRC_JSAPI_PLUGIN_PROP_OPTIONS, key); +} + +static const char ** +get_options(struct irc_plugin *plg) +{ + struct self *js = plg->data; + + return get_table(js->ctx, IRC_JSAPI_PLUGIN_PROP_OPTIONS, &js->options); +} + +static void +vcall(duk_context *ctx, const char *function, const char *fmt, va_list ap) +{ + int nargs = 0; + + printf("obtain %s\n", function); + duk_get_global_string(ctx, function); + + if (!duk_is_function(ctx, -1)) { + puts("not callable..."); + duk_pop(ctx); + return; + } + + for (const char *f = fmt; *f; ++f) { + bool array = false; + void (*push)(duk_context *, void *); + + switch (*f) { + case '>': + array = true; + break; + case 'S': + nargs++; + irc_jsapi_server_push(ctx, va_arg(ap, struct irc_server *)); + break; + case 's': + if (array) { + const char **list = va_arg(ap, const char **), **p; + int i = 0; + + duk_push_array(ctx); + + for (p = list; *p; ++p) { + nargs++; + duk_push_string(ctx, *p); + duk_put_prop_index(ctx, -2, i++); + }; + } else { + nargs++; + duk_push_string(ctx, va_arg(ap, const char *)); + } + break; + case 'x': + nargs++; + push = va_arg(ap, void (*)(duk_context *, void *)); + push(ctx, va_arg(ap, void *)); + break; + default: + break; + } + } + + if (duk_pcall(ctx, nargs) != 0) { + printf("errro: %s\n", duk_to_string(ctx, -1)); + } + + duk_pop(ctx); +} + +static void +call(struct irc_plugin *plg, const char *function, const char *fmt, ...) +{ + struct self *self = plg->data; + va_list ap; + + va_start(ap, fmt); + vcall(self->ctx, function, fmt, ap); + va_end(ap); +} + +static void +handle(struct irc_plugin *plg, const struct irc_event *ev) +{ + switch (ev->type) { + 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", "Ssss", ev->server, ev->invite.origin, + ev->invite.channel, ev->invite.nickname); + break; + case IRC_EVENT_JOIN: + call(plg, "onJoin", "Sss", ev->server, ev->join.origin, + ev->join.channel); + break; + case IRC_EVENT_KICK: + call(plg, "onKick", "Sssss", ev->server, ev->kick.origin, ev->kick.channel, + ev->kick.target, ev->kick.reason); + break; + case IRC_EVENT_ME: + call(plg, "onMe", "Ssss", ev->server, ev->me.origin, ev->me.channel, + ev->me.message); + break; + case IRC_EVENT_MESSAGE: + call(plg, "onMessage", "Ssss", ev->server, ev->message.origin, + ev->message.channel, ev->message.message); + break; + case IRC_EVENT_MODE: + call(plg, "onMode", "Sssssss", ev->server, ev->mode.origin, ev->mode.channel, + ev->mode.mode, ev->mode.limit, ev->mode.user, ev->mode.mask); + break; +#if 0 + case IRC_EVENT_NAMES: + call(plg, "onNames", "Ss>s", ev->names.server, ev->names.channel, + ev->names.names); + break; +#endif + case IRC_EVENT_NICK: + call(plg, "onNick", "Sss", ev->server, ev->nick.origin, ev->nick.nickname); + break; + case IRC_EVENT_NOTICE: + call(plg, "onNotice", "Ssss", ev->server, ev->notice.origin, + ev->notice.channel, ev->notice.message); + break; + case IRC_EVENT_PART: + call(plg, "onPart", "Ssss", ev->server, ev->part.origin, ev->part.channel, + ev->part.reason); + break; + case IRC_EVENT_TOPIC: + call(plg, "onTopic", "Ssss", ev->server, ev->topic.origin, + ev->topic.channel, ev->topic.topic); + break; +#if 0 + case IRC_EVENT_WHOIS: + call(plg, "onWhois", "Sx", ev->topic.server, js_event_whois_push, &ev->whois.whois); + break; +#endif + 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: + 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 bool +init(struct irc_plugin *plg, const char *script) +{ + struct self js = {0}; + + /* Load all modules. */ + js.ctx = duk_create_heap(wrap_malloc, wrap_realloc, wrap_free, NULL, NULL); + irc_jsapi_load(js.ctx); + irc_jsapi_file_load(js.ctx); + irc_jsapi_logger_load(js.ctx); + irc_jsapi_plugin_load(js.ctx, plg); + irc_jsapi_server_load(js.ctx); + irc_jsapi_system_load(js.ctx); + irc_jsapi_timer_load(js.ctx); + irc_jsapi_unicode_load(js.ctx); + + if (duk_peval_string(js.ctx, script) != 0) { + irc_log_warn("plugin %s: %s", plg->name, duk_to_string(js.ctx, -1)); + duk_destroy_heap(js.ctx); + return false; + } + + plg->license = js.license = metadata(js.ctx, "license"); + plg->version = js.version = metadata(js.ctx, "version"); + plg->author = js.author = metadata(js.ctx, "author"); + plg->description = js.description = metadata(js.ctx, "summary"); + plg->data = irc_util_memdup(&js, sizeof (js)); + + return true; +} + +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); + + free(self->license); + free(self->version); + free(self->author); + free(self->description); + + memset(self, 0, sizeof (*self)); +} + +bool +irc_js_plugin_open(struct irc_plugin *plg, const char *path) +{ + assert(plg); + assert(path); + + bool ret = false; + char *script = NULL; + + if (!(script = eat(path))) { + irc_log_warn("plugin: %s", strerror(errno)); + return false; + } + + if (!(init(plg, script))) { + free(script); + return false; + } + + plg->set_template = set_template; + plg->get_template = get_template; + plg->get_templates = get_templates; + plg->set_path = set_path; + plg->get_path = get_path; + plg->get_paths = get_paths; + plg->set_option = set_option; + plg->get_option = get_option; + plg->get_options = get_options; + plg->load = load; + plg->reload = reload; + plg->unload = unload; + plg->handle = handle; + plg->finish = finish; + + /* No longer needed. */ + free(script); + + /* If error occured, init() has logged. */ + return plg->data != NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-plugin.h Wed Jan 13 17:18:35 2021 +0100 @@ -0,0 +1,29 @@ +/* + * 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 <stdbool.h> + +struct irc_plugin; + +bool +irc_js_plugin_open(struct irc_plugin *, const char *); + +#endif /* !IRCCD_JS_PLUGIN_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-chrono.c Wed Jan 13 17:18:35 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 "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) + 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 (*self)); + timespec_get(&timer->start, TIME_UTC); + + duk_push_this(ctx); + duk_push_pointer(ctx, timer); + duk_put_prop_string(ctx, -2, SIGNATURE); + duk_pop(ctx); + + /* 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); + + 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_js_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/lib/irccd/jsapi-chrono.h Wed Jan 13 17:18:35 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 +irc_jsapi_chrono_load(duk_context *); + +#endif /* !IRCCD_JSAPI_CHRONO_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-file.c Wed Jan 13 17:18:35 2021 +0100 @@ -0,0 +1,514 @@ +/* + * 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 "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(IRCCD_HAVE_STAT_ST_ATIME) + duk_push_int(ctx, st.st_atime); + duk_put_prop_string(ctx, -2, "atime"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_BLKSIZE) + duk_push_int(ctx, st.st_blksize); + duk_put_prop_string(ctx, -2, "blksize"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_BLOCKS) + duk_push_int(ctx, st.st_blocks); + duk_put_prop_string(ctx, -2, "blocks"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_CTIME) + duk_push_int(ctx, st.st_ctime); + duk_put_prop_string(ctx, -2, "ctime"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_DEV) + duk_push_int(ctx, st.st_dev); + duk_put_prop_string(ctx, -2, "dev"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_GID) + duk_push_int(ctx, st.st_gid); + duk_put_prop_string(ctx, -2, "gid"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_INO) + duk_push_int(ctx, st.st_ino); + duk_put_prop_string(ctx, -2, "ino"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_MODE) + duk_push_int(ctx, st.st_mode); + duk_put_prop_string(ctx, -2, "mode"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_MTIME) + duk_push_int(ctx, st.st_mtime); + duk_put_prop_string(ctx, -2, "mtime"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_NLINK) + duk_push_int(ctx, st.st_nlink); + duk_put_prop_string(ctx, -2, "nlink"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_RDEV) + duk_push_int(ctx, st.st_rdev); + duk_put_prop_string(ctx, -2, "rdev"); +#endif +#if defined(IRCCD_HAVE_STAT_ST_SIZE) + duk_push_int(ctx, st.st_size); + duk_put_prop_string(ctx, -2, "size"); +#endif +#if defined(IRCCD_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) + 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 == -1 + ? 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 || ferror(file->fp)) { + free(line); + 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) + irc_jsapi_system_raise(ctx); + + 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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-file.h Wed Jan 13 17:18:35 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 +irc_jsapi_file_load(duk_context *); + +void +irc_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/lib/irccd/jsapi-irccd.c Wed Jan 13 17:18:35 2021 +0100 @@ -0,0 +1,322 @@ +/* + * 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 "util.h" + +static duk_ret_t +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 +}; + +/* }}} */ + +void +irc_jsapi_load(duk_context *ctx) +{ + /* Irccd (global object) */ + duk_push_object(ctx); + + /* Irccd.version (property) */ +#if 0 + 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"); +#endif + + /* 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"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-irccd.h Wed Jan 13 17:18:35 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 +irc_jsapi_load(duk_context *); + +#endif /* !IRCCD_JSAPI_IRCCD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-logger.c Wed Jan 13 17:18:35 2021 +0100 @@ -0,0 +1,73 @@ +/* + * 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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-logger.h Wed Jan 13 17:18:35 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 +irc_jsapi_logger_load(duk_context *); + +#endif /* !IRCCD_JSAPI_LOGGER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-plugin.c Wed Jan 13 17:18:35 2021 +0100 @@ -0,0 +1,242 @@ +/* + * 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)) + 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 duk_ret_t +Plugin_info(duk_context *ctx) +{ + struct irc_plugin *p; + + if (duk_get_top(ctx) >= 1) + p = irc_find_plugin(duk_require_string(ctx, 0)); + 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) +{ + duk_push_array(ctx); + + for (size_t i = 0; i < irc.pluginsz; ++i) { + duk_push_string(ctx, irc.plugins[i].name); + duk_put_prop_index(ctx, -2, i++); + } + + return 1; +} + +static duk_ret_t +Plugin_load(duk_context *ctx) +{ + return 0; +} + +static duk_ret_t +Plugin_reload(duk_context *ctx) +{ + return 0; +} + +static duk_ret_t +Plugin_unload(duk_context *ctx) +{ + 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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-plugin.h Wed Jan 13 17:18:35 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 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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-server.c Wed Jan 13 17:18:35 2021 +0100 @@ -0,0 +1,499 @@ +/* + * 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.h" +#include "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) +{ + /* + * Server are stored using their identifiers and searched in the + * registry as they may be removed at runtime. + */ + struct irc_server *sv; + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, SIGNATURE); + sv = irc_find_server(duk_to_string(ctx, -1)); + duk_pop_2(ctx); + + if (!sv) + 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)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); + + duk_get_prop_string(ctx, index, SIGNATURE); + sv = irc_find_server(duk_to_string(ctx, -1)); + duk_pop(ctx); + + return sv; +} + +static duk_ret_t +Server_prototype_info(duk_context *ctx) +{ + const struct irc_server *s = self(ctx); + + duk_push_object(ctx); + duk_push_string(ctx, s->name); + duk_put_prop_string(ctx, -2, "name"); + duk_push_string(ctx, s->hostname); + duk_put_prop_string(ctx, -2, "hostname"); + duk_push_uint(ctx, s->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->realname); + duk_put_prop_string(ctx, -2, "realname"); + duk_push_string(ctx, s->nickname); + duk_put_prop_string(ctx, -2, "nickname"); + duk_push_string(ctx, s->username); + duk_put_prop_string(ctx, -2, "username"); + + duk_push_array(ctx); + + for (size_t i = 0; i < s->channelsz; ++i) { + duk_push_string(ctx, s->channels[i].name); + duk_put_prop_index(ctx, -2, i); + } + + 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) +{ +#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 + +#if 0 + duk_push_boolean(ctx, irc_server_names(channel)); +#endif + + 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 + +#if 0 + duk_push_boolean(set_nickname(std::move(nickname)); +#endif + + return 0; +} + +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 + +#if 0 + duk_push_boolean(ctx, irc_server_whois(s, target)); +#endif + + 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) +{ +#if 0 + return wrap(ctx, [] (auto ctx) { + if (!duk_is_constructor_call(ctx)) + return 0; + + duk_check_type(ctx, 0, DUK_TYPE_OBJECT); + + auto json = nlohmann::json::parse(duk_json_encode(ctx, 0)); + auto s = from_json(duk::type_traits<bot>::self(ctx).get_service(), json); + + duk_push_this(ctx); + duk_push_pointer(ctx, new std::shared_ptr<server>(std::move(s))); + duk_put_prop_string(ctx, -2, signature.data()); + duk_pop(ctx); + + return 0; + }); +#endif + return 0; +} + +#if 0 + +static duk_ret_t +Server_add(duk_context *ctx) +{ + return wrap(ctx, [] (auto ctx) { + duk::type_traits<bot>::self(ctx).get_servers().add( + duk::require<std::shared_ptr<server>>(ctx, 0)); + + return 0; + }); +} + +#endif + +#if 0 + +static duk_ret_t +Server_find(duk_context *ctx) +{ + return wrap(ctx, [] (auto ctx) { + auto id = duk::require<std::string>(ctx, 0); + auto server = duk::type_traits<bot>::self(ctx).get_servers().get(id); + + if (!server) + return 0; + + duk::push(ctx, server); + + return 1; + }); +} + +#endif + +#if 0 + +static duk_ret_t +Server_list(duk_context *ctx) +{ + duk_push_object(ctx); + + for (const auto& server : duk::type_traits<bot>::self(ctx).get_servers().list()) { + duk::push(ctx, server); + duk_put_prop_string(ctx, -2, server->get_id().c_str()); + } + + return 1; +} + +#endif + +#if 0 + +static duk_ret_t +Server_remove(duk_context *ctx) +{ + duk::type_traits<bot>::self(ctx).get_servers().remove(duk_require_string(ctx, 0)); + + return 0; +} + +#endif + +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[] = { +#if 0 + { "add", Server_add, 1 }, + { "find", Server_find, 1 }, + { "list", Server_list, 0 }, + { "remove", Server_remove, 1 }, +#endif + { 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_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); + + duk_push_object(ctx); + duk_push_string(ctx, s->name); + 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/lib/irccd/jsapi-server.h Wed Jan 13 17:18:35 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 +irc_jsapi_server_push(duk_context *, struct irc_server *); + +void +irc_jsapi_server_load(duk_context *); + +#endif /* IRCCD_JSAPI_SERVER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-system.c Wed Jan 13 17:18:35 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 + return "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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-system.h Wed Jan 13 17:18:35 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 +irc_jsapi_system_raise(duk_context *); + +void +irc_jsapi_system_load(duk_context *); + +#endif /* !IRCCD_JSAPI_SYSTEM_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-timer.c Wed Jan 13 17:18:35 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.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). + */ + printf("FINISHED: %d, %d\n", rc, tm->status); + if (rc == ETIMEDOUT && tm->status == TIMER_ACTIVE) + irc_post(timer_expired, tm); + else + irc_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) + 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) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type"); + if (!duk_is_callable(ctx, 2)) + 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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-timer.h Wed Jan 13 17:18:35 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 +irc_jsapi_timer_load(duk_context *); + +#endif /* !IRCCD_JSAPI_TIMER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-unicode.c Wed Jan 13 17:18:35 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, 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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/jsapi-unicode.h Wed Jan 13 17:18:35 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 +irc_jsapi_unicode_load(duk_context *); + +#endif /* !IRCCD_JSAPI_UNICODE_H */
--- a/lib/irccd/limits.h Mon Jan 11 21:25:58 2021 +0100 +++ b/lib/irccd/limits.h Wed Jan 13 17:18:35 2021 +0100 @@ -37,5 +37,6 @@ /* Types limits. */ #define IRC_NAME_MAX 16 +#define IRC_COMMANDCHAR_MAX 8 #endif /* !IRCCD_LIMITS_H */
--- a/lib/irccd/plugin.h Mon Jan 11 21:25:58 2021 +0100 +++ b/lib/irccd/plugin.h Wed Jan 13 17:18:35 2021 +0100 @@ -21,10 +21,12 @@ #include <stdbool.h> +#include "limits.h" + struct irc_event; struct irc_plugin { - const char *name; + char name[IRC_NAME_MAX]; const char *license; const char *version; const char *author;
--- a/lib/irccd/server.c Mon Jan 11 21:25:58 2021 +0100 +++ b/lib/irccd/server.c Wed Jan 13 17:18:35 2021 +0100 @@ -437,6 +437,7 @@ static void clear(struct irc_server *s) { + puts("clear..."); s->state = IRC_SERVER_STATE_DISCONNECTED; if (s->fd != 0) { @@ -473,7 +474,7 @@ snprintf(service, sizeof (service), "%hu", s->port); - if ((ret = getaddrinfo(s->host, service, &hints, &s->ai)) != 0) + if ((ret = getaddrinfo(s->hostname, service, &hints, &s->ai)) != 0) irc_log_warn("server %s: %s", s->name, gai_strerror(ret)); s->aip = s->ai; @@ -783,6 +784,7 @@ { assert(s); + puts("HERE?!"); clear(s); } @@ -799,6 +801,9 @@ void irc_server_flush(struct irc_server *s, const struct pollfd *pfd) { + if (pfd->fd != s->fd) + return; + if (io_table[s->state].flush) io_table[s->state].flush(s, pfd); } @@ -872,6 +877,16 @@ } bool +irc_server_invite(struct irc_server *s, const char *target, const char *channel) +{ + assert(s); + assert(target); + assert(channel); + + return irc_server_send(s, "INVITE %s %s", target, channel); +} + +bool irc_server_join(struct irc_server *s, const char *name, const char *pass) { assert(s); @@ -899,6 +914,23 @@ } bool +irc_server_kick(struct irc_server *s, const char *target, const char *channel, const char *reason) +{ + assert(s); + assert(target); + assert(channel); + + bool ret; + + if (reason) + ret = irc_server_send(s, "KICK %s %s :%s", channel, target, reason); + else + ret = irc_server_send(s, "KICK %s %s", channel, target); + + return ret; +} + +bool irc_server_part(struct irc_server *s, const char *name, const char *reason) { assert(s); @@ -944,6 +976,34 @@ return irc_server_send(s, "PRIVMSG %s :\001ACTION %s\001", chan, message); } +bool +irc_server_mode(struct irc_server *s, + const char *channel, + const char *mode, + const char *limit, + const char *user, + const char *mask) +{ + assert(s); + assert(channel); + assert(mode); + + return irc_server_send(s, "MODE %s %s %s %s %s", channel, mode, + limit ? limit : "", + user ? user : "", + mask ? mask : ""); +} + +bool +irc_server_notice(struct irc_server *s, const char *target, const char *message) +{ + assert(s); + assert(target); + assert(message); + + return irc_server_send(s, "NOTICE %s: %s", target, message); +} + void irc_server_finish(struct irc_server *s) {
--- a/lib/irccd/server.h Mon Jan 11 21:25:58 2021 +0100 +++ b/lib/irccd/server.h Wed Jan 13 17:18:35 2021 +0100 @@ -70,10 +70,13 @@ struct irc_server { /* Connection settings. */ char name[IRC_NAME_MAX]; - char host[IRC_HOST_MAX]; + char hostname[IRC_HOST_MAX]; unsigned short port; enum irc_server_flags flags; + /* Plugin prefix. */ + char commandchar[IRC_COMMANDCHAR_MAX]; + /* IRC identity. */ char nickname[IRC_NICKNAME_MAX]; char username[IRC_USERNAME_MAX]; @@ -127,9 +130,15 @@ irc_server_send(struct irc_server *, const char *, ...); bool +irc_server_invite(struct irc_server *, const char *, const char *); + +bool irc_server_join(struct irc_server *, const char *, const char *); bool +irc_server_kick(struct irc_server *, const char *, const char *, const char *); + +bool irc_server_part(struct irc_server *, const char *, const char *); bool @@ -141,6 +150,17 @@ bool irc_server_me(struct irc_server *, const char *, const char *); +bool +irc_server_mode(struct irc_server *, + const char *, + const char *, + const char *, + const char *, + const char *); + +bool +irc_server_notice(struct irc_server *, const char *, const char *); + void irc_server_finish(struct irc_server *);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/unicode.c Wed Jan 13 17:18:35 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 +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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/unicode.h Wed Jan 13 17:18:35 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 +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 */