#define _ISOC99_SOURCE
#include "config.h"

#ifdef HAVE_YAML
#include <yaml.h>
#endif

#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef __STDC_VERSION__
#define __STDC_VERSION__ 199901L
#endif
#include <math.h>

#include "atoms_yaml.h"

#ifndef FC_FUNC_
#define FC_FUNC_(A,B) A ## _
#endif

#ifdef HAVE_YAML
static const char *UnitsPositions_keys[] = {"bohr", "angstroem", "reduced", "atomic", NULL};
#ifdef TEST_ME
static const char *BC_keys[] = {"free", "wireZ", "wireY", "surfaceYZ", "wireX", "surfaceXZ", "surfaceXY", "periodic", NULL};
static const char *Units_keys[] = {"bohr", "angstroem", "atomic", NULL};
#endif
static const char *funits_keys[] = {"Ha/Bohr", "eV/Ang", NULL};
static const char *eunits_keys[] = {"Ha", "eV", "Ry", NULL};
static const char *frozen_keys[] = {"No", "Yes", "fy", "fxz",
                                    "N",  "Y",   "",   "",
                                    "",  "f",   "",   "",
                                    "",  "fxyz",   "",   "",
                                    "false", "true", "", "",
                                    "off", "on", "", "", NULL};
static const char *bool_keys[] = {"No", "Yes",
                                  "N",  "Y",
                                  "false", "true",
                                  "off", "on", NULL};

static PosinpAtoms* posinp_atoms_new()
{
  PosinpAtoms *atoms;

  atoms = malloc(sizeof(PosinpAtoms));
  memset(atoms, 0, sizeof(PosinpAtoms));

  /* Default values. */
  atoms->BC = POSINP_BC_FREE;
  atoms->Units = POSINP_CELL_UNITS_BOHR;
  atoms->angdeg[0] = 90.;
  atoms->angdeg[1] = 90.;
  atoms->angdeg[2] = 90.;

  /* Default values. */
  atoms->units = POSINP_COORD_UNITS_BOHR;
  atoms->punits = POSINP_COORD_UNITS_BOHR;

  /* Default values. */
  atoms->funits = POSINP_FORCE_UNITS_HARTREE_PER_BOHR;

  /* Default values. */
  atoms->energy = NAN;
  atoms->eunits = POSINP_ENERG_UNITS_HARTREE;
  atoms->gnrm_wfn = NAN;

  return atoms;
}
#endif

static unsigned int _dict_len(const PosinpDict *dict)
{
  unsigned int j;

  for (j = 0; j < (dict ? dict->len : 0) && dict->items[j].key; j++);
  return j;
}
static const PosinpDictEntry* _dict_value_const(const PosinpDict *dict, const char *key)
{
  unsigned int j;

  if (!key)
    return (PosinpDictEntry*)0;
  for (j = 0; j < (dict ? dict->len : 0) && dict->items[j].key; j++)
    if (!strcmp(dict->items[j].key, key))
      return dict->items + j;
  return (const PosinpDictEntry*)0;
}
static const PosinpDictEntry* _dict_at_const(const PosinpDict *dict, unsigned int i)
{
  if (i < _dict_len(dict))
    return dict->items + i;
  return (const PosinpDictEntry*)0;
}
#ifdef HAVE_YAML
static const PosinpDict* _as_dict(const PosinpDict *dict, const char *key)
{
  const PosinpDictEntry *val;

  val = _dict_value_const(dict, key);
  if (!val || !val->key || val->type != POSINP_TYPE_DICT)
    return (PosinpDict*)0;

  return &val->value.dict;
}
static const PosinpDict* _at_dict(const PosinpDict *dict, unsigned int i)
{
  const PosinpDictEntry *val;

  val = _dict_at_const(dict, i);
  if (!val || !val->key || val->type != POSINP_TYPE_DICT)
    return (PosinpDict*)0;

  return &val->value.dict;
}
static const char* _as_str(const PosinpDict *dict, const char *key)
{
  const PosinpDictEntry *val;

  val = _dict_value_const(dict, key);
  if (!val || !val->key || val->type != POSINP_TYPE_STR)
    return (const char*)0;

  return val->value.str;
}
static void _as_dbl(const PosinpDict *dict, const char *key, double *arr, size_t len)
{
  const PosinpDictEntry *val;

  val = _dict_value_const(dict, key);
  if (!val || !val->key || val->type != POSINP_TYPE_DBL_ARR ||
      val->value.darr.len != len)
    return;
  memcpy(arr, val->value.darr.arr, sizeof(double) * len);
}
#endif
/* static void _dict_repr(const PosinpDict *dict, const char *buf) */
/* { */
/*   unsigned int j, i; */
/*   char *buf2; */

