X-Git-Url: https://git.distorted.org.uk/~mdw/runlisp/blobdiff_plain/e29834b853038e8c90dcfe8377f02431cad42fc5..7b8ff279e7304e41b243459d78c3b6703bb8c3f5:/lib.h diff --git a/lib.h b/lib.h new file mode 100644 index 0000000..2209c30 --- /dev/null +++ b/lib.h @@ -0,0 +1,319 @@ +/* -*-c-*- + * + * Common definitions for `runlisp' + * + * (c) 2020 Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Runlisp, a tool for invoking Common Lisp scripts. + * + * Runlisp is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * Runlisp is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with Runlisp. If not, see . + */ + +#ifndef LIB_H +#define LIB_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include + +/*----- Handy macros ------------------------------------------------------*/ + +#define N(v) (sizeof(v)/sizeof((v)[0])) + +#if defined(__GNUC__) +# define GCC_VERSION_P(maj, min) \ + (__GNUC__ > (maj) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min))) +#else +# define GCC_VERSION_P(maj, min) 0 +#endif + +#ifdef __clang__ +# define CLANG_VERSION_P(maj, min) \ + (__clang_major__ > (maj) || (__clang_major__ == (maj) && \ + __clang_minor__ >= (min))) +#else +# define CLANG_VERSION_P(maj, min) 0 +#endif + +#if GCC_VERSION_P(2, 5) || CLANG_VERSION_P(3, 3) +# define NORETURN __attribute__((__noreturn__)) +# define PRINTF_LIKE(fix, aix) __attribute__((__format__(printf, fix, aix))) +#endif + +#if GCC_VERSION_P(4, 0) || CLANG_VERSION_P(3, 3) +# define EXECL_LIKE(ntrail) __attribute__((__sentinel__(ntrail))) +#endif + +#define CTYPE_HACK(func, ch) (func((unsigned char)(ch))) +#define ISSPACE(ch) CTYPE_HACK(isspace, ch) +#define ISALNUM(ch) CTYPE_HACK(isalnum, ch) + +#define MEMCMP(x, op, y, n) (memcmp((x), (y), (n)) op 0) +#define STRCMP(x, op, y) (strcmp((x), (y)) op 0) +#define STRNCMP(x, op, y, n) (strncmp((x), (y), (n)) op 0) + +#define DISCARD(x) do if (x); while (0) + +#define END ((const char *)0) + +#ifndef SIZE_MAX +# define SIZE_MAX (-(size_t)1) +#endif + +/*----- Miscellany --------------------------------------------------------*/ + +extern int str_lt(const char */*a*/, size_t /*an*/, + const char */*b*/, size_t /*bn*/); + +/*----- Diagnostic utilities ----------------------------------------------*/ + +extern const char *progname; + +extern void set_progname(const char */*prog*/); +extern void vmoan(const char */*msg*/, va_list /*ap*/); +extern PRINTF_LIKE(1, 2) void moan(const char */*msg*/, ...); +extern NORETURN PRINTF_LIKE(1, 2) void lose(const char */*msg*/, ...); + +/*----- Memory allocation -------------------------------------------------*/ + +extern void *xmalloc(size_t /*n*/); +extern void *xrealloc(void */*p*/, size_t /*n*/); +extern char *xstrndup(const char */*p*/, size_t /*n*/); +extern char *xstrdup(const char */*p*/); + +/*----- Dynamic strings ---------------------------------------------------*/ + +struct dstr { + char *p; + size_t len, sz; +}; +#define DSTR_INIT { 0, 0, 0 } + +extern void dstr_init(struct dstr */*d*/); +extern void dstr_reset(struct dstr */*d*/); +extern void dstr_ensure(struct dstr */*d*/, size_t /*n*/); +extern void dstr_release(struct dstr */*d*/); +extern void dstr_putm(struct dstr */*d*/, const void */*p*/, size_t /*n*/); +extern void dstr_puts(struct dstr */*d*/, const char */*p*/); +extern void dstr_putc(struct dstr */*d*/, int /*ch*/); +extern void dstr_putz(struct dstr */*d*/); +extern void dstr_vputf(struct dstr */*d*/, + const char */*p*/, va_list /*ap*/); +extern PRINTF_LIKE(2, 3) + void dstr_putf(struct dstr */*d*/, const char */*p*/, ...); +extern int dstr_readline(struct dstr */*d*/, FILE */*fp*/); + +/*----- Dynamic vectors of strings ----------------------------------------*/ + +struct argv { + const char **v; + size_t o, n, sz; +}; +#define ARGV_INIT { 0, 0, 0, 0 } + +extern void argv_init(struct argv */*a*/v); +extern void argv_reset(struct argv */*av*/); +extern void argv_ensure(struct argv */*av*/, size_t /*n*/); +extern void argv_ensure_offset(struct argv */*av*/, size_t /*n*/); +extern void argv_release(struct argv */*av*/); +extern void argv_append(struct argv */*av*/, const char */*p*/); +extern void argv_appendz(struct argv */*av*/); +extern void argv_appendn(struct argv */*av*/, + const char *const */*v*/, size_t /*n*/); +extern void argv_appendav(struct argv */*av*/, const struct argv */*bv*/); +extern void argv_appendv(struct argv */*av*/, va_list /*ap*/); +extern EXECL_LIKE(0) void argv_appendl(struct argv */*av*/, ...); +extern void argv_prepend(struct argv */*av*/, const char */*p*/); +extern void argv_prependn(struct argv */*av*/, + const char *const */*v*/, size_t /*n*/); +extern void argv_prependav(struct argv */*av*/, const struct argv */*bv*/); +extern void argv_prependv(struct argv */*av*/, va_list /*ap*/); +extern EXECL_LIKE(0) void argv_prependl(struct argv */*av*/, ...); + +/*----- Treaps ------------------------------------------------------------*/ + +struct treap { + struct treap_node *root; +}; +#define TREAP_INIT { 0 } + +struct treap_node { + unsigned wt; + struct treap_node *left, *right; + char *k; size_t kn; +}; +#define TREAP_NODE_KEY(n) (((const struct treap_node *)(n))->k + 0) +#define TREAP_NODE_KEYLEN(n) (((const struct treap_node *)(n))->kn + 0) + +#define TREAP_PATHMAX 64 +struct treap_path { + struct treap_node **path[TREAP_PATHMAX]; + unsigned nsteps; +}; + +struct treap_iter { + struct treap_node *stack[TREAP_PATHMAX]; + unsigned sp; +}; + +extern void treap_init(struct treap */*t*/); +extern void *treap_lookup(const struct treap */*t*/, + const char */*k*/, size_t /*kn*/); +extern void *treap_probe(struct treap */*t*/, + const char */*k*/, size_t /*kn*/, + struct treap_path */*p*/); +extern void treap_insert(struct treap */*t*/, const struct treap_path */*p*/, + struct treap_node */*n*/, + const char */*k*/, size_t /*kn*/); +extern void *treap_remove(struct treap */*t*/, + const char */*k*/, size_t /*kn*/); +extern void treap_start_iter(struct treap */*t*/, struct treap_iter */*i*/); +extern void *treap_next(struct treap_iter */*i*/); +extern void treap_check(struct treap */*t*/); +extern void treap_dump(struct treap */*t*/); + +/*----- Configuration file parsing ----------------------------------------*/ + +struct config { + struct treap sections; + struct config_section *head, **tail; + struct config_section *fallback; +}; +#define CONFIG_INIT { TREAP_INIT, 0, 0 } + +struct config_section { + struct treap_node _node; + struct config_section *next; + struct config_section **parents; size_t nparents; + struct treap vars; + struct treap cache; +}; +#define CONFIG_SECTION_NAME(sect) TREAP_NODE_KEY(sect) +#define CONFIG_SECTION_NAMELEN(sect) TREAP_NODE_KEYLEN(sect) + +struct config_cache_entry { + struct treap_node _node; + unsigned f; +#define CF_OPEN 1u + struct config_var *var; +}; + +struct config_var { + struct treap_node _node; + char *file; unsigned line; + char *val; size_t n; + unsigned f; +}; +#define CONFIG_VAR_NAME(var) TREAP_NODE_KEY(var) +#define CONFIG_VAR_NAMELEN(var) TREAP_NODE_KEYLEN(var) +#define CF_LITERAL 1u +#define CF_EXPAND 2u +#define CF_OVERRIDE 4u + +struct config_section_iter { + struct config_section *sect; +}; + +struct config_var_iter { + struct treap_iter i; +}; + +extern void config_init(struct config */*conf*/); + +extern struct config_section *config_find_section(struct config */*conf*/, + unsigned /*f*/, + const char */*name*/); +extern struct config_section *config_find_section_n(struct config */*conf*/, + unsigned /*f*/, + const char */*name*/, + size_t /*sz*/); +#define CF_CREAT 1u + +extern void config_set_fallback(struct config */*conf*/, + struct config_section */*sect*/); +extern void config_set_parent(struct config_section */*sect*/, + struct config_section */*parent*/); + +extern void config_start_section_iter(struct config */*conf*/, + struct config_section_iter */*i*/); +extern struct config_section *config_next_section + (struct config_section_iter */*i*/); + +extern struct config_var *config_find_var(struct config */*conf*/, + struct config_section */*sect*/, + unsigned /*f*/, + const char */*name*/); +extern struct config_var *config_find_var_n(struct config */*conf*/, + struct config_section */*sect*/, + unsigned /*f*/, + const char */*name*/, + size_t /*sz*/); +#define CF_INHERIT 2u + +extern void config_set_var(struct config */*conf*/, + struct config_section */*sect*/, unsigned /*f*/, + const char */*name*/, const char */*value*/); +extern void config_set_var_n(struct config */*conf*/, + struct config_section */*sect*/, unsigned /*f*/, + const char */*name*/, size_t /*namelen*/, + const char */*value*/, size_t /*valuelen*/); +extern void config_start_var_iter(struct config_section */*sect*/, + struct config_var_iter */*i*/); +extern struct config_var *config_next_var(struct config_var_iter */*i*/); + +extern int config_read_file(struct config */*conf*/, const char */*file*/, + unsigned /*f*/); +extern int config_read_dir(struct config */*conf*/, + const char */*dir*/, unsigned /*f*/); +extern void config_read_env(struct config */*conf*/, + struct config_section */*sect*/); +#define CF_NOENTOK 1u + +extern void config_subst_string(struct config */*config*/, + struct config_section */*home*/, + const char */*what*/, + const char */*p*/, struct dstr */*d*/); +extern char *config_subst_string_alloc(struct config */*config*/, + struct config_section */*home*/, + const char */*what*/, + const char */*p*/); +extern void config_subst_var(struct config */*config*/, + struct config_section */*home*/, + struct config_var */*var*/, + struct dstr */*d*/); +extern char *config_subst_var_alloc(struct config */*config*/, + struct config_section */*home*/, + struct config_var */*var*/); +extern void config_subst_split_var(struct config */*config*/, + struct config_section */*home*/, + struct config_var */*var*/, + struct argv */*av*/); + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif