Commit | Line | Data |
---|---|---|
7b8ff279 MW |
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 |