changeset 1037:8f8ce47aba8a

make: switch to GNU make
author David Demelier <markand@malikania.fr>
date Tue, 27 Apr 2021 09:22:16 +0200
parents bafb5943cd35
children b7585f0c3934
files .hgignore CMakeLists.txt GNUmakefile INSTALL.md README.md cmake/IrccdDefinePlugin.cmake examples/CMakeLists.txt extern/libcompat/CHANGES.md extern/libcompat/CMakeLists.txt extern/libcompat/CREDITS.md extern/libcompat/LICENSE.md extern/libcompat/README.md extern/libcompat/extern/queue/sys/queue.h extern/libcompat/src/basename.c extern/libcompat/src/compat.c extern/libcompat/src/compat.h.in extern/libcompat/src/dirname.c extern/libcompat/src/err.c extern/libcompat/src/errc.c extern/libcompat/src/errx.c extern/libcompat/src/getopt.c extern/libcompat/src/getprogname.c extern/libcompat/src/pledge.c extern/libcompat/src/reallocarray.c extern/libcompat/src/recallocarray.c extern/libcompat/src/setprogname.c extern/libcompat/src/strdup.c extern/libcompat/src/strlcat.c extern/libcompat/src/strlcpy.c extern/libcompat/src/strndup.c extern/libcompat/src/strnlen.c extern/libcompat/src/strsep.c extern/libcompat/src/strtok_r.c extern/libcompat/src/strtonum.c extern/libcompat/src/verr.c extern/libcompat/src/verrc.c extern/libcompat/src/verrx.c extern/libcompat/src/vsyslog.c extern/libcompat/src/vwarn.c extern/libcompat/src/vwarnc.c extern/libcompat/src/vwarnx.c extern/libcompat/src/warn.c extern/libcompat/src/warnc.c extern/libcompat/src/warnx.c extern/libcompat/tests/CMakeLists.txt extern/libcompat/tests/test-bsd.c extern/libcompat/tests/test-dirent.c extern/libcompat/tests/test-dlfcn.c extern/libcompat/tests/test-posix.c extern/libcompat/win/dirent/dirent.h extern/libcompat/win/dlfcn/CMakeLists.txt extern/libcompat/win/dlfcn/dlfcn.c extern/libcompat/win/dlfcn/dlfcn.h extern/libduktape/CMakeLists.txt extern/libgreatest/CMakeLists.txt extern/libketopt/CMakeLists.txt irccd/CMakeLists.txt irccd/conf.y irccd/dl-plugin.c irccd/js-plugin.c irccd/jsapi-directory.c irccd/jsapi-file.c irccd/jsapi-irccd.c irccd/jsapi-rule.c irccd/jsapi-util.c irccd/main.c irccd/peer.c irccd/transport.c irccdctl/CMakeLists.txt irccdctl/irccdctl.c irccdctl/main.c lib/CMakeLists.txt lib/IrccdConfig.cmake lib/irccd.pc lib/irccd.pc.in lib/irccd/channel.c lib/irccd/config.h.in lib/irccd/conn.c lib/irccd/event.c lib/irccd/hook.c lib/irccd/irccd.c lib/irccd/server.c lib/irccd/subst.c lib/irccd/util.c man/CMakeLists.txt plugins/CMakeLists.txt plugins/ask/CMakeLists.txt plugins/auth/CMakeLists.txt plugins/hangman/CMakeLists.txt plugins/history/CMakeLists.txt plugins/joke/CMakeLists.txt plugins/links/CMakeLists.txt plugins/links/links.c plugins/logger/CMakeLists.txt plugins/plugin/CMakeLists.txt plugins/roulette/CMakeLists.txt plugins/tictactoe/CMakeLists.txt tests/CMakeLists.txt tests/data/example-dl-plugin.c tests/test-dl-plugin.c tests/test-jsapi-chrono.c tests/test-jsapi-directory.c tests/test-jsapi-file.c tests/test-jsapi-irccd.c tests/test-jsapi-system.c tests/test-jsapi-unicode.c tests/test-jsapi-util.c tests/test-plugin-ask.c tests/test-plugin-auth.c tests/test-plugin-hangman.c tests/test-plugin-history.c tests/test-plugin-joke.c tests/test-plugin-logger.c tests/test-plugin-plugin.c tests/test-plugin-tictactoe.c
diffstat 115 files changed, 1545 insertions(+), 6774 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Apr 12 11:16:18 2021 +0200
+++ b/.hgignore	Tue Apr 27 09:22:16 2021 +0200
@@ -1,8 +1,7 @@
-# Build directory used in lots of documentation.
-^build
-
-# Qt Creator creates CMakeLists.txt.user.
-^CMakeLists\.txt\.user$
+# temporary files.
+\.a$
+\.d$
+\.o$
 
 # vim/emacs specific.
 ^tags$
@@ -15,6 +14,36 @@
 ^irccd/irccd$
 ^irccdctl/irccdctl$
 
+# generated files.
+^irccd/conf\.c$
+^irccd/conf\.h$
+^irccd/lex\.c$
+^lib/irccd/config\.h$
+
 # macOS specific.
 \.DS_Store$
 \.dSYM
+
+# tests files.
+^tests/test-bot$
+^tests/test-channel$
+^tests/test-event$
+^tests/test-jsapi-chrono$
+^tests/test-jsapi-directory$
+^tests/test-jsapi-file$
+^tests/test-jsapi-irccd$
+^tests/test-jsapi-timer$
+^tests/test-jsapi-unicode$
+^tests/test-jsapi-util$
+^tests/test-log$
+^tests/test-plugin-ask$
+^tests/test-plugin-auth$
+^tests/test-plugin-hangman$
+^tests/test-plugin-history$
+^tests/test-plugin-joke$
+^tests/test-plugin-logger$
+^tests/test-plugin-plugin$
+^tests/test-plugin-tictactoe$
+^tests/test-rule$
+^tests/test-subst$
+^tests/test-util$
--- a/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-cmake_minimum_required(VERSION 3.12)
-project(irccd)
-
-set_property(GLOBAL PROPERTY USE_FOLDERS On)
-
-set(IRCCD_VERSION_MAJOR 4)
-set(IRCCD_VERSION_MINOR 0)
-set(IRCCD_VERSION_PATCH 0)
-set(IRCCD_VERSION "${IRCCD_VERSION_MAJOR}.${IRCCD_VERSION_MINOR}.${IRCCD_VERSION_PATCH}")
-
-option(IRCCD_WITH_JS "Enable Javascript" On)
-option(IRCCD_WITH_SSL "Enable SSL support" On)
-option(IRCCD_WITH_IRCCD "Enable irccd daemon" On)
-option(IRCCD_WITH_IRCCDCTL "Enable irccdctl utility" On)
-option(IRCCD_WITH_TESTS "Enable unit tests" Off)
-
-if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
-	set(CMAKE_C_FLAGS "-Wall -Wextra ${CMAKE_C_FLAGS}")
-endif ()
-
-set(CMAKE_POSITION_INDEPENDENT_CODE On)
-
-include(GNUInstallDirs)
-
-include(cmake/IrccdDefinePlugin.cmake)
-
-find_package(FLEX REQUIRED)
-find_package(BISON REQUIRED)
-
-if (IRCCD_WITH_SSL)
-	find_package(OpenSSL REQUIRED)
-endif ()
-
-add_subdirectory(extern/libcompat)
-add_subdirectory(extern/libketopt)
-
-if (IRCCD_WITH_JS)
-	add_subdirectory(extern/libduktape)
-endif ()
-
-add_subdirectory(lib)
-add_subdirectory(irccd)
-add_subdirectory(irccdctl)
-add_subdirectory(examples)
-add_subdirectory(plugins)
-add_subdirectory(man)
-
-if (IRCCD_WITH_TESTS)
-	enable_testing()
-	add_subdirectory(extern/libgreatest)
-	add_subdirectory(tests)
-endif ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GNUmakefile	Tue Apr 27 09:22:16 2021 +0200
@@ -0,0 +1,332 @@
+#
+# GNUmakefile -- GNU make for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+CC=             cc
+CFLAGS=         -O0 -DNDEBUG -Wall -Wextra -Wno-cpp -g -fPIC
+
+PREFIX=         /usr/local
+BINDIR=         ${PREFIX}/bin
+ETCDIR=         ${PREFIX}/etc
+INCDIR=         ${PREFIX}/include
+LIBDIR=         ${PREFIX}/lib
+MANDIR=         ${PREFIX}/share/man
+SHAREDIR=       ${PREFIX}/share
+VARDIR=         ${PREFIX}/var
+
+SSL=            1
+JS=             1
+
+MAJOR=          4
+MINOR=          0
+PATCH=          0
+
+LIB_SRCS=       lib/irccd/channel.c \
+                lib/irccd/conn.c \
+                lib/irccd/event.c \
+                lib/irccd/hook.c \
+                lib/irccd/irccd.c \
+                lib/irccd/log.c \
+                lib/irccd/plugin.c \
+                lib/irccd/rule.c \
+                lib/irccd/server.c \
+                lib/irccd/subst.c \
+                lib/irccd/util.c
+LIB_OBJS=       ${LIB_SRCS:.c=.o}
+LIB_DEPS=       ${LIB_SRCS:.c=.d}
+
+IRCCD_SRCS=     irccd/conf.c \
+                irccd/dl-plugin.c \
+                irccd/lex.c \
+                irccd/peer.c \
+                irccd/transport.c \
+                irccd/unicode.c
+
+ifeq (${JS},1)
+IRCCD_SRCS+=    extern/libduktape/duktape.c \
+                irccd/js-plugin.c \
+                irccd/jsapi-chrono.c \
+                irccd/jsapi-directory.c \
+                irccd/jsapi-file.c \
+                irccd/jsapi-hook.c \
+                irccd/jsapi-irccd.c \
+                irccd/jsapi-logger.c \
+                irccd/jsapi-plugin.c \
+                irccd/jsapi-rule.c \
+                irccd/jsapi-server.c \
+                irccd/jsapi-system.c \
+                irccd/jsapi-timer.c \
+                irccd/jsapi-unicode.c \
+                irccd/jsapi-util.c
+endif
+
+IRCCD_OBJS=     ${IRCCD_SRCS:.c=.o}
+IRCCD_DEPS=     ${IRCCD_SRCS:.c=.d}
+
+MAN1=           man/irccd.1 \
+                man/irccdctl.1
+
+MAN3=           man/irccd-api-chrono.3 \
+                man/irccd-api-directory.3 \
+                man/irccd-api-file.3 \
+                man/irccd-api-hook.3 \
+                man/irccd-api-logger.3 \
+                man/irccd-api-plugin.3 \
+                man/irccd-api-rule.3 \
+                man/irccd-api-server.3 \
+                man/irccd-api-system.3 \
+                man/irccd-api-timer.3 \
+                man/irccd-api-unicode.3 \
+                man/irccd-api-util.3 \
+                man/irccd-api.3 \
+                man/libirccd-channel.3 \
+                man/libirccd-compat.3 \
+                man/libirccd-event.3 \
+                man/libirccd-hook.3 \
+                man/libirccd-log.3 \
+                man/libirccd-rule.3 \
+                man/libirccd-subst.3 \
+                man/libirccd-util.3 \
+                man/libirccd.3
+
+MAN5=           man/irccd.conf.5
+
+MAN7=           man/irccd-ipc.7 \
+                man/irccd-templates.7
+
+PLUGINS.js=     ask auth hangman history joke logger plugin roulette tictactoe
+PLUGINS.c=      links
+
+TESTS=          tests/test-bot.c                \
+                tests/test-channel.c            \
+                tests/test-dl-plugin.c          \
+                tests/test-event.c              \
+                tests/test-log.c                \
+                tests/test-rule.c               \
+                tests/test-subst.c              \
+                tests/test-util.c
+
+ifeq (${JS},1)
+TESTS+=         tests/test-jsapi-chrono.c       \
+                tests/test-jsapi-directory.c    \
+                tests/test-jsapi-file.c         \
+                tests/test-jsapi-irccd.c        \
+                tests/test-jsapi-timer.c        \
+                tests/test-jsapi-system.c       \
+                tests/test-jsapi-unicode.c      \
+                tests/test-jsapi-util.c         \
+                tests/test-plugin-ask.c         \
+                tests/test-plugin-auth.c        \
+                tests/test-plugin-hangman.c     \
+                tests/test-plugin-history.c     \
+                tests/test-plugin-joke.c        \
+                tests/test-plugin-logger.c      \
+                tests/test-plugin-plugin.c      \
+                tests/test-plugin-tictactoe.c
+endif
+
+TESTS_OBJS=     ${TESTS:.c=}
+
+# Compile flags.
+DEFS=           -D_BSD_SOURCE -DLIBBSD_OVERLAY -DTOP=\"`pwd`\"
+
+# Include directories.
+INCS=           -I lib/
+INCS+=          -I ./
+INCS+=          -I extern/libgreatest/
+INCS+=          -I extern/libketopt/
+INCS+=          $(shell pkg-config --cflags libbsd-overlay)
+
+ifeq (${SSL},1)
+INCS+=          $(shell pkg-config --cflags openssl)
+endif
+ifeq (${JS},1)
+INCS+=          -I extern/libduktape
+endif
+
+# Whole libraries for every binaries.
+LIBS+=          $(shell pkg-config --libs libbsd-overlay)
+
+ifeq (${SSL},1)
+LIBS+=          $(shell pkg-config --libs openssl)
+endif
+
+# For config.h file.
+ifeq (${SSL},1)
+SED.ssl=        s/@define WITH_SSL@/\#define IRCCD_WITH_SSL/
+else
+SED.ssl=        /@define WITH_SSL@/d
+
+endif
+ifeq (${JS},1)
+SED.js=         s/@define WITH_JS@/\#define IRCCD_WITH_JS/
+else
+SED.js=         /@define WITH_JS@/d
+endif
+
+# Per system commands.
+OS:=            $(shell uname -s)
+
+ifeq (${OS},Darwin)
+SHFLAGS=        -undefined dynamic_lookup
+else
+SHFLAGS=        -shared
+endif
+
+CMD.cc=         ${CC} ${DEFS} ${INCS} ${CFLAGS} -MMD -c $< -o $@
+CMD.ccld=       ${CC} ${DEFS} ${INCS} ${CFLAGS} -o $@ $^ ${LIBS} ${LDFLAGS}
+CMD.cchost=     ${CC} -Wl,-E -o $@ ${DEFS} ${INCS} ${CFLAGS} \
+	-Wl,--whole-archive $^ -Wl,--no-whole-archive ${LIBS} ${LDFLAGS}
+CMD.ccplg=      ${CC} ${DEFS} ${INCS} ${CFLAGS} ${SHFLAGS} -o $@ $^ ${LIBS} ${LDFLAGS}
+
+.SUFFIXES:
+.SUFFIXES: .c .o .js
+
+# Template for Javascript plugins.
+define js-plugin =
+PLUGINS.all+=   plugin-${1}
+PLUGINS.inst+=  install-plugin-${1}
+
+.PHONY: plugin-${1}
+plugin-${1}:
+
+.PHONY: install-plugin-${1}
+install-plugin-${1}:
+	mkdir -p ${DESTDIR}${LIBDIR}/irccd
+	mkdir -p ${DESTDIR}${MANDIR}/man7
+	cp plugins/${1}/${1}.js ${DESTDIR}${LIBDIR}/irccd
+	cp plugins/${1}/${1}.7 ${DESTDIR}${MANDIR}/man7/irccd-plugin-${1}.7
+endef
+
+# Template for C native plugins.
+define c-plugin =
+PLUGINS.all+=   plugin-${1}
+PLUGINS.objs+=  plugins/${1}/${1}.so
+PLUGINS.inst+=  install-plugin-${1}
+
+.PHONY: plugin-${1}
+plugin-${1}: plugins/${1}/${1}.so
+
+.PHONY: install-plugin-${1}
+install-plugin-${1}:
+	mkdir -p ${DESTDIR}${LIBDIR}/irccd
+	mkdir -p ${DESTDIR}${MANDIR}/man7
+	cp plugins/${1}/${1}.so ${DESTDIR}${LIBDIR}/irccd
+	cp plugins/${1}/${1}.7 ${DESTDIR}${MANDIR}/man7/irccd-plugin-${1}.7
+endef
+
+.c.o:
+	${CMD.cc}
+
+.c:
+	${CMD.ccld}
+
+all: irccd/irccd irccdctl/irccdctl
+
+-include ${LIB_DEPS} ${IRCCD_DEPS}
+
+lib/irccd/config.h: lib/irccd/config.h.in
+	sed -e "s,@ETCDIR@,${ETCDIR},g" \
+		-e "s,@LIBDIR@,${LIBDIR},g" \
+		-e "s,@SHAREDIR@,${SHAREDIR},g" \
+		-e "s,@VARDIR@,${VARDIR},g" \
+		-e "s,@MAJOR@,${MAJOR},g" \
+		-e "s,@MINOR@,${MINOR},g" \
+		-e "s,@PATCH@,${PATCH},g" \
+		-e "${SED.ssl}" \
+		-e "${SED.js}" \
+		< $< > $@
+
+${LIB_OBJS} ${IRCCD_OBJS} irccd/main.o: lib/irccd/config.h
+
+irccd/conf.c: irccd/conf.y
+	bison -d -o $@ $<
+
+irccd/lex.c: irccd/lex.l
+	flex -o $@ $<
+
+irccd/irccd: irccd/main.o ${IRCCD_OBJS} ${LIB_OBJS}
+	${CMD.cchost}
+
+irccdctl/irccdctl: ${LIB_OBJS}
+
+$(foreach p,${PLUGINS.js},$(eval $(call js-plugin,${p})))
+$(foreach p,${PLUGINS.c},$(eval $(call c-plugin,${p})))
+
+install:
+	mkdir -p ${DESTDIR}${BINDIR}
+	cp irccd/irccd ${DESTDIR}${BINDIR}
+	chmod 755 ${DESTDIR}${BINDIR}/irccd
+	cp irccdctl/irccdctl ${DESTDIR}${BINDIR}
+	chmod 755 ${DESTDIR}${BINDIR}/irccdctl
+	mkdir -p ${DESTDIR}${MANDIR}/man1
+	cp ${MAN1} ${DESTDIR}${MANDIR}/man1
+	mkdir -p ${DESTDIR}${MANDIR}/man3
+	cp ${MAN3} ${DESTDIR}${MANDIR}/man3
+	mkdir -p ${DESTDIR}${MANDIR}/man5
+	cp ${MAN5} ${DESTDIR}${MANDIR}/man5
+	mkdir -p ${DESTDIR}${MANDIR}/man7
+	cp ${MAN7} ${DESTDIR}${MANDIR}/man7
+	mkdir -p ${DESTDIR}${ETCDIR}
+	cp irccd/irccd.conf ${DESTDIR}${ETCDIR}/irccd.conf.sample
+	mkdir -p ${DESTDIR}${LIBDIR}/pkgconfig
+	sed -e "s,@MAJOR@,${MAJOR}," \
+		-e "s,@MINOR@,${MINOR}," \
+		-e "s,@PATCH@,${PATCH}," \
+		-e "s,@INCDIR@,${INCDIR}," \
+		-e "s,@SHFLAGS@,${SHFLAGS}," \
+		< lib/irccd.pc.in > ${DESTDIR}${LIBDIR}/pkgconfig/irccd.pc
+
+install-plugins: ${PLUGINS.inst}
+
+install-systemd:
+	mkdir -p ${DESTDIR}${LIBDIR}/systemd/system
+	sed -e "s,@PATH@,${BINDIR}/irccd," \
+		< systemd/irccd.service \
+		> ${DESTDIR}${LIBDIR}/systemd/system/irccd.service
+
+tests/data/example-dl-plugin.so: tests/data/example-dl-plugin.c
+	${CMD.ccplg}
+
+${TESTS_OBJS}: ${IRCCD_OBJS} ${LIB_OBJS} | irccd/irccd tests/data/example-dl-plugin.so
+
+# Generic plugin build command.
+plugins/%.so: plugins/%.c | ${IRCCD_OBJS}
+	${CMD.ccplg}
+
+# Plugin `links` require libcurl.
+plugins/links/links.so: plugins/links/links.c ${LIB_OBJS}
+	${CMD.ccplg} $(shell pkg-config --libs --cflags libcurl)
+
+plugins: ${PLUGINS.all}
+
+tests/%: tests/%.c
+	${CMD.cchost}
+
+tests: ${TESTS_OBJS}
+	for t in ${TESTS_OBJS}; do ./$$t -v; done
+
+clean:
+	rm -f lib/irccd/config.h ${LIB_OBJS} ${LIB_DEPS}
+	rm -f irccd/irccd irccd/main.o irccd/main.d \
+		irccd/conf.c irccd/conf.h irccd/lex.c \
+		${IRCCD_OBJS} ${IRCCD_DEPS}
+	rm -f irccdctl/irccdctl
+	rm -f ${TESTS_OBJS} tests/data/example-dl-plugin.so
+	rm -f ${PLUGINS.objs}
+
+.PHONY: all clean install install-plugins install-systemd plugins tests
--- a/INSTALL.md	Mon Apr 12 11:16:18 2021 +0200
+++ b/INSTALL.md	Tue Apr 27 09:22:16 2021 +0200
@@ -1,16 +1,20 @@
 IRC Client Daemon INSTALL
 =========================
 
-This guide will help you to install irccd
+This guide will help you to install irccd.
 
 Requirements
 ------------
 
+Runtime dependencies:
+
+- [libbsd][]: some BSD extensions.
+
 Build dependencies:
 
-- C99 and few features from C11 (stdatomics, stdnoreturn).
+- C99 and few features from C11 (stdatomics.h, stdnoreturn.h).
 - [Bison][] and [Flex][]: For configuration files.
-- [CMake][]: Portable build system.
+- [GNU Make][]: The GNU make utility.
 
 Optional runtime dependencies:
 
@@ -24,14 +28,54 @@
 
     tar xvzf irccd-x.y.z-tar.xz
     cd irccd-x.y.z
-    mkdir build
-    cd build
-    cmake .. -DCMAKE_BUILD_TYPE=Release
     make
     sudo make install
 
+### Installing plugins
+
+And to install plugins you must build and use `plugins` and `install-plugins`
+targets:
+
+    make plugins
+    sudo make install-plugins
+
+Alternatively you can build and install plugins manually using `plugin-NAME` and
+`install-plugin-NAME` to install only wanted plugins.
+
+Example:
+
+    make plugin-ask plugin-links
+    sudo make install-plugin-ask plugin-links
+
+### Systemd service
+
+A systemd service is available through the `install-systemd` target. The service
+file is named `irccd.service`.
+
+Options
+-------
+
+The following options are available at build time (make sure to run `make clean`
+when you change options).
+
+- `SSL`: set to 1 or 0 to enable/disable OpenSSL (default: 1).
+- `JS`: set to 1 or 0 to disable Javascript (default: 1).
+
+You can tweak the installation directories by changing the following variables
+(note: all paths must be absolute):
+
+- `PREFIX`: root directory for installing (default: /usr/local).
+- `BINDIR`: binaries (default: ${PREFIX}/bin).
+- `ETCDIR`: config files (default: ${PREFIX}/etc).
+- `LIBDIR`: libraries (default: ${PREFIX}/lib).
+- `INCDIR`: header files (default: ${PREFIX}/include).
+- `SHAREDIR`: data files (default: ${PREFIX}/share).
+- `MANDIR`: path to manual pages (default: ${PREFIX}/share/man).
+- `VARDIR`: local cache files (default: ${PREFIX}/var).
+
 [Bison]: https://www.gnu.org/software/bison
-[CMake]: http://www.cmake.org
+[GNU Make]: http://www.cmake.org
 [CURL]: https://curl.se
 [Flex]: https://github.com/westes/flex
 [OpenSSL]: http://openssl.org
+[libbsd]: https://libbsd.freedesktop.org/wiki
--- a/README.md	Mon Apr 12 11:16:18 2021 +0200
+++ b/README.md	Tue Apr 27 09:22:16 2021 +0200
@@ -1,27 +1,25 @@
 IRC Client Daemon
 =================
 
-IRC Client Daemon aka irccd is a full featured IRC bot written in C++17. It runs
-as a daemon waiting for events. It's also possible to connect to more than one
+IRC Client Daemon aka irccd is a full featured IRC bot written in C. It runs as
+a daemon waiting for events. It's also possible to connect to more than one
 server.
 
-Irccd is also able to use optional JavaScript plugins to do specific actions on
+Irccd is also able to use optional Javascript plugins to do specific actions on
 these events.
 
-Irccd is also controllable via internet and unix sockets, this let you use irccd
-as a message relayer and such.
+Irccd is also controllable via unix sockets allowing you use irccd as a message
+relayer and such.
 
 Features
 --------
 
-  - Can use JavaScript to create plugins,
-  - Can connect to multiple servers,
-  - Support multiple identities,
-  - Can be controlled by sockets and irccdctl,
-  - Runs on Linux, Windows and \*BSD,
-  - Extremely well documented,
-  - Clean and powerful JavaScript API,
-  - Very fast and light.
+- Can use Javascript to create plugins,
+- Can connect to multiple servers,
+- Can be controlled by sockets and irccdctl,
+- Extremely well documented,
+- Clean and powerful Javascript API,
+- Very fast and light.
 
 Documentation
 -------------
