/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:symtab.c 12.0$ */
/* $ACIS:symtab.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/fdb_ca/lib/src/RCS/symtab.c,v $ */

/* (ef) 7/24/86 -- NULL and stderr are nice to have */
#include <stdio.h>

#ifndef lint
static char *rcsid = "$Header:symtab.c 12.0$";
#endif

/* #define debug    */
/****************************************************************************\
* 									     *
* 									     *
* symtab.cc: package of routines to support symbol table usage		     *
* 									     *
* The following routines are provided:					     *
* 									     *
* symtab_create: Makes and initializes a symbol table			     *
* 									     *
* symtab_add: Adds an entry and its associated data to a symbol table	     *
* 									     *
* symtab_find: Locates an entry in a symbol table and returns its	     *
* 	associated data							     *
* 									     *
* symtab_find_update: The same as symtab_find except if the entry is not     *
* 	found then symtab_find_update will put it in the symbol table	     *
* 	and return a pointer to a pointer which the user can set to point    *
* 	to his user data.						     *
* 	--not yet available--						     *
* 									     *
* symtab_remove: removes an entry from a symbol table			     *
*        --not yet available--						     *
* 									     *
* symtab_distroy: uninitializes and distroys a symbol table		     *
*                                                                            *
* symtab_scan_reset: restarts scanning of a symbol table		     *
* 									     *
* symtab_scan_next: returns the next entry in a symbol table until	     *
*        there are none left, the first time this routine is called	     *
*        and any time it is called after a call to symtab_scan_reset	     *
*        a new scan is started						     *
* 									     *
* There are three types of parameters that these routines take		     *
* as follows:								     *
* 									     *
* symbol table: a point to a private struct used by the symbol table	     *
* 	routines to identify a particular symbol table			     *
* 									     *
* symbol: an unsigned char string which is the symbol			     *
* 									     *
* data: a pointer to a user private struct				     *
*        which contains whatever data the user choses			     *
* 									     *
* Return codes: Many of these routines return an integer value to indicate   *
* the outcome of the operation.  The integer can be interpreted as follows:  *
* 									     *
* 	-1 -- Resource depletion, unable to carry out operation because	     *
* 		of resource (usally memory) limitations.		     *
* 									     *
* 	0 -- Normal return, the operation did its normal thing		     *
* 									     *
* 	1 -- Entry not found or not previously in the table (in the case     *
* 		of symtab_find_update).  This is the return given by	     *
* 		symtab_scan_next when the table has been completly	     *
* 		scanned.						     *
* 									     *
\****************************************************************************/

extern char *malloc();

struct symtab_entry_struct {
    unsigned char  *image;
    struct user_data   *data;
    struct symtab_entry_struct *next;
};
typedef struct symtab_entry_struct symtab_entry_type;

struct symtab_struct {
    int     size;		/* the number of entries in table */
    int     row;		/* current row in table, used in  scanning
				   the symbol table */
    symtab_entry_type * next;   /* current entry in table, used in
				   scanning */
    symtab_entry_type * table[1];
				/* each row is a pointer to a chain of
				   entries */
};

typedef struct symtab_struct symtab_type;

/****************\
* 		 *
* symtab_pentry	 *
* 		 *
\****************/
#ifdef debug
int symtab_pentry (entry, msg)
  symtab_entry_type *entry;
  char *msg;
{
    printf ("Symtab entry: %s", msg);
    if (entry == 0) {
	printf (": **** no entry ****\n");
    }
    else {
	printf (": addr %d, image <%s>, data %d, next %d \n",
		entry, entry -> image,
		entry -> data, entry -> next);
    }
}
#endif

/****************\
* 		 *
* symtab_create	 *
* 		 *
\****************/
symtab_type *symtab_create (expected_size)
  int expected_size;
{
    char *x;
    symtab_type *symtab;
    int     i;
    int size;

    /*  allocate symbol table, allowing room for table   */
    size = sizeof (symtab_type) + (expected_size - 1) * sizeof(int*);
    x = malloc(size);
    symtab = (symtab_type *) x;

    /*  initialize table   */
    symtab -> size = expected_size;
    for (i = 0; i < expected_size; i++) {
	(symtab -> table)[i] = 0;
    }
    /* (ef) 7/24/86 -- Initialize everything. C'mon, guys... */
    symtab -> row= -1;
    symtab -> next= NULL;
    return symtab;
}

