aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/__charN_t.h10
-rw-r--r--include/__qmacros.h25
-rw-r--r--include/__rune.h8
-rw-r--r--include/alloc.h8
-rw-r--r--include/bitset.h17
-rw-r--r--include/bob.h48
-rw-r--r--include/dynarr.h49
-rw-r--r--include/errors.h22
-rw-r--r--include/macros.h22
-rw-r--r--include/mbstring.h53
-rw-r--r--include/rune.h36
11 files changed, 298 insertions, 0 deletions
diff --git a/include/__charN_t.h b/include/__charN_t.h
new file mode 100644
index 0000000..eca16b9
--- /dev/null
+++ b/include/__charN_t.h
@@ -0,0 +1,10 @@
+#ifndef MLIB___CHARN_T_H
+#define MLIB___CHARN_T_H
+
+#include <stdint.h>
+
+typedef unsigned char char8_t;
+typedef uint_least16_t char16_t;
+typedef uint_least32_t char32_t;
+
+#endif /* !MLIB___CHARN_T_H */
diff --git a/include/__qmacros.h b/include/__qmacros.h
new file mode 100644
index 0000000..d765864
--- /dev/null
+++ b/include/__qmacros.h
@@ -0,0 +1,25 @@
+#ifndef MLIB___QMACROS_H
+#define MLIB___QMACROS_H
+
+/* Macros for qualifier-preserving functions. These are wrappers around some
+ functions declared above which will return a const-qualified pointer if the
+ input string is const-qualified, and a non-const-qualified pointer otherwise.
+
+ The macros are taken from the N3020 proposal for C23. */
+
+/* clang-format off */
+#define _RUNE_PTR_IS_CONST(P) \
+ _Generic(1 ? (P) : (void *)(P), \
+ const void *: 1, \
+ default: 0)
+#define _RUNE_STATIC_IF(P, T, E) \
+ _Generic(&(char[!!(P) + 1]){0}, \
+ char(*)[2]: T, \
+ char(*)[1]: E)
+#define _RUNE_Q_PTR(T, F, S, ...) \
+ _RUNE_STATIC_IF(_RUNE_PTR_IS_CONST((S)), \
+ (const T *)(F)(__VA_ARGS__), \
+ (T *)(F)(__VA_ARGS__))
+/* clang-format on */
+
+#endif /* !MLIB___QMACROS_H */
diff --git a/include/__rune.h b/include/__rune.h
new file mode 100644
index 0000000..4011411
--- /dev/null
+++ b/include/__rune.h
@@ -0,0 +1,8 @@
+#ifndef MLIB___RUNE_H
+#define MLIB___RUNE_H
+
+#include <stdint.h>
+
+typedef uint_least32_t rune;
+
+#endif /* !MLIB___RUNE_H */
diff --git a/include/alloc.h b/include/alloc.h
new file mode 100644
index 0000000..920a9a8
--- /dev/null
+++ b/include/alloc.h
@@ -0,0 +1,8 @@
+#ifndef MLIB_ALLOC_H
+#define MLIB_ALLOC_H
+
+#include <stddef.h>
+
+void *bufalloc(void *, size_t, size_t);
+
+#endif /* !MLIB_ALLOC_H */
diff --git a/include/bitset.h b/include/bitset.h
new file mode 100644
index 0000000..397435f
--- /dev/null
+++ b/include/bitset.h
@@ -0,0 +1,17 @@
+#ifndef MLIB_BITSET_H
+#define MLIB_BITSET_H
+
+#include <limits.h>
+
+#define __MLIB_BITSLOT(x) ((x) / CHAR_BIT)
+#define __MLIB_BITMASK(x) (1 << ((x) % CHAR_BIT))
+#define __MLIB_BITIMPL(bs, x, op) ((bs)[__MLIB_BITSLOT(x)] op __MLIB_BITMASK(x))
+
+#define bitset(name, n) unsigned char name[(n + CHAR_BIT - 1) / CHAR_BIT]
+
+#define BITCLR(bs, x) __MLIB_BITIMPL(bs, x, &=~)
+#define BITSET(bs, x) __MLIB_BITIMPL(bs, x, |=)
+#define BITTOGL(bs, x) __MLIB_BITIMPL(bs, x, ^=)
+#define BITTEST(bs, x) (bool)__MLIB_BITIMPL(bs, x, &)
+
+#endif /* !MLIB_BITSET_H */
diff --git a/include/bob.h b/include/bob.h
new file mode 100644
index 0000000..f2fb429
--- /dev/null
+++ b/include/bob.h
@@ -0,0 +1,48 @@
+#ifndef MLIB_BOB_H
+#define MLIB_BOB_H
+
+#include <stddef.h>
+
+#include "__charN_t.h"
+#include "__rune.h"
+
+#if !__MLIB_HAS_U8VIEW
+# define __MLIB_HAS_U8VIEW 1
+
+struct u8view {
+ const char8_t *p;
+ size_t len;
+};
+#endif
+
+struct u8str {
+ char8_t *p;
+ size_t len, cap;
+};
+
+struct u8str *u8strinit(struct u8str *, size_t);
+struct u8str *u8strgrow(struct u8str *, size_t);
+struct u8str *u8strfit(struct u8str *);
+void u8strfree(struct u8str);
+
+struct u8str *u8strpushr(struct u8str *, rune);
+struct u8str *u8strpushstr(struct u8str *, const char *);
+struct u8str *u8strpushu8(struct u8str *, struct u8view);
+
+[[gnu::always_inline]]
+static inline struct u8view
+u8strtou8(struct u8str s)
+{
+ return (struct u8view){.p = s.p, .len = s.len};
+}
+
+#define u8strpush(sb, x) \
+ _Generic((x), \
+ char: u8strpushr, \
+ int: u8strpushr, \
+ rune: u8strpushr, \
+ char *: u8strpushstr, \
+ struct u8view: u8strpushu8 \
+ )((sb), (x))
+
+#endif /* !MLIB_BOB_H */
diff --git a/include/dynarr.h b/include/dynarr.h
new file mode 100644
index 0000000..3785e18
--- /dev/null
+++ b/include/dynarr.h
@@ -0,0 +1,49 @@
+#ifndef MLIB_DYNARR_H
+#define MLIB_DYNARR_H
+
+#include <string.h>
+
+#include "alloc.h"
+
+#define DAGROW(da, n) \
+ do { \
+ if ((n) > (a)->cap) { \
+ (a)->cap = (n); \
+ (a)->buf = bufalloc((a)->buf, (a)->cap, sizeof(*(a)->buf)); \
+ } \
+ } while (false)
+
+#define DAPUSH(da, x) \
+ do { \
+ if ((da)->len >= (da)->cap) { \
+ (da)->cap = (da)->cap ? (da)->cap * 2 : 1; \
+ (da)->buf = bufalloc((da)->buf, (da)->cap, sizeof(*(da)->buf)); \
+ } \
+ (da)->buf[(da)->len++] = (x); \
+ } while (false)
+
+#define DAEXTEND(da, xs, n) \
+ do { \
+ if ((da)->len + (n) >= (da)->cap) { \
+ do \
+ (da)->cap = (da)->cap ? (da)->cap * 2 : 1; \
+ while ((da)->len + (n) >= (da)->cap); \
+ (da)->buf = bufalloc((da)->buf, (da)->cap, sizeof(*(da)->buf)); \
+ } \
+ memcpy((da)->buf + (da)->len, (xs), (n)); \
+ (a)->len += (n); \
+ } while (false)
+
+#define DAREMOVE(da, i) DA_REMOVE_RANGE((a), (i), (i) + 1)
+
+#define DA_REMOVE_RANGE(da, i, j) \
+ do { \
+ memmove((da)->buf + (i), (da)->buf + (j), \
+ ((da)->len - (j)) * sizeof(*(da)->buf)); \
+ (da)->len -= j - i; \
+ } while (false)
+
+#define da_foreach(da, p) \
+ for (auto p = (da)->buf; (size_t)(p - (da)->buf) < (da)->len; p++)
+
+#endif /* !MLIB_DYNARR_H */
diff --git a/include/errors.h b/include/errors.h
new file mode 100644
index 0000000..00fe6dc
--- /dev/null
+++ b/include/errors.h
@@ -0,0 +1,22 @@
+#ifndef MLIB_ERRORS_H
+#define MLIB_ERRORS_H
+
+#include <stdarg.h>
+
+void setprogname(const char *);
+
+[[gnu::format(printf, 1, 2)]] void warn(const char *, ...);
+[[gnu::format(printf, 1, 2)]] void warnx(const char *, ...);
+void vwarn(const char *, va_list);
+void vwarnx(const char *, va_list);
+
+[[noreturn, gnu::format(printf, 1, 2)]] void err(const char *, ...);
+[[noreturn, gnu::format(printf, 1, 2)]] void errx(const char *, ...);
+[[noreturn, gnu::format(printf, 2, 3)]] void cerr(int, const char *, ...);
+[[noreturn, gnu::format(printf, 2, 3)]] void cerrx(int, const char *, ...);
+
+extern const char *__mlib_errors_progname;
+
+#define progname() (__mlib_errors_progname)
+
+#endif /* !MLIB_ERRORS_H */
diff --git a/include/macros.h b/include/macros.h
new file mode 100644
index 0000000..2b62625
--- /dev/null
+++ b/include/macros.h
@@ -0,0 +1,22 @@
+#ifndef MLIB_MACROS_H
+#define MLIB_MACROS_H
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+#define lengthof(a) (sizeof(a) / sizeof(*(a)))
+
+#define memeq(x, y, n) (!memcmp(x, y, n))
+#define streq(x, y) (!strcmp(x, y))
+#define u8eq(x, y) (!u8cmp(x, y))
+
+#ifdef NDEBUG
+# include <stddef.h>
+# define ASSUME(p) ((p) ? (void)0 : unreachable())
+#else
+# include "errors.h"
+# define ASSUME(p) ((p) ? (void)0 : warnx("%s:%s:%d: assumption ā€˜%sā€™ failed", \
+ __FILE__, __func__, __LINE__, #p))
+#endif
+
+#endif /* !MLIB_MACROS_H */
diff --git a/include/mbstring.h b/include/mbstring.h
new file mode 100644
index 0000000..ddeb514
--- /dev/null
+++ b/include/mbstring.h
@@ -0,0 +1,53 @@
+#ifndef MLIB_MBSTRING_H
+#define MLIB_MBSTRING_H
+
+#include <stddef.h>
+
+#include "__charN_t.h"
+#include "__qmacros.h"
+#include "__rune.h"
+
+#if !__MLIB_HAS_U8VIEW
+# define __MLIB_HAS_U8VIEW 1
+
+struct u8view {
+ const char8_t *p;
+ size_t len;
+};
+#endif
+
+#define U8_BYTE_1(x) (((x) & 0x80) == 0x00)
+#define U8_BYTE_2(x) (((x) & 0xE0) == 0xC0)
+#define U8_BYTE_3(x) (((x) & 0xF0) == 0xE0)
+#define U8_BYTE_4(x) (((x) & 0xF8) == 0xF0)
+#define U8_BYTE_C(x) (((x) & 0xC0) == 0x80)
+
+static const rune U8_1B_MAX = 0x00007FL;
+static const rune U8_2B_MAX = 0x0007FFL;
+static const rune U8_3B_MAX = 0x00FFFFL;
+static const rune U8_4B_MAX = 0x10FFFFL;
+
+#define PRIsU8 ".*s"
+#define U8_PRI_ARGS(sv) ((int)(sv).len), ((sv).p)
+
+char8_t *u8chk(const char8_t *, size_t);
+char8_t *u8chr(const char8_t *, rune, size_t);
+char8_t *u8rchr(const char8_t *, rune, size_t);
+int rtou8(char8_t *, rune, size_t);
+int u8cmp(struct u8view, struct u8view);
+int u8next(rune *, const char8_t **, size_t *);
+int u8prev(rune *, const char8_t **, const char8_t *);
+int u8tor(rune *, const char8_t *);
+size_t u8cspn(const char8_t *, size_t, const rune *, size_t);
+size_t u8len(const char8_t *, size_t);
+size_t u8spn(const char8_t *, size_t, const rune *, size_t);
+
+#if !_RUNE_NO_MACRO_WRAPPER
+# define u8chk(s, n) _RUNE_Q_PTR(char8_t, u8chk, (s), (s), (n))
+# define u8chr(s, ch, n) _RUNE_Q_PTR(char8_t, u8chr, (s), (s), (ch), (n))
+# define u8rchr(s, ch, n) _RUNE_Q_PTR(char8_t, u8rchr, (s), (s), (ch), (n))
+#endif
+
+static const int U8_LEN_MAX = 4;
+
+#endif /* !MLIB_MBSTRING_H */
diff --git a/include/rune.h b/include/rune.h
new file mode 100644
index 0000000..2f8ce59
--- /dev/null
+++ b/include/rune.h
@@ -0,0 +1,36 @@
+#ifndef MLIB_RUNE_H
+#define MLIB_RUNE_H
+
+#include <inttypes.h>
+
+#include "__rune.h"
+
+#define _RUNE_PRIDEF(c) PRI##c##LEAST32
+#define _RUNE_SCNDEF(c) SCN##c##LEAST32
+
+#ifdef PRIBLEAST32
+# define PRIBRUNE _RUNE_PRIDEF(B)
+#endif
+#define PRIbRUNE _RUNE_PRIDEF(b)
+#define PRIdRUNE _RUNE_PRIDEF(d)
+#define PRIiRUNE _RUNE_PRIDEF(i)
+#define PRIoRUNE _RUNE_PRIDEF(o)
+#define PRIuRUNE _RUNE_PRIDEF(u)
+#define PRIxRUNE _RUNE_PRIDEF(x)
+#define PRIXRUNE _RUNE_PRIDEF(X)
+
+#define SCNbRUNE _RUNE_SCNDEF(b)
+#define SCNdRUNE _RUNE_SCNDEF(d)
+#define SCNiRUNE _RUNE_SCNDEF(i)
+#define SCNuRUNE _RUNE_SCNDEF(u)
+#define SCNoRUNE _RUNE_SCNDEF(o)
+#define SCNxRUNE _RUNE_SCNDEF(x)
+
+#define RUNE_C(x) UINT32_C(x)
+
+static const rune ASCII_MAX = RUNE_C(0x00007F);
+static const rune LATIN1_MAX = RUNE_C(0x0000FF);
+static const rune RUNE_ERROR = RUNE_C(0x00FFFD);
+static const rune RUNE_MAX = RUNE_C(0x10FFFF);
+
+#endif /* !MLIB_RUNE_H */