more type simplifier tests
[hiphop-php.git] / hphp / neo / neo_hdf.c
blob1155f4603a6589726b1ed3f425083297fd7a7a91
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 static int _walk_hdf (HDF *hdf, const char *name, HDF **node)
235 HDF *parent = NULL;
236 HDF *hp = hdf;
237 HDF hash_key;
238 int x = 0;
239 const char *s, *n;
240 int r;
242 *node = NULL;
244 if (hdf == NULL) return -1;
245 if (name == NULL || name[0] == '\0')
247 *node = hdf;
248 return 0;
251 if (hdf->link)
253 r = _walk_hdf (hdf->top, hdf->value, &hp);
254 if (r) return r;
255 if (hp)
257 parent = hp;
258 hp = hp->child;
261 else
263 parent = hdf;
264 hp = hdf->child;
266 if (hp == NULL)
268 return -1;
271 n = name;
272 s = strchr (n, '.');
273 x = (s == NULL) ? strlen(n) : s - n;
275 while (1)
277 if (parent && parent->hash)
279 hash_key.name = (char *)n;
280 hash_key.name_len = x;
281 hp = ne_hash_lookup(parent->hash, &hash_key);
283 else
285 while (hp != NULL)
287 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
289 break;
291 else
293 hp = hp->next;
297 if (hp == NULL)
299 return -1;
301 if (s == NULL) break;
303 if (hp->link)
305 r = _walk_hdf (hp->top, hp->value, &hp);
306 if (r) {
307 return r;
309 parent = hp;
310 hp = hp->child;
312 else
314 parent = hp;
315 hp = hp->child;
317 n = s + 1;
318 s = strchr (n, '.');
319 x = (s == NULL) ? strlen(n) : s - n;
321 if (hp->link)
323 return _walk_hdf (hp->top, hp->value, node);
326 *node = hp;
327 return 0;
330 HDF* hdf_get_obj (HDF *hdf, const char *name)
332 HDF *obj;
334 _walk_hdf(hdf, name, &obj);
335 return obj;
338 HDF* hdf_get_child (HDF *hdf, const char *name)
340 HDF *obj;
341 _walk_hdf(hdf, name, &obj);
342 if (obj != NULL) return obj->child;
343 return obj;
346 void hdf_set_visited (HDF *hdf, int visited) {
347 if (hdf) hdf->visited = visited;
350 int hdf_is_visited (HDF *hdf) {
351 return hdf ? hdf->visited : 0;
354 HDF* hdf_obj_child (HDF *hdf)
356 HDF *obj;
357 if (hdf == NULL) return NULL;
358 if (hdf->link)
360 if (_walk_hdf(hdf->top, hdf->value, &obj))
361 return NULL;
362 return obj->child;
364 return hdf->child;
367 HDF* hdf_obj_next (HDF *hdf)
369 if (hdf == NULL) return NULL;
370 return hdf->next;
373 char* hdf_obj_name (HDF *hdf)
375 if (hdf == NULL) return NULL;
376 return hdf->name;
379 char* hdf_obj_value (HDF *hdf)
381 int count = 0;
383 if (hdf == NULL) return NULL;
384 while (hdf->link && count < 100)
386 if (_walk_hdf (hdf->top, hdf->value, &hdf))
387 return NULL;
388 count++;
390 return hdf->value;
393 void _merge_attr (HDF_ATTR *dest, HDF_ATTR *src)
395 HDF_ATTR *da, *ld;
396 HDF_ATTR *sa, *ls;
397 char found;
399 sa = src;
400 ls = src;
401 while (sa != NULL)
403 da = dest;
404 ld = da;
405 found = 0;
406 while (da != NULL)
408 if (!strcmp(da->key, sa->key))
410 if (da->value) free(da->value);
411 da->value = sa->value;
412 sa->value = NULL;
413 found = 1;
414 break;
416 ld = da;
417 da = da->next;
419 if (!found)
421 ld->next = sa;
422 ls->next = sa->next;
423 if (src == sa) src = sa->next;
424 ld->next->next = NULL;
425 sa = ls->next;
427 else
429 ls = sa;
430 sa = sa->next;
433 _dealloc_hdf_attr(&src);
436 NEOERR* _hdf_hash_level(HDF *hdf)
438 NEOERR *err;
439 HDF *child;
441 err = ne_hash_init(&(hdf->hash), hash_hdf_hash, hash_hdf_comp);
442 if (err) return nerr_pass(err);
444 child = hdf->child;
445 while (child)
447 err = ne_hash_insert(hdf->hash, child, child);
448 if (err) return nerr_pass(err);
449 child = child->next;
451 return STATUS_OK;
454 static NEOERR* _set_value (HDF *hdf, const char *name, const char *value,
455 int dupl, int wf, int lnk, HDF_ATTR *attr,
456 HDF **set_node)
458 NEOERR *err;
459 HDF *hn, *hp, *hs;
460 HDF hash_key;
461 int x = 0;
462 const char *s = name;
463 const char *n = name;
464 int count = 0;
466 if (set_node != NULL) *set_node = NULL;
467 if (hdf == NULL)
469 return nerr_raise(NERR_ASSERT, "Unable to set %s on NULL hdf", name);
472 /* HACK: allow setting of this node by passing an empty name */
473 if (name == NULL || name[0] == '\0')
475 /* handle setting attr first */
476 if (hdf->attr == NULL)
478 hdf->attr = attr;
480 else
482 _merge_attr(hdf->attr, attr);
484 /* set link flag */
485 if (lnk) hdf->link = 1;
486 else hdf->link = 0;
487 /* if we're setting ourselves to ourselves... */
488 if (hdf->value == value)
490 if (set_node != NULL) *set_node = hdf;
491 return STATUS_OK;
493 if (hdf->alloc_value)
495 free(hdf->value);
496 hdf->value = NULL;
498 if (value == NULL)
500 hdf->alloc_value = 0;
501 hdf->value = NULL;
503 else if (dupl)
505 hdf->alloc_value = 1;
506 hdf->value = strdup(value);
507 if (hdf->value == NULL)
508 return nerr_raise (NERR_NOMEM, "Unable to duplicate value %s for %s",
509 value, hdf->name);
511 else
513 hdf->alloc_value = wf;
514 hdf->value = (char *)value;
516 if (set_node != NULL) *set_node = hdf;
517 return STATUS_OK;
520 n = name;
521 s = strchr (n, '.');
522 x = (s != NULL) ? s - n : strlen(n);
523 if (x == 0)
525 return nerr_raise(NERR_ASSERT, "Unable to set Empty component %s", name);
528 if (hdf->link)
530 char *new_name = (char *) malloc(strlen(hdf->value) + 1 + strlen(name) + 1);
531 if (new_name == NULL)
533 return nerr_raise(NERR_NOMEM, "Unable to allocate memory");
535 strcpy(new_name, hdf->value);
536 strcat(new_name, ".");
537 strcat(new_name, name);
538 err = _set_value (hdf->top, new_name, value, dupl, wf, lnk, attr, set_node);
539 free(new_name);
540 return nerr_pass(err);
542 else
544 hn = hdf;
547 while (1)
549 /* examine cache to see if we have a match */
550 count = 0;
551 hp = hn->last_hp;
552 hs = hn->last_hs;
554 if ((hs == NULL && hp == hn->child) || (hs && hs->next == hp))
556 if (hp && hp->name && (x == hp->name_len) && !strncmp (hp->name, n, x))
558 goto skip_search;
562 hp = hn->child;
563 hs = NULL;
565 /* Look for a matching node at this level */
566 if (hn->hash != NULL)
568 hash_key.name = (char *)n;
569 hash_key.name_len = x;
570 hp = ne_hash_lookup(hn->hash, &hash_key);
571 hs = hn->last_child;
573 else
575 while (hp != NULL)
577 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
579 break;
581 hs = hp;
582 hp = hp->next;
583 count++;
587 /* save in cache any value we found */
588 if (hp) {
589 hn->last_hp = hp;
590 hn->last_hs = hs;
593 skip_search:
595 if (hp == NULL)
597 /* If there was no matching node at this level, we need to
598 * allocate an intersitial node (or the actual node if we're
599 * at the last part of the HDF name) */
600 if (s != NULL)
602 /* intersitial */
603 err = _alloc_hdf (&hp, n, x, NULL, 0, 0, hdf->top);
605 else
607 err = _alloc_hdf (&hp, n, x, value, dupl, wf, hdf->top);
608 if (lnk) hp->link = 1;
609 else hp->link = 0;
610 hp->attr = attr;
612 if (err != STATUS_OK)
613 return nerr_pass (err);
614 if (hn->child == NULL)
615 hn->child = hp;
616 else
617 hs->next = hp;
618 hn->last_child = hp;
620 /* This is the point at which we convert to a hash table
621 * at this level, if we're over the count */
622 if (count > FORCE_HASH_AT && hn->hash == NULL)
624 err = _hdf_hash_level(hn);
625 if (err) return nerr_pass(err);
627 else if (hn->hash != NULL)
629 err = ne_hash_insert(hn->hash, hp, hp);
630 if (err) return nerr_pass(err);
633 else if (s == NULL)
635 /* If there is a matching node and we're at the end of the HDF
636 * name, then we update the value of the node */
637 /* handle setting attr first */
638 if (hp->attr == NULL)
640 hp->attr = attr;
642 else
644 _merge_attr(hp->attr, attr);
646 if (hp->value != value)
648 if (hp->alloc_value)
650 free(hp->value);
651 hp->value = NULL;
653 if (value == NULL)
655 hp->alloc_value = 0;
656 hp->value = NULL;
658 else if (dupl)
660 hp->alloc_value = 1;
661 hp->value = strdup(value);
662 if (hp->value == NULL)
663 return nerr_raise (NERR_NOMEM, "Unable to duplicate value %s for %s",
664 value, name);
666 else
668 hp->alloc_value = wf;
669 hp->value = (char *)value;
672 if (lnk) hp->link = 1;
673 else hp->link = 0;
675 else if (hp->link)
677 char *new_name = (char *) malloc(strlen(hp->value) + strlen(s) + 1);
678 if (new_name == NULL)
680 return nerr_raise(NERR_NOMEM, "Unable to allocate memory");
682 strcpy(new_name, hp->value);
683 strcat(new_name, s);
684 err = _set_value (hdf->top, new_name, value, dupl, wf, lnk, attr, set_node);
685 free(new_name);
686 return nerr_pass(err);
688 /* At this point, we're done if there is not more HDF name space to
689 * traverse */
690 if (s == NULL)
691 break;
692 /* Otherwise, we need to find the next part of the namespace */
693 n = s + 1;
694 s = strchr (n, '.');
695 x = (s != NULL) ? s - n : strlen(n);
696 if (x == 0)
698 return nerr_raise(NERR_ASSERT, "Unable to set Empty component %s", name);
700 hn = hp;
702 if (set_node != NULL) *set_node = hp;
703 return STATUS_OK;
706 NEOERR* hdf_set_value (HDF *hdf, const char *name, const char *value)
708 return nerr_pass(_set_value (hdf, name, value, 1, 1, 0, NULL, NULL));
711 NEOERR* hdf_get_node (HDF *hdf, const char *name, HDF **ret)
713 _walk_hdf(hdf, name, ret);
714 if (*ret == NULL)
716 return nerr_pass(_set_value (hdf, name, NULL, 0, 1, 0, NULL, ret));
718 return STATUS_OK;
721 NEOERR* hdf_remove_tree (HDF *hdf, const char *name)
723 HDF *hp = hdf;
724 HDF *lp = NULL, *ln = NULL; /* last parent, last node */
725 int x = 0;
726 const char *s = name;
727 const char *n = name;
729 if (hdf == NULL) return STATUS_OK;
731 hp = hdf->child;
732 if (hp == NULL)
734 return STATUS_OK;
737 lp = hdf;
738 ln = NULL;
740 n = name;
741 s = strchr (n, '.');
742 x = (s == NULL) ? strlen(n) : s - n;
744 while (1)
746 while (hp != NULL)
748 if (hp->name && (x == hp->name_len) && !strncmp(hp->name, n, x))
750 break;
752 else
754 ln = hp;
755 hp = hp->next;
758 if (hp == NULL)
760 return STATUS_OK;
762 if (s == NULL) break;
764 lp = hp;
765 ln = NULL;
766 hp = hp->child;
767 n = s + 1;
768 s = strchr (n, '.');
769 x = (s == NULL) ? strlen(n) : s - n;
772 if (lp->hash != NULL)
774 ne_hash_remove(lp->hash, hp);
776 if (ln)
778 ln->next = hp->next;
779 /* check to see if we are the last parent's last_child, if so
780 * repoint so hash table inserts will go to the right place */
781 if (hp == lp->last_child)
782 lp->last_child = ln;
783 hp->next = NULL;
785 else
787 lp->child = hp->next;
788 hp->next = NULL;
790 _dealloc_hdf (&hp);
792 return STATUS_OK;
795 static NEOERR * _copy_attr (HDF_ATTR **dest, HDF_ATTR *src)
797 HDF_ATTR *copy, *last = NULL;
799 *dest = NULL;
800 while (src != NULL)
802 copy = (HDF_ATTR *)malloc(sizeof(HDF_ATTR));
803 if (copy == NULL)
805 _dealloc_hdf_attr(dest);
806 return nerr_raise(NERR_NOMEM, "Unable to allocate copy of HDF_ATTR");
808 copy->key = strdup(src->key);
809 copy->value = strdup(src->value);
810 copy->next = NULL;
811 if ((copy->key == NULL) || (copy->value == NULL))
813 _dealloc_hdf_attr(dest);
814 return nerr_raise(NERR_NOMEM, "Unable to allocate copy of HDF_ATTR");
816 if (last) {
817 last->next = copy;
819 else
821 *dest = copy;
823 last = copy;
824 src = src->next;
826 return STATUS_OK;
829 static NEOERR * _copy_nodes (HDF *dest, HDF *src)
831 NEOERR *err = STATUS_OK;
832 HDF *dt, *st;
833 HDF_ATTR *attr_copy;
835 st = src->child;
836 while (st != NULL)
838 err = _copy_attr(&attr_copy, st->attr);
839 if (err) return nerr_pass(err);
840 err = _set_value(dest, st->name, st->value, 1, 1, st->link, attr_copy, &dt);
841 if (err) {
842 _dealloc_hdf_attr(&attr_copy);
843 return nerr_pass(err);
845 if (src->child)
847 err = _copy_nodes (dt, st);
848 if (err) return nerr_pass(err);
850 st = st->next;
852 return STATUS_OK;
855 NEOERR* hdf_copy (HDF *dest, const char *name, HDF *src)
857 NEOERR *err;
858 HDF *node;
859 HDF_ATTR *attr_copy;
861 if (_walk_hdf(dest, name, &node) == -1)
863 err = _copy_attr(&attr_copy, src->attr);
864 if (err) return nerr_pass(err);
865 err = _set_value (dest, name, src->value, 1, 1, src->link, attr_copy,
866 &node);
867 if (err) {
868 _dealloc_hdf_attr(&attr_copy);
869 return nerr_pass(err);
872 return nerr_pass (_copy_nodes (node, src));
875 /* BUG: currently, this only prints something if there is a value...
876 * but we now allow attributes on nodes with no value... */
878 static void gen_ml_break(char *ml, size_t len)
880 int nlen;
881 int x = 0;
883 ml[x++] = '\n';
884 nlen = 2 + neo_rand(len-5);
885 if (nlen == 0)
887 nlen = len / 2;
889 while (nlen)
891 ml[x++] = ('A' + neo_rand(26));
892 nlen--;
894 ml[x++] = '\n';
895 ml[x] = '\0';
898 typedef NEOERR *(*DUMPF_CB)(void *rock, const char *fmt, ...);
900 static NEOERR *_fp_dump_cb (void *rock, const char *fmt, ...)
902 FILE *fp = (FILE *)rock;
903 va_list ap;
905 va_start (ap, fmt);
906 vfprintf(fp, fmt, ap);
907 va_end(ap);
908 return STATUS_OK;
911 static NEOERR *_string_dump_cb (void *rock, const char *fmt, ...)
913 NEOERR *err;
914 NEOSTRING *str = (NEOSTRING *)rock;
915 va_list ap;
917 va_start (ap, fmt);
918 err = string_appendvf(str, fmt, ap);
919 va_end(ap);
920 return nerr_pass(err);
923 #define DUMP_TYPE_DOTTED 0
924 #define DUMP_TYPE_COMPACT 1
925 #define DUMP_TYPE_PRETTY 2
927 static NEOERR* hdf_dump_cb(HDF *hdf, const char *prefix, int dtype, int lvl,
928 void *rock, DUMPF_CB dump_cbf)
930 NEOERR *err;
931 char *p, op;
932 char ml[10] = "\nEOM\n";
933 int ml_len = strlen(ml);
934 char whsp[256] = "";
936 if (dtype == DUMP_TYPE_PRETTY)
938 memset(whsp, ' ', 256);
939 if (lvl > 127)
940 lvl = 127;
941 whsp[lvl*2] = '\0';
944 if (hdf != NULL) hdf = hdf->child;
946 while (hdf != NULL)
948 op = '=';
949 if (hdf->value)
951 if (hdf->link) op = ':';
952 if (prefix && (dtype == DUMP_TYPE_DOTTED))
954 err = dump_cbf(rock, "%s.%s", prefix, hdf->name);
956 else
958 err = dump_cbf(rock, "%s%s", whsp, hdf->name);
960 if (err) return nerr_pass (err);
961 if (hdf->attr)
963 HDF_ATTR *attr = hdf->attr;
964 char *v = NULL;
966 err = dump_cbf(rock, " [");
967 if (err) return nerr_pass(err);
968 while (attr != NULL)
970 //#undef strcmp
971 if (attr->value == NULL || !strcmp(attr->value, "1"))
972 err = dump_cbf(rock, "%s", attr->key);
973 else
975 v = repr_string_alloc(attr->value);
977 if (v == NULL)
978 return nerr_raise(NERR_NOMEM, "Unable to repr attr %s value %s", attr->key, attr->value);
979 err = dump_cbf(rock, "%s=%s", attr->key, v);
980 free(v);
982 if (err) return nerr_pass(err);
983 if (attr->next)
985 err = dump_cbf(rock, ", ");
986 if (err) return nerr_pass(err);
988 attr = attr->next;
990 err = dump_cbf(rock, "] ");
991 if (err) return nerr_pass(err);
993 if (strchr (hdf->value, '\n'))
995 int vlen = strlen(hdf->value);
997 while (strstr(hdf->value, ml) || ((vlen > ml_len) && !strncmp(hdf->value + vlen - ml_len + 1, ml, strlen(ml) - 1)))
999 gen_ml_break(ml, sizeof(ml));
1000 ml_len = strlen(ml);
1002 if (hdf->value[strlen(hdf->value)-1] != '\n')
1003 err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml);
1004 else
1005 err = dump_cbf(rock, " << %s%s%s", ml+1, hdf->value, ml+1);
1007 else
1009 err = dump_cbf(rock, " %c %s\n", op, hdf->value);
1011 if (err) return nerr_pass (err);
1013 if (hdf->child)
1015 if (prefix && (dtype == DUMP_TYPE_DOTTED))
1017 p = (char *) malloc (strlen(hdf->name) + strlen(prefix) + 2);
1018 sprintf (p, "%s.%s", prefix, hdf->name);
1019 err = hdf_dump_cb (hdf, p, dtype, lvl+1, rock, dump_cbf);
1020 free(p);
1022 else
1024 if (hdf->name && (dtype != DUMP_TYPE_DOTTED))
1026 err = dump_cbf(rock, "%s%s {\n", whsp, hdf->name);
1027 if (err) return nerr_pass (err);
1028 err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
1029 if (err) return nerr_pass (err);
1030 err = dump_cbf(rock, "%s}\n", whsp);
1032 else
1034 err = hdf_dump_cb (hdf, hdf->name, dtype, lvl+1, rock, dump_cbf);
1037 if (err) return nerr_pass (err);
1039 hdf = hdf->next;
1041 return STATUS_OK;
1044 NEOERR* hdf_dump_str (HDF *hdf, const char *prefix, int dtype, NEOSTRING *str)
1046 return nerr_pass(hdf_dump_cb(hdf, prefix, dtype, 0, str, _string_dump_cb));
1049 NEOERR* hdf_dump_format (HDF *hdf, int lvl, FILE *fp)
1051 return nerr_pass(hdf_dump_cb(hdf, "", DUMP_TYPE_PRETTY, 0, fp, _fp_dump_cb));
1054 NEOERR *hdf_write_file (HDF *hdf, const char *path)
1056 NEOERR *err;
1057 FILE *fp;
1059 fp = fopen(path, "w");
1060 if (fp == NULL)
1061 return nerr_raise_errno (NERR_IO, "Unable to open %s for writing", path);
1063 err = hdf_dump_format (hdf, 0, fp);
1065 fclose (fp);
1066 if (err)
1068 unlink(path);
1070 return nerr_pass(err);
1073 NEOERR *hdf_write_string (HDF *hdf, char **s)
1075 NEOSTRING str;
1076 NEOERR *err;
1078 *s = NULL;
1080 string_init (&str);
1082 err = hdf_dump_str (hdf, NULL, 2, &str);
1083 if (err)
1085 string_clear (&str);
1086 return nerr_pass(err);
1088 if (str.buf == NULL)
1090 *s = strdup("");
1091 if (*s == NULL) return nerr_raise(NERR_NOMEM, "Unable to allocate empty string");
1093 else
1095 *s = str.buf;
1098 return STATUS_OK;
1102 #define SKIPWS(s) while (*s && isspace(*s)) s++;
1104 static int _copy_line (const char **s, char *buf, size_t buf_len)
1106 int x = 0;
1107 const char *st = *s;
1109 while (*st && x < buf_len-1)
1111 buf[x++] = *st;
1112 if (*st++ == '\n') break;
1114 buf[x] = '\0';
1115 *s = st;
1117 return x;
1120 /* Copy the characters in the file (up to the next newline) into line
1121 * and advance s to the next line */
1122 static NEOERR *_copy_line_advance(const char **s, NEOSTRING *line)
1124 NEOERR *err;
1125 int x = 0;
1126 const char *st = *s;
1127 const char *nl;
1129 nl = strchr(st, '\n');
1130 if (nl == NULL)
1132 x = strlen(st);
1133 err = string_appendn(line, st, x);
1134 if (err) return nerr_pass(err);
1135 *s = st + x;
1137 else
1139 x = nl - st;
1140 err = string_appendn(line, st, x);
1141 if (err) return nerr_pass(err);
1142 *s = nl + 1;
1145 return STATUS_OK;
1148 char *_strndup(const char *s, int len) {
1149 int x;
1150 char *dupl;
1151 if (s == NULL) return NULL;
1152 dupl = (char *) malloc(len+1);
1153 if (dupl == NULL) return NULL;
1154 for (x = 0; x < len && s[x]; x++)
1156 dupl[x] = s[x];
1158 dupl[x] = '\0';
1159 dupl[len] = '\0';
1160 return dupl;
1163 /* attributes are of the form [key1, key2, key3=value, key4="repr"] */
1164 static NEOERR* parse_attr(char **str, HDF_ATTR **attr)
1166 NEOERR *err = STATUS_OK;
1167 char *s = *str;
1168 char *k, *v;
1169 int k_l, v_l;
1170 NEOSTRING buf;
1171 char c;
1172 HDF_ATTR *ha, *hal = NULL;
1174 *attr = NULL;
1176 string_init(&buf);
1177 while (*s && *s != ']')
1179 k = s;
1180 k_l = 0;
1181 v = NULL;
1182 v_l = 0;
1183 while (*s && isalnum(*s)) s++;
1184 k_l = s-k;
1185 if (*s == '\0' || k_l == 0)
1187 _dealloc_hdf_attr(attr);
1188 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1190 SKIPWS(s);
1191 if (*s == '=')
1193 s++;
1194 SKIPWS(s);
1195 if (*s == '"')
1197 s++;
1198 while (*s && *s != '"')
1200 if (*s == '\\')
1202 if (isdigit(*(s+1)))
1204 s++;
1205 c = *s - '0';
1206 if (isdigit(*(s+1)))
1208 s++;
1209 c = (c * 8) + (*s - '0');
1210 if (isdigit(*(s+1)))
1212 s++;
1213 c = (c * 8) + (*s - '0');
1217 else
1219 s++;
1220 if (*s == 'n') c = '\n';
1221 else if (*s == 't') c = '\t';
1222 else if (*s == 'r') c = '\r';
1223 else c = *s;
1225 err = string_append_char(&buf, c);
1227 else
1229 err = string_append_char(&buf, *s);
1231 if (err)
1233 string_clear(&buf);
1234 _dealloc_hdf_attr(attr);
1235 return nerr_pass(err);
1237 s++;
1239 if (*s == '\0')
1241 _dealloc_hdf_attr(attr);
1242 string_clear(&buf);
1243 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1245 s++;
1246 v = buf.buf;
1247 v_l = buf.len;
1249 else
1251 v = s;
1252 while (*s && *s != ' ' && *s != ',' && *s != ']') s++;
1253 if (*s == '\0')
1255 _dealloc_hdf_attr(attr);
1256 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1258 v_l = s-v;
1261 else
1263 v = "1";
1265 ha = (HDF_ATTR*) calloc (1, sizeof(HDF_ATTR));
1266 if (ha == NULL)
1268 _dealloc_hdf_attr(attr);
1269 string_clear(&buf);
1270 return nerr_raise(NERR_NOMEM, "Unable to load attributes: %s", s);
1272 if (*attr == NULL) *attr = ha;
1273 ha->key = _strndup(k, k_l);
1274 if (v)
1275 ha->value = _strndup(v, v_l);
1276 else
1277 ha->value = strdup("");
1278 if (ha->key == NULL || ha->value == NULL)
1280 _dealloc_hdf_attr(attr);
1281 string_clear(&buf);
1282 return nerr_raise(NERR_NOMEM, "Unable to load attributes: %s", s);
1284 if (hal != NULL) hal->next = ha;
1285 hal = ha;
1286 string_clear(&buf);
1287 SKIPWS(s);
1288 if (*s == ',')
1290 s++;
1291 SKIPWS(s);
1294 if (*s == '\0')
1296 _dealloc_hdf_attr(attr);
1297 return nerr_raise(NERR_PARSE, "Malformed attribute specification: %s", *str);
1299 *str = s+1;
1300 return STATUS_OK;
1303 #define INCLUDE_ERROR -1
1304 #define INCLUDE_IGNORE -2
1305 #define INCLUDE_FILE 0
1306 #define INCLUDE_MAX_DEPTH 50
1308 static NEOERR* _hdf_read_string (HDF *hdf, const char **str, NEOSTRING *line,
1309 const char *path, int *lineno,
1310 int include_handle, int expect_end_brace) {
1311 NEOERR *err;
1312 HDF *lower;
1313 char *s;
1314 char *name, *value;
1315 HDF_ATTR *attr = NULL;
1317 while (**str != '\0')
1319 /* Reset string length, but don't free the reserved buffer */
1320 line->len = 0;
1321 err = _copy_line_advance(str, line);
1322 if (err) return nerr_pass(err);
1323 attr = NULL;
1324 (*lineno)++;
1325 s = line->buf;
1326 SKIPWS(s);
1327 if ((!strncmp(s, "#include ", 9) || !strncmp(s, "-include ", 9)) && include_handle != INCLUDE_IGNORE)
1329 int required = !strncmp(s, "#include ", 9);
1330 if (include_handle == INCLUDE_ERROR)
1332 return nerr_raise (NERR_PARSE,
1333 "[%d]: #include not supported in string parse",
1334 *lineno);
1336 else if (include_handle < INCLUDE_MAX_DEPTH)
1338 int l;
1339 s += 9;
1340 name = neos_strip(s);
1341 l = strlen(name);
1342 if (name[0] == '"' && name[l-1] == '"')
1344 name[l-1] = '\0';
1345 name++;
1347 char fullpath[PATH_MAX];
1348 if (name[0] != '/') {
1349 memset(fullpath, 0, PATH_MAX);
1351 char *p = strrchr(path, '/');
1352 if (p == NULL) {
1353 char pwd[PATH_MAX];
1354 memset(pwd, 0, PATH_MAX);
1355 getcwd(pwd, PATH_MAX);
1356 snprintf(fullpath, PATH_MAX, "%s/%s", pwd, name);
1357 } else {
1358 int dir_len = p - path + 1;
1359 snprintf(fullpath, PATH_MAX, "%s", path);
1360 snprintf(fullpath + dir_len, PATH_MAX - dir_len, "%s", name);
1362 name = fullpath;
1364 err = hdf_read_file_internal(hdf, name, include_handle + 1);
1365 if (err != STATUS_OK && required)
1367 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1370 else {
1371 return nerr_raise (NERR_MAX_RECURSION,
1372 "[%d]: Too many recursion levels.",
1373 *lineno
1377 else if (s[0] == '#')
1379 /* comment: pass */
1381 else if (s[0] == '}') /* up */
1383 s = neos_strip(s);
1384 if (strcmp(s, "}"))
1386 err = nerr_raise(NERR_PARSE,
1387 "[%s:%d] Trailing garbage on line following }: %s", path, *lineno,
1388 line->buf);
1389 return err;
1391 return STATUS_OK;
1393 else if (s[0])
1395 /* Valid hdf name is [0-9a-zA-Z_.*\]+ */
1396 int splice = *s == '@';
1397 if (splice) s++;
1398 name = s;
1399 while (*s && (isalnum(*s) || *s == '_' || *s == '.' || *s == '*' || *s == '\\')) s++;
1400 SKIPWS(s);
1402 char num[256];
1403 static int counter = 0;
1404 char *p;
1405 int i = 0;
1406 for (p = name; p < s && i < 200; p++) {
1407 if (*p != '*') {
1408 num[i++] = *p;
1409 } else {
1410 i += snprintf(num + i, 256 - i, "%d", counter++);
1411 name = num;
1414 num[i] = '\0';
1416 if (s[0] == '[') /* attributes */
1418 *s = '\0';
1419 name = neos_strip(name);
1420 s++;
1421 err = parse_attr(&s, &attr);
1422 if (err)
1424 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1426 SKIPWS(s);
1428 if (splice) {
1429 name = neos_strip(name);
1430 HDF *h = hdf_get_obj(hdf->top, name);
1431 if (h) {
1432 HDF *c = hdf_obj_child(h);
1433 while (c) {
1434 err = hdf_copy (hdf, hdf_obj_name(c), c);
1435 if (err != STATUS_OK) break;
1436 c = hdf_obj_next(c);
1439 if (err != STATUS_OK)
1441 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1443 } else if (s[0] == '=') /* assignment */
1445 *s = '\0';
1446 name = neos_strip(name);
1447 s++;
1448 value = neos_strip(s);
1449 err = _set_value (hdf, name, value, 1, 1, 0, attr, NULL);
1450 if (err != STATUS_OK)
1452 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1455 else if (s[0] == ':' && s[1] == '=') /* copy */
1457 *s = '\0';
1458 name = neos_strip(name);
1459 s+=2;
1460 value = neos_strip(s);
1461 HDF *h = hdf_get_obj(hdf->top, value);
1462 if (!h)
1464 err = nerr_raise(NERR_PARSE,
1465 "[%s:%d] Failed to copy a node that is not loaded "
1466 "yet: %s", path, *lineno, value);
1467 return err;
1469 err = hdf_copy(hdf, name, h);
1470 if (err != STATUS_OK)
1472 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1475 else if (s[0] == '!' && s[1] == '=') /* exec */
1477 *s = '\0';
1478 name = neos_strip(name);
1479 s+=2;
1480 value = neos_strip(s);
1482 #ifdef _MSC_VER
1483 FILE *f = _popen(value, "r");
1484 #else
1485 FILE *f = popen(value, "r");
1486 #endif
1487 if (f == NULL)
1489 err = nerr_raise(NERR_PARSE,
1490 "[%s:%d] Failed to exec specified command: %s",
1491 path, *lineno, line->buf);
1492 return err;
1494 char *content = _read_file(f);
1495 fclose(f);
1496 int len = strlen(content);
1497 if (len > 0 && content[len - 1] == '\n') {
1498 content[len - 1] = '\0'; // remove \n artifact
1500 err = _set_value (hdf, name, content, 1, 1, 0, attr, NULL);
1501 free(content);
1503 if (err != STATUS_OK)
1505 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1508 else if (s[0] == ':') /* link */
1510 *s = '\0';
1511 name = neos_strip(name);
1512 s++;
1513 value = neos_strip(s);
1514 err = _set_value (hdf, name, value, 1, 1, 1, attr, NULL);
1515 if (err != STATUS_OK)
1517 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1520 else if (s[0] == '{') /* deeper */
1522 *s = '\0';
1523 name = neos_strip(name);
1524 lower = hdf_get_obj (hdf, name);
1525 if (lower == NULL)
1527 err = _set_value (hdf, name, NULL, 1, 1, 0, attr, &lower);
1529 else
1531 err = _set_value (lower, NULL, lower->value, 1, 1, 0, attr, NULL);
1533 if (err != STATUS_OK)
1535 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1537 err = _hdf_read_string (lower, str, line, path, lineno, include_handle,
1539 if (err != STATUS_OK)
1541 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1544 else if (s[0] == '<' && s[1] == '<') /* multi-line assignment */
1546 char *m;
1547 int msize = 0;
1548 int mmax = 128;
1549 int l;
1551 *s = '\0';
1552 name = neos_strip(name);
1553 s+=2;
1554 value = neos_strip(s);
1555 l = strlen(value);
1556 if (l == 0)
1558 err = nerr_raise(NERR_PARSE,
1559 "[%s:%d] No multi-assignment terminator given: %s", path, *lineno,
1560 line->buf);
1561 return err;
1563 m = (char *) malloc (mmax * sizeof(char));
1564 if (m == NULL)
1566 return nerr_raise(NERR_NOMEM,
1567 "[%s:%d] Unable to allocate memory for multi-line assignment to %s",
1568 path, *lineno, name);
1570 while (_copy_line (str, m+msize, mmax-msize) != 0)
1572 (*lineno)++;
1573 if (!strncmp(value, m+msize, l) && isspace(m[msize+l]))
1575 m[msize] = '\0';
1576 break;
1578 msize += strlen(m+msize);
1579 if (msize + l + 10 > mmax)
1581 void *new_ptr;
1582 mmax += 128;
1583 new_ptr = realloc (m, mmax * sizeof(char));
1584 if (new_ptr == NULL)
1586 free(m);
1587 return nerr_raise(NERR_NOMEM,
1588 "[%s:%d] Unable to allocate memory for multi-line assignment to %s: size=%d",
1589 path, *lineno, name, mmax);
1591 m = (char *) new_ptr;
1594 err = _set_value (hdf, name, m, 0, 1, 0, attr, NULL);
1595 if (err != STATUS_OK)
1597 free (m);
1598 return nerr_pass_ctx(err, "In file %s:%d", path, *lineno);
1602 else
1604 err = nerr_raise(NERR_PARSE, "[%s:%d] Unable to parse line %s", path,
1605 *lineno, line->buf);
1606 return err;
1610 if (expect_end_brace) {
1611 err = nerr_raise(NERR_PARSE, "[%s:%d] Missing matching }", path, *lineno);
1612 return err;
1614 return STATUS_OK;
1617 NEOERR * hdf_read_string (HDF *hdf, const char *str)
1619 NEOERR *err;
1620 int lineno = 0;
1621 NEOSTRING line;
1622 string_init(&line);
1623 err = _hdf_read_string(hdf, &str, &line, "<string>", &lineno, INCLUDE_ERROR,
1625 string_clear(&line);
1626 return nerr_pass(err);
1629 /* The search path is part of the HDF by convention */
1630 NEOERR* hdf_search_path (HDF *hdf, const char *path, char *full, int full_len)
1632 HDF *paths;
1633 struct stat s;
1635 for (paths = hdf_get_child (hdf, "hdf.loadpaths");
1636 paths;
1637 paths = hdf_obj_next (paths))
1639 snprintf (full, full_len, "%s/%s", hdf_obj_value(paths), path);
1640 errno = 0;
1641 if (stat (full, &s) == -1)
1643 if (errno != ENOENT)
1644 return nerr_raise_errno (NERR_SYSTEM, "Stat of %s failed", full);
1646 else
1648 return STATUS_OK;
1652 strncpy (full, path, full_len);
1653 if (stat (full, &s) == -1)
1655 if (errno != ENOENT)
1656 return nerr_raise_errno (NERR_SYSTEM, "Stat of %s failed", full);
1658 else return STATUS_OK;
1660 return nerr_raise (NERR_NOT_FOUND, "Path %s not found", path);
1663 static NEOERR* hdf_read_file_internal (HDF *hdf, const char *path,
1664 int include_handle)
1666 NEOERR *err;
1667 int lineno = 0;
1668 char fpath[PATH_BUF_SIZE];
1669 char *ibuf = NULL;
1670 const char *ptr = NULL;
1671 NEOSTRING line;
1673 string_init(&line);
1675 if (path == NULL)
1676 return nerr_raise(NERR_ASSERT, "Can't read NULL file");
1677 if (path[0] != '/')
1679 err = hdf_search_path (hdf, path, fpath, PATH_BUF_SIZE);
1680 if (err != STATUS_OK) return nerr_pass(err);
1681 path = fpath;
1684 err = ne_load_file (path, &ibuf);
1685 if (err) return nerr_pass(err);
1687 ptr = ibuf;
1688 err = _hdf_read_string(hdf, &ptr, &line, path, &lineno, include_handle, 0);
1689 free(ibuf);
1690 string_clear(&line);
1691 return nerr_pass(err);
1694 NEOERR* hdf_read_file (HDF *hdf, const char *path)
1696 NEOERR *err;
1697 err = hdf_read_file_internal (hdf, path, INCLUDE_FILE);
1698 return nerr_pass(err);