/*************\
* 	      *
* symtab_add  *
* 	      *
\*************/
int symtab_add (symtab, symbol, data)
  symtab_type *symtab;
  unsigned char *symbol;
  struct user_data *data;
{
    symtab_entry_type * entry;
    int     tabrow;		/* row in symtab->table where this symbols
				   entry goes */

 /* allocate and initialize entry */
    entry = (symtab_entry_type *) malloc (sizeof (symtab_entry_type));
    if ((int) entry <= 0) {
	return (-1);
    }
    entry -> image = symbol;
    entry -> data = data;

 /* compute row in symbol table and insert entry */
    strhash (symbol, symtab -> size, &tabrow);
#ifdef debug
    printf ("in add: symbol <%s>, hashkey = %d\n", symbol, tabrow);
    symtab_pentry (entry, "almost added");
#endif
    entry -> next = (symtab -> table)[tabrow];
    (symtab -> table)[tabrow] = entry;
#ifdef debug
    printf ("at added: %d", (symtab -> table)[tabrow]);
    symtab_pentry (entry, "added");
#endif

}
/****************\
*                *
* symtab_distroy *
*                *
\****************/
int symtab_distroy ( symtab)
 symtab_type *symtab;
{
  symtab_entry_type *entry, *entry_next;
  int i;
  
  for (i=0;i<symtab->size;i++) {
#ifdef debug
      printf("in distroy: %d,i=%d\n", (symtab->table)[i],i);
#endif      
      if ((entry = (symtab ->table)[i]) != 0) {
#ifdef debug
    printf ("in distroy: %d\n", (symtab -> table)[i]);
    symtab_pentry (entry, "deleted");
#endif
         while ((entry_next = entry ->next) !=0 ) {
            free (entry);
            entry = entry_next;
	 }
      free(entry);	 
      }
  }
  free(symtab);    
	 
}
/**************\
* 	       *
* symtab_find  *
* 	       *
\**************/
int symtab_find (symtab, symbol, data)
  symtab_type *symtab;
  unsigned char *symbol;
  struct user_data **data;
{
    symtab_entry_type * entry;
    int     tabrow;		/* row in symbol table where symbol should
				   be */
    int     rc = 0;		/* return code */

 /* compute row in symbol table */
    strhash (symbol, symtab -> size, &tabrow);
#ifdef debug
    printf ("in find: symbol <%s>, hashkey = %d\n", symbol, tabrow);
#endif

 /* scan chain at appropriate row in table for symbol */
    entry = (symtab -> table)[tabrow];
#ifdef debug
    symtab_pentry (entry, "find1");
#endif
    while (entry && (strcmp (entry -> image, symbol) != 0)) {
	entry = entry -> next;
#ifdef debug
	symtab_pentry (entry, "find2");
#endif
    }
 /* if entry = 0 then no match was found */
    if (entry) {
	*data = entry -> data;
	rc = 0;
    }
    else {
	*data = 0;
	rc = 1;
    }

    return (rc);
}

/********************\
* 		     *
* symtab_scan_reset  *
* 		     *
\********************/
int symtab_scan_reset (symtab)
  symtab_type *symtab;
{
    symtab -> row = -1;
    symtab -> next = 0;
}

/*******************\
* 		    *
* symtab_scan_next  *
* 		    *
\*******************/
int symtab_scan_next (symtab, symbol, data)
  symtab_type *symtab;
  unsigned char **symbol;
  struct user_data **data;
{
    symtab_entry_type * entry;
    int     rc = 0;

#ifdef debug
    printf ("scan: row %d, size %d\n", symtab->row, symtab->size); 
#endif
    while (symtab -> row < symtab -> size) {
	entry = symtab -> next;
#ifdef debug
        symtab_pentry (entry, "scan"); 
#endif
	if (entry) {
	/* next entry found */
	    *symbol = entry -> image;
	    *data = entry -> data;
	    symtab -> next = entry -> next;
	    break;
	}
	else {
	    (symtab -> row)++;
	    symtab -> next = (symtab -> table)[symtab -> row];
	}
    }

/* if entry is 0 then no entry was found, set rc accordingly	*/
    if (entry == 0) {
	rc = 1;
    }

    return (rc);
}


