Move the job of converting provided coeffects to ambient coeffects from callee to...
[hiphop-php.git] / hphp / neo / neo_hdf.c
blob50dc108eccd3024e17ce9a94e974ff859a521bbc
1 /*
2 * Copyright 2001-2004 Brandon Long
3 * All Rights Reserved.
5 * ClearSilver Templating System
7 * This code is made available under the terms of the ClearSilver License.
8 * http://www.clearsilver.net/license.hdf
12 #include "cs_config.h"
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <limits.h>
20 #include <stdarg.h>
21 #include <sys/stat.h>
23 #ifdef _MSC_VER
24 #include <windows.h>
25 #include <direct.h>
26 #include <io.h>
27 #define PATH_MAX MAX_PATH
28 #else
29 #include <unistd.h>
30 #endif
32 #include "neo_misc.h"
33 #include "neo_err.h"
34 #include "neo_rand.h"
35 #include "neo_hdf.h"
36 #include "neo_str.h"
37 #include "neo_files.h"
38 #include "ulist.h"
40 static NEOERR* hdf_read_file_internal (HDF *hdf, const char *path,
41 int include_handle);
44 static char *_read_file(FILE *f) {
45 int size = 1024;
46 char *ret = malloc(size + 1);
47 char *newret;
49 size_t nread;
50 char *buf = ret;
51 int len = size;
52 while ((nread = fread(buf, 1, len, f))) {
53 buf += nread;
54 len -= nread;
55 if (len == 0) {
56 len = size;
57 size <<= 1;
59 newret = realloc(ret, size + 1);
60 buf = buf - ret + newret;
61 ret = newret;
64 *buf = '\0';
65 return ret;
68 /* Ok, in order to use the hash, we have to support n-len strings
69 * instead of null terminated strings (since in set_value and walk_hdf
70 * we are merely using part of the HDF name for lookup, and that might
71 * be a const, and we don't want the overhead of allocating/copying
72 * that data out...)
74 * Since HASH doesn't maintain any data placed in it, merely pointers to
75 * it, we use the HDF node itself as the key, and have specific
76 * comp/hash functions which just use the name/name_len as the key.
79 static int hash_hdf_comp(const void *a, const void *b)
81 HDF *ha = (HDF *)a;
82 HDF *hb = (HDF *)b;
84 return (ha->name_len == hb->name_len) && !strncmp(ha->name, hb->name, ha->name_len);
87 static UINT32 hash_hdf_hash(const void *a)
89 HDF *ha = (HDF *)a;
90 return ne_crc((UINT8 *)(ha->name), ha->name_len);
93 static NEOERR *_alloc_hdf (HDF **hdf, const char *name, size_t nlen,
94 const char *value, int dupl, int wf, HDF *top)
96 *hdf = calloc (1, sizeof (HDF));
97 if (*hdf == NULL)
99 return nerr_raise (NERR_NOMEM, "Unable to allocate memory for hdf element");
102 (*hdf)->top = top;
104 if (name != NULL)
106 (*hdf)->name_len = nlen;
107 (*hdf)->name = (char *) malloc (nlen + 1);
108 if ((*hdf)->name == NULL)
110 free((*hdf));
111 (*hdf) = NULL;
112 return nerr_raise (NERR_NOMEM,
113 "Unable to allocate memory for hdf element: %s", name);
115 strncpy((*hdf)->name, name, nlen);
116 (*hdf)->name[nlen] = '\0';
118 if (value != NULL)
120 if (dupl)
122 (*hdf)->alloc_value = 1;
123 (*hdf)->value = strdup(value);
124 if ((*hdf)->value == NULL)
126 free((*hdf)->name);
127 free((*hdf));
128 (*hdf) = NULL;
129 return nerr_raise (NERR_NOMEM,
130 "Unable to allocate memory for hdf element %s", name);
133 else
135 (*hdf)->alloc_value = wf;
136 /* We're overriding the const of value here for the set_buf case
137 * where we overrode the char * to const char * earlier, since
138 * alloc_value actually keeps track of the const-ness for us */
139 (*hdf)->value = (char *)value;
142 return STATUS_OK;
145 static void _dealloc_hdf_attr(HDF_ATTR **attr)
147 HDF_ATTR *next;
149 while ((*attr) != NULL)
151 next = (*attr)->next;
152 if ((*attr)->key) free((*attr)->key);
153 if ((*attr)->value) free((*attr)->value);
154 free(*attr);
155 *attr = next;
157 *attr = NULL;
160 static void _dealloc_hdf (HDF **hdf)
162 HDF *myhdf = *hdf;
163 HDF *next = NULL;
165 if (myhdf == NULL) return;
166 if (myhdf->child != NULL)
167 _dealloc_hdf(&(myhdf->child));
169 /* This was easier recursively, but dangerous on long lists, so we
170 * walk it ourselves */
171 next = myhdf->next;
172 while (next != NULL)
174 myhdf->next = next->next;
175 next->next = NULL;
176 _dealloc_hdf(&next);
177 next = myhdf->next;
179 if (myhdf->name != NULL)
181 free (myhdf->name);
182 myhdf->name = NULL;
184 if (myhdf->value != NULL)
186 if (myhdf->alloc_value)
187 free (myhdf->value);
188 myhdf->value = NULL;
190 if (myhdf->attr != NULL)
192 _dealloc_hdf_attr(&(myhdf->attr));
194 if (myhdf->hash != NULL)
196 ne_hash_destroy(&myhdf->hash);
198 free(myhdf);
199 *hdf = NULL;
202 NEOERR* hdf_init (HDF **hdf)
204 NEOERR *err;
205 HDF *my_hdf;
207 *hdf = NULL;
209 err = nerr_init();
210 if (err != STATUS_OK)
211 return nerr_pass (err);
213 err = _alloc_hdf (&my_hdf, NULL, 0, NULL, 0, 0, NULL);
214 if (err != STATUS_OK)
215 return nerr_pass (err);
217 my_hdf->top = my_hdf;
219 *hdf = my_hdf;
221 return STATUS_OK;
224 void hdf_destroy (HDF **hdf)
226 if (*hdf == NULL) return;
227 if ((*hdf)->top == (*hdf))
229 _dealloc_hdf(hdf);
233 #define WALK_MAX_DEPTH 1000
235 static int _walk_hdf (HDF *hdf, const char *name, HDF **node,
236 NEOERR** err, int recursion)
238 HDF *parent = NULL;
239 HDF *hp = hdf;
240 HDF hash_key;
241 int x = 0;
242 const char *s, *n;
243 int r;
245 *node = NULL;
247 if (hdf == NULL) return -1;
248 if (name == NULL || name[0] == '\0')
250 *node = hdf;
251 return 0;
254 if (hdf->link)
256 if (recursion >= WALK_MAX_DEPTH) {
257 *err = nerr_raise (NERR_MAX_RECURSION,
258 "Recursion limit reached in _walk_hdf"
260 return -1;
262 r = _walk_hdf (hdf->top, hdf->value, &hp, err, recursion + 1);
263 if (r) return r;
264 if (hp)
266 parent = hp;
267 hp = hp->child;
270 else
272 parent = hdf;
273 hp = hdf->child;
275 if (hp == NULL)
277 return -1;
280 n = name;
281 s = strchr (n, '.');
282 x = (s == NULL) ? strlen(n) : s - n;
284 while (1)
286 if (parent && parent->hash)
288 hash_key.name = (char *)n;
289 hash_key.name_len = x;
290 hp = ne_hash_lookup(parent->hash, &hash_key);
292 else
294 while (hp != NULL)
296 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
298 break;
300 else
302 hp = hp->next;
306 if (hp == NULL)
308 return -1;
310 if (s == NULL) break;
312 if (hp->link)
314 if (recursion >= WALK_MAX_DEPTH) {
315 *err = nerr_raise (NERR_MAX_RECURSION,
316 "Recursion limit reached in _walk_hdf"
318 return -1;
320 r = _walk_hdf (hp->top, hp->value, &hp, err, recursion + 1);
321 if (r) {
322 return r;
324 parent = hp;
325 hp = hp->child;
327 else
329 parent = hp;
330 hp = hp->child;
332 n = s + 1;
333 s = strchr (n, '.');
334 x = (s == NULL) ? strlen(n) : s - n;
336 if (hp->link)
338 if (recursion >= WALK_MAX_DEPTH) {
339 *err = nerr_raise (NERR_MAX_RECURSION,
340 "Recursion limit reached in _walk_hdf"
342 return -1;
344 return _walk_hdf (hp->top, hp->value, node, err, recursion + 1);
347 *node = hp;
348 return 0;
351 HDF* hdf_get_obj (HDF *hdf, const char *name, NEOERR** err)
353 HDF *obj;
355 _walk_hdf(hdf, name, &obj, err, 0);
356 return obj;
359 HDF* hdf_get_child (HDF *hdf, const char *name, NEOERR** err)
361 HDF *obj;
362 _walk_hdf(hdf, name, &obj, err, 0);
363 if (obj != NULL) return obj->child;
364 return obj;
367 void hdf_set_visited (HDF *hdf, int visited) {
368 if (hdf) hdf->visited = visited;
371 int hdf_is_visited (HDF *hdf) {
372 return hdf ? hdf->visited : 0;
375 HDF* hdf_obj_child (HDF *hdf, NEOERR** err)
377 HDF *obj;
378 if (hdf == NULL) return NULL;
379 if (hdf->link)
381 if (_walk_hdf(hdf->top, hdf->value, &obj, err, 0))
382 return NULL;
383 return obj->child;
385 return hdf->child;
388 HDF* hdf_obj_next (HDF *hdf)
390 if (hdf == NULL) return NULL;
391 return hdf->next;
394 char* hdf_obj_name (HDF *hdf)
396 if (hdf == NULL) return NULL;
397 return hdf->name;
400 char* hdf_obj_value (HDF *hdf, NEOERR** err)
402 int count = 0;
404 if (hdf == NULL) return NULL;
405 while (hdf->link && count < 100)
407 if (_walk_hdf (hdf->top, hdf->value, &hdf, err, 0))
408 return NULL;
409 count++;
411 return hdf->value;
414 void _merge_attr (HDF_ATTR *dest, HDF_ATTR *src)
416 HDF_ATTR *da, *ld;
417 HDF_ATTR *sa, *ls;
418 char found;
420 sa = src;
421 ls = src;
422 while (sa != NULL)
424 da = dest;
425 ld = da;
426 found = 0;
427 while (da != NULL)
429 if (!strcmp(da->key, sa->key))
431 if (da->value) free(da->value);
432 da->value = sa->value;
433 sa->value = NULL;
434 found = 1;
435 break;
437 ld = da;
438 da = da->next;
440 if (!found)
442 ld->next = sa;
443 ls->next = sa->next;
444 if (src == sa) src = sa->next;
445 ld->next->next = NULL;
446 sa = ls->next;
448 else
450 ls = sa;
451 sa = sa->next;
454 _dealloc_hdf_attr(&src);
457 NEOERR* _hdf_hash_level(HDF *hdf)
459 NEOERR *err;
460 HDF *child;
462 err = ne_hash_init(&(hdf->hash), hash_hdf_hash, hash_hdf_comp);
463 if (err) return nerr_pass(err);
465 child = hdf->child;
466 while (child)
468 err = ne_hash_insert(hdf->hash, child, child);
469 if (err) return nerr_pass(err);
470 child = child->next;
472 return STATUS_OK;
475 static NEOERR* _set_value (HDF *hdf, const char *name, const char *value,
476 int dupl, int wf, int lnk, HDF_ATTR *attr,
477 HDF **set_node)
479 NEOERR *err;
480 HDF *hn, *hp, *hs;
481 HDF hash_key;
482 int x = 0;
483 const char *s = name;
484 const char *n = name;
485 int count = 0;
487 if (set_node != NULL) *set_node = NULL;
488 if (hdf == NULL)
490 return nerr_raise(NERR_ASSERT, "Unable to set %s on NULL hdf", name);
493 /* HACK: allow setting of this node by passing an empty name */
494 if (name == NULL || name[0] == '\0')
496 /* handle setting attr first */
497 if (hdf->attr == NULL)
499 hdf->attr = attr;
501 else
503 _merge_attr(hdf->attr, attr);
505 /* set link flag */
506 if (lnk) hdf->link = 1;
507 else hdf->link = 0;
508 /* if we're setting ourselves to ourselves... */
509 if (hdf->value == value)
511 if (set_node != NULL) *set_node = hdf;
512 return STATUS_OK;
514 if (hdf->alloc_value)
516 free(hdf->value);
517 hdf->value = NULL;
519 if (value == NULL)
521 hdf->alloc_value = 0;
522 hdf->value = NULL;
524 else if (dupl)
526 hdf->alloc_value = 1;
527 hdf->value = strdup(value);
528 if (hdf->value == NULL)
529 return nerr_raise (NERR_NOMEM, "Unable to duplicate value %s for %s",
530 value, hdf->name);
532 else
534 hdf->alloc_value = wf;
535 hdf->value = (char *)value;
537 if (set_node != NULL) *set_node = hdf;
538 return STATUS_OK;
541 n = name;
542 s = strchr (n, '.');
543 x = (s != NULL) ? s - n : strlen(n);
544 if (x == 0)
546 return nerr_raise(NERR_ASSERT, "Unable to set Empty component %s", name);
549 if (hdf->link)
551 char *new_name = (char *) malloc(strlen(hdf->value) + 1 + strlen(name) + 1);
552 if (new_name == NULL)
554 return nerr_raise(NERR_NOMEM, "Unable to allocate memory");
556 strcpy(new_name, hdf->value);
557 strcat(new_name, ".");
558 strcat(new_name, name);
559 err = _set_value (hdf->top, new_name, value, dupl, wf, lnk, attr, set_node);
560 free(new_name);
561 return nerr_pass(err);
563 else
565 hn = hdf;
568 while (1)
570 /* examine cache to see if we have a match */
571 count = 0;
572 hp = hn->last_hp;
573 hs = hn->last_hs;
575 if ((hs == NULL && hp == hn->child) || (hs && hs->next == hp))
577 if (hp && hp->name && (x == hp->name_len) && !strncmp (hp->name, n, x))
579 goto skip_search;
583 hp = hn->child;
584 hs = NULL;
586 /* Look for a matching node at this level */
587 if (hn->hash != NULL)
589 hash_key.name = (char *)n;
590 hash_key.name_len = x;
591 hp = ne_hash_lookup(hn->hash, &hash_key);
592 hs = hn->last_child;
594 else
596 while (hp != NULL)
598 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
600 break;
602 hs = hp;
603 hp = hp->next;
604 count++;
608 /* save in cache any value we found */
609 if (hp) {
610 hn->last_hp = hp;
611 hn->last_hs = hs;
614 skip_search:
616 if (hp == NULL)
618 /* If there was no matching node at this level, we need to
619 * allocate an intersitial node (or the actual node if we're
620 * at the last part of the HDF name) */
621 if (s != NULL)
623 /* intersitial */
624 err = _alloc_hdf (&hp, n, x, NULL, 0, 0, hdf->top);
626 else
628 err = _alloc_hdf (&hp, n, x, value, dupl, wf, hdf->top);
629 if (lnk) hp->link = 1;
630 else hp->link = 0;
631 hp->attr = attr;
633 if (err != STATUS_OK)
634 return nerr_pass (err);
635 if (hn->child == NULL)
636 hn->child = hp;
637 else
638 hs->next = hp;
639 hn->last_child = hp;
641 /* This is the point at which we convert to a hash table
642 * at this level, if we're over the count */
643 if (count > FORCE_HASH_AT && hn->hash == NULL)
645 err = _hdf_hash_level(hn);
646 if (err) return nerr_pass(err);
648 else if (hn->hash != NULL)
650 err = ne_hash_insert(hn->hash, hp, hp);
651 if (err) return nerr_pass(err);
654 else if (s == NULL)
656 /* If there is a matching node and we're at the end of the HDF
657 * name, then we update the value of the node */
658 /* handle setting attr first */
659 if (hp->attr == NULL)
661 hp->attr = attr;
663 else
665 _merge_attr(hp->attr, attr);
667 if (hp->value != value)
669 if (hp->alloc_value)
671 free(hp->value);
672 hp->value = NULL;
674 if (value == NULL)
676 hp->alloc_value = 0;
677 hp->value = NULL;
679 else if (dupl)
681 hp->alloc_value = 1;
682 hp->value = strdup(value);
683 if (hp->value == NULL)
684 return nerr_raise (NERR_NOMEM, "Unable to duplicate value %s for %s",
685 value, name);
687 else
689 hp->alloc_value = wf;
690 hp->value = (char *)value;
693 if (lnk) hp->link = 1;
694 else hp->link = 0;
696 else if (hp->link)
698 char *new_name = (char *) malloc(strlen(hp->value) + strlen(s) + 1);
699 if (new_name == NULL)
701 return nerr_raise(NERR_NOMEM, "Unable to allocate memory");
703 strcpy(new_name, hp->value);
704 strcat(new_name, s);
705 err = _set_value (hdf->top, new_name, value, dupl, wf, lnk, attr, set_node);
706 free(new_name);
707 return nerr_pass(err);
709 /* At this point, we're done if there is not more HDF name space to
710 * traverse */
711 if (s == NULL)
712 break;
713 /* Otherwise, we need to find the next part of the namespace */
714 n = s + 1;
715 s = strchr (n, '.');
716 x = (s != NULL) ? s - n : strlen(n);
717 if (x == 0)
719 return nerr_raise(NERR_ASSERT, "Unable to set Empty component %s", name);
721 hn = hp;
723 if (set_node != NULL) *set_node = hp;
724 return STATUS_OK;
727 NEOERR* hdf_set_value (HDF *hdf, const char *name, const char *value)
729 return nerr_pass(_set_value (hdf, name, value, 1, 1, 0, NULL, NULL));
732 NEOERR* hdf_get_node (HDF *hdf, const char *name, HDF **ret)
734 NEOERR* err = STATUS_OK;
735 _walk_hdf(hdf, name, ret, &err, 0);
736 if (*ret == NULL)
738 if (err != STATUS_OK) return err;
739 return nerr_pass(_set_value (hdf, name, NULL, 0, 1, 0, NULL, ret));
741 return STATUS_OK;
744 NEOERR* hdf_remove_tree (HDF *hdf, const char *name)
746 HDF *hp = hdf;
747 HDF *lp = NULL, *ln = NULL; /* last parent, last node */
748 int x = 0;
749 const char *s = name;
750 const char *n = name;
752 if (hdf == NULL) return STATUS_OK;
754 hp = hdf->child;
755 if (hp == NULL)
757 return STATUS_OK;
760 lp = hdf;
761 ln = NULL;
763 n = name;
764 s = strchr (n, '.');
765 x = (s == NULL) ? strlen(n) : s - n;
767 while (1)
769 while (hp != NULL)
771 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
773 break;
775 else
777 ln = hp;
778 hp = hp->next;
781 if (hp == NULL)
783 return STATUS_OK;
785 if (s == NULL) break;
787 lp = hp;
788 ln = NULL;
789 hp = hp->child;
790 n = s + 1;
791 s = strchr (n, '.');
792 x = (s == NULL) ? strlen(n) : s - n;
795 if (lp->hash != NULL)
797 ne_hash_remove(lp->hash, hp);
799 if (ln)
801 ln->next = hp->next;
802 /* check to see if we are the last parent's last_child, if so
803 * repoint so hash table inserts will go to the right place */
804 if (hp == lp->last_child)
805 lp->last_child = ln;
806 hp->next = NULL;
808 else
810 lp->child = hp->next;
811 hp->next = NULL;
813 _dealloc_hdf (&hp);
815 return STATUS_OK;
818 static NEOERR * _copy_attr (HDF_ATTR **dest, HDF_ATTR *src)
820 HDF_ATTR *copy, *last = NULL;
822 *dest = NULL;
823 while (src != NULL)
825 copy = (HDF_ATTR *)malloc(sizeof(HDF_ATTR));
826 if (copy == NULL)
828 _dealloc_hdf_attr(dest);
829 return nerr_raise(NERR_NOMEM, "Unable to allocate copy of HDF_ATTR");
831 copy->key = strdup(src->key);
832 copy->value = strdup(src->value);
833 copy->next = NULL;
834 if ((copy->key == NULL) || (copy->value == NULL))
836 _dealloc_hdf_attr(dest);
837 return nerr_raise(NERR_NOMEM, "Unable to allocate copy of HDF_ATTR");
839 if (last) {
840 last->next = copy;
842 else
844 *dest = copy;
846 last = copy;
847 src = src->next;
849 return STATUS_OK;
852 static NEOERR * _copy_nodes (HDF *dest, HDF *src)
854 NEOERR *err = STATUS_OK;
855 HDF *dt, *st;
856 HDF_ATTR *attr_copy;
858 st = src->child;
859 while (st != NULL)
861 err = _copy_attr(&attr_copy, st->attr);
862 if (err) return nerr_pass(err);
863 err = _set_value(dest, st->name, st->value, 1, 1, st->link, attr_copy, &dt);
864 if (err) {
865 _dealloc_hdf_attr(&attr_copy);
866 return nerr_pass(err);
868 if (src->child)
870 err = _copy_nodes (dt, st);
871 if (err) return nerr_pass(err);
873 st = st->next;
875 return STATUS_OK;
878 NEOERR* hdf_copy (HDF *dest, const char *name, HDF *src)
880 NEOERR *err;
881 HDF *node;
882 HDF_ATTR *attr_copy;
884 err = STATUS_OK;
885 if (_walk_hdf(dest, name, &node, &err, 0) == -1)
887 if (err) return err;
888 err = _copy_attr(&attr_copy, src->attr);
889 if (err) return nerr_pass(err);
890 err = _set_value (dest, name, src->value, 1, 1, src->link, attr_copy,
891 &node);
892 if (err) {
893 _dealloc_hdf_attr(&attr_copy);
894 return nerr_pass(err);
897 return nerr_pass (_copy_nodes (node, src));
900 /* BUG: currently, this only prints something if there is a value...
901 * but we now allow attributes on nodes with no value... */
903 static void gen_ml_break(char *ml, size_t len)
905 int nlen;
906 int x = 0;
908 ml[x++] = '\n';
909 nlen = 2 + neo_rand(len-5);
910 if (nlen == 0)
912 nlen = len / 2;
914 while (nlen)
916 ml[x++] = ('A' + neo_rand(26));
917 nlen--;
919 ml[x++] = '\n';
920 ml[x] = '\0';
923 typedef NEOERR *(*DUMPF_CB)(void *rock, const char *fmt, ...);
925 static NEOERR *_fp_dump_cb (void *rock, const char *fmt, ...)
927 FILE *fp = (FILE *)rock;
928 va_list ap;
930 va_start (ap, fmt);
931 vfprintf(fp, fmt, ap);
932 va_end(ap);
933 return STATUS_OK;
936 static NEOERR *_string_dump_cb (void *rock, const char *fmt, ...)
938 NEOERR *err;
939 NEOSTRING *str = (NEOSTRING *)rock;
940 va_list ap;
942 va_start (ap, fmt);
943 err = string_appendvf(str, fmt, ap);
944 va_end(ap);
945 return nerr_pass(err);
948 #define DUMP_TYPE_DOTTED 0
949 #define DUMP_TYPE_COMPACT 1
950 #define DUMP_TYPE_PRETTY 2
952 static NEOERR* hdf_dump_cb(HDF *hdf, const char *prefix, int dtype, int lvl,
953 void *rock, DUMPF_CB dump_cbf)
955 NEOERR *err;
956 char *p, op;
957 char ml[10] = "\nEOM\n";
958 int ml_len = strlen(ml);
959 char whsp[256] = "";
961 if (dtype == DUMP_TYPE_PRETTY)
963 memset(whsp, ' ', 256);
964 if (lvl > 127)
965 lvl = 127;
966 whsp[lvl*2] = '\0';
969 if (hdf != NULL) hdf = hdf->child;
971 while (hdf != NULL)
973 op = '=';
974 if (hdf->value)
976 if (hdf->link) op = ':';
977 if (prefix && (dtype == DUMP_TYPE_DOTTED))
979 err = dump_cbf(rock, "%s.%s", prefix, hdf->name);
981 else
983 err = dump_cbf(rock, "%s%s", whsp, hdf->name);
985 if (err) return nerr_pass (err);
986 if (hdf->attr)
988 HDF_ATTR *attr = hdf->attr;
989 char *v = NULL;
991 err = dump_cbf(rock, " [");
992 if (err) return nerr_pass(err);
993 while (attr != NULL)
995 //#undef strcmp
996 if (attr->value == NULL || !strcmp(attr->value, "1"))
997 err = dump_cbf(rock, "%s", attr->key);
998 else
1000 v = repr_string_alloc(attr->value);
1002 if (v == NULL)
1003 return nerr_raise(NERR_NOMEM, "Unable to repr attr %s value %s", attr->key, attr->value);
1004 err = dump_cbf(rock, "%s=%s", attr->key, v);
1005 free(v);
1007 if (err) return nerr_pass(err);
1008 if (attr->next)
1010 err = dump_cbf(rock, ", ");
1011 if (err) return nerr_pass(err);
1013 attr = attr->next;
1015 err = dump_cbf(rock, "] ");
1016 if (err) return nerr_pass(err);
1018 if (strchr (hdf->value, '\n'))
1020 int vlen = strlen(hdf->value);
1022 while (strstr(hdf->value, ml) || ((vlen > ml_len) && !strncmp(hdf->value + vlen - ml_len + 1, ml, strlen(ml) - 1)))
1024 gen_ml_break(ml, sizeof(ml));
1025 ml_len = strlen(ml);
1027 if (hdf->value[strlen(hdf->value)-1] != '\n')
1028 err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml);
1029 else
1030 err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml+1);
1032 else
1034 err = dump_cbf(rock, " %c %s\n", op, hdf->value);
1036 if (err) return nerr_pass (err);
1038 if (hdf->child)
1040 if (prefix && (dtype == DUMP_TYPE_DOTTED))
1042 size_t p_len = strlen(hdf->name) + strlen(prefix) + 2;
1043 p = (char *) malloc (p_len);
1044 snprintf (p, p_len, "%s.%s", prefix, hdf->name);
1046 err = hdf_dump_cb (hdf, p, dtype, lvl+1, rock, dump_cbf);
1047 free(p);
1049 else
1051 if (hdf->name && (dtype != DUMP_TYPE_DOTTED))
1053 err = dump_cbf(rock, "%s%s {\n", whsp, hdf->name);
1054 if (err) return nerr_pass (err);
1055 err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
1056 if (err) return nerr_pass (err);
1057 err = dump_cbf(rock, "%s}\n", whsp);
1059 else
1061 err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
1064 if (err) return nerr_pass (err);
1066 hdf = hdf->next;
1068 return STATUS_OK;
1071 NEOERR* hdf_dump_str (HDF *hdf, const char *prefix, int dtype, NEOSTRING *str)
1073 return nerr_pass(hdf_dump_cb(hdf, prefix, dtype, 0, str, _string_dump_cb));
1076 NEOERR* hdf_dump_format (HDF *hdf, int lvl, FILE *fp)
1078 return nerr_pass(hdf_dump_cb(hdf, "", DUMP_TYPE_PRETTY, 0, fp, _fp_dump_cb));
1081 NEOERR *hdf_write_file (HDF *hdf, const char *path)
1083 NEOERR *err;
1084 FILE *fp;
1086 fp = fopen(path, "w");
1087 if (fp == NULL)
1088 return nerr_raise_errno (NERR_IO, "Unable to open %s for writing", path);
1090 err = hdf_dump_format (hdf, 0, fp);
1092 fclose (fp);
1093 if (err)
1095 unlink(path);
1097 return nerr_pass(err);
1100 NEOERR *hdf_write_string (HDF *hdf, char **s)
1102 NEOSTRING str;
1103 NEOERR *err;
1105 *s = NULL;
1107 string_init (&str);
1109 err = hdf_dump_str (hdf, NULL, 2, &str);
1110 if (err)
1112 string_clear (&str);
1113 return nerr_pass(err);
1115 if (str.buf == NULL)
1117 *s = strdup("");
1118 if (*s == NULL) return nerr_raise(NERR_NOMEM, "Unable to allocate empty string");
1120 else
1122 *s = str.buf;
1125 return STATUS_OK;
1129 #define SKIPWS(s) while (*s && isspace(*s)) s++;
1131 static int _copy_line (const char **s, char *buf, size_t buf_len)
1133 int x = 0;
1134 const char *st = *s;
1136 while (*st && x < buf_len-1)
1138 buf[x++] = *st;
1139 if (*st++ == '\n') break;
1141 buf[x] = '\0';
1142 *s = st;
1144 return x;
1147 /* Copy the characters in the file (up to the next newline) into line
1148 * and advance s to the next line */
1149 static NEOERR *_copy_line_advance(const char **s, NEOSTRING *line)
1151 NEOERR *err;
1152 int x = 0;
1153 const char *st = *s;
1154 const char *nl;
1156 nl = strchr(st, '\n');
1157 if (nl == NULL)
1159 x = strlen(st);
1160 err = string_appendn(line, st, x);
1161 if (err) return nerr_pass(err);
1162 *s = st + x;
1164 else
1166 x = nl - st;
1167 err = string_appendn(line, st, x);
1168 if (err) return nerr_pass(err);
1169 *s = nl + 1;
1172 return STATUS_OK;
1175 char *_strndup(const char *s, int len) {
1176 int x;
1177 char *dupl;
1178 if (s == NULL) return NULL;
1179 dupl = (char *) malloc(len+1);
1180 if (dupl == NULL) return NULL;
1181 for (x = 0; x < len && s[x]; x++)
1183 dupl[x] = s[x];
1185 dupl[x] = '\0';
1186 dupl[len] = '\0';
1187 return dupl;
1190 /* attributes are of the form [key1, key2, key3=value, key4="repr"] */
1191 static NEOERR* parse_attr(char **str, HDF_ATTR **attr)
1193 NEOERR *err = STATUS_OK;
1194 char *s = *str;
1195 char *k, *v;
1196 int k_l, v_l;
1197 NEOSTRING buf;
1198 char c;
1199 HDF_ATTR *ha, *hal = NULL;
1201 *attr = NULL;
1203 string_init(&buf);
1204 while (*s && *s != ']')
1206 k = s;
1207 k_l = 0;
1208 v = NULL;
1209 v_l = 0;
1210 while (*s && isalnum(*s)) s++;
1211 k_l = s-k;
1212 if (*s == '\0' || k_l == 0)
1214 _dealloc_hdf_attr(attr);
1215 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1217 SKIPWS(s);
1218 if (*s == '=')
1220 s++;
1221 SKIPWS(s);
1222 if (*s == '"')
1224 s++;
1225 while (*s && *s != '"')
1227 if (*s == '\\')
1229 if (isdigit(*(s+1)))
1231 s++;
1232 c = *s - '0';
1233 if (isdigit(*(s+1)))
1235 s++;
1236 c = (c * 8) + (*s - '0');
1237 if (isdigit(*(s+1)))
1239 s++;
1240 c = (c * 8) + (*s - '0');
1244 else
1246 s++;
1247 if (*s == 'n') c = '\n';
1248 else if (*s == 't') c = '\t';
1249 else if (*s == 'r') c = '\r';
1250 else c = *s;
1252 err = string_append_char(&buf, c);
1254 else
1256 err = string_append_char(&buf, *s);
1258 if (err)
1260 string_clear(&buf);
1261 _dealloc_hdf_attr(attr);
1262 return nerr_pass(err);
1264 s++;
1266 if (*s == '\0')
1268 _dealloc_hdf_attr(attr);
1269 string_clear(&buf);
1270 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1272 s++;
1273 v = buf.buf;
1274 v_l = buf.len;
1276 else
1278 v = s;
1279 while (*s && *s != ' ' && *s != ',' && *s != ']') s++;
1280 if (*s == '\0')
1282 _dealloc_hdf_attr(attr);
1283 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1285 v_l = s-v;
1288 else
1290 v = "1";
1292 ha = (HDF_ATTR*) calloc (1, sizeof(HDF_ATTR));
1293 if (ha == NULL)
1295 _dealloc_hdf_attr(attr);
1296 string_clear(&buf);
1297 return nerr_raise(NERR_NOMEM, "Unable to load attributes: %s", s);
1299 if (*attr == NULL) *attr = ha;
1300 ha->key = _strndup(k, k_l);
1301 if (v)
1302 ha->value = _strndup(v, v_l);
1303 else
1304 ha->value = strdup("");
1305 if (ha->key == NULL || ha->value == NULL)
1307 _dealloc_hdf_attr(attr);
1308 string_clear(&buf);
1309 return nerr_raise(NERR_NOMEM, "Unable to load attributes: %s", s);
1311 if (hal != NULL) hal->next = ha;
1312 hal = ha;
1313 string_clear(&buf);
1314 SKIPWS(s);
1315 if (*s == ',')
1317 s++;
1318 SKIPWS(s);
1321 if (*s == '\0')
1323 _dealloc_hdf_attr(attr);
1324 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1326 *str = s+1;
1327 return STATUS_OK;
1330 #define INCLUDE_ERROR -1
1331 #define INCLUDE_IGNORE -2
1332 #define INCLUDE_FILE 0
1333 #define INCLUDE_MAX_DEPTH 50
1335 static NEOERR* _hdf_read_string (HDF *hdf, const char **str, NEOSTRING *line,
1336 const char *path, int *lineno,
1337 int include_handle, int expect_end_brace) {
1338 NEOERR *err;
1339 HDF *lower;
1340 char *s;
1341 char *name, *value;
1342 HDF_ATTR *attr = NULL;
1344 while (**str != '\0')
1346 /* Reset string length, but don't free the reserved buffer */
1347 line->len = 0;
1348 err = _copy_line_advance(str, line);
1349 if (err) return nerr_pass(err);
1350 attr = NULL;
1351 (*lineno)++;
1352 s = line->buf;
1353 SKIPWS(s);
1354 if ((!strncmp(s, "#include ", 9) || !strncmp(s, "-include ", 9)) && include_handle != INCLUDE_IGNORE)
1356 int required = !strncmp(s, "#include ", 9);
1357 if (include_handle == INCLUDE_ERROR)
1359 return nerr_raise (NERR_PARSE,
1360 "[%d]: #include not supported in string parse",
1361 *lineno);
1363 else if (include_handle < INCLUDE_MAX_DEPTH)
1365 int l;
1366 s += 9;
1367 name = neos_strip(s);
1368 l = strlen(name);
1369 if (name[0] == '"' && name[l-1] == '"')
1371 name[l-1] = '\0';
1372 name++;
1374 char fullpath[PATH_MAX];
1375 if (name[0] != '/') {
1376 memset(fullpath, 0, PATH_MAX);
1378 char *p = strrchr(path, '/');
1379 if (p == NULL) {
1380 char pwd[PATH_MAX];
1381 memset(pwd, 0, PATH_MAX);
1382 getcwd(pwd, PATH_MAX);
1383 snprintf(fullpath, PATH_MAX, "%s/%s", pwd, name);
1384 } else {
1385 int dir_len = p - path + 1;
1386 snprintf(fullpath, PATH_MAX, "%s", path);
1387 snprintf(fullpath + dir_len, PATH_MAX - dir_len, "%s", name);
1389 name = fullpath;
1391 err = hdf_read_file_internal(hdf, name, include_handle + 1);
1392 if (err != STATUS_OK && required)
1394 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1397 else {
1398 return nerr_raise (NERR_MAX_RECURSION,
1399 "[%d]: Too many recursion levels.",
1400 *lineno
1404 else if (s[0] == '#')
1406 /* comment: pass */
1408 else if (s[0] == '}') /* up */
1410 s = neos_strip(s);
1411 if (strcmp(s, "}"))
1413 err = nerr_raise(NERR_PARSE,
1414 "[%s:%d] Trailing garbage on line following }: %s", path, *lineno,
1415 line->buf);
1416 return err;
1418 return STATUS_OK;
1420 else if (s[0])
1422 /* Valid hdf name is [0-9a-zA-Z_.*\]+ */
1423 int splice = *s == '@';
1424 if (splice) s++;
1425 name = s;
1426 while (*s && (isalnum(*s) || *s == '_' || *s == '.' || *s == '*' || *s == '\\')) s++;
1427 SKIPWS(s);
1429 char num[256];
1430 static int counter = 0;
1431 char *p;
1432 int i = 0;
1433 for (p = name; p < s && i < 200; p++) {
1434 if (*p != '*') {
1435 num[i++] = *p;
1436 } else {
1437 i += snprintf(num + i, 256 - i, "%d", counter++);
1438 name = num;
1441 num[i] = '\0';
1443 if (s[0] == '[') /* attributes */
1445 *s = '\0';
1446 name = neos_strip(name);
1447 s++;
1448 err = parse_attr(&s, &attr);
1449 if (err)
1451 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1453 SKIPWS(s);
1455 if (splice) {
1456 name = neos_strip(name);
1457 HDF *h = hdf_get_obj(hdf->top, name, &err);
1458 if (err != STATUS_OK) {
1459 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1461 if (h) {
1462 HDF *c = hdf_obj_child(h, &err);
1463 if (err != STATUS_OK) {
1464 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1466 while (c) {
1467 err = hdf_copy (hdf, hdf_obj_name(c), c);
1468 if (err != STATUS_OK) break;
1469 c = hdf_obj_next(c);
1472 if (err != STATUS_OK)
1474 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1476 } else if (s[0] == '=') /* assignment */
1478 *s = '\0';
1479 name = neos_strip(name);
1480 s++;
1481 value = neos_strip(s);
1482 err = _set_value (hdf, name, value, 1, 1, 0, attr, NULL);
1483 if (err != STATUS_OK)
1485 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1488 else if (s[0] == ':' && s[1] == '=') /* copy */
1490 *s = '\0';
1491 name = neos_strip(name);
1492 s+=2;
1493 value = neos_strip(s);
1494 HDF *h = hdf_get_obj(hdf->top, value, &err);
1495 if (err != STATUS_OK) {
1496 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1498 if (!h)
1500 err = nerr_raise(NERR_PARSE,
1501 "[%s:%d] Failed to copy a node that is not loaded "
1502 "yet: %s", path, *lineno, value);
1503 return err;
1505 err = hdf_copy(hdf, name, h);
1506 if (err != STATUS_OK)
1508 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1511 else if (s[0] == '!' && s[1] == '=') /* exec */
1513 *s = '\0';
1514 name = neos_strip(name);
1515 s+=2;
1516 value = neos_strip(s);
1518 #ifdef _MSC_VER
1519 FILE *f = _popen(value, "r");
1520 #else
1521 FILE *f = popen(value, "r");
1522 #endif
1523 if (f == NULL)
1525 err = nerr_raise(NERR_PARSE,
1526 "[%s:%d] Failed to exec specified command: %s",
1527 path, *lineno, line->buf);
1528 return err;
1530 char *content = _read_file(f);
1531 fclose(f);
1532 int len = strlen(content);
1533 if (len > 0 && content[len - 1] == '\n') {
1534 content[len - 1] = '\0'; // remove \n artifact
1536 err = _set_value (hdf, name, content, 1, 1, 0, attr, NULL);
1537 free(content);
1539 if (err != STATUS_OK)
1541 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1544 else if (s[0] == ':') /* link */
1546 *s = '\0';
1547 name = neos_strip(name);
1548 s++;
1549 value = neos_strip(s);
1550 err = _set_value (hdf, name, value, 1, 1, 1, attr, NULL);
1551 if (err != STATUS_OK)
1553 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1556 else if (s[0] == '{') /* deeper */
1558 *s = '\0';
1559 name = neos_strip(name);
1560 lower = hdf_get_obj (hdf, name, &err);
1561 if (lower == NULL)
1563 err = _set_value (hdf, name, NULL, 1, 1, 0, attr, &lower);
1565 else
1567 err = _set_value (lower, NULL, lower->value, 1, 1, 0, attr, NULL);
1569 if (err != STATUS_OK)
1571 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1573 err = _hdf_read_string (lower, str, line, path, lineno, include_handle,
1575 if (err != STATUS_OK)
1577 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1580 else if (s[0] == '<' && s[1] == '<') /* multi-line assignment */
1582 char *m;
1583 int msize = 0;
1584 int mmax = 128;
1585 int l;
1587 *s = '\0';
1588 name = neos_strip(name);
1589 s+=2;
1590 value = neos_strip(s);
1591 l = strlen(value);
1592 if (l == 0)
1594 err = nerr_raise(NERR_PARSE,
1595 "[%s:%d] No multi-assignment terminator given: %s", path, *lineno,
1596 line->buf);
1597 return err;
1599 m = (char *) malloc (mmax * sizeof(char));
1600 if (m == NULL)
1602 return nerr_raise(NERR_NOMEM,
1603 "[%s:%d] Unable to allocate memory for multi-line assignment to %s",
1604 path, *lineno, name);
1606 while (_copy_line (str, m+msize, mmax-msize) != 0)
1608 (*lineno)++;
1609 if (!strncmp(value, m+msize, l) && isspace(m[msize+l]))
1611 m[msize] = '\0';
1612 break;
1614 msize += strlen(m+msize);
1615 if (msize + l + 10 > mmax)
1617 void *new_ptr;
1618 mmax += 128;
1619 new_ptr = realloc (m, mmax * sizeof(char));
1620 if (new_ptr == NULL)
1622 free(m);
1623 return nerr_raise(NERR_NOMEM,
1624 "[%s:%d] Unable to allocate memory for multi-line assignment to %s: size=%d",
1625 path, *lineno, name, mmax);
1627 m = (char *) new_ptr;
1630 err = _set_value (hdf, name, m, 0, 1, 0, attr, NULL);
1631 if (err != STATUS_OK)
1633 free (m);
1634 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1638 else
1640 err = nerr_raise(NERR_PARSE, "[%s:%d] Unable to parse line %s", path,
1641 *lineno, line->buf);
1642 return err;
1646 if (expect_end_brace) {
1647 err = nerr_raise(NERR_PARSE, "[%s:%d] Missing matching }", path, *lineno);
1648 return err;
1650 return STATUS_OK;
1653 NEOERR * hdf_read_string (HDF *hdf, const char *str)
1655 NEOERR *err;
1656 int lineno = 0;
1657 NEOSTRING line;
1658 string_init(&line);
1659 err = _hdf_read_string(hdf, &str, &line, "<string>", &lineno, INCLUDE_ERROR,
1661 string_clear(&line);
1662 return nerr_pass(err);
1665 /* The search path is part of the HDF by convention */
1666 NEOERR* hdf_search_path (HDF *hdf, const char *path, char *full, int full_len)
1668 HDF *paths;
1669 struct stat s;
1670 NEOERR* err = STATUS_OK;
1672 paths = hdf_get_child (hdf, "hdf.loadpaths", &err);
1673 if (err != STATUS_OK) return err;
1675 for (; paths; paths = hdf_obj_next (paths))
1677 char* value = hdf_obj_value(paths, &err);
1678 if (err != STATUS_OK) return err;
1679 snprintf (full, full_len, "%s/%s", value, path);
1680 errno = 0;
1681 if (stat (full, &s) == -1)
1683 if (errno != ENOENT)
1684 return nerr_raise_errno (NERR_SYSTEM, "Stat of %s failed", full);
1686 else
1688 return STATUS_OK;
1692 strncpy (full, path, full_len);
1693 full[full_len > 0 ? full_len-1 : full_len] = '\0';
1695 if (stat (full, &s) == -1)
1697 if (errno != ENOENT)
1698 return nerr_raise_errno (NERR_SYSTEM, "Stat of %s failed", full);
1700 else return STATUS_OK;
1702 return nerr_raise (NERR_NOT_FOUND, "Path %s not found", path);
1705 static NEOERR* hdf_read_file_internal (HDF *hdf, const char *path,
1706 int include_handle)
1708 NEOERR *err;
1709 int lineno = 0;
1710 char fpath[PATH_BUF_SIZE];
1711 char *ibuf = NULL;
1712 const char *ptr = NULL;
1713 NEOSTRING line;
1715 string_init(&line);
1717 if (path == NULL)
1718 return nerr_raise(NERR_ASSERT, "Can't read NULL file");
1719 if (path[0] != '/')
1721 err = hdf_search_path (hdf, path, fpath, PATH_BUF_SIZE);
1722 if (err != STATUS_OK) return nerr_pass(err);
1723 path = fpath;
1726 err = ne_load_file (path, &ibuf);
1727 if (err) return nerr_pass(err);
1729 ptr = ibuf;
1730 err = _hdf_read_string(hdf, &ptr, &line, path, &lineno, include_handle, 0);
1731 free(ibuf);
1732 string_clear(&line);
1733 return nerr_pass(err);
1736 NEOERR* hdf_read_file (HDF *hdf, const char *path)
1738 NEOERR *err;
1739 err = hdf_read_file_internal (hdf, path, INCLUDE_FILE);
1740 return nerr_pass(err);