/*   fprintf(stderr, "%s(%p) %2d entries\n", buf ? buf : "", (void*)dict, _dict_len(dict)); */
/*   for (j = 0; j < (dict ? dict->len : 0) && dict->items[j].key; j++) */
/*     switch (dict->items[j].type) */
/*       { */
/*       case POSINP_TYPE_INT: */
/*         fprintf(stderr, "%s - %d (%s)\n", buf ? buf : "", dict->items[j].value.ival, dict->items[j].key); */
/*         break; */
/*       case POSINP_TYPE_DBL: */
/*         fprintf(stderr, "%s - %f (%s)\n", buf ? buf : "", dict->items[j].value.dval, dict->items[j].key); */
/*         break; */
/*       case POSINP_TYPE_INT_ARR: */
/*         fprintf(stderr, "%s - [", buf ? buf : ""); */
/*         if (dict->items[j].value.iarr.len > 0) */
/*           fprintf(stderr, "%d", dict->items[j].value.iarr.arr[0]); */
/*         for (i = 1; i < dict->items[j].value.iarr.len; i++) */
/*           fprintf(stderr, ", %d", dict->items[j].value.iarr.arr[i]); */
/*         fprintf(stderr, "] (%s)\n", dict->items[j].key); */
/*         break; */
/*       case POSINP_TYPE_DBL_ARR: */
/*         fprintf(stderr, "%s - [", buf ? buf : ""); */
/*         if (dict->items[j].value.darr.len > 0) */
/*           fprintf(stderr, "%f", dict->items[j].value.darr.arr[0]); */
/*         for (i = 1; i < dict->items[j].value.darr.len; i++) */
/*           fprintf(stderr, ", %f", dict->items[j].value.darr.arr[i]); */
/*         fprintf(stderr, "] (%s)\n", dict->items[j].key); */
/*         break; */
/*       case POSINP_TYPE_STR: */
/*         fprintf(stderr, "%s - '%s' (%s)\n", buf ? buf : "", dict->items[j].value.str, dict->items[j].key); */
/*         break; */
/*       case POSINP_TYPE_DICT: */
/*         fprintf(stderr, "%s - (%s)\n", buf ? buf : "", dict->items[j].key); */
/*         buf2 = malloc(sizeof(char) * (strlen(buf) + 2)); */
/*         memcpy(buf2, buf, sizeof(char) * strlen(buf)); */
/*         buf2[strlen(buf)] = ' '; */
/*         buf2[strlen(buf) + 1] = '\0'; */
/*         _dict_repr(&dict->items[j].value.dict, buf2); */
/*         free(buf2); */
/*         break; */
/*       } */
/* } */
static void _free_dict(PosinpDict *dict)
{
  unsigned int j;

  for (j = 0; j < dict->len; j++)
    {
      free(dict->items[j].key);
      switch (dict->items[j].type)
        {
        case (POSINP_TYPE_INT_ARR):
          free(dict->items[j].value.iarr.arr);
          break;
        case (POSINP_TYPE_DBL_ARR):
          free(dict->items[j].value.darr.arr);
          break;
        case (POSINP_TYPE_STR):
          free(dict->items[j].value.str);
          break;
        case (POSINP_TYPE_DICT):
          _free_dict(&dict->items[j].value.dict);
          break;
        default:
          break;
        }
    }
}
static void posinp_atoms_free(PosinpAtoms *atoms)
{
  unsigned int i;

  /* Freeing. */
  free(atoms->comment);
  free(atoms->rxyz);
  if (atoms->atomnames)
    for (i = 0; i < atoms->ntypes; i++)
      free(atoms->atomnames[i]);
  free(atoms->atomnames);
  free(atoms->iatype);
  free(atoms->ifrztyp);
  free(atoms->igspin);
  free(atoms->igchg);
  free(atoms->fxyz);
  free(atoms->pxyz);
  free(atoms->psigma);
  free(atoms->ppoles);
  for (i = 0; atoms->potnames && atoms->potnames[i]; i++)
    free(atoms->potnames[i]);
  free(atoms->potnames);
  if (atoms->props)
    for (i = 0; i < atoms->nat; i++)
      _free_dict(atoms->props + i);
  free(atoms->props);

  free(atoms);
}
#ifdef TEST_ME
static void posinp_atoms_trace(PosinpAtoms *atoms)
{
  unsigned int i;

  fprintf(stdout, "'%s'.\n", atoms->comment);
  if (!isnan(atoms->gnrm_wfn))
    fprintf(stdout, "Converged %d (%g).\n", atoms->converged, atoms->gnrm_wfn);
  if (!isnan(atoms->energy))
    fprintf(stdout, "Energy is %g %s (%d).\n", atoms->energy, eunits_keys[atoms->eunits], atoms->eunits);
  fprintf(stdout, "BC is %d (%s).\n", atoms->BC, BC_keys[atoms->BC]);
  fprintf(stdout, "Units are %d (%s).\n", atoms->Units, Units_keys[atoms->Units]);
  fprintf(stdout, "acell is %g %g %g.\n", atoms->acell[0], atoms->acell[1], atoms->acell[2]);
  fprintf(stdout, "angdeg is %g %g %g.\n", atoms->angdeg[0], atoms->angdeg[1], atoms->angdeg[2]);
  fprintf(stdout, "Position units are %d (%s).\n", atoms->units, UnitsPositions_keys[atoms->units]);
  for (i = 0; i < atoms->nat; i++)
    fprintf(stdout, "Atom '%s' at %g %g %g (%d) f:%d s:%d c:%d.\n", atoms->atomnames[atoms->iatype[i]],
            atoms->rxyz[3 * i + 0], atoms->rxyz[3 * i + 1], atoms->rxyz[3 * i + 2], atoms->iatype[i],
            atoms->ifrztyp[i], atoms->igspin[i], atoms->igchg[i]);
  if (atoms->fxyz)
    {
      fprintf(stdout, "Forces units are %d (%s).\n", atoms->funits, funits_keys[atoms->funits]);
      fprintf(stdout, "fnrm is %g, maxval is %g.\n", atoms->fnrm, atoms->maxval);
      for (i = 0; i < atoms->nat; i++)
        fprintf(stdout, "Force on '%s' is %g %g %g.\n", atoms->atomnames[atoms->iatype[i]],
                atoms->fxyz[3 * i + 0], atoms->fxyz[3 * i + 1], atoms->fxyz[3 * i + 2]);
    }
}
#endif

#define set_error(...)                          \
  if (message && !*message)                     \
    {                                           \
      ln = snprintf(NULL, 0, __VA_ARGS__);      \
      *message = malloc(sizeof(char) * ln);     \
      sprintf(*message, __VA_ARGS__);           \
    }                                           \
  else                                          \
    fprintf(stderr, __VA_ARGS__)

#ifdef HAVE_YAML

static void _yaml_parser_error(const yaml_parser_t *parser, char **message)
{
  size_t ln;

  switch (parser->error)
    {
    case YAML_MEMORY_ERROR:
      set_error("Memory error: Not enough memory for parsing\n");
      return;
    case YAML_READER_ERROR:
      if (parser->problem_value != -1)
        {
          set_error("Reader error: %s: #%X at %zu\n", parser->problem,
                    parser->problem_value, parser->problem_offset);
        }
      else
        {
          set_error("Reader error: %s at %zu\n", parser->problem,
                    parser->problem_offset);
        }
      return;
    case YAML_SCANNER_ERROR:
      if (parser->context)
        {
          set_error("Scanner error: %s at line %zu, column %zu\n"
                    "%s at line %zu, column %zu\n", parser->context,
                    parser->context_mark.line+1, parser->context_mark.column+1,
                    parser->problem, parser->problem_mark.line+1,
                    parser->problem_mark.column+1);
        }
      else
        {
          set_error("Scanner error: %s at line %zu, column %zu\n",
                    parser->problem, parser->problem_mark.line+1,
                    parser->problem_mark.column+1);
        }
      return;
    case YAML_PARSER_ERROR:
      if (parser->context)
        {
          set_error("Parser error: %s at line %zu, column %zu\n"
                    "%s at line %zu, column %zu\n", parser->context,
                    parser->context_mark.line+1, parser->context_mark.column+1,
                    parser->problem, parser->problem_mark.line+1,
                    parser->problem_mark.column+1);
        }
      else
        {
          set_error("Parser error: %s at line %zu, column %zu\n",
                    parser->problem, parser->problem_mark.line+1,
                    parser->problem_mark.column+1);
        }
      return;
    default:
      /* Couldn't happen. */
      set_error("Internal error\n");
      return;
    }
}

