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
42static 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
50static 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
56static 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
108static 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
123static 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
165NEOERR* 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
187void hdf_destroy (HDF **hdf)
188{
189  if (*hdf == NULL) return;
190  if ((*hdf)->top == (*hdf))
191  {
192    _dealloc_hdf(hdf);
193  }
194}
195
196static 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
293int 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 */
310char* 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
321char* 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
337char* 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
348NEOERR* 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
377HDF* hdf_get_obj (HDF *hdf, const char *name)
378{
379  HDF *obj;
380
381  _walk_hdf(hdf, name, &obj);
382  return obj;
383}
384
385HDF* 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
393HDF_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
401NEOERR* 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
460HDF* 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
473HDF* hdf_obj_next (HDF *hdf)
474{
475  if (hdf == NULL) return NULL;
476  return hdf->next;
477}
478
479HDF* hdf_obj_top (HDF *hdf)
480{
481  if (hdf == NULL) return NULL;
482  return hdf->top;
483}
484
485HDF_ATTR* hdf_obj_attr (HDF *hdf)
486{
487  if (hdf == NULL) return NULL;
488  return hdf->attr;
489}
490
491char* hdf_obj_name (HDF *hdf)
492{
493  if (hdf == NULL) return NULL;
494  return hdf->name;
495}
496
497char* 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
511void _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
554NEOERR* _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
572static 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
708skip_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
821NEOERR* 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
826NEOERR* 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
832NEOERR* 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
837NEOERR* 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
845NEOERR* 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
850NEOERR* 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
860NEOERR* 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
884NEOERR* 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
895NEOERR* 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... */
908NEOERR *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
943NEOERR* 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
1017static 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
1051static 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
1077NEOERR* 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
1093static 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
1113typedef NEOERR *(*DUMPF_CB)(void *rock, const char *fmt, ...);
1114
1115static 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
1126static 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
1142static 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
1258NEOERR* 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
1263NEOERR* 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
1268NEOERR* 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
1273NEOERR *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
1292NEOERR *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
1324NEOERR *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
1355static 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 */
1373static 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
1399char *_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"] */
1415static 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
1558static 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
1764NEOERR * 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
1775NEOERR * 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 */
1788NEOERR* 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
1821NEOERR* 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
1860void 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