Home | History | Annotate | Download | only in util
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    473 HDF* hdf_obj_next (HDF *hdf)
    474 {
    475   if (hdf == NULL) return NULL;
    476   return hdf->next;
    477 }
    478 
    479 HDF* hdf_obj_top (HDF *hdf)
    480 {
    481   if (hdf == NULL) return NULL;
    482   return hdf->top;
    483 }
    484 
    485 HDF_ATTR* hdf_obj_attr (HDF *hdf)
    486 {
    487   if (hdf == NULL) return NULL;
    488   return hdf->attr;
    489 }
    490 
    491 char* hdf_obj_name (HDF *hdf)
    492 {
    493   if (hdf == NULL) return NULL;
    494   return hdf->name;
    495 }
    496 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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... */
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 */
   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 
   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"] */
   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 
   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 
   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 
   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 */
   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 
   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 
   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