
/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/
#ident "$Header: names.c 1.1 90/01/19 $@(#)names.c	1.1 89/12/01"
#include <stdio.h>
#include <malloc.h>
#include "xsld.h"

#define NS_SIZE		1024	/* size of a memory block */
#define NS_LEN		10	/* Initial # of entries for memory blocks */
#define HASH_SIZE	5	/* Initial # of hash tables in a name table */
#define HASH_INC	1013	/* # of entries in each hash table */

extern char *gettxt();

char *calloc();

struct na_hash {
  char **nt_low;
  char **nt_high;
  SYMBOL *nt_data;
  int nt_used;
};
  
typedef struct na_access NAMETAB;

struct na_access {
  struct na_hash *na_tab;
  int na_ntab;
};
  
/*
 * Actual memory storage organization
 */
struct na_store {
  int ns_free;
  char *ns_mem;
};

static NAMETAB names = { 0, 0 };
static struct na_store *mem;
static int ns_free;
static int ns_cur = -1;
static int ns_max;

/*
 * Enlarge a table. Add entries for hash tables.
 */
static
na_enlarge()
{
  register int old;

  if (names.na_ntab == 0){
    /*
     * No hash entries allocated yet
     */
    names.na_tab = (struct na_hash *)calloc(sizeof(struct na_hash), HASH_SIZE);
    if (names.na_tab == 0){
      fprintf(stderr,gettxt("xsld:21","Out of memory (names.c (1))\n"));
      fatal();
    }
    names.na_ntab = HASH_SIZE;
  } else {
    /*
     * More hash entries needed
     */
    old = names.na_ntab;
    names.na_ntab += HASH_SIZE;
    names.na_tab = (struct na_hash *)realloc((char *)names.na_tab,
                    sizeof(struct na_hash) * names.na_ntab);
    if (names.na_tab == 0){
      fprintf(stderr,gettxt("xsld:22","Out of memory (names.c (2))\n"));
      fatal();
    }
    for ( ; old < names.na_ntab ; old++)
      names.na_tab[old].nt_low = 0;
  }
}

/*
 * Allocate a new memory block
 */
static
ns_enlarge()
{
  if (ns_free == ns_max){
    ns_max += NS_LEN;
    if (mem == 0){
      /*
       * Allocate first memory blocks reference table
       */
      if ((mem = (struct na_store *)malloc(sizeof (struct na_store) *
            NS_LEN)) == 0){
        fprintf(stderr,gettxt("xsld:23","Out of memory (names.c (3))\n"));
        fatal();
      }
    } else {
      /*
       * Enlarge table
       */
      if ((mem = (struct na_store *)realloc(mem, sizeof (struct na_store)
           * ns_max)) == 0){
        fprintf(stderr,gettxt("xsld:24","Out of memory (names.c (4))\n"));
        fatal();
      }
    }
  }
  /*
   * Allocate a memory block
   */
  if ((mem[ns_free].ns_mem = malloc(NS_SIZE)) == 0){
    fprintf(stderr,gettxt("xsld:25","Out of memory (names.c (5))\n"));
    fatal();
  }
  mem[ns_free].ns_free = 0;
  ns_free++;
  ns_cur++;
}
char *
na_store(name)
  char *name;
{
  int len = strlen(name) + 1;
  register char *h;
  struct na_store *aux;
  
  if (mem == 0 || len + mem[ns_cur].ns_free >= NS_SIZE)
    ns_enlarge();
  aux = mem + ns_cur;
  h  = aux->ns_mem + aux->ns_free;
  strcpy(h, name);
  aux->ns_free += len;
  return h;
}

/*
 * Add an entry in a names table
 */
char *
sym_store(name, data)
  char *name;
  SYMBOL data;
{
  struct na_hash *cur_tab;
  register char **h;
  register int i, j;
  char *ptr;
  int len, pos;
  
  for (i = 0, len = 0, ptr = name ; *ptr != '\0' ; ptr++, len++)
    i = (i << 1) + *ptr;

  pos = (i & 077777) % HASH_INC;

  /*
   * Scan each hash table in turn
   */
  for (j = 0 ; ; j++){
    if (j >= names.na_ntab)
      /*
       * Need more tables
       */
      na_enlarge();

    cur_tab = names.na_tab + j;

    if (cur_tab->nt_low == 0){
      /*
       * entry for hash table exists, but table is not yet allocated
       */
      register char **hp;
      register SYMBOL *dp;
      if ((hp = (char **)calloc(sizeof(char *), HASH_INC)) == 0){
        fprintf(stderr,gettxt("xsld:26","Out of memory (names.c (6))\n"));
        fatal();
      }
      cur_tab->nt_low = hp;
      cur_tab->nt_high = hp + HASH_INC;
      cur_tab->nt_used = 0;
      if ((dp = (SYMBOL *)malloc(sizeof(SYMBOL) * HASH_INC)) == 0){
        fprintf(stderr,gettxt("xsld:27","Out of memory (names.c (7))\n"));
        fatal();
      }
      cur_tab->nt_data = dp;
    }
    /*
     * Use quadratic hashing
     */
    h = cur_tab->nt_low + pos;
    i = 1;
    do {
      if (*h == 0){
        /*
         * Free slot found : insert here
         */
        struct na_store *aux;

        if (cur_tab->nt_used > (HASH_INC * 3) / 4)
          /*
           * Insert in another table, the current one is 'full'
           */
          break;
        cur_tab->nt_used++;

        len++;
        if (mem == 0 || len + mem[ns_cur].ns_free >= NS_SIZE)
          ns_enlarge();
         aux = mem + ns_cur;
        *h  = aux->ns_mem + aux->ns_free;
        strcpy(*h, name);
        aux->ns_free += len;
        pos = h - cur_tab->nt_low;
        cur_tab->nt_data[pos] = data;
      }
      if (**h == *name && strcmp(*h, name) == 0)
        /*
         * Entry is already in the table
         */
        return *h;

      h += i;
      i += 2;

      if (h > cur_tab->nt_high)
        h -= HASH_INC;

    } while (i < HASH_INC);
  }
}

/*
 * Locate a symbol in a table
 */
SYMBOL
sym_locate(name)
  char *name;
{
  struct na_hash *cur_tab;
  register char **h;
  register int i, j;
  char *ptr;
  int len, pos;
  
  for (i = 0, len = 0, ptr = name ; *ptr != '\0' ; ptr++, len++)
    i = (i << 1) + *ptr;

  pos = (i & 077777) % HASH_INC;

  /*
   * Scan each hash table in turn
   */
  for (j = 0 ; ; j++){
    if (j >= names.na_ntab){
      /*
       * not found in any table
       */
      return null_symbol;
    }

    cur_tab = names.na_tab + j;

    if (cur_tab->nt_low == 0){
      /*
       * Reached last actually allocated table
       * Entry is not present
       */
      return null_symbol;
    }

    h = cur_tab->nt_low + pos;
    i = 1;
    do {
      if (*h == 0)
        break;

      if (**h == *name && strcmp(*h, name) == 0){
        /*
         * Found entry;
         */
        pos = h - cur_tab->nt_low;
        return cur_tab->nt_data[pos];
      }

      h += i;
      i += 2;

      if (h > cur_tab->nt_high)
        h -= HASH_INC;

    } while (i < HASH_INC);
  }
}
