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