--- a/cmake/IrccdDefinePlugin.cmake	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-include(GNUInstallDirs)
-
-function(_idp_install_man file)
-	get_filename_component(basename ${file} NAME)
-	configure_file(${file} ${CMAKE_CURRENT_BINARY_DIR}/${basename})
-
-	install(
-		FILES ${CMAKE_CURRENT_BINARY_DIR}/${basename}
-		DESTINATION ${CMAKE_INSTALL_MANDIR}/man7
-		RENAME irccd-plugin-${basename}
-	)
-endfunction ()
-
-function(irccd_define_js_plugin)
-	set(options "")
-	set(oneValueArgs MAN NAME SCRIPT)
-	set(multiValueArgs "")
-
-	cmake_parse_arguments(PLG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
-	if (NOT PLG_NAME)
-		message(FATAL_ERROR "Missing NAME argument")
-	elseif (NOT PLG_SCRIPT)
-		message(FATAL_ERROR "Missing SCRIPT argument")
-	endif ()
-
-	# Create a dummy custom target just to get it through the IDE.
-	add_custom_target(
-		irccd-plugin-${PLG_NAME}
-		SOURCES ${PLG_SCRIPT} ${PLG_MAN}
-	)
-	set_target_properties(irccd-plugin-${PLG_NAME} PROPERTIES FOLDER "plugins")
-
-	# Install script.
-	get_filename_component(basename ${PLG_SCRIPT} NAME)
-	configure_file(${PLG_SCRIPT} ${CMAKE_CURRENT_BINARY_DIR}/${basename})
-
-	install(
-		FILES ${CMAKE_CURRENT_BINARY_DIR}/${basename}
-		DESTINATION ${CMAKE_INSTALL_LIBDIR}/irccd
-	)
-
-	if (PLG_MAN)
-		_idp_install_man(${PLG_MAN})
-	endif ()
-endfunction()
-
-function(irccd_define_c_plugin)
-	set(options "")
-	set(oneValueArgs NAME MAN)
-	set(multiValueArgs INCLUDES LIBRARIES SOURCES)
-
-	cmake_parse_arguments(PLG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
-	if (NOT PLG_NAME)
-		message(FATAL_ERROR "Missing NAME argument")
-	elseif (NOT PLG_SOURCES)
-		message(FATAL_ERROR "Missing SOURCES argument")
-	endif ()
-
-	add_library(irccd-plugin-${PLG_NAME} MODULE ${PLG_SOURCES} ${PLG_MAN})
-	target_link_libraries(irccd-plugin-${PLG_NAME} irccd::libirccd ${PLG_LIBRARIES})
-	set_target_properties(irccd-plugin-${PLG_NAME}
-		PROPERTIES
-			PREFIX ""
-			PROJECT_LABEL "irccd"
-			FOLDER "plugins"
-			OUTPUT_NAME ${PLG_NAME}
-			RUNTIME_OUTPUT_NAME_${c} ${PLG_NAME}
-	)
-	install(TARGETS irccd-plugin-${PLG_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/irccd)
-
-	foreach (c ${CMAKE_CONFIGURATION_TYPES})
-		string(TOUPPER ${c} c)
-		set_target_properties(irccd-plugin-${PLG_NAME}
-			PROPERTIES
-				OUTPUT_NAME_${c} ${PLG_NAME}
-				RUNTIME_OUTPUT_NAME_${c} ${PLG_NAME}
-		)
-	endforeach ()
-
-	#
-	# This is required but not enabled by default, otherwise we get
-	# undefined errors from any libirccd functions.
-	#
-	if (APPLE)
-		set_target_properties(irccd-plugin-${PLG_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
-	endif ()
-
-	if (PLG_MAN)
-		_idp_install_man(${PLG_MAN})
-	endif ()
-endfunction()
--- a/examples/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(examples)
-
-install(
-	FILES
-		${examples_SOURCE_DIR}/sample-plugin.c
-		${examples_SOURCE_DIR}/sample-plugin.js
-	DESTINATION ${CMAKE_INSTALL_DATADIR}/irccd
-)
--- a/extern/libcompat/CHANGES.md	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-libcompat CHANGES
-=================
-
-libcompat current
------------------------------
-
-project name 1.0.0 2017-12-25
------------------------------
-
-- Some topic,
-- Other topics.
--- a/extern/libcompat/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for libcompat
-#
-# Copyright (c) 2020-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.
-#
-
-cmake_minimum_required(VERSION 3.10)
-project(libirccd-compat)
-
-option(COMPAT_WITH_TESTS "Enable tests" Off)
-
-include(CheckFunctionExists)
-include(CheckIncludeFile)
-include(CheckStructHasMember)
-include(CheckSymbolExists)
-
-set(
-	SOURCES
-	${libirccd-compat_SOURCE_DIR}/src/compat.c
-	${libirccd-compat_SOURCE_DIR}/src/compat.h.in
-)
-
-set(
-	FUNCTIONS
-	# BSD extensions.
-	err
-	errc
-	errx
-	getprogname
-	pledge
-	reallocarray
-	recallocarray
-	setprogname
-	strlcat
-	strlcpy
-	strsep
-	strtonum
-	verr
-	verrc
-	verrx
-	vsyslog
-	vwarn
-	vwarnc
-	vwarnx
-	warn
-	warnc
-	warnx
-	# POSIX functions.
-	basename
-	dirname
-	getopt
-	strdup
-	strndup
-	strnlen
-	strtok_r
-)
-
-set(
-	INCLUDES
-	# BSD extensions.
-	err.h
-	# POSIX extensions.
-	unistd.h
-	libgen.h
-)
-
-foreach (f ${FUNCTIONS})
-	string(TOUPPER ${f} var)
-
-	check_function_exists(${f} COMPAT_HAVE_${var})
-
-	if (NOT COMPAT_HAVE_${var})
-		list(APPEND SOURCES ${libirccd-compat_SOURCE_DIR}/src/${f}.c)
-	endif ()
-endforeach ()
-
-# Functionalities we can't replace
-check_include_file(syslog.h COMPAT_HAVE_SYSLOG_H)
-
-add_library(libirccd-compat STATIC ${SOURCES})
-target_include_directories(
-	libirccd-compat
-	PUBLIC
-		$<BUILD_INTERFACE:${libirccd-compat_BINARY_DIR}>
-		$<BUILD_INTERFACE:${libirccd-compat_BINARY_DIR}/irccd>
-)
-set_target_properties(libirccd-compat PROPERTIES PREFIX "" FOLDER extern)
-
-# Remove useless C4996 warning about "deprecated" functions from MSVC.
-if (CMAKE_C_COMPILER_ID MATCHES MSVC)
-	target_compile_options(libirccd-compat PUBLIC /wd4996)
-endif ()
-
-foreach (i ${INCLUDES})
-	string(TOUPPER ${i} var)
-	string(REGEX REPLACE "\\." "_" var ${var})
-
-	check_include_file(${i} COMPAT_HAVE_${var})
-
-	if (NOT COMPAT_HAVE_${var})
-		file(WRITE ${libirccd-compat_BINARY_DIR}/${i} "/* Empty stub for ${i}. */\n")
-
-		install(
-			FILES ${libirccd-compat_BINARY_DIR}/${i}
-			DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/irccd/extern
-		)
-	endif ()
-endforeach ()
-
-# POSIX dirent.h
-check_include_file(dirent.h COMPAT_HAVE_DIRENT_H)
-
-if (NOT COMPAT_HAVE_DIRENT_H)
-	if (CMAKE_SYSTEM_NAME MATCHES "Windows")
-		target_include_directories(
-			libirccd-compat
-			PUBLIC
-				$<BUILD_INTERFACE:${libirccd-compat_SOURCE_DIR}/win/dirent>
-		)
-	endif ()
-endif ()
-
-# Specific BSD sys/queue.h file
-check_include_file(sys/queue.h COMPAT_HAVE_SYS_QUEUE_H)
-
-if (NOT COMPAT_HAVE_SYS_QUEUE_H)
-	target_include_directories(
-		libirccd-compat
-		PUBLIC
-			$<BUILD_INTERFACE:${libirccd-compat_SOURCE_DIR}/extern/queue>
-	)
-
-	install(
-		FILES ${libirccd-compat_SOURCE_DIR}/extern/queue/sys/queue.h
-		DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/irccd/extern/sys
-	)
-else ()
-	#
-	# Make sure it has at least _SAFE macros because some implementations
-	# may provide terribly outdated queue.h (e.g. glibc).
-	#
-	check_symbol_exists(LIST_FOREACH_SAFE sys/queue.h COMPAT_HAVE_LIST_FOREACH_SAFE)
-	check_symbol_exists(SLIST_FOREACH_SAFE sys/queue.h COMPAT_HAVE_SLIST_FOREACH_SAFE)
-	check_symbol_exists(STAILQ_FOREACH_SAFE sys/queue.h COMPAT_HAVE_STAILQ_FOREACH_SAFE)
-	check_symbol_exists(TAILQ_FOREACH_SAFE sys/queue.h COMPAT_HAVE_TAILQ_FOREACH_SAFE)
-
-	if (NOT COMPAT_HAVE_LIST_FOREACH_SAFE OR
-	    NOT COMPAT_HAVE_SLIST_FOREACH_SAFE OR
-	    NOT COMPAT_HAVE_STAILQ_FOREACH_SAFE OR
-	    NOT COMPAT_HAVE_TAILQ_FOREACH_SAFE)
-		target_include_directories(
-			libirccd-compat
-			PUBLIC
-				$<BUILD_INTERFACE:${libirccd-compat_SOURCE_DIR}/extern/queue>
-		)
-	endif ()
-endif ()
-
-# Math library
-find_library(COMPAT_HAVE_LIBM m)
-
-if (NOT COMPAT_HAVE_LIBM)
-	add_library(m INTERFACE)
-endif ()
-
-# POSIX dlfcn.h
-check_include_file(dlfcn.h COMPAT_HAVE_DLFCN_H)
-
-if (NOT COMPAT_HAVE_DLFCN_H)
-	if (CMAKE_SYSTEM_NAME MATCHES "Windows")
-		add_subdirectory(win/dlfcn)
-	endif ()
-else ()
-	# Some systems may not provide the dl library.
-	find_library(COMPAT_HAVE_LIBDL dl)
-
-	if (NOT COMPAT_HAVE_LIBDL)
-		add_library(dl INTERFACE)
-	endif ()
-endif ()
-
-# struct stat fields
-check_struct_has_member("struct stat" st_atime sys/stat.h COMPAT_HAVE_STAT_ST_ATIME)
-check_struct_has_member("struct stat" st_blksize sys/stat.h COMPAT_HAVE_STAT_ST_BLKSIZE)
-check_struct_has_member("struct stat" st_blocks sys/stat.h COMPAT_HAVE_STAT_ST_BLOCKS)
-check_struct_has_member("struct stat" st_ctime sys/stat.h COMPAT_HAVE_STAT_ST_CTIME)
-check_struct_has_member("struct stat" st_dev sys/stat.h COMPAT_HAVE_STAT_ST_DEV)
-check_struct_has_member("struct stat" st_gid sys/stat.h COMPAT_HAVE_STAT_ST_GID)
-check_struct_has_member("struct stat" st_ino sys/stat.h COMPAT_HAVE_STAT_ST_INO)
-check_struct_has_member("struct stat" st_mode sys/stat.h COMPAT_HAVE_STAT_ST_MODE)
-check_struct_has_member("struct stat" st_mtime sys/stat.h COMPAT_HAVE_STAT_ST_MTIME)
-check_struct_has_member("struct stat" st_nlink sys/stat.h COMPAT_HAVE_STAT_ST_NLINK)
-check_struct_has_member("struct stat" st_rdev sys/stat.h COMPAT_HAVE_STAT_ST_RDEV)
-check_struct_has_member("struct stat" st_size sys/stat.h COMPAT_HAVE_STAT_ST_SIZE)
-check_struct_has_member("struct stat" st_uid sys/stat.h COMPAT_HAVE_STAT_ST_UID)
-
-if (COMPAT_WITH_TESTS)
-	enable_testing()
-	add_subdirectory(tests)
-endif ()
-
-configure_file(
-	${libirccd-compat_SOURCE_DIR}/src/compat.h.in
-	${libirccd-compat_BINARY_DIR}/irccd/compat.h
-)
-
-install(
-	FILES ${libirccd-compat_BINARY_DIR}/irccd/compat.h
-	DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/irccd
-)
--- a/extern/libcompat/CREDITS.md	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-libcompat CREDITS
-=================
-
-Libraries and projects
-----------------------
-
-- [OpenBSD](http://openbsd.org): innovated several technologies.
-- [dirent.h for Windows](https://github.com/tronkko/dirent): polyfill
-  implementation for Windows.
--- a/extern/libcompat/LICENSE.md	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-libcompat LICENSES
-==================
-
-Some files in this projects are licensed under different licenses and must be
-checked individually. Few files are kindly borrowed from OpenBSD and other
-projects.
-
-Other home made code in this repository is licensed under the following license:
-
-ISC
----
-
-Copyright (c) 2020-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.
--- a/extern/libcompat/README.md	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-libcompat
-=========
-
-This project contains several polyfill for various C extensions that are not
-part of C standard or POSIX.
-
-For example, it contains various functions such as:
-
-- pledge: privileges separation from OpenBSD (no-op on other systems),
-- reallocarray/recallocarray: safe alternative to realloc for arrays from
-  OpenBSD,
-- strlcpy/strlcat: safer alternatives to strncpy/strncat from OpenBSD,
-- strsep: better alternative to strtok from 4.4BSD.
-
-Requirements
-------------
-
-- C compiler,
-- POSIX conformant system (ar, make, sh, rm, tr, touch).
-
-Usage
------
-
-The easiest way to use libcompat is to copy the directory content into your
-project and to adapt files you need.
-
-Every routine (or group of routines) is implemented into an individual file
-plus tested with a test file.
-
-Example with strlcpy:
-
-- libcompat/strlcpy.c
-- libcompat/test-strlcpy.c
-
-Then, the build process create the following output files, example with
-strlcpy:
-
-- libcompat/strlcpy.t: output of the compiler command, usually empty on
-  success.
-- libcompat/strlcpy.h: a header file containing `#define COMPAT_HAVE_STRLCPY`
-  if the test succeed.
-- libcompat/strlcpy.o: object file containing fallback implementation or
-  nothing if the component is available in the host system.
-
-Finally, when you want to use one of the extension, you'll have to import the
-header file where it's supposed to be declared (unless this header file is not
-portable) and you also must include libcompat/compat.h.
-
-Example with strlcpy:
-
-	#include <string.h>
-	#include "libcompat/compat.h"
-
-### Wrapper script
-
-The convenient script libcompat/compile.sh will try co compile the test and
-will either compile the polyfill or a dummy empty file instead. It should be
-invoked with the canonical filename (without extension).
-
-It also read `CC`, `CFLAGS` and `LDFLAGS` environment variable which are all
-optional.
-
-Example of use:
-
-	./libcompat/compile.sh strlcpy
-	CC="clang" CFLAGS="-O2" ./libcompat/compile.sh strlcat
-
-### Makefile
-
-The included Makefile can be used as boilerplate into your project and create a
-libcompat.a archive ready to use. Simply adapt macros in the Makefile for your
-own use.
-
-Licenses
---------
-
-Polyfill code are licensed per their authors and must be checked individually.
-See headers in the libcompat directory.
-
-Author
-------
-
-David Demelier <markand@malikania.fr>
--- a/extern/libcompat/extern/queue/sys/queue.h	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,615 +0,0 @@
-/*	$OpenBSD: queue.h,v 1.46 2020/12/30 13:33:12 millert Exp $	*/
-/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/
-
-/*
- * Copyright (c) 1991, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)queue.h	8.5 (Berkeley) 8/20/94
- */
-
-#ifndef	_SYS_QUEUE_H_
-#define	_SYS_QUEUE_H_
-
-/*
- * This file defines five types of data structures: singly-linked lists,
- * lists, simple queues, tail queues and XOR simple queues.
- *
- *
- * A singly-linked list is headed by a single forward pointer. The elements
- * are singly linked for minimum space and pointer manipulation overhead at
- * the expense of O(n) removal for arbitrary elements. New elements can be
- * added to the list after an existing element or at the head of the list.
- * Elements being removed from the head of the list should use the explicit
- * macro for this purpose for optimum efficiency. A singly-linked list may
- * only be traversed in the forward direction.  Singly-linked lists are ideal
- * for applications with large datasets and few or no removals or for
- * implementing a LIFO queue.
- *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before
- * or after an existing element or at the head of the list. A list
- * may only be traversed in the forward direction.
- *
- * A simple queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are singly
- * linked to save space, so elements can only be removed from the
- * head of the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the
- * list. A simple queue may only be traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or
- * after an existing element, at the head of the list, or at the end of
- * the list. A tail queue may be traversed in either direction.
- *
- * An XOR simple queue is used in the same way as a regular simple queue.
- * The difference is that the head structure also includes a "cookie" that
- * is XOR'd with the queue pointer (first, last or next) to generate the
- * real pointer value.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- */
-
-/*
- * Singly-linked List definitions.
- */
-#define SLIST_HEAD(name, type)						\
-struct name {								\
-	struct type *slh_first;	/* first element */			\
-}
-
-#define	SLIST_HEAD_INITIALIZER(head)					\
-	{ NULL }
-
-#define SLIST_ENTRY(type)						\
-struct {								\
-	struct type *sle_next;	/* next element */			\
-}
-
-/*
- * Singly-linked List access methods.
- */
-#define	SLIST_FIRST(head)	((head)->slh_first)
-#define	SLIST_END(head)		NULL
-#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
-#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
-
-#define	SLIST_FOREACH(var, head, field)					\
-	for((var) = SLIST_FIRST(head);					\
-	    (var) != SLIST_END(head);					\
-	    (var) = SLIST_NEXT(var, field))
-
-#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = SLIST_FIRST(head);				\
-	    (var) && ((tvar) = SLIST_NEXT(var, field), 1);		\
-	    (var) = (tvar))
-
-/*
- * Singly-linked List functions.
- */
-#define	SLIST_INIT(head) {						\
-	SLIST_FIRST(head) = SLIST_END(head);				\
-}
-
-#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
-	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
-	(slistelm)->field.sle_next = (elm);				\
-} while (0)
-
-#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
-	(elm)->field.sle_next = (head)->slh_first;			\
-	(head)->slh_first = (elm);					\
-} while (0)
-
-#define	SLIST_REMOVE_AFTER(elm, field) do {				\
-	(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
-} while (0)
-
-#define	SLIST_REMOVE_HEAD(head, field) do {				\
-	(head)->slh_first = (head)->slh_first->field.sle_next;		\
-} while (0)
-
-#define SLIST_REMOVE(head, elm, type, field) do {			\
-	if ((head)->slh_first == (elm)) {				\
-		SLIST_REMOVE_HEAD((head), field);			\
-	} else {							\
-		struct type *curelm = (head)->slh_first;		\
-									\
-		while (curelm->field.sle_next != (elm))			\
-			curelm = curelm->field.sle_next;		\
-		curelm->field.sle_next =				\
-		    curelm->field.sle_next->field.sle_next;		\
-	}								\
-} while (0)
-
-/*
- * List definitions.
- */
-#define LIST_HEAD(name, type)						\
-struct name {								\
-	struct type *lh_first;	/* first element */			\
-}
-
-#define LIST_HEAD_INITIALIZER(head)					\
-	{ NULL }
-
-#define LIST_ENTRY(type)						\
-struct {								\
-	struct type *le_next;	/* next element */			\
-	struct type **le_prev;	/* address of previous next element */	\
-}
-
-/*
- * List access methods.
- */
-#define	LIST_FIRST(head)		((head)->lh_first)
-#define	LIST_END(head)			NULL
-#define	LIST_EMPTY(head)		(LIST_FIRST(head) == LIST_END(head))
-#define	LIST_NEXT(elm, field)		((elm)->field.le_next)
-
-#define LIST_FOREACH(var, head, field)					\
-	for((var) = LIST_FIRST(head);					\
-	    (var)!= LIST_END(head);					\
-	    (var) = LIST_NEXT(var, field))
-
-#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = LIST_FIRST(head);				\
-	    (var) && ((tvar) = LIST_NEXT(var, field), 1);		\
-	    (var) = (tvar))
-
-/*
- * List functions.
- */
-#define	LIST_INIT(head) do {						\
-	LIST_FIRST(head) = LIST_END(head);				\
-} while (0)
-
-#define LIST_INSERT_AFTER(listelm, elm, field) do {			\
-	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
-		(listelm)->field.le_next->field.le_prev =		\
-		    &(elm)->field.le_next;				\
-	(listelm)->field.le_next = (elm);				\
-	(elm)->field.le_prev = &(listelm)->field.le_next;		\
-} while (0)
-
-#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
-	(elm)->field.le_prev = (listelm)->field.le_prev;		\
-	(elm)->field.le_next = (listelm);				\
-	*(listelm)->field.le_prev = (elm);				\
-	(listelm)->field.le_prev = &(elm)->field.le_next;		\
-} while (0)
-
-#define LIST_INSERT_HEAD(head, elm, field) do {				\
-	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
-		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
-	(head)->lh_first = (elm);					\
-	(elm)->field.le_prev = &(head)->lh_first;			\
-} while (0)
-
-#define LIST_REMOVE(elm, field) do {					\
-	if ((elm)->field.le_next != NULL)				\
-		(elm)->field.le_next->field.le_prev =			\
-		    (elm)->field.le_prev;				\
-	*(elm)->field.le_prev = (elm)->field.le_next;			\
-} while (0)
-
-#define LIST_REPLACE(elm, elm2, field) do {				\
-	if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
-		(elm2)->field.le_next->field.le_prev =			\
-		    &(elm2)->field.le_next;				\
-	(elm2)->field.le_prev = (elm)->field.le_prev;			\
-	*(elm2)->field.le_prev = (elm2);				\
-} while (0)
-
-/*
- * Simple queue definitions.
- */
-#define SIMPLEQ_HEAD(name, type)					\
-struct name {								\
-	struct type *sqh_first;	/* first element */			\
-	struct type **sqh_last;	/* addr of last next element */		\
-}
-
-#define SIMPLEQ_HEAD_INITIALIZER(head)					\
-	{ NULL, &(head).sqh_first }
-
-#define SIMPLEQ_ENTRY(type)						\
-struct {								\
-	struct type *sqe_next;	/* next element */			\
-}
-
-/*
- * Simple queue access methods.
- */
-#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
-#define	SIMPLEQ_END(head)	    NULL
-#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
-#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
-
-#define SIMPLEQ_FOREACH(var, head, field)				\
-	for((var) = SIMPLEQ_FIRST(head);				\
-	    (var) != SIMPLEQ_END(head);					\
-	    (var) = SIMPLEQ_NEXT(var, field))
-
-#define	SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = SIMPLEQ_FIRST(head);				\
-	    (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1);		\
-	    (var) = (tvar))
-
-/*
- * Simple queue functions.
- */
-#define	SIMPLEQ_INIT(head) do {						\
-	(head)->sqh_first = NULL;					\
-	(head)->sqh_last = &(head)->sqh_first;				\
-} while (0)
-
-#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
-	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
-		(head)->sqh_last = &(elm)->field.sqe_next;		\
-	(head)->sqh_first = (elm);					\
-} while (0)
-
-#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
-	(elm)->field.sqe_next = NULL;					\
-	*(head)->sqh_last = (elm);					\
-	(head)->sqh_last = &(elm)->field.sqe_next;			\
-} while (0)
-
-#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
-		(head)->sqh_last = &(elm)->field.sqe_next;		\
-	(listelm)->field.sqe_next = (elm);				\
-} while (0)
-
-#define SIMPLEQ_REMOVE_HEAD(head, field) do {			\
-	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
-		(head)->sqh_last = &(head)->sqh_first;			\
-} while (0)
-
-#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
-	if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
-	    == NULL)							\
-		(head)->sqh_last = &(elm)->field.sqe_next;		\
-} while (0)
-
-#define SIMPLEQ_CONCAT(head1, head2) do {				\
-	if (!SIMPLEQ_EMPTY((head2))) {					\
-		*(head1)->sqh_last = (head2)->sqh_first;		\
-		(head1)->sqh_last = (head2)->sqh_last;			\
-		SIMPLEQ_INIT((head2));					\
-	}								\
-} while (0)
-
-/*
- * XOR Simple queue definitions.
- */
-#define XSIMPLEQ_HEAD(name, type)					\
-struct name {								\
-	struct type *sqx_first;	/* first element */			\
-	struct type **sqx_last;	/* addr of last next element */		\
-	unsigned long sqx_cookie;					\
-}
-
-#define XSIMPLEQ_ENTRY(type)						\
-struct {								\
-	struct type *sqx_next;	/* next element */			\
-}
-
-/*
- * XOR Simple queue access methods.
- */
-#define XSIMPLEQ_XOR(head, ptr)	    ((__typeof(ptr))((head)->sqx_cookie ^ \
-					(unsigned long)(ptr)))
-#define	XSIMPLEQ_FIRST(head)	    XSIMPLEQ_XOR(head, ((head)->sqx_first))
-#define	XSIMPLEQ_END(head)	    NULL
-#define	XSIMPLEQ_EMPTY(head)	    (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
-#define	XSIMPLEQ_NEXT(head, elm, field)    XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
-
-
-#define XSIMPLEQ_FOREACH(var, head, field)				\
-	for ((var) = XSIMPLEQ_FIRST(head);				\
-	    (var) != XSIMPLEQ_END(head);				\
-	    (var) = XSIMPLEQ_NEXT(head, var, field))
-
-#define	XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = XSIMPLEQ_FIRST(head);				\
-	    (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1);	\
-	    (var) = (tvar))
-
-/*
- * XOR Simple queue functions.
- */
-#define	XSIMPLEQ_INIT(head) do {					\
-	arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
-	(head)->sqx_first = XSIMPLEQ_XOR(head, NULL);			\
-	(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first);	\
-} while (0)
-
-#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
-	if (((elm)->field.sqx_next = (head)->sqx_first) ==		\
-	    XSIMPLEQ_XOR(head, NULL))					\
-		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
-	(head)->sqx_first = XSIMPLEQ_XOR(head, (elm));			\
-} while (0)
-
-#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
-	(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL);		\
-	*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
-	(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);	\
-} while (0)
-
-#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if (((elm)->field.sqx_next = (listelm)->field.sqx_next) ==	\
-	    XSIMPLEQ_XOR(head, NULL))					\
-		(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
-	(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm));		\
-} while (0)
-
-#define XSIMPLEQ_REMOVE_HEAD(head, field) do {				\
-	if (((head)->sqx_first = XSIMPLEQ_XOR(head,			\
-	    (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
-		(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
-} while (0)
-
-#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
-	if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head,			\
-	    (elm)->field.sqx_next)->field.sqx_next)			\
-	    == XSIMPLEQ_XOR(head, NULL))				\
-		(head)->sqx_last = 					\
-		    XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);		\
-} while (0)
-
-
-/*
- * Tail queue definitions.
- */
-#define TAILQ_HEAD(name, type)						\
-struct name {								\
-	struct type *tqh_first;	/* first element */			\
-	struct type **tqh_last;	/* addr of last next element */		\
-}
-
-#define TAILQ_HEAD_INITIALIZER(head)					\
-	{ NULL, &(head).tqh_first }
-
-#define TAILQ_ENTRY(type)						\
-struct {								\
-	struct type *tqe_next;	/* next element */			\
-	struct type **tqe_prev;	/* address of previous next element */	\
-}
-
-/*
- * Tail queue access methods.
- */
-#define	TAILQ_FIRST(head)		((head)->tqh_first)
-#define	TAILQ_END(head)			NULL
-#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
-#define TAILQ_LAST(head, headname)					\
-	(*(((struct headname *)((head)->tqh_last))->tqh_last))
-/* XXX */
-#define TAILQ_PREV(elm, headname, field)				\
-	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-#define	TAILQ_EMPTY(head)						\
-	(TAILQ_FIRST(head) == TAILQ_END(head))
-
-#define TAILQ_FOREACH(var, head, field)					\
-	for((var) = TAILQ_FIRST(head);					\
-	    (var) != TAILQ_END(head);					\
-	    (var) = TAILQ_NEXT(var, field))
-
-#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = TAILQ_FIRST(head);					\
-	    (var) != TAILQ_END(head) &&					\
-	    ((tvar) = TAILQ_NEXT(var, field), 1);			\
-	    (var) = (tvar))
-
-
-#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
-	for((var) = TAILQ_LAST(head, headname);				\
-	    (var) != TAILQ_END(head);					\
-	    (var) = TAILQ_PREV(var, headname, field))
-
-#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
-	for ((var) = TAILQ_LAST(head, headname);			\
-	    (var) != TAILQ_END(head) &&					\
-	    ((tvar) = TAILQ_PREV(var, headname, field), 1);		\
-	    (var) = (tvar))
-
-/*
- * Tail queue functions.
- */
-#define	TAILQ_INIT(head) do {						\
-	(head)->tqh_first = NULL;					\
-	(head)->tqh_last = &(head)->tqh_first;				\
-} while (0)
-
-#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
-	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
-		(head)->tqh_first->field.tqe_prev =			\
-		    &(elm)->field.tqe_next;				\
-	else								\
-		(head)->tqh_last = &(elm)->field.tqe_next;		\
-	(head)->tqh_first = (elm);					\
-	(elm)->field.tqe_prev = &(head)->tqh_first;			\
-} while (0)
-
-#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
-	(elm)->field.tqe_next = NULL;					\
-	(elm)->field.tqe_prev = (head)->tqh_last;			\
-	*(head)->tqh_last = (elm);					\
-	(head)->tqh_last = &(elm)->field.tqe_next;			\
-} while (0)
-
-#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
-		(elm)->field.tqe_next->field.tqe_prev =			\
-		    &(elm)->field.tqe_next;				\
-	else								\
-		(head)->tqh_last = &(elm)->field.tqe_next;		\
-	(listelm)->field.tqe_next = (elm);				\
-	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
-} while (0)
-
-#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
-	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
-	(elm)->field.tqe_next = (listelm);				\
-	*(listelm)->field.tqe_prev = (elm);				\
-	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
-} while (0)
-
-#define TAILQ_REMOVE(head, elm, field) do {				\
-	if (((elm)->field.tqe_next) != NULL)				\
-		(elm)->field.tqe_next->field.tqe_prev =			\
-		    (elm)->field.tqe_prev;				\
-	else								\
-		(head)->tqh_last = (elm)->field.tqe_prev;		\
-	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
-} while (0)
-
-#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
-	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
-		(elm2)->field.tqe_next->field.tqe_prev =		\
-		    &(elm2)->field.tqe_next;				\
-	else								\
-		(head)->tqh_last = &(elm2)->field.tqe_next;		\
-	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
-	*(elm2)->field.tqe_prev = (elm2);				\
-} while (0)
-
-#define TAILQ_CONCAT(head1, head2, field) do {				\
-	if (!TAILQ_EMPTY(head2)) {					\
-		*(head1)->tqh_last = (head2)->tqh_first;		\
-		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
-		(head1)->tqh_last = (head2)->tqh_last;			\
-		TAILQ_INIT((head2));					\
-	}								\
-} while (0)
-
-/*
- * Singly-linked Tail queue declarations.
- */
-#define	STAILQ_HEAD(name, type)						\
-struct name {								\
-	struct type *stqh_first;	/* first element */		\
-	struct type **stqh_last;	/* addr of last next element */	\
-}
-
-#define	STAILQ_HEAD_INITIALIZER(head)					\
-	{ NULL, &(head).stqh_first }
-
-#define	STAILQ_ENTRY(type)						\
-struct {								\
-	struct type *stqe_next;	/* next element */			\
-}
-
-/*
- * Singly-linked Tail queue access methods.
- */
-#define	STAILQ_FIRST(head)	((head)->stqh_first)
-#define	STAILQ_END(head)	NULL
-#define	STAILQ_EMPTY(head)	(STAILQ_FIRST(head) == STAILQ_END(head))
-#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
-
-#define STAILQ_FOREACH(var, head, field)				\
-	for ((var) = STAILQ_FIRST(head);				\
-	    (var) != STAILQ_END(head);					\
-	    (var) = STAILQ_NEXT(var, field))
-
-#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
-	for ((var) = STAILQ_FIRST(head);				\
-	    (var) && ((tvar) = STAILQ_NEXT(var, field), 1);		\
-	    (var) = (tvar))
-
-/*
- * Singly-linked Tail queue functions.
- */
-#define	STAILQ_INIT(head) do {						\
-	STAILQ_FIRST((head)) = NULL;					\
-	(head)->stqh_last = &STAILQ_FIRST((head));			\
-} while (0)
-
-#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
-	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
-		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
-	STAILQ_FIRST((head)) = (elm);					\
-} while (0)
-
-#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
-	STAILQ_NEXT((elm), field) = NULL;				\
-	*(head)->stqh_last = (elm);					\
-	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
-} while (0)
-
-#define	STAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((elm), field)) == NULL)\
-		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
-	STAILQ_NEXT((elm), field) = (elm);				\
-} while (0)
-
-#define STAILQ_REMOVE_HEAD(head, field) do {                            \
-	if ((STAILQ_FIRST((head)) =					\
-	    STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
-		(head)->stqh_last = &STAILQ_FIRST((head));		\
-} while (0)
-
-#define STAILQ_REMOVE_AFTER(head, elm, field) do {                      \
-	if ((STAILQ_NEXT(elm, field) =					\
-	    STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)	\
-		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
-} while (0)
-
-#define	STAILQ_REMOVE(head, elm, type, field) do {			\
-	if (STAILQ_FIRST((head)) == (elm)) {				\
-		STAILQ_REMOVE_HEAD((head), field);			\
-	} else {							\
-		struct type *curelm = (head)->stqh_first;		\
-		while (STAILQ_NEXT(curelm, field) != (elm))		\
-			curelm = STAILQ_NEXT(curelm, field);		\
-		STAILQ_REMOVE_AFTER(head, curelm, field);		\
-	}								\
-} while (0)
-
-#define	STAILQ_CONCAT(head1, head2) do {				\
-	if (!STAILQ_EMPTY((head2))) {					\
-		*(head1)->stqh_last = (head2)->stqh_first;		\
-		(head1)->stqh_last = (head2)->stqh_last;		\
-		STAILQ_INIT((head2));					\
-	}								\
-} while (0)
-
-#define	STAILQ_LAST(head, type, field)					\
-	(STAILQ_EMPTY((head)) ?	NULL :					\
-	        ((struct type *)(void *)				\
-		((char *)((head)->stqh_last) - offsetof(struct type, field))))
-
-#endif	/* !_SYS_QUEUE_H_ */
--- a/extern/libcompat/src/basename.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*	$OpenBSD: basename.c,v 1.17 2020/10/20 19:30:14 naddy Exp $	*/
-
-/*
- * Copyright (c) 1997, 2004 Todd C. Miller <millert@openbsd.org>
- *
- * Permission to use, copy, modify, and 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 <libgen.h>
-#include <limits.h>
-#include <string.h>
-
-#ifndef PATH_MAX
-#       define PATH_MAX 2048
-#endif
-
-char *
-basename(char *path)
-{
-	static char bname[PATH_MAX];
-	size_t len;
-	const char *endp, *startp;
-
-	/* Empty or NULL string gets treated as "." */
-	if (path == NULL || *path == '\0') {
-		bname[0] = '.';
-		bname[1] = '\0';
-		return (bname);
-	}
-
-	/* Strip any trailing slashes */
-	endp = path + strlen(path) - 1;
-	while (endp > path && *endp == '/')
-		endp--;
-
-	/* All slashes becomes "/" */
-	if (endp == path && *endp == '/') {
-		bname[0] = '/';
-		bname[1] = '\0';
-		return (bname);
-	}
-
-	/* Find the start of the base */
-	startp = endp;
-	while (startp > path && *(startp - 1) != '/')
-		startp--;
-
-	len = endp - startp + 1;
-	if (len >= sizeof(bname)) {
-		errno = ENAMETOOLONG;
-		return (NULL);
-	}
-	memcpy(bname, startp, len);
-	bname[len] = '\0';
-	return (bname);
-}
--- a/extern/libcompat/src/compat.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-/*
- * compat.c -- dummy file to avoid stupid empty library warnings
- *
- * Copyright (c) 2020-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.
- */
-
-int
-libcompat_presence(void)
-{
-	return 1;
-}
--- a/extern/libcompat/src/compat.h.in	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/*
- * compat.h -- compatibility definitions
- *
- * 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 LIBCOMPAT_COMPAT_H
-#define LIBCOMPAT_COMPAT_H
-
-#cmakedefine COMPAT_HAVE_BASENAME
-#cmakedefine COMPAT_HAVE_DIRNAME
-#cmakedefine COMPAT_HAVE_ERR
-#cmakedefine COMPAT_HAVE_ERRC
-#cmakedefine COMPAT_HAVE_ERRX
-#cmakedefine COMPAT_HAVE_GETOPT
-#cmakedefine COMPAT_HAVE_GETPROGNAME
-#cmakedefine COMPAT_HAVE_PLEDGE
-#cmakedefine COMPAT_HAVE_REALLOCARRAY
-#cmakedefine COMPAT_HAVE_RECALLOCARRAY
-#cmakedefine COMPAT_HAVE_SETPROGNAME
-#cmakedefine COMPAT_HAVE_STRDUP
-#cmakedefine COMPAT_HAVE_STRLCAT
-#cmakedefine COMPAT_HAVE_STRLCPY
-#cmakedefine COMPAT_HAVE_STRNDUP
-#cmakedefine COMPAT_HAVE_STRNLEN
-#cmakedefine COMPAT_HAVE_STRSEP
-#cmakedefine COMPAT_HAVE_STRTOK_R
-#cmakedefine COMPAT_HAVE_STRTONUM
-#cmakedefine COMPAT_HAVE_VERR
-#cmakedefine COMPAT_HAVE_VERRC
-#cmakedefine COMPAT_HAVE_VERRX
-#cmakedefine COMPAT_HAVE_VWARN
-#cmakedefine COMPAT_HAVE_VWARNC
-#cmakedefine COMPAT_HAVE_VWARNX
-#cmakedefine COMPAT_HAVE_WARN
-#cmakedefine COMPAT_HAVE_WARNC
-#cmakedefine COMPAT_HAVE_WARNX
-
-#cmakedefine COMPAT_HAVE_STAT_ST_ATIME
-#cmakedefine COMPAT_HAVE_STAT_ST_BLKSIZE
-#cmakedefine COMPAT_HAVE_STAT_ST_BLOCKS
-#cmakedefine COMPAT_HAVE_STAT_ST_CTIME
-#cmakedefine COMPAT_HAVE_STAT_ST_DEV
-#cmakedefine COMPAT_HAVE_STAT_ST_GID
-#cmakedefine COMPAT_HAVE_STAT_ST_INO
-#cmakedefine COMPAT_HAVE_STAT_ST_MODE
-#cmakedefine COMPAT_HAVE_STAT_ST_MTIME
-#cmakedefine COMPAT_HAVE_STAT_ST_NLINK
-#cmakedefine COMPAT_HAVE_STAT_ST_RDEV
-#cmakedefine COMPAT_HAVE_STAT_ST_SIZE
-#cmakedefine COMPAT_HAVE_STAT_ST_UID
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#ifndef COMPAT_HAVE_BASENAME
-char *
-basename(char *);
-#endif
-
-#ifndef COMPAT_HAVE_DIRNAME
-char *
-dirname(char *);
-#endif
-
-#ifndef COMPAT_HAVE_ERR
-void
-err(int, const char *, ...);
-#endif
-
-#ifndef COMPAT_HAVE_ERRC
-void
-errc(int, int, const char *, ...);
-#endif
-
-#ifndef COMPAT_HAVE_ERRX
-void
-errx(int, const char *, ...);
-#endif
-
-#ifndef COMPAT_HAVE_VERR
-void
-verr(int, const char *, va_list);
-#endif
-
-#ifndef COMPAT_HAVE_VERRC
-void
-verrc(int, int, const char *, va_list);
-#endif
-
-#ifndef COMPAT_HAVE_VERRX
-void
-verrx(int, const char *, va_list);
-#endif
-
-#ifndef COMPAT_HAVE_VWARN
-void
-vwarn(const char *, va_list);
-#endif
-
-#ifndef COMPAT_HAVE_VWARNC
-void
-vwarnc(int, const char *, va_list);
-#endif
-
-#ifndef COMPAT_HAVE_VWARNX
-void
-vwarnx(const char *, va_list);
-#endif
-
-#ifndef COMPAT_HAVE_WARN
-void
-warn(const char *, ...);
-#endif
-
-#ifndef COMPAT_HAVE_WARNC
-void
-warnc(int, const char *, ...);
-#endif
-
-#ifndef COMPAT_HAVE_WARNX
-void
-warnx(const char *, ...);
-#endif
-
-#ifndef COMPAT_HAVE_GETOPT
-extern int opterr;
-extern int optind;
-extern int optopt;
-extern char *optarg;
-
-int
-getopt(int, char **, const char *);
-#endif
-
-#ifndef COMPAT_HAVE_GETPROGNAME
-const char *
-getprogname(void);
-#endif
-
-#ifndef COMPAT_HAVE_PLEDGE
-int
-pledge(const char *, const char *);
-#endif
-
-#ifndef COMPAT_HAVE_REALLOCARRAY
-void *
-reallocarray(void *, size_t, size_t);
-#endif
-
-#ifndef COMPAT_HAVE_RECALLOCARRAY
-void *
-recallocarray(void *, size_t, size_t, size_t);
-#endif
-
-#ifndef COMPAT_HAVE_SETPROGNAME
-void
-setprogname(const char *);
-#endif
-
-#ifndef COMPAT_HAVE_STRDUP
-char *
-strdup(const char *);
-#endif
-
-#ifndef COMPAT_HAVE_STRLCAT
-size_t
-strlcat(char *, const char *, size_t);
-#endif
-
-#ifndef COMPAT_HAVE_STRLCPY
-size_t
-strlcpy(char *, const char *, size_t);
-#endif
-
-#ifndef COMPAT_HAVE_STRNDUP
-char *
-strndup(const char *, size_t);
-#endif
-
-#ifndef COMPAT_HAVE_STRNLEN
-size_t
-strnlen(const char *, size_t);
-#endif
-
-#ifndef COMPAT_HAVE_STRSEP
-char *
-strsep(char **, const char *);
-#endif
-
-#ifndef COMPAT_HAVE_STRTOK_R
-char *
-strtok_r(char *, const char *, char **);
-#endif
-
-#ifndef COMPAT_HAVE_STRTONUM
-long long
-strtonum(const char *, long long, long long, const char **);
-#endif
-
-#endif /* !LIBCOMPAT_COMPAT_H */
--- a/extern/libcompat/src/dirname.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*	$OpenBSD: dirname.c,v 1.17 2020/10/20 19:30:14 naddy Exp $	*/
-
-/*
- * Copyright (c) 1997, 2004 Todd C. Miller <millert@openbsd.org>
- *
- * Permission to use, copy, modify, and 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 <libgen.h>
-#include <limits.h>
-#include <string.h>
-
-#ifndef PATH_MAX
-#       define PATH_MAX 2048
-#endif
-
-char *
-dirname(char *path)
-{
-	static char dname[PATH_MAX];
-	size_t len;
-	const char *endp;
-
-	/* Empty or NULL string gets treated as "." */
-	if (path == NULL || *path == '\0') {
-		dname[0] = '.';
-		dname[1] = '\0';
-		return (dname);
-	}
-
-	/* Strip any trailing slashes */
-	endp = path + strlen(path) - 1;
-	while (endp > path && *endp == '/')
-		endp--;
-
-	/* Find the start of the dir */
-	while (endp > path && *endp != '/')
-		endp--;
-
-	/* Either the dir is "/" or there are no slashes */
-	if (endp == path) {
-		dname[0] = *endp == '/' ? '/' : '.';
-		dname[1] = '\0';
-		return (dname);
-	} else {
-		/* Move forward past the separating slashes */
-		do {
-			endp--;
-		} while (endp > path && *endp == '/');
-	}
-
-	len = endp - path + 1;
-	if (len >= sizeof(dname)) {
-		errno = ENAMETOOLONG;
-		return (NULL);
-	}
-	memcpy(dname, path, len);
-	dname[len] = '\0';
-	return (dname);
-}
--- a/extern/libcompat/src/err.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*	$OpenBSD: err.c,v 1.12 2015/08/31 02:53:57 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-err(int eval, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	verr(eval, fmt, ap);
-	va_end(ap);
-}
--- a/extern/libcompat/src/errc.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*	$OpenBSD: errc.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-errc(int eval, int code, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	verrc(eval, code, fmt, ap);
-	va_end(ap);
-}
--- a/extern/libcompat/src/errx.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*	$OpenBSD: errx.c,v 1.11 2015/08/31 02:53:57 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-errx(int eval, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	verrx(eval, fmt, ap);
-	va_end(ap);
-}
--- a/extern/libcompat/src/getopt.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 1987, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int	opterr = 1,		/* if error message should be printed */
-	optind = 1,		/* index into parent argv vector */
-	optopt,			/* character checked for validity */
-	optreset;		/* reset getopt */
-char	*optarg;		/* argument associated with option */
-
-#define	BADCH	(int)'?'
-#define	BADARG	(int)':'
-#define	EMSG	""
-
-/*
- * getopt --
- *	Parse argc/argv argument vector.
- */
-int
-getopt(int nargc, char * const *nargv, const char *ostr)
-{
-	static char *place = EMSG;		/* option letter processing */
-	char *oli;				/* option letter list index */
-
-	if (ostr == NULL)
-		return (-1);
-
-	if (optreset || !*place) {		/* update scanning pointer */
-		optreset = 0;
-		if (optind >= nargc || *(place = nargv[optind]) != '-') {
-			place = EMSG;
-			return (-1);
-		}
-		if (place[1] && *++place == '-') {	/* found "--" */
-			++optind;
-			place = EMSG;
-			return (-1);
-		}
-	}					/* option letter okay? */
-	if ((optopt = (int)*place++) == (int)':' ||
-	    !(oli = strchr(ostr, optopt))) {
-		/*
-		 * if the user didn't specify '-' as an option,
-		 * assume it means -1.
-		 */
-		if (optopt == (int)'-')
-			return (-1);
-		if (!*place)
-			++optind;
-		if (opterr && *ostr != ':')
-			(void)fprintf(stderr,
-			    "illegal option -- %c\n", optopt);
-		return (BADCH);
-	}
-	if (*++oli != ':') {			/* don't need argument */
-		optarg = NULL;
-		if (!*place)
-			++optind;
-	}
-	else {					/* need an argument */
-		if (*place)			/* no white space */
-			optarg = place;
-		else if (nargc <= ++optind) {	/* no arg */
-			place = EMSG;
-			if (*ostr == ':')
-				return (BADARG);
-			if (opterr)
-				(void)fprintf(stderr,
-				    "option requires an argument -- %c\n",
-				    optopt);
-			return (BADCH);
-		}
-		else				/* white space */
-			optarg = nargv[optind];
-		place = EMSG;
-		++optind;
-	}
-	return (optopt);			/* dump back option letter */
-}
--- a/extern/libcompat/src/getprogname.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- * getprogname.c -- getprogname implementation
- *
- * Copyright (c) 2020-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.
- */
-
-extern const char *libcompat_progname;
-
-const char *
-getprogname(void)
-{
-	return libcompat_progname;
-}
--- a/extern/libcompat/src/pledge.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * pledge.c -- no-op implementation
- *
- * Copyright (c) 2020-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.
- */
-
-int
-pledge(const char *promises, const char *execpromises)
-{
-	(void)promises;
-	(void)execpromises;
-
-	return 0;
-}
--- a/extern/libcompat/src/reallocarray.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*	$OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $	*/
-/*
- * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
- *
- * Permission to use, copy, modify, and 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/types.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/*
- * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
- * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
- */
-#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
-
-void *
-reallocarray(void *optr, size_t nmemb, size_t size)
-{
-	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
-	    nmemb > 0 && SIZE_MAX / nmemb < size) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	return realloc(optr, size * nmemb);
-}
--- a/extern/libcompat/src/recallocarray.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*	$OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $	*/
-/*
- * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
- *
- * Permission to use, copy, modify, and 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 <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-/*
- * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
- * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
- */
-#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
-
-void *
-recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
-{
-	size_t oldsize, newsize;
-	void *newptr;
-
-	if (ptr == NULL)
-		return calloc(newnmemb, size);
-
-	if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
-	    newnmemb > 0 && SIZE_MAX / newnmemb < size) {
-		errno = ENOMEM;
-		return NULL;
-	}
-	newsize = newnmemb * size;
-
-	if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
-	    oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
-		errno = EINVAL;
-		return NULL;
-	}
-	oldsize = oldnmemb * size;
-	
-	newptr = malloc(newsize);
-	if (newptr == NULL)
-		return NULL;
-
-	if (newsize > oldsize) {
-		memcpy(newptr, ptr, oldsize);
-		memset((char *)newptr + oldsize, 0, newsize - oldsize);
-	} else
-		memcpy(newptr, ptr, newsize);
-
-	memset(ptr, 0, oldsize);
-	free(ptr);
-
-	return newptr;
-}
--- a/extern/libcompat/src/setprogname.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/*
- * setprogname.c -- setprogname implementation
- *
- * Copyright (c) 2020-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 <stdio.h>
-
-static char libcompat_progname_buf[64] = "";
-
-const char *libcompat_progname = libcompat_progname_buf;
-
-void
-setprogname(const char *name)
-{
-	snprintf(libcompat_progname_buf, sizeof (libcompat_progname_buf), "%s", name);
-}
--- a/extern/libcompat/src/strdup.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * strdup.c -- strdup implementation
- *
- * Copyright (c) 2020-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 <stdlib.h>
-#include <string.h>
-
-char *
-strdup(const char *src)
-{
-	assert(src);
-
-	char *ret;
-	size_t length;
-
-	length = strlen(src) + 1;
-
-	if (!(ret = malloc(length)))
-		return NULL;
-
-	return memcpy(ret, src, length);
-}
--- a/extern/libcompat/src/strlcat.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*	$OpenBSD: strlcat.c,v 1.19 2019/01/25 00:19:25 millert Exp $	*/
-
-/*
- * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
- *
- * Permission to use, copy, modify, and 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/types.h>
-#include <string.h>
-
-/*
- * Appends src to string dst of size dsize (unlike strncat, dsize is the
- * full size of dst, not space left).  At most dsize-1 characters
- * will be copied.  Always NUL terminates (unless dsize <= strlen(dst)).
- * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
- * If retval >= dsize, truncation occurred.
- */
-size_t
-strlcat(char *dst, const char *src, size_t dsize)
-{
-	const char *odst = dst;
-	const char *osrc = src;
-	size_t n = dsize;
-	size_t dlen;
-
-	/* Find the end of dst and adjust bytes left but don't go past end. */
-	while (n-- != 0 && *dst != '\0')
-		dst++;
-	dlen = dst - odst;
-	n = dsize - dlen;
-
-	if (n-- == 0)
-		return(dlen + strlen(src));
-	while (*src != '\0') {
-		if (n != 0) {
-			*dst++ = *src;
-			n--;
-		}
-		src++;
-	}
-	*dst = '\0';
-
-	return(dlen + (src - osrc));	/* count does not include NUL */
-}
--- a/extern/libcompat/src/strlcpy.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*	$OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $	*/
-
-/*
- * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
- *
- * Permission to use, copy, modify, and 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/types.h>
-#include <string.h>
-
-/*
- * Copy string src to buffer dst of size dsize.  At most dsize-1
- * chars will be copied.  Always NUL terminates (unless dsize == 0).
- * Returns strlen(src); if retval >= dsize, truncation occurred.
- */
-size_t
-strlcpy(char *dst, const char *src, size_t dsize)
-{
-	const char *osrc = src;
-	size_t nleft = dsize;
-
-	/* Copy as many bytes as will fit. */
-	if (nleft != 0) {
-		while (--nleft != 0) {
-			if ((*dst++ = *src++) == '\0')
-				break;
-		}
-	}
-
-	/* Not enough room in dst, add NUL and traverse rest of src. */
-	if (nleft == 0) {
-		if (dsize != 0)
-			*dst = '\0';		/* NUL-terminate dst */
-		while (*src++)
-			;
-	}
-
-	return(src - osrc - 1);	/* count does not include NUL */
-}
--- a/extern/libcompat/src/strndup.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * strndup.c -- strndup implementation
- *
- * Copyright (c) 2020-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 <stdlib.h>
-#include <string.h>
-
-#include "compat.h"
-
-char *
-strndup(const char *src, size_t max)
-{
-	assert(src);
-
-	char *ret;
-	size_t length;
-
-	length = strnlen(src, max);
-
-	if (!(ret = malloc(length + 1)))
-		return NULL;
-
-	memcpy(ret, src, length);
-	ret[length] = '\0';
-
-	return ret;
-}
--- a/extern/libcompat/src/strnlen.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*	$OpenBSD: strnlen.c,v 1.9 2019/01/25 00:19:25 millert Exp $	*/
-
-/*
- * Copyright (c) 2010 Todd C. Miller <millert@openbsd.org>
- *
- * Permission to use, copy, modify, and 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 <stddef.h>
-
-size_t
-strnlen(const char *str, size_t maxlen)
-{
-	const char *cp;
-
-	for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--)
-		;
-
-	return (size_t)(cp - str);
-}
--- a/extern/libcompat/src/strsep.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*	$OpenBSD: strsep.c,v 1.8 2015/08/31 02:53:57 guenther Exp $	*/
-
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <string.h>
-
-/*
- * Get next token from string *stringp, where tokens are possibly-empty
- * strings separated by characters from delim.  
- *
- * Writes NULs into the string at *stringp to end tokens.
- * delim need not remain constant from call to call.
- * On return, *stringp points past the last NUL written (if there might
- * be further tokens), or is NULL (if there are definitely no more tokens).
- *
- * If *stringp is NULL, strsep returns NULL.
- */
-char *
-strsep(char **stringp, const char *delim)
-{
-	char *s;
-	const char *spanp;
-	int c, sc;
-	char *tok;
-
-	if ((s = *stringp) == NULL)
-		return (NULL);
-	for (tok = s;;) {
-		c = *s++;
-		spanp = delim;
-		do {
-			if ((sc = *spanp++) == c) {
-				if (c == 0)
-					s = NULL;
-				else
-					s[-1] = 0;
-				*stringp = s;
-				return (tok);
-			}
-		} while (sc != 0);
-	}
-	/* NOTREACHED */
-}
--- a/extern/libcompat/src/strtok_r.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-char *
-strtok_r(char *s, const char *delim, char **last)
-{
-	const char *spanp;
-	int c, sc;
-	char *tok;
-
-	if (s == NULL && (s = *last) == NULL)
-		return (NULL);
-
-	/*
-	 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
-	 */
-cont:
-	c = *s++;
-	for (spanp = delim; (sc = *spanp++) != 0;) {
-		if (c == sc)
-			goto cont;
-	}
-
-	if (c == 0) {		/* no non-delimiter characters */
-		*last = NULL;
-		return (NULL);
-	}
-	tok = s - 1;
-
-	/*
-	 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
-	 * Note that delim must have one NUL; we stop if we see that, too.
-	 */
-	for (;;) {
-		c = *s++;
-		spanp = delim;
-		do {
-			if ((sc = *spanp++) == c) {
-				if (c == 0)
-					s = NULL;
-				else
-					s[-1] = '\0';
-				*last = s;
-				return (tok);
-			}
-		} while (sc != 0);
-	}
-	/* NOTREACHED */
-}
--- a/extern/libcompat/src/strtonum.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*	$OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $	*/
-
-/*
- * Copyright (c) 2004 Ted Unangst and Todd Miller
- * All rights reserved.
- *
- * Permission to use, copy, modify, and 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 <limits.h>
-#include <stdlib.h>
-
-#define	INVALID		1
-#define	TOOSMALL	2
-#define	TOOLARGE	3
-
-long long
-strtonum(const char *numstr, long long minval, long long maxval,
-    const char **errstrp)
-{
-	long long ll = 0;
-	int error = 0;
-	char *ep;
-	struct errval {
-		const char *errstr;
-		int err;
-	} ev[4] = {
-		{ NULL,		0 },
-		{ "invalid",	EINVAL },
-		{ "too small",	ERANGE },
-		{ "too large",	ERANGE },
-	};
-
-	ev[0].err = errno;
-	errno = 0;
-	if (minval > maxval) {
-		error = INVALID;
-	} else {
-		ll = strtoll(numstr, &ep, 10);
-		if (numstr == ep || *ep != '\0')
-			error = INVALID;
-		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
-			error = TOOSMALL;
-		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
-			error = TOOLARGE;
-	}
-	if (errstrp != NULL)
-		*errstrp = ev[error].errstr;
-	errno = ev[error].err;
-	if (error)
-		ll = 0;
-
-	return (ll);
-}
--- a/extern/libcompat/src/verr.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*	$OpenBSD: verr.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-verr(int eval, const char *fmt, va_list ap)
-{
-	int sverrno = errno;
-
-	if (fmt != NULL) {
-		(void)vfprintf(stderr, fmt, ap);
-		(void)fprintf(stderr, ": ");
-	}
-
-	(void)fprintf(stderr, "%s\n", strerror(sverrno));
-	exit(eval);
-}
--- a/extern/libcompat/src/verrc.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*	$OpenBSD: verrc.c,v 1.3 2016/03/13 18:34:20 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-void
-verrc(int eval, int code, const char *fmt, va_list ap)
-{
-	if (fmt != NULL) {
-		(void)vfprintf(stderr, fmt, ap);
-		(void)fprintf(stderr, ": ");
-	}
-
-	(void)fprintf(stderr, "%s\n", strerror(code));
-	exit(eval);
-}
--- a/extern/libcompat/src/verrx.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*	$OpenBSD: verrx.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-verrx(int eval, const char *fmt, va_list ap)
-{
-	if (fmt != NULL)
-		(void)vfprintf(stderr, fmt, ap);
-
-	(void)fprintf(stderr, "\n");
-	exit(eval);
-}
--- a/extern/libcompat/src/vsyslog.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * vsyslog.c -- fallback implementation
- *
- * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "compat.h"
-
-#if defined(COMPAT_HAVE_SYSLOG_H)
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <syslog.h>
-
-void
-vsyslog(int priority, const char *msg, va_list ap)
-{
-	assert(msg);
-
-	char buf[1024] = {0};
-
-	if (vsnprintf(buf, sizeof (buf), fmt, ap) >= 0)
-		syslog(priority, "%s", buf);
-}
-
-#endif
--- a/extern/libcompat/src/vwarn.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*	$OpenBSD: vwarn.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-vwarn(const char *fmt, va_list ap)
-{
-	int sverrno = errno;
-
-	if (fmt != NULL) {
-		(void)vfprintf(stderr, fmt, ap);
-		(void)fprintf(stderr, ": ");
-	}
-
-	(void)fprintf(stderr, "%s\n", strerror(sverrno));
-}
--- a/extern/libcompat/src/vwarnc.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*	$OpenBSD: vwarnc.c,v 1.3 2016/03/13 18:34:20 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-vwarnc(int code, const char *fmt, va_list ap)
-{
-	if (fmt != NULL) {
-		(void)vfprintf(stderr, fmt, ap);
-		(void)fprintf(stderr, ": ");
-	}
-
-	(void)fprintf(stderr, "%s\n", strerror(code));
-}
--- a/extern/libcompat/src/vwarnx.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*	$OpenBSD: vwarnx.c,v 1.11 2016/03/13 18:34:20 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-vwarnx(const char *fmt, va_list ap)
-{
-	if (fmt != NULL)
-		(void)vfprintf(stderr, fmt, ap);
-
-	(void)fprintf(stderr, "\n");
-}
--- a/extern/libcompat/src/warn.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*	$OpenBSD: warn.c,v 1.11 2015/08/31 02:53:57 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-warn(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarn(fmt, ap);
-	va_end(ap);
-}
--- a/extern/libcompat/src/warnc.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*	$OpenBSD: warnc.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-warnc(int code, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarnc(code, fmt, ap);
-	va_end(ap);
-}
--- a/extern/libcompat/src/warnx.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*	$OpenBSD: warnx.c,v 1.10 2015/08/31 02:53:57 guenther Exp $ */
-/*-
- * Copyright (c) 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#include "compat.h"
-
-void
-warnx(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	vwarnx(fmt, ap);
-	va_end(ap);
-}
--- a/extern/libcompat/tests/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for libcompat
-#
-# Copyright (c) 2020-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.
-#
-
-project(tests)
-
-function(define_test name)
-	add_executable(test-${name} test-${name}.c)
-	add_test(NAME test-${name} COMMAND test-${name})
-	target_link_libraries(test-${name} libcompat)
-endfunction()
-
-# POSIX dlfcn/dlopen/dlsym.
-define_test(dlfcn)
-set_target_properties(test-dlfcn PROPERTIES ENABLE_EXPORTS On)
-target_link_libraries(test-dlfcn dl)
-
-# POSIX opendir/readdir.
-define_test(dirent)
-target_compile_definitions(test-dirent PRIVATE DIRECTORY="${tests_SOURCE_DIR}")
-
-# BSD and POSIX functions.
-define_test(bsd)
-define_test(posix)
--- a/extern/libcompat/tests/test-bsd.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * test-bsd.c -- test BSD extensions
- *
- * Copyright (c) 2020-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.
- */
-
-#define _BSD_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <compat.h>
-
-int
-main(void)
-{
-	int *ints = NULL;
-	char buf[BUFSIZ];
-	char *token, *p;
-
-	pledge("stdio", NULL);
-
-	ints = reallocarray(ints, 5, sizeof (*ints));
-	ints = recallocarray(ints, 5, 10, sizeof (*ints));
-
-	strlcpy(buf, "Hello", sizeof (buf));
-	strlcat(buf, " world", sizeof (buf));
-
-	p = token = buf;
-
-	while ((token = strsep(&p, " \t")))
-		printf("%s\n", token);
-
-	free(ints);
-
-	return 0;
-}
--- a/extern/libcompat/tests/test-dirent.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * dirent.c -- test opendir/readdir
- *
- * Copyright (c) 2020-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 <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-int
-main(void)
-{
-	DIR *dp;
-	struct dirent *entry;
-
-	if (!(dp = opendir(DIRECTORY))) {
-		fprintf(stderr, "abort: %s\n", strerror(errno));
-		return 1;
-	}
-
-	while ((entry = readdir(dp)))
-		printf("%s\n", entry->d_name);
-
-	closedir(dp);
-
-	return 0;
-}
--- a/extern/libcompat/tests/test-dlfcn.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * test-dlfcn.c -- test dlopen/dlsym/dlclose
- *
- * Copyright (c) 2020-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 <dlfcn.h>
-#include <stdio.h>
-
-#if defined(_WIN32)
-#       define EXPORT __declspec(dllexport)
-#else
-#       define EXPORT
-#endif
-
-EXPORT int
-hello(void)
-{
-	return 0;
-}
-
-int
-main(void)
-{
-	void *handle;
-	int (*func)(void);
-	int ret = 1;
-
-	if (!(handle = dlopen(NULL, RTLD_NOW)) ||
-	    !(func = dlsym(handle, "hello"))) {
-		fprintf(stderr, "%s\n", dlerror());
-		goto end;
-	}
-
-	ret = func();
-
-	dlclose(handle);
-
-end:
-	return ret;
-}
--- a/extern/libcompat/tests/test-posix.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * test-posix.c -- test POSIX functions
- *
- * Copyright (c) 2020-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.
- */
-
-#define _BSD_SOURCE
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <compat.h>
-
-int
-main(int argc, char **argv)
-{
-	char path1[FILENAME_MAX] = "/usr/local/bin/vim";
-	char path2[FILENAME_MAX] = "/usr/local/bin/vim";
-	char tmppath[FILENAME_MAX];
-	char *s;
-
-	for (int ch; (ch = getopt(argc, argv, "l:v")) != -1; ) {
-		switch (ch) {
-		case 'l':
-			printf("log level: %s\n", optarg);
-			break;
-		case 'v':
-			printf("verbosity set\n");
-			break;
-		default:
-			break;
-		}
-	}
-
-	s = strdup("Hello World");
-	printf("%s\n", s);
-	free(s);
-
-	s = strndup("Hello World, what's up?", 11);
-	printf("%s\n", s);
-	free(s);
-
-	snprintf(tmppath, sizeof (tmppath), "%s", basename(path1));
-	puts(tmppath);
-
-	snprintf(tmppath, sizeof (tmppath), "%s", dirname(path1));
-	puts(tmppath);
-
-	printf("max len: %zu\n", strnlen("francis", 3));
-}
--- a/extern/libcompat/win/dirent/dirent.h	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1027 +0,0 @@
-/*
- * Dirent interface for Microsoft Visual Studio
- *
- * Copyright (C) 1998-2019 Toni Ronkko
- * This file is part of dirent.  Dirent may be freely distributed
- * under the MIT license.  For all details and documentation, see
- * https://github.com/tronkko/dirent
- */
-#ifndef DIRENT_H
-#define DIRENT_H
-
-/* Hide warnings about unreferenced local functions */
-#if defined(__clang__)
-#	pragma clang diagnostic ignored "-Wunused-function"
-#elif defined(_MSC_VER)
-#	pragma warning(disable:4505)
-#elif defined(__GNUC__)
-#	pragma GCC diagnostic ignored "-Wunused-function"
-#endif
-
-/*
- * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
- * Windows Sockets 2.0.
- */
-#ifndef WIN32_LEAN_AND_MEAN
-#	define WIN32_LEAN_AND_MEAN
-#endif
-#include <windows.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <wchar.h>
-#include <string.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <ctype.h>
-
-/* Indicates that d_type field is available in dirent structure */
-#define _DIRENT_HAVE_D_TYPE
-
-/* Indicates that d_namlen field is available in dirent structure */
-#define _DIRENT_HAVE_D_NAMLEN
-
-/* Entries missing from MSVC 6.0 */
-#if !defined(FILE_ATTRIBUTE_DEVICE)
-#	define FILE_ATTRIBUTE_DEVICE 0x40
-#endif
-
-/* File type and permission flags for stat(), general mask */
-#if !defined(S_IFMT)
-#	define S_IFMT _S_IFMT
-#endif
-
-/* Directory bit */
-#if !defined(S_IFDIR)
-#	define S_IFDIR _S_IFDIR
-#endif
-
-/* Character device bit */
-#if !defined(S_IFCHR)
-#	define S_IFCHR _S_IFCHR
-#endif
-
-/* Pipe bit */
-#if !defined(S_IFFIFO)
-#	define S_IFFIFO _S_IFFIFO
-#endif
-
-/* Regular file bit */
-#if !defined(S_IFREG)
-#	define S_IFREG _S_IFREG
-#endif
-
-/* Read permission */
-#if !defined(S_IREAD)
-#	define S_IREAD _S_IREAD
-#endif
-
-/* Write permission */
-#if !defined(S_IWRITE)
-#	define S_IWRITE _S_IWRITE
-#endif
-
-/* Execute permission */
-#if !defined(S_IEXEC)
-#	define S_IEXEC _S_IEXEC
-#endif
-
-/* Pipe */
-#if !defined(S_IFIFO)
-#	define S_IFIFO _S_IFIFO
-#endif
-
-/* Block device */
-#if !defined(S_IFBLK)
-#	define S_IFBLK 0
-#endif
-
-/* Link */
-#if !defined(S_IFLNK)
-#	define S_IFLNK 0
-#endif
-
-/* Socket */
-#if !defined(S_IFSOCK)
-#	define S_IFSOCK 0
-#endif
-
-/* Read user permission */
-#if !defined(S_IRUSR)
-#	define S_IRUSR S_IREAD
-#endif
-
-/* Write user permission */
-#if !defined(S_IWUSR)
-#	define S_IWUSR S_IWRITE
-#endif
-
-/* Execute user permission */
-#if !defined(S_IXUSR)
-#	define S_IXUSR 0
-#endif
-
-/* Read group permission */
-#if !defined(S_IRGRP)
-#	define S_IRGRP 0
-#endif
-
-/* Write group permission */
-#if !defined(S_IWGRP)
-#	define S_IWGRP 0
-#endif
-
-/* Execute group permission */
-#if !defined(S_IXGRP)
-#	define S_IXGRP 0
-#endif
-
-/* Read others permission */
-#if !defined(S_IROTH)
-#	define S_IROTH 0
-#endif
-
-/* Write others permission */
-#if !defined(S_IWOTH)
-#	define S_IWOTH 0
-#endif
-
-/* Execute others permission */
-#if !defined(S_IXOTH)
-#	define S_IXOTH 0
-#endif
-
-/* Maximum length of file name */
-#if !defined(PATH_MAX)
-#	define PATH_MAX MAX_PATH
-#endif
-#if !defined(FILENAME_MAX)
-#	define FILENAME_MAX MAX_PATH
-#endif
-#if !defined(NAME_MAX)
-#	define NAME_MAX FILENAME_MAX
-#endif
-
-/* File type flags for d_type */
-#define DT_UNKNOWN 0
-#define DT_REG S_IFREG
-#define DT_DIR S_IFDIR
-#define DT_FIFO S_IFIFO
-#define DT_SOCK S_IFSOCK
-#define DT_CHR S_IFCHR
-#define DT_BLK S_IFBLK
-#define DT_LNK S_IFLNK
-
-/* Macros for converting between st_mode and d_type */
-#define IFTODT(mode) ((mode) & S_IFMT)
-#define DTTOIF(type) (type)
-
-/*
- * File type macros.  Note that block devices, sockets and links cannot be
- * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
- * only defined for compatibility.  These macros should always return false
- * on Windows.
- */
-#if !defined(S_ISFIFO)
-#	define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
-#endif
-#if !defined(S_ISDIR)
-#	define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
-#endif
-#if !defined(S_ISREG)
-#	define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
-#endif
-#if !defined(S_ISLNK)
-#	define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
-#endif
-#if !defined(S_ISSOCK)
-#	define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
-#endif
-#if !defined(S_ISCHR)
-#	define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
-#endif
-#if !defined(S_ISBLK)
-#	define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
-#endif
-
-/* Return the exact length of the file name without zero terminator */
-#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
-
-/* Return the maximum size of a file name */
-#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Wide-character version */
-struct _wdirent {
-	/* Always zero */
-	long d_ino;
-
-	/* File position within stream */
-	long d_off;
-
-	/* Structure size */
-	unsigned short d_reclen;
-
-	/* Length of name without \0 */
-	size_t d_namlen;
-
-	/* File type */
-	int d_type;
-
-	/* File name */
-	wchar_t d_name[PATH_MAX+1];
-};
-typedef struct _wdirent _wdirent;
-
-struct _WDIR {
-	/* Current directory entry */
-	struct _wdirent ent;
-
-	/* Private file data */
-	WIN32_FIND_DATAW data;
-
-	/* True if data is valid */
-	int cached;
-
-	/* Win32 search handle */
-	HANDLE handle;
-
-	/* Initial directory name */
-	wchar_t *patt;
-};
-typedef struct _WDIR _WDIR;
-
-/* Multi-byte character version */
-struct dirent {
-	/* Always zero */
-	long d_ino;
-
-	/* File position within stream */
-	long d_off;
-
-	/* Structure size */
-	unsigned short d_reclen;
-
-	/* Length of name without \0 */
-	size_t d_namlen;
-
-	/* File type */
-	int d_type;
-
-	/* File name */
-	char d_name[PATH_MAX+1];
-};
-typedef struct dirent dirent;
-
-struct DIR {
-	struct dirent ent;
-	struct _WDIR *wdirp;
-};
-typedef struct DIR DIR;
-
-
-/* Dirent functions */
-static DIR *opendir(const char *dirname);
-static _WDIR *_wopendir(const wchar_t *dirname);
-
-static struct dirent *readdir(DIR *dirp);
-static struct _wdirent *_wreaddir(_WDIR *dirp);
-
-static int readdir_r(
-	DIR *dirp, struct dirent *entry, struct dirent **result);
-static int _wreaddir_r(
-	_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
-
-static int closedir(DIR *dirp);
-static int _wclosedir(_WDIR *dirp);
-
-static void rewinddir(DIR* dirp);
-static void _wrewinddir(_WDIR* dirp);
-
-static int scandir(const char *dirname, struct dirent ***namelist,
-	int (*filter)(const struct dirent*),
-	int (*compare)(const struct dirent**, const struct dirent**));
-
-static int alphasort(const struct dirent **a, const struct dirent **b);
-
-static int versionsort(const struct dirent **a, const struct dirent **b);
-
-static int strverscmp(const char *a, const char *b);
-
-/* For compatibility with Symbian */
-#define wdirent _wdirent
-#define WDIR _WDIR
-#define wopendir _wopendir
-#define wreaddir _wreaddir
-#define wclosedir _wclosedir
-#define wrewinddir _wrewinddir
-
-/* Compatibility with older Microsoft compilers and non-Microsoft compilers */
-#if !defined(_MSC_VER) || _MSC_VER < 1400
-#	define wcstombs_s dirent_wcstombs_s
-#	define mbstowcs_s dirent_mbstowcs_s
-#endif
-
-/* Optimize dirent_set_errno() away on modern Microsoft compilers */
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-#	define dirent_set_errno _set_errno
-#endif
-
-
-/* Internal utility functions */
-static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
-static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
-
-#if !defined(_MSC_VER) || _MSC_VER < 1400
-static int dirent_mbstowcs_s(
-	size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords,
-	const char *mbstr, size_t count);
-#endif
-
-#if !defined(_MSC_VER) || _MSC_VER < 1400
-static int dirent_wcstombs_s(
-	size_t *pReturnValue, char *mbstr, size_t sizeInBytes,
-	const wchar_t *wcstr, size_t count);
-#endif
-
-#if !defined(_MSC_VER) || _MSC_VER < 1400
-static void dirent_set_errno(int error);
-#endif
-
-
-/*
- * Open directory stream DIRNAME for read and return a pointer to the
- * internal working area that is used to retrieve individual directory
- * entries.
- */
-static _WDIR *_wopendir(const wchar_t *dirname)
-{
-	wchar_t *p;
-
-	/* Must have directory name */
-	if (dirname == NULL || dirname[0] == '\0') {
-		dirent_set_errno(ENOENT);
-		return NULL;
-	}
-
-	/* Allocate new _WDIR structure */
-	_WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR));
-	if (!dirp)
-		return NULL;
-
-	/* Reset _WDIR structure */
-	dirp->handle = INVALID_HANDLE_VALUE;
-	dirp->patt = NULL;
-	dirp->cached = 0;
-
-	/*
-	 * Compute the length of full path plus zero terminator
-	 *
-	 * Note that on WinRT there's no way to convert relative paths
-	 * into absolute paths, so just assume it is an absolute path.
-	 */
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-	/* Desktop */
-	DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL);
-#else
-	/* WinRT */
-	size_t n = wcslen(dirname);
-#endif
-
-	/* Allocate room for absolute directory name and search pattern */
-	dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16);
-	if (dirp->patt == NULL)
-		goto exit_closedir;
-
-	/*
-	 * Convert relative directory name to an absolute one.  This
-	 * allows rewinddir() to function correctly even when current
-	 * working directory is changed between opendir() and rewinddir().
-	 *
-	 * Note that on WinRT there's no way to convert relative paths
-	 * into absolute paths, so just assume it is an absolute path.
-	 */
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-	/* Desktop */
-	n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
-	if (n <= 0)
-		goto exit_closedir;
-#else
-	/* WinRT */
-	wcsncpy_s(dirp->patt, n+1, dirname, n);
-#endif
-
-	/* Append search pattern \* to the directory name */
-	p = dirp->patt + n;
-	switch (p[-1]) {
-	case '\\':
-	case '/':
-	case ':':
-		/* Directory ends in path separator, e.g. c:\temp\ */
-		/*NOP*/;
-		break;
-
-	default:
-		/* Directory name doesn't end in path separator */
-		*p++ = '\\';
-	}
-	*p++ = '*';
-	*p = '\0';
-
-	/* Open directory stream and retrieve the first entry */
-	if (!dirent_first(dirp))
-		goto exit_closedir;
-
-	/* Success */
-	return dirp;
-
-	/* Failure */
-exit_closedir:
-	_wclosedir(dirp);
-	return NULL;
-}
-
-/*
- * Read next directory entry.
- *
- * Returns pointer to static directory entry which may be overwritten by
- * subsequent calls to _wreaddir().
- */
-static struct _wdirent *_wreaddir(_WDIR *dirp)
-{
-	/*
-	 * Read directory entry to buffer.  We can safely ignore the return
-	 * value as entry will be set to NULL in case of error.
-	 */
-	struct _wdirent *entry;
-	(void) _wreaddir_r(dirp, &dirp->ent, &entry);
-
-	/* Return pointer to statically allocated directory entry */
-	return entry;
-}
-
-/*
- * Read next directory entry.
- *
- * Returns zero on success.  If end of directory stream is reached, then sets
- * result to NULL and returns zero.
- */
-static int _wreaddir_r(
-	_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result)
-{
-	/* Read next directory entry */
-	WIN32_FIND_DATAW *datap = dirent_next(dirp);
-	if (!datap) {
-		/* Return NULL to indicate end of directory */
-		*result = NULL;
-		return /*OK*/0;
-	}
-
-	/*
-	 * Copy file name as wide-character string.  If the file name is too
-	 * long to fit in to the destination buffer, then truncate file name
-	 * to PATH_MAX characters and zero-terminate the buffer.
-	 */
-	size_t n = 0;
-	while (n < PATH_MAX && datap->cFileName[n] != 0) {
-		entry->d_name[n] = datap->cFileName[n];
-		n++;
-	}
-	entry->d_name[n] = 0;
-
-	/* Length of file name excluding zero terminator */
-	entry->d_namlen = n;
-
-	/* File type */
-	DWORD attr = datap->dwFileAttributes;
-	if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
-		entry->d_type = DT_CHR;
-	else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
-		entry->d_type = DT_DIR;
-	else
-		entry->d_type = DT_REG;
-
-	/* Reset dummy fields */
-	entry->d_ino = 0;
-	entry->d_off = 0;
-	entry->d_reclen = sizeof(struct _wdirent);
-
-	/* Set result address */
-	*result = entry;
-	return /*OK*/0;
-}
-
-/*
- * Close directory stream opened by opendir() function.  This invalidates the
- * DIR structure as well as any directory entry read previously by
- * _wreaddir().
- */
-static int _wclosedir(_WDIR *dirp)
-{
-	if (!dirp) {
-		dirent_set_errno(EBADF);
-		return /*failure*/-1;
-	}
-
-	/* Release search handle */
-	if (dirp->handle != INVALID_HANDLE_VALUE)
-		FindClose(dirp->handle);
-
-	/* Release search pattern */
-	free(dirp->patt);
-
-	/* Release directory structure */
-	free(dirp);
-	return /*success*/0;
-}
-
-/*
- * Rewind directory stream such that _wreaddir() returns the very first
- * file name again.
- */
-static void _wrewinddir(_WDIR* dirp)
-{
-	if (!dirp)
-		return;
-
-	/* Release existing search handle */
-	if (dirp->handle != INVALID_HANDLE_VALUE)
-		FindClose(dirp->handle);
-
-	/* Open new search handle */
-	dirent_first(dirp);
-}
-
-/* Get first directory entry */
-static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp)
-{
-	if (!dirp)
-		return NULL;
-
-	/* Open directory and retrieve the first entry */
-	dirp->handle = FindFirstFileExW(
-		dirp->patt, FindExInfoStandard, &dirp->data,
-		FindExSearchNameMatch, NULL, 0);
-	if (dirp->handle == INVALID_HANDLE_VALUE)
-		goto error;
-
-	/* A directory entry is now waiting in memory */
-	dirp->cached = 1;
-	return &dirp->data;
-
-error:
-	/* Failed to open directory: no directory entry in memory */
-	dirp->cached = 0;
-
-	/* Set error code */
-	DWORD errorcode = GetLastError();
-	switch (errorcode) {
-	case ERROR_ACCESS_DENIED:
-		/* No read access to directory */
-		dirent_set_errno(EACCES);
-		break;
-
-	case ERROR_DIRECTORY:
-		/* Directory name is invalid */
-		dirent_set_errno(ENOTDIR);
-		break;
-
-	case ERROR_PATH_NOT_FOUND:
-	default:
-		/* Cannot find the file */
-		dirent_set_errno(ENOENT);
-	}
-	return NULL;
-}
-
-/* Get next directory entry */
-static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp)
-{
-	/* Is the next directory entry already in cache? */
-	if (dirp->cached) {
-		/* Yes, a valid directory entry found in memory */
-		dirp->cached = 0;
-		return &dirp->data;
-	}
-
-	/* No directory entry in cache */
-	if (dirp->handle == INVALID_HANDLE_VALUE)
-		return NULL;
-
-	/* Read the next directory entry from stream */
-	if (FindNextFileW(dirp->handle, &dirp->data) == FALSE)
-		goto exit_close;
-
-	/* Success */
-	return &dirp->data;
-
-	/* Failure */
-exit_close:
-	FindClose(dirp->handle);
-	dirp->handle = INVALID_HANDLE_VALUE;
-	return NULL;
-}
-
-/* Open directory stream using plain old C-string */
-static DIR *opendir(const char *dirname)
-{
-	/* Must have directory name */
-	if (dirname == NULL || dirname[0] == '\0') {
-		dirent_set_errno(ENOENT);
-		return NULL;
-	}
-
-	/* Allocate memory for DIR structure */
-	struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR));
-	if (!dirp)
-		return NULL;
-
-	/* Convert directory name to wide-character string */
-	wchar_t wname[PATH_MAX + 1];
-	size_t n;
-	int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1);
-	if (error)
-		goto exit_failure;
-
-	/* Open directory stream using wide-character name */
-	dirp->wdirp = _wopendir(wname);
-	if (!dirp->wdirp)
-		goto exit_failure;
-
-	/* Success */
-	return dirp;
-
-	/* Failure */
-exit_failure:
-	free(dirp);
-	return NULL;
-}
-
-/* Read next directory entry */
-static struct dirent *readdir(DIR *dirp)
-{
-	/*
-	 * Read directory entry to buffer.  We can safely ignore the return
-	 * value as entry will be set to NULL in case of error.
-	 */
-	struct dirent *entry;
-	(void) readdir_r(dirp, &dirp->ent, &entry);
-
-	/* Return pointer to statically allocated directory entry */
-	return entry;
-}
-
-/*
- * Read next directory entry into called-allocated buffer.
- *
- * Returns zero on success.  If the end of directory stream is reached, then
- * sets result to NULL and returns zero.
- */
-static int readdir_r(
-	DIR *dirp, struct dirent *entry, struct dirent **result)
-{
-	/* Read next directory entry */
-	WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp);
-	if (!datap) {
-		/* No more directory entries */
-		*result = NULL;
-		return /*OK*/0;
-	}
-
-	/* Attempt to convert file name to multi-byte string */
-	size_t n;
-	int error = wcstombs_s(
-		&n, entry->d_name, PATH_MAX + 1,
-		datap->cFileName, PATH_MAX + 1);
-
-	/*
-	 * If the file name cannot be represented by a multi-byte string, then
-	 * attempt to use old 8+3 file name.  This allows the program to
-	 * access files although file names may seem unfamiliar to the user.
-	 *
-	 * Be ware that the code below cannot come up with a short file name
-	 * unless the file system provides one.  At least VirtualBox shared
-	 * folders fail to do this.
-	 */
-	if (error && datap->cAlternateFileName[0] != '\0') {
-		error = wcstombs_s(
-			&n, entry->d_name, PATH_MAX + 1,
-			datap->cAlternateFileName, PATH_MAX + 1);
-	}
-
-	if (!error) {
-		/* Length of file name excluding zero terminator */
-		entry->d_namlen = n - 1;
-
-		/* File attributes */
-		DWORD attr = datap->dwFileAttributes;
-		if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
-			entry->d_type = DT_CHR;
-		else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
-			entry->d_type = DT_DIR;
-		else
-			entry->d_type = DT_REG;
-
-		/* Reset dummy fields */
-		entry->d_ino = 0;
-		entry->d_off = 0;
-		entry->d_reclen = sizeof(struct dirent);
-	} else {
-		/*
-		 * Cannot convert file name to multi-byte string so construct
-		 * an erroneous directory entry and return that.  Note that
-		 * we cannot return NULL as that would stop the processing
-		 * of directory entries completely.
-		 */
-		entry->d_name[0] = '?';
-		entry->d_name[1] = '\0';
-		entry->d_namlen = 1;
-		entry->d_type = DT_UNKNOWN;
-		entry->d_ino = 0;
-		entry->d_off = -1;
-		entry->d_reclen = 0;
-	}
-
-	/* Return pointer to directory entry */
-	*result = entry;
-	return /*OK*/0;
-}
-
-/* Close directory stream */
-static int closedir(DIR *dirp)
-{
-	int ok;
-
-	if (!dirp)
-		goto exit_failure;
-
-	/* Close wide-character directory stream */
-	ok = _wclosedir(dirp->wdirp);
-	dirp->wdirp = NULL;
-
-	/* Release multi-byte character version */
-	free(dirp);
-	return ok;
-
-exit_failure:
-	/* Invalid directory stream */
-	dirent_set_errno(EBADF);
-	return /*failure*/-1;
-}
-
-/* Rewind directory stream to beginning */
-static void rewinddir(DIR* dirp)
-{
-	if (!dirp)
-		return;
-
-	/* Rewind wide-character string directory stream */
-	_wrewinddir(dirp->wdirp);
-}
-
-/* Scan directory for entries */
-static int scandir(
-	const char *dirname, struct dirent ***namelist,
-	int (*filter)(const struct dirent*),
-	int (*compare)(const struct dirent**, const struct dirent**))
-{
-	int result;
-
-	/* Open directory stream */
-	DIR *dir = opendir(dirname);
-	if (!dir) {
-		/* Cannot open directory */
-		return /*Error*/ -1;
-	}
-
-	/* Read directory entries to memory */
-	struct dirent *tmp = NULL;
-	struct dirent **files = NULL;
-	size_t size = 0;
-	size_t allocated = 0;
-	while (1) {
-		/* Allocate room for a temporary directory entry */
-		if (!tmp) {
-			tmp = (struct dirent*) malloc(sizeof(struct dirent));
-			if (!tmp)
-				goto exit_failure;
-		}
-
-		/* Read directory entry to temporary area */
-		struct dirent *entry;
-		if (readdir_r(dir, tmp, &entry) != /*OK*/0)
-			goto exit_failure;
-
-		/* Stop if we already read the last directory entry */
-		if (entry == NULL)
-			goto exit_success;
-
-		/* Determine whether to include the entry in results */
-		if (filter && !filter(tmp))
-			continue;
-
-		/* Enlarge pointer table to make room for another pointer */
-		if (size >= allocated) {
-			/* Compute number of entries in the new table */
-			size_t num_entries = size * 2 + 16;
-
-			/* Allocate new pointer table or enlarge existing */
-			void *p = realloc(files, sizeof(void*) * num_entries);
-			if (!p)
-				goto exit_failure;
-
-			/* Got the memory */
-			files = (dirent**) p;
-			allocated = num_entries;
-		}
-
-		/* Store the temporary entry to ptr table */
-		files[size++] = tmp;
-		tmp = NULL;
-	}
-
-exit_failure:
-	/* Release allocated file entries */
-	for (size_t i = 0; i < size; i++) {
-		free(files[i]);
-	}
-
-	/* Release the pointer table */
-	free(files);
-	files = NULL;
-
-	/* Exit with error code */
-	result = /*error*/ -1;
-	goto exit_status;
-
-exit_success:
-	/* Sort directory entries */
-	qsort(files, size, sizeof(void*),
-		(int (*) (const void*, const void*)) compare);
-
-	/* Pass pointer table to caller */
-	if (namelist)
-		*namelist = files;
-
-	/* Return the number of directory entries read */
-	result = (int) size;
-
-exit_status:
-	/* Release temporary directory entry, if we had one */
-	free(tmp);
-
-	/* Close directory stream */
-	closedir(dir);
-	return result;
-}
-
-/* Alphabetical sorting */
-static int alphasort(const struct dirent **a, const struct dirent **b)
-{
-	return strcoll((*a)->d_name, (*b)->d_name);
-}
-
-/* Sort versions */
-static int versionsort(const struct dirent **a, const struct dirent **b)
-{
-	return strverscmp((*a)->d_name, (*b)->d_name);
-}
-
-/* Compare strings */
-static int strverscmp(const char *a, const char *b)
-{
-	size_t i = 0;
-	size_t j;
-
-	/* Find first difference */
-	while (a[i] == b[i]) {
-		if (a[i] == '\0') {
-			/* No difference */
-			return 0;
-		}
-		++i;
-	}
-
-	/* Count backwards and find the leftmost digit */
-	j = i;
-	while (j > 0 && isdigit(a[j-1])) {
-		--j;
-	}
-
-	/* Determine mode of comparison */
-	if (a[j] == '0' || b[j] == '0') {
-		/* Find the next non-zero digit */
-		while (a[j] == '0' && a[j] == b[j]) {
-			j++;
-		}
-
-		/* String with more digits is smaller, e.g 002 < 01 */
-		if (isdigit(a[j])) {
-			if (!isdigit(b[j])) {
-				return -1;
-			}
-		} else if (isdigit(b[j])) {
-			return 1;
-		}
-	} else if (isdigit(a[j]) && isdigit(b[j])) {
-		/* Numeric comparison */
-		size_t k1 = j;
-		size_t k2 = j;
-
-		/* Compute number of digits in each string */
-		while (isdigit(a[k1])) {
-			k1++;
-		}
-		while (isdigit(b[k2])) {
-			k2++;
-		}
-
-		/* Number with more digits is bigger, e.g 999 < 1000 */
-		if (k1 < k2)
-			return -1;
-		else if (k1 > k2)
-			return 1;
-	}
-
-	/* Alphabetical comparison */
-	return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]);
-}
-
-/* Convert multi-byte string to wide character string */
-#if !defined(_MSC_VER) || _MSC_VER < 1400
-static int dirent_mbstowcs_s(
-	size_t *pReturnValue, wchar_t *wcstr,
-	size_t sizeInWords, const char *mbstr, size_t count)
-{
-	/* Older Visual Studio or non-Microsoft compiler */
-	size_t n = mbstowcs(wcstr, mbstr, sizeInWords);
-	if (wcstr && n >= count)
-		return /*error*/ 1;
-
-	/* Zero-terminate output buffer */
-	if (wcstr && sizeInWords) {
-		if (n >= sizeInWords)
-			n = sizeInWords - 1;
-		wcstr[n] = 0;
-	}
-
-	/* Length of multi-byte string with zero terminator */
-	if (pReturnValue) {
-		*pReturnValue = n + 1;
-	}
-
-	/* Success */
-	return 0;
-}
-#endif
-
-/* Convert wide-character string to multi-byte string */
-#if !defined(_MSC_VER) || _MSC_VER < 1400
-static int dirent_wcstombs_s(
-	size_t *pReturnValue, char *mbstr,
-	size_t sizeInBytes, const wchar_t *wcstr, size_t count)
-{
-	/* Older Visual Studio or non-Microsoft compiler */
-	size_t n = wcstombs(mbstr, wcstr, sizeInBytes);
-	if (mbstr && n >= count)
-		return /*error*/1;
-
-	/* Zero-terminate output buffer */
-	if (mbstr && sizeInBytes) {
-		if (n >= sizeInBytes) {
-			n = sizeInBytes - 1;
-		}
-		mbstr[n] = '\0';
-	}
-
-	/* Length of resulting multi-bytes string WITH zero-terminator */
-	if (pReturnValue) {
-		*pReturnValue = n + 1;
-	}
-
-	/* Success */
-	return 0;
-}
-#endif
-
-/* Set errno variable */
-#if !defined(_MSC_VER) || _MSC_VER < 1400
-static void dirent_set_errno(int error)
-{
-	/* Non-Microsoft compiler or older Microsoft compiler */
-	errno = error;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /*DIRENT_H*/
--- a/extern/libcompat/win/dlfcn/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-project(dl)
-add_library(
-	dl
-	STATIC
-	${dl_SOURCE_DIR}/dlfcn.h
-	${dl_SOURCE_DIR}/dlfcn.c
-)
-
-# Correctly export the location of installed includes in the target
-target_include_directories(
-	dl
-	PUBLIC
-		$<BUILD_INTERFACE:${dl_SOURCE_DIR}>
-		$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-)
-
-if (CMAKE_C_COMPILER_ID MATCHES "MSVC")
-	target_compile_definitions(dl PRIVATE _CRT_SECURE_NO_WARNINGS)
-endif ()
-
-install(
-	TARGETS dl
-	RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-	LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-	ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-)
--- a/extern/libcompat/win/dlfcn/dlfcn.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,478 +0,0 @@
-/*
- * dlfcn-win32
- * Copyright (c) 2007 Ramiro Polla
- * Copyright (c) 2015 Tiancheng "Timothy" Gu
- * Copyright (c) 2019 Pali Rohár <pali.rohar@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#ifdef _DEBUG
-#define _CRTDBG_MAP_ALLOC
-#include <stdlib.h>
-#include <crtdbg.h>
-#endif
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef _MSC_VER
-/* https://docs.microsoft.com/en-us/cpp/intrinsics/returnaddress */
-#pragma intrinsic(_ReturnAddress)
-#else
-/* https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html */
-#ifndef _ReturnAddress
-#define _ReturnAddress() (__builtin_extract_return_addr(__builtin_return_address(0)))
-#endif
-#endif
-
-#ifdef SHARED
-#define DLFCN_WIN32_EXPORTS
-#endif
-#include "dlfcn.h"
-
-/* Note:
- * MSDN says these functions are not thread-safe. We make no efforts to have
- * any kind of thread safety.
- */
-
-typedef struct local_object {
-    HMODULE hModule;
-    struct local_object *previous;
-    struct local_object *next;
-} local_object;
-
-static local_object first_object;
-
-/* These functions implement a double linked list for the local objects. */
-static local_object *local_search( HMODULE hModule )
-{
-    local_object *pobject;
-
-    if( hModule == NULL )
-        return NULL;
-
-    for( pobject = &first_object; pobject; pobject = pobject->next )
-        if( pobject->hModule == hModule )
-            return pobject;
-
-    return NULL;
-}
-
-static BOOL local_add( HMODULE hModule )
-{
-    local_object *pobject;
-    local_object *nobject;
-
-    if( hModule == NULL )
-        return TRUE;
-
-    pobject = local_search( hModule );
-
-    /* Do not add object again if it's already on the list */
-    if( pobject )
-        return TRUE;
-
-    for( pobject = &first_object; pobject->next; pobject = pobject->next );
-
-    nobject = (local_object*) malloc( sizeof( local_object ) );
-
-    if( !nobject )
-    {
-        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
-        return FALSE;
-    }
-
-    pobject->next = nobject;
-    nobject->next = NULL;
-    nobject->previous = pobject;
-    nobject->hModule = hModule;
-
-    return TRUE;
-}
-
-static void local_rem( HMODULE hModule )
-{
-    local_object *pobject;
-
-    if( hModule == NULL )
-        return;
-
-    pobject = local_search( hModule );
-
-    if( !pobject )
-        return;
-
-    if( pobject->next )
-        pobject->next->previous = pobject->previous;
-    if( pobject->previous )
-        pobject->previous->next = pobject->next;
-
-    free( pobject );
-}
-
-/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
- * static buffer.
- * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
- * the limit.
- */
-static char error_buffer[65535];
-static BOOL error_occurred;
-
-static void save_err_str( const char *str )
-{
-    DWORD dwMessageId;
-    DWORD ret;
-    size_t pos, len;
-
-    dwMessageId = GetLastError( );
-
-    if( dwMessageId == 0 )
-        return;
-
-    len = strlen( str );
-    if( len > sizeof( error_buffer ) - 5 )
-        len = sizeof( error_buffer ) - 5;
-
-    /* Format error message to:
-     * "<argument to function that failed>": <Windows localized error message>
-      */
-    pos = 0;
-    error_buffer[pos++] = '"';
-    memcpy( error_buffer+pos, str, len );
-    pos += len;
-    error_buffer[pos++] = '"';
-    error_buffer[pos++] = ':';
-    error_buffer[pos++] = ' ';
-
-    ret = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwMessageId,
-        MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
-        error_buffer+pos, (DWORD) (sizeof(error_buffer)-pos), NULL );
-    pos += ret;
-
-    /* When FormatMessageA() fails it returns zero and does not touch buffer
-     * so add trailing null byte */
-    if( ret == 0 )
-        error_buffer[pos] = '\0';
-
-    if( pos > 1 )
-    {
-        /* POSIX says the string must not have trailing <newline> */
-        if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
-            error_buffer[pos-2] = '\0';
-    }
-
-    error_occurred = TRUE;
-}
-
-static void save_err_ptr_str( const void *ptr )
-{
-    char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */
-
-#ifdef _MSC_VER
-/* Supress warning C4996: 'sprintf': This function or variable may be unsafe */
-#pragma warning( suppress: 4996 )
-#endif
-    sprintf( ptr_buf, "0x%p", ptr );
-
-    save_err_str( ptr_buf );
-}
-
-/* Load Psapi.dll at runtime, this avoids linking caveat */
-static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded )
-{
-    static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD);
-    HMODULE psapi;
-
-    if( !EnumProcessModulesPtr )
-    {
-        psapi = LoadLibraryA( "Psapi.dll" );
-        if( psapi )
-            EnumProcessModulesPtr = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( psapi, "EnumProcessModules" );
-        if( !EnumProcessModulesPtr )
-            return 0;
-    }
-
-    return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded );
-}
-
-void *dlopen( const char *file, int mode )
-{
-    HMODULE hModule;
-    UINT uMode;
-
-    error_occurred = FALSE;
-
-    /* Do not let Windows display the critical-error-handler message box */
-    uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
-
-    if( file == 0 )
-    {
-        /* POSIX says that if the value of file is 0, a handle on a global
-         * symbol object must be provided. That object must be able to access
-         * all symbols from the original program file, and any objects loaded
-         * with the RTLD_GLOBAL flag.
-         * The return value from GetModuleHandle( ) allows us to retrieve
-         * symbols only from the original program file. EnumProcessModules() is
-         * used to access symbols from other libraries. For objects loaded
-         * with the RTLD_LOCAL flag, we create our own list later on. They are
-         * excluded from EnumProcessModules() iteration.
-         */
-        hModule = GetModuleHandle( NULL );
-
-        if( !hModule )
-            save_err_str( "(null)" );
-    }
-    else
-    {
-        HANDLE hCurrentProc;
-        DWORD dwProcModsBefore, dwProcModsAfter;
-        char lpFileName[MAX_PATH];
-        size_t i, len;
-
-        len = strlen( file );
-
-        if( len >= sizeof( lpFileName ) )
-        {
-            SetLastError( ERROR_FILENAME_EXCED_RANGE );
-            save_err_str( file );
-            hModule = NULL;
-        }
-        else
-        {
-            /* MSDN says backslashes *must* be used instead of forward slashes. */
-            for( i = 0; i < len; i++ )
-            {
-                if( file[i] == '/' )
-                    lpFileName[i] = '\\';
-                else
-                    lpFileName[i] = file[i];
-            }
-            lpFileName[len] = '\0';
-
-            hCurrentProc = GetCurrentProcess( );
-
-            if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsBefore ) == 0 )
-                dwProcModsBefore = 0;
-
-            /* POSIX says the search path is implementation-defined.
-             * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
-             * to UNIX's search paths (start with system folders instead of current
-             * folder).
-             */
-            hModule = LoadLibraryExA( lpFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
-
-            if( !hModule )
-            {
-                save_err_str( lpFileName );
-            }
-            else
-            {
-                if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 )
-                    dwProcModsAfter = 0;
-
-                /* If the object was loaded with RTLD_LOCAL, add it to list of local
-                 * objects, so that its symbols cannot be retrieved even if the handle for
-                 * the original program file is passed. POSIX says that if the same
-                 * file is specified in multiple invocations, and any of them are
-                 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
-                 * symbols will remain global. If number of loaded modules was not
-                 * changed after calling LoadLibraryEx(), it means that library was
-                 * already loaded.
-                 */
-                if( (mode & RTLD_LOCAL) && dwProcModsBefore != dwProcModsAfter )
-                {
-                    if( !local_add( hModule ) )
-                    {
-                        save_err_str( lpFileName );
-                        FreeLibrary( hModule );
-                        hModule = NULL;
-                    }
-                }
-                else if( !(mode & RTLD_LOCAL) && dwProcModsBefore == dwProcModsAfter )
-                {
-                    local_rem( hModule );
-                }
-            }
-        }
-    }
-
-    /* Return to previous state of the error-mode bit flags. */
-    SetErrorMode( uMode );
-
-    return (void *) hModule;
-}
-
-int dlclose( void *handle )
-{
-    HMODULE hModule = (HMODULE) handle;
-    BOOL ret;
-
-    error_occurred = FALSE;
-
-    ret = FreeLibrary( hModule );
-
-    /* If the object was loaded with RTLD_LOCAL, remove it from list of local
-     * objects.
-     */
-    if( ret )
-        local_rem( hModule );
-    else
-        save_err_ptr_str( handle );
-
-    /* dlclose's return value in inverted in relation to FreeLibrary's. */
-    ret = !ret;
-
-    return (int) ret;
-}
-
-__declspec(noinline) /* Needed for _ReturnAddress() */
-void *dlsym( void *handle, const char *name )
-{
-    FARPROC symbol;
-    HMODULE hCaller;
-    HMODULE hModule;
-    HANDLE hCurrentProc;
-
-    error_occurred = FALSE;
-
-    symbol = NULL;
-    hCaller = NULL;
-    hModule = GetModuleHandle( NULL );
-    hCurrentProc = GetCurrentProcess( );
-
-    if( handle == RTLD_DEFAULT )
-    {
-        /* The symbol lookup happens in the normal global scope; that is,
-         * a search for a symbol using this handle would find the same
-         * definition as a direct use of this symbol in the program code.
-         * So use same lookup procedure as when filename is NULL.
-         */
-        handle = hModule;
-    }
-    else if( handle == RTLD_NEXT )
-    {
-        /* Specifies the next object after this one that defines name.
-         * This one refers to the object containing the invocation of dlsym().
-         * The next object is the one found upon the application of a load
-         * order symbol resolution algorithm. To get caller function of dlsym()
-         * use _ReturnAddress() intrinsic. To get HMODULE of caller function
-         * use standard GetModuleHandleExA() function.
-         */
-        if( !GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) _ReturnAddress( ), &hCaller ) )
-            goto end;
-    }
-
-    if( handle != RTLD_NEXT )
-    {
-        symbol = GetProcAddress( (HMODULE) handle, name );
-
-        if( symbol != NULL )
-            goto end;
-    }
-
-    /* If the handle for the original program file is passed, also search
-     * in all globally loaded objects.
-     */
-
-    if( hModule == handle || handle == RTLD_NEXT )
-    {
-        HMODULE *modules;
-        DWORD cbNeeded;
-        DWORD dwSize;
-        size_t i;
-
-        /* GetModuleHandle( NULL ) only returns the current program file. So
-         * if we want to get ALL loaded module including those in linked DLLs,
-         * we have to use EnumProcessModules( ).
-         */
-        if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwSize ) != 0 )
-        {
-            modules = malloc( dwSize );
-            if( modules )
-            {
-                if( MyEnumProcessModules( hCurrentProc, modules, dwSize, &cbNeeded ) != 0 && dwSize == cbNeeded )
-                {
-                    for( i = 0; i < dwSize / sizeof( HMODULE ); i++ )
-                    {
-                        if( handle == RTLD_NEXT && hCaller )
-                        {
-                            /* Next modules can be used for RTLD_NEXT */
-                            if( hCaller == modules[i] )
-                                hCaller = NULL;
-                            continue;
-                        }
-                        if( local_search( modules[i] ) )
-                            continue;
-                        symbol = GetProcAddress( modules[i], name );
-                        if( symbol != NULL )
-                        {
-                            free( modules );
-                            goto end;
-                        }
-                    }
-
-                }
-                free( modules );
-            }
-            else
-            {
-                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
-                goto end;
-            }
-        }
-    }
-
-end:
-    if( symbol == NULL )
-    {
-        if( GetLastError() == 0 )
-            SetLastError( ERROR_PROC_NOT_FOUND );
-        save_err_str( name );
-    }
-
-    return *(void **) (&symbol);
-}
-
-char *dlerror( void )
-{
-    /* If this is the second consecutive call to dlerror, return NULL */
-    if( !error_occurred )
-        return NULL;
-
-    /* POSIX says that invoking dlerror( ) a second time, immediately following
-     * a prior invocation, shall result in NULL being returned.
-     */
-    error_occurred = FALSE;
-
-    return error_buffer;
-}
-
-#ifdef SHARED
-BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
-{
-    (void) hinstDLL;
-    (void) fdwReason;
-    (void) lpvReserved;
-    return TRUE;
-}
-#endif
--- a/extern/libcompat/win/dlfcn/dlfcn.h	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * dlfcn-win32
- * Copyright (c) 2007 Ramiro Polla
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef DLFCN_H
-#define DLFCN_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(DLFCN_BUILD_DLL)
-#   define DLFCN_EXPORT __declspec(dllexport)
-#else
-#   define DLFCN_EXPORT
-#endif
-
-/* Relocations are performed when the object is loaded. */
-#define RTLD_NOW    0
-
-/* Relocations are performed at an implementation-defined time.
- * Windows API does not support lazy symbol resolving (when first reference
- * to a given symbol occurs). So RTLD_LAZY implementation is same as RTLD_NOW.
- */
-#define RTLD_LAZY   RTLD_NOW
-
-/* All symbols are available for relocation processing of other modules. */
-#define RTLD_GLOBAL (1 << 1)
-
-/* All symbols are not made available for relocation processing by other modules. */
-#define RTLD_LOCAL  (1 << 2)
-
-/* These two were added in The Open Group Base Specifications Issue 6.
- * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
- */
-
-/* The symbol lookup happens in the normal global scope. */
-#define RTLD_DEFAULT    ((void *)0)
-
-/* Specifies the next object after this one that defines name. */
-#define RTLD_NEXT       ((void *)-1)
-
-/* Open a symbol table handle. */
-DLFCN_EXPORT void *dlopen(const char *file, int mode);
-
-/* Close a symbol table handle. */
-DLFCN_EXPORT int dlclose(void *handle);
-
-/* Get the address of a symbol from a symbol table handle. */
-DLFCN_EXPORT void *dlsym(void *handle, const char *name);
-
-/* Get diagnostic information. */
-DLFCN_EXPORT char *dlerror(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* DLFCN_H */
--- a/extern/libduktape/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for duktape
-#
-# Copyright (c) 2016-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.
-#
-
-cmake_minimum_required(VERSION 3.0)
-project(libirccd-duktape)
-add_library(libirccd-duktape duk_config.h duktape.c duktape.h)
-target_include_directories(
-	libirccd-duktape
-	PUBLIC
-		$<BUILD_INTERFACE:${libirccd-duktape_SOURCE_DIR}>
-)
-target_link_libraries(libirccd-duktape m)
-
-if (BUILD_SHARED_LIBS)
-	target_compile_definitions(libirccd-duktape PUBLIC DUK_F_DLL_BUILD)
-endif ()
-
-set_target_properties(libirccd-duktape PROPERTIES PREFIX "" FOLDER extern)
--- a/extern/libgreatest/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for libgreatest
-#
-# Copyright (c) 2016-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.
-#
-
-cmake_minimum_required(VERSION 3.0)
-project(libirccd-greatest)
-add_library(libirccd-greatest INTERFACE)
-target_include_directories(
-	libirccd-greatest
-	INTERFACE
-		$<BUILD_INTERFACE:${libirccd-greatest_SOURCE_DIR}>
-)
-target_sources(libirccd-greatest INTERFACE ${libirccd-greatest_SOURCE_DIR}/greatest.h)
--- a/extern/libketopt/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#
-# CMakeLists.txt -- CMake build system for ketopt
-#
-# Copyright (c) 2016-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.
-#
-
-cmake_minimum_required(VERSION 3.0)
-project(libirccd-ketopt)
-add_library(libirccd-ketopt INTERFACE)
-target_sources(libirccd-ketopt INTERFACE ${libirccd-ketopt_SOURCE_DIR}/ketopt.h)
-target_include_directories(
-	libirccd-ketopt
-	INTERFACE
-		$<BUILD_INTERFACE:${libirccd-ketopt_SOURCE_DIR}>
-)
--- a/irccd/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(irccd)
-
-set(
-	SOURCES
-	${irccd_SOURCE_DIR}/dl-plugin.c
-	${irccd_SOURCE_DIR}/dl-plugin.h
-	${irccd_SOURCE_DIR}/peer.c
-	${irccd_SOURCE_DIR}/peer.h
-	${irccd_SOURCE_DIR}/transport.c
-	${irccd_SOURCE_DIR}/transport.h
-)
-
-if (IRCCD_WITH_JS)
-	list(
-		APPEND SOURCES
-		${irccd_SOURCE_DIR}/js-plugin.c
-		${irccd_SOURCE_DIR}/js-plugin.h
-		${irccd_SOURCE_DIR}/jsapi-chrono.c
-		${irccd_SOURCE_DIR}/jsapi-chrono.h
-		${irccd_SOURCE_DIR}/jsapi-directory.c
-		${irccd_SOURCE_DIR}/jsapi-directory.h
-		${irccd_SOURCE_DIR}/jsapi-file.c
-		${irccd_SOURCE_DIR}/jsapi-file.h
-		${irccd_SOURCE_DIR}/jsapi-hook.c
-		${irccd_SOURCE_DIR}/jsapi-hook.h
-		${irccd_SOURCE_DIR}/jsapi-irccd.c
-		${irccd_SOURCE_DIR}/jsapi-irccd.h
-		${irccd_SOURCE_DIR}/jsapi-logger.c
-		${irccd_SOURCE_DIR}/jsapi-logger.h
-		${irccd_SOURCE_DIR}/jsapi-plugin.c
-		${irccd_SOURCE_DIR}/jsapi-plugin.h
-		${irccd_SOURCE_DIR}/jsapi-rule.c
-		${irccd_SOURCE_DIR}/jsapi-rule.h
-		${irccd_SOURCE_DIR}/jsapi-server.c
-		${irccd_SOURCE_DIR}/jsapi-server.h
-		${irccd_SOURCE_DIR}/jsapi-system.c
-		${irccd_SOURCE_DIR}/jsapi-system.h
-		${irccd_SOURCE_DIR}/jsapi-timer.c
-		${irccd_SOURCE_DIR}/jsapi-timer.h
-		${irccd_SOURCE_DIR}/jsapi-unicode.c
-		${irccd_SOURCE_DIR}/jsapi-unicode.h
-		${irccd_SOURCE_DIR}/jsapi-util.c
-		${irccd_SOURCE_DIR}/jsapi-util.h
-		${irccd_SOURCE_DIR}/unicode.c
-		${irccd_SOURCE_DIR}/unicode.h
-	)
-endif ()
-
-# This is required for unit tests.
-add_library(irccd-fe OBJECT ${SOURCES})
-target_link_libraries(irccd-fe libirccd-static)
-target_include_directories(
-	irccd-fe
-	PUBLIC
-		$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
-		$<BUILD_INTERFACE:${irccd_SOURCE_DIR}>
-)
-
-if (IRCCD_WITH_JS)
-	target_link_libraries(irccd-fe libirccd-duktape -pthread ${CMAKE_DL_LIBS})
-endif ()
-
-flex_target(irccd-lex ${irccd_SOURCE_DIR}/lex.l ${irccd_BINARY_DIR}/lex.c)
-bison_target(irccd-conf ${irccd_SOURCE_DIR}/conf.y ${irccd_BINARY_DIR}/conf.c)
-add_flex_bison_dependency(irccd-lex irccd-conf)
-
-add_executable(
-	irccd
-	${irccd_SOURCE_DIR}/main.c
-	${irccd_SOURCE_DIR}/lex.l
-	${irccd_SOURCE_DIR}/conf.y
-	${BISON_irccd-conf_OUTPUTS}
-	${FLEX_irccd-lex_OUTPUTS}
-)
-
-set_target_properties(irccd PROPERTIES ENABLE_EXPORTS On)
-target_link_libraries(irccd irccd-fe)
-install(TARGETS irccd DESTINATION ${CMAKE_INSTALL_BINDIR})
-install(FILES irccd.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} RENAME irccd.conf.sample)
-
-source_group(TREE ${irccd_SOURCE_DIR} FILES ${SOURCES})
--- a/irccd/conf.y	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/conf.y	Tue Apr 27 09:22:16 2021 +0200
@@ -26,7 +26,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include <irccd/compat.h>
 #include <irccd/irccd.h>
 #include <irccd/log.h>
 #include <irccd/rule.h>