static int _yaml_parser_copy_str(yaml_parser_t *parser, char **val, char **message)
{
  yaml_event_t event;
  int done;
  size_t ln;

  /* Read the value. */
  done = 0;
  if (yaml_parser_parse(parser, &event))
    {
      if (event.type == YAML_SCALAR_EVENT)
        {
          ln = strlen((const char*)event.data.scalar.value);
          *val = malloc(sizeof(char) * (ln + 1));
          memcpy(*val, event.data.scalar.value, sizeof(char) * (ln + 1));
          done = 0;
        }
      else
        {
          set_error("Parser error: value awaited.\n");
          done = (event.type == YAML_STREAM_END_EVENT)?1:-1;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  else
    {
      /* Error treatment. */
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return done;
}
static int _yaml_parser_read_int(yaml_parser_t *parser, int *val, char **message)
{
  yaml_event_t event;
  int done;
  char *end;
  size_t ln;

  /* Read the value. */
  done = 0;
  if (yaml_parser_parse(parser, &event))
    {
      if (event.type == YAML_SCALAR_EVENT)
        {
          *val = (int)strtol((const char*)event.data.scalar.value, &end, 10);
          if (end == (char*)event.data.scalar.value)
            {
              set_error("Parser error: cannot convert '%s' to an int.\n", end);
              done = -1;
            }
          else
            done = 0;
        }
      else
        {
          set_error("Parser error: value awaited.\n");
          done = (event.type == YAML_STREAM_END_EVENT)?1:-1;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  else
    {
      /* Error treatment. */
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return done;
}
static int _yaml_parser_read_bool(yaml_parser_t *parser, int *val, char **message)
{
  yaml_event_t event;
  int done;
  size_t ln;
  const char *value;

  *val = 0;
  /* Read the value. */
  done = 0;
  if (yaml_parser_parse(parser, &event))
    {
      if (event.type == YAML_SCALAR_EVENT)
        {
          value = (const char*)event.data.scalar.value;
          done = 0;
          if (value &&
              (value[0] == 'T' || value[0] == 'Y'
               || !strcmp(value, "true") || !strcmp(value, "yes")))
            *val = 1;
          else if (value &&
                   (value[0] == 'F' || value[0] == 'N'
                    || !strcmp(value, "false") || !strcmp(value, "no")))
            *val = 0;
          else
            {
              set_error("Parser error: cannot convert '%s' to a boolean.\n", value);
              done = -1;
            }
        }
      else
        {
          set_error("Parser error: value awaited.\n");
          done = (event.type == YAML_STREAM_END_EVENT)?1:-1;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  else
    {
      /* Error treatment. */
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return done;
}
static int _yaml_parser_read_double(yaml_parser_t *parser, double *val, char **message)
{
  yaml_event_t event;
  int done;
  char *end;
  size_t ln;

  /* Read the value. */
  done = 0;
  if (yaml_parser_parse(parser, &event))
    {
      if (event.type == YAML_SCALAR_EVENT)
        {
          end = (char*)0;
          if (!event.data.scalar.value[0])
            *val = NAN;
          else if (!strcasecmp((const char*)event.data.scalar.value, ".inf"))
            *val = INFINITY;
          else
            *val = strtod((const char*)event.data.scalar.value, &end);
          if (end == (char*)event.data.scalar.value)
            {
              set_error("Parser error: cannot convert '%s' to a double.\n", end);
              done = -1;
            }
          else
            done = 0;
        }
      else
        {
          set_error("Parser error: value awaited.\n");
          done = (event.type == YAML_STREAM_END_EVENT)?1:-1;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  else
    {
      /* Error treatment. */
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return done;
}
static int _yaml_parser_read_double_array(yaml_parser_t *parser, const char *key,
                                          double *vals, unsigned int n, char **message)
{
  yaml_event_t event;
  int done;
  unsigned int i;
  size_t ln;

  /* Read the value. */
  done = 0;
  if (yaml_parser_parse(parser, &event))
    {
      if (event.type == YAML_SEQUENCE_START_EVENT)
        {
          for (i = 0; i < n && done == 0; i++)
            done = _yaml_parser_read_double(parser, vals + i, message);
          yaml_event_delete(&event);
          if (yaml_parser_parse(parser, &event))
            {
              if (event.type != YAML_SEQUENCE_END_EVENT)
                {
                  set_error("Parser error: end sequence missing for key '%s' after %d values.\n", key, n);
                  done = -1;
                }
            }
          else
            {
              /* Error treatment. */
              _yaml_parser_error(parser, message);
              done = -1;
            }
        }
      else
        {
          set_error("Parser error: sequence awaited after key '%s'.\n", key);
          done = -1;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  else
    {
      /* Error treatment. */
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return done;
}
static PosinpDictEntry* _dict_get_next(PosinpDict *dict, const char *key)
{
  size_t ln;
  unsigned int j;
#define DICT_INC 5

  if (!dict->items)
    {
      dict->items = malloc(sizeof(PosinpDictEntry) * DICT_INC);
      memset(dict->items, 0, sizeof(PosinpDictEntry) * DICT_INC);
      dict->len = DICT_INC;
    }
  for (j = 0; dict->items[j].key && j < dict->len; j++);
  if (j == dict->len)
    {
      dict->items = realloc(dict->items, sizeof(PosinpDictEntry) * (dict->len + DICT_INC));
      memset(dict->items + dict->len, 0, sizeof(PosinpDictEntry) * DICT_INC);
      dict->len += DICT_INC;
    }

  /* Store the key. */
  ln = strlen(key);
  dict->items[j].key = malloc(sizeof(char) * (ln + 1));
  memcpy(dict->items[j].key, key, sizeof(char) * (ln + 1));

  return dict->items + j;
}
static void _read_value(PosinpDictEntry *entry, const char *value)
{
  char *end, *pt;
  size_t ln;
  int ival;

  entry->type = POSINP_TYPE_DBL;
  if (!value[0])
    entry->value.dval = NAN;
  else if (!strcasecmp(value, ".inf"))
    entry->value.dval = INFINITY;
  else
    {
      entry->value.dval = strtod(value, &end);
      if (end == value)
        entry->type = POSINP_TYPE_INT;
    }

  ival = (int)strtol(value, &end, 10);
  pt = strchr(value, '.');
  if (end != value && !pt && (entry->type == POSINP_TYPE_INT ||
                              (double)ival == entry->value.dval))
    {
      entry->type = POSINP_TYPE_INT;
      entry->value.ival = ival;
      return;
    }
  else if (entry->type == POSINP_TYPE_DBL)
    return;

  entry->type = POSINP_TYPE_STR;
  ln = strlen(value);
  entry->value.str = malloc(sizeof(char) * (ln + 1));
  memcpy(entry->value.str, value, sizeof(char) * (ln + 1));
}
static void _read_array(PosinpDictEntry *entry)
{
  unsigned int ln;
  PosinpDict *dict;
  PosinpTypeId type;
  int *iarr;
  double *darr;

  if (entry->type != POSINP_TYPE_DICT ||
      !entry->value.dict.len ||
      !entry->value.dict.items[0].key)
    return;

  type = entry->value.dict.items[0].type;
  if (type != POSINP_TYPE_INT &&
      type != POSINP_TYPE_DBL)
    return;

  dict = &entry->value.dict;
  for (ln = 1; ln < dict->len && dict->items[ln].key; ln++)
    if (dict->items[ln].type != type)
      return;

  switch (type)
    {
    case (POSINP_TYPE_INT):
      iarr = malloc(sizeof(int) * ln);
      for (ln = 0; ln < dict->len && dict->items[ln].key; ln++)
        iarr[ln] = dict->items[ln].value.ival;
      _free_dict(dict);
      entry->type = POSINP_TYPE_INT_ARR;
      entry->value.iarr.len = ln;
      entry->value.iarr.arr = iarr;
      break;
    case (POSINP_TYPE_DBL):
      darr = malloc(sizeof(double) * ln);
      for (ln = 0; ln < dict->len && dict->items[ln].key; ln++)
        darr[ln] = dict->items[ln].value.dval;
      _free_dict(dict);
      entry->type = POSINP_TYPE_DBL_ARR;
      entry->value.darr.len = ln;
      entry->value.darr.arr = darr;
      break;
    default:
      break;
    }
}
static int _yaml_parser_read_property_map(yaml_parser_t *parser,
                                          PosinpDictEntry *entry, char **message);
static int _yaml_parser_read_property_list(yaml_parser_t *parser,
                                           PosinpDictEntry *entry, char **message)
{
  yaml_event_t event;
  int done;
  size_t ln;
  PosinpDict *dict;
  PosinpDictEntry *val;

  if (entry->type != POSINP_TYPE_DICT)
    return 0;

  dict = &entry->value.dict;

  /* Store the value. */
  done = 0;
  while (!done && yaml_parser_parse(parser, &event))
    {
      switch (event.type)
        {
        case YAML_SCALAR_EVENT:
          _read_value(_dict_get_next(dict, "index"),
                      (const char*)event.data.scalar.value);
          done = 0;
          break;
        case YAML_MAPPING_START_EVENT:
        case YAML_SEQUENCE_START_EVENT:
          val = _dict_get_next(dict, "index");
          val->type = POSINP_TYPE_DICT;
          if (event.type == YAML_SEQUENCE_START_EVENT)
            done = _yaml_parser_read_property_list(parser, val, message);
          else
            done = _yaml_parser_read_property_map(parser, val, message);
          break;
        case YAML_SEQUENCE_END_EVENT:
          _read_array(entry);
          done = 1;
          break;
        default:
          set_error("Parser error: value in list '%s' awaited.\n", entry->key);
          done = (event.type == YAML_STREAM_END_EVENT)?1:-1;
          break;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  /* Error treatment. */
  if (!done)
    {
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return (done < 0) ? done : 0;
}
static int _yaml_parser_read_property_map(yaml_parser_t *parser,
                                          PosinpDictEntry *entry, char **message)
{
  yaml_event_t event;
  int done;
  size_t ln;
  PosinpDict *dict;
  PosinpDictEntry *key;

  if (entry->type != POSINP_TYPE_DICT)
    return 0;

  dict = &entry->value.dict;
  key = (PosinpDictEntry*)0;

  /* Store the value. */
  done = 0;
  while (!done && yaml_parser_parse(parser, &event))
    {
      switch (event.type)
        {
        case YAML_SCALAR_EVENT:
          if (!key)
            key = _dict_get_next(dict, (const char*)event.data.scalar.value);
          else
            {
              _read_value(key, (const char*)event.data.scalar.value);
              key = (PosinpDictEntry*)0;
            }
          done = 0;
          break;
        case YAML_MAPPING_START_EVENT:
        case YAML_SEQUENCE_START_EVENT:
          if (!key)
            {
              set_error("Parser error: key must be a scalar in '%s'.\n", entry->key);
              done = -1;
            }
          else
            {
              key->type = POSINP_TYPE_DICT;
              if (event.type == YAML_SEQUENCE_START_EVENT)
                done = _yaml_parser_read_property_list(parser, key, message);
              else
                done = _yaml_parser_read_property_map(parser, key, message);
              key = (PosinpDictEntry*)0;
            }
          break;
        case YAML_MAPPING_END_EVENT:
          done = 1;
          break;
        default:
          set_error("Parser error: value in list '%s' awaited.\n", entry->key);
          done = (event.type == YAML_STREAM_END_EVENT)?1:-1;
          break;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  /* Error treatment. */
  if (!done)
    {
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return (done < 0) ? done : 0;
}
static int _yaml_parser_read_property(yaml_parser_t *parser, const char *key,
                                      PosinpDict *props, char **message)
{
  yaml_event_t event;
  int done;
  size_t ln;
  PosinpDictEntry *val;

  val = _dict_get_next(props, key);

  /* Store the value. */
  done = 0;
  if (yaml_parser_parse(parser, &event))
    {
      switch (event.type)
        {
        case YAML_SCALAR_EVENT:
          _read_value(val, (const char*)event.data.scalar.value);
          done = 0;
          break;
        case YAML_SEQUENCE_START_EVENT:
          val->type = POSINP_TYPE_DICT;
          done = _yaml_parser_read_property_list(parser, val, message);
          break;
        case YAML_MAPPING_START_EVENT:
          val->type = POSINP_TYPE_DICT;
          done = _yaml_parser_read_property_map(parser, val, message);
          break;
        default:
          set_error("Parser error: value awaited for '%s'.\n", val->key);
          done = (event.type == YAML_STREAM_END_EVENT)?1:-1;
          break;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  else
    {
      /* Error treatment. */
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return done;
}
static int _find_keyword(const char *keys[], const char *value, unsigned int *id,
                         unsigned int modulo, char **message)
{
  int done;
  size_t ln;

  for (*id = 0; keys[*id]; *id += 1)
    if (!strcasecmp(value, keys[*id]))
      break;
  if (keys[*id])
    {
      *id = *id % modulo;
      done = 0;
    }
  else
    {
      *id = 0;
      set_error("Parser error: cannot find key value '%s'.\n", value);
      done = -1;
    }
  return done;
}
static int _find_units(const char *keys[], const char *value, unsigned int *id,
                       unsigned int modulo, char **message)
{
  int done;
  size_t ln;
  char *start, *end, *unit;

  *id = 0;
  start = strchr(value, '(');
  if (!start)
    /* No unit specified, no error. */
    return 0;
  end = strchr(start, ')');
  if (!end)
    {
      /* Parentethis not closed, error. */
      set_error("Parser error: unit not properly written in '%s'.\n", value);
      return -1;
    }
  ln = end - start - 1;
  unit = malloc(sizeof(char) * (ln + 1));
  memcpy(unit, start + 1, ln);
  unit[ln] = '\0';

  done = _find_keyword(keys, unit, id, modulo, message);

  free(unit);
  return done;
}
static int _yaml_parser_read_keyword(yaml_parser_t *parser, const char *key,
                                     const char *keys[], unsigned int *id,
                                     unsigned int modulo, char **message)
{
  yaml_event_t event;
  int done;
  size_t ln;

  /* Read the value. */
  done = 0;
  if (yaml_parser_parse(parser, &event))
    {
      if (event.type == YAML_SCALAR_EVENT)
        done = _find_keyword(keys, (const char*)event.data.scalar.value, id, modulo, message);
      else
        {
          set_error("Parser error: value awaited after key '%s'.\n", key);
          done = -1;
        }

      /* The application is responsible for destroying the event object. */
      yaml_event_delete(&event);
    }
  else
    {
      /* Error treatment. */
      _yaml_parser_error(parser, message);
      done = -1;
    }

  return done;
}








static int posinp_yaml_cell(yaml_parser_t *parser, PosinpAtoms *atoms, char **message)
{
  int done;

  done = _yaml_parser_read_double_array(parser, "acell", atoms->acell, 3, message);
  if (done == 0)
    {
      atoms->BC = POSINP_BC_PERIODIC;
      if (atoms->acell[0] == INFINITY)
        atoms->BC -= 4;
      if (atoms->acell[1] == INFINITY)
        atoms->BC -= 2;
      if (atoms->acell[2] == INFINITY)
        atoms->BC -= 1;
    }
  
  return done;
}
static int posinp_yaml_coord(yaml_parser_t *parser, const char *symbol,
                             double coords[3], char **names, unsigned int *iat,
                             char **message)
{
  unsigned int ln;
  int done;

  /* Here parse the name... */
  for (*iat = 0; names[*iat] && strcmp((const char*)names[*iat], symbol); *iat += 1);
  if (!names[*iat])
    {
      ln = strlen(symbol);
      names[*iat] = malloc(sizeof(char*) * (ln + 1));
      memcpy(names[*iat], symbol, sizeof(char*) * ln);
      names[*iat][ln] = '\0';
    }

  done = _yaml_parser_read_double_array(parser, names[*iat], coords, 3, message);

  return done;
}
static int posinp_yaml_coords(yaml_parser_t *parser, PosinpAtoms *atoms, char **message)
{
  yaml_event_t event;
  int done, hasIGSpin, hasIGChg, hasFrozen;
  unsigned int count, atom_size;
#define ATOM_INC 100
#define UNSET 123456789

  /* Read the event sequence. */
  done = 0;
  count = 0;
  atom_size = ATOM_INC;
  atoms->rxyz = realloc(atoms->rxyz, sizeof(double) * atom_size * 3);
  atoms->atomnames = realloc(atoms->atomnames, sizeof(char*) * atom_size);
  memset(atoms->atomnames, 0, sizeof(char*) * atom_size);
  atoms->iatype = realloc(atoms->iatype, sizeof(unsigned int) * atom_size);
  atoms->ifrztyp = realloc(atoms->ifrztyp, sizeof(unsigned int) * atom_size);
  memset(atoms->ifrztyp, 0, sizeof(unsigned int) * atom_size);
  atoms->igspin = realloc(atoms->igspin, sizeof(int) * atom_size);
  memset(atoms->igspin, 0, sizeof(int) * atom_size);
  atoms->igchg = realloc(atoms->igchg, sizeof(int) * atom_size);
  memset(atoms->igchg, 0, sizeof(int) * atom_size);
  atoms->props = realloc(atoms->props, sizeof(PosinpDict) * atom_size);
  memset(atoms->props, 0, sizeof(PosinpDict) * atom_size);
  hasIGSpin = 0;
  hasIGChg  = 0;
  hasFrozen = 0;
  
  while (!done)
    /* Get the next event. */
    if (yaml_parser_parse(parser, &event))
      {
        switch(event.type)
          {
          case YAML_MAPPING_START_EVENT:
            if (count >= atom_size)
              {
                atom_size += ATOM_INC;
                atoms->rxyz = realloc(atoms->rxyz, sizeof(double) * 3 * atom_size);
                atoms->atomnames = realloc(atoms->atomnames, sizeof(char*) * atom_size);
                memset(atoms->atomnames + atom_size - ATOM_INC, 0, sizeof(char*) * ATOM_INC);
                atoms->iatype = realloc(atoms->iatype, sizeof(unsigned int) * atom_size);
                atoms->ifrztyp = realloc(atoms->ifrztyp, sizeof(unsigned int) * atom_size);
                memset(atoms->ifrztyp + atom_size - ATOM_INC, 0, sizeof(unsigned int) * ATOM_INC);
                atoms->igspin = realloc(atoms->igspin, sizeof(int) * atom_size);
                memset(atoms->igspin + atom_size - ATOM_INC, 0, sizeof(int) * ATOM_INC);
                atoms->igchg = realloc(atoms->igchg, sizeof(int) * atom_size);
                memset(atoms->igchg + atom_size - ATOM_INC, 0, sizeof(int) * ATOM_INC);
                atoms->props = realloc(atoms->props, sizeof(PosinpDict) * atom_size);
                memset(atoms->props + atom_size - ATOM_INC, 0, sizeof(PosinpDict) * ATOM_INC);
              }
            atoms->iatype[count] = UNSET;
            break;
          case YAML_MAPPING_END_EVENT:
            if (atoms->iatype[count] != UNSET)
              count += 1;
            break;
          case YAML_SEQUENCE_END_EVENT:
            done = 2;
            break;
          case YAML_SCALAR_EVENT:
            if (!strcmp((const char*)event.data.scalar.value, "IGSpin"))
              {
                done = _yaml_parser_read_int(parser, atoms->igspin + count, message);
                hasIGSpin = 1;
              }
            else if (!strcmp((const char*)event.data.scalar.value, "IGChg"))
              {
                done = _yaml_parser_read_int(parser, atoms->igchg + count, message);
                hasIGChg = 1;
              }
            else if (!strcmp((const char*)event.data.scalar.value, "Frozen"))
              {
                done = _yaml_parser_read_keyword(parser, "Frozen", frozen_keys,
                                                 atoms->ifrztyp + count,
                                                 POSINP_N_FROZEN, message);
                hasFrozen = 1;
              }
            else if (event.data.scalar.value[0] >= 'A' &&
                     event.data.scalar.value[0] <= 'Z' &&
                     atoms->iatype[count] == UNSET)
              done = posinp_yaml_coord(parser, (const char*)event.data.scalar.value,
                                       atoms->rxyz + 3 * count, atoms->atomnames,
                                       atoms->iatype + count, message);

            else
              done = _yaml_parser_read_property(parser, (const char*)event.data.scalar.value,
                                                atoms->props + count, message);
            break;
          default:
            done = (event.type == YAML_STREAM_END_EVENT);
            break;
          }

        /* The application is responsible for destroying the event object. */
        yaml_event_delete(&event);
      }
    else
      {
        /* Error treatment. */
        _yaml_parser_error(parser, message);
        done = -1;
      }
  
  if (done == 2)
    done = 0;

  atoms->nat       = count;
  atoms->rxyz      = realloc(atoms->rxyz,      sizeof(double) * 3 * atoms->nat);
  atoms->iatype    = realloc(atoms->iatype,    sizeof(unsigned int) * atoms->nat);
  if (hasFrozen)
    atoms->ifrztyp   = realloc(atoms->ifrztyp,   sizeof(unsigned int) * atoms->nat);
  else
    {
      free(atoms->ifrztyp);
      atoms->ifrztyp = (unsigned int*)0;
    }
  if (hasIGSpin)
    atoms->igspin    = realloc(atoms->igspin,    sizeof(int) * atoms->nat);
  else
    {
      free(atoms->igspin);
      atoms->igspin = (int*)0;
    }
  if (hasIGChg)
    atoms->igchg     = realloc(atoms->igchg,     sizeof(int) * atoms->nat);
  else
    {
      free(atoms->igchg);
      atoms->igchg = (int*)0;
    }
  for (atoms->ntypes = 0; atoms->atomnames[atoms->ntypes]; atoms->ntypes++);
  atoms->props     = realloc(atoms->props,     sizeof(PosinpDict) * atoms->nat);
  atoms->atomnames = realloc(atoms->atomnames, sizeof(char*) * atoms->ntypes);

  return done;
}
static int posinp_yaml_force(yaml_parser_t *parser, PosinpAtoms *atoms, char **message)
{
  yaml_event_t event, event2;
  int done;
  unsigned int count;
  size_t ln;

  if (atoms->nat < 1)
    {
      set_error("Parser error: forces are defined before atoms.\n");
      done = -1;
    }

  /* Read the event sequence. */
  done = 0;
  count = 0;

  atoms->fxyz = realloc(atoms->fxyz, sizeof(double) * atoms->nat * 3);
  memset(atoms->fxyz, 0, sizeof(double) * atoms->nat * 3);
  
  while (!done)
    /* Get the next event. */
    if (yaml_parser_parse(parser, &event))
      {
        switch(event.type)
          {
          case YAML_MAPPING_START_EVENT:
            /* Each mapping is one atom. */
            if (count >= atoms->nat)
              {
                set_error("Parser error: there are more forces than actual atoms.\n");
                done = -1;
                break;
              }
            if (yaml_parser_parse(parser, &event2))
              {
                if (event2.type == YAML_SCALAR_EVENT)
                  {
                    /* Here parse the name... */
                    if (!strcmp(atoms->atomnames[atoms->iatype[count]],
                                (const char*)event2.data.scalar.value))
                      /* Then the coordinates. */
                      done = _yaml_parser_read_double_array(parser,
                                                            atoms->atomnames[atoms->iatype[count]],
                                                            atoms->fxyz + 3 * count, 3, message);
                    else
                      {
                        set_error("Parser error: force %d is applied on atom '%s' while atom"
                                  " %d is named '%s'.\n", count, (const char*)event2.data.scalar.value,
                                  count, atoms->atomnames[atoms->iatype[count]]);
                        done = -1;
                      }
                  }
                else
                  {
                    set_error("Parser error: atom name awaited.\n");
                    done = -1;
                  }
              }
            else
              {
                /* Error treatment. */
                _yaml_parser_error(parser, message);
                done = -1;
              }
            yaml_event_delete(&event2);
            count += 1;
            break;
          case YAML_SEQUENCE_END_EVENT:
            done = 2;
            break;
          case YAML_SCALAR_EVENT:
            done = 0;
            break;
          default:
            done = (event.type == YAML_STREAM_END_EVENT);
            break;
          }

        /* The application is responsible for destroying the event object. */
        yaml_event_delete(&event);
      }
    else
      {
        /* Error treatment. */
        _yaml_parser_error(parser, message);
        done = -1;
      }
  
  if (done == 2)
    done = 0;

  return done;
}
static int posinp_yaml_forces(yaml_parser_t *parser, PosinpAtoms *atoms, char **message)
{
  yaml_event_t event;
  int done, count;

  /* Read the event sequence. */
  done = 0;
  count = 0;
  while (!done)
    /* Get the next event. */
    if (yaml_parser_parse(parser, &event))
      {
        switch(event.type)
          {
          case YAML_SEQUENCE_START_EVENT:
            if (count == 0)
              {
                done = posinp_yaml_force(parser, atoms, message);
                break;
              }
            /* Falls through. */
          case YAML_MAPPING_START_EVENT:
            count += 1;
            done = 0;
            break;
          case YAML_SEQUENCE_END_EVENT:
          case YAML_MAPPING_END_EVENT:
            count -= 1;
            done = 0;
            break;
          case YAML_SCALAR_EVENT:
            if (!strcmp((const char*)event.data.scalar.value, "Units"))
              done = _yaml_parser_read_keyword(parser, "Units", funits_keys,
                                               &atoms->funits, POSINP_FORCE_N_UNITS, message);
            else if (!strcmp((const char*)event.data.scalar.value, "Values"))
              done = posinp_yaml_force(parser, atoms, message);
            else if (!strcmp((const char*)event.data.scalar.value, "Fnrm"))
              done = _yaml_parser_read_double(parser, &atoms->fnrm, message);
            else if (!strcmp((const char*)event.data.scalar.value, "MaxVal"))
              done = _yaml_parser_read_double(parser, &atoms->maxval, message);
            else
              done = 0;
            break;
          default:
            done = (event.type == YAML_STREAM_END_EVENT);
            break;
          }

        /* Are we finished? */
        if (count == 0)
          done = 2;

        /* The application is responsible for destroying the event object. */
        yaml_event_delete(&event);
      }
    else
      {
        /* Error treatment. */
        _yaml_parser_error(parser, message);
        done = -1;
      }

  if (done == 2)
    done = 0;

  return done;
}
#if SYSTEM_X11 == 1
static char* strdup(const char *src)
{
  char *dest;
  size_t ln;

  ln = strlen(src);
  dest = malloc(sizeof(char) * (ln + 1));
  memcpy(dest, src, sizeof(char) * ln);
  dest[ln] = '\0';
  return dest;
}
#endif
static int posinp_yaml_external_potential(const PosinpDict *dict, PosinpAtoms *atoms, char **message)
{
  int done;
  const char *val;
  const PosinpDict *values;
  unsigned int i;

  done = 0;
  val = _as_str(dict, "units");
  if (val && (done = _find_keyword(UnitsPositions_keys, val, &atoms->punits,
                                   POSINP_COORD_N_UNITS, message)))
    return done;

  values = _as_dict(dict, "values");
  if (!values)
    return done;
  atoms->npots = _dict_len(values);
  if (atoms->npots)
    {
      atoms->potnames = malloc(sizeof(char*) * (atoms->npots + 1));
      for (i = 0; i < atoms->npots; i++)
        atoms->potnames[i] = strdup(_as_str(_at_dict(values, i), "sym"));
      atoms->potnames[atoms->npots] = (char*)0;
      atoms->pxyz = malloc(sizeof(double) * atoms->npots * 3);
      for (i = 0; i < atoms->npots; i++)
        _as_dbl(_at_dict(values, i), "r", atoms->pxyz + 3 * i, 3);
      atoms->psigma = malloc(sizeof(PosinpSigma) * atoms->npots);
      memset(atoms->psigma, '\0', sizeof(PosinpSigma) * atoms->npots);
      for (i = 0; i < atoms->npots; i++)
        _as_dbl(_at_dict(values, i), "sigma", atoms->psigma[i], POSINP_SIGMA_SIZE);
      atoms->ppoles = malloc(sizeof(PosinpPole) * atoms->npots);
      memset(atoms->ppoles, '\0', sizeof(PosinpPole) * atoms->npots);
      for (i = 0; i < atoms->npots; i++)
        {
          _as_dbl(_at_dict(values, i), "q0", &atoms->ppoles[i].q0, 1);
          _as_dbl(_at_dict(values, i), "q1", atoms->ppoles[i].q1, 3);
          _as_dbl(_at_dict(values, i), "q2", atoms->ppoles[i].q2, 5);
        }
    }

  return done;
}
static int posinp_yaml_properties(yaml_parser_t *parser, PosinpAtoms *atoms, char **message)
{
  yaml_event_t event;
  int done, count, reduced;

  /* Read the event sequence. */
  done = 0;
  count = 0;
  while (!done)
    /* Get the next event. */
    if (yaml_parser_parse(parser, &event))
      {
        switch(event.type)
          {
          case YAML_SEQUENCE_START_EVENT:
          case YAML_MAPPING_START_EVENT:
            count += 1;
            done = 0;
            break;
          case YAML_SEQUENCE_END_EVENT:
          case YAML_MAPPING_END_EVENT:
            count -= 1;
            done = 0;
            break;
          case YAML_SCALAR_EVENT:
            if (!strcmp((const char*)event.data.scalar.value, "Converged"))
              done = _yaml_parser_read_keyword(parser, "Converged", bool_keys,
                                               &atoms->converged, 2, message);
            else if (!strcmp((const char*)event.data.scalar.value, "Gnrm_wfn"))
              done = _yaml_parser_read_double(parser, &atoms->gnrm_wfn, message);
            else if (!strncmp((const char*)event.data.scalar.value, "Energy", 6))
              {
                done = _find_units(eunits_keys, (const char*)event.data.scalar.value,
                                   &atoms->eunits, POSINP_ENERG_N_UNITS, message);
                done = (!done)?_yaml_parser_read_double(parser, &atoms->energy, message):done;
              }
            else if (!strcmp((const char*)event.data.scalar.value, "Comment"))
              done = _yaml_parser_copy_str(parser, &atoms->comment, message);
            else if (!strcmp((const char*)event.data.scalar.value, "reduced"))
              {
                done = _yaml_parser_read_bool(parser, &reduced, message);
                if (reduced)
                  atoms->units = POSINP_COORD_UNITS_REDUCED;
              }
            else
              done = 0;
            break;
          default:
            done = (event.type == YAML_STREAM_END_EVENT);
            break;
          }

        /* Are we finished? */
        if (count == 0)
          done = 2;

        /* The application is responsible for destroying the event object. */
        yaml_event_delete(&event);
      }
    else
      {
        /* Error treatment. */
        _yaml_parser_error(parser, message);
        done = -1;
      }

  if (done == 2)
    done = 0;

  return done;
}
#endif

PosinpDict* posinp_yaml_parse_properties(const char *buffer, char **message)
{
  PosinpDict *dict;
#ifdef HAVE_YAML
  yaml_parser_t parser;
  yaml_event_t event;
  int done;

  dict = (PosinpDict*)0;

  /* Create the Parser object. */
  yaml_parser_initialize(&parser);
  yaml_parser_set_input_string(&parser, (const unsigned char*)buffer, strlen(buffer));

  /* Read the event sequence. */
  done = 0;
  while (!done)
    /* Get the next event. */
    if (yaml_parser_parse(&parser, &event))
      {
        if (event.type == YAML_DOCUMENT_START_EVENT)
          {
            dict = malloc(sizeof(PosinpDict));
            memset(dict, '\0', sizeof(PosinpDict));
          }
        else if (event.type == YAML_SCALAR_EVENT)
          done = _yaml_parser_read_property(&parser, (const char*)event.data.scalar.value, dict, message);
        else
          done = (event.type == YAML_STREAM_END_EVENT);

        /* The application is responsible for destroying the event object. */
        yaml_event_delete(&event);
      }
    else
      {
        /* Error treatment. */
        _yaml_parser_error(&parser, message);
        done = -1;
      }

  /* Destroy the Parser object. */
  yaml_parser_delete(&parser);
#else
  int ln;

  (void)buffer;
  dict = (PosinpDict*)0;

  set_error("No YAML support, cannot read properties.\n");
#endif

  return dict;
}
void posinp_yaml_free_properties(PosinpDict *dict)
{
  if (!dict)
    return;

  _free_dict(dict);
}

void posinp_yaml_parse(PosinpList **out, const char *filename, char **message)
{
#ifdef HAVE_YAML
  PosinpList *list, *single, *tmp;
  PosinpList start;
  PosinpDict dict;
  FILE *input;
  yaml_parser_t parser;
  yaml_event_t event;
  int done, stored;

  if (out)
    list = *out;
  else
    list = (PosinpList*)0;
  start.next = list;
  tmp = &start;
  
  input = fopen(filename, "rb");
  if (!input)
    return;

  /* Create the Parser object. */
  yaml_parser_initialize(&parser);
  yaml_parser_set_input_file(&parser, input);

  /* Read the event sequence. */
  stored = 0;
  done = 0;
  while (!done)
    /* Get the next event. */
    if (yaml_parser_parse(&parser, &event))
      {
        if (event.type == YAML_DOCUMENT_START_EVENT)
          {
            if (!tmp->next)
              {
                single = malloc(sizeof(PosinpList));
                memset(single, 0, sizeof(PosinpList));
                single->data = posinp_atoms_new();
                if (!list)
                  list = single;
                tmp->next = single;
              }
            tmp = tmp->next;
            stored = 0;
          }
        else if (event.type == YAML_SCALAR_EVENT && !stored &&
                 !strcmp((const char*)event.data.scalar.value, "units"))
          {
            done = _yaml_parser_read_keyword(&parser, "units", UnitsPositions_keys,
                                             &tmp->data->units, POSINP_COORD_N_UNITS,
                                             message);
            if (tmp->data->units != POSINP_COORD_UNITS_REDUCED)
              tmp->data->Units = (PosinpCellUnits)tmp->data->units;
          }
        else if (event.type == YAML_SCALAR_EVENT && !stored &&
                 !strcmp((const char*)event.data.scalar.value, "cell"))
          done = posinp_yaml_cell(&parser, tmp->data, message);
        else if (event.type == YAML_SCALAR_EVENT && !stored &&
                 !strcmp((const char*)event.data.scalar.value, "positions"))
          done = posinp_yaml_coords(&parser, tmp->data, message);
        else if (event.type == YAML_SCALAR_EVENT && !stored &&
                 !strcmp((const char*)event.data.scalar.value, "forces"))
          done = posinp_yaml_forces(&parser, tmp->data, message);
        else if (event.type == YAML_SCALAR_EVENT && !stored &&
                 !strcmp((const char*)event.data.scalar.value, "properties"))
          done = posinp_yaml_properties(&parser, tmp->data, message);
        else if (event.type == YAML_SCALAR_EVENT &&
                 !strcmp((const char*)event.data.scalar.value, "external_potential"))
          {
            memset(&dict, '\0', sizeof(PosinpDict));
            done = _yaml_parser_read_property(&parser, (const char*)event.data.scalar.value, &dict, message);
            if (!done)
              done = posinp_yaml_external_potential(_as_dict(&dict, "external_potential"), tmp->data, message);
            _free_dict(&dict);
          }
        else if (event.type == YAML_MAPPING_END_EVENT) {
          stored = (tmp->data->rxyz != (double*)0);
          done = 0;
        }
        else
          done = (event.type == YAML_STREAM_END_EVENT);

        /* The application is responsible for destroying the event object. */
        yaml_event_delete(&event);
      }
    else
      {
        /* Error treatment. */
        _yaml_parser_error(&parser, message);
        done = -1;
      }

  /* Destroy the Parser object. */
  yaml_parser_delete(&parser);
  fclose(input);
  
  if (out)
    *out = list;
  else
    posinp_yaml_free_list(list);
#else
  size_t ln;

  set_error("No YAML support, cannot read file '%s'.\n", filename);
  if (out)
    *out = (PosinpList*)0;
#endif
}
void posinp_yaml_free_list(PosinpList *lst)
{
  PosinpList *tmp;

  while(lst)
    {
      posinp_atoms_free(lst->data);
      tmp = lst;
      lst = lst->next;
      free(tmp);
    }
}

#ifdef TEST_ME
int main(int argc, const char **argv)
{
  PosinpList *lst, *tmp;

  lst = posinp_yaml_parse(argv[1], NULL);
  for (tmp = lst; tmp; tmp = tmp->next)
    {
      fprintf(stdout, "---\n");
      posinp_atoms_trace(tmp->data);
    }
  posinp_yaml_free_list(lst);

  return 0;
}
#endif
