aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Makefile15
-rw-r--r--README.md104
-rw-r--r--chad.h13
-rw-r--r--chad/experimental/bits.h25
-rw-r--r--chad/experimental/nargs.h20
-rw-r--r--chad/experimental/strlist.h60
-rw-r--r--chad/experimental/terminal.h31
-rw-r--r--chad/narg.h55
-rw-r--r--extern/.gitkeep0
-rw-r--r--object/.gitkeep0
-rw-r--r--peru.yaml27
12 files changed, 354 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bf2dd55
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.so
+.peru/
+extern/
+object/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c4904f6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+SOURCE := $(wildcard chad/*.c extern/*.c)
+
+so:
+ ${CC} -fPIC -shared ${SOURCE} -o object/libchad.so
+
+dist:
+ -mkdir object/chad/
+ for d in chad/ extern/; do \
+ pushd $$d; \
+ find ./ -type f -name '*.h' -exec cp --parents {} ../object/chad/ \; ; \
+ popd; \
+ done
+
+clean:
+ -rm -frfr object/*
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1470d81
--- /dev/null
+++ b/README.md
@@ -0,0 +1,104 @@
+# Libchad
+> Who said you ought to reinvent the wheel?
+
+---
+
+## Rationele
+C libraries are hard to find; good libraries are even harder.
+
+## Contents
+
+> [!NOTE] `chad.h` includes all Chad libraries.
+
+| Lib | Description |
+| :--- | :---------- |
+| chad.h | Includes all Chad libraries. |
+| bits.h | Various miscellaneous functionalities. |
+
+### IO
+
+| Lib | Description |
+| :--- | :---------- |
+| dictate.h | Über-printer. |
+| plumblism.h | PBMplus (PNM) image IO. |
+
+### Datastructures
+
+| Lib | Description |
+| :--- | :---------- |
+| sds.h | Dynamic strings. |
+
+### Ported functionality
+
+| Lib | Lang | Description |
+| :--- | :---: | :---------- |
+| qx.h | Perl | Capture output of exec. |
+| remove\_all.h | C++ | Remove a directory recursively. |
+
+---
+
+## Experimental
+The mainline chad libraries are considered to have a stable API.
+They might get extended, but are not expected to change.
+Experimental libraries on the other hand are volatile.
+
+| Lib | Description |
+| :--- | :---------- |
+| bits.h | Various miscellaneous functionalities. |
+| kvec.h | Small, typesafe, generic datastructures optimized for speed. |
+
+## Criteria
+
+* A clear way in which the functionality can be described as.
+(e.g.: "generic datastructures" - good; "roguelike stuff" - bad)
+* Clean and simple interface which can be learned under a few minutes.
+Complexity has its place: within its own library.
+* Must be amalgamable into a single header.
+* No project-namespacing.
+
+## Todo
+* peru is nice as a concept, but 1) depends on py-yaml, 2) yaml makes make me vomit from my eyes
+* code
+ file filesystem.h {
+ int touch_file(const char * p);
+ int touch_directory(const char * p);
+ int touch(const char * p); // wrapper based on whether the last char is '/'
+
+ int copy_file(const char * s, const char * d);
+ int copy(const char * s, const char * d);
+ int copy_ex(const char * s, const char * d, int flags);
+
+ int remove(const char * p);
+ int remove_all(const char * p);
+
+ int rename(const char * s, const char * d);
+ }
+ file arena.h {
+ arena_t new_arena(size_t n_bytes);
+ void * arenaloc(arena_t * a, size_t n_bytes);
+ int free_arena(arena_t * a);
+ }
+ tree chad/
+ file nargs.h { // for narg hack functions?
+ #define coalesce_env() // char * _coalesce_env(char * mydefault, size_t argc, ...)
+ // maybe just coalesce()? that means every argument is eval-ed; maybe both
+ #define max()
+ #define min()
+ // all(), any()
+ // ?! i cant think of a single instance where its preferable over plain logic,
+ // but it would be consistent
+ }
+ # something addressing math.h
+ # gcd(), lcm(), sq() /*square, after ino*/
+ # trim() and pad() even tho its a meme
+ # MB(n) etc. macros
+ #
+ # the linux kernel has a bunch of small, high quality utilities,
+ # these should be inspected
+ # * minmax.h looks good; i wonder if it can be made N-arg
+ # in_range does not with in _there_
+ # * array_size.h looks good
+ # * DIV_ROUND_UP
+ # * base64.h
+ # * crc?
+ # * glob.h
diff --git a/chad.h b/chad.h
new file mode 100644
index 0000000..216791f
--- /dev/null
+++ b/chad.h
@@ -0,0 +1,13 @@
+#ifndef CHAD_H
+#define CHAD_H
+// internal code
+#include "chad/bits.h"
+#include "chad/terminal.h"
+#include "chad/dictate.h"
+#include "chad/qx.h"
+
+// external code
+#include "chad/sds.h"
+#include "chad/kvec.h"
+#include "chad/klist.h"
+#include "chad/remove_all.h"
diff --git a/chad/experimental/bits.h b/chad/experimental/bits.h
new file mode 100644
index 0000000..a1518e2
--- /dev/null
+++ b/chad/experimental/bits.h
@@ -0,0 +1,25 @@
+#ifndef CHAD_BITS_H
+#define CHAD_BITS_H
+
+#include <stdbool.h>
+#include <iso646>
+
+#define UNUSED(x) ((void)x)
+
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#define STRINGIFY(x) #x
+
+// could be a generic
+static inline
+long map(
+ long x,
+ long in_min,
+ long in_max,
+ long out_min,
+ long out_max
+) {
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+#endif
diff --git a/chad/experimental/nargs.h b/chad/experimental/nargs.h
new file mode 100644
index 0000000..c4224c9
--- /dev/null
+++ b/chad/experimental/nargs.h
@@ -0,0 +1,20 @@
+#ifndef CHAD_NARGS_H
+#define CHAD_NARGS_H
+
+#include "nargs.h"
+#include <stdarg.h>
+
+#define _max_function(T) \
+static inline _max_function_ ## T (size_t n, ...) { \
+ va_list args; \
+ va_start(args, n); \
+ T r = 0; \
+ for (size_t i = 0; i < n; i++) { \
+ T c =
+ if ()
+ } \
+
+ return r;
+}
+
+#endif
diff --git a/chad/experimental/strlist.h b/chad/experimental/strlist.h
new file mode 100644
index 0000000..f72e356
--- /dev/null
+++ b/chad/experimental/strlist.h
@@ -0,0 +1,60 @@
+/* The string based list is a common pattern,
+ * as it is the most intuitive way to serialize a list.
+ *
+ * In many languages you would handle it by instantiating
+ * an actual list by means of splitting,
+ * but in C we can often do better
+ * (and we dont have general lists to begin with).
+ *
+ * Examples would include:
+ * + file paths (a/b)
+ * + file extensions (a.b)
+ * + unix style option lists (a:b)
+ * + symbol hierarchies (a->b)
+ */
+
+typedef const char * const * const sep_t;
+sep_t UNIX_PATH_SEP = { "/", NULL, };
+sep_t DOS_PATH_SEP = { "\\", NULL, };
+sep_t UNIX_SEP = { ":", NULL, };
+sep_t CPP_SEP = { "::", ".", "->", NULL, };
+sep_t EXT_SEP = { ".", NULL, };
+
+size_t strlist_len(char * list, sep_t sep);
+
+/* This function in an abstract sense performs list indexing.
+ * The result overwrites the `list` argument and is returned.
+ * (We know that this may never result in an overflow.)
+ */
+char * strlist_component(char * list, size_t n, sep_t sep);
+/* This function returns a range.
+ */
+char * strlist_components(char * list, size_t from, size_t to, sep_t sep);
+
+/* The following are shorthands for component()/components(),
+ * with a specific numbers which may or may not be lenght specific
+ *
+ * Visual explanation:
+ * this/is/my/example/path
+ * Root <---------------->
+ * Base <-->
+ * Head <-->
+ * Tail <---------------->
+ */
+char * strlist_root(char * list, sep_t sep);
+char * strlist_base(char * list, sep_t sep);
+char * strlist_head(char * list, sep_t sep);
+char * strlist_tail(char * list, sep_t sep);
+
+/* Notes:
+ * + we very contiously made the decision to not take a destination operand;
+ * you would have to allocate it just the same,
+ * copying the source string is not a real performance concern,
+ * but we want our interface to be as clean as possible
+ */
+
+/* Example:
+ * Getting the absolute basename of a file.
+ * char name[] = "this/is/my.file.example";
+ * name = strlist_head(strlist_base(name, UNIX_PATH_SEP), EXT_SEP);
+ */
diff --git a/chad/experimental/terminal.h b/chad/experimental/terminal.h
new file mode 100644
index 0000000..e36ddf6
--- /dev/null
+++ b/chad/experimental/terminal.h
@@ -0,0 +1,31 @@
+#ifndef CHAD_TERMINAL_H
+#define CHAD_TERMINAL_H
+
+#define VT100_RESET "\033[0m"
+
+#define VT100_BOLD "\033[1m"
+#define VT100_ITALICS "\033[3m"
+#define VT100_REVERSE "\033[7m"
+
+#define VT100_FG_BLACK "\033[30m"
+#define VT100_FG_RED "\033[31m"
+#define VT100_FG_GREEN "\033[32m"
+#define VT100_FG_YELLOW "\033[33m"
+#define VT100_FG_BLUE "\033[34m"
+#define VT100_FG_MAGENTA "\033[35m"
+#define VT100_FG_CYAN "\033[36m"
+#define VT100_FG_WHITE "\033[37m"
+
+#define VT100_BG_BLACK "\033[40m"
+#define VT100_BG_RED "\033[41m"
+#define VT100_BG_GREEN "\033[42m"
+#define VT100_BG_YELLOW "\033[43m"
+#define VT100_BG_BLUE "\033[44m"
+#define VT100_BG_MAGENTA "\033[45m"
+#define VT100_BG_CYAN "\033[46m"
+#define VT100_BG_WHITE "\033[47m"
+
+#define VT100_SAVE_CUR "\033[s"
+#define VT100_RESTORE_CUR "\033[u"
+
+#endif
diff --git a/chad/narg.h b/chad/narg.h
new file mode 100644
index 0000000..a965e85
--- /dev/null
+++ b/chad/narg.h
@@ -0,0 +1,55 @@
+#ifndef NARG_H
+#define NARG_H
+
+/* A common problem when writting comfortable interfaces is that you want variable arguments,
+ but without the baggage.
+ Passing a terminator or the argument count is error prone.
+ This is a convenience header exactly for that.
+ The idea is that you define your function to take the argument count:
+ `_my_comfy_interface(int n, ...)`
+ Then you wrap it with our macro magick:
+ `#define my_comfy_interface _my_comfy_interface(NARG(__VA_ARGS__), __VA_ARGS__)`
+ And it just werks™.
+*/
+
+#define NARG(...) \
+ PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
+#define PP_NARG_(...) \
+ PP_128TH_ARG(__VA_ARGS__)
+#define PP_128TH_ARG( \
+ _1, _2, _3, _4, _5, _6, _7, _8, \
+ _9, _10, _11, _12, _13, _14, _15, _16, \
+ _17, _18, _19, _20, _21, _22, _23, _24, \
+ _25, _26, _27, _28, _29, _30, _31, _32, \
+ _33, _34, _35, _36, _37, _38, _39, _40, \
+ _41, _42, _43, _44, _45, _46, _47, _48, \
+ _49, _50, _51, _52, _53, _54, _55, _56, \
+ _57, _58, _59, _60, _61, _62, _63, _64, \
+ _65, _66, _67, _68, _69, _70, _71, _72, \
+ _73, _74, _75, _76, _77, _78, _79, _80, \
+ _81, _82, _83, _84, _85, _86, _87, _88, \
+ _89, _90, _91, _92, _93, _94, _95, _96, \
+ _97, _98, _99,_100,_101,_102,_103,_104, \
+ _105,_106,_107,_108,_109,_110,_111,_112, \
+ _113,_114,_115,_116,_117,_118,_119,_120, \
+ _121,_122,_123,_124,_125,_126,_127, N, ... \
+ ) N
+#define PP_RSEQ_N() \
+ 127,126,125,124,123,122,121,120, \
+ 119,118,117,116,115,114,113,112, \
+ 111,110,109,108,107,106,105,104, \
+ 103,102,101,100, 99, 98, 97, 96, \
+ 95, 94, 93, 92, 91, 90, 89, 88, \
+ 87, 86, 85, 84, 83, 82, 81, 80, \
+ 79, 78, 77, 76, 75, 74, 73, 72, \
+ 71, 70, 69, 68, 67, 66, 65, 64, \
+ 63, 62, 61, 60, 59, 58, 57, 56, \
+ 55, 54, 53, 52, 51, 50, 49, 48, \
+ 47, 46, 45, 44, 43, 42, 41, 40, \
+ 39, 38, 37, 36, 35, 34, 33, 32, \
+ 31, 30, 29, 28, 27, 26, 25, 24, \
+ 23, 22, 21, 20, 19, 18, 17, 16, \
+ 15, 14, 13, 12, 11, 10, 9, 8, \
+ 7, 6, 5, 4, 3, 2, 1, 0
+
+#endif
diff --git a/extern/.gitkeep b/extern/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/extern/.gitkeep
diff --git a/object/.gitkeep b/object/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/object/.gitkeep
diff --git a/peru.yaml b/peru.yaml
new file mode 100644
index 0000000..f729f37
--- /dev/null
+++ b/peru.yaml
@@ -0,0 +1,27 @@
+imports:
+ dictate: extern/
+ qx: extern/
+ remove_all: extern/
+ sds: extern/
+ kvec: extern/experimental/
+
+git module dictate:
+ url: https://github.com/agvxov/dictate.git
+ export: source/
+ pick: source/
+
+git module kvec:
+ url: https://bis64wqhh3louusbd45iyj76kmn4rzw5ysawyan5bkxwyzihj67c5lid.onion/anon/kvec.git
+ pick: [kvec.h, klist.h]
+
+git module qx:
+ url: https://github.com/agvxov/qx.git
+ pick: qx.h
+
+git module remove_all:
+ url: https://github.com/agvxov/remove_all.git
+ pick: remove_all.h
+
+git module sds:
+ url: https://github.com/jcorporation/sds.git
+ pick: [sds.c, sds.h, sdsalloc.h]