--- a/irccd/dl-plugin.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/dl-plugin.c	Tue Apr 27 09:22:16 2021 +0200
@@ -25,7 +25,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <irccd/compat.h>
 #include <irccd/config.h>
 #include <irccd/log.h>
 #include <irccd/plugin.h>
@@ -204,6 +203,7 @@
 		return NULL;
 
 	if (!(self.handle = dlopen(path, RTLD_NOW | RTLD_GLOBAL))) {
+		printf("==> %s\n", dlerror());
 		irc_log_warn("plugin: %s: %s", path, dlerror());
 		return NULL;
 	}
--- a/irccd/js-plugin.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/js-plugin.c	Tue Apr 27 09:22:16 2021 +0200
@@ -26,7 +26,6 @@
 #include <unistd.h>
 
 #include <irccd/channel.h>
-#include <irccd/compat.h>
 #include <irccd/config.h>
 #include <irccd/event.h>
 #include <irccd/log.h>
--- a/irccd/jsapi-directory.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/jsapi-directory.c	Tue Apr 27 09:22:16 2021 +0200
@@ -30,8 +30,6 @@
 
 #include <duktape.h>
 
-#include <irccd/compat.h>
-
 #include "jsapi-system.h"
 
 enum {
--- a/irccd/jsapi-file.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/jsapi-file.c	Tue Apr 27 09:22:16 2021 +0200
@@ -16,8 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <compat.h>
-
 #include <sys/stat.h>
 #include <assert.h>
 #include <errno.h>
@@ -99,58 +97,32 @@
 {
 	duk_push_object(ctx);
 
-#if defined(COMPAT_HAVE_STAT_ST_ATIME)
 	duk_push_int(ctx, st->st_atime);
 	duk_put_prop_string(ctx, -2, "atime");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_BLKSIZE)
 	duk_push_int(ctx, st->st_blksize);
 	duk_put_prop_string(ctx, -2, "blksize");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_BLOCKS)
 	duk_push_int(ctx, st->st_blocks);
 	duk_put_prop_string(ctx, -2, "blocks");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_CTIME)
 	duk_push_int(ctx, st->st_ctime);
 	duk_put_prop_string(ctx, -2, "ctime");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_DEV)
 	duk_push_int(ctx, st->st_dev);
 	duk_put_prop_string(ctx, -2, "dev");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_GID)
 	duk_push_int(ctx, st->st_gid);
 	duk_put_prop_string(ctx, -2, "gid");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_INO)
 	duk_push_int(ctx, st->st_ino);
 	duk_put_prop_string(ctx, -2, "ino");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_MODE)
 	duk_push_int(ctx, st->st_mode);
 	duk_put_prop_string(ctx, -2, "mode");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_MTIME)
 	duk_push_int(ctx, st->st_mtime);
 	duk_put_prop_string(ctx, -2, "mtime");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_NLINK)
 	duk_push_int(ctx, st->st_nlink);
 	duk_put_prop_string(ctx, -2, "nlink");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_RDEV)
 	duk_push_int(ctx, st->st_rdev);
 	duk_put_prop_string(ctx, -2, "rdev");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_SIZE)
 	duk_push_int(ctx, st->st_size);
 	duk_put_prop_string(ctx, -2, "size");
