1 /*
2 * Copyright 2001-2004 Brandon Long
3 * All Rights Reserved.
4 *
5 * ClearSilver Templating System
6 *
7 * This code is made available under the terms of the ClearSilver License.
8 * http://www.clearsilver.net/license.hdf
9 *
10 */
11
12 #include "cs_config.h"
13
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <stdarg.h>
22 #include <sys/stat.h>
23 #include "neo_misc.h"
24 #include "neo_err.h"
25 #include "neo_rand.h"
26 #include "neo_hdf.h"
27 #include "neo_str.h"
28 #include "neo_files.h"
29 #include "ulist.h"
30
31 /* Ok, in order to use the hash, we have to support n-len strings
32 * instead of null terminated strings (since in set_value and walk_hdf
33 * we are merely using part of the HDF name for lookup, and that might
34 * be a const, and we don't want the overhead of allocating/copying
35 * that data out...)
36 *
37 * Since HASH doesn't maintain any data placed in it, merely pointers to
38 * it, we use the HDF node itself as the key, and have specific
39 * comp/hash functions which just use the name/name_len as the key.
40 */
41
hash_hdf_comp(const void * a,const void * b)42 static int hash_hdf_comp(const void *a, const void *b)
43 {
44 HDF *ha = (HDF *)a;
45 HDF *hb = (HDF *)b;
46
47 return (ha->name_len == hb->name_len) && !strncmp(ha->name, hb->name, ha->name_len);
48 }
49
hash_hdf_hash(const void * a)50 static UINT32 hash_hdf_hash(const void *a)
51 {
52 HDF *ha = (HDF *)a;
53 return ne_crc((UINT8 *)(ha->name), ha->name_len);
54 }
55
_alloc_hdf(HDF ** hdf,const char * name,size_t nlen,const char * value,int dup,int wf,HDF * top)56 static NEOERR *_alloc_hdf (HDF **hdf, const char *name, size_t nlen,
57 const char *value, int dup, int wf, HDF *top)
58 {
59 *hdf = calloc (1, sizeof (HDF));
60 if (*hdf == NULL)
61 {
62 return nerr_raise (NERR_NOMEM, "Unable to allocate memory for hdf element");
63 }
64
65 (*hdf)->top = top;
66
67 if (name != NULL)
68 {
69 (*hdf)->name_len = nlen;
70 (*hdf)->name = (char *) malloc (nlen + 1);
71 if ((*hdf)->name == NULL)
72 {
73 free((*hdf));
74 (*hdf) = NULL;
75 return nerr_raise (NERR_NOMEM,
76 "Unable to allocate memory for hdf element: %s", name);
77 }
78 strncpy((*hdf)->name, name, nlen);
79 (*hdf)->name[nlen] = '\0';
80 }
81 if (value != NULL)
82 {
83 if (dup)
84 {
85 (*hdf)->alloc_value = 1;
86 (*hdf)->value = strdup(value);
87 if ((*hdf)->value == NULL)
88 {
89 free((*hdf)->name);
90 free((*hdf));
91 (*hdf) = NULL;
92 return nerr_raise (NERR_NOMEM,
93 "Unable to allocate memory for hdf element %s", name);
94 }
95 }
96 else
97 {
98 (*hdf)->alloc_value = wf;
99 /* We're overriding the const of value here for the set_buf case
100 * where we overrode the char * to const char * earlier, since
101 * alloc_value actually keeps track of the const-ness for us */
102 (*hdf)->value = (char *)value;
103 }
104 }
105 return STATUS_OK;
106 }
107
_dealloc_hdf_attr(HDF_ATTR ** attr)108 static void _dealloc_hdf_attr(HDF_ATTR **attr)
109 {
110 HDF_ATTR *next;
111
112 while ((*attr) != NULL)
113 {
114 next = (*attr)->next;
115 if ((*attr)->key) free((*attr)->key);
116 if ((*attr)->value) free((*attr)->value);
117 free(*attr);
118 *attr = next;
119 }
120 *attr = NULL;
121 }
122
_dealloc_hdf(HDF ** hdf)123 static void _dealloc_hdf (HDF **hdf)
124 {
125 HDF *myhdf = *hdf;
126 HDF *next = NULL;
127
128 if (myhdf == NULL) return;
129 if (myhdf->child != NULL)
130 _dealloc_hdf(&(myhdf->child));
131
132 /* This was easier recursively, but dangerous on long lists, so we
133 * walk it ourselves */
134 next = myhdf->next;
135 while (next != NULL)
136 {
137 myhdf->next = next->next;
138 next->next = NULL;
139 _dealloc_hdf(&next);
140 next = myhdf->next;
141 }
142 if (myhdf->name != NULL)
143 {
144 free (myhdf->name);
145 myhdf->name = NULL;
146 }
147 if (myhdf->value != NULL)
148 {
149 if (myhdf->alloc_value)
150 free (myhdf->value);
151 myhdf->value = NULL;
152 }
153 if (myhdf->attr != NULL)
154 {
155 _dealloc_hdf_attr(&(myhdf->attr));
156 }
157 if (myhdf->hash != NULL)
158 {
159 ne_hash_destroy(&myhdf->hash);
160 }
161 free(myhdf);
162 *hdf = NULL;
163 }
164
hdf_init(HDF ** hdf)165 NEOERR* hdf_init (HDF **hdf)
166 {
167 NEOERR *err;
168 HDF *my_hdf;
169
170 *hdf = NULL;
171
172 err = nerr_init();
173 if (err != STATUS_OK)
174 return nerr_pass (err);
175
176 err = _alloc_hdf (&my_hdf, NULL, 0, NULL, 0, 0, NULL);
177 if (err != STATUS_OK)
178 return nerr_pass (err);
179
180 my_hdf->top = my_hdf;
181
182 *hdf = my_hdf;
183
184 return STATUS_OK;
185 }
186
hdf_destroy(HDF ** hdf)187 void hdf_destroy (HDF **hdf)
188 {
189 if (*hdf == NULL) return;
190 if ((*hdf)->top == (*hdf))
191 {
192 _dealloc_hdf(hdf);
193 }
194 }
195
_walk_hdf(HDF * hdf,const char * name,HDF ** node)196 static int _walk_hdf (HDF *hdf, const char *name, HDF **node)
197 {
198 HDF *parent = NULL;
199 HDF *hp = hdf;
200 HDF hash_key;
201 int x = 0;
202 const char *s, *n;
203 int r;
204
205 *node = NULL;
206
207 if (hdf == NULL) return -1;
208 if (name == NULL || name[0] == '\0')
209 {
210 *node = hdf;
211 return 0;
212 }
213
214 if (hdf->link)
215 {
216 r = _walk_hdf (hdf->top, hdf->value, &hp);
217 if (r) return r;
218 if (hp)
219 {
220 parent = hp;
221 hp = hp->child;
222 }
223 }
224 else
225 {
226 parent = hdf;
227 hp = hdf->child;
228 }
229 if (hp == NULL)
230 {
231 return -1;
232 }
233
234 n = name;
235 s = strchr (n, '.');
236 x = (s == NULL) ? strlen(n) : s - n;
237
238 while (1)
239 {
240 if (parent && parent->hash)
241 {
242 hash_key.name = (char *)n;
243 hash_key.name_len = x;
244 hp = ne_hash_lookup(parent->hash, &hash_key);
245 }
246 else
247 {
248 while (hp != NULL)
249 {
250 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
251 {
252 break;
253 }
254 else
255 {
256 hp = hp->next;
257 }
258 }
259 }
260 if (hp == NULL)
261 {
262 return -1;
263 }
264 if (s == NULL) break;
265
266 if (hp->link)
267 {
268 r = _walk_hdf (hp->top, hp->value, &hp);
269 if (r) {
270 return r;
271 }
272 parent = hp;
273 hp = hp->child;
274 }
275 else
276 {
277 parent = hp;
278 hp = hp->child;
279 }
280 n = s + 1;
281 s = strchr (n, '.');
282 x = (s == NULL) ? strlen(n) : s - n;
283 }
284 if (hp->link)
285 {
286 return _walk_hdf (hp->top, hp->value, node);
287 }
288
289 *node = hp;
290 return 0;
291 }
292
hdf_get_int_value(HDF * hdf,const char * name,int defval)293 int hdf_get_int_value (HDF *hdf, const char *name, int defval)
294 {
295 HDF *node;
296 int v;
297 char *n;
298
299 if ((_walk_hdf(hdf, name, &node) == 0) && (node->value != NULL))
300 {
301 v = strtol (node->value, &n, 10);
302 if (node->value == n) v = defval;
303 return v;
304 }
305 return defval;
306 }
307
308 /* This should return a const char *, but changing this would have big
309 * repurcussions for any C code using this function, so no change for now */
hdf_get_value(HDF * hdf,const char * name,const char * defval)310 char* hdf_get_value (HDF *hdf, const char *name, const char *defval)
311 {
312 HDF *node;
313
314 if ((_walk_hdf(hdf, name, &node) == 0) && (node->value != NULL))
315 {
316 return node->value;
317 }
318 return (char *)defval;
319 }
320
hdf_get_valuevf(HDF * hdf,const char * namefmt,va_list ap)321 char* hdf_get_valuevf (HDF *hdf, const char *namefmt, va_list ap)
322 {
323 HDF *node;
324 char *name;
325
326 name = vsprintf_alloc(namefmt, ap);
327 if (name == NULL) return NULL;
328 if ((_walk_hdf(hdf, name, &node) == 0) && (node->value != NULL))
329 {
330 free(name);
331 return node->value;
332 }
333 free(name);
334 return NULL;
335 }
336
hdf_get_valuef(HDF * hdf,const char * namefmt,...)337 char* hdf_get_valuef (HDF *hdf, const char *namefmt, ...)
338 {
339 char *val;
340 va_list ap;
341
342 va_start(ap, namefmt);
343 val = hdf_get_valuevf(hdf, namefmt, ap);
344 va_end(ap);
345 return val;
346 }
347
hdf_get_copy(HDF * hdf,const char * name,char ** value,const char * defval)348 NEOERR* hdf_get_copy (HDF *hdf, const char *name, char **value,
349 const char *defval)
350 {
351 HDF *node;
352
353 if ((_walk_hdf(hdf, name, &node) == 0) && (node->value != NULL))
354 {
355 *value = strdup(node->value);
356 if (*value == NULL)
357 {
358 return nerr_raise (NERR_NOMEM, "Unable to allocate copy of %s", name);
359 }
360 }
361 else
362 {
363 if (defval == NULL)
364 *value = NULL;
365 else
366 {
367 *value = strdup(defval);
368 if (*value == NULL)
369 {
370 return nerr_raise (NERR_NOMEM, "Unable to allocate copy of %s", name);
371 }
372 }
373 }
374 return STATUS_OK;
375 }
376
hdf_get_obj(HDF * hdf,const char * name)377 HDF* hdf_get_obj (HDF *hdf, const char *name)
378 {
379 HDF *obj;
380
381 _walk_hdf(hdf, name, &obj);
382 return obj;
383 }
384
hdf_get_child(HDF * hdf,const char * name)385 HDF* hdf_get_child (HDF *hdf, const char *name)
386 {
387 HDF *obj;
388 _walk_hdf(hdf, name, &obj);
389 if (obj != NULL) return obj->child;
390 return obj;
391 }
392
hdf_get_attr(HDF * hdf,const char * name)393 HDF_ATTR* hdf_get_attr (HDF *hdf, const char *name)
394 {
395 HDF *obj;
396 _walk_hdf(hdf, name, &obj);
397 if (obj != NULL) return obj->attr;
398 return NULL;
399 }
400
hdf_set_attr(HDF * hdf,const char * name,const char * key,const char * value)401 NEOERR* hdf_set_attr (HDF *hdf, const char *name, const char *key,
402 const char *value)
403 {
404 HDF *obj;
405 HDF_ATTR *attr, *last;
406
407 _walk_hdf(hdf, name, &obj);
408 if (obj == NULL)
409 return nerr_raise(NERR_ASSERT, "Unable to set attribute on none existant node");
410
411 if (obj->attr != NULL)
412 {
413 attr = obj->attr;
414 last = attr;
415 while (attr != NULL)
416 {
417 if (!strcmp(attr->key, key))
418 {
419 if (attr->value) free(attr->value);
420 /* a set of NULL deletes the attr */
421 if (value == NULL)
422 {
423 if (attr == obj->attr)
424 obj->attr = attr->next;
425 else
426 last->next = attr->next;
427 free(attr->key);
428 free(attr);
429 return STATUS_OK;
430 }
431 attr->value = strdup(value);
432 if (attr->value == NULL)
433 return nerr_raise(NERR_NOMEM, "Unable to set attr %s to %s", key, value);
434 return STATUS_OK;
435 }
436 last = attr;
437 attr = attr->next;
438 }
439 last->next = (HDF_ATTR *) calloc(1, sizeof(HDF_ATTR));
440 if (last->next == NULL)
441 return nerr_raise(NERR_NOMEM, "Unable to set attr %s to %s", key, value);
442 attr = last->next;
443 }
444 else
445 {
446 if (value == NULL) return STATUS_OK;
447 obj->attr = (HDF_ATTR *) calloc(1, sizeof(HDF_ATTR));
448 if (obj->attr == NULL)
449 return nerr_raise(NERR_NOMEM, "Unable to set attr %s to %s", key, value);
450 attr = obj->attr;
451 }
452 attr->key = strdup(key);
453 attr->value = strdup(value);
454 if (attr->key == NULL || attr->value == NULL)
455 return nerr_raise(NERR_NOMEM, "Unable to set attr %s to %s", key, value);
456
457 return STATUS_OK;
458 }
459
hdf_obj_child(HDF * hdf)460 HDF* hdf_obj_child (HDF *hdf)
461 {
462 HDF *obj;
463 if (hdf == NULL) return NULL;
464 if (hdf->link)
465 {
466 if (_walk_hdf(hdf->top, hdf->value, &obj))
467 return NULL;
468 return obj->child;
469 }
470 return hdf->child;
471 }
472
hdf_obj_next(HDF * hdf)473 HDF* hdf_obj_next (HDF *hdf)
474 {
475 if (hdf == NULL) return NULL;
476 return hdf->next;
477 }
478
hdf_obj_top(HDF * hdf)479 HDF* hdf_obj_top (HDF *hdf)
480 {
481 if (hdf == NULL) return NULL;
482 return hdf->top;
483 }
484
hdf_obj_attr(HDF * hdf)485 HDF_ATTR* hdf_obj_attr (HDF *hdf)
486 {
487 if (hdf == NULL) return NULL;
488 return hdf->attr;
489 }
490
hdf_obj_name(HDF * hdf)491 char* hdf_obj_name (HDF *hdf)
492 {
493 if (hdf == NULL) return NULL;
494 return hdf->name;
495 }
496
hdf_obj_value(HDF * hdf)497 char* hdf_obj_value (HDF *hdf)
498 {
499 int count = 0;
500
501 if (hdf == NULL) return NULL;
502 while (hdf->link && count < 100)
503 {
504 if (_walk_hdf (hdf->top, hdf->value, &hdf))
505 return NULL;
506 count++;
507 }
508 return hdf->value;
509 }
510
_merge_attr(HDF_ATTR * dest,HDF_ATTR * src)511 void _merge_attr (HDF_ATTR *dest, HDF_ATTR *src)
512 {
513 HDF_ATTR *da, *ld;
514 HDF_ATTR *sa, *ls;
515 BOOL found;
516
517 sa = src;
518 ls = src;
519 while (sa != NULL)
520 {
521 da = dest;
522 ld = da;
523 found = 0;
524 while (da != NULL)
525 {
526 if (!strcmp(da->key, sa->key))
527 {
528 if (da->value) free(da->value);
529 da->value = sa->value;
530 sa->value = NULL;
531 found = 1;
532 break;
533 }
534 ld = da;
535 da = da->next;
536 }
537 if (!found)
538 {
539 ld->next = sa;
540 ls->next = sa->next;
541 if (src == sa) src = sa->next;
542 ld->next->next = NULL;
543 sa = ls->next;
544 }
545 else
546 {
547 ls = sa;
548 sa = sa->next;
549 }
550 }
551 _dealloc_hdf_attr(&src);
552 }
553
_hdf_hash_level(HDF * hdf)554 NEOERR* _hdf_hash_level(HDF *hdf)
555 {
556 NEOERR *err;
557 HDF *child;
558
559 err = ne_hash_init(&(hdf->hash), hash_hdf_hash, hash_hdf_comp);
560 if (err) return nerr_pass(err);
561
562 child = hdf->child;
563 while (child)
564 {
565 err = ne_hash_insert(hdf->hash, child, child);
566 if (err) return nerr_pass(err);
567 child = child->next;
568 }
569 return STATUS_OK;
570 }
571
_set_value(HDF * hdf,const char * name,const char * value,int dup,int wf,int link,HDF_ATTR * attr,HDF ** set_node)572 static NEOERR* _set_value (HDF *hdf, const char *name, const char *value,
573 int dup, int wf, int link, HDF_ATTR *attr,
574 HDF **set_node)
575 {
576 NEOERR *err;
577 HDF *hn, *hp, *hs;
578 HDF hash_key;
579 int x = 0;
580 const char *s = name;
581 const char *n = name;
582 int count = 0;
583
584 if (set_node != NULL) *set_node = NULL;
585 if (hdf == NULL)
586 {
587 return nerr_raise(NERR_ASSERT, "Unable to set %s on NULL hdf", name);
588 }
589
590 /* HACK: allow setting of this node by passing an empty name */
591 if (name == NULL || name[0] == '\0')
592 {
593 /* handle setting attr first */
594 if (hdf->attr == NULL)
595 {
596 hdf->attr = attr;
597 }
598 else
599 {
600 _merge_attr(hdf->attr, attr);
601 }
602 /* if we're setting ourselves to ourselves... */
603 if (hdf->value == value)
604 {
605 if (set_node != NULL) *set_node = hdf;
606 return STATUS_OK;
607 }
608 if (hdf->alloc_value)
609 {
610 free(hdf->value);
611 hdf->value = NULL;
612 }
613 if (value == NULL)
614 {
615 hdf->alloc_value = 0;
616 hdf->value = NULL;
617 }
618 else if (dup)
619 {
620 hdf->alloc_value = 1;
621 hdf->value = strdup(value);
622 if (hdf->value == NULL)
623 return nerr_raise (NERR_NOMEM, "Unable to duplicate value %s for %s",
624 value, name);
625 }
626 else
627 {
628 hdf->alloc_value = wf;
629 hdf->value = (char *)value;
630 }
631 if (set_node != NULL) *set_node = hdf;
632 return STATUS_OK;
633 }
634
635 n = name;
636 s = strchr (n, '.');
637 x = (s != NULL) ? s - n : strlen(n);
638 if (x == 0)
639 {
640 return nerr_raise(NERR_ASSERT, "Unable to set Empty component %s", name);
641 }
642
643 if (hdf->link)
644 {
645 char *new_name = (char *) malloc(strlen(hdf->value) + 1 + strlen(name) + 1);
646 if (new_name == NULL)
647 {
648 return nerr_raise(NERR_NOMEM, "Unable to allocate memory");
649 }
650 strcpy(new_name, hdf->value);
651 strcat(new_name, ".");
652 strcat(new_name, name);
653 err = _set_value (hdf->top, new_name, value, dup, wf, link, attr, set_node);
654 free(new_name);
655 return nerr_pass(err);
656 }
657 else
658 {
659 hn = hdf;
660 }
661
662 while (1)
663 {
664 /* examine cache to see if we have a match */
665 count = 0;
666 hp = hn->last_hp;
667 hs = hn->last_hs;
668
669 if ((hs == NULL && hp == hn->child) || (hs && hs->next == hp))
670 {
671 if (hp && hp->name && (x == hp->name_len) && !strncmp (hp->name, n, x))
672 {
673 goto skip_search;
674 }
675 }
676
677 hp = hn->child;
678 hs = NULL;
679
680 /* Look for a matching node at this level */
681 if (hn->hash != NULL)
682 {
683 hash_key.name = (char *)n;
684 hash_key.name_len = x;
685 hp = ne_hash_lookup(hn->hash, &hash_key);
686 hs = hn->last_child;
687 }
688 else
689 {
690 while (hp != NULL)
691 {
692 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
693 {
694 break;
695 }
696 hs = hp;
697 hp = hp->next;
698 count++;
699 }
700 }
701
702 /* save in cache any value we found */
703 if (hp) {
704 hn->last_hp = hp;
705 hn->last_hs = hs;
706 }
707
708 skip_search:
709
710 if (hp == NULL)
711 {
712 /* If there was no matching node at this level, we need to
713 * allocate an intersitial node (or the actual node if we're
714 * at the last part of the HDF name) */
715 if (s != NULL)
716 {
717 /* intersitial */
718 err = _alloc_hdf (&hp, n, x, NULL, 0, 0, hdf->top);
719 }
720 else
721 {
722 err = _alloc_hdf (&hp, n, x, value, dup, wf, hdf->top);
723 if (link) hp->link = 1;
724 else hp->link = 0;
725 hp->attr = attr;
726 }
727 if (err != STATUS_OK)
728 return nerr_pass (err);
729 if (hn->child == NULL)
730 hn->child = hp;
731 else
732 hs->next = hp;
733 hn->last_child = hp;
734
735 /* This is the point at which we convert to a hash table
736 * at this level, if we're over the count */
737 if (count > FORCE_HASH_AT && hn->hash == NULL)
738 {
739 err = _hdf_hash_level(hn);
740 if (err) return nerr_pass(err);
741 }
742 else if (hn->hash != NULL)
743 {
744 err = ne_hash_insert(hn->hash, hp, hp);
745 if (err) return nerr_pass(err);
746 }
747 }
748 else if (s == NULL)
749 {
750 /* If there is a matching node and we're at the end of the HDF
751 * name, then we update the value of the node */
752 /* handle setting attr first */
753 if (hp->attr == NULL)
754 {
755 hp->attr = attr;
756 }
757 else
758 {
759 _merge_attr(hp->attr, attr);
760 }
761 if (hp->value != value)
762 {
763 if (hp->alloc_value)
764 {
765 free(hp->value);
766 hp->value = NULL;
767 }
768 if (value == NULL)
769 {
770 hp->alloc_value = 0;
771 hp->value = NULL;
772 }
773 else if (dup)
774 {
775 hp->alloc_value = 1;
776 hp->value = strdup(value);
777 if (hp->value == NULL)
778 return nerr_raise (NERR_NOMEM, "Unable to duplicate value %s for %s",
779 value, name);
780 }
781 else
782 {
783 hp->alloc_value = wf;
784 hp->value = (char *)value;
785 }
786 }
787 if (link) hp->link = 1;
788 else hp->link = 0;
789 }
790 else if (hp->link)
791 {
792 char *new_name = (char *) malloc(strlen(hp->value) + strlen(s) + 1);
793 if (new_name == NULL)
794 {
795 return nerr_raise(NERR_NOMEM, "Unable to allocate memory");
796 }
797 strcpy(new_name, hp->value);
798 strcat(new_name, s);
799 err = _set_value (hdf->top, new_name, value, dup, wf, link, attr, set_node);
800 free(new_name);
801 return nerr_pass(err);
802 }
803 /* At this point, we're done if there is not more HDF name space to
804 * traverse */
805 if (s == NULL)
806 break;
807 /* Otherwise, we need to find the next part of the namespace */
808 n = s + 1;
809 s = strchr (n, '.');
810 x = (s != NULL) ? s - n : strlen(n);
811 if (x == 0)
812 {
813 return nerr_raise(NERR_ASSERT, "Unable to set Empty component %s", name);
814 }
815 hn = hp;
816 }
817 if (set_node != NULL) *set_node = hp;
818 return STATUS_OK;
819 }
820
hdf_set_value(HDF * hdf,const char * name,const char * value)821 NEOERR* hdf_set_value (HDF *hdf, const char *name, const char *value)
822 {
823 return nerr_pass(_set_value (hdf, name, value, 1, 1, 0, NULL, NULL));
824 }
825
hdf_set_value_attr(HDF * hdf,const char * name,const char * value,HDF_ATTR * attr)826 NEOERR* hdf_set_value_attr (HDF *hdf, const char *name, const char *value,
827 HDF_ATTR *attr)
828 {
829 return nerr_pass(_set_value (hdf, name, value, 1, 1, 0, attr, NULL));
830 }
831
hdf_set_symlink(HDF * hdf,const char * src,const char * dest)832 NEOERR* hdf_set_symlink (HDF *hdf, const char *src, const char *dest)
833 {
834 return nerr_pass(_set_value (hdf, src, dest, 1, 1, 1, NULL, NULL));
835 }
836
hdf_set_int_value(HDF * hdf,const char * name,int value)837 NEOERR* hdf_set_int_value (HDF *hdf, const char *name, int value)
838 {
839 char buf[256];
840
841 snprintf (buf, sizeof(buf), "%d", value);
842 return nerr_pass(_set_value (hdf, name, buf, 1, 1, 0, NULL, NULL));
843 }
844
hdf_set_buf(HDF * hdf,const char * name,char * value)845 NEOERR* hdf_set_buf (HDF *hdf, const char *name, char *value)
846 {
847 return nerr_pass(_set_value (hdf, name, value, 0, 1, 0, NULL, NULL));
848 }
849
hdf_set_copy(HDF * hdf,const char * dest,const char * src)850 NEOERR* hdf_set_copy (HDF *hdf, const char *dest, const char *src)
851 {
852 HDF *node;
853 if ((_walk_hdf(hdf, src, &node) == 0) && (node->value != NULL))
854 {
855 return nerr_pass(_set_value (hdf, dest, node->value, 0, 0, 0, NULL, NULL));
856 }
857 return nerr_raise (NERR_NOT_FOUND, "Unable to find %s", src);
858 }
859
hdf_set_valuevf(HDF * hdf,const char * fmt,va_list ap)860 NEOERR* hdf_set_valuevf (HDF *hdf, const char *fmt, va_list ap)
861 {
862 NEOERR *err;
863 char *k;
864 char *v;
865
866 k = vsprintf_alloc(fmt, ap);
867 if (k == NULL)
868 {
869 return nerr_raise(NERR_NOMEM, "Unable to allocate memory for format string");
870 }
871 v = strchr(k, '=');
872 if (v == NULL)
873 {
874 err = nerr_raise(NERR_ASSERT, "No equals found: %s", k);
875 free(k);
876 return err;
877 }
878 *v++ = '\0';
879 err = hdf_set_value(hdf, k, v);
880 free(k);
881 return nerr_pass(err);
882 }
883
hdf_set_valuef(HDF * hdf,const char * fmt,...)884 NEOERR* hdf_set_valuef (HDF *hdf, const char *fmt, ...)
885 {
886 NEOERR *err;
887 va_list ap;
888
889 va_start(ap, fmt);
890 err = hdf_set_valuevf(hdf, fmt, ap);
891 va_end(ap);
892 return nerr_pass(err);
893 }
894
hdf_get_node(HDF * hdf,const char * name,HDF ** ret)895 NEOERR* hdf_get_node (HDF *hdf, const char *name, HDF **ret)
896 {
897 _walk_hdf(hdf, name, ret);
898 if (*ret == NULL)
899 {
900 return nerr_pass(_set_value (hdf, name, NULL, 0, 1, 0, NULL, ret));
901 }
902 return STATUS_OK;
903 }
904
905 /* Ok, this version avoids the bubble sort by walking the level once to
906 * load them all into a ULIST, qsort'ing the list, and then dumping them
907 * back out... */
hdf_sort_obj(HDF * h,int (* compareFunc)(const void *,const void *))908 NEOERR *hdf_sort_obj (HDF *h, int (*compareFunc)(const void *, const void *))
909 {
910 NEOERR *err = STATUS_OK;
911 ULIST *level = NULL;
912 HDF *p, *c;
913 int x;
914
915 if (h == NULL) return STATUS_OK;
916 c = h->child;
917 if (c == NULL) return STATUS_OK;
918
919 do {
920 err = uListInit(&level, 40, 0);
921 if (err) return nerr_pass(err);
922 for (p = c; p; p = p->next) {
923 err = uListAppend(level, p);
924 if (err) break;
925 }
926 err = uListSort(level, compareFunc);
927 if (err) break;
928 uListGet(level, 0, (void *)&c);
929 h->child = c;
930 for (x = 1; x < uListLength(level); x++)
931 {
932 uListGet(level, x, (void *)&p);
933 c->next = p;
934 p->next = NULL;
935 c = p;
936 }
937 h->last_child = c;
938 } while (0);
939 uListDestroy(&level, 0);
940 return nerr_pass(err);
941 }
942
hdf_remove_tree(HDF * hdf,const char * name)943 NEOERR* hdf_remove_tree (HDF *hdf, const char *name)
944 {
945 HDF *hp = hdf;
946 HDF *lp = NULL, *ln = NULL; /* last parent, last node */
947 int x = 0;
948 const char *s = name;
949 const char *n = name;
950
951 if (hdf == NULL) return STATUS_OK;
952
953 hp = hdf->child;
954 if (hp == NULL)
955 {
956 return STATUS_OK;
957 }
958
959 lp = hdf;
960 ln = NULL;
961
962 n = name;
963 s = strchr (n, '.');
964 x = (s == NULL) ? strlen(n) : s - n;
965
966 while (1)
967 {
968 while (hp != NULL)
969 {
970 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
971 {
972 break;
973 }
974 else
975 {
976 ln = hp;
977 hp = hp->next;
978 }
979 }
980 if (hp == NULL)
981 {
982 return STATUS_OK;
983 }
984 if (s == NULL) break;
985
986 lp = hp;
987 ln = NULL;
988 hp = hp->child;
989 n = s + 1;
990 s = strchr (n, '.');
991 x = (s == NULL) ? strlen(n) : s - n;
992 }
993
994 if (lp->hash != NULL)
995 {
996 ne_hash_remove(lp->hash, hp);
997 }
998 if (ln)
999 {
1000 ln->next = hp->next;
1001 /* check to see if we are the last parent's last_child, if so
1002 * repoint so hash table inserts will go to the right place */
1003 if (hp == lp->last_child)
1004 lp->last_child = ln;
1005 hp->next = NULL;
1006 }
1007 else
1008 {
1009 lp->child = hp->next;
1010 hp->next = NULL;
1011 }
1012 _dealloc_hdf (&hp);
1013
1014 return STATUS_OK;
1015 }
1016
_copy_attr(HDF_ATTR ** dest,HDF_ATTR * src)1017 static NEOERR * _copy_attr (HDF_ATTR **dest, HDF_ATTR *src)
1018 {
1019 HDF_ATTR *copy, *last = NULL;
1020
1021 *dest = NULL;
1022 while (src != NULL)
1023 {
1024 copy = (HDF_ATTR *)malloc(sizeof(HDF_ATTR));
1025 if (copy == NULL)
1026 {
1027 _dealloc_hdf_attr(dest);
1028 return nerr_raise(NERR_NOMEM, "Unable to allocate copy of HDF_ATTR");
1029 }
1030 copy->key = strdup(src->key);
1031 copy->value = strdup(src->value);
1032 copy->next = NULL;
1033 if ((copy->key == NULL) || (copy->value == NULL))
1034 {
1035 _dealloc_hdf_attr(dest);
1036 return nerr_raise(NERR_NOMEM, "Unable to allocate copy of HDF_ATTR");
1037 }
1038 if (last) {
1039 last->next = copy;
1040 }
1041 else
1042 {
1043 *dest = copy;
1044 }
1045 last = copy;
1046 src = src->next;
1047 }
1048 return STATUS_OK;
1049 }
1050
_copy_nodes(HDF * dest,HDF * src)1051 static NEOERR * _copy_nodes (HDF *dest, HDF *src)
1052 {
1053 NEOERR *err = STATUS_OK;
1054 HDF *dt, *st;
1055 HDF_ATTR *attr_copy;
1056
1057 st = src->child;
1058 while (st != NULL)
1059 {
1060 err = _copy_attr(&attr_copy, st->attr);
1061 if (err) return nerr_pass(err);
1062 err = _set_value(dest, st->name, st->value, 1, 1, 0, attr_copy, &dt);
1063 if (err) {
1064 _dealloc_hdf_attr(&attr_copy);
1065 return nerr_pass(err);
1066 }
1067 if (src->child)
1068 {
1069 err = _copy_nodes (dt, st);
1070 if (err) return nerr_pass(err);
1071 }
1072 st = st->next;
1073 }
1074 return STATUS_OK;
1075 }
1076
hdf_copy(HDF * dest,const char * name,HDF * src)1077 NEOERR* hdf_copy (HDF *dest, const char *name, HDF *src)
1078 {
1079 NEOERR *err;
1080 HDF *node;
1081
1082 if (_walk_hdf(dest, name, &node) == -1)
1083 {
1084 err = _set_value (dest, name, NULL, 0, 0, 0, NULL, &node);
1085 if (err) return nerr_pass (err);
1086 }
1087 return nerr_pass (_copy_nodes (node, src));
1088 }
1089
1090 /* BUG: currently, this only prints something if there is a value...
1091 * but we now allow attributes on nodes with no value... */
1092
gen_ml_break(char * ml,size_t len)1093 static void gen_ml_break(char *ml, size_t len)
1094 {
1095 int nlen;
1096 int x = 0;
1097
1098 ml[x++] = '\n';
1099 nlen = 2 + neo_rand(len-5);
1100 if (nlen == 0)
1101 {
1102 nlen = len / 2;
1103 }
1104 while (nlen)
1105 {
1106 ml[x++] = ('A' + neo_rand(26));
1107 nlen--;
1108 }
1109 ml[x++] = '\n';
1110 ml[x] = '\0';
1111 }
1112
1113 typedef NEOERR *(*DUMPF_CB)(void *rock, const char *fmt, ...);
1114
_fp_dump_cb(void * rock,const char * fmt,...)1115 static NEOERR *_fp_dump_cb (void *rock, const char *fmt, ...)
1116 {
1117 FILE *fp = (FILE *)rock;
1118 va_list ap;
1119
1120 va_start (ap, fmt);
1121 vfprintf(fp, fmt, ap);
1122 va_end(ap);
1123 return STATUS_OK;
1124 }
1125
_string_dump_cb(void * rock,const char * fmt,...)1126 static NEOERR *_string_dump_cb (void *rock, const char *fmt, ...)
1127 {
1128 NEOERR *err;
1129 STRING *str = (STRING *)rock;
1130 va_list ap;
1131
1132 va_start (ap, fmt);
1133 err = string_appendvf(str, fmt, ap);
1134 va_end(ap);
1135 return nerr_pass(err);
1136 }
1137
1138 #define DUMP_TYPE_DOTTED 0
1139 #define DUMP_TYPE_COMPACT 1
1140 #define DUMP_TYPE_PRETTY 2
1141
hdf_dump_cb(HDF * hdf,const char * prefix,int dtype,int lvl,void * rock,DUMPF_CB dump_cbf)1142 static NEOERR* hdf_dump_cb(HDF *hdf, const char *prefix, int dtype, int lvl,
1143 void *rock, DUMPF_CB dump_cbf)
1144 {
1145 NEOERR *err;
1146 char *p, op;
1147 char ml[10] = "\nEOM\n";
1148 int ml_len = strlen(ml);
1149 char whsp[256] = "";
1150
1151 if (dtype == DUMP_TYPE_PRETTY)
1152 {
1153 memset(whsp, ' ', 256);
1154 if (lvl > 127)
1155 lvl = 127;
1156 whsp[lvl*2] = '\0';
1157 }
1158
1159 if (hdf != NULL) hdf = hdf->child;
1160
1161 while (hdf != NULL)
1162 {
1163 op = '=';
1164 if (hdf->value)
1165 {
1166 if (hdf->link) op = ':';
1167 if (prefix && (dtype == DUMP_TYPE_DOTTED))
1168 {
1169 err = dump_cbf(rock, "%s.%s", prefix, hdf->name);
1170 }
1171 else
1172 {
1173 err = dump_cbf(rock, "%s%s", whsp, hdf->name);
1174 }
1175 if (err) return nerr_pass (err);
1176 if (hdf->attr)
1177 {
1178 HDF_ATTR *attr = hdf->attr;
1179 char *v = NULL;
1180
1181 err = dump_cbf(rock, " [");
1182 if (err) return nerr_pass(err);
1183 while (attr != NULL)
1184 {
1185 if (attr->value == NULL || !strcmp(attr->value, "1"))
1186 err = dump_cbf(rock, "%s", attr->key);
1187 else
1188 {
1189 v = repr_string_alloc(attr->value);
1190
1191 if (v == NULL)
1192 return nerr_raise(NERR_NOMEM, "Unable to repr attr %s value %s", attr->key, attr->value);
1193 err = dump_cbf(rock, "%s=%s", attr->key, v);
1194 free(v);
1195 }
1196 if (err) return nerr_pass(err);
1197 if (attr->next)
1198 {
1199 err = dump_cbf(rock, ", ");
1200 if (err) return nerr_pass(err);
1201 }
1202 attr = attr->next;
1203 }
1204 err = dump_cbf(rock, "] ");
1205 if (err) return nerr_pass(err);
1206 }
1207 if (strchr (hdf->value, '\n'))
1208 {
1209 int vlen = strlen(hdf->value);
1210
1211 while (strstr(hdf->value, ml) || ((vlen > ml_len) && !strncmp(hdf->value + vlen - ml_len + 1, ml, strlen(ml) - 1)))
1212 {
1213 gen_ml_break(ml, sizeof(ml));
1214 ml_len = strlen(ml);
1215 }
1216 if (hdf->value[strlen(hdf->value)-1] != '\n')
1217 err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml);
1218 else
1219 err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml+1);
1220 }
1221 else
1222 {
1223 err = dump_cbf(rock, " %c %s\n", op, hdf->value);
1224 }
1225 if (err) return nerr_pass (err);
1226 }
1227 if (hdf->child)
1228 {
1229 if (prefix && (dtype == DUMP_TYPE_DOTTED))
1230 {
1231 p = (char *) malloc (strlen(hdf->name) + strlen(prefix) + 2);
1232 sprintf (p, "%s.%s", prefix, hdf->name);
1233 err = hdf_dump_cb (hdf, p, dtype, lvl+1, rock, dump_cbf);
1234 free(p);
1235 }
1236 else
1237 {
1238 if (hdf->name && (dtype != DUMP_TYPE_DOTTED))
1239 {
1240 err = dump_cbf(rock, "%s%s {\n", whsp, hdf->name);
1241 if (err) return nerr_pass (err);
1242 err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
1243 if (err) return nerr_pass (err);
1244 err = dump_cbf(rock, "%s}\n", whsp);
1245 }
1246 else
1247 {
1248 err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
1249 }
1250 }
1251 if (err) return nerr_pass (err);
1252 }
1253 hdf = hdf->next;
1254 }
1255 return STATUS_OK;
1256 }
1257
hdf_dump_str(HDF * hdf,const char * prefix,int dtype,STRING * str)1258 NEOERR* hdf_dump_str (HDF *hdf, const char *prefix, int dtype, STRING *str)
1259 {
1260 return nerr_pass(hdf_dump_cb(hdf, prefix, dtype, 0, str, _string_dump_cb));
1261 }
1262
hdf_dump(HDF * hdf,const char * prefix)1263 NEOERR* hdf_dump(HDF *hdf, const char *prefix)
1264 {
1265 return nerr_pass(hdf_dump_cb(hdf, prefix, DUMP_TYPE_DOTTED, 0, stdout, _fp_dump_cb));
1266 }
1267
hdf_dump_format(HDF * hdf,int lvl,FILE * fp)1268 NEOERR* hdf_dump_format (HDF *hdf, int lvl, FILE *fp)
1269 {
1270 return nerr_pass(hdf_dump_cb(hdf, "", DUMP_TYPE_PRETTY, 0, fp, _fp_dump_cb));
1271 }
1272
hdf_write_file(HDF * hdf,const char * path)1273 NEOERR *hdf_write_file (HDF *hdf, const char *path)
1274 {
1275 NEOERR *err;
1276 FILE *fp;
1277
1278 fp = fopen(path, "w");
1279 if (fp == NULL)
1280 return nerr_raise_errno (NERR_IO, "Unable to open %s for writing", path);
1281
1282 err = hdf_dump_format (hdf, 0, fp);
1283
1284 fclose (fp);
1285 if (err)
1286 {
1287 unlink(path);
1288 }
1289 return nerr_pass(err);
1290 }
1291
hdf_write_file_atomic(HDF * hdf,const char * path)1292 NEOERR *hdf_write_file_atomic (HDF *hdf, const char *path)
1293 {
1294 NEOERR *err;
1295 FILE *fp;
1296 char tpath[_POSIX_PATH_MAX];
1297 static int count = 0;
1298
1299 snprintf(tpath, sizeof(tpath), "%s.%5.5f.%d", path, ne_timef(), count++);
1300
1301 fp = fopen(tpath, "w");
1302 if (fp == NULL)
1303 return nerr_raise_errno (NERR_IO, "Unable to open %s for writing", tpath);
1304
1305 err = hdf_dump_format (hdf, 0, fp);
1306
1307 fclose (fp);
1308
1309 if (err)
1310 {
1311 unlink(tpath);
1312 return nerr_pass(err);
1313 }
1314 if (rename(tpath, path) == -1)
1315 {
1316 unlink (tpath);
1317 return nerr_raise_errno (NERR_IO, "Unable to rename file %s to %s",
1318 tpath, path);
1319 }
1320
1321 return STATUS_OK;
1322 }
1323
hdf_write_string(HDF * hdf,char ** s)1324 NEOERR *hdf_write_string (HDF *hdf, char **s)
1325 {
1326 STRING str;
1327 NEOERR *err;
1328
1329 *s = NULL;
1330
1331 string_init (&str);
1332
1333 err = hdf_dump_str (hdf, NULL, 1, &str);
1334 if (err)
1335 {
1336 string_clear (&str);
1337 return nerr_pass(err);
1338 }
1339 if (str.buf == NULL)
1340 {
1341 *s = strdup("");
1342 if (*s == NULL) return nerr_raise(NERR_NOMEM, "Unable to allocate empty string");
1343 }
1344 else
1345 {
1346 *s = str.buf;
1347 }
1348
1349 return STATUS_OK;
1350 }
1351
1352
1353 #define SKIPWS(s) while (*s && isspace(*s)) s++;
1354
_copy_line(const char ** s,char * buf,size_t buf_len)1355 static int _copy_line (const char **s, char *buf, size_t buf_len)
1356 {
1357 int x = 0;
1358 const char *st = *s;
1359
1360 while (*st && x < buf_len-1)
1361 {
1362 buf[x++] = *st;
1363 if (*st++ == '\n') break;
1364 }
1365 buf[x] = '\0';
1366 *s = st;
1367
1368 return x;
1369 }
1370
1371 /* Copy the characters in the file (up to the next newline) into line
1372 * and advance s to the next line */
_copy_line_advance(const char ** s,STRING * line)1373 static NEOERR *_copy_line_advance(const char **s, STRING *line)
1374 {
1375 NEOERR *err;
1376 int x = 0;
1377 const char *st = *s;
1378 const char *nl;
1379
1380 nl = strchr(st, '\n');
1381 if (nl == NULL)
1382 {
1383 x = strlen(st);
1384 err = string_appendn(line, st, x);
1385 if (err) return nerr_pass(err);
1386 *s = st + x;
1387 }
1388 else
1389 {
1390 x = nl - st;
1391 err = string_appendn(line, st, x);
1392 if (err) return nerr_pass(err);
1393 *s = nl + 1;
1394 }
1395
1396 return STATUS_OK;
1397 }
1398
_strndup(const char * s,int len)1399 char *_strndup(const char *s, int len) {
1400 int x;
1401 char *dup;
1402 if (s == NULL) return NULL;
1403 dup = (char *) malloc(len+1);
1404 if (dup == NULL) return NULL;
1405 for (x = 0; x < len && s[x]; x++)
1406 {
1407 dup[x] = s[x];
1408 }
1409 dup[x] = '\0';
1410 dup[len] = '\0';
1411 return dup;
1412 }
1413
1414 /* attributes are of the form [key1, key2, key3=value, key4="repr"] */
parse_attr(char ** str,HDF_ATTR ** attr)1415 static NEOERR* parse_attr(char **str, HDF_ATTR **attr)
1416 {
1417 NEOERR *err = STATUS_OK;
1418 char *s = *str;
1419 char *k, *v;
1420 int k_l, v_l;
1421 STRING buf;
1422 char c;
1423 HDF_ATTR *ha, *hal = NULL;
1424
1425 *attr = NULL;
1426
1427 string_init(&buf);
1428 while (*s && *s != ']')
1429 {
1430 k = s;
1431 k_l = 0;
1432 v = NULL;
1433 v_l = 0;
1434 while (*s && isalnum(*s)) s++;
1435 k_l = s-k;
1436 if (*s == '\0' || k_l == 0)
1437 {
1438 _dealloc_hdf_attr(attr);
1439 return nerr_raise(NERR_PARSE, "Misformed attribute specification: %s", *str);
1440 }
1441 SKIPWS(s);
1442 if (*s == '=')
1443 {
1444 s++;
1445 SKIPWS(s);
1446 if (*s == '"')
1447 {
1448 s++;
1449 while (*s && *s != '"')
1450 {
1451 if (*s == '\\')
1452 {
1453 if (isdigit(*(s+1)))
1454 {
1455 s++;
1456 c = *s - '0';
1457 if (isdigit(*(s+1)))
1458 {
1459 s++;
1460 c = (c * 8) + (*s - '0');
1461 if (isdigit(*(s+1)))
1462 {
1463 s++;
1464 c = (c * 8) + (*s - '0');
1465 }
1466 }
1467 }
1468 else
1469 {
1470 s++;
1471 if (*s == 'n') c = '\n';
1472 else if (*s == 't') c = '\t';
1473 else if (*s == 'r') c = '\r';
1474 else c = *s;
1475 }
1476 err = string_append_char(&buf, c);
1477 }
1478 else
1479 {
1480 err = string_append_char(&buf, *s);
1481 }
1482 if (err)
1483 {
1484 string_clear(&buf);
1485 _dealloc_hdf_attr(attr);
1486 return nerr_pass(err);
1487 }
1488 s++;
1489 }
1490 if (*s == '\0')
1491 {
1492 _dealloc_hdf_attr(attr);
1493 string_clear(&buf);
1494 return nerr_raise(NERR_PARSE, "Misformed attribute specification: %s", *str);
1495 }
1496 s++;
1497 v = buf.buf;
1498 v_l = buf.len;
1499 }
1500 else
1501 {
1502 v = s;
1503 while (*s && *s != ' ' && *s != ',' && *s != ']') s++;
1504 if (*s == '\0')
1505 {
1506 _dealloc_hdf_attr(attr);
1507 return nerr_raise(NERR_PARSE, "Misformed attribute specification: %s", *str);
1508 }
1509 v_l = s-v;
1510 }
1511 }
1512 else
1513 {
1514 v = "1";
1515 }
1516 ha = (HDF_ATTR*) calloc (1, sizeof(HDF_ATTR));
1517 if (ha == NULL)
1518 {
1519 _dealloc_hdf_attr(attr);
1520 string_clear(&buf);
1521 return nerr_raise(NERR_NOMEM, "Unable to load attributes: %s", s);
1522 }
1523 if (*attr == NULL) *attr = ha;
1524 ha->key = _strndup(k, k_l);
1525 if (v)
1526 ha->value = _strndup(v, v_l);
1527 else
1528 ha->value = strdup("");
1529 if (ha->key == NULL || ha->value == NULL)
1530 {
1531 _dealloc_hdf_attr(attr);
1532 string_clear(&buf);
1533 return nerr_raise(NERR_NOMEM, "Unable to load attributes: %s", s);
1534 }
1535 if (hal != NULL) hal->next = ha;
1536 hal = ha;
1537 string_clear(&buf);
1538 SKIPWS(s);
1539 if (*s == ',')
1540 {
1541 s++;
1542 SKIPWS(s);
1543 }
1544 }
1545 if (*s == '\0')
1546 {
1547 _dealloc_hdf_attr(attr);
1548 return nerr_raise(NERR_PARSE, "Misformed attribute specification: %s", *str);
1549 }
1550 *str = s+1;
1551 return STATUS_OK;
1552 }
1553
1554 #define INCLUDE_ERROR 0
1555 #define INCLUDE_IGNORE 1
1556 #define INCLUDE_FILE 2
1557
_hdf_read_string(HDF * hdf,const char ** str,STRING * line,const char * path,int * lineno,int include_handle)1558 static NEOERR* _hdf_read_string (HDF *hdf, const char **str, STRING *line,
1559 const char *path, int *lineno, int include_handle)
1560 {
1561 NEOERR *err;
1562 HDF *lower;
1563 char *s;
1564 char *name, *value;
1565 HDF_ATTR *attr = NULL;
1566
1567 while (**str != '\0')
1568 {
1569 /* Reset string length, but don't free the reserved buffer */
1570 line->len = 0;
1571 err = _copy_line_advance(str, line);
1572 if (err) return nerr_pass(err);
1573 attr = NULL;
1574 (*lineno)++;
1575 s = line->buf;
1576 SKIPWS(s);
1577 if (!strncmp(s, "#include ", 9))
1578 {
1579 if (include_handle == INCLUDE_ERROR)
1580 {
1581 return nerr_raise (NERR_PARSE,
1582 "[%d]: #include not supported in string parse",
1583 *lineno);
1584 }
1585 else if (include_handle == INCLUDE_FILE)
1586 {
1587 int l;
1588 s += 9;
1589 name = neos_strip(s);
1590 l = strlen(name);
1591 if (name[0] == '"' && name[l-1] == '"')
1592 {
1593 name[l-1] = '\0';
1594 name++;
1595 }
1596 err = hdf_read_file(hdf, name);
1597 if (err != STATUS_OK)
1598 {
1599 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1600 }
1601 }
1602 }
1603 else if (s[0] == '#')
1604 {
1605 /* comment: pass */
1606 }
1607 else if (s[0] == '}') /* up */
1608 {
1609 s = neos_strip(s);
1610 if (strcmp(s, "}"))
1611 {
1612 err = nerr_raise(NERR_PARSE,
1613 "[%s:%d] Trailing garbage on line following }: %s", path, *lineno,
1614 line->buf);
1615 return err;
1616 }
1617 return STATUS_OK;
1618 }
1619 else if (s[0])
1620 {
1621 /* Valid hdf name is [0-9a-zA-Z_.]+ */
1622 name = s;
1623 while (*s && (isalnum(*s) || *s == '_' || *s == '.')) s++;
1624 SKIPWS(s);
1625
1626 if (s[0] == '[') /* attributes */
1627 {
1628 *s = '\0';
1629 name = neos_strip(name);
1630 s++;
1631 err = parse_attr(&s, &attr);
1632 if (err)
1633 {
1634 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1635 }
1636 SKIPWS(s);
1637 }
1638 if (s[0] == '=') /* assignment */
1639 {
1640 *s = '\0';
1641 name = neos_strip(name);
1642 s++;
1643 value = neos_strip(s);
1644 err = _set_value (hdf, name, value, 1, 1, 0, attr, NULL);
1645 if (err != STATUS_OK)
1646 {
1647 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1648 }
1649 }
1650 else if (s[0] == ':' && s[1] == '=') /* copy */
1651 {
1652 *s = '\0';
1653 name = neos_strip(name);
1654 s+=2;
1655 value = neos_strip(s);
1656 value = hdf_get_value(hdf->top, value, "");
1657 err = _set_value (hdf, name, value, 1, 1, 0, attr, NULL);
1658 if (err != STATUS_OK)
1659 {
1660 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1661 }
1662 }
1663 else if (s[0] == ':') /* link */
1664 {
1665 *s = '\0';
1666 name = neos_strip(name);
1667 s++;
1668 value = neos_strip(s);
1669 err = _set_value (hdf, name, value, 1, 1, 1, attr, NULL);
1670 if (err != STATUS_OK)
1671 {
1672 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1673 }
1674 }
1675 else if (s[0] == '{') /* deeper */
1676 {
1677 *s = '\0';
1678 name = neos_strip(name);
1679 lower = hdf_get_obj (hdf, name);
1680 if (lower == NULL)
1681 {
1682 err = _set_value (hdf, name, NULL, 1, 1, 0, attr, &lower);
1683 }
1684 else
1685 {
1686 err = _set_value (lower, NULL, lower->value, 1, 1, 0, attr, NULL);
1687 }
1688 if (err != STATUS_OK)
1689 {
1690 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1691 }
1692 err = _hdf_read_string (lower, str, line, path, lineno, include_handle);
1693 if (err != STATUS_OK)
1694 {
1695 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1696 }
1697 }
1698 else if (s[0] == '<' && s[1] == '<') /* multi-line assignment */
1699 {
1700 char *m;
1701 int msize = 0;
1702 int mmax = 128;
1703 int l;
1704
1705 *s = '\0';
1706 name = neos_strip(name);
1707 s+=2;
1708 value = neos_strip(s);
1709 l = strlen(value);
1710 if (l == 0)
1711 {
1712 err = nerr_raise(NERR_PARSE,
1713 "[%s:%d] No multi-assignment terminator given: %s", path, *lineno,
1714 line->buf);
1715 return err;
1716 }
1717 m = (char *) malloc (mmax * sizeof(char));
1718 if (m == NULL)
1719 {
1720 return nerr_raise(NERR_NOMEM,
1721 "[%s:%d] Unable to allocate memory for multi-line assignment to %s",
1722 path, *lineno, name);
1723 }
1724 while (_copy_line (str, m+msize, mmax-msize) != 0)
1725 {
1726 (*lineno)++;
1727 if (!strncmp(value, m+msize, l) && isspace(m[msize+l]))
1728 {
1729 m[msize] = '\0';
1730 break;
1731 }
1732 msize += strlen(m+msize);
1733 if (msize + l + 10 > mmax)
1734 {
1735 mmax += 128;
1736 m = (char *) realloc (m, mmax * sizeof(char));
1737 if (m == NULL)
1738 {
1739 return nerr_raise(NERR_NOMEM,
1740 "[%s:%d] Unable to allocate memory for multi-line assignment to %s: size=%d",
1741 path, *lineno, name, mmax);
1742 }
1743 }
1744 }
1745 err = _set_value (hdf, name, m, 0, 1, 0, attr, NULL);
1746 if (err != STATUS_OK)
1747 {
1748 free (m);
1749 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1750 }
1751
1752 }
1753 else
1754 {
1755 err = nerr_raise(NERR_PARSE, "[%s:%d] Unable to parse line %s", path,
1756 *lineno, line->buf);
1757 return err;
1758 }
1759 }
1760 }
1761 return STATUS_OK;
1762 }
1763
hdf_read_string(HDF * hdf,const char * str)1764 NEOERR * hdf_read_string (HDF *hdf, const char *str)
1765 {
1766 NEOERR *err;
1767 int lineno = 0;
1768 STRING line;
1769 string_init(&line);
1770 err = _hdf_read_string(hdf, &str, &line, "<string>", &lineno, INCLUDE_ERROR);
1771 string_clear(&line);
1772 return nerr_pass(err);
1773 }
1774
hdf_read_string_ignore(HDF * hdf,const char * str,int ignore)1775 NEOERR * hdf_read_string_ignore (HDF *hdf, const char *str, int ignore)
1776 {
1777 NEOERR *err;
1778 int lineno = 0;
1779 STRING line;
1780 string_init(&line);
1781 err = _hdf_read_string(hdf, &str, &line, "<string>", &lineno,
1782 (ignore ? INCLUDE_IGNORE : INCLUDE_ERROR));
1783 string_clear(&line);
1784 return nerr_pass(err);
1785 }
1786
1787 /* The search path is part of the HDF by convention */
hdf_search_path(HDF * hdf,const char * path,char * full)1788 NEOERR* hdf_search_path (HDF *hdf, const char *path, char *full)
1789 {
1790 HDF *paths;
1791 struct stat s;
1792
1793 for (paths = hdf_get_child (hdf, "hdf.loadpaths");
1794 paths;
1795 paths = hdf_obj_next (paths))
1796 {
1797 snprintf (full, _POSIX_PATH_MAX, "%s/%s", hdf_obj_value(paths), path);
1798 errno = 0;
1799 if (stat (full, &s) == -1)
1800 {
1801 if (errno != ENOENT)
1802 return nerr_raise_errno (NERR_SYSTEM, "Stat of %s failed", full);
1803 }
1804 else
1805 {
1806 return STATUS_OK;
1807 }
1808 }
1809
1810 strncpy (full, path, _POSIX_PATH_MAX);
1811 if (stat (full, &s) == -1)
1812 {
1813 if (errno != ENOENT)
1814 return nerr_raise_errno (NERR_SYSTEM, "Stat of %s failed", full);
1815 }
1816 else return STATUS_OK;
1817
1818 return nerr_raise (NERR_NOT_FOUND, "Path %s not found", path);
1819 }
1820
hdf_read_file(HDF * hdf,const char * path)1821 NEOERR* hdf_read_file (HDF *hdf, const char *path)
1822 {
1823 NEOERR *err;
1824 int lineno = 0;
1825 char fpath[_POSIX_PATH_MAX];
1826 char *ibuf = NULL;
1827 const char *ptr = NULL;
1828 HDF *top = hdf->top;
1829 STRING line;
1830
1831 string_init(&line);
1832
1833 if (path == NULL)
1834 return nerr_raise(NERR_ASSERT, "Can't read NULL file");
1835
1836 if (top->fileload)
1837 {
1838 err = top->fileload(top->fileload_ctx, hdf, path, &ibuf);
1839 }
1840 else
1841 {
1842 if (path[0] != '/')
1843 {
1844 err = hdf_search_path (hdf, path, fpath);
1845 if (err != STATUS_OK) return nerr_pass(err);
1846 path = fpath;
1847 }
1848
1849 err = ne_load_file (path, &ibuf);
1850 }
1851 if (err) return nerr_pass(err);
1852
1853 ptr = ibuf;
1854 err = _hdf_read_string(hdf, &ptr, &line, path, &lineno, INCLUDE_FILE);
1855 free(ibuf);
1856 string_clear(&line);
1857 return nerr_pass(err);
1858 }
1859
hdf_register_fileload(HDF * hdf,void * ctx,HDFFILELOAD fileload)1860 void hdf_register_fileload(HDF *hdf, void *ctx, HDFFILELOAD fileload)
1861 {
1862 if (hdf == NULL) return;
1863 if (hdf->top != NULL) hdf = hdf->top;
1864 hdf->fileload_ctx = ctx;
1865 hdf->fileload = fileload;
1866 }
1867
1868