#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "struct.h"

/*
 *	Vocab.c:	Version 1.08
 *	Author:		Alan Cox
 *	Last Changed:	2/6/90
 *
 *	Purpose:
 *		Manages the system vocabulary lists. Finds, adds and deletes
 *	vocabulary entries, whle maintaing the vocabulary lists and usage
 *	counters.
 *
 *	Bugs & Limits
 *		stricmp assumes ASCII set and can be fooled. Really needs
 *	a #ifdef ANSI to remove it on ANSI systems.
 *
 *	Functions Provided:
 *		AddWord,DelWord,FindWord,FindNumWord,stricmp,ResolveWord
 *	Functions Used:
 *		Allocator:estralloc,Allocator:emalloc
 *
 */

 
extern char *estralloc();

static struct Word *WordList=NULL;	/* Vocabulary linked list */

static void LockWord(wp)
struct Word *wp;
{
	wp->wd_Use++;
}


/*
 *	Add a word to the system vocabulary, or if it exists increase its
 *	usage count.
 */
 
void AddWord(x,v,t)
char *x;
int t;
tag v;
{
	extern struct Word *FindWord();
	struct Word *nwd=FindWord(x,t);
	if(nwd)
	{
		LockWord(nwd);
		return;
	}
	nwd=(struct Word *)emalloc(sizeof(struct Word));
	nwd->wd_Text=estralloc(x);
	nwd->wd_Type=t;
	nwd->wd_Code=v;
	nwd->wd_Use=1;
	nwd->wd_Next=WordList;
	WordList=nwd;
}

/*
 *	Reduce usage count of a word, and remove if nothing left.
 */
 
void DelWord(wp)
struct Word *wp;
{
	struct Word *w=WordList;
	wp->wd_Use--;
	if(wp->wd_Use)
		return;
	if(w==wp)
	{
		WordList=w->wd_Next;
		free(wp->wd_Text);
		free(wp);
		return;
	}
	while(w->wd_Next!=NULL)
	{
		if(w->wd_Next==wp)
		{
			w->wd_Next=w->wd_Next->wd_Next;
			free(wp->wd_Text);
			free(wp);
			return;
		}
		w=w->wd_Next;
	}
	fprintf(stderr,"[SYSTEM ERROR]: DelWord - Trash pointer\n");
}

/*
 *	Find a word in the vocabulary
 */
 
struct Word *FindWord(x,t)
char *x;
int t;
{
	struct Word *w=WordList;
/*	if(Me()==1) UPrintf("Looking for '%s' type %d.\n",x,t);*/
	while(w)
	{
		if((t==w->wd_Type||t==0)&&stricmp(w->wd_Text,x)==0)
			return(w);
		w=w->wd_Next;
	}
	return(NULL);
}

/*
 *	Find a word by word number in the vocabulary
 */

struct Word *FindNumWord(x,t)
int x;
int t;
{
	struct Word *w=WordList;
	while(w)
	{
		if((t==w->wd_Type||t==0)&&VAL(w->wd_Code)==x)
			return(w);
		w=w->wd_Next;
	}
	return(NULL);
}

/*
 *	Reasonably fast case independant string compare. This can be fooled
 *	by some system characters - works fine for normal characters
 *	Assumes ascii - FIX ME
 */

int stricmp(x,y)
char *x,*y;
{
	while(*x)
	{
		if(!*y)
			return(1);
		if((*x&~32)!=(*y&~32))
			return(1);
		x++;
		y++;
	}
	if(*y)
		return(1);
	return(0);
}


tag ResolveWord(x)
char *x;
{
	int vt;
	struct Word *w;
	switch(*x)
	{
		case 'V':;
		case 'v':vt=1;break;
		case 'A':;
		case 'a':vt=2;break;
		case 'N':;
		case 'n':vt=3;break;
		case 'P':;
		case 'p':vt=4;break;
		default:ELine();
			fprintf(stderr,"[ERROR]: Unknown word type in '%s.\n",x);
			break;
	}
	w=FindWord(x+2,vt);
	if(!w)
	{
		ELine();
		fprintf(stderr,"[ERROR]: Unknown word for '%s.\n",x);
		exit(0);
	}
	return(w->wd_Code);
}