-#endif
-#if defined(COMPAT_HAVE_STAT_ST_UID)
 	duk_push_int(ctx, st->st_uid);
 	duk_put_prop_string(ctx, -2, "uid");
-#endif
 }
 
 static struct file *
--- a/irccd/jsapi-irccd.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/jsapi-irccd.c	Tue Apr 27 09:22:16 2021 +0200
@@ -22,10 +22,9 @@
 
 #include <duktape.h>
 
+#include <irccd/config.h>
 #include <irccd/util.h>
 
-#include "config.h"
-
 static int
 SystemError_constructor(duk_context *ctx)
 {
--- a/irccd/jsapi-rule.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/jsapi-rule.c	Tue Apr 27 09:22:16 2021 +0200
@@ -16,8 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <compat.h>
-
 #include <assert.h>
 #include <string.h>
 
--- a/irccd/jsapi-util.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/jsapi-util.c	Tue Apr 27 09:22:16 2021 +0200
@@ -16,8 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <compat.h>
-
 #include <string.h>
 
 #include <irccd/server.h>
--- a/irccd/main.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/main.c	Tue Apr 27 09:22:16 2021 +0200
@@ -16,27 +16,30 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <config.h>
-#include <compat.h>
-
 #include <err.h>
 #include <errno.h>
 #include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
+#include <irccd/config.h>
 #include <irccd/irccd.h>
 #include <irccd/log.h>
-#include <irccd/server.h>
-#include <irccd/transport.h>
-#include <irccd/util.h>
 #include <irccd/plugin.h>
 #include <irccd/rule.h>
+#include <irccd/server.h>
+#include <irccd/util.h>
 
 #include "dl-plugin.h"
-#include "js-plugin.h"
+
 #include "peer.h"
+#include "transport.h"
+
+#if defined(IRCCD_WITH_JS)
+#       include "js-plugin.h"
+#endif
 
 struct pollables {
 	struct pollfd *fds;
--- a/irccd/peer.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/peer.c	Tue Apr 27 09:22:16 2021 +0200
@@ -28,7 +28,6 @@
 
 #include <assert.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/irccd.h>
 #include <irccd/log.h>
--- a/irccd/transport.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/irccd/transport.c	Tue Apr 27 09:22:16 2021 +0200
@@ -28,13 +28,12 @@
 #include <sys/un.h>
 #include <unistd.h>
 
-#include <irccd/compat.h>
 #include <irccd/config.h>
 #include <irccd/log.h>
-#include <irccd/transport.h>
 #include <irccd/util.h>
 
 #include "peer.h"
+#include "transport.h"
 
 static struct sockaddr_un addr;
 static int fd = -1;
--- a/irccdctl/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(irccdctl)
-add_executable(irccdctl main.c)
-target_link_libraries(irccdctl libirccd-static libirccd-ketopt)
-install(TARGETS irccdctl DESTINATION ${CMAKE_INSTALL_BINDIR})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/irccdctl/irccdctl.c	Tue Apr 27 09:22:16 2021 +0200
@@ -0,0 +1,995 @@
+/*
+ * main.c -- irccdctl(1) main file
+ *
+ * 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/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdnoreturn.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <ketopt.h>
+
+#include <irccd/limits.h>
+#include <irccd/util.h>
+
+static int verbose;
+static int sock;
+static struct sockaddr_un sockaddr = {
+	.sun_family = PF_LOCAL,
+	.sun_path = "/tmp/irccd.sock"
+};
+static char in[IRC_BUF_LEN];
+static char out[IRC_BUF_LEN];
+
+static char *
+poll(void)
+{
+	static char ret[IRC_BUF_LEN];
+	char *nl;
+
+	while (!(nl = strstr(in, "\n"))) {
+		char buf[IRC_BUF_LEN] = {0};
+		ssize_t nr;
+
+		if ((nr = recv(sock, buf, sizeof (buf) - 1, 0)) <= 0)
+			errc(1, nr == 0 ? ECONNRESET : errno, "abort");
+		if (strlcat(in, buf, sizeof (in)) >= sizeof (in))
+			errc(1, EMSGSIZE, "abort");
+	}
+
+	*nl = '\0';
+	strlcpy(ret, in, sizeof (ret));
+	memmove(in, nl + 1, sizeof (in) - (nl - in) - 1);
+
+	return ret;
+}
+
+static void
+dial(void)
+{
+	const struct timeval tv = {
+		.tv_sec = 30
+	};
+
+	if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
+		err(1, "socket");
+	if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (tv)) < 0 ||
+	    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)) < 0)
+		err(1, "setsockopt");
+	if (connect(sock, (const struct sockaddr *)&sockaddr, SUN_LEN(&sockaddr)) < 0)
+		err(1, "connect");
+}
+
+static void
+check(void)
+{
+	/* Ensure we're talking to irccd. */
+	int major, minor, patch;
+
+	if ((sscanf(poll(), "IRCCD %d.%d.%d", &major, &minor, &patch) != 3))
+		errx(1, "abort: not irccd instance");
+	if (verbose)
+		printf("connected to irccd %d.%d.%d\n", major, minor, patch);
+}
+
+static void
+req(const char *fmt, ...)
+{
+	char buf[IRC_BUF_LEN];
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof (buf), fmt, ap);
+	va_end(ap);
+
+	if (strlcat(out, buf, sizeof (out)) >= sizeof (out) ||
+	    strlcat(out, "\n", sizeof (out)) >= sizeof (out))
+		errc(1, EMSGSIZE, "abort");
+
+	while (out[0]) {
+		ssize_t ns, len;
+
+		len = strlen(out);
+
+		if ((ns = send(sock, out, len, MSG_NOSIGNAL)) <= 0)
+			err(1, "send");
+
+		if (ns >= len)
+			memset(out, 0, sizeof (out));
+		else
+			memmove(out, out + ns, sizeof (out) - ns);
+	}
+}
+
+static char *
+ok(void)
+{
+	char *response = poll();
+
+	if (strncmp(response, "OK", 2) != 0)
+		errx(1, "abort: %s", response);
+
+	/* Skip "OK". */
+	response += 2;
+
+	while (*response && isspace(*response))
+		response++;
+
+	return response;
+}
+
+static void
+show_connect(char *line)
+{
+	const char *args[2] = {0};
+
+	if (irc_util_split(line, args, 2, ' ') == 2) {
+		printf("%-16s: %s\n", "event", "onConnect");
+		printf("%-16s: %s\n", "server", args[0]);
+	}
+}
+
+static void
+show_disconnect(char *line)
+{
+	const char *args[2] = {0};
+
+	if (irc_util_split(line, args, 2, ' ') == 2) {
+		printf("%-16s: %s\n", "event", "onDisonnect");
+		printf("%-16s: %s\n", "server", args[0]);
+	}
+}
+
+static void
+show_invite(char *line)
+{
+	const char *args[5] = {0};
+
+	if (irc_util_split(line, args, 5, ' ') == 5) {
+		printf("%-16s: %s\n", "event", "onInvite");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "nickname", args[4]);
+	}
+}
+
+static void
+show_join(char *line)
+{
+	const char *args[4] = {0};
+
+	if (irc_util_split(line, args, 4, ' ') == 4) {
+		printf("%-16s: %s\n", "event", "onJoin");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+	}
+}
+
+static void
+show_kick(char *line)
+{
+	const char *args[6] = {0};
+
+	if (irc_util_split(line, args, 6, ' ') >= 5) {
+		printf("%-16s: %s\n", "event", "onKick");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "target", args[4]);
+		printf("%-16s: %s\n", "reason", args[5] ? args[5] : "");
+	}
+}
+
+static void
+show_me(char *line)
+{
+	const char *args[5] = {0};
+
+	if (irc_util_split(line, args, 5, ' ') == 5) {
+		printf("%-16s: %s\n", "event", "onMe");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "message", args[4]);
+	}
+}
+
+static void
+show_message(char *line)
+{
+	const char *args[5] = {0};
+
+	if (irc_util_split(line, args, 5, ' ') == 5) {
+		printf("%-16s: %s\n", "event", "onMessage");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "message", args[4]);
+	}
+}
+
+static void
+show_mode(char *line)
+{
+	const char *args[8] = {0};
+
+	if (irc_util_split(line, args, 8, ' ') >= 5) {
+		printf("%-16s: %s\n", "event", "onMode");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "mode", args[4]);
+		printf("%-16s: %s\n", "limit", (args[5] ? args[5] : ""));
+		printf("%-16s: %s\n", "user", (args[6] ? args[6] : ""));
+		printf("%-16s: %s\n", "mask", (args[7] ? args[7] : ""));
+	}
+}
+
+static void
+show_nick(char *line)
+{
+	const char *args[4] = {0};
+
+	if (irc_util_split(line, args, 4, ' ') == 4) {
+		printf("%-16s: %s\n", "event", "onNick");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "nickname", args[3]);
+	}
+}
+
+static void
+show_notice(char *line)
+{
+	const char *args[5] = {0};
+
+	if (irc_util_split(line, args, 5, ' ') == 5) {
+		printf("%-16s: %s\n", "event", "onNotice");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "message", args[4]);
+	}
+}
+
+static void
+show_part(char *line)
+{
+	const char *args[5] = {0};
+
+	if (irc_util_split(line, args, 5, ' ') >= 4) {
+		printf("%-16s: %s\n", "event", "onPart");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "reason", (args[4] ? args[4] : ""));
+	}
+}
+
+static void
+show_topic(char *line)
+{
+	const char *args[5] = {0};
+
+	if (irc_util_split(line, args, 5, ' ') >= 4) {
+		printf("%-16s: %s\n", "event", "onTopic");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "origin", args[2]);
+		printf("%-16s: %s\n", "channel", args[3]);
+		printf("%-16s: %s\n", "topic", args[4]);
+	}
+}
+
+static void
+show_whois(char *line)
+{
+	const char *args[6] = {0};
+	//char *p, *token;
+
+	if (irc_util_split(line, args, 6, ' ') >= 4) {
+		printf("%-16s: %s\n", "event", "onWhois");
+		printf("%-16s: %s\n", "server", args[1]);
+		printf("%-16s: %s\n", "nickname", args[2]);
+		printf("%-16s: %s\n", "username", args[3]);
+		printf("%-16s: %s\n", "hostname", args[4]);
+		printf("%-16s: %s\n", "username", args[5]);
+		//printf("channels:  %s\n", args[6]);
+	}
+}
+
+static const struct {
+	const char *event;
+	void (*show)(char *);
+} watchtable[] = {
+	{ "EVENT-CONNECT",      show_connect    },
+	{ "EVENT-DISCONNECT",   show_disconnect },
+	{ "EVENT-INVITE",       show_invite     },
+	{ "EVENT-JOIN",         show_join       },
+	{ "EVENT-KICK",         show_kick       },
+	{ "EVENT-MESSAGE",      show_message    },
+	{ "EVENT-ME",           show_me         },
+	{ "EVENT-MODE",         show_mode       },
+	{ "EVENT-NICK",         show_nick       },
+	{ "EVENT-NOTICE",       show_notice     },
+	{ "EVENT-PART",         show_part       },
+	{ "EVENT-TOPIC",        show_topic      },
+	{ "EVENT-WHOIS",        show_whois      }
+};
+
+static void
+show(char *ev)
+{
+	for (size_t i = 0; i < IRC_UTIL_SIZE(watchtable); ++i) {
+		if (strncmp(watchtable[i].event, ev, strlen(watchtable[i].event)) == 0) {
+			watchtable[i].show(ev);
+			printf("\n");
+			break;
+		}
+	}
+}
+
+static void
+plugin_list_set(int argc, char **argv, const char *cmd)
+{
+	char *line, *p;
+	size_t num = 0;
+
+	if (argc == 3) {
+		req("%s %s %s %s", cmd, argv[0], argv[1], argv[2]);
+		ok();
+		return;
+	}
+
+	if (argc == 2)
+		req("%s %s %s", cmd, argv[0], argv[1]);
+	else
+		req("%s %s", cmd, argv[0]);
+
+	if (sscanf(line = ok(), "%zu", &num) != 1)
+		errx(1, "could not retrieve list");
+
+	if (argc == 2)
+		puts(poll());
+	else {
+		while (num-- != 0 && (line = poll())) {
+			if (!(p = strchr(line, '=')))
+				continue;
+
+			*p = '\0';
+			printf("%-16s: %s\n", line, p + 1);
+		}
+	}
+}
+
+static void
+response_list(const char *cmd)
+{
+	char *list;
+
+	req(cmd);
+
+	if (strncmp(list = poll(), "OK ", 3) != 0)
+		errx(1, "failed to retrieve plugin list");
+
+	list += 3;
+
+	for (char *p; (p = strchr(list, ' ')); )
+		*p = '\n';
+
+	if (*list)
+		puts(list);
+}
+
+static void
+cmd_hook_add(int argc, char **argv)
+{
+	(void)argc;
+
+	req("HOOK-ADD %s %s", argv[0], argv[1]);
+	ok();
+}
+
+static void
+cmd_hook_list(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	response_list("HOOK-LIST");
+}
+
+static void
+cmd_hook_remove(int argc, char **argv)
+{
+	(void)argc;
+
+	req("HOOK-REMOVE %s", argv[0]);
+	ok();
+}
+
+static void
+cmd_plugin_config(int argc, char **argv)
+{
+	return plugin_list_set(argc, argv, "PLUGIN-CONFIG");
+}
+
+/*
+ * Response:
+ *
+ *     OK name
+ *     summary
+ *     version
+ *     license
+ *     author
+ */
+static void
+cmd_plugin_info(int argc, char **argv)
+{
+	(void)argc;
+
+	const char *response;
+
+	req("PLUGIN-INFO %s", argv[0]);
+
+	if (strncmp((response = poll()), "OK ", 3) != 0)
+		errx(1, "failed to retrieve plugin information");
+
+	printf("%-16s: %s\n", "name", response + 3);
+	printf("%-16s: %s\n", "summary", poll());
+	printf("%-16s: %s\n", "version", poll());
+	printf("%-16s: %s\n", "license", poll());
+	printf("%-16s: %s\n", "author", poll());
+}
+
+static void
+cmd_plugin_list(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	response_list("PLUGIN-LIST");
+}
+
+static void
+cmd_plugin_load(int argc, char **argv)
+{
+	(void)argc;
+
+	req("PLUGIN-LOAD %s", argv[0]);
+	ok();
+}
+
+static void
+cmd_plugin_path(int argc, char **argv)
+{
+	return plugin_list_set(argc, argv, "PLUGIN-PATH");
+}
+
+static void
+cmd_plugin_reload(int argc, char **argv)
+{
+	if (argc == 1)
+		req("PLUGIN-RELOAD %s", argv[0]);
+	else
+		req("PLUGIN-RELOAD");
+
+	ok();
+}
+
+static void
+cmd_plugin_template(int argc, char **argv)
+{
+	return plugin_list_set(argc, argv, "PLUGIN-TEMPLATE");
+}
+
+static void
+cmd_plugin_unload(int argc, char **argv)
+{
+	if (argc == 1)
+		req("PLUGIN-UNLOAD %s", argv[0]);
+	else
+		req("PLUGIN-UNLOAD");
+
+	ok();
+}
+
+static void
+cmd_rule_add(int argc, char **argv)
+{
+	ketopt_t ko = KETOPT_INIT;
+	FILE *fp;
+	char out[IRC_BUF_LEN];
+
+	if (!(fp = fmemopen(out, sizeof (out) - 1, "w")))
+		err(1, "fmemopen");
+
+	/* TODO: invalid option. */
+	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "c:e:i:o:p:s:", NULL)) != -1; )
+		fprintf(fp, "%c=%s ", ch, ko.arg);
+
+	argc -= ko.ind;
+	argv += ko.ind;
+
+	if (argc < 1)
+		errx(1, "missing accept or drop rule action");
+
+	fprintf(fp, "%s", argv[0]);
+
+	if (ferror(fp) || feof(fp))
+		err(1, "fprintf");
+
+	fclose(fp);
+	req("RULE-ADD %s %s", argv[0], out);
+	ok();
+}
+
+static void
+cmd_rule_edit(int argc, char **argv)
+{
+	ketopt_t ko = KETOPT_INIT;
+	FILE *fp;
+	char out[IRC_BUF_LEN];
+
+	if (!(fp = fmemopen(out, sizeof (out) - 1, "w")))
+		err(1, "fmemopen");
+
+	/* TODO: invalid option. */
+	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "a:C:c:E:e:O:o:P:p:S:s:", NULL)) != -1; ) {
+		if (ch == 'a')
+			fprintf(fp, "a=%s ", ko.arg);
+		else
+			fprintf(fp, "%c%c%s ", tolower(ch), isupper(ch) ? '-' : '+', ko.arg);
+	}
+
+	argc -= ko.ind;
+	argv += ko.ind;
+
+	if (argc < 1)
+		errx(1, "missing rule index");
+
+	if (ferror(fp) || feof(fp))
+		err(1, "fprintf");
+
+	fclose(fp);
+	req("RULE-EDIT %s %s", argv[0], out);
+	ok();
+}
+
+/*
+ * Response:
+ *
+ *     OK <n>
+ *     accept
+ *     server1 server2 server3 ...
+ *     channel1 channel2 channel3 ...
+ *     origin1 origin2 origin3 ...
+ *     plugin1 plugin2 plugin3 ...
+ *     event1 event2 plugin3 ...
+ *     (repeat for every rule in <n>)
+ */
+static void
+cmd_rule_list(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	size_t num = 0;
+
+	req("RULE-LIST");
+
+	if (sscanf(ok(), "%zu", &num) != 1)
+		errx(1, "could not retrieve rule list");
+
+	for (size_t i = 0; i < num; ++i) {
+		printf("%-16s: %zu\n", "index", i);
+		printf("%-16s: %s\n", "action", poll());
+		printf("%-16s: %s\n", "servers", poll());
+		printf("%-16s: %s\n", "channels", poll());
+		printf("%-16s: %s\n", "origins", poll());
+		printf("%-16s: %s\n", "plugins", poll());
+		printf("%-16s: %s\n", "events", poll());
+		printf("\n");
+	}
+}
+
+static void
+cmd_rule_move(int argc, char **argv)
+{
+	(void)argc;
+
+	long long from, to;
+	const char *errstr;
+
+	if ((from = strtonum(argv[0], 0, LLONG_MAX, &errstr)) == 0 && errstr)
+		err(1, "%s", argv[0]);
+	if ((to = strtonum(argv[1], 0, LLONG_MAX, &errstr)) == 0 && errstr)
+		err(1, "%s", argv[1]);
+
+	req("RULE-MOVE %lld %lld", from, to);
+	ok();
+}
+
+static void
+cmd_rule_remove(int argc, char **argv)
+{
+	(void)argc;
+
+	req("RULE-REMOVE %s", argv[0]);
+	ok();
+}
+
+static void
+cmd_server_connect(int argc, char **argv)
+{
+	ketopt_t ko = KETOPT_INIT;
+	int ssl = 0;
+	const char *nickname = "irccd",
+	           *username = "irccd",
+	           *realname = "IRC Client Daemon",
+	           *port = "6667";
+
+	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "sn:r:u:p:", NULL)) != -1; ) {
+		switch (ch) {
+		case 's':
+			ssl = 1;
+			break;
+		case 'n':
+			nickname = ko.arg;
+			break;
+		case 'r':
+			realname = ko.arg;
+			break;
+		case 'u':
+			username = ko.arg;
+			break;
+		case 'p':
+			port = ko.arg;
+			break;
+		default:
+			break;
+		}
+	}
+
+	argc -= ko.ind;
+	argv += ko.ind;
+
+	if (argc < 2)
+		errx(1, "missing id and/or host");
+
+	req("SERVER-CONNECT %s %s %s%s %s %s %s", argv[0], argv[1], (ssl ? "+" : ""),
+	    port, nickname, username, realname);
+	ok();
+}
+
+static void
+cmd_server_disconnect(int argc, char **argv)
+{
+	if (argc == 1)
+		req("SERVER-DISCONNECT %s", argv[0]);
+	else
+		req("SERVER-DISCONNECT");
+
+	ok();
+}
+
+/*
+ * Response:
+ *
+ *     OK name
+ *     hostname port [ssl]
+ *     nickname username realname
+ *     chan1 chan2 chanN
+ */
+static void
+cmd_server_info(int argc, char **argv)
+{
+	(void)argc;
+
+	char *list;
+	const char *args[16] = {0};
+
+	req("SERVER-INFO %s", argv[0]);
+
+	if (strncmp(list = poll(), "OK ", 3) != 0)
+		errx(1, "failed to retrieve server information");
+
+	printf("%-16s: %s\n", "name", list + 3);
+
+	if (irc_util_split((list = poll()), args, 3, ' ') < 2)
+		errx(1, "malformed server connection");
+
+	printf("%-16s: %s\n", "hostname", args[0]);
+	printf("%-16s: %s\n", "port", args[1]);
+
+	if (args[2])
+		printf("%-16s: %s\n", "ssl", "true");
+
+	if (irc_util_split((list = poll()), args, 3, ' ') != 3)
+		errx(1, "malformed server ident");
+
+	printf("%-16s: %s\n", "nickname", args[0]);
+	printf("%-16s: %s\n", "username", args[0]);
+	printf("%-16s: %s\n", "realname", args[0]);
+	printf("%-16s: %s\n", "channels", poll());
+}
+
+static void
+cmd_server_join(int argc, char **argv)
+{
+	if (argc >= 3)
+		req("SERVER-JOIN %s %s %s", argv[0], argv[1], argv[2]);
+	else
+		req("SERVER-JOIN %s %s", argv[0], argv[1]);
+
+	ok();
+}
+
+static void
+cmd_server_list(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	response_list("SERVER-LIST");
+}
+
+static void
+cmd_server_message(int argc, char **argv)
+{
+	(void)argc;
+
+	req("SERVER-MESSAGE %s %s %s", argv[0], argv[1], argv[2]);
+	ok();
+}
+
+static void
+cmd_server_me(int argc, char **argv)
+{
+	(void)argc;
+
+	req("SERVER-ME %s %s %s", argv[0], argv[1], argv[2]);
+	ok();
+}
+
+static void
+cmd_server_mode(int argc, char **argv)
+{
+	req("SERVER-MODE %s %s %s%c%s", argv[0], argv[1], argv[2],
+	    argc >= 4 ? ' '     : '\0',
+	    argc >= 4 ? argv[3] : "");
+	ok();
+}
+
+static void
+cmd_server_nick(int argc, char **argv)
+{
+	(void)argc;
+
+	req("SERVER-NICK %s %s", argv[0], argv[1]);
+	ok();
+}
+
+static void
+cmd_server_notice(int argc, char **argv)
+{
+	(void)argc;
+
+	req("SERVER-NOTICE %s %s %s", argv[0], argv[1], argv[2]);
+	ok();
+}
+
+static void
+cmd_server_part(int argc, char **argv)
+{
+	(void)argc;
+
+	/* Let's advertise irccd a bit. */
+	req("SERVER-PART %s %s %s", argv[0], argv[1],
+	    argc >= 3 ? argv[2] : "irccd is shutting down");
+	ok();
+}
+
+static void
+cmd_server_topic(int argc, char **argv)
+{
+	(void)argc;
+
+	req("SERVER-TOPIC %s %s %s", argv[0], argv[1], argv[2]);
+	ok();
+}
+
+static void
+cmd_watch(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	struct timeval tv = {0};
+	char *ev;
+
+	/* Enable watch. */
+	req("WATCH");
+	ok();
+
+	/* Turn off timeout to receive indefinitely. */
+	if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)) < 0)
+		err(1, "setsockopt");
+
+	while ((ev = poll()))
+		show(ev);
+}
+
+static const struct cmd {
+	const char *name;
+	int minargs;
+	int maxargs;
+	void (*exec)(int, char **);
+} cmds[] = {
+	/* name                 min     max     exec                   */
+	{ "hook-add",           2,      2,      cmd_hook_add            },
+	{ "hook-list",          0,      0,      cmd_hook_list           },
+	{ "hook-remove",        1,      1,      cmd_hook_remove         },
+	{ "plugin-config",      1,      3,      cmd_plugin_config       },
+	{ "plugin-info",        1,      1,      cmd_plugin_info         },
+	{ "plugin-list",        0,      0,      cmd_plugin_list         },
+	{ "plugin-load",        1,      1,      cmd_plugin_load         },
+	{ "plugin-path",        0,      3,      cmd_plugin_path         },
+	{ "plugin-reload",      0,      1,      cmd_plugin_reload       },
+	{ "plugin-template",    1,      3,      cmd_plugin_template     },
+	{ "plugin-unload",      0,      1,      cmd_plugin_unload       },
+	{ "rule-add",          -1,     -1,      cmd_rule_add            },
+	{ "rule-edit",         -1,     -1,      cmd_rule_edit           },
+	{ "rule-list",          0,      0,      cmd_rule_list           },
+	{ "rule-move",          2,      2,      cmd_rule_move           },
+	{ "rule-remove",        1,      1,      cmd_rule_remove         },
+	{ "server-connect",    -1,     -1,      cmd_server_connect      },
+	{ "server-disconnect",  0,      1,      cmd_server_disconnect   },
+	{ "server-info",        1,      1,      cmd_server_info         },
+	{ "server-join",        2,      3,      cmd_server_join         },
+	{ "server-list",        0,      0,      cmd_server_list         },
+	{ "server-me",          3,      3,      cmd_server_me           },
+	{ "server-message",     3,      3,      cmd_server_message      },
+	{ "server-mode",        3,      4,      cmd_server_mode         },
+	{ "server-nick",        2,      2,      cmd_server_nick         },
+	{ "server-notice",      3,      3,      cmd_server_notice       },
+	{ "server-part",        3,      3,      cmd_server_part         },
+	{ "server-topic",       3,      3,      cmd_server_topic        },
+	{ "watch",              0,      0,      cmd_watch               }
+};
+
+static int
+cmp_cmd(const void *d1, const void *d2)
+{
+	return strcmp(d1, ((const struct cmd *)d2)->name);
+}
+
+static const struct cmd *
+find_cmd(const char *name)
+{
+	return bsearch(name, cmds, IRC_UTIL_SIZE(cmds), sizeof (cmds[0]), cmp_cmd);
+}
+
+static void
+run(int argc, char **argv)
+{
+	const struct cmd *c;
+
+	if (!(c = find_cmd(argv[0])))
+		errx(1, "abort: command not found");
+
+	--argc;
+	++argv;
+
+	if ((c->minargs != -1 && argc < c->minargs) || (c->minargs != -1 && argc > c->maxargs))
+		errx(1, "abort: invalid number of arguments");
+
+	c->exec(argc, argv);
+}
+
+noreturn static void
+usage(void)
+{
+	fprintf(stderr, "usage: %s [-v] [-s sock] command [options...] [arguments...]\n", getprogname());
+	exit(1);
+}
+
+noreturn static void
+help(void)
+{
+	fprintf(stderr, "usage: %s hook-add name path\n", getprogname());
+	fprintf(stderr, "       %s hook-list\n", getprogname());
+	fprintf(stderr, "       %s hook-remove id\n", getprogname());
+	fprintf(stderr, "       %s plugin-config id [variable [value]]\n", getprogname());
+	fprintf(stderr, "       %s plugin-info id\n", getprogname());
+	fprintf(stderr, "       %s plugin-list\n", getprogname());
+	fprintf(stderr, "       %s plugin-load name\n", getprogname());
+	fprintf(stderr, "       %s plugin-path [variable [value]]\n", getprogname());
+	fprintf(stderr, "       %s plugin-template [variable [value]]\n", getprogname());
+	fprintf(stderr, "       %s plugin-reload [plugin]\n", getprogname());
+	fprintf(stderr, "       %s plugin-unload [plugin]\n", getprogname());
+	fprintf(stderr, "       %s rule-add [-c channel] [-e event] [-i index] [-o origin] [-p plugin] [-s server] accept|drop\n", getprogname());
+	fprintf(stderr, "       %s rule-edit [-a accept|drop] [-c|C channel] [-e|E event] [-o|O origin] [-s|S server] index\n", getprogname());
+	fprintf(stderr, "       %s rule-list\n", getprogname());
+	fprintf(stderr, "       %s rule-move from to\n", getprogname());
+	fprintf(stderr, "       %s rule-remove index\n", getprogname());
+	fprintf(stderr, "       %s server-connect [-n nickname] [-r realname] [-u username] [-p port] id hostname\n", getprogname());
+	fprintf(stderr, "       %s server-disconnect [server]\n", getprogname());
+	fprintf(stderr, "       %s server-info server\n", getprogname());
+	fprintf(stderr, "       %s server-invite server target channel\n", getprogname());
+	fprintf(stderr, "       %s server-join server channel [password]\n", getprogname());
+	fprintf(stderr, "       %s server-kick server target channel [reason]\n", getprogname());
+	fprintf(stderr, "       %s server-list\n", getprogname());
+	fprintf(stderr, "       %s server-me server target message\n", getprogname());
+	fprintf(stderr, "       %s server-message server target message\n", getprogname());
+	fprintf(stderr, "       %s server-mode server target mode [args]\n", getprogname());
+	fprintf(stderr, "       %s server-nick server nickname\n", getprogname());
+	fprintf(stderr, "       %s server-notice server target message\n", getprogname());
+	fprintf(stderr, "       %s server-part server channel [reason]\n", getprogname());
+	fprintf(stderr, "       %s server-reconnect [server]\n", getprogname());
+	fprintf(stderr, "       %s server-topic server channel topic\n", getprogname());
+	fprintf(stderr, "       %s watch\n", getprogname());
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	ketopt_t ko = KETOPT_INIT;
+
+	setprogname("irccdctl");
+
+	--argc;
+	++argv;
+
+	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "s:v", NULL)) != -1; ) {
+		switch (ch) {
+		case 's':
+			strlcpy(sockaddr.sun_path, ko.arg, sizeof (sockaddr.sun_path));
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		default:
+			usage();
+			break;
+		}
+	}
+
+	argc -= ko.ind;
+	argv += ko.ind;
+
+	if (argc < 1)
+		usage();
+	else if (strcmp(argv[0], "help") == 0)
+		help();
+
+	dial();
+	check();
+	run(argc, argv);
+}
--- a/irccdctl/main.c	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,997 +0,0 @@
-/*
- * main.c -- irccdctl(1) main file
- *
- * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <compat.h>
-
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/un.h>
-#include <assert.h>
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdnoreturn.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <ketopt.h>
-
-#include <irccd/limits.h>
-#include <irccd/util.h>
-
-static int verbose;
-static int sock;
-static struct sockaddr_un sockaddr = {
-	.sun_family = PF_LOCAL,
-	.sun_path = "/tmp/irccd.sock"
-};
-static char in[IRC_BUF_LEN];
-static char out[IRC_BUF_LEN];
-
-static char *
-poll(void)
-{
-	static char ret[IRC_BUF_LEN];
-	char *nl;
-
-	while (!(nl = strstr(in, "\n"))) {
-		char buf[IRC_BUF_LEN] = {0};
-		ssize_t nr;
-
-		if ((nr = recv(sock, buf, sizeof (buf) - 1, 0)) <= 0)
-			errc(1, nr == 0 ? ECONNRESET : errno, "abort");
-		if (strlcat(in, buf, sizeof (in)) >= sizeof (in))
-			errc(1, EMSGSIZE, "abort");
-	}
-
-	*nl = '\0';
-	strlcpy(ret, in, sizeof (ret));
-	memmove(in, nl + 1, sizeof (in) - (nl - in) - 1);
-
-	return ret;
-}
-
-static void
-dial(void)
-{
-	const struct timeval tv = {
-		.tv_sec = 30
-	};
-
-	if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
-		err(1, "socket");
-	if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (tv)) < 0 ||
-	    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)) < 0)
-		err(1, "setsockopt");
-	if (connect(sock, (const struct sockaddr *)&sockaddr, SUN_LEN(&sockaddr)) < 0)
-		err(1, "connect");
-}
-
-static void
-check(void)
-{
-	/* Ensure we're talking to irccd. */
-	int major, minor, patch;
-
-	if ((sscanf(poll(), "IRCCD %d.%d.%d", &major, &minor, &patch) != 3))
-		errx(1, "abort: not irccd instance");
-	if (verbose)
-		printf("connected to irccd %d.%d.%d\n", major, minor, patch);
-}
-
-static void
-req(const char *fmt, ...)
-{
-	char buf[IRC_BUF_LEN];
-	va_list ap;
-
-	va_start(ap, fmt);
-	vsnprintf(buf, sizeof (buf), fmt, ap);
-	va_end(ap);
-
-	if (strlcat(out, buf, sizeof (out)) >= sizeof (out) ||
-	    strlcat(out, "\n", sizeof (out)) >= sizeof (out))
-		errc(1, EMSGSIZE, "abort");
-
-	while (out[0]) {
-		ssize_t ns, len;
-
-		len = strlen(out);
-
-		if ((ns = send(sock, out, len, MSG_NOSIGNAL)) <= 0)
-			err(1, "send");
-
-		if (ns >= len)
-			memset(out, 0, sizeof (out));
-		else
-			memmove(out, out + ns, sizeof (out) - ns);
-	}
-}
-
-static char *
-ok(void)
-{
-	char *response = poll();
-
-	if (strncmp(response, "OK", 2) != 0)
-		errx(1, "abort: %s", response);
-
-	/* Skip "OK". */
-	response += 2;
-
-	while (*response && isspace(*response))
-		response++;
-
-	return response;
-}
-
-static void
-show_connect(char *line)
-{
-	const char *args[2] = {0};
-
-	if (irc_util_split(line, args, 2, ' ') == 2) {
-		printf("%-16s: %s\n", "event", "onConnect");
-		printf("%-16s: %s\n", "server", args[0]);
-	}
-}
-
-static void
-show_disconnect(char *line)
-{
-	const char *args[2] = {0};
-
-	if (irc_util_split(line, args, 2, ' ') == 2) {
-		printf("%-16s: %s\n", "event", "onDisonnect");
-		printf("%-16s: %s\n", "server", args[0]);
-	}
-}
-
-static void
-show_invite(char *line)
-{
-	const char *args[5] = {0};
-
-	if (irc_util_split(line, args, 5, ' ') == 5) {
-		printf("%-16s: %s\n", "event", "onInvite");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "nickname", args[4]);
-	}
-}
-
-static void
-show_join(char *line)
-{
-	const char *args[4] = {0};
-
-	if (irc_util_split(line, args, 4, ' ') == 4) {
-		printf("%-16s: %s\n", "event", "onJoin");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-	}
-}
-
-static void
-show_kick(char *line)
-{
-	const char *args[6] = {0};
-
-	if (irc_util_split(line, args, 6, ' ') >= 5) {
-		printf("%-16s: %s\n", "event", "onKick");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "target", args[4]);
-		printf("%-16s: %s\n", "reason", args[5] ? args[5] : "");
-	}
-}
-
-static void
-show_me(char *line)
-{
-	const char *args[5] = {0};
-
-	if (irc_util_split(line, args, 5, ' ') == 5) {
-		printf("%-16s: %s\n", "event", "onMe");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "message", args[4]);
-	}
-}
-
-static void
-show_message(char *line)
-{
-	const char *args[5] = {0};
-
-	if (irc_util_split(line, args, 5, ' ') == 5) {
-		printf("%-16s: %s\n", "event", "onMessage");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "message", args[4]);
-	}
-}
-
-static void
-show_mode(char *line)
-{
-	const char *args[8] = {0};
-
-	if (irc_util_split(line, args, 8, ' ') >= 5) {
-		printf("%-16s: %s\n", "event", "onMode");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "mode", args[4]);
-		printf("%-16s: %s\n", "limit", (args[5] ? args[5] : ""));
-		printf("%-16s: %s\n", "user", (args[6] ? args[6] : ""));
-		printf("%-16s: %s\n", "mask", (args[7] ? args[7] : ""));
-	}
-}
-
-static void
-show_nick(char *line)
-{
-	const char *args[4] = {0};
-
-	if (irc_util_split(line, args, 4, ' ') == 4) {
-		printf("%-16s: %s\n", "event", "onNick");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "nickname", args[3]);
-	}
-}
-
-static void
-show_notice(char *line)
-{
-	const char *args[5] = {0};
-
-	if (irc_util_split(line, args, 5, ' ') == 5) {
-		printf("%-16s: %s\n", "event", "onNotice");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "message", args[4]);
-	}
-}
-
-static void
-show_part(char *line)
-{
-	const char *args[5] = {0};
-
-	if (irc_util_split(line, args, 5, ' ') >= 4) {
-		printf("%-16s: %s\n", "event", "onPart");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "reason", (args[4] ? args[4] : ""));
-	}
-}
-
-static void
-show_topic(char *line)
-{
-	const char *args[5] = {0};
-
-	if (irc_util_split(line, args, 5, ' ') >= 4) {
-		printf("%-16s: %s\n", "event", "onTopic");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "origin", args[2]);
-		printf("%-16s: %s\n", "channel", args[3]);
-		printf("%-16s: %s\n", "topic", args[4]);
-	}
-}
-
-static void
-show_whois(char *line)
-{
-	const char *args[6] = {0};
-	//char *p, *token;
-
-	if (irc_util_split(line, args, 6, ' ') >= 4) {
-		printf("%-16s: %s\n", "event", "onWhois");
-		printf("%-16s: %s\n", "server", args[1]);
-		printf("%-16s: %s\n", "nickname", args[2]);
-		printf("%-16s: %s\n", "username", args[3]);
-		printf("%-16s: %s\n", "hostname", args[4]);
-		printf("%-16s: %s\n", "username", args[5]);
-		//printf("channels:  %s\n", args[6]);
-	}
-}
-
-static const struct {
-	const char *event;
-	void (*show)(char *);
-} watchtable[] = {
-	{ "EVENT-CONNECT",      show_connect    },
-	{ "EVENT-DISCONNECT",   show_disconnect },
-	{ "EVENT-INVITE",       show_invite     },
-	{ "EVENT-JOIN",         show_join       },
-	{ "EVENT-KICK",         show_kick       },
-	{ "EVENT-MESSAGE",      show_message    },
-	{ "EVENT-ME",           show_me         },
-	{ "EVENT-MODE",         show_mode       },
-	{ "EVENT-NICK",         show_nick       },
-	{ "EVENT-NOTICE",       show_notice     },
-	{ "EVENT-PART",         show_part       },
-	{ "EVENT-TOPIC",        show_topic      },
-	{ "EVENT-WHOIS",        show_whois      }
-};
-
-static void
-show(char *ev)
-{
-	for (size_t i = 0; i < IRC_UTIL_SIZE(watchtable); ++i) {
-		if (strncmp(watchtable[i].event, ev, strlen(watchtable[i].event)) == 0) {
-			watchtable[i].show(ev);
-			printf("\n");
-			break;
-		}
-	}
-}
-
-static void
-plugin_list_set(int argc, char **argv, const char *cmd)
-{
-	char *line, *p;
-	size_t num = 0;
-
-	if (argc == 3) {
-		req("%s %s %s %s", cmd, argv[0], argv[1], argv[2]);
-		ok();
-		return;
-	}
-
-	if (argc == 2)
-		req("%s %s %s", cmd, argv[0], argv[1]);
-	else
-		req("%s %s", cmd, argv[0]);
-
-	if (sscanf(line = ok(), "%zu", &num) != 1)
-		errx(1, "could not retrieve list");
-
-	if (argc == 2)
-		puts(poll());
-	else {
-		while (num-- != 0 && (line = poll())) {
-			if (!(p = strchr(line, '=')))
-				continue;
-
-			*p = '\0';
-			printf("%-16s: %s\n", line, p + 1);
-		}
-	}
-}
-
-static void
-response_list(const char *cmd)
-{
-	char *list;
-
-	req(cmd);
-
-	if (strncmp(list = poll(), "OK ", 3) != 0)
-		errx(1, "failed to retrieve plugin list");
-
-	list += 3;
-
-	for (char *p; (p = strchr(list, ' ')); )
-		*p = '\n';
-
-	if (*list)
-		puts(list);
-}
-
-static void
-cmd_hook_add(int argc, char **argv)
-{
-	(void)argc;
-
-	req("HOOK-ADD %s %s", argv[0], argv[1]);
-	ok();
-}
-
-static void
-cmd_hook_list(int argc, char **argv)
-{
-	(void)argc;
-	(void)argv;
-
-	response_list("HOOK-LIST");
-}
-
-static void
-cmd_hook_remove(int argc, char **argv)
-{
-	(void)argc;
-
-	req("HOOK-REMOVE %s", argv[0]);
-	ok();
-}
-
-static void
-cmd_plugin_config(int argc, char **argv)
-{
-	return plugin_list_set(argc, argv, "PLUGIN-CONFIG");
-}
-
-/*
- * Response:
- *
- *     OK name
- *     summary
- *     version
- *     license
- *     author
- */
-static void
-cmd_plugin_info(int argc, char **argv)
-{
-	(void)argc;
-
-	const char *response;
-
-	req("PLUGIN-INFO %s", argv[0]);
-
-	if (strncmp((response = poll()), "OK ", 3) != 0)
-		errx(1, "failed to retrieve plugin information");
-
-	printf("%-16s: %s\n", "name", response + 3);
-	printf("%-16s: %s\n", "summary", poll());
-	printf("%-16s: %s\n", "version", poll());
-	printf("%-16s: %s\n", "license", poll());
-	printf("%-16s: %s\n", "author", poll());
-}
-
-static void
-cmd_plugin_list(int argc, char **argv)
-{
-	(void)argc;
-	(void)argv;
-
-	response_list("PLUGIN-LIST");
-}
-
-static void
-cmd_plugin_load(int argc, char **argv)
-{
-	(void)argc;
-
-	req("PLUGIN-LOAD %s", argv[0]);
-	ok();
-}
-
-static void
-cmd_plugin_path(int argc, char **argv)
-{
-	return plugin_list_set(argc, argv, "PLUGIN-PATH");
-}
-
-static void
-cmd_plugin_reload(int argc, char **argv)
-{
-	if (argc == 1)
-		req("PLUGIN-RELOAD %s", argv[0]);
-	else
-		req("PLUGIN-RELOAD");
-
-	ok();
-}
-
-static void
-cmd_plugin_template(int argc, char **argv)
-{
-	return plugin_list_set(argc, argv, "PLUGIN-TEMPLATE");
-}
-
-static void
-cmd_plugin_unload(int argc, char **argv)
-{
-	if (argc == 1)
-		req("PLUGIN-UNLOAD %s", argv[0]);
-	else
-		req("PLUGIN-UNLOAD");
-
-	ok();
-}
-
-static void
-cmd_rule_add(int argc, char **argv)
-{
-	ketopt_t ko = KETOPT_INIT;
-	FILE *fp;
-	char out[IRC_BUF_LEN];
-
-	if (!(fp = fmemopen(out, sizeof (out) - 1, "w")))
-		err(1, "fmemopen");
-
-	/* TODO: invalid option. */
-	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "c:e:i:o:p:s:", NULL)) != -1; )
-		fprintf(fp, "%c=%s ", ch, ko.arg);
-
-	argc -= ko.ind;
-	argv += ko.ind;
-
-	if (argc < 1)
-		errx(1, "missing accept or drop rule action");
-
-	fprintf(fp, "%s", argv[0]);
-
-	if (ferror(fp) || feof(fp))
-		err(1, "fprintf");
-
-	fclose(fp);
-	req("RULE-ADD %s %s", argv[0], out);
-	ok();
-}
-
-static void
-cmd_rule_edit(int argc, char **argv)
-{
-	ketopt_t ko = KETOPT_INIT;
-	FILE *fp;
-	char out[IRC_BUF_LEN];
-
-	if (!(fp = fmemopen(out, sizeof (out) - 1, "w")))
-		err(1, "fmemopen");
-
-	/* TODO: invalid option. */
-	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "a:C:c:E:e:O:o:P:p:S:s:", NULL)) != -1; ) {
-		if (ch == 'a')
-			fprintf(fp, "a=%s ", ko.arg);
-		else
-			fprintf(fp, "%c%c%s ", tolower(ch), isupper(ch) ? '-' : '+', ko.arg);
-	}
-
-	argc -= ko.ind;
-	argv += ko.ind;
-
-	if (argc < 1)
-		errx(1, "missing rule index");
-
-	if (ferror(fp) || feof(fp))
-		err(1, "fprintf");
-
-	fclose(fp);
-	req("RULE-EDIT %s %s", argv[0], out);
-	ok();
-}
-
-/*
- * Response:
- *
- *     OK <n>
- *     accept
- *     server1 server2 server3 ...
- *     channel1 channel2 channel3 ...
- *     origin1 origin2 origin3 ...
- *     plugin1 plugin2 plugin3 ...
- *     event1 event2 plugin3 ...
- *     (repeat for every rule in <n>)
- */
-static void
-cmd_rule_list(int argc, char **argv)
-{
-	(void)argc;
-	(void)argv;
-
-	size_t num = 0;
-
-	req("RULE-LIST");
-
-	if (sscanf(ok(), "%zu", &num) != 1)
-		errx(1, "could not retrieve rule list");
-
-	for (size_t i = 0; i < num; ++i) {
-		printf("%-16s: %zu\n", "index", i);
-		printf("%-16s: %s\n", "action", poll());
-		printf("%-16s: %s\n", "servers", poll());
-		printf("%-16s: %s\n", "channels", poll());
-		printf("%-16s: %s\n", "origins", poll());
-		printf("%-16s: %s\n", "plugins", poll());
-		printf("%-16s: %s\n", "events", poll());
-		printf("\n");
-	}
-}
-
-static void
-cmd_rule_move(int argc, char **argv)
-{
-	(void)argc;
-
-	long long from, to;
-	const char *errstr;
-
-	if ((from = strtonum(argv[0], 0, LLONG_MAX, &errstr)) == 0 && errstr)
-		err(1, "%s", argv[0]);
-	if ((to = strtonum(argv[1], 0, LLONG_MAX, &errstr)) == 0 && errstr)
-		err(1, "%s", argv[1]);
-
-	req("RULE-MOVE %lld %lld", from, to);
-	ok();
-}
-
-static void
-cmd_rule_remove(int argc, char **argv)
-{
-	(void)argc;
-
-	req("RULE-REMOVE %s", argv[0]);
-	ok();
-}
-
-static void
-cmd_server_connect(int argc, char **argv)
-{
-	ketopt_t ko = KETOPT_INIT;
-	int ssl = 0;
-	const char *nickname = "irccd",
-	           *username = "irccd",
-	           *realname = "IRC Client Daemon",
-	           *port = "6667";
-
-	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "sn:r:u:p:", NULL)) != -1; ) {
-		switch (ch) {
-		case 's':
-			ssl = 1;
-			break;
-		case 'n':
-			nickname = ko.arg;
-			break;
-		case 'r':
-			realname = ko.arg;
-			break;
-		case 'u':
-			username = ko.arg;
-			break;
-		case 'p':
-			port = ko.arg;
-			break;
-		default:
-			break;
-		}
-	}
-
-	argc -= ko.ind;
-	argv += ko.ind;
-
-	if (argc < 2)
-		errx(1, "missing id and/or host");
-
-	req("SERVER-CONNECT %s %s %s%s %s %s %s", argv[0], argv[1], (ssl ? "+" : ""),
-	    port, nickname, username, realname);
-	ok();
-}
-
-static void
-cmd_server_disconnect(int argc, char **argv)
-{
-	if (argc == 1)
-		req("SERVER-DISCONNECT %s", argv[0]);
-	else
-		req("SERVER-DISCONNECT");
-
-	ok();
-}
-
-/*
- * Response:
- *
- *     OK name
- *     hostname port [ssl]
- *     nickname username realname
- *     chan1 chan2 chanN
- */
-static void
-cmd_server_info(int argc, char **argv)
-{
-	(void)argc;
-
-	char *list;
-	const char *args[16] = {0};
-
-	req("SERVER-INFO %s", argv[0]);
-
-	if (strncmp(list = poll(), "OK ", 3) != 0)
-		errx(1, "failed to retrieve server information");
-
-	printf("%-16s: %s\n", "name", list + 3);
-
-	if (irc_util_split((list = poll()), args, 3, ' ') < 2)
-		errx(1, "malformed server connection");
-
-	printf("%-16s: %s\n", "hostname", args[0]);
-	printf("%-16s: %s\n", "port", args[1]);
-
-	if (args[2])
-		printf("%-16s: %s\n", "ssl", "true");
-
-	if (irc_util_split((list = poll()), args, 3, ' ') != 3)
-		errx(1, "malformed server ident");
-
-	printf("%-16s: %s\n", "nickname", args[0]);
-	printf("%-16s: %s\n", "username", args[0]);
-	printf("%-16s: %s\n", "realname", args[0]);
-	printf("%-16s: %s\n", "channels", poll());
-}
-
-static void
-cmd_server_join(int argc, char **argv)
-{
-	if (argc >= 3)
-		req("SERVER-JOIN %s %s %s", argv[0], argv[1], argv[2]);
-	else
-		req("SERVER-JOIN %s %s", argv[0], argv[1]);
-
-	ok();
-}
-
-static void
-cmd_server_list(int argc, char **argv)
-{
-	(void)argc;
-	(void)argv;
-
-	response_list("SERVER-LIST");
-}
-
-static void
-cmd_server_message(int argc, char **argv)
-{
-	(void)argc;
-
-	req("SERVER-MESSAGE %s %s %s", argv[0], argv[1], argv[2]);
-	ok();
-}
-
-static void
-cmd_server_me(int argc, char **argv)
-{
-	(void)argc;
-
-	req("SERVER-ME %s %s %s", argv[0], argv[1], argv[2]);
-	ok();
-}
-
-static void
-cmd_server_mode(int argc, char **argv)
-{
-	req("SERVER-MODE %s %s %s%c%s", argv[0], argv[1], argv[2],
-	    argc >= 4 ? ' '     : '\0',
-	    argc >= 4 ? argv[3] : "");
-	ok();
-}
-
-static void
-cmd_server_nick(int argc, char **argv)
-{
-	(void)argc;
-
-	req("SERVER-NICK %s %s", argv[0], argv[1]);
-	ok();
-}
-
-static void
-cmd_server_notice(int argc, char **argv)
-{
-	(void)argc;
-
-	req("SERVER-NOTICE %s %s %s", argv[0], argv[1], argv[2]);
-	ok();
-}
-
-static void
-cmd_server_part(int argc, char **argv)
-{
-	(void)argc;
-
-	/* Let's advertise irccd a bit. */
-	req("SERVER-PART %s %s %s", argv[0], argv[1],
-	    argc >= 3 ? argv[2] : "irccd is shutting down");
-	ok();
-}
-
-static void
-cmd_server_topic(int argc, char **argv)
-{
-	(void)argc;
-
-	req("SERVER-TOPIC %s %s %s", argv[0], argv[1], argv[2]);
-	ok();
-}
-
-static void
-cmd_watch(int argc, char **argv)
-{
-	(void)argc;
-	(void)argv;
-
-	struct timeval tv = {0};
-	char *ev;
-
-	/* Enable watch. */
-	req("WATCH");
-	ok();
-
-	/* Turn off timeout to receive indefinitely. */
-	if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)) < 0)
-		err(1, "setsockopt");
-
-	while ((ev = poll()))
-		show(ev);
-}
-
-static const struct cmd {
-	const char *name;
-	int minargs;
-	int maxargs;
-	void (*exec)(int, char **);
-} cmds[] = {
-	/* name                 min     max     exec                   */
-	{ "hook-add",           2,      2,      cmd_hook_add            },
-	{ "hook-list",          0,      0,      cmd_hook_list           },
-	{ "hook-remove",        1,      1,      cmd_hook_remove         },
-	{ "plugin-config",      1,      3,      cmd_plugin_config       },
-	{ "plugin-info",        1,      1,      cmd_plugin_info         },
-	{ "plugin-list",        0,      0,      cmd_plugin_list         },
-	{ "plugin-load",        1,      1,      cmd_plugin_load         },
-	{ "plugin-path",        0,      3,      cmd_plugin_path         },
-	{ "plugin-reload",      0,      1,      cmd_plugin_reload       },
-	{ "plugin-template",    1,      3,      cmd_plugin_template     },
-	{ "plugin-unload",      0,      1,      cmd_plugin_unload       },
-	{ "rule-add",          -1,     -1,      cmd_rule_add            },
-	{ "rule-edit",         -1,     -1,      cmd_rule_edit           },
-	{ "rule-list",          0,      0,      cmd_rule_list           },
-	{ "rule-move",          2,      2,      cmd_rule_move           },
-	{ "rule-remove",        1,      1,      cmd_rule_remove         },
-	{ "server-connect",    -1,     -1,      cmd_server_connect      },
-	{ "server-disconnect",  0,      1,      cmd_server_disconnect   },
-	{ "server-info",        1,      1,      cmd_server_info         },
-	{ "server-join",        2,      3,      cmd_server_join         },
-	{ "server-list",        0,      0,      cmd_server_list         },
-	{ "server-me",          3,      3,      cmd_server_me           },
-	{ "server-message",     3,      3,      cmd_server_message      },
-	{ "server-mode",        3,      4,      cmd_server_mode         },
-	{ "server-nick",        2,      2,      cmd_server_nick         },
-	{ "server-notice",      3,      3,      cmd_server_notice       },
-	{ "server-part",        3,      3,      cmd_server_part         },
-	{ "server-topic",       3,      3,      cmd_server_topic        },
-	{ "watch",              0,      0,      cmd_watch               }
-};
-
-static int
-cmp_cmd(const void *d1, const void *d2)
-{
-	return strcmp(d1, ((const struct cmd *)d2)->name);
-}
-
-static const struct cmd *
-find_cmd(const char *name)
-{
-	return bsearch(name, cmds, IRC_UTIL_SIZE(cmds), sizeof (cmds[0]), cmp_cmd);
-}
-
-static void
-run(int argc, char **argv)
-{
-	const struct cmd *c;
-
-	if (!(c = find_cmd(argv[0])))
-		errx(1, "abort: command not found");
-
-	--argc;
-	++argv;
-
-	if ((c->minargs != -1 && argc < c->minargs) || (c->minargs != -1 && argc > c->maxargs))
-		errx(1, "abort: invalid number of arguments");
-
-	c->exec(argc, argv);
-}
-
-noreturn static void
-usage(void)
-{
-	fprintf(stderr, "usage: %s [-v] [-s sock] command [options...] [arguments...]\n", getprogname());
-	exit(1);
-}
-
-noreturn static void
-help(void)
-{
-	fprintf(stderr, "usage: %s hook-add name path\n", getprogname());
-	fprintf(stderr, "       %s hook-list\n", getprogname());
-	fprintf(stderr, "       %s hook-remove id\n", getprogname());
-	fprintf(stderr, "       %s plugin-config id [variable [value]]\n", getprogname());
-	fprintf(stderr, "       %s plugin-info id\n", getprogname());
-	fprintf(stderr, "       %s plugin-list\n", getprogname());
-	fprintf(stderr, "       %s plugin-load name\n", getprogname());
-	fprintf(stderr, "       %s plugin-path [variable [value]]\n", getprogname());
-	fprintf(stderr, "       %s plugin-template [variable [value]]\n", getprogname());
-	fprintf(stderr, "       %s plugin-reload [plugin]\n", getprogname());
-	fprintf(stderr, "       %s plugin-unload [plugin]\n", getprogname());
-	fprintf(stderr, "       %s rule-add [-c channel] [-e event] [-i index] [-o origin] [-p plugin] [-s server] accept|drop\n", getprogname());
-	fprintf(stderr, "       %s rule-edit [-a accept|drop] [-c|C channel] [-e|E event] [-o|O origin] [-s|S server] index\n", getprogname());
-	fprintf(stderr, "       %s rule-list\n", getprogname());
-	fprintf(stderr, "       %s rule-move from to\n", getprogname());
-	fprintf(stderr, "       %s rule-remove index\n", getprogname());
-	fprintf(stderr, "       %s server-connect [-n nickname] [-r realname] [-u username] [-p port] id hostname\n", getprogname());
-	fprintf(stderr, "       %s server-disconnect [server]\n", getprogname());
-	fprintf(stderr, "       %s server-info server\n", getprogname());
-	fprintf(stderr, "       %s server-invite server target channel\n", getprogname());
-	fprintf(stderr, "       %s server-join server channel [password]\n", getprogname());
-	fprintf(stderr, "       %s server-kick server target channel [reason]\n", getprogname());
-	fprintf(stderr, "       %s server-list\n", getprogname());
-	fprintf(stderr, "       %s server-me server target message\n", getprogname());
-	fprintf(stderr, "       %s server-message server target message\n", getprogname());
-	fprintf(stderr, "       %s server-mode server target mode [args]\n", getprogname());
-	fprintf(stderr, "       %s server-nick server nickname\n", getprogname());
-	fprintf(stderr, "       %s server-notice server target message\n", getprogname());
-	fprintf(stderr, "       %s server-part server channel [reason]\n", getprogname());
-	fprintf(stderr, "       %s server-reconnect [server]\n", getprogname());
-	fprintf(stderr, "       %s server-topic server channel topic\n", getprogname());
-	fprintf(stderr, "       %s watch\n", getprogname());
-	exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
-	ketopt_t ko = KETOPT_INIT;
-
-	setprogname("irccdctl");
-
-	--argc;
-	++argv;
-
-	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "s:v", NULL)) != -1; ) {
-		switch (ch) {
-		case 's':
-			strlcpy(sockaddr.sun_path, ko.arg, sizeof (sockaddr.sun_path));
-			break;
-		case 'v':
-			verbose = 1;
-			break;
-		default:
-			usage();
-			break;
-		}
-	}
-
-	argc -= ko.ind;
-	argv += ko.ind;
-
-	if (argc < 1)
-		usage();
-	else if (strcmp(argv[0], "help") == 0)
-		help();
-
-	dial();
-	check();
-	run(argc, argv);
-}
--- a/lib/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(libirccd)
-
-include(CMakePackageConfigHelpers)
-
-set(
-	HEADERS
-	irccd/channel.h
-	irccd/conn.h
-	irccd/event.h
-	irccd/hook.h
-	irccd/irccd.h
-	irccd/limits.h
-	irccd/log.h
-	irccd/plugin.h
-	irccd/rule.h
-	irccd/server.h
-	irccd/subst.h
-	irccd/util.h
-)
-
-set(
-	SOURCES
-	CMakeLists.txt
-	irccd/channel.c
-	irccd/config.h.in
-	irccd/conn.c
-	irccd/event.c
-	irccd/hook.c
-	irccd/irccd.c
-	irccd/log.c
-	irccd/plugin.c
-	irccd/rule.c
-	irccd/server.c
-	irccd/subst.c
-	irccd/util.c
-)
-
-configure_file(
-	${libirccd_SOURCE_DIR}/irccd/config.h.in
-	${libirccd_BINARY_DIR}/irccd/config.h
-)
-
-add_library(libirccd-static ${SOURCES} ${HEADERS})
-set_target_properties(libirccd-static PROPERTIES PREFIX "")
-
-# This is what we export to the world.
-add_library(libirccd INTERFACE)
-add_library(irccd::libirccd ALIAS libirccd)
-
-get_target_property(COMPAT_INCS libirccd-compat INCLUDE_DIRECTORIES)
-
-target_include_directories(libirccd INTERFACE
-	$<BUILD_INTERFACE:${libirccd-compat_BINARY_DIR}>
-	$<BUILD_INTERFACE:${libirccd_SOURCE_DIR}>
-	$<BUILD_INTERFACE:${libirccd_BINARY_DIR}>
-	$<BUILD_INTERFACE:${libirccd_BINARY_DIR}/irccd>
-	$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-	$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/irccd/extern>
-	${COMPAT_INCS}
-)
-
-target_include_directories(
-	libirccd-static
-	PUBLIC
-		$<BUILD_INTERFACE:${libirccd_BINARY_DIR}/irccd>
-		$<BUILD_INTERFACE:${libirccd_SOURCE_DIR}>
-		$<BUILD_INTERFACE:${libirccd_BINARY_DIR}>
-)
-target_link_libraries(libirccd-static libirccd-compat)
-
-if (IRCCD_WITH_SSL)
-	target_link_libraries(libirccd-static OpenSSL::SSL OpenSSL::Crypto)
-endif ()
-
-# pkg-config file
-if (APPLE)
-	set(EXTRA_LIBS "-undefined dynamic_lookup")
-endif ()
-
-configure_file(
-	${libirccd_SOURCE_DIR}/irccd.pc
-	${libirccd_BINARY_DIR}/irccd.pc
-)
-
-write_basic_package_version_file(${libirccd_BINARY_DIR}/IrccdConfigVersion.cmake
-	VERSION ${IRCCD_VERSION}
-	COMPATIBILITY SameMajorVersion
-)
-
-install(TARGETS libirccd EXPORT IrccdTargets)
-install(
-	EXPORT IrccdTargets
-	FILE IrccdTargets.cmake
-	NAMESPACE
-		irccd::
-	DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/irccd
-)
-install(
-	FILES
-		${CMAKE_SOURCE_DIR}/cmake/IrccdDefinePlugin.cmake
-		${libirccd_SOURCE_DIR}/IrccdConfig.cmake
-		${libirccd_BINARY_DIR}/IrccdConfigVersion.cmake
-	DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/irccd
-)
-
-install(
-	FILES
-		${HEADERS}
-		${libirccd_BINARY_DIR}/irccd/config.h
-	DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/irccd
-)
-
-install(
-	FILES ${libirccd_BINARY_DIR}/irccd.pc
-	DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
-)
-
-source_group(TREE ${libirccd_SOURCE_DIR} FILES ${SOURCES})
--- a/lib/IrccdConfig.cmake	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-include("${CMAKE_CURRENT_LIST_DIR}/IrccdTargets.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/IrccdDefinePlugin.cmake")
--- a/lib/irccd.pc	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-Name: irccd
-Description: Native C interface for irccd plugins
-Version: @IRCCD_VERSION@
-Cflags: -I@CMAKE_INSTALL_FULL_INCLUDEDIR@ -I@CMAKE_INSTALL_FULL_INCLUDEDIR@/irccd/extern
-Libs: @EXTRA_LIBS@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/irccd.pc.in	Tue Apr 27 09:22:16 2021 +0200
@@ -0,0 +1,5 @@
+Name: irccd
+Description: Native C interface for irccd plugins
+Version: @MAJOR@.@MINOR@.@PATCH@
+Cflags: -I@INCDIR@
+Libs: @SHFLAGS@
--- a/lib/irccd/channel.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/channel.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #include <string.h>
 
 #include "channel.h"
