| 1 | /* -*-c-*- |
| 2 | * |
| 3 | * Common definitions for `runlisp' |
| 4 | * |
| 5 | * (c) 2020 Mark Wooding |
| 6 | */ |
| 7 | |
| 8 | /*----- Licensing notice --------------------------------------------------* |
| 9 | * |
| 10 | * This file is part of Runlisp, a tool for invoking Common Lisp scripts. |
| 11 | * |
| 12 | * Runlisp is free software: you can redistribute it and/or modify it |
| 13 | * under the terms of the GNU General Public License as published by the |
| 14 | * Free Software Foundation; either version 3 of the License, or (at your |
| 15 | * option) any later version. |
| 16 | * |
| 17 | * Runlisp is distributed in the hope that it will be useful, but WITHOUT |
| 18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 20 | * for more details. |
| 21 | * |
| 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with Runlisp. If not, see <https://www.gnu.org/licenses/>. |
| 24 | */ |
| 25 | |
| 26 | #ifndef LIB_H |
| 27 | #define LIB_H |
| 28 | |
| 29 | #ifdef __cplusplus |
| 30 | extern "C" { |
| 31 | #endif |
| 32 | |
| 33 | /*----- Header files ------------------------------------------------------*/ |
| 34 | |
| 35 | #include <limits.h> |
| 36 | #include <stdarg.h> |
| 37 | #include <stddef.h> |
| 38 | #include <stdio.h> |
| 39 | |
| 40 | /*----- Handy macros ------------------------------------------------------*/ |
| 41 | |
| 42 | #define N(v) (sizeof(v)/sizeof((v)[0])) |
| 43 | |
| 44 | #if defined(__GNUC__) |
| 45 | # define GCC_VERSION_P(maj, min) \ |
| 46 | (__GNUC__ > (maj) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min))) |
| 47 | #else |
| 48 | # define GCC_VERSION_P(maj, min) 0 |
| 49 | #endif |
| 50 | |
| 51 | #ifdef __clang__ |
| 52 | # define CLANG_VERSION_P(maj, min) \ |
| 53 | (__clang_major__ > (maj) || (__clang_major__ == (maj) && \ |
| 54 | __clang_minor__ >= (min))) |
| 55 | #else |
| 56 | # define CLANG_VERSION_P(maj, min) 0 |
| 57 | #endif |
| 58 | |
| 59 | #if GCC_VERSION_P(2, 5) || CLANG_VERSION_P(3, 3) |
| 60 | # define NORETURN __attribute__((__noreturn__)) |
| 61 | # define PRINTF_LIKE(fix, aix) __attribute__((__format__(printf, fix, aix))) |
| 62 | #endif |
| 63 | |
| 64 | #if GCC_VERSION_P(4, 0) || CLANG_VERSION_P(3, 3) |
| 65 | # define EXECL_LIKE(ntrail) __attribute__((__sentinel__(ntrail))) |
| 66 | #endif |
| 67 | |
| 68 | #define CTYPE_HACK(func, ch) (func((unsigned char)(ch))) |
| 69 | #define ISSPACE(ch) CTYPE_HACK(isspace, ch) |
| 70 | #define ISALNUM(ch) CTYPE_HACK(isalnum, ch) |
| 71 | |
| 72 | #define MEMCMP(x, op, y, n) (memcmp((x), (y), (n)) op 0) |
| 73 | #define STRCMP(x, op, y) (strcmp((x), (y)) op 0) |
| 74 | #define STRNCMP(x, op, y, n) (strncmp((x), (y), (n)) op 0) |
| 75 | |
| 76 | #define DISCARD(x) do if (x); while (0) |
| 77 | |
| 78 | #define END ((const char *)0) |
| 79 | |
| 80 | #ifndef SIZE_MAX |
| 81 | # define SIZE_MAX (-(size_t)1) |
| 82 | #endif |
| 83 | |
| 84 | /*----- Miscellany --------------------------------------------------------*/ |
| 85 | |
| 86 | extern int str_lt(const char */*a*/, size_t /*an*/, |
| 87 | const char */*b*/, size_t /*bn*/); |
| 88 | |
| 89 | /*----- Diagnostic utilities ----------------------------------------------*/ |
| 90 | |
| 91 | extern const char *progname; |
| 92 | |
| 93 | extern void set_progname(const char */*prog*/); |
| 94 | extern void vmoan(const char */*msg*/, va_list /*ap*/); |
| 95 | extern PRINTF_LIKE(1, 2) void moan(const char */*msg*/, ...); |
| 96 | extern NORETURN PRINTF_LIKE(1, 2) void lose(const char */*msg*/, ...); |
| 97 | |
| 98 | /*----- Memory allocation -------------------------------------------------*/ |
| 99 | |
| 100 | extern void *xmalloc(size_t /*n*/); |
| 101 | extern void *xrealloc(void */*p*/, size_t /*n*/); |
| 102 | extern char *xstrndup(const char */*p*/, size_t /*n*/); |
| 103 | extern char *xstrdup(const char */*p*/); |
| 104 | |
| 105 | /*----- Dynamic strings ---------------------------------------------------*/ |
| 106 | |
| 107 | struct dstr { |
| 108 | char *p; |
| 109 | size_t len, sz; |
| 110 | }; |
| 111 | #define DSTR_INIT { 0, 0, 0 } |
| 112 | |
| 113 | extern void dstr_init(struct dstr */*d*/); |
| 114 | extern void dstr_reset(struct dstr */*d*/); |
| 115 | extern void dstr_ensure(struct dstr */*d*/, size_t /*n*/); |
| 116 | extern void dstr_release(struct dstr */*d*/); |
| 117 | extern void dstr_putm(struct dstr */*d*/, const void */*p*/, size_t /*n*/); |
| 118 | extern void dstr_puts(struct dstr */*d*/, const char */*p*/); |
| 119 | extern void dstr_putc(struct dstr */*d*/, int /*ch*/); |
| 120 | extern void dstr_putz(struct dstr */*d*/); |
| 121 | extern void dstr_vputf(struct dstr */*d*/, |
| 122 | const char */*p*/, va_list /*ap*/); |
| 123 | extern PRINTF_LIKE(2, 3) |
| 124 | void dstr_putf(struct dstr */*d*/, const char */*p*/, ...); |
| 125 | extern int dstr_readline(struct dstr */*d*/, FILE */*fp*/); |
| 126 | |
| 127 | /*----- Dynamic vectors of strings ----------------------------------------*/ |
| 128 | |
| 129 | struct argv { |
| 130 | const char **v; |
| 131 | size_t o, n, sz; |
| 132 | }; |
| 133 | #define ARGV_INIT { 0, 0, 0, 0 } |
| 134 | |
| 135 | extern void argv_init(struct argv */*a*/v); |
| 136 | extern void argv_reset(struct argv */*av*/); |
| 137 | extern void argv_ensure(struct argv */*av*/, size_t /*n*/); |
| 138 | extern void argv_ensure_offset(struct argv */*av*/, size_t /*n*/); |
| 139 | extern void argv_release(struct argv */*av*/); |
| 140 | extern void argv_append(struct argv */*av*/, const char */*p*/); |
| 141 | extern void argv_appendz(struct argv */*av*/); |
| 142 | extern void argv_appendn(struct argv */*av*/, |
| 143 | const char *const */*v*/, size_t /*n*/); |
| 144 | extern void argv_appendav(struct argv */*av*/, const struct argv */*bv*/); |
| 145 | extern void argv_appendv(struct argv */*av*/, va_list /*ap*/); |
| 146 | extern EXECL_LIKE(0) void argv_appendl(struct argv */*av*/, ...); |
| 147 | extern void argv_prepend(struct argv */*av*/, const char */*p*/); |
| 148 | extern void argv_prependn(struct argv */*av*/, |
| 149 | const char *const */*v*/, size_t /*n*/); |
| 150 | extern void argv_prependav(struct argv */*av*/, const struct argv */*bv*/); |
| 151 | extern void argv_prependv(struct argv */*av*/, va_list /*ap*/); |
| 152 | extern EXECL_LIKE(0) void argv_prependl(struct argv */*av*/, ...); |
| 153 | |
| 154 | /*----- Treaps ------------------------------------------------------------*/ |
| 155 | |
| 156 | struct treap { |
| 157 | struct treap_node *root; |
| 158 | }; |
| 159 | #define TREAP_INIT { 0 } |
| 160 | |
| 161 | struct treap_node { |
| 162 | unsigned wt; |
| 163 | struct treap_node *left, *right; |
| 164 | char *k; size_t kn; |
| 165 | }; |
| 166 | #define TREAP_NODE_KEY(n) (((const struct treap_node *)(n))->k + 0) |
| 167 | #define TREAP_NODE_KEYLEN(n) (((const struct treap_node *)(n))->kn + 0) |
| 168 | |
| 169 | #define TREAP_PATHMAX 64 |
| 170 | struct treap_path { |
| 171 | struct treap_node **path[TREAP_PATHMAX]; |
| 172 | unsigned nsteps; |
| 173 | }; |
| 174 | |
| 175 | struct treap_iter { |
| 176 | struct treap_node *stack[TREAP_PATHMAX]; |
| 177 | unsigned sp; |
| 178 | }; |
| 179 | |
| 180 | extern void treap_init(struct treap */*t*/); |
| 181 | extern void *treap_lookup(const struct treap */*t*/, |
| 182 | const char */*k*/, size_t /*kn*/); |
| 183 | extern void *treap_probe(struct treap */*t*/, |
| 184 | const char */*k*/, size_t /*kn*/, |
| 185 | struct treap_path */*p*/); |
| 186 | extern void treap_insert(struct treap */*t*/, const struct treap_path */*p*/, |
| 187 | struct treap_node */*n*/, |
| 188 | const char */*k*/, size_t /*kn*/); |
| 189 | extern void *treap_remove(struct treap */*t*/, |
| 190 | const char */*k*/, size_t /*kn*/); |
| 191 | extern void treap_start_iter(struct treap */*t*/, struct treap_iter */*i*/); |
| 192 | extern void *treap_next(struct treap_iter */*i*/); |
| 193 | extern void treap_check(struct treap */*t*/); |
| 194 | extern void treap_dump(struct treap */*t*/); |
| 195 | |
| 196 | /*----- Configuration file parsing ----------------------------------------*/ |
| 197 | |
| 198 | struct config { |
| 199 | struct treap sections; |
| 200 | struct config_section *head, **tail; |
| 201 | struct config_section *fallback; |
| 202 | }; |
| 203 | #define CONFIG_INIT { TREAP_INIT, 0, 0 } |
| 204 | |
| 205 | struct config_section { |
| 206 | struct treap_node _node; |
| 207 | struct config_section *next; |
| 208 | struct config_section **parents; size_t nparents; |
| 209 | struct treap vars; |
| 210 | struct treap cache; |
| 211 | }; |
| 212 | #define CONFIG_SECTION_NAME(sect) TREAP_NODE_KEY(sect) |
| 213 | #define CONFIG_SECTION_NAMELEN(sect) TREAP_NODE_KEYLEN(sect) |
| 214 | |
| 215 | struct config_cache_entry { |
| 216 | struct treap_node _node; |
| 217 | unsigned f; |
| 218 | #define CF_OPEN 1u |
| 219 | struct config_var *var; |
| 220 | }; |
| 221 | |
| 222 | struct config_var { |
| 223 | struct treap_node _node; |
| 224 | char *file; unsigned line; |
| 225 | char *val; size_t n; |
| 226 | unsigned f; |
| 227 | }; |
| 228 | #define CONFIG_VAR_NAME(var) TREAP_NODE_KEY(var) |
| 229 | #define CONFIG_VAR_NAMELEN(var) TREAP_NODE_KEYLEN(var) |
| 230 | #define CF_LITERAL 1u |
| 231 | #define CF_EXPAND 2u |
| 232 | #define CF_OVERRIDE 4u |
| 233 | |
| 234 | struct config_section_iter { |
| 235 | struct config_section *sect; |
| 236 | }; |
| 237 | |
| 238 | struct config_var_iter { |
| 239 | struct treap_iter i; |
| 240 | }; |
| 241 | |
| 242 | extern void config_init(struct config */*conf*/); |
| 243 | |
| 244 | extern struct config_section *config_find_section(struct config */*conf*/, |
| 245 | unsigned /*f*/, |
| 246 | const char */*name*/); |
| 247 | extern struct config_section *config_find_section_n(struct config */*conf*/, |
| 248 | unsigned /*f*/, |
| 249 | const char */*name*/, |
| 250 | size_t /*sz*/); |
| 251 | #define CF_CREAT 1u |
| 252 | |
| 253 | extern void config_set_fallback(struct config */*conf*/, |
| 254 | struct config_section */*sect*/); |
| 255 | extern void config_set_parent(struct config_section */*sect*/, |
| 256 | struct config_section */*parent*/); |
| 257 | |
| 258 | extern void config_start_section_iter(struct config */*conf*/, |
| 259 | struct config_section_iter */*i*/); |
| 260 | extern struct config_section *config_next_section |
| 261 | (struct config_section_iter */*i*/); |
| 262 | |
| 263 | extern struct config_var *config_find_var(struct config */*conf*/, |
| 264 | struct config_section */*sect*/, |
| 265 | unsigned /*f*/, |
| 266 | const char */*name*/); |
| 267 | extern struct config_var *config_find_var_n(struct config */*conf*/, |
| 268 | struct config_section */*sect*/, |
| 269 | unsigned /*f*/, |
| 270 | const char */*name*/, |
| 271 | size_t /*sz*/); |
| 272 | #define CF_INHERIT 2u |
| 273 | |
| 274 | extern void config_set_var(struct config */*conf*/, |
| 275 | struct config_section */*sect*/, unsigned /*f*/, |
| 276 | const char */*name*/, const char */*value*/); |
| 277 | extern void config_set_var_n(struct config */*conf*/, |
| 278 | struct config_section */*sect*/, unsigned /*f*/, |
| 279 | const char */*name*/, size_t /*namelen*/, |
| 280 | const char */*value*/, size_t /*valuelen*/); |
| 281 | extern void config_start_var_iter(struct config_section */*sect*/, |
| 282 | struct config_var_iter */*i*/); |
| 283 | extern struct config_var *config_next_var(struct config_var_iter */*i*/); |
| 284 | |
| 285 | extern int config_read_file(struct config */*conf*/, const char */*file*/, |
| 286 | unsigned /*f*/); |
| 287 | extern int config_read_dir(struct config */*conf*/, |
| 288 | const char */*dir*/, unsigned /*f*/); |
| 289 | extern void config_read_env(struct config */*conf*/, |
| 290 | struct config_section */*sect*/); |
| 291 | #define CF_NOENTOK 1u |
| 292 | |
| 293 | extern void config_subst_string(struct config */*config*/, |
| 294 | struct config_section */*home*/, |
| 295 | const char */*what*/, |
| 296 | const char */*p*/, struct dstr */*d*/); |
| 297 | extern char *config_subst_string_alloc(struct config */*config*/, |
| 298 | struct config_section */*home*/, |
| 299 | const char */*what*/, |
| 300 | const char */*p*/); |
| 301 | extern void config_subst_var(struct config */*config*/, |
| 302 | struct config_section */*home*/, |
| 303 | struct config_var */*var*/, |
| 304 | struct dstr */*d*/); |
| 305 | extern char *config_subst_var_alloc(struct config */*config*/, |
| 306 | struct config_section */*home*/, |
| 307 | struct config_var */*var*/); |
| 308 | extern void config_subst_split_var(struct config */*config*/, |
| 309 | struct config_section */*home*/, |
| 310 | struct config_var */*var*/, |
| 311 | struct argv */*av*/); |
| 312 | |
| 313 | /*----- That's all, folks -------------------------------------------------*/ |
| 314 | |
| 315 | #ifdef __cplusplus |
| 316 | } |
| 317 | #endif |
| 318 | |
| 319 | #endif |