/*
 * File hash.c - generate hash tables for Wine debugger symbols
 *
 * Copyright (C) 1993, Eric Youngdale.
 */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <neexe.h>
#include <segmem.h>
#include <prototypes.h>
#include <wine.h>
#include <dlls.h>

struct  name_hash{
	struct name_hash * next;
	unsigned int * address;
	char * name;
};

#define NR_NAME_HASH 128

static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,};

static  unsigned int name_hash(const char * name){
	unsigned int hash = 0;
	const char * p;

	p = name;

	while (*p) hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++;
	return hash % NR_NAME_HASH;

}


void add_hash(char * name, unsigned int * address){
	struct name_hash  * new;
	int hash;

	new = (struct  name_hash *) malloc(sizeof(struct name_hash));
	new->address = address;
	new->name = strdup(name);
	new->next = NULL;
	hash = name_hash(name);

	/* Now insert into the hash table */
	new->next = name_hash_table[hash];
	name_hash_table[hash] = new;
}

unsigned int * find_hash(char * name){
	char buffer[256];
	struct name_hash  * nh;

	for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
		if(strcmp(nh->name, name) == 0) return nh->address;

	if(name[0] != '_'){
		buffer[0] = '_';
		strcpy(buffer+1, name);
		for(nh = name_hash_table[name_hash(buffer)]; nh; nh = nh->next)
			if(strcmp(nh->name, buffer) == 0) return nh->address;
	};


	return (unsigned int *) 0xffffffff;
}


static char name_buffer[256];

char * find_nearest_symbol(unsigned int * address){
	struct name_hash * nearest;
	struct name_hash start;
	struct name_hash  * nh;
	int i;
	
	nearest = &start;
	start.address = (unsigned int *) 0;
	
	for(i=0; i<NR_NAME_HASH; i++) {
		for(nh = name_hash_table[i]; nh; nh = nh->next)
			if(nh->address <= address && nh->address > nearest->address)
				nearest = nh;
	};
	if((unsigned int) nearest->address == 0) return NULL;

	sprintf(name_buffer, "%s+0x%x", nearest->name, ((unsigned int) address) - 
		((unsigned int) nearest->address));
	return name_buffer;
}


void
read_symboltable(char * filename){
	FILE * symbolfile;
	unsigned int addr;
	int nargs;
	char type;
	char * cpnt;
	char buffer[256];
	char name[256];

	symbolfile = fopen(filename, "r");
	if(!symbolfile) {
		fprintf(stderr,"Unable to open symbol table %s\n", filename);
		return;
	};

	fprintf(stderr,"Reading symbols from file %s\n", filename);


	while (1)
	{
		fgets(buffer, sizeof(buffer),  symbolfile);
		if (feof(symbolfile)) break;
		
		/* Strip any text after a # sign (i.e. comments) */
		cpnt = buffer;
		while(*cpnt){
			if(*cpnt == '#') {*cpnt = 0; break; };
			cpnt++;
		};
		
		/* Quietly ignore any lines that have just whitespace */
		cpnt = buffer;
		while(*cpnt){
			if(*cpnt != ' ' && *cpnt != '\t') break;
			cpnt++;
		};
		if (!(*cpnt) || *cpnt == '\n') {
			continue;
		};
		
		nargs = sscanf(buffer, "%x %c %s", &addr, &type, name);
		add_hash(name, (unsigned int *) addr);
      };
      fclose(symbolfile);
}


/* Load the entry points from the dynamic linking into the hash tables. 
 * This does not work yet - something needs to be added before it scans the
 * tables correctly 
 */

void
load_entrypoints(){
	char buffer[256];
	char * cpnt;
	int j, ordinal, len;
	unsigned int address;

	struct w_files * wpnt;
	for(wpnt = wine_files; wpnt; wpnt = wpnt->next){
		cpnt  = wpnt->ne->nrname_table;
		while(1==1){
			if( ((int) cpnt)  - ((int)wpnt->ne->nrname_table) >  
			   wpnt->ne->ne_header->nrname_tab_length)  break;
			len = *cpnt++;
			strncpy(buffer, cpnt, len);
			buffer[len] = 0;
			ordinal =  *((unsigned short *)  (cpnt +  len));
			j = GetEntryPointFromOrdinal(wpnt, ordinal);		
			address  = j & 0xffff;
			j = j >> 16;
			address |= (wpnt->ne->selector_table[j].selector) << 16;
			fprintf(stderr,"%s -> %x\n", buffer, address);
			add_hash(buffer, (unsigned int *) address);
			cpnt += len + 2;
		};
	};
	return;
}