-#include "compat.h"
 #include "util.h"
 
 struct irc_channel *
--- a/lib/irccd/config.h.in	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/config.h.in	Tue Apr 27 09:22:16 2021 +0200
@@ -19,17 +19,17 @@
 #ifndef IRCCD_CONFIG_H
 #define IRCCD_CONFIG_H
 
-#define IRCCD_VERSION_MAJOR     @IRCCD_VERSION_MAJOR@
-#define IRCCD_VERSION_MINOR     @IRCCD_VERSION_MINOR@
-#define IRCCD_VERSION_PATCH     @IRCCD_VERSION_PATCH@
-#define IRCCD_VERSION           "@IRCCD_VERSION_MAJOR@.@IRCCD_VERSION_MINOR@.@IRCCD_VERSION_PATCH@"
+#define IRCCD_VERSION_MAJOR     @MAJOR@
+#define IRCCD_VERSION_MINOR     @MINOR@
+#define IRCCD_VERSION_PATCH     @PATCH@
+#define IRCCD_VERSION           "@MAJOR@.@MINOR@.@PATCH@"
 
-#define IRCCD_CACHEDIR          "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/cache/irccd"
-#define IRCCD_SYSCONFDIR        "@CMAKE_INSTALL_FULL_SYSCONFDIR@"
-#define IRCCD_LIBDIR            "@CMAKE_INSTALL_FULL_LIBDIR@"
-#define IRCCD_DATADIR           "@CMAKE_INSTALL_FULL_DATADIR@/irccd"
+#define IRCCD_CACHEDIR          "@VARDIR@/cache/irccd"
+#define IRCCD_SYSCONFDIR        "@ETCDIR@"
+#define IRCCD_LIBDIR            "@LIBDIR@"
+#define IRCCD_DATADIR           "@SHAREDIR@/irccd"
 
