/* UPE library - id tables
 * (c)2000 Stepan Roh
 * see license.txt for copying
 */
 
#include "upecc_ids.h"

#include <string.h>
#include <stdlib.h>
#include <assert.h>

/* id table item */
typedef struct id_table_item_t {
  char *id;				/* identifier */
  void *info;				/* user info */
  void (*free_info)(void *);		/* function to free info */
  struct id_table_item_t *next;		/* next in chain */
} id_table_item_t;

/* id table */
struct id_table_t {
  id_table_item_t *walk;		/* id table walk pointer */
  id_table_item_t *item;		/* id table items */
};

/* creates id table
 * returns NULL on error
 */
id_table_t *create_id_table (void) {
  id_table_t *table;
  
  if (!(table = malloc (sizeof (id_table_t)))) return NULL;
  table->item = table->walk = NULL;
  
  return table;
}

/* destroy id table */
void destroy_id_table (id_table_t *table) {
  id_table_item_t *i, *n;
  
  assert (table);
  
  i = table->item;
  while (i) {
    n = i->next;
    free (i->id);
    if (i->free_info) i->free_info (i->info);
    free (i);
    i = n;
  }
  free (table);
}

/* lookup id in table and return its info or NULL */
void *lookup_id_table (id_table_t *table, char *id) {
  id_table_item_t *i;

  assert (table); assert (id);
  
  i = table->item;
  while (i) {
    if (!strcmp (id, i->id)) return i->info;
    i = i->next;
  }
  
  return NULL;
}

/* add id and info into table - free_info is called when destroying item
 * returns 0 on success, -1 on error
 */
int add_id_table (id_table_t *table, char *id, void *info, void (*free_info)(void *)) {
  id_table_item_t *i;

  assert (table); assert (id); assert (info);
  
  if (!(i = malloc (sizeof (id_table_item_t)))) return -1;
  
  if (!(i->id = strdup (id))) return -1;
  i->info = info;
  i->free_info = free_info;
  i->next = table->item;
  table->item = i;
  
  return 0;
}

/* initialises table for id_table_walk_next() */
void init_id_table_walk (id_table_t *table) {
  
  assert (table);
  
  table->walk = table->item;
}

/* walk through table - returns 0 if there is no more items */
int id_table_walk_next (id_table_t *table, char **id, void **info) {

  assert (table); assert (id); assert (info);
  
  if (!table->walk) return 0;
  
  *id = table->walk->id;
  *info = table->walk->info;
  table->walk = table->walk->next;
  
  return 1;
}
