2209c3038ffd5c0111077cb870777b127a8febea
[runlisp] / lib.h
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