-#cmakedefine IRCCD_WITH_JS
-#cmakedefine IRCCD_WITH_SSL
+@define WITH_JS@
+@define WITH_SSL@
 
 #endif /* !IRCCD_CONFIG_H */
--- a/lib/irccd/conn.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/conn.c	Tue Apr 27 09:22:16 2021 +0200
@@ -25,7 +25,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "compat.h"
 #include "conn.h"
 #include "log.h"
 #include "server.h"
--- a/lib/irccd/event.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/event.c	Tue Apr 27 09:22:16 2021 +0200
@@ -22,8 +22,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <compat.h>
-
 #include "event.h"
 #include "server.h"
 
--- a/lib/irccd/hook.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/hook.c	Tue Apr 27 09:22:16 2021 +0200
@@ -16,8 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <compat.h>
-
 #include <sys/wait.h>
 #include <assert.h>
 #include <errno.h>
@@ -37,7 +35,7 @@
 {
 	char **ret;
 	va_list ap;
-	
+
 	ret = irc_util_calloc(n + 2, sizeof (*ret));
 	ret[0] = (char *)h->path;
 
--- a/lib/irccd/irccd.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/irccd.c	Tue Apr 27 09:22:16 2021 +0200
@@ -28,7 +28,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "compat.h"
 #include "config.h"
 #include "event.h"
 #include "irccd.h"
--- a/lib/irccd/server.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/server.c	Tue Apr 27 09:22:16 2021 +0200
@@ -16,8 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <compat.h>
-
 #include <assert.h>
 #include <errno.h>
 #include <err.h>
--- a/lib/irccd/subst.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/subst.c	Tue Apr 27 09:22:16 2021 +0200
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "compat.h"
 #include "subst.h"
 #include "util.h"
 
--- a/lib/irccd/util.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/lib/irccd/util.c	Tue Apr 27 09:22:16 2021 +0200
@@ -24,8 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <compat.h>
-
 #include "util.h"
 
 void *
--- a/man/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(man)
-
-function(man file section)
-	get_filename_component(basename ${file} NAME)
-	configure_file(${file} ${man_BINARY_DIR}/${basename})
-	install(
-		FILES ${man_BINARY_DIR}/${basename}
-		DESTINATION ${CMAKE_INSTALL_MANDIR}/${section}
-	)
-endfunction()
-
-set(
-	MAN1
-	${man_SOURCE_DIR}/irccd.1
-	${man_SOURCE_DIR}/irccdctl.1
-)
-
-set(
-	MAN3
-	${man_SOURCE_DIR}/libirccd-compat.3
-	${man_SOURCE_DIR}/libirccd-event.3
-	${man_SOURCE_DIR}/libirccd-hook.3
-	${man_SOURCE_DIR}/libirccd-log.3
-	${man_SOURCE_DIR}/libirccd-rule.3
-	${man_SOURCE_DIR}/libirccd-util.3
-	${man_SOURCE_DIR}/libirccd-subst.3
-	${man_SOURCE_DIR}/libirccd.3
-)
-
-if (IRCCD_WITH_JS)
-	list(
-		APPEND MAN3
-		${man_SOURCE_DIR}/irccd-api-chrono.3
-		${man_SOURCE_DIR}/irccd-api-directory.3
-		${man_SOURCE_DIR}/irccd-api-file.3
-		${man_SOURCE_DIR}/irccd-api-hook.3
-		${man_SOURCE_DIR}/irccd-api-logger.3
-		${man_SOURCE_DIR}/irccd-api-plugin.3
-		${man_SOURCE_DIR}/irccd-api-rule.3
-		${man_SOURCE_DIR}/irccd-api-server.3
-		${man_SOURCE_DIR}/irccd-api-system.3
-		${man_SOURCE_DIR}/irccd-api-timer.3
-		${man_SOURCE_DIR}/irccd-api-unicode.3
-		${man_SOURCE_DIR}/irccd-api-util.3
-		${man_SOURCE_DIR}/irccd-api.3
-	)
-endif ()
-
-set(
-	MAN5
-	${man_SOURCE_DIR}/irccd.conf.5
-)
-
-set(
-	MAN7
-	${man_SOURCE_DIR}/irccd-ipc.7
-	${man_SOURCE_DIR}/irccd-templates.7
-)
-
-foreach (m ${MAN1})
-	man(${m} man1)
-endforeach ()
-
-foreach (m ${MAN3})
-	man(${m} man3)
-endforeach ()
-
-foreach (m ${MAN5})
-	man(${m} man5)
-endforeach ()
-
-foreach (m ${MAN7})
-	man(${m} man7)
-endforeach ()
-
-add_custom_target(
-	man
-	COMMENT "Manual pages"
-	SOURCES ${MAN1} ${MAN3} ${MAN5} ${MAN7}
-)
--- a/plugins/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-set(
-	JS_PLUGINS
-	ask
-	auth
-	hangman
-	history
-	joke
-	logger
-	plugin
-	roulette
-	tictactoe
-)
-
-set(
-	C_PLUGINS
-	links
-)
-
-foreach (p ${C_PLUGINS} ${JS_PLUGINS})
-	string(TOUPPER ${p} opt)
-	option(IRCCD_WITH_PLUGIN_${opt} "Enable ${p} plugin" On)
-endforeach ()
-
-if (IRCCD_WITH_JS)
-	foreach (p ${JS_PLUGINS})
-		string(TOUPPER ${p} plg)
-		if (IRCCD_WITH_PLUGIN_${plg})
-			add_subdirectory(${p})
-		endif ()
-	endforeach ()
-endif ()
-
-foreach (p ${C_PLUGINS})
-	string(TOUPPER ${p} p)
-
-	if (IRCCD_WITH_PLUGIN_${p})
-		add_subdirectory(links)
-	endif ()
-endforeach ()
--- a/plugins/ask/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(ask)
-
-irccd_define_js_plugin(
-	NAME ask
-	SCRIPT ${ask_SOURCE_DIR}/ask.js
-	MAN ${ask_SOURCE_DIR}/ask.7
-)
--- a/plugins/auth/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(auth)
-
-irccd_define_js_plugin(
-	NAME auth
-	SCRIPT ${auth_SOURCE_DIR}/auth.js
-	MAN ${auth_SOURCE_DIR}/auth.7
-)
--- a/plugins/hangman/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(hangman)
-
-irccd_define_js_plugin(
-	NAME hangman
-	SCRIPT ${hangman_SOURCE_DIR}/hangman.js
-	MAN ${hangman_SOURCE_DIR}/hangman.7
-)
--- a/plugins/history/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(history)
-
-irccd_define_js_plugin(
-	NAME history
-	SCRIPT ${history_SOURCE_DIR}/history.js
-	MAN ${history_SOURCE_DIR}/history.7
-)
--- a/plugins/joke/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(joke)
-
-irccd_define_js_plugin(
-	NAME joke
-	SCRIPT ${joke_SOURCE_DIR}/joke.js
-	MAN ${joke_SOURCE_DIR}/joke.7
-)
--- a/plugins/links/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(links)
-
-find_package(CURL REQUIRED)
-
-irccd_define_c_plugin(
-	NAME links
-	MAN ${links_SOURCE_DIR}/links.7
-	SOURCES ${links_SOURCE_DIR}/links.c
-	LIBRARIES CURL::libcurl
-)
--- a/plugins/links/links.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/plugins/links/links.c	Tue Apr 27 09:22:16 2021 +0200
@@ -28,7 +28,6 @@
 
 #include <curl/curl.h>
 
-#include <irccd/compat.h>
 #include <irccd/config.h>
 #include <irccd/irccd.h>
 #include <irccd/limits.h>
--- a/plugins/logger/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(logger)
-
-irccd_define_js_plugin(
-	NAME logger
-	SCRIPT ${logger_SOURCE_DIR}/logger.js
-	MAN ${logger_SOURCE_DIR}/logger.7
-)
--- a/plugins/plugin/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(plugin)
-
-irccd_define_js_plugin(
-	NAME plugin
-	SCRIPT ${plugin_SOURCE_DIR}/plugin.js
-	MAN ${plugin_SOURCE_DIR}/plugin.7
-)
--- a/plugins/roulette/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(roulette)
-
-irccd_define_js_plugin(
-	NAME roulette
-	SCRIPT ${roulette_SOURCE_DIR}/roulette.js
-	MAN ${roulette_SOURCE_DIR}/roulette.7
-)
--- a/plugins/tictactoe/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(tictactoe)
-
-irccd_define_js_plugin(
-	NAME tictactoe
-	SCRIPT ${tictactoe_SOURCE_DIR}/tictactoe.js
-	MAN ${tictactoe_SOURCE_DIR}/tictactoe.7
-)
--- a/tests/CMakeLists.txt	Mon Apr 12 11:16:18 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-#
-# CMakeLists.txt -- CMake build for irccd
-#
-# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(tests)
-
-set(
-	TESTS
-	test-bot
-	test-channel
-	test-event
-	test-dl-plugin
-	test-log
-	test-rule
-	test-subst
-	test-util
-)
-
-if (IRCCD_WITH_JS)
-	list(
-		APPEND TESTS
-		test-jsapi-chrono
-		test-jsapi-directory
-		test-jsapi-file
-		test-jsapi-irccd
-		test-jsapi-system
-		test-jsapi-timer
-		test-jsapi-unicode
-		test-jsapi-util
-		test-plugin-ask
-		test-plugin-auth
-		test-plugin-hangman
-		test-plugin-history
-		test-plugin-joke
-		test-plugin-logger
-		test-plugin-plugin
-		test-plugin-tictactoe
-	)
-endif ()
-
-add_library(example-dl-plugin MODULE ${tests_SOURCE_DIR}/data/example-dl-plugin.c)
-target_link_libraries(example-dl-plugin libirccd)
-
-if (APPLE)
-	set_target_properties(example-dl-plugin PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
-endif ()
-
-set_target_properties(example-dl-plugin
-	PROPERTIES
-		FOLDER tests/test-dl-plugin
-		PREFIX ""
-)
-
-foreach (t ${TESTS})
-	add_executable(${t} ${t}.c)
-	add_test(${t} ${t})
-	target_link_libraries(${t} irccd-fe libirccd-greatest)
-	set_target_properties(${t} PROPERTIES FOLDER "tests" ENABLE_EXPORTS On)
-	target_compile_definitions(
-		${t}
-		PRIVATE
-			EXAMPLE_DL_PLUGIN="$<TARGET_FILE:example-dl-plugin>"
-			IRCCD_EXECUTABLE="$<TARGET_FILE:irccd>"
-			CMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}"
-			# TODO: change those names.
-			BINARY="${tests_BINARY_DIR}"
-			SOURCE="${tests_SOURCE_DIR}"
-	)
-	add_dependencies(${t} irccd example-dl-plugin)
-endforeach ()
--- a/tests/data/example-dl-plugin.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/data/example-dl-plugin.c	Tue Apr 27 09:22:16 2021 +0200
@@ -18,8 +18,6 @@
 
 #include <string.h>
 
-#include <compat.h>
-
 #include <irccd/event.h>
 #include <irccd/server.h>
 #include <irccd/util.h>
--- a/tests/test-dl-plugin.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-dl-plugin.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/dl-plugin.h>
 #include <irccd/event.h>
@@ -36,7 +35,7 @@
 	(void)udata;
 
 	/* TODO: No idea how to stop greatest from here. */
-	if ((plugin = dl_plugin_open("example", EXAMPLE_DL_PLUGIN)) == NULL)
+	if ((plugin = dl_plugin_open("example", TOP "/tests/data/example-dl-plugin.so")) == NULL)
 		err(1, "dlopen");
 }
 
