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