From 2f381d9c24c1418af5b27243428622d4a2b9c467 Mon Sep 17 00:00:00 2001 From: anon Date: Wed, 2 Jul 2025 09:52:28 +0200 Subject: init --- .gitignore | 4 ++ Makefile | 15 +++++++ README.md | 104 +++++++++++++++++++++++++++++++++++++++++++ chad.h | 13 ++++++ chad/experimental/bits.h | 25 +++++++++++ chad/experimental/nargs.h | 20 +++++++++ chad/experimental/strlist.h | 60 +++++++++++++++++++++++++ chad/experimental/terminal.h | 31 +++++++++++++ chad/narg.h | 55 +++++++++++++++++++++++ extern/.gitkeep | 0 object/.gitkeep | 0 peru.yaml | 27 +++++++++++ 12 files changed, 354 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 chad.h create mode 100644 chad/experimental/bits.h create mode 100644 chad/experimental/nargs.h create mode 100644 chad/experimental/strlist.h create mode 100644 chad/experimental/terminal.h create mode 100644 chad/narg.h create mode 100644 extern/.gitkeep create mode 100644 object/.gitkeep create mode 100644 peru.yaml 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 +#include + +#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 + +#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 diff --git a/object/.gitkeep b/object/.gitkeep new file mode 100644 index 0000000..e69de29 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] -- cgit v1.2.3