--- a/tests/test-jsapi-chrono.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-jsapi-chrono.c	Tue Apr 27 09:22:16 2021 +0200
@@ -32,7 +32,7 @@
 {
 	(void)udata;
 
-	plugin = js_plugin_open("example", SOURCE "/data/example-plugin.js");
+	plugin = js_plugin_open("example", TOP "/tests/data/example-plugin.js");
 	ctx = js_plugin_get_context(plugin);
 }
 
--- a/tests/test-jsapi-directory.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-jsapi-directory.c	Tue Apr 27 09:22:16 2021 +0200
@@ -32,14 +32,11 @@
 {
 	(void)udata;
 
-	plugin = js_plugin_open("example", SOURCE "/data/example-plugin.js");
+	plugin = js_plugin_open("example", TOP "/tests/data/example-plugin.js");
 	ctx = js_plugin_get_context(plugin);
 
-	duk_push_string(ctx, SOURCE);
-	duk_put_global_string(ctx, "SOURCE");
-
-	duk_push_string(ctx, BINARY);
-	duk_put_global_string(ctx, "BINARY");
+	duk_push_string(ctx, TOP);
+	duk_put_global_string(ctx, "TOP");
 }
 
 static void
@@ -47,6 +44,9 @@
 {
 	(void)udata;
 
+	remove(TOP "/tests/1/2");
+	remove(TOP "/tests/1");
+
 	irc_plugin_finish(plugin);
 
 	plugin = NULL;
@@ -57,7 +57,7 @@
 object_constructor(void)
 {
 	const char *script =
-		"d = new Irccd.Directory(SOURCE + '/data/root');"
+		"d = new Irccd.Directory(TOP + '/tests/data/root');"
 		"p = d.path;"
 		"l = d.entries.length;";
 
@@ -75,7 +75,7 @@
 GREATEST_TEST
 object_find(void)
 {
-	const char *script = "d = new Irccd.Directory(SOURCE + '/data/root');";
+	const char *script = "d = new Irccd.Directory(TOP + '/tests/data/root');";
 
 	if (duk_peval_string(ctx, script) != 0)
 		GREATEST_FAIL();
@@ -85,7 +85,7 @@
 		GREATEST_FAIL();
 
 	duk_get_global_string(ctx, "p");
-	GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/lines.txt", duk_get_string(ctx, -1));
+	GREATEST_ASSERT_STR_EQ(TOP "/tests/data/root/lines.txt", duk_get_string(ctx, -1));
 
 	/* Find "unknown.txt" not recursively (not found). */
 	if (duk_peval_string(ctx, "p = d.find('unknown.txt');") != 0)
@@ -106,7 +106,7 @@
 		GREATEST_FAIL();
 
 	duk_get_global_string(ctx, "p");
-	GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/level-1/level-2/file-2.txt", duk_get_string(ctx, -1));
+	GREATEST_ASSERT_STR_EQ(TOP "/tests/data/root/level-1/level-2/file-2.txt", duk_get_string(ctx, -1));
 
 	GREATEST_PASS();
 }
@@ -117,28 +117,28 @@
 	struct stat st;
 
 	/* First create an empty directory. */
-	mkdir(BINARY "/empty", 0700);
+	mkdir(TOP "/tests/empty", 0700);
 
-	if (duk_peval_string(ctx, "d = new Irccd.Directory(BINARY + '/empty')") != 0)
+	if (duk_peval_string(ctx, "d = new Irccd.Directory(TOP + '/tests/empty')") != 0)
 		GREATEST_FAIL();
 
 	/* Not recursive. */
 	if (duk_peval_string(ctx, "d.remove()") != 0)
 		GREATEST_FAIL();
 
-	GREATEST_ASSERT_EQ(-1, stat(BINARY "/empty", &st));
+	GREATEST_ASSERT_EQ(-1, stat(TOP "/tests/empty", &st));
 
-	mkdir(BINARY "/notempty", 0700);
-	mkdir(BINARY "/notempty/empty", 0700);
+	mkdir(TOP "/tests/notempty", 0700);
+	mkdir(TOP "/tests/notempty/empty", 0700);
 
-	if (duk_peval_string(ctx, "d = new Irccd.Directory(BINARY + '/notempty')") != 0)
+	if (duk_peval_string(ctx, "d = new Irccd.Directory(TOP + '/tests/notempty')") != 0)
 		GREATEST_FAIL();
 
 	/* Not recursive. */
 	if (duk_peval_string(ctx, "d.remove(true)") != 0)
 		GREATEST_FAIL();
 
-	GREATEST_ASSERT_EQ(-1, stat(BINARY "/notempty", &st));
+	GREATEST_ASSERT_EQ(-1, stat(TOP "/tests/notempty", &st));
 
 	GREATEST_PASS();
 }
@@ -156,34 +156,34 @@
 free_find(void)
 {
 	/* Find "lines.txt" not recursively. */
-	if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'lines.txt');") != 0) {
+	if (duk_peval_string(ctx, "p = Irccd.Directory.find(TOP + '/tests/data/root', 'lines.txt');") != 0) {
 		puts(duk_to_string(ctx, -1));
 		GREATEST_FAIL();
 	}
 
 	duk_get_global_string(ctx, "p");
-	GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/lines.txt", duk_get_string(ctx, -1));
+	GREATEST_ASSERT_STR_EQ(TOP "/tests/data/root/lines.txt", duk_get_string(ctx, -1));
 
 	/* Find "unknown.txt" not recursively (not found). */
-	if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'unknown.txt');") != 0)
+	if (duk_peval_string(ctx, "p = Irccd.Directory.find(TOP + '/tests/data/root', 'unknown.txt');") != 0)
 		GREATEST_FAIL();
 
 	duk_get_global_string(ctx, "p");
 	GREATEST_ASSERT(duk_is_null(ctx, -1));
 
 	/* Find "file-2.txt" not recursively (exists but in sub directory). */
