@@@ work in progress
[runlisp] / lib.h
diff --git a/lib.h b/lib.h
new file mode 100644 (file)
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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIB_H
+#define LIB_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+
+/*----- 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