diff options
| author | user <user@clank> | 2026-09-02 14:43:09 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-02 14:43:09 +0200 |
| commit | 18d1aef0f9bf4620135fd9f77f26683e6f2f8c00 (patch) | |
| tree | bf3ea334988ce03f61705ba9628941c175c1ee38 /src | |
| parent | web: the real site is the only site, and web/publish ships it (diff) | |
| download | slosh-18d1aef0f9bf4620135fd9f77f26683e6f2f8c00.tar.gz slosh-18d1aef0f9bf4620135fd9f77f26683e6f2f8c00.tar.xz slosh-18d1aef0f9bf4620135fd9f77f26683e6f2f8c00.zip | |
shaders: remove the .so plugin loader
The static musl release builds cannot dlopen -- musl compiles it out
-- so loadable shader plugins were a feature most shipped binaries
could not use. Nothing we ship used it either: every shader in
contrib/shaders is an expression. Gone: the dlopen/glob loader in
shader.c, shader_dir in the config, the plugin ABI table and entry
macro, the Windows dl*/glob shims that existed only for it, the
contrib/shader-plugin skeleton, its tests, and every doc mention.
shader_abi.h stays as the shader model (cell_t, shade_ctx_t,
shader_t) with a note about what it used to be.
Diffstat (limited to 'src')
| -rw-r--r-- | src/compat_win.c | 88 | ||||
| -rw-r--r-- | src/config.c | 37 | ||||
| -rw-r--r-- | src/shader.c | 148 |
3 files changed, 2 insertions, 271 deletions
diff --git a/src/compat_win.c b/src/compat_win.c index fcce416..7b5b914 100644 --- a/src/compat_win.c +++ b/src/compat_win.c @@ -603,94 +603,6 @@ int sl_spawn_detached(const char *const argv[], const char *logpath) { return (int)pi.dwProcessId; } -/* ---- dynamic loading ----------------------------------------------------- */ - -static char g_dlerr[256]; - -void *sl_dlopen(const char *path, int flags) { - (void)flags; - HMODULE h = LoadLibraryA(path); - if (!h) - snprintf(g_dlerr, sizeof g_dlerr, "LoadLibrary failed (%lu)", - (unsigned long)GetLastError()); - return (void *)h; -} -void *sl_dlsym(void *lib, const char *sym) { - FARPROC p = GetProcAddress((HMODULE)lib, sym); - if (!p) snprintf(g_dlerr, sizeof g_dlerr, "no symbol %s", sym); - return (void *)(uintptr_t)p; -} -int sl_dlclose(void *lib) { return FreeLibrary((HMODULE)lib) ? 0 : -1; } -const char *sl_dlerror(void) { return g_dlerr[0] ? g_dlerr : NULL; } - -/* ---- glob ---------------------------------------------------------------- */ - -/* Only what shader.c asks for: one directory, one wildcard in the last - * component. FindFirstFile does the matching. */ -int sl_glob(const char *pat, int flags, int (*errfn)(const char *, int), - glob_t *g) { - (void)flags; - (void)errfn; - if (!g) return GLOB_NOMATCH; - memset(g, 0, sizeof *g); - - char dir[PATH_MAX]; - snprintf(dir, sizeof dir, "%s", pat); - char *slash = strrchr(dir, '/'); - char *bslash = strrchr(dir, '\\'); - if (bslash > slash) slash = bslash; - if (slash) - *slash = 0; - else - dir[0] = 0; - - WIN32_FIND_DATAA fd; - HANDLE h = FindFirstFileA(pat, &fd); - if (h == INVALID_HANDLE_VALUE) return GLOB_NOMATCH; - - size_t cap = 16, n = 0; - char **v = (char **)malloc(cap * sizeof *v); - if (!v) { - FindClose(h); - return GLOB_NOMATCH; - } - do { - if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0) - continue; - if (n + 1 >= cap) { - cap *= 2; - char **nv = (char **)realloc(v, cap * sizeof *v); - if (!nv) break; - v = nv; - } - char full[PATH_MAX]; - if (dir[0]) - snprintf(full, sizeof full, "%s/%s", dir, fd.cFileName); - else - snprintf(full, sizeof full, "%s", fd.cFileName); - v[n] = _strdup(full); - if (v[n]) n++; - } while (FindNextFileA(h, &fd)); - FindClose(h); - - if (n == 0) { - free(v); - return GLOB_NOMATCH; - } - v[n] = NULL; - g->gl_pathc = n; - g->gl_pathv = v; - return 0; -} - -void sl_globfree(glob_t *g) { - if (!g || !g->gl_pathv) return; - for (size_t i = 0; i < g->gl_pathc; i++) free(g->gl_pathv[i]); - free(g->gl_pathv); - g->gl_pathv = NULL; - g->gl_pathc = 0; -} - /* ---- console ------------------------------------------------------------- */ static DWORD g_in_mode = 0, g_out_mode = 0; diff --git a/src/config.c b/src/config.c index f85ccb1..0c7af63 100644 --- a/src/config.c +++ b/src/config.c @@ -1169,7 +1169,6 @@ void config_free(config_t *c) { free(c->binds); free(c->shell); free(c->editor); - free(c->shader_dir); free(c->project_layout); for (size_t i = 0; i < c->nproject_roots; i++) free(c->project_roots[i]); for (size_t i = 0; i < c->nfiles; i++) free(c->files[i]); @@ -1655,10 +1654,6 @@ char *config_render(const config_t *c) { cb_qstr(&b, "editor", c->editor, NULL); else cb_add(&b, "// editor \"nvim\" // unset: $EDITOR, then vi\n"); - if (c->shader_dir) - cb_qstr(&b, "shader_dir", c->shader_dir, NULL); - else - cb_add(&b, "// shader_dir \"~/.config/slosh/shaders\"\n"); if (c->nproject_roots) { cb_add(&b, "project_roots"); for (size_t i = 0; i < c->nproject_roots; i++) { @@ -1878,7 +1873,6 @@ static const char *const KNOWN_TOP[] = { "scrollback", "scrollback_bytes", "select_scroll_ms", - "shader_dir", "shaders", "shell", "splash_ms", @@ -2214,37 +2208,6 @@ static bool load_into(config_t *c, const char *path, int depth, char *err, c->editor = strdup(ed); } - /* Shader plugins, before any shader is named below: a `shaders` block may - * use what one of these adds, and a name is looked up as it is parsed. The - * default is a directory beside this file, so dropping a `.so` next to the - * config is the whole installation procedure. */ - const char *sdir = kdl_arg(kdl_child(root, "shader_dir"), 0, NULL); - if (sdir) { - free(c->shader_dir); - c->shader_dir = strdup(sdir); - } - { - char dir[1024]; - if (c->shader_dir) { - char buf[1024]; - snprintf(dir, sizeof dir, "%s", - path_expand(c->shader_dir, buf, sizeof buf)); - } else { - snprintf(dir, sizeof dir, "%s", path); - char *slash = strrchr(dir, '/'); - if (slash) - slash[1] = 0; - else - dir[0] = 0; - snprintf(dir + strlen(dir), sizeof dir - strlen(dir), "shaders"); - } - char lerr[256] = {0}; - shader_load_dir(dir, lerr, sizeof lerr); - /* A plugin that will not load is worth a line, and worth nothing more: - * the config it came with still works, minus that effect (D9). */ - if (lerr[0]) complain(c, err, errcap, 0, "%s", lerr); - } - /* Where projects live. Several roots because people have `~/dev` and `~/work`, * and a `depth` property rather than a second node because it is one small * fixed record -- the same shape `min_pane cols=24 rows=6` uses. diff --git a/src/shader.c b/src/shader.c index 2cd5375..e6414cc 100644 --- a/src/shader.c +++ b/src/shader.c @@ -1,10 +1,7 @@ -/* The shader pass, the built-in shaders, and loading more of them from disk. - * See shader.h for the model and shader_abi.h for what a plugin sees. */ +/* The shader pass and the built-in shaders. See shader.h for the model. */ #define _GNU_SOURCE #include "shader.h" -#include <dlfcn.h> -#include <glob.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -163,28 +160,9 @@ static const shader_def_t REGISTRY[] = { #define NBUILTIN (sizeof REGISTRY / sizeof *REGISTRY) -/* ---- loaded shaders ----------------------------------------------------- - * - * Kept beside the built-ins rather than merged into them: a built-in is a - * fixed table the compiler can put in .rodata, and this is a list that grows - * at runtime. Lookup asks the built-ins first, so a plugin cannot shadow - * `dim` and change what every existing config means. - * - * Both the name and the function belong to the loaded library, which is why - * nothing here is ever freed or unloaded: a shader_t copied into a config or - * onto a pane holds both pointers. */ -static struct { - shader_def_t *defs; - size_t n, cap; - char **paths; /* what has been loaded, so a reload does not load it twice */ - size_t npaths, pathcap; -} LOADED; - static const shader_def_t *find_kind(const char *kind) { for (size_t i = 0; i < NBUILTIN; i++) if (strcmp(REGISTRY[i].name, kind) == 0) return ®ISTRY[i]; - for (size_t i = 0; i < LOADED.n; i++) - if (strcmp(LOADED.defs[i].name, kind) == 0) return &LOADED.defs[i]; return NULL; } @@ -209,129 +187,7 @@ bool shader_make_p(shader_t *out, const char *kind, color_t color, } const char *shader_kind(size_t i) { - if (i < NBUILTIN) return REGISTRY[i].name; - i -= NBUILTIN; - return i < LOADED.n ? LOADED.defs[i].name : NULL; -} - -/* ---- loading ------------------------------------------------------------ */ - -static bool already_loaded(const char *path) { - for (size_t i = 0; i < LOADED.npaths; i++) - if (strcmp(LOADED.paths[i], path) == 0) return true; - return false; -} - -static void remember_path(const char *path) { - if (LOADED.npaths == LOADED.pathcap) { - LOADED.pathcap = LOADED.pathcap ? LOADED.pathcap * 2 : 8; - LOADED.paths = realloc(LOADED.paths, LOADED.pathcap * sizeof *LOADED.paths); - } - LOADED.paths[LOADED.npaths++] = strdup(path); -} - -/* One library. Everything that can be wrong with it is checked before a - * single one of its shaders is registered, so a plugin is all-or-nothing: - * half a bundle is harder to explain than none of it. */ -static size_t load_one(const char *path, char *err, size_t errcap) { - void *lib = dlopen(path, RTLD_NOW | RTLD_LOCAL); - if (!lib) { - if (err && !err[0]) - snprintf(err, errcap, "%s: %s", path, dlerror() ? dlerror() : "dlopen"); - return 0; - } - - /* An object pointer is not a function pointer in ISO C, and dlsym returns - * the former. POSIX requires the conversion to work; the cast through a - * union is how it is written without the compiler being right to warn. */ - union { - void *obj; - const shader_plugin_t *(*fn)(void); - } entry = {.obj = dlsym(lib, SLOSH_SHADER_PLUGIN_SYM)}; - - if (!entry.obj) { - if (err && !err[0]) - snprintf(err, errcap, "%s: no " SLOSH_SHADER_PLUGIN_SYM, path); - dlclose(lib); - return 0; - } - - const shader_plugin_t *t = entry.fn(); - if (!t || t->abi != SLOSH_SHADER_ABI) { - if (err && !err[0]) - snprintf(err, errcap, "%s: shader ABI %u, we speak %u", path, - t ? t->abi : 0, SLOSH_SHADER_ABI); - dlclose(lib); - return 0; - } - /* The version says which contract; the sizes say whether the plugin really - * has that contract's structs. They differ when someone edits their copy of - * shader_abi.h, which a version number alone reports as fine and a running - * session reports as garbled colours or a crash. */ - if (t->cell_size != sizeof(cell_t) || t->ctx_size != sizeof(shade_ctx_t) || - t->shader_size != sizeof(shader_t)) { - if (err && !err[0]) - snprintf(err, errcap, "%s: built against different structs", path); - dlclose(lib); - return 0; - } - if (t->count && !t->shaders) { - if (err && !err[0]) snprintf(err, errcap, "%s: empty shader table", path); - dlclose(lib); - return 0; - } - - for (size_t i = 0; i < t->count; i++) { - const shader_def_t *d = &t->shaders[i]; - if (!d->name || !*d->name || !d->fn) { - if (err && !err[0]) snprintf(err, errcap, "%s: nameless shader", path); - continue; - } - if (find_kind(d->name)) { - /* Refused rather than replacing: a config naming `dim` means the `dim` - * it was written against, and a plugin that could redefine it would - * change effects nobody asked it to touch. */ - if (err && !err[0]) - snprintf(err, errcap, "%s: shader %s already exists", path, d->name); - continue; - } - if (LOADED.n == LOADED.cap) { - LOADED.cap = LOADED.cap ? LOADED.cap * 2 : 8; - LOADED.defs = realloc(LOADED.defs, LOADED.cap * sizeof *LOADED.defs); - } - LOADED.defs[LOADED.n++] = *d; - } - - /* The library stays mapped for the life of the session, on purpose: see - * shader_load_dir()'s comment in the header. */ - return t->count; -} - -size_t shader_load_dir(const char *dir, char *err, size_t errcap) { - if (err && errcap) err[0] = 0; - if (!dir || !*dir) return 0; - - char pattern[1024]; - snprintf(pattern, sizeof pattern, "%s/*.so", dir); - - glob_t g = {0}; - int rc = glob(pattern, 0, NULL, &g); - if (rc != 0) { - globfree(&g); - return 0; /* no directory, or nothing in it: the normal case */ - } - - size_t added = 0; - for (size_t i = 0; i < g.gl_pathc; i++) { - if (already_loaded(g.gl_pathv[i])) continue; - /* Remembered whether or not it loads. A library that fails today fails - * every reload, and saying so once is a warning while saying so on every - * save is a broken editor. */ - remember_path(g.gl_pathv[i]); - added += load_one(g.gl_pathv[i], err, errcap); - } - globfree(&g); - return added; + return i < NBUILTIN ? REGISTRY[i].name : NULL; } /* ---- the pass ----------------------------------------------------------- */ |
