	/***************************************************************\
	*								*
	*	compdict.c - symbol table management routines for	*
	*	adlcomp.						*
	*	Copyright 1987 by Ross Cunniff				*
	*								*
	\***************************************************************/

/*LINTLIBRARY*/

#include <stdio.h>

#include "adltypes.h"
#include "adlprog.h"

#define HTSIZE 512		/* Size of a hash table */

char
    *calloc();

/* Structure of a hash table entry */
struct hash_entry {
    struct symbol
	entry_val;
    struct hash_entry
	*next;
};

/* The three dictionaries */
static struct hash_entry
    *sys_symb[ HTSIZE ],		/* The system symbols */
    *loc_symb[ HTSIZE ],		/* The local symbols */
    *gen_symb[ HTSIZE ];		/* The general symbols */

static int write_hash( FILE *fd, struct hash_entry **tab, int writing );

static int16 find( char *s, int16 hash, struct hash_entry **tab, int16 *val )
{
    struct hash_entry
	*ent;

    ent = tab[ hash ];
    while( ent != (struct hash_entry *)NULL ) {
	if( strcmp( ent->entry_val.name, s ) == 0 ) {
	    *val = ent->entry_val.val;
	    return ent->entry_val.type;
	}
	ent = ent->next;
    }
    return -1;
}


static int16 hashval( char *s )
{
    int
	t;

    t = 0;
    while( *s )
	t = (t + *s++) % HTSIZE;
    return t;
}


static void insert( char *s, int16 type, int16 val, int16 first,
				struct hash_entry **tab )
{
    struct hash_entry
	*ent;
    int16
	hash;
    char
	temp[ LENGTH+1 ];

    /* Trim the string to the maximum appropriate length */
    strncpy( temp, s, LENGTH );
    temp[ LENGTH ] = '\0';

    hash = hashval( temp );
    ent = tab[ hash ];
    tab[ hash ] = (struct hash_entry *)calloc( 1, sizeof( struct hash_entry ) );
    tab[ hash ]->next = ent;
    strcpy( tab[ hash ]->entry_val.name, temp );
    tab[ hash ]->entry_val.type = type;
    tab[ hash ]->entry_val.val = val;
    tab[ hash ]->entry_val.first = first;
}


int16 lookup( char *s, int16 *val )
{
    int16
	found,
	hash;
    char
	temp[ LENGTH+1 ];

    /* Trim the string to the maximum appropriate length */
    strncpy( temp, s, LENGTH );
    temp[ LENGTH ] = '\0';

    hash = hashval( temp );

    /* Search the local dictionary first */
    found = find( temp, hash, loc_symb, val );
    if( found >= 0 )
	return found;

    /* Search the system dictionary next */
    found = find( temp, hash, sys_symb, val );
    if( found >= 0 )
	return found;

    /* Search the general dictionary last */
    found = find( temp, hash, gen_symb, val );
    return found;
}


void insertkey( char *s, int16 type, int16 val, int16 first )
{
    insert( s, type, val, first, gen_symb );
    NUMSYM++;
}


void insert_sys( char *s, int16 type, int16 val )
{
    insert( s, type, val, 0, sys_symb );
}


void insert_local( char *s, int16 type, int16 val )
{
    insert( s, type, val, 0, loc_symb );
}


void count_symtab( int debug )
{
    NUMSYM = write_hash( 0, gen_symb, 0 );
    if( debug ) {
	NUMSYM += write_hash( 0, sys_symb, 0 );
    }
}


void write_symtab( FILE *fd, int debug )
{
    fseek( fd, 0L, 2 );			/* Seek to EOF */
    (void)write_hash( fd, gen_symb, 1 );
    if( debug ) {
	(void)write_hash( fd, sys_symb, 1 );
    }
}


static int write_hash( FILE *fd, struct hash_entry **tab, int writing )
{
    int16
	i, j, num;
    struct hash_entry
	*ent;

    num = 0;
    for( i = 0; i < HTSIZE; i++ ) {
	ent = tab[ i ];
	while( ent != (struct hash_entry *)0 ) {
	    if( writing ) {
		for( j = 0; j < strlen( ent->entry_val.name ); j++ )
		    ent->entry_val.name[ j ] ^= CODE_CHAR;
		fwrite( &ent->entry_val, sizeof( struct symbol ), 1, fd );
	    }
	    ent = ent->next;
	    num++;
	}
    }
    return num;
}


void del_locals( void )
{
    int16
	i;
    struct hash_entry
	*ent1, *ent2;

    for( i = 0; i < HTSIZE; i++ ) {
	ent1 = loc_symb[ i ];
	while( ent1 != (struct hash_entry *)0 ) {
	    ent2 = ent1;
	    ent1 = ent1->next;
	    free( ent2 );
	}
	loc_symb[ i ] = (struct hash_entry *)0;
    }
}

/*** EOF compdict.c ***/