-	if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'file-2.txt');") != 0)
+	if (duk_peval_string(ctx, "p = Irccd.Directory.find(TOP + '/tests/data/root', 'file-2.txt');") != 0)
 		GREATEST_FAIL();
 
 	duk_get_global_string(ctx, "p");
 	GREATEST_ASSERT(duk_is_null(ctx, -1));
 
 	/* Find "file-2.txt" recursively. */
-	if (duk_peval_string(ctx, "p = Irccd.Directory.find(SOURCE + '/data/root', 'file-2.txt', true);") != 0)
+	if (duk_peval_string(ctx, "p = Irccd.Directory.find(TOP + '/tests/data/root', 'file-2.txt', true);") != 0)
 		GREATEST_FAIL();
 
 	duk_get_global_string(ctx, "p");
-	GREATEST_ASSERT_STR_EQ(SOURCE "/data/root/level-1/level-2/file-2.txt", duk_get_string(ctx, -1));
+	GREATEST_ASSERT_STR_EQ(TOP "/tests/data/root/level-1/level-2/file-2.txt", duk_get_string(ctx, -1));
 
 	GREATEST_PASS();
 }
@@ -194,24 +194,24 @@
 	struct stat st;
 
 	/* First create an empty directory. */
-	mkdir(BINARY "/empty", 0700);
+	mkdir(TOP "/tests/empty", 0700);
 
 	/* Not recursive. */
-	if (duk_peval_string(ctx, "Irccd.Directory.remove(BINARY + '/empty')") != 0) {
+	if (duk_peval_string(ctx, "Irccd.Directory.remove(TOP + '/tests/empty')") != 0) {
 		puts(duk_to_string(ctx, -1));
 		GREATEST_FAIL();
 	}
 
-	GREATEST_ASSERT_EQ(-1, stat(BINARY "/empty", &st));
+	GREATEST_ASSERT_EQ(-1, stat(TOP "/tests/empty", &st));
 
-	mkdir(BINARY "/notempty", 0700);
-	mkdir(BINARY "/notempty/empty", 0700);
+	mkdir(TOP "/tests/notempty", 0700);
+	mkdir(TOP "/tests/notempty/empty", 0700);
 
 	/* Not recursive. */
-	if (duk_peval_string(ctx, "Irccd.Directory.remove(BINARY + '/notempty', true)") != 0)
+	if (duk_peval_string(ctx, "Irccd.Directory.remove(TOP + '/tests/notempty', true)") != 0)
 		GREATEST_FAIL();
 
-	GREATEST_ASSERT_EQ(-1, stat(BINARY "/notempty", &st));
+	GREATEST_ASSERT_EQ(-1, stat(TOP "/tests/notempty", &st));
 
 	GREATEST_PASS();
 }
@@ -221,15 +221,15 @@
 {
 	struct stat st;
 
-	remove(BINARY "/1/2");
-	remove(BINARY "/1");
+	remove(TOP "/tests/1/2");
+	remove(TOP "/tests/1");
 
-	if (duk_peval_string(ctx, "Irccd.Directory.mkdir(BINARY + '/1/2')") != 0) {
+	if (duk_peval_string(ctx, "Irccd.Directory.mkdir(TOP + '/tests/1/2')") != 0) {
 		puts(duk_to_string(ctx, -1));
 		GREATEST_FAIL();
 	}
 
-	GREATEST_ASSERT_EQ(0, stat(BINARY "/1/2", &st));
+	GREATEST_ASSERT_EQ(0, stat(TOP "/tests/1/2", &st));
 
 	GREATEST_PASS();
 }
--- a/tests/test-jsapi-file.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-jsapi-file.c	Tue Apr 27 09:22:16 2021 +0200
@@ -33,14 +33,11 @@
 {
 	(void)udata;
 
-	plugin = js_plugin_open("example", SOURCE "/data/example-plugin.js");
+	plugin = js_plugin_open("example", TOP "/tests/data/example-plugin.js");
 	ctx = js_plugin_get_context(plugin);
 
-	duk_push_string(ctx, SOURCE);
-	duk_put_global_string(ctx, "SOURCE");
-
-	duk_push_string(ctx, BINARY);
-	duk_put_global_string(ctx, "BINARY");
+	duk_push_string(ctx, TOP);
+	duk_put_global_string(ctx, "TOP");
 }
 
 static void
@@ -74,14 +71,14 @@
 
 	GREATEST_ASSERT(duk_get_global_string(ctx, "result"));
 	GREATEST_ASSERT_STR_EQ("/usr/local/etc", duk_get_string(ctx, -1));
-	
+
 	GREATEST_PASS();
 }
 
 GREATEST_TEST
 free_exists(void)
 {
-	if (duk_peval_string(ctx, "result = Irccd.File.exists(SOURCE + '/data/root/file-1.txt')"))
+	if (duk_peval_string(ctx, "result = Irccd.File.exists(TOP + '/tests/data/root/file-1.txt')"))
 		GREATEST_FAIL();
 
 	GREATEST_ASSERT(duk_get_global_string(ctx, "result"));
@@ -108,15 +105,15 @@
 	FILE *fp;
 	struct stat st;
 
-	if (!(fp = fopen(BINARY "/test.bin", "w")))
+	if (!(fp = fopen(TOP "/tests/test.bin", "w")))
 		GREATEST_FAIL();
 
 	fclose(fp);
 
-	if (duk_peval_string(ctx, "Irccd.File.remove(BINARY + '/test.bin')") != 0)
+	if (duk_peval_string(ctx, "Irccd.File.remove(TOP + '/tests/test.bin')") != 0)
 		GREATEST_FAIL();
 
-	GREATEST_ASSERT(stat(BINARY "/test.bin", &st) < 0);
+	GREATEST_ASSERT(stat(TOP "/tests/test.bin", &st) < 0);
 
 	GREATEST_PASS();
 }
@@ -136,7 +133,7 @@
 object_basename(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"result = f.basename();"
 	);
 
@@ -153,7 +150,7 @@
 object_basename_closed(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"f.close();"
 		"result = f.basename();"
 	);
@@ -171,7 +168,7 @@
 object_dirname(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"result = f.dirname();"
 	);
 
@@ -179,7 +176,7 @@
 		GREATEST_FAIL();
 
 	GREATEST_ASSERT(duk_get_global_string(ctx, "result"));
-	GREATEST_ASSERT_STR_EQ(SOURCE "/data/root", duk_get_string(ctx, -1));
+	GREATEST_ASSERT_STR_EQ(TOP "/tests/data/root", duk_get_string(ctx, -1));
 
 	GREATEST_PASS();
 }
@@ -188,7 +185,7 @@
 object_dirname_closed(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"f.close();"
 		"result = f.dirname();"
 	);
@@ -197,7 +194,7 @@
 		GREATEST_FAIL();
 
 	GREATEST_ASSERT(duk_get_global_string(ctx, "result"));
-	GREATEST_ASSERT_STR_EQ(SOURCE "/data/root", duk_get_string(ctx, -1));
+	GREATEST_ASSERT_STR_EQ(TOP "/tests/data/root", duk_get_string(ctx, -1));
 
 	GREATEST_PASS();
 }
@@ -206,7 +203,7 @@
 object_lines(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"result = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r').lines();"
+		"result = new Irccd.File(TOP + '/tests/data/root/lines.txt', 'r').lines();"
 	);
 
 	if (ret != 0)
@@ -229,7 +226,7 @@
 {
 	const int ret = duk_peval_string(ctx,
 		"try {"
-		"  f = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r');"
+		"  f = new Irccd.File(TOP + '/tests/data/root/lines.txt', 'r');"
 		"  f.close();"
 		"  f.lines();"
 		"} catch (e) {"
@@ -250,7 +247,7 @@
 object_seek1(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"f.seek(Irccd.File.SeekSet, 6);"
 		"result = f.read(1);"
 	);
@@ -268,7 +265,7 @@
 object_seek2(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"f.seek(Irccd.File.SeekSet, 2);"
 		"f.seek(Irccd.File.SeekCur, 4);"
 		"result = f.read(1);"
@@ -287,7 +284,7 @@
 object_seek3(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"f.seek(Irccd.File.SeekEnd, -2);"
 		"result = f.read(1);"
 	);
@@ -306,7 +303,7 @@
 {
 	const int ret = duk_peval_string(ctx,
 		"try {"
-		"  f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"  f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"  f.close();"
 		"  f.seek(Irccd.File.SeekEnd, -2);"
 		"} catch (e) {"
@@ -327,7 +324,7 @@
 object_read(void)
 {
 	const int ret = duk_peval_string(ctx,
-		"f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"result = f.read();"
 	);
 
@@ -345,7 +342,7 @@
 {
 	const int ret = duk_peval_string(ctx,
 		"try {"
-		"  f = new Irccd.File(SOURCE + '/data/root/file-1.txt', 'r');"
+		"  f = new Irccd.File(TOP + '/tests/data/root/file-1.txt', 'r');"
 		"  f.close();"
 		"  f.read();"
 		"} catch (e) {"
@@ -367,7 +364,7 @@
 {
 	const int ret = duk_peval_string(ctx,
 		"result = [];"
-		"f = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r');"
+		"f = new Irccd.File(TOP + '/tests/data/root/lines.txt', 'r');"
 		"for (var s; s = f.readline(); ) {"
 		"  result.push(s);"
 		"}"
@@ -396,7 +393,7 @@
 	const int ret = duk_peval_string(ctx,
 		"try {"
 		"  result = [];"
-		"  f = new Irccd.File(SOURCE + '/data/root/lines.txt', 'r');"
+		"  f = new Irccd.File(TOP + '/tests/data/root/lines.txt', 'r');"
 		"  f.close();"
 		"  for (var s; s = f.readline(); ) {"
 		"    result.push(s);"
--- a/tests/test-jsapi-irccd.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-jsapi-irccd.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,8 +21,7 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <config.h>
-
+#include <irccd/config.h>
 #include <irccd/js-plugin.h>
 #include <irccd/jsapi-system.h>
 #include <irccd/plugin.h>
@@ -35,7 +34,7 @@
 {
 	(void)udata;
 
-	plugin = js_plugin_open("example", SOURCE "/data/example-plugin.js");
+	plugin = js_plugin_open("example", TOP "/tests/data/example-plugin.js");
 	ctx = js_plugin_get_context(plugin);
 }
 
--- a/tests/test-jsapi-system.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-jsapi-system.c	Tue Apr 27 09:22:16 2021 +0200
@@ -19,9 +19,7 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-// TODO: irccd/
-#include <config.h>
-
+#include <irccd/config.h>
 #include <irccd/js-plugin.h>
 #include <irccd/plugin.h>
 
@@ -33,7 +31,7 @@
 {
 	(void)udata;
 
-	plugin = js_plugin_open("example", SOURCE "/data/example-plugin.js");
+	plugin = js_plugin_open("example", TOP "/tests/data/example-plugin.js");
 	ctx = js_plugin_get_context(plugin);
 }
 
@@ -52,7 +50,7 @@
 basics_popen(void)
 {
 	int ret = duk_peval_string(ctx,
-		"f = Irccd.System.popen(\"" IRCCD_EXECUTABLE " version\", \"r\");"
+		"f = Irccd.System.popen(\"" TOP "/irccd/irccd version\", \"r\");"
 		"r = f.readline();"
 	);
 
--- a/tests/test-jsapi-unicode.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-jsapi-unicode.c	Tue Apr 27 09:22:16 2021 +0200
@@ -23,9 +23,7 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-// TODO: irccd/
-#include <config.h>
-
+#include <irccd/config.h>
 #include <irccd/js-plugin.h>
 #include <irccd/plugin.h>
 
@@ -37,7 +35,7 @@
 {
 	(void)udata;
 
-	plugin = js_plugin_open("example", SOURCE "/data/example-plugin.js");
+	plugin = js_plugin_open("example", TOP "/tests/data/example-plugin.js");
 	ctx = js_plugin_get_context(plugin);
 }
 
--- a/tests/test-jsapi-util.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-jsapi-util.c	Tue Apr 27 09:22:16 2021 +0200
@@ -30,7 +30,7 @@
 {
 	(void)udata;
 
-	plugin = js_plugin_open("example", SOURCE "/data/example-plugin.js");
+	plugin = js_plugin_open("example", TOP "/tests/data/example-plugin.js");
 	ctx = js_plugin_get_context(plugin);
 }
 
--- a/tests/test-plugin-ask.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-ask.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/js-plugin.h>
 #include <irccd/plugin.h>
@@ -36,13 +35,13 @@
 	(void)udata;
 
 	server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("test", CMAKE_SOURCE_DIR "/plugins/ask/ask.js");
+	plugin = js_plugin_open("test", TOP "/plugins/ask/ask.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");
 
 	irc_server_incref(server);
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/answers.conf");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/answers.conf");
 	irc_plugin_load(plugin);
 
 	/* Fake server connected to send data. */
--- a/tests/test-plugin-auth.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-auth.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/js-plugin.h>
 #include <irccd/plugin.h>
@@ -43,7 +42,7 @@
 	servers[0] = irc_server_new("nickserv1", "t", "t", "t", "127.0.0.1", 6667);
 	servers[1] = irc_server_new("nickserv2", "t", "t", "t", "127.0.0.1", 6667);
 	servers[2] = irc_server_new("quakenet", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("test", CMAKE_SOURCE_DIR "/plugins/auth/auth.js");
+	plugin = js_plugin_open("test", TOP "/plugins/auth/auth.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");
--- a/tests/test-plugin-hangman.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-hangman.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/js-plugin.h>
 #include <irccd/log.h>
@@ -63,7 +62,7 @@
 	(void)udata;
 
 	server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("hangman", CMAKE_SOURCE_DIR "/plugins/hangman/hangman.js");
+	plugin = js_plugin_open("hangman", TOP "/plugins/hangman/hangman.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");
@@ -79,7 +78,7 @@
 	irc_plugin_set_template(plugin, "wrong-letter", "wrong-letter=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{letter}");
 	irc_plugin_set_template(plugin, "wrong-player", "wrong-player=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{letter}");
 	irc_plugin_set_template(plugin, "wrong-word", "wrong-word=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{word}");
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/words.conf");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/words.conf");
 	irc_plugin_set_option(plugin, "collaborative", "false");
 	irc_plugin_load(plugin);
 
--- a/tests/test-plugin-history.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-history.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/js-plugin.h>
 #include <irccd/log.h>
@@ -62,10 +61,10 @@
 {
 	(void)udata;
 
-	remove(BINARY "/seen.json");
+	remove(TOP "/tests/seen.json");
 
 	server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("history", CMAKE_SOURCE_DIR "/plugins/history/history.js");
+	plugin = js_plugin_open("history", TOP "/plugins/history/history.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");
@@ -76,7 +75,7 @@
 	irc_plugin_set_template(plugin, "seen", "seen=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{target}:%H:%M");
 	irc_plugin_set_template(plugin, "said", "said=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{target}:#{message}:%H:%M");
 	irc_plugin_set_template(plugin, "unknown", "unknown=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{target}");
-	irc_plugin_set_option(plugin, "file", BINARY "/seen.json");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/seen.json");
 	irc_plugin_load(plugin);
 
 	/* Fake server connected to send data. */
@@ -88,6 +87,8 @@
 {
 	(void)udata;
 
+	remove(TOP "/tests/seen.json");
+
 	irc_plugin_finish(plugin);
 	irc_server_decref(server);
 }
@@ -95,7 +96,7 @@
 GREATEST_TEST
 basics_error(void)
 {
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/error.json");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/error.json");
 	CALL(IRC_EVENT_COMMAND, "seen francis");
 	GREATEST_ASSERT_STR_EQ("PRIVMSG #history :error=history:!history:test:#history:jean!jean@localhost:jean\r\n", server->conn->out);
 	GREATEST_PASS();
--- a/tests/test-plugin-joke.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-joke.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/js-plugin.h>
 #include <irccd/plugin.h>
@@ -49,7 +48,7 @@
 	(void)udata;
 
 	server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("joke", CMAKE_SOURCE_DIR "/plugins/joke/joke.js");
+	plugin = js_plugin_open("joke", TOP "/plugins/joke/joke.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");
@@ -57,7 +56,7 @@
 	irc_server_incref(server);
 	irc_plugin_set_template(plugin, "error", "error=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}");
 
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/joke/jokes.json");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/joke/jokes.json");
 	irc_plugin_load(plugin);
 
 	/* Fake server connected to send data. */
@@ -110,7 +109,7 @@
 	 * The jokes "xxx" and "yyy" are both 3-lines which we disallow. only a
 	 * must be said.
 	 */
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/joke/error-toobig.json");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/joke/error-toobig.json");
 	irc_plugin_set_option(plugin, "max-list-lines", "2");
 
 	for (int i = 0; i < 64; ++i) {
@@ -125,7 +124,7 @@
 errors_invalid(void)
 {
 	/* Only a is the valid joke in this file. */
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/joke/error-invalid.json");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/joke/error-invalid.json");
 	irc_plugin_set_option(plugin, "max-list-lines", "2");
 
 	for (int i = 0; i < 64; ++i) {
@@ -150,7 +149,7 @@
 GREATEST_TEST
 errors_not_array(void)
 {
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/joke/error-not-array.json");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/joke/error-not-array.json");
 
 	CALL();
 	GREATEST_ASSERT_STR_EQ("PRIVMSG #joke :error=joke:!joke:test:#joke:jean!jean@localhost:jean\r\n", server->conn->out);
@@ -161,7 +160,7 @@
 GREATEST_TEST
 errors_empty(void)
 {
-	irc_plugin_set_option(plugin, "file", SOURCE "/data/joke/error-empty.json");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/data/joke/error-empty.json");
 
 	CALL();
 	GREATEST_ASSERT_STR_EQ("PRIVMSG #joke :error=joke:!joke:test:#joke:jean!jean@localhost:jean\r\n", server->conn->out);
--- a/tests/test-plugin-logger.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-logger.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/js-plugin.h>
 #include <irccd/log.h>
 #include <irccd/plugin.h>
@@ -35,10 +34,10 @@
 {
 	(void)udata;
 
-	remove(BINARY "/log");
+	remove(TOP "/tests/log");
 
 	server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("logger", CMAKE_SOURCE_DIR "/plugins/logger/logger.js");
+	plugin = js_plugin_open("logger", TOP "/plugins/logger/logger.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");
@@ -53,7 +52,7 @@
 	irc_plugin_set_template(plugin, "part", "part=#{server}:#{channel}:#{origin}:#{nickname}:#{reason}");
 	irc_plugin_set_template(plugin, "query", "query=#{server}:#{origin}:#{nickname}:#{message}");
 	irc_plugin_set_template(plugin, "topic", "topic=#{server}:#{channel}:#{origin}:#{nickname}:#{topic}");
-	irc_plugin_set_option(plugin, "file", BINARY "/log");
+	irc_plugin_set_option(plugin, "file", TOP "/tests/log");
 	irc_plugin_load(plugin);
 
 	/* Fake server connected to send data. */
@@ -65,6 +64,8 @@
 {
 	(void)udata;
 
+	remove(TOP "/tests/log");
+
 	irc_plugin_finish(plugin);
 	irc_server_decref(server);
 }
@@ -77,7 +78,7 @@
 
 	buf[0] = '\0';
 
-	if (!(fp = fopen(BINARY "/log", "r")))
+	if (!(fp = fopen(TOP "/tests/log", "r")))
 		err(1, "fopen");
 	if (!(fgets(buf, sizeof (buf), fp)))
 		err(1, "fgets");
--- a/tests/test-plugin-plugin.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-plugin.c	Tue Apr 27 09:22:16 2021 +0200
@@ -22,7 +22,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/irccd.h>
 #include <irccd/js-plugin.h>
@@ -64,7 +63,7 @@
 	(void)udata;
 
 	server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("plugin", CMAKE_SOURCE_DIR "/plugins/plugin/plugin.js");
+	plugin = js_plugin_open("plugin", TOP "/plugins/plugin/plugin.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");
--- a/tests/test-plugin-tictactoe.c	Mon Apr 12 11:16:18 2021 +0200
+++ b/tests/test-plugin-tictactoe.c	Tue Apr 27 09:22:16 2021 +0200
@@ -21,7 +21,6 @@
 #define GREATEST_USE_ABBREVS 0
 #include <greatest.h>
 
-#include <irccd/compat.h>
 #include <irccd/conn.h>
 #include <irccd/irccd.h>
 #include <irccd/js-plugin.h>
@@ -65,7 +64,7 @@
 	(void)udata;
 
 	server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667);
-	plugin = js_plugin_open("tictactoe", CMAKE_SOURCE_DIR "/plugins/tictactoe/tictactoe.js");
+	plugin = js_plugin_open("tictactoe", TOP "/plugins/tictactoe/tictactoe.js");
 
 	if (!plugin)
 		errx(1, "could not load plugin");