aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRatakor <ratakor@disroot.org>2023-07-03 02:14:16 +0200
committerRatakor <ratakor@disroot.org>2023-07-03 02:14:16 +0200
commit71293eaa1598c54a410537e7185a0a705f7298ac (patch)
treed964b9c0dac91d049562e3e37836e57948feb02e
parentcf0fba532ab4b1d78f49005f324eb6d5a7149240 (diff)
Update Makefiles + add librev0.0.12
-rw-r--r--.gitignore4
-rw-r--r--Makefile51
-rw-r--r--README.md1
-rw-r--r--libre/LICENSE13
-rw-r--r--libre/Makefile24
-rw-r--r--libre/cthread/cthread.c343
-rw-r--r--libre/cthread/cthread.h248
-rw-r--r--libre/dalloc/dalloc.c402
-rw-r--r--libre/dalloc/dalloc.h65
-rw-r--r--libre/libre.h8
-rw-r--r--libre/util/util.c (renamed from src/util.c)23
-rw-r--r--libre/util/util.h (renamed from src/util.h)25
-rw-r--r--src/Makefile56
-rw-r--r--src/main.c4
-rw-r--r--src/nolan.h2
-rw-r--r--src/ocr.c1
16 files changed, 1218 insertions, 52 deletions
diff --git a/.gitignore b/.gitignore
index bdd6716..957f325 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
+*.o
+*.csv
tests/
-build/
images/
-*.csv
nolan
config.h
diff --git a/Makefile b/Makefile
index 2b114d6..15cc47c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,46 +1,35 @@
# Copywrong © 2023 Ratakor. See LICENSE file for license details.
-NAME = nolan
-PREFIX ?= /usr/local
-CC = cc
+NAME = nolan
+PREFIX ?= /usr/local
+CC = cc
-BUILD_DIR ?= build
-SRC_DIR ?= src
+LIBRE_DIR = libre
+SRC_DIR = src
-SRCS := ${wildcard ${SRC_DIR}/*.c}
-OBJS := ${SRCS:%=${BUILD_DIR}/%.o}
+CFLAGS ?= -O3
+LDFLAGS ?= -s
-DISCORDLIBS = -ldiscord -lcurl -lpthread
-TESSLIBS = -ltesseract -lleptonica
-GDLIBS = -lgd -lpng -lz -ljpeg -lfreetype -lm
+all: build
-WARN_FLAGS = -Werror -Wall -Wextra -Wmissing-prototypes -Wpadded\
- -Waggregate-return -Wunused-macros -Wshadow -Wcast-align
-CFLAGS += -std=c99 -pedantic -D_DEFAULT_SOURCE ${WARN_FLAGS}
-LDFLAGS += -s ${DISCORDLIBS} ${TESSLIBS} ${GDLIBS}
-
-all: options ${NAME}
-
-options:
+echo:
@echo ${NAME} build options:
+ @echo "CC = ${CC}"
+ @echo "PREFIX = ${PREFIX}"
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
- @echo "CC = ${CC}"
-
-${BUILD_DIR}/%.c.o: %.c
- @mkdir -p ${dir $@}
- ${CC} -c ${CFLAGS} $< -o $@
-
-${OBJS}: config.h
-config.h:
- cp config.def.h $@
+build:
+ @CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" ${MAKE} -C ${LIBRE_DIR}
+ @CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" ${MAKE} -C ${SRC_DIR}
-${NAME}: ${OBJS}
- ${CC} -o $@ ${OBJS} ${LDFLAGS}
+debug:
+ @${MAKE} -C ${LIBRE_DIR} $@
+ @${MAKE} -C ${SRC_DIR} $@
clean:
- rm -rf ${NAME} ${BUILD_DIR}
+ @${MAKE} -C ${LIBRE_DIR} $@
+ @${MAKE} -C $(SRC_DIR) $@
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
@@ -50,4 +39,4 @@ install: all
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${NAME}
-.PHONY: all options clean install uninstall
+.PHONY: all echo build debug clean install uninstall
diff --git a/README.md b/README.md
index 77f3e5e..c6f6deb 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@ A discord bot for Orna.
- [concord](https://github.com/Cogmasters/concord)
- [tesseract](https://github.com/tesseract-ocr/tesseract)
- [gd](https://github.com/libgd/libgd)
+- [libre](https://github.com/ratakor/libre) (included)
## TODO
diff --git a/libre/LICENSE b/libre/LICENSE
new file mode 100644
index 0000000..f1c9616
--- /dev/null
+++ b/libre/LICENSE
@@ -0,0 +1,13 @@
+Copyright © 2023, Ratakor <ratakor@disroot.org>
+
+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.
diff --git a/libre/Makefile b/libre/Makefile
new file mode 100644
index 0000000..3fb7c06
--- /dev/null
+++ b/libre/Makefile
@@ -0,0 +1,24 @@
+OBJS = cthread.o \
+ dalloc.o \
+ util.o
+
+DFLAGS = -O0 -g -DDALLOC
+CFLAGS += -std=c99 -pthread -D_DEFAULT_SOURCE
+
+all: ${OBJS}
+
+echo:
+ @echo "CC = ${CC}"
+ @echo "CFLAGS = ${CFLAGS}"
+ @echo "OBJS = ${OBJS}"
+
+${OBJS}:
+ ${CC} ${CFLAGS} -c ${@:.o=}/${@:.o=.c} -o $@
+
+debug:
+ @CFLAGS="${DFLAGS}" ${MAKE}
+
+clean:
+ rm -f ${OBJS}
+
+.PHONY: all echo debug clean
diff --git a/libre/cthread/cthread.c b/libre/cthread/cthread.c
new file mode 100644
index 0000000..094f455
--- /dev/null
+++ b/libre/cthread/cthread.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright © 2023, Ratakor <ratakor@disroot.org>
+ *
+ * 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 "cthread.h"
+
+#ifdef _WIN32
+#include <stdint.h>
+#define WIN32_FAILURE 0
+typedef DWORD WINAPI w_func(LPVOID);
+#endif /* _WIN32 */
+
+int
+cthread_create(cthread_t *thread, cthread_attr_t *attr, void *(*func)(void *),
+ void *arg)
+{
+#ifdef _WIN32
+ if (attr == NULL)
+ *thread = CreateThread(NULL, 0, (w_func *)func, arg, 0, NULL);
+ else
+ *thread = CreateThread(NULL, attr->stacksize, (w_func *)func,
+ arg, attr->w_dwCreationFlags, NULL);
+
+ return *thread == NULL;
+#else
+ pthread_attr_t a;
+ int ret;
+
+ if ((ret = pthread_attr_init(&a)) != 0)
+ return ret;
+
+ if (attr != NULL) {
+ if (attr->stacksize)
+ pthread_attr_setstacksize(&a, attr->stacksize);
+ if (attr->p_detachstate)
+ pthread_attr_setdetachstate(&a, attr->p_detachstate);
+ if (attr->p_guardsize)
+ pthread_attr_setguardsize(&a, attr->p_guardsize);
+#ifndef __ANDROID__
+ if (attr->p_inheritsched)
+ pthread_attr_setinheritsched(&a, attr->p_inheritsched);
+#endif /* __ANDROID__ */
+ if (attr->p_schedpolicy)
+ pthread_attr_setschedpolicy(&a, attr->p_schedpolicy);
+ if (attr->p_scope)
+ pthread_attr_setscope(&a, attr->p_scope);
+ if (attr->p_stack)
+ pthread_attr_setstack(&a, attr->p_stackaddr,
+ attr->p_stack);
+ }
+
+ ret = pthread_create(thread, &a, func, arg);
+ pthread_attr_destroy(&a);
+
+ return ret;
+#endif /* _WIN32 */
+}
+
+int
+cthread_join(cthread_t thread, void **retval)
+{
+#ifdef _WIN32
+ if (WaitForSingleObject(thread, INFINITE) == WAIT_FAILED)
+ return 0;
+
+ return GetExitCodeThread(thread, (LPDWORD)retval) == WIN32_FAILURE;
+#else
+ return pthread_join(thread, retval);
+#endif /* _WIN32 */
+}
+
+int
+cthread_detach(cthread_t thread)
+{
+#ifdef _WIN32
+ return CloseHandle(thread) == WIN32_FAILURE;
+#else
+ return pthread_detach(thread);
+#endif /* _WIN32 */
+}
+
+int
+cthread_equal(cthread_t t1, cthread_t t2)
+{
+#ifdef _WIN32
+ return t1 == t2;
+#else
+ return pthread_equal(t1, t2);
+#endif /* _WIN32 */
+}
+
+cthread_t
+cthread_self(void)
+{
+#ifdef _WIN32
+ return GetCurrentThread();
+#else
+ return pthread_self();
+#endif /* _WIN32 */
+}
+
+void
+cthread_exit(void *retval)
+{
+#ifdef _WIN32
+ ExitThread((DWORD)(uintptr_t)retval);
+#else
+ pthread_exit(retval);
+#endif /* _WIN32 */
+}
+
+int
+cthread_mutex_init(cthread_mutex_t *mutex, cthread_mutexattr_t *attr)
+{
+#ifdef _WIN32
+ if (attr == NULL)
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ else
+ *mutex = CreateMutex(NULL, attr->w_bInitialOwner,
+ attr->w_lpName);
+
+ return *mutex == NULL;
+#else
+ pthread_mutexattr_t a;
+ int ret;
+
+ if ((ret = pthread_mutexattr_init(&a)) != 0)
+ return ret;
+
+ if (attr != NULL) {
+ if (attr->p_pshared)
+ pthread_mutexattr_setpshared(&a, attr->p_pshared);
+ if (attr->p_type)
+ pthread_mutexattr_settype(&a, attr->p_type);
+#if (defined __linux__ || defined __FreeBSD__) && !defined __ANDROID__
+ if (attr->p_robust)
+ pthread_mutexattr_setrobust(&a, attr->p_robust);
+#endif /* (__linux__ || __FreeBSD__) && !__ANDROID__ */
+#ifndef __ANDROID__
+ if (attr->p_protocol)
+ pthread_mutexattr_setprotocol(&a, attr->p_protocol);
+ if (attr->p_prioceiling)
+ pthread_mutexattr_setprioceiling(&a,
+ attr->p_prioceiling);
+#endif /* __ANDROID__ */
+ }
+
+ ret = pthread_mutex_init(mutex, &a);
+ pthread_mutexattr_destroy(&a);
+
+ return ret;
+#endif /* _WIN32 */
+}
+
+int
+cthread_mutex_lock(cthread_mutex_t *mutex)
+{
+#ifdef _WIN32
+ cthread_mutex_t m;
+
+ if (*mutex == CTHREAD_MUTEX_INITIALIZER) {
+ m = CreateMutex(NULL, FALSE, NULL);
+ if (InterlockedCompareExchangePointer(mutex, m, NULL) != NULL)
+ CloseHandle(m);
+ }
+
+ return WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED;
+#else
+ return pthread_mutex_lock(mutex);
+#endif /* _WIN32 */
+}
+
+int
+cthread_mutex_trylock(cthread_mutex_t *mutex)
+{
+#ifdef _WIN32
+ return WaitForSingleObject(*mutex, 0) == WAIT_FAILED;
+#else
+ return pthread_mutex_trylock(mutex);
+#endif /* _WIN32 */
+}
+
+int
+cthread_mutex_unlock(cthread_mutex_t *mutex)
+{
+#ifdef _WIN32
+ return ReleaseMutex(*mutex) == WIN32_FAILURE;
+#else
+ return pthread_mutex_unlock(mutex);
+#endif /* _WIN32 */
+}
+
+int
+cthread_mutex_destroy(cthread_mutex_t *mutex)
+{
+#ifdef _WIN32
+ return CloseHandle(*mutex) == WIN32_FAILURE;
+#else
+ return pthread_mutex_destroy(mutex);
+#endif /* _WIN32 */
+}
+
+int
+cthread_cond_init(cthread_cond_t *cond, cthread_condattr_t *attr)
+{
+#ifdef _WIN32
+ if (attr == NULL)
+ *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
+ else
+ *cond = CreateEvent(NULL, attr->w_bManualReset,
+ attr->w_bInitialState, attr->w_lpName);
+
+ return *cond == NULL;
+#else
+ pthread_condattr_t a;
+ int ret;
+
+ if ((ret = pthread_condattr_init(&a)) != 0)
+ return ret;
+
+ if (attr != NULL) {
+ if (attr->p_pshared)
+ pthread_condattr_setpshared(&a, attr->p_pshared);
+ if (attr->p_clock)
+ pthread_condattr_setclock(&a, attr->p_clock);
+ }
+
+ ret = pthread_cond_init(cond, &a);
+ pthread_condattr_destroy(&a);
+
+ return ret;
+#endif /* _WIN32 */
+}
+
+int
+cthread_cond_signal(cthread_cond_t *cond)
+{
+#ifdef _WIN32
+ return SetEvent(*cond) == WIN32_FAILURE;
+#else
+ return pthread_cond_signal(cond);
+#endif /* _WIN32 */
+}
+
+int
+cthread_cond_broadcast(cthread_cond_t *cond)
+{
+#ifdef _WIN32
+ return SetEvent(*cond) == WIN32_FAILURE;
+#else
+ return pthread_cond_broadcast(cond);
+#endif /* _WIN32 */
+}
+
+int
+cthread_cond_wait(cthread_cond_t *cond, cthread_mutex_t *mutex)
+{
+#ifdef _WIN32
+ if (cthread_mutex_unlock(mutex) == 1)
+ return 1;
+
+ if (WaitForSingleObject(*cond, INFINITE) == WAIT_FAILED)
+ return 1;
+
+ return cthread_mutex_lock(mutex);
+#else
+ return pthread_cond_wait(cond, mutex);
+#endif /* _WIN32 */
+}
+
+int
+cthread_cond_destroy(cthread_cond_t *cond)
+{
+#ifdef _WIN32
+ return CloseHandle(*cond) == WIN32_FAILURE;
+#else
+ return pthread_cond_destroy(cond);
+#endif /* _WIN32 */
+}
+
+int
+cthread_rwlock_init(cthread_rwlock_t *rwlock)
+{
+#ifdef _WIN32
+ *rwlock = CreateMutex(NULL, FALSE, NULL);
+
+ return *rwlock == NULL;
+#else
+ return pthread_rwlock_init(rwlock, NULL);
+#endif /* _WIN32 */
+}
+
+int
+cthread_rwlock_rdlock(cthread_rwlock_t *rwlock)
+{
+#ifdef _WIN32
+ return WaitForSingleObject(*rwlock, INFINITE) == WAIT_FAILED;
+#else
+ return pthread_rwlock_rdlock(rwlock);
+#endif /* _WIN32 */
+}
+
+int
+cthread_rwlock_wrlock(cthread_rwlock_t *rwlock)
+{
+#ifdef _WIN32
+ return WaitForSingleObject(*rwlock, INFINITE) == WAIT_FAILED;
+#else
+ return pthread_rwlock_wrlock(rwlock);
+#endif /* _WIN32 */
+}
+
+int
+cthread_rwlock_unlock(cthread_rwlock_t *rwlock)
+{
+#ifdef _WIN32
+ return ReleaseMutex(*rwlock) == WIN32_FAILURE;
+#else
+ return pthread_rwlock_unlock(rwlock);
+#endif /* _WIN32 */
+}
+
+int
+cthread_rwlock_destroy(cthread_rwlock_t *rwlock)
+{
+#ifdef _WIN32
+ return CloseHandle(*rwlock) == WIN32_FAILURE;
+#else
+ return pthread_rwlock_destroy(rwlock);
+#endif /* _WIN32 */
+}
diff --git a/libre/cthread/cthread.h b/libre/cthread/cthread.h
new file mode 100644
index 0000000..27cb1fb
--- /dev/null
+++ b/libre/cthread/cthread.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright © 2023, Ratakor <ratakor@disroot.org>
+ *
+ * This library is free software. You can redistribute it and/or modify it
+ * under the terms of the ISC license. See cthread.c for details.
+ */
+
+#ifndef CTHREAD_H
+#define CTHREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef _WIN32
+#include <windows.h>
+
+#define CTHREAD_MUTEX_INITIALIZER NULL
+
+typedef HANDLE cthread_t;
+typedef HANDLE cthread_mutex_t;
+typedef HANDLE cthread_cond_t;
+typedef HANDLE cthread_rwlock_t;
+#else
+#include <pthread.h>
+
+#define CTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+typedef pthread_t cthread_t;
+typedef pthread_mutex_t cthread_mutex_t;
+typedef pthread_cond_t cthread_cond_t;
+typedef pthread_rwlock_t cthread_rwlock_t;
+#endif /* _WIN32 */
+
+typedef struct {
+ size_t stacksize;
+
+ int w_dwCreationFlags;
+
+ int p_detachstate;
+ size_t p_guardsize;
+ int p_inheritsched;
+ int p_schedpolicy;
+ int p_scope;
+ size_t p_stack;
+ void *p_stackaddr;
+} cthread_attr_t;
+
+typedef struct {
+ char *w_lpName;
+ int w_bInitialOwner;
+
+ int p_pshared;
+ int p_type;
+ int p_robust;
+ int p_protocol;
+ int p_prioceiling;
+} cthread_mutexattr_t;
+
+typedef struct {
+ char *w_lpName;
+ int w_bManualReset;
+ int w_bInitialState;
+
+ int p_pshared;
+ int p_clock;
+} cthread_condattr_t;
+
+/**
+ * Create a new thread.
+ *
+ * @param thread Pointer to the thread.
+ * @param attr Pointer to the thread attributes. NULL for default attributes.
+ * @param func Pointer to the function that will be executed in the new thread.
+ * @param arg Pointer to the data that will be passed to the thread function.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_create(cthread_t *thread, cthread_attr_t *attr,
+ void *(*func)(void *), void *arg);
+
+/**
+ * Join with a terminated thread.
+ *
+ * @param thread The thread to be joined.
+ * @param retval Pointer to store the exit code of the joined thread.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_join(cthread_t thread, void **retval);
+
+/**
+ * Detach a thread.
+ *
+ * @param thread Pointer to the thread.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_detach(cthread_t thread);
+
+/**
+ * Compares two threads for equality.
+ *
+ * @param t1 First thread to compare.
+ * @param t2 Second thread to compare.
+ * @return Non-zero if the threads are equal, zero otherwise.
+ */
+int cthread_equal(cthread_t t1, cthread_t t2);
+
+/**
+ * Obtain ID of the current thread.
+ *
+ * @return Thread ID of the current thread.
+ */
+cthread_t cthread_self(void);
+
+/**
+ * Terminate the current thread.
+ *
+ * @param retval Pointer to store the thread exit code.
+ */
+void cthread_exit(void *retval);
+
+/**
+ * Initialize a mutex.
+ *
+ * @param mutex Pointer to the mutex.
+ * @param attr Pointer to the mutex attributes. NULL for default attributes.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_mutex_init(cthread_mutex_t *mutex, cthread_mutexattr_t *attr);
+
+/**
+ * Lock a mutex.
+ *
+ * @param mutex Pointer to the mutex.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_mutex_lock(cthread_mutex_t *mutex);
+
+/**
+ * Try to lock a mutex without blocking.
+ *
+ * @param mutex Pointer to the mutex.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_mutex_trylock(cthread_mutex_t *mutex);
+
+/**
+ * Unlock a mutex.
+ *
+ * @param mutex Pointer to the mutex.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_mutex_unlock(cthread_mutex_t *mutex);
+
+/**
+ * Destroy a mutex.
+ *
+ * @param mutex Pointer to the mutex.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_mutex_destroy(cthread_mutex_t *mutex);
+
+/**
+ * Initialize a condition.
+ *
+ * @param cond Pointer to the condition.
+ * @param attr Pointer to the condition attributes. NULL for default.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_cond_init(cthread_cond_t *cond, cthread_condattr_t *attr);
+
+/**
+ * Signal a condition.
+ *
+ * @param cond Pointer to the condition.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_cond_signal(cthread_cond_t *cond);
+
+/**
+ * Broadcast a condition.
+ *
+ * @param cond Pointer to the condition.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_cond_broadcast(cthread_cond_t *cond);
+
+/**
+ * Wait on a condition.
+ *
+ * @param cond Pointer to the condition.
+ * @param mutex Pointer to the associated mutex.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_cond_wait(cthread_cond_t *cond, cthread_mutex_t *mutex);
+
+/**
+ * Destroy a condition.
+ *
+ * @param cond Pointer to the condition.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_cond_destroy(cthread_cond_t *cond);
+
+/**
+ * Initialize a read-write lock.
+ *
+ * @param rwlock Pointer to the read-write lock.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_rwlock_init(cthread_rwlock_t *rwlock);
+
+/**
+ * Lock a read-write lock for reading.
+ *
+ * @param rwlock Pointer to the read-write lock.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_rwlock_rdlock(cthread_rwlock_t *rwlock);
+
+/**
+ * Lock a read-write lock for writing.
+ *
+ * @param rwlock Pointer to the read-write lock.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_rwlock_wrlock(cthread_rwlock_t *rwlock);
+
+/**
+ * Unlock a read-write lock.
+ *
+ * @param rwlock Pointer to the read-write lock.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_rwlock_unlock(cthread_rwlock_t *rwlock);
+
+/**
+ * Destroy a read-write lock.
+ *
+ * @param rwlock Pointer to the read-write lock.
+ * @return 0 on success, non-zero error code on failure.
+ */
+int cthread_rwlock_destroy(cthread_rwlock_t *rwlock);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CTHREAD_H */
diff --git a/libre/dalloc/dalloc.c b/libre/dalloc/dalloc.c
new file mode 100644
index 0000000..46fb5c9
--- /dev/null
+++ b/libre/dalloc/dalloc.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright © 2023, Ratakor <ratakor@disroot.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DALLOC
+#define NO_DALLOC "dalloc: Define `DALLOC` to enable dalloc"
+#else
+void dalloc_check_all(void) __attribute__((destructor));
+#undef DALLOC
+#endif /* DALLOC */
+#include "../libre.h"
+
+#define OVER_ALLOC 64
+#define MAGIC_NUMBER 0x99
+#define EXIT_STATUS 9
+#define MAX_POINTERS 1024
+#define COMMENT_MAX 128
+#ifndef PATH_MAX
+#define PATH_MAX 256
+#endif /* PATH_MAX */
+
+struct Pointer {
+ void *p;
+ size_t siz;
+ char comment[COMMENT_MAX];
+ int ignored;
+ char file[PATH_MAX];
+ int line;
+};
+
+static int overflow(unsigned char *p, size_t siz);
+static size_t find_pointer_index(void *p, char *file, int line);
+
+static cthread_mutex_t dalloc_mutex = CTHREAD_MUTEX_INITIALIZER;
+static struct Pointer pointers[MAX_POINTERS];
+static size_t npointers;
+
+static int
+overflow(unsigned char *p, size_t siz)
+{
+ size_t i = 0;
+
+ while (p[siz + i] == MAGIC_NUMBER && ++i < OVER_ALLOC);
+
+ return i < OVER_ALLOC;
+}
+
+static size_t
+find_pointer_index(void *p, char *file, int line)
+{
+ size_t i = npointers;
+
+ while (i-- > 0 && p != pointers[i].p);
+
+ if (i == (size_t) -1) {
+ fprintf(stderr, "%s:%d: dalloc: Unknown pointer %p\n",
+ file, line, p);
+ cthread_mutex_unlock(&dalloc_mutex);
+ exit(EXIT_STATUS);
+ }
+
+ return i;
+}
+
+size_t
+dalloc_check_overflow(void)
+{
+ size_t i, sum = 0;
+
+#ifdef NO_DALLOC
+ fprintf(stderr, "%s\n", NO_DALLOC);
+ return 0;
+#endif /* NO_DALLOC */
+
+ cthread_mutex_lock(&dalloc_mutex);
+ fprintf(stderr, "Memory overflow:");
+ for (i = 0; i < npointers; i++) {
+ if (!overflow(pointers[i].p, pointers[i].siz))
+ continue;
+
+ sum++;
+ fprintf(stderr, "\n%s:%d: %p, total: %zu bytes",
+ pointers[i].file, pointers[i].line,
+ pointers[i].p, pointers[i].siz);
+ if (pointers[i].comment[0])
+ fprintf(stderr, " /* %s */", pointers[i].comment);
+ }
+ cthread_mutex_unlock(&dalloc_mutex);
+
+ if (sum == 0)
+ fprintf(stderr, " 0 overflow :)\n");
+ else
+ fprintf(stderr, "\nTotal overflow: %zu\n", sum);
+
+ return sum;
+}
+
+void
+dalloc_check_free(void)
+{
+ size_t i, sum = 0;
+
+#ifdef NO_DALLOC
+ fprintf(stderr, "%s\n", NO_DALLOC);
+ return;
+#endif /* NO_DALLOC */
+
+ cthread_mutex_lock(&dalloc_mutex);
+ fprintf(stderr, "Memory allocated and not freed:");
+ for (i = 0; i < npointers; i++) {
+ if (pointers[i].ignored)
+ continue;
+
+ sum += pointers[i].siz;
+ fprintf(stderr, "\n%s:%d: %p, %zu bytes",
+ pointers[i].file, pointers[i].line,
+ pointers[i].p, pointers[i].siz);
+ if (pointers[i].comment[0])
+ fprintf(stderr, " /* %s */", pointers[i].comment);
+ }
+ cthread_mutex_unlock(&dalloc_mutex);
+
+ if (sum == 0)
+ fprintf(stderr, " 0 byte :)\n");
+ else
+ fprintf(stderr, "\nTotal: %zu bytes, %zu pointers\n", sum, i);
+}
+
+void
+dalloc_check_all(void)
+{
+#ifdef NO_DALLOC
+ fprintf(stderr, "%s\n", NO_DALLOC);
+ return;
+#endif /* NO_DALLOC */
+
+ dalloc_check_overflow();
+ dalloc_check_free();
+}
+
+void
+dalloc_sighandler(int sig)
+{
+#ifdef _WIN32
+ fprintf(stderr, "dalloc: signal %d\n", sig);
+#else
+ fprintf(stderr, "dalloc: %s\n", strsignal(sig));
+#endif /* _WIN32 */
+
+#ifdef NO_DALLOC
+ fprintf(stderr, "%s\n", NO_DALLOC);
+#endif /* NO_DALLOC */
+
+ exit(EXIT_STATUS);
+}
+
+void
+___dalloc_ignore(void *p, char *file, int line)
+{
+ size_t i;
+
+#ifdef NO_DALLOC
+ return;
+#endif /* NO_DALLOC */
+
+ cthread_mutex_lock(&dalloc_mutex);
+ i = find_pointer_index(p, file, line);
+ pointers[i].ignored = 1;
+ cthread_mutex_unlock(&dalloc_mutex);
+}
+
+void
+___dalloc_comment(void *p, char *comment, char *file, int line)
+{
+ size_t i, j;
+
+#ifdef NO_DALLOC
+ return;
+#endif /* NO_DALLOC */
+
+ cthread_mutex_lock(&dalloc_mutex);
+ i = find_pointer_index(p, file, line);
+ for (j = 0; j < COMMENT_MAX && comment[j] != '\0'; j++)
+ pointers[i].comment[j] = comment[j];
+ pointers[i].comment[j] = '\0';
+ cthread_mutex_unlock(&dalloc_mutex);
+}
+
+void
+___free(void *p, char *file, int line)
+{
+ size_t i;
+
+ if (p == NULL)
+ return;
+
+ cthread_mutex_lock(&dalloc_mutex);
+ i = find_pointer_index(p, file, line);
+ if (overflow(pointers[i].p, pointers[i].siz)) {
+ fprintf(stderr, "%s:%d: dalloc: "
+ "Memory overflow on %p, total: %zu bytes\n",
+ file, line, pointers[i].p, pointers[i].siz);
+ fprintf(stderr, "The pointer ");
+ if (pointers[i].comment[0])
+ fprintf(stderr, "'%s' ", pointers[i].comment);
+ fprintf(stderr, "was allocated in '%s' on line %d.\n",
+ pointers[i].file, pointers[i].line);
+ cthread_mutex_unlock(&dalloc_mutex);
+ exit(EXIT_STATUS);
+ }
+
+ for (i++; i < npointers; i++)
+ pointers[i - 1] = pointers[i];
+ npointers--;
+ free(p);
+ cthread_mutex_unlock(&dalloc_mutex);
+}
+
+
+void *
+___malloc(size_t siz, char *file, int line)
+{
+ void *p = NULL;
+ size_t i;
+
+ if (siz == 0)
+ return NULL;
+
+ if (npointers == MAX_POINTERS) {
+ fprintf(stderr, "dalloc: Too much pointers (max:%d)\n",
+ MAX_POINTERS);
+ exit(EXIT_STATUS);
+ }
+
+ if (siz + OVER_ALLOC < OVER_ALLOC)
+ errno = ENOMEM;
+ else
+ p = malloc(siz + OVER_ALLOC);
+
+ if (p == NULL) {
+ fprintf(stderr, "%s:%d: dalloc: %s\n",
+ file, line, strerror(errno));
+ exit(EXIT_STATUS);
+ }
+
+ memset((unsigned char *)p + siz, MAGIC_NUMBER, OVER_ALLOC);
+ cthread_mutex_lock(&dalloc_mutex);
+ pointers[npointers].p = p;
+ pointers[npointers].siz = siz;
+ for (i = 0; i < PATH_MAX - 1 && file[i] != '\0'; i++)
+ pointers[npointers].file[i] = file[i];
+ pointers[npointers].file[i] = '\0';
+ pointers[npointers].line = line;
+ npointers++;
+ cthread_mutex_unlock(&dalloc_mutex);
+
+ return p;
+}
+
+void *
+___calloc(size_t nmemb, size_t siz, char *file, int line)
+{
+ void *p;
+
+ if (nmemb == 0 || siz == 0)
+ return NULL;
+
+ if (nmemb > -1 / siz) {
+ fprintf(stderr, "%s:%d: dalloc: calloc: %s\n",
+ file, line, strerror(ENOMEM));
+ exit(EXIT_STATUS);
+ }
+
+ siz *= nmemb;
+ p = ___malloc(siz, file, line);
+ memset(p, 0, siz);
+
+ return p;
+}
+
+void *
+___realloc(void *p, size_t siz, char *file, int line)
+{
+ size_t i, j;
+
+ if (p == NULL)
+ return ___malloc(siz, file, line);
+
+ if (siz == 0) {
+ ___free(p, file, line);
+ return NULL;
+ }
+
+ cthread_mutex_lock(&dalloc_mutex);
+ i = find_pointer_index(p, file, line);
+
+ if (overflow(pointers[i].p, pointers[i].siz)) {
+ fprintf(stderr, "%s:%d: dalloc: "
+ "Memory overflow on %p, total: %zu bytes\n",
+ file, line, pointers[i].p, pointers[i].siz);
+ fprintf(stderr, "The pointer ");
+ if (pointers[i].comment[0])
+ fprintf(stderr, "'%s' ", pointers[i].comment);
+ fprintf(stderr, "was allocated in '%s' on line %d.\n",
+ pointers[i].file, pointers[i].line);
+ cthread_mutex_unlock(&dalloc_mutex);
+ exit(EXIT_STATUS);
+ }
+
+ if (siz + OVER_ALLOC < OVER_ALLOC) {
+ p = NULL;
+ errno = ENOMEM;
+ } else {
+ p = realloc(p, siz + OVER_ALLOC);
+ }
+
+ if (p == NULL) {
+ fprintf(stderr, "%s:%d: dalloc: %s\n",
+ file, line, strerror(errno));
+ cthread_mutex_unlock(&dalloc_mutex);
+ exit(EXIT_STATUS);
+ }
+
+ memset((unsigned char *)p + siz, MAGIC_NUMBER, OVER_ALLOC);
+ pointers[i].p = p;
+ pointers[i].siz = siz;
+ for (j = 0; j < PATH_MAX - 1 && file[j] != '\0'; j++)
+ pointers[i].file[j] = file[j];
+ pointers[i].file[j] = '\0';
+ pointers[i].line = line;
+ cthread_mutex_unlock(&dalloc_mutex);
+
+ return p;
+}
+
+void *
+___reallocarray(void *p, size_t nmemb, size_t siz, char *file, int line)
+{
+ if (siz != 0 && nmemb > -1 / siz) {
+ fprintf(stderr, "%s:%d: dalloc: reallocarray: %s\n",
+ file, line, strerror(ENOMEM));
+ exit(EXIT_STATUS);
+ }
+
+ return ___realloc(p, nmemb * siz, file, line);
+}
+
+char *
+___strdup(const char *s, char *file, int line)
+{
+ char *p;
+ size_t siz;
+
+ siz = strlen(s) + 1;
+ p = ___malloc(siz, file, line);
+ memcpy(p, s, siz);
+
+ return p;
+}
+
+char *
+___strndup(const char *s, size_t n, char *file, int line)
+{
+ const char *end;
+ char *p;
+ size_t siz;
+
+ end = memchr(s, '\0', n);
+ siz = (end ? (size_t)(end - s) : n) + 1;
+ p = ___malloc(siz, file, line);
+ memcpy(p, s, siz - 1);
+ p[siz - 1] = '\0';
+
+ return p;
+}
+
+void
+exitsegv(int dummy)
+{
+ int *x = NULL;
+
+ dalloc_check_all();
+ *x = dummy;
+}
diff --git a/libre/dalloc/dalloc.h b/libre/dalloc/dalloc.h
new file mode 100644
index 0000000..c0fa081
--- /dev/null
+++ b/libre/dalloc/dalloc.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2023, Ratakor <ratakor@disroot.org>
+ *
+ * This library is free software. You can redistribute it and/or modify it
+ * under the terms of the ISC license. See dalloc.c for details.
+ */
+
+#ifndef DALLOC_H
+#define DALLOC_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef DALLOC
+#define free(p) (___free(p, __FILE__, __LINE__))
+#define malloc(siz) (___malloc(siz, __FILE__, __LINE__))
+#define calloc(nmemb, siz) (___calloc(nmemb, siz, __FILE__, __LINE__))
+#define realloc(p, siz) (___realloc(p, siz, __FILE__, __LINE__))
+#define reallocarray(p, n, s) (___reallocarray(p, n, s, __FILE__, __LINE__))
+#define strdup(s) (___strdup(s, __FILE__, __LINE__))
+#define strndup(s, n) (___strndup(s, n, __FILE__, __LINE__))
+
+#ifdef _UTIL_H
+#define emalloc(siz) (___malloc(siz, __FILE__, __LINE__))
+#define ecalloc(nmemb, siz) (___calloc(nmemb, siz, __FILE__, __LINE__))
+#define erealloc(p, siz) (___realloc(p, siz, __FILE__, __LINE__))
+#define ereallocarray(p, n, s) (___reallocarray(p, n, s, __FILE__, __LINE__))
+#define estrdup(s) (___strdup(s, __FILE__, __LINE__))
+#define estrndup(s, n) (___strndup(s, n, __FILE__, __LINE__))
+#endif /* _UTIL_H */
+#endif /* DALLOC */
+
+#ifdef EXITSEGV
+#define exit(dummy) (exitsegv(dummy))
+#endif /* EXITSEGV */
+
+#define dalloc_ignore(p) (___dalloc_ignore(p, __FILE__, __LINE__))
+#define dalloc_comment(p, com) (___dalloc_comment(p, com, __FILE__, __LINE__))
+
+size_t dalloc_check_overflow(void);
+void dalloc_check_free(void);
+void dalloc_check_all(void);
+void dalloc_sighandler(int sig);
+
+void ___dalloc_ignore(void *p, char *file, int line);
+void ___dalloc_comment(void *p, char *comment, char *file, int line);
+void ___free(void *p, char *file, int line);
+void *___malloc(size_t siz, char *file, int line);
+void *___calloc(size_t nmemb, size_t siz, char *file, int line);
+void *___realloc(void *p, size_t siz, char *file, int line);
+void *___reallocarray(void *p, size_t nmemb, size_t siz, char *file, int line);
+char *___strdup(const char *s, char *file, int line);
+char *___strndup(const char *s, size_t n, char *file, int line);
+
+void exitsegv(int dummy);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* DALLOC_H */
diff --git a/libre/libre.h b/libre/libre.h
new file mode 100644
index 0000000..a58fe78
--- /dev/null
+++ b/libre/libre.h
@@ -0,0 +1,8 @@
+#ifndef LIBRE_H
+#define LIBRE_H
+
+#include "util/util.h"
+#include "cthread/cthread.h"
+#include "dalloc/dalloc.h"
+
+#endif /* LIBRE_H */
diff --git a/src/util.c b/libre/util/util.c
index eb4998c..d9db063 100644
--- a/src/util.c
+++ b/libre/util/util.c
@@ -1,4 +1,4 @@
-/* Copywrong © 2023 Ratakor. See LICENSE file for license details. */
+/* Copyright © 2023 Ratakor. See LICENSE file for license details. */
#include <sys/stat.h>
@@ -12,11 +12,11 @@
#include "util.h"
size_t
-strlcpy(char *dst, const char *src, size_t siz)
+strlcpy(char *restrict dst, const char *restrict src, size_t siz)
{
const char *osrc = src;
- if (siz == 0)
+ if (UNLIKELY(siz == 0))
return strlen(src);
while (--siz != 0 && (*dst++ = *src++) != '\0');
@@ -51,7 +51,7 @@ estrlcpy(char *dst, const char *src, size_t siz)
}
size_t
-strlcat(char *dst, const char *src, size_t siz)
+strlcat(char *restrict dst, const char *restrict src, size_t siz)
{
size_t dsiz;
@@ -116,6 +116,15 @@ erealloc(void *p, size_t siz)
}
void *
+ereallocarray(void *p, size_t nmemb, size_t siz)
+{
+ if ((p = reallocarray(p, nmemb, siz)) == NULL)
+ err(1, "reallocarray");
+
+ return p;
+}
+
+void *
estrdup(const char *s)
{
char *p;
@@ -151,7 +160,7 @@ efopen(const char *filename, const char *mode)
char *
nstrchr(const char *s, int c, size_t n)
{
- if (n == 0)
+ if (UNLIKELY(n == 0))
return NULL;
do {
@@ -160,6 +169,7 @@ nstrchr(const char *s, int c, size_t n)
if (*s == c)
n--;
} while (*s++);
+
return NULL;
}
@@ -186,7 +196,7 @@ ufmt(char *dst, size_t dsiz, uint64_t n)
size_t
ifmt(char *dst, size_t dsiz, int64_t n)
{
- if (dsiz == 0)
+ if (UNLIKELY(dsiz == 0))
return ufmt(dst, dsiz, n);
if (n < 0) {
@@ -204,6 +214,7 @@ int
file_exists(const char *filename)
{
struct stat buf;
+
return (stat(filename, &buf) == 0);
}
diff --git a/src/util.h b/libre/util/util.h
index 060cce1..d0a75de 100644
--- a/src/util.h
+++ b/libre/util/util.h
@@ -1,29 +1,32 @@
-/* Copywrong © 2023 Ratakor. See LICENSE file for license details. */
+/* Copyright © 2023 Ratakor. See LICENSE file for license details. */
-#ifndef UTIL_H
-#define UTIL_H
+#ifndef _UTIL_H
+#define _UTIL_H
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
-#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
-#define STRLEN(X) (sizeof(X) - 1)
-#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
-#define UNUSED(X) ((void)(X))
+#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
+#define STRLEN(X) (sizeof(X) - 1)
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#define UNUSED(X) ((void)(X))
+#define LIKELY(X) __builtin_expect(!!(X), 1)
+#define UNLIKELY(X) __builtin_expect(!!(X), 0)
-size_t strlcpy(char *dst, const char *src, size_t siz);
+size_t strlcpy(char *restrict dst, const char *restrict src, size_t siz);
size_t wstrlcpy(char *dst, const char *src, size_t siz);
size_t estrlcpy(char *dst, const char *src, size_t siz);
-size_t strlcat(char *dst, const char *src, size_t siz);
+size_t strlcat(char *restrict dst, const char *restrict src, size_t siz);
size_t wstrlcat(char *dst, const char *src, size_t siz);
size_t estrlcat(char *dst, const char *src, size_t siz);
void *emalloc(size_t siz);
void *ecalloc(size_t nmemb, size_t siz);
void *erealloc(void *p, size_t siz);
+void *ereallocarray(void *p, size_t nmemb, size_t siz);
void *estrdup(const char *s);
void *estrndup(const char *s, size_t n);
FILE *efopen(const char *filename, const char *mode);
@@ -34,4 +37,4 @@ size_t ifmt(char *dst, size_t dsiz, int64_t n);
int file_exists(const char *filename);
time_t ltime(void);
-#endif /* UTIL_H */
+#endif /* _UTIL_H */
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..a5e7771
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,56 @@
+# Copywrong © 2023 Ratakor. See LICENSE file for license details.
+
+BIN = ../nolan
+CONFIG_H = ../config.h
+LIBRE_DIR = ../libre
+
+LIBRE_OBJS = ${LIBRE_DIR}/cthread.o \
+ ${LIBRE_DIR}/dalloc.o \
+ ${LIBRE_DIR}/util.o
+
+OBJS = cmd_correct.o \
+ cmd_help.o \
+ cmd_info.o \
+ cmd_lbraid.o \
+ cmd_leaderboard.o \
+ cmd_source.o \
+ cmd_uraid.o \
+ init.o \
+ main.o \
+ ocr.o \
+ raids.o \
+ roles.o \
+ run.o \
+ stats.o
+
+DISCORDLIBS = -ldiscord -lcurl -lpthread
+TESSLIBS = -ltesseract -lleptonica
+GDLIBS = -lgd -lpng -lz -ljpeg -lfreetype -lm
+
+WFLAGS = -Werror -Wall -Wextra -Wpedantic -Waggregate-return -Wshadow\
+ -Wmissing-prototypes -Wunused-macros -Wdouble-promotion
+DFLAGS = -O0 -g -DDALLOC
+CFLAGS += -std=c99 -D_DEFAULT_SOURCE ${WFLAGS}
+LDFLAGS += ${DISCORDLIBS} ${TESSLIBS} ${GDLIBS}
+
+all: ${BIN}
+
+echo:
+ @echo "CC = ${CC}"
+ @echo "CFLAGS = ${CFLAGS}"
+ @echo "LDFLAGS = ${LDFLAGS}"
+ @echo "OBJS = ${OBJS}"
+
+${BIN}: ${CONFIG_H} ${OBJS}
+ ${CC} ${OBJS} ${LIBRE_OBJS} ${LDFLAGS} -o $@
+
+${CONFIG_H}:
+ @cp ../config.def.h $@
+
+debug:
+ @CFLAGS="${DFLAGS}" ${MAKE}
+
+clean:
+ rm -f ${OBJS} ${BIN}
+
+.PHONY: all echo debug clean
diff --git a/src/main.c b/src/main.c
index efdc1fc..c6f96ab 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,8 @@
#include <concord/discord.h>
#include <concord/discord-internal.h>
+#include <signal.h>
+
#include "nolan.h"
Player players[MAX_PLAYERS];
@@ -56,6 +58,8 @@ main(void)
char *lb[] = { "lb", "leaderboard" };
struct discord *client;
+ signal(SIGINT, &dalloc_sighandler);
+
create_folders();
create_stats_file();
init_players();
diff --git a/src/nolan.h b/src/nolan.h
index a5416e2..036f352 100644
--- a/src/nolan.h
+++ b/src/nolan.h
@@ -7,7 +7,7 @@
#include <concord/log.h>
#include "../config.h"
-#include "util.h"
+#include "../libre/libre.h"
#define MAX_SLAYERS 50
#define LINE_SIZE 300 + 1
diff --git a/src/ocr.c b/src/ocr.c
index 94f8bad..c643fca 100644
--- a/src/ocr.c
+++ b/src/ocr.c
@@ -25,7 +25,6 @@ write_data(void *ptr, size_t size, size_t nmemb, void *stream)
return strlcpy(stream, ptr, MAX_MESSAGE_LEN);
}
-
char *
curl(char *url)
{