1 /* -*- mode: c; mode: fold -*- */
2 # include "config.h"
3 # include <stdio.h>
4 # include <stdlib.h>
5 # include <ctype.h>
6 # include <string.h>
7 # include "pager.h"
8
9 /*{{{ typedefs */
10 typedef unsigned long hash_t;
11
12 typedef struct _entry {
13 hash_t hval;
14 char *var;
15 char *val;
16 struct _entry
17 *next;
18 } entry;
19
20 typedef struct _charc {
21 hash_t hval;
22 char *name;
23 struct _charc
24 *next;
25 } charc;
26
27 typedef struct _block {
28 # ifndef NDEBUG
29 # define MAGIC MKMAGIC ('c', 'f', 'g', '\0')
30 long magic;
31 # endif /* NDEBUG */
32 hash_t hval;
33 char *name;
34 charc *use;
35 Bool done;
36 entry *e;
37 char *sep;
38 int seplen;
39 struct _block
40 *next;
41 } block;
42
43 typedef struct _fifo {
44 void *dat;
45 struct _fifo
46 *next;
47 } fifo;
48
49 typedef struct _fpstack {
50 FILE *fp;
51 struct _fpstack
52 *up;
53 } fpstack;
54 /*}}}*/
55 /*{{{ support routines */
56 static hash_t
calc_hash(char * str)57 calc_hash (char *str)
58 {
59 hash_t hval;
60
61 for (hval = 0; *str; ) {
62 hval <<= 2;
63 hval += *str++ & 0xff;
64 hval >>= 1;
65 }
66 return hval;
67 }
68
69 static Bool
issame(hash_t h1,char * s1,hash_t h2,char * s2)70 issame (hash_t h1, char *s1, hash_t h2, char *s2)
71 {
72 if (h1 == h2)
73 if ((! s1) && (! s2))
74 return True;
75 else if (s1 && s2 && (s1[0] == s2[0]) && (! strcmp (s1, s2)))
76 return True;
77 return False;
78 }
79
80 static block *
new_block(char * bname,hash_t hval,char * sep)81 new_block (char *bname, hash_t hval, char *sep)
82 {
83 block *b;
84
85 if (b = (block *) malloc (sizeof (block))) {
86 b -> name = NULL;
87 if ((! bname) || (b -> name = strdup (bname))) {
88 b -> sep = NULL;
89 b -> seplen = 0;
90 if ((! sep) || (b -> sep = strdup (sep))) {
91 # ifndef NDEBUG
92 b -> magic = MAGIC;
93 # endif /* NDEBUG */
94 b -> hval = hval;
95 b -> use = NULL;
96 b -> done = False;
97 b -> e = NULL;
98 b -> next = NULL;
99 } else {
100 if (b -> name)
101 free (b -> name);
102 free (b);
103 b = NULL;
104 }
105 } else {
106 free (b);
107 b = NULL;
108 }
109 }
110 return b;
111 }
112
113 static void
add_entry(block * base,block * b,char * var,char * val)114 add_entry (block *base, block *b, char *var, char *val)
115 {
116 hash_t hval;
117 entry *e, *etmp;
118 Bool add;
119 char *sav;
120
121 if (b && var) {
122 if (*var == '+') {
123 ++var;
124 add = True;
125 } else
126 add = False;
127 hval = calc_hash (var);
128 for (e = b -> e; e; e = e -> next)
129 if (issame (hval, var, e -> hval, e -> var))
130 break;
131 if (e) {
132 if (e -> val)
133 if (add) {
134 if (val && *val) {
135 sav = e -> val;
136 if (e -> val = malloc (strlen (sav) + strlen (val) + base -> seplen + 2)) {
137 sprintf (e -> val, "%s%s%s", sav, (base -> sep ? base -> sep : ""), val);
138 free (sav);
139 val = NULL;
140 } else
141 e -> val = sav;
142 }
143 } else {
144 free (e -> val);
145 e -> val = NULL;
146 }
147 } else if (e = (entry *) malloc (sizeof (entry)))
148 if (e -> var = strdup (var)) {
149 e -> hval = hval;
150 e -> val = NULL;
151 e -> next = b -> e;
152 b -> e = e;
153 } else {
154 free (e);
155 e = NULL;
156 }
157 if (e && (! e -> val) && val && *val) {
158 if (add && (base != b)) {
159 for (etmp = base -> e; etmp; etmp = etmp -> next)
160 if (issame (hval, var, etmp -> hval, etmp -> var))
161 break;
162 if (etmp && etmp -> val)
163 if (e -> val = malloc (strlen (etmp -> val) + strlen (val) + base -> seplen + 2))
164 sprintf (e -> val, "%s%s%s", etmp -> val, (base -> sep ? base -> sep : ""), val);
165 }
166 if (! e -> val)
167 e -> val = strdup (val);
168 }
169 }
170 }
171 /*}}}*/
172 /*{{{ read configuration */
173 void *
cfg_new(char * sep)174 cfg_new (char *sep)
175 {
176 return (void *) new_block (NULL, 0, sep);
177 }
178
179 void *
cfg_read(char * fname,void * bp,char * sep)180 cfg_read (char *fname, void *bp, char *sep)
181 {
182 FILE *fp;
183 fpstack *fcur, *ftmp;
184 char *gline, *line;
185 char *ptr, *use;
186 charc *prv, *tmp;
187 block *base, *prev, *cur;
188 hash_t hval;
189 char *var, *val;
190 int plen;
191 Bool done;
192 int siz, len;
193 char *temp;
194
195 if (bp)
196 base = (block *) bp;
197 else
198 if (! (base = new_block (NULL, 0, sep)))
199 return NULL;
200 cur = base;
201 if (fp = fopen (fname, "r"))
202 if (fcur = (fpstack *) malloc (sizeof (fpstack))) {
203 fcur -> fp = fp;
204 fcur -> up = NULL;
205 while (fcur) {
206 while (gline = get_line (fcur -> fp, True)) {
207 for (line = gline; isspace (*line); ++line)
208 ;
209 if ((! *line) || (*line == '#')) {
210 free (gline);
211 continue;
212 }
213 if (*line == '[') {
214 use = NULL;
215 if (ptr = strchr (line, ']')) {
216 *ptr++ = '\0';
217 while (isspace (*ptr))
218 ++ptr;
219 if (*ptr)
220 use = ptr;
221 }
222 ptr = line + 1;
223 if (! *ptr)
224 cur = base;
225 else {
226 hval = calc_hash (ptr);
227 for (cur = base, prev = NULL; cur; cur = cur -> next)
228 if (issame (hval, ptr, cur -> hval, cur -> name))
229 break;
230 else
231 prev = cur;
232 if ((! cur) && (cur = new_block (ptr, hval, NULL)))
233 if (prev)
234 prev -> next = cur;
235 if (cur && use) {
236 if (cur -> use)
237 for (prv = cur -> use; prv -> next; prv = prv -> next)
238 ;
239 else
240 prv = NULL;
241 while (*use) {
242 ptr = use;
243 use = skipch (ptr, ',');
244 if (tmp = (charc *) malloc (sizeof (charc)))
245 if (tmp -> name = strdup (ptr)) {
246 tmp -> hval = 0;
247 tmp -> next = NULL;
248 if (prv)
249 prv -> next = tmp;
250 else
251 cur -> use = tmp;
252 prv = tmp;
253 } else
254 free (tmp);
255 }
256 }
257 }
258 if (! cur) {
259 free (gline);
260 break;
261 }
262 } else if (*line == '|') {
263 ++line;
264 while (isspace (*line))
265 ++line;
266 if (fp = fopen (line, "r"))
267 if (ftmp = (fpstack *) malloc (sizeof (fpstack))) {
268 ftmp -> fp = fp;
269 ftmp -> up = fcur;
270 fcur = ftmp;
271 } else
272 fclose (fp);
273 } else {
274 var = line;
275 val = skip (var);
276 if (var = strdup (var)) {
277 temp = NULL;
278 if ((*val == '{') && (! *(val + 1))) {
279 done = False;
280 siz = 0;
281 len = 0;
282 while (ptr = get_line (fcur -> fp, False)) {
283 if ((*ptr != '}') || *(ptr + 1)) {
284 plen = strlen (ptr);
285 if (len + plen + 2 >= siz) {
286 siz = len + plen + 256;
287 if (! (temp = Realloc (temp, siz + 2))) {
288 siz = 0;
289 done = True;
290 }
291 }
292 if (len + plen < siz) {
293 if (len)
294 temp[len++] = '\n';
295 strcpy (temp + len, ptr);
296 len += plen;
297 }
298 } else
299 done = True;
300 free (ptr);
301 if (done)
302 break;
303 }
304 if (temp) {
305 temp[len] = '\0';
306 val = temp;
307 } else
308 val = NULL;
309 } else if (*val == '\\')
310 ++val;
311 add_entry (base, cur, var, val);
312 if (temp)
313 free (temp);
314 free (var);
315 }
316 }
317 free (gline);
318 }
319 ftmp = fcur;
320 fcur = fcur -> up;
321 fclose (ftmp -> fp);
322 free (ftmp);
323 }
324 } else
325 fclose (fp);
326 return (void *) base;
327 }
328 /*}}}*/
329 /*{{{ add/change configuration */
330 void
cfg_modify(void * bp,char * bname,char * var,char * val)331 cfg_modify (void *bp, char *bname, char *var, char *val)
332 {
333 block *base = (block *) bp;
334 block *use, *prv;
335 hash_t hval;
336
337 MCHK (base);
338 if (base) {
339 if (! bname)
340 use = base;
341 else {
342 hval = calc_hash (bname);
343 for (use = base -> next, prv = base; use; use = use -> next)
344 if (issame (hval, bname, use -> hval, use -> name))
345 break;
346 else
347 prv = use;
348 if (! use)
349 use = new_block (bname, hval, NULL);
350 }
351 if (use)
352 add_entry (base, use, var, val);
353 }
354 }
355 /*}}}*/
356 /*{{{ end (free up) configuration */
357 void *
cfg_end(void * bp)358 cfg_end (void *bp)
359 {
360 block *b = (block *) bp;
361 block *tmp;
362 charc *run;
363 entry *e;
364
365 MCHK (b);
366 while (b) {
367 if (b -> name)
368 free (b -> name);
369 while (b -> use) {
370 run = b -> use;
371 b -> use = b -> use -> next;
372 if (run -> name)
373 free (run -> name);
374 free (run);
375 }
376 while (b -> e) {
377 e = b -> e;
378 b -> e = b -> e -> next;
379 if (e -> var)
380 free (e -> var);
381 if (e -> val)
382 free (e -> val);
383 free (e);
384 }
385 if (b -> sep)
386 free (b -> sep);
387 tmp = b;
388 b = b -> next;
389 free (tmp);
390 }
391 return NULL;
392 }
393 /*}}}*/
394 /*{{{ retrieving */
395 static char *
do_get(void * bp,char * bname,char * var,Bool glob,char * dflt)396 do_get (void *bp, char *bname, char *var, Bool glob, char *dflt)
397 {
398 block *b = (block *) bp;
399 block *run, *tmp;
400 entry *e;
401 fifo *f, *l, *ft;
402 charc *use;
403 char *ptr, *sav;
404 charc *vars, *vprv, *vtmp, *vrun;
405 Bool first;
406 hash_t hval;
407
408 MCHK (b);
409 if (! (var = strdup (var)))
410 return NULL;
411 vars = NULL;
412 vprv = NULL;
413 for (ptr = var; *ptr; ) {
414 sav = ptr;
415 ptr = skipch (ptr, ',');
416 if (vtmp = (charc *) malloc (sizeof (charc)))
417 if (vtmp -> name = strdup (sav)) {
418 vtmp -> hval = calc_hash (vtmp -> name);
419 vtmp -> next = NULL;
420 if (vprv)
421 vprv -> next = vtmp;
422 else
423 vars = vtmp;
424 vprv = vtmp;
425 } else
426 free (vtmp);
427 }
428 free (var);
429 if (! vars)
430 return NULL;
431 e = NULL;
432 f = NULL;
433 l = NULL;
434 first = True;
435 while ((! e) && bname) {
436 hval = calc_hash (bname);
437 for (run = b -> next; run; run = run -> next)
438 if (issame (hval, bname, run -> hval, run -> name))
439 break;
440 bname = NULL;
441 if (run && (first || (! run -> done))) {
442 for (vrun = vars; vrun; vrun = vrun -> next) {
443 for (e = run -> e; e; e = e -> next)
444 if (issame (vrun -> hval, vrun -> name, e -> hval, e -> var))
445 break;
446 if (e)
447 break;
448 }
449 if (! e) {
450 if (use = run -> use) {
451 if (first) {
452 for (tmp = b -> next; tmp; tmp = tmp -> next)
453 tmp -> done = False;
454 first = False;
455 }
456 for (; use; use = use -> next)
457 if (ft = (fifo *) malloc (sizeof (fifo))) {
458 ft -> dat = (void *) use;
459 ft -> next = NULL;
460 if (l)
461 l -> next = ft;
462 else {
463 f = ft;
464 l = ft;
465 }
466 } else
467 break;
468 }
469 if (f) {
470 ft = f;
471 f = f -> next;
472 if (! f)
473 l = NULL;
474 use = (charc *) ft -> dat;
475 bname = use -> name;
476 free (ft);
477 } else
478 bname = NULL;
479 run -> done = True;
480 }
481 }
482 }
483 if ((! e) && glob)
484 for (vrun = vars; vrun; vrun = vrun -> next) {
485 for (e = b -> e; e; e = e -> next)
486 if (issame (vrun -> hval, vrun -> name, e -> hval, e -> var))
487 break;
488 if (e)
489 break;
490 }
491 while (vars) {
492 vtmp = vars;
493 vars = vars -> next;
494 free (vtmp -> name);
495 free (vtmp);
496 }
497 return e ? e -> val : dflt;
498 }
499
500 static int
do_iget(void * bp,char * bname,char * var,Bool glob,int dflt)501 do_iget (void *bp, char *bname, char *var, Bool glob, int dflt)
502 {
503 char *ret;
504
505 ret = do_get (bp, bname, var, glob, NULL);
506 return ret ? atoi (ret) : dflt;
507 }
508
509 static Bool
do_bget(void * bp,char * bname,char * var,Bool glob,int dflt)510 do_bget (void *bp, char *bname, char *var, Bool glob, int dflt)
511 {
512 char *ret;
513
514 ret = do_get (bp, bname, var, glob, NULL);
515 return ret ? ((*ret && strchr ("TtYy1+", *ret)) ? True : False) : dflt;
516 }
517
518 char *
cfg_get(void * bp,char * bname,char * var,char * dflt)519 cfg_get (void *bp, char *bname, char *var, char *dflt)
520 {
521 return do_get (bp, bname, var, True, dflt);
522 }
523
524 int
cfg_iget(void * bp,char * bname,char * var,int dflt)525 cfg_iget (void *bp, char *bname, char *var, int dflt)
526 {
527 return do_iget (bp, bname, var, True, dflt);
528 }
529
530 Bool
cfg_bget(void * bp,char * bname,char * var,Bool dflt)531 cfg_bget (void *bp, char *bname, char *var, Bool dflt)
532 {
533 return do_bget (bp, bname, var, True, dflt);
534 }
535
536 char *
cfg_block_get(void * bp,char * bname,char * var,char * dflt)537 cfg_block_get (void *bp, char *bname, char *var, char *dflt)
538 {
539 return do_get (bp, bname, var, False, dflt);
540 }
541
542 int
cfg_block_iget(void * bp,char * bname,char * var,int dflt)543 cfg_block_iget (void *bp, char *bname, char *var, int dflt)
544 {
545 return do_iget (bp, bname, var, False, dflt);
546 }
547
548 Bool
cfg_block_bget(void * bp,char * bname,char * var,Bool dflt)549 cfg_block_bget (void *bp, char *bname, char *var, Bool dflt)
550 {
551 return do_bget (bp, bname, var, False, dflt);
552 }
553 /*}}}*/
554