/************* Random poetry generator ***********************/
/**                                                         **/
/**                           poetry.c                      **/
/**                                                         **/
/** Copyright (C) Paul Gaze 1997                            **/
/**     Please, notify me, if you make any                  **/
/**     changes to this file.                               **/
/*************************************************************/
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<time.h>

#define	DEBUG_MESSAGES	0

//**************************************
//	Structures
//**************************************
typedef struct{
	char	*String;
	int		Subject,Object;
}VERB;

#define	MAX_LINE_LENGTH	256

#define	GENDA_HE	0
#define	GENDA_SHE	1
#define	GENDA_IT	2
#define	GENDA_THEY	3
#define	GENDA_I		4
#define	GENDA_WE	5

typedef struct{
	void	*Next;
	char	*String;
}TYPE_DATA;

typedef struct{
	char	*String;
	int		Genda;
	int		NTypes;
	int		*Types;
}NOUN;

typedef struct{
	int		NQuality;
	NOUN	*Quality;
	char	*String;
}TYPE;

typedef struct{
	int		NVerb;
	VERB	*Verb;
	int		NNoun;
	NOUN	*Noun;
	int		NExclamation;
	char	**Exclamation;
	int		NType;
	TYPE	*Type;
}POET;

typedef struct{
	int		N;
	NOUN 	*Noun;
	NOUN	*Quality;
	char	*String;
	int		Genda;
	int		HisGenda;
	int		NTypes;
	int		*Types;
}THING;

typedef struct{
	void	*Next;
	void	*Data;
	size_t	Amount;
}MEMBLOCK;

//**************************************
//	Prototypes
//**************************************
POET	*LoadPoet(char *name);
void	ErrorExit(char *message);
void	ComposePoem(char *output, POET *poet, int seed);
int		RND(int range);
void	SetGenda(THING *t);
void	NewThing(POET *p, THING *t);
void	ChooseQuality(POET *p, THING *t);
void	Replace(char *key, char *replacement, char *str);
int		FindLine(char **lines, int nlines, char *str);
void	*GetMem(size_t amount, char *ErrorMessage);
char	*CloneString(char *from);
void	FreeMem(void *data);
void	ReadNoun(char *from, NOUN *noun, POET *p);
void	IndentLine(char *line);
int		StringToBin(char *str);
void	ShowHelp(void);
#define	FAIL(message)	{printf(message); goto fail;}

//**************************************
//	Static data
//**************************************
char	*He[]={"he","she","it","they","i","we"};
char	*Him[]={"him","her","it","them","me","us"};
char	*His[]={"his","her","its","their","my","our"};
char	*Himself[]={"himself","herself","itself","themselves","myself","ourselves"};

//	Constants
int			NumberLines=6,PrintWidth=60;
char		*SubStr,*ObjStr;
MEMBLOCK	*MemList=0;
size_t		TotalMemory=0;

int main(int argc, char *argv[])
{
	POET	*poet;
	int		j;
	char	input;
	char	*poem,*ss;	
	int		seed;
	time_t	t;

	if(argc>1){
		if(!strcmp("?",argv[1]))ShowHelp();
	}
	if(argc==1)
		poet=LoadPoet("poet.txt");
	else
		poet=LoadPoet(argv[1]);

	//	Allocate space for strings
	SubStr=(char *)GetMem(MAX_LINE_LENGTH*sizeof(char), "Couldnt allocate space for subject string\n");
	ObjStr=(char *)GetMem(MAX_LINE_LENGTH*sizeof(char), "Couldnt allocate space for object string\n");

	//	Randomize timer
	time(&t);
	j=(int)t;
	srand(j);

	//	GET OPTIONS
	for(j=2; j<argc; j++){
		ss=argv[j];
		if( (ss[0]=='-') || (ss[0]='/') ){
			switch(ss[1]){
			case 'L': case 'l':
				NumberLines=StringToBin(&ss[2]);
				break;
			case 'W': case 'w':
				PrintWidth=StringToBin(&ss[2]);
				break;
			case 'S': case 's':
				seed=StringToBin(&ss[2]);
				srand(seed);
				break;
			case '?': case 'H': case 'h':
				ShowHelp();
				break;
			default:
				break;
			}
		}else if(ss[0]=='?'){
			ShowHelp();
		}
	}
		
	if(!poet)ErrorExit("Couldnt load poet data\n");
	poem=(char *)GetMem(64000,"Ran out of memory allocating buffer to recieve poems\n");
	seed=0;
	do{
		ComposePoem(poem, poet, seed);
		printf("\n\n");
		printf(poem);
		printf("\nENTER TO CONTINUE - Q = QUIT\n");
		input=getchar();
		seed++;
	}while( (input!='q') && (input!='Q') );

	ErrorExit(0);
	return 1;
}

//***********************************************
//	Show programs help screen
//***********************************************
//	Input:		None
//	Output:		None
//***********************************************
void	ShowHelp(void)
{
	printf(	"Random Poetry Generator Copyright 1997 - Paul Gaze\n"
			"Version 1.00   "__DATE__"\n"
			"\n"
			"Syntax: poem <filename> options\n"
			"\n"
			"Options can any of the following:\n"
			"    -Wnn  Set Characters per line to nn (default 60)\n"
			"    -Snn  Set random number seed to nn. Normaly its set\n"
			"          according to the current time\n"
			"    -Lnn  Set lines per poem to nn (default 6)\n"
			"    ?     Show this help screen\n"
			"\n"
			"filename is the name of the file containing the poetry data.\n"
			"If it isnt specified then the program will attempt to load\n"
			"a file called poet.txt\n"
			"\n"
	);
	ErrorExit("");
}

//***********************************************
//	Figure out the person of a noun, taking into
//	account if its quality is being used. Also
//	make list of types.
//***********************************************
//	Input:		Thing
//	Output:		None
//***********************************************
void	SetGenda(THING *t)
{
	t->HisGenda=t->Noun->Genda;
	if(t->Quality){
		t->Genda=t->Quality->Genda;
		t->Types=t->Quality->Types;
		t->NTypes=t->Quality->NTypes;
	}else{
		t->Genda=t->Noun->Genda;
		t->Types=t->Noun->Types;
		t->NTypes=t->Noun->NTypes;
	}
}

//***********************************************
//	Randomly choose a noun
//***********************************************
//	Input:		Poet data & output for noun
//	Output:		None
//***********************************************
void	NewThing(POET *p, THING *t)
{
	t->N=RND(p->NNoun);
	t->Noun=&p->Noun[t->N];
	t->Quality=0;
	SetGenda(t);
}

//***********************************************
//	Randomly choose a quality of a noun
//***********************************************
//	Input:		Poet data & thing to choose a
//				quality of
//	Output:		None
//***********************************************
void	ChooseQuality(POET *p, THING *t)
{
	int		j;
	TYPE	*type;

	if(!t->Noun->NTypes){
		ErrorExit("Strangely this noun had no types\n");
		return;
	}
	j=RND(t->Noun->NTypes);
	type=&p->Type[t->Noun->Types[j]];
	if(!type->NQuality){
		return;
	}
	j=RND(type->NQuality);
	t->Quality=&type->Quality[j];
	SetGenda(t);
}
//***********************************************
//	Substitute string
//***********************************************
//	Input:		String to replace, replacement,
//				string to work on
//	Output:		None
//***********************************************
void	Replace(char *key, char *replacement, char *str)
{
	char	*from, *comp, *to;
	int		j, nchar, move;

	for(; *str; str++){
		from=str;
		for(comp=key; *comp; comp++,from++){
			if(*comp!=*from)break;
		}
		if(*comp)continue;

		//	MAKE SPACE TO PUT IN SUBSTITUTE
		move=strlen(replacement)-strlen(key);
		if(move>0){
			from=str+strlen(str);
			to=from+move;
			nchar=strlen(str)-strlen(key)+1;
			for(j=nchar; j; j--){
				*to=*from;
				to--; from--;
			}		
		}else if(move<0){
			from=str+strlen(replacement);
			to=from+move;
			while(*from){
				*to++=*from++;
			}
			*to++=0;
		}
		memcpy(str, replacement, strlen(replacement) );
	}
}




//***********************************************
//	Create a random poem
//***********************************************
//	Input:		output for string, poet data &
//				seed form random number generator
//	Output:		None
//***********************************************
void	ComposePoem(char *output, POET *poet, int seed)
{
	int		verb,UseableVerbs,i,j,k,xx;
	char	*ex,letter;
	VERB	*v;
	THING	sub,obj,temp;
	THING	sub_last,obj_last;

	sub.String=SubStr;
	obj.String=ObjStr;
	NewThing(poet, &sub);
	NewThing(poet, &obj);
	sub_last.N=-1;
	sub_last.Quality=0;
	obj_last.N=-1;
	obj_last.Quality=0;

	*output=0;
	for(j=0; j<NumberLines; j++){
		do{
			v=poet->Verb;
			UseableVerbs=0;
			for(k=0; k<poet->NVerb; k++,v++){

//***********************************************************
#define	CHECK_VERB											\
				for(i=0; i<sub.NTypes; i++){				\
					if(sub.Types[i]==v->Subject)break;		\
				}											\
				if(i==sub.NTypes)continue;					\
				for(i=0; i<obj.NTypes; i++){				\
					if(obj.Types[i]==v->Object)break;		\
				}											\
				if(i==obj.NTypes)continue;
//***********************************************************
				CHECK_VERB
				UseableVerbs++;
			}
			if(!UseableVerbs){
				NewThing(poet, &sub);
				NewThing(poet, &obj);
			}
		}while(!UseableVerbs);
		verb=RND(UseableVerbs)+1;
		v=poet->Verb;
		for(v=poet->Verb; 1; v++){
			CHECK_VERB
			verb--;
			if(!verb)break;
		}
		if(RND(100)<33){
			ex=poet->Exclamation[RND(poet->NExclamation)];
		}else{
			ex=0;
		}
		

		//	GET OBJECT STRING
		if(obj.N==obj_last.N && obj.Quality==obj_last.Quality){
			sprintf( obj.String, Him[obj.Genda]);
		}else{
			if(obj.Quality){
				sprintf(obj.String, "%s %s",His[obj.HisGenda],obj.Quality->String);
			}else{
				sprintf(obj.String, obj.Noun->String);
			}
		}

		//	GET SUBJECT STRING
		if(sub.N==sub_last.N && sub.Quality==sub_last.Quality){
			sprintf( sub.String, He[sub.Genda]);
		}else{
			if(sub.Quality){
				sprintf(sub.String, "%s %s",His[sub.HisGenda],sub.Quality->String);
			}else{
				sprintf(sub.String, sub.Noun->String);
			}
		}
		if(ex){
			sprintf(output,"%s %s,\n", ex, v->String);
		}else{
			sprintf(output,"%s,\n", v->String);
		}
		Replace("*sub", sub.String, output);
		Replace("*psub", His[sub.Genda], output); 
		Replace("*ref", Himself[sub.Genda], output); 

		Replace("*obj", obj.String, output);
		Replace("*pobj", His[obj.Genda], output); 

		//	MAKE FIRST LETTER CAPITAL
		letter=*output;
		if( (letter>='a') && (letter<='z') )letter+=('A'-'a');
		*output=letter;
		IndentLine(output);		


		output+=(strlen(output));

		sub_last=sub;
		obj_last=obj;

		//	CHANGE OBJECT & SUBJECT
		xx=RND(100);
		if(xx<15){
			NewThing(poet, &obj);
		}else if(xx<30){
			NewThing(poet, &sub);
		}else if(xx<45){
			ChooseQuality(poet, &obj);
		}else if(xx<60){
			ChooseQuality(poet, &sub);
		}else if(xx<80){
			temp=sub;
			sub=obj;
			obj=temp;
		}
	}
	output-=2;
	*output='.';
}

//***********************************************
//	Return number in range 0 -> limit-1
//***********************************************
//	Input:		Range
//	Output:		Random number
//***********************************************
int	RND(int range)
{
	return	rand()%range;
}

//***********************************************
//	Format line to fit in display width
//***********************************************
//	Input:		String for line
//	Output:		None
//***********************************************
void	IndentLine(char *line)
{
	char	*indent="\n    ";
	char	*from,*to;
	int		move,nchar,j;	

	while(1){
		nchar=strlen(line);
		if(nchar<PrintWidth)break;
		j=PrintWidth;
		while( line[j]!=' ' ){
			j--;
			if(j<0)return;
		}
		line=&line[j];
		move=strlen(indent)-1;
		nchar=strlen(line)+1-1;
		from=&line[strlen(line)];
		to=&from[move];
		while(nchar){
			*to=*from;
			to--; from--;
			nchar--;
		}
		memcpy(line, indent, strlen(indent));
		line++;
	}
}
//***********************************************
//	Exit code with an error message
//***********************************************
//	Input:		Pointer to error message
//	Output:		None
//***********************************************
void	ErrorExit(char *message)
{
	if(message)printf(message);

	//	Free all memory
	while(MemList){
		FreeMem(MemList->Data);
	}
	#if	DEBUG_MESSAGES
		printf("%d bytes left unfreed\n",(int)TotalMemory);
	#endif
	exit(1);
}
//***********************************************
//	Load data for poet from file
//***********************************************
//	Input:	File name
//	Output:	Pointer to poet data
//***********************************************
POET	*LoadPoet(char *name)
{
	char 		*data=NULL,*from,*from2,*to,letter,*str,*str2;
	FILE		*f=NULL;
	size_t		length;
	int			nline, blank, j, k, doneit, n, start, end, nletter;
	int			iverb, sub_type, obj_type, finished;
	POET		*p=0;
	char		**line,*ss;
	NOUN		*noun;
	VERB		*v;
	TYPE_DATA	*TypeData=0, *t;
	TYPE		*tt;

	//	SET UP INITIAL STRUCTURE
	p=(POET *)GetMem(sizeof(POET),"Couldnt allocate space for poet data\n");
	memset(p, 0, sizeof(POET));

	//	LOAD IN DATA
	f=fopen(name,"rb");
	if(f==NULL)FAIL("Unable to open poet file\n");
	if(fseek(f, 0, SEEK_END))FAIL("Trouble reading poet file\n");
	length=ftell(f);
	data=(char *)GetMem(length+1, "Trouble allocating data to read poet file\n");
	if(fseek(f, 0, SEEK_SET))FAIL("Trouble reading poet file\n");;
	if(length!=fread(data, 1, length, f))FAIL("Trouble reading poet file\n");
	data[length]=0;
	fclose(f);

	//	REMOVE ESCAPE CHARACTERS
	from=to=data;
	while( (letter=*from++) ){
		if(letter!=0x0d)
			*to++=letter;
	}
	*to++=0;

	//	REMOVE COMMENTS & BLANK LINES	
	from=to=data;
	while(1){
		letter=*from;
		if(!letter)break;
		if(letter==';'){
			while(1){
				letter=*from++;
				if( (letter=='\n') || (!letter) )break;
			}
		}else{
			blank=1;
			nline=0;
			from2=from;
			while(1){
				nline++;
				letter=*from2++;
				if( (letter=='\n') || (!letter) )break;
				if( (letter!=' ') && (letter!='	') ){
					blank=0;
				}
			}
			if(!blank){
				memcpy(to, from, nline);
				to+=nline;
			}
			from+=nline;
		}
	}
	*to++=0;

	//	DIVIDE INTO LINES
	nline=0;
	from=data;
	do{
		letter=*from++;
		if( (!letter) || (letter=='\n') ){
			nline++;
		}
	}while(letter);
	line=(char **)GetMem(nline*sizeof(char *), "Trouble allocating memory for poet file\n");
	from=data;
	for(j=0; j<nline; j++){
		line[j]=from;
		do{
			letter=*from++;
			if( (letter=='\n')||(!letter) )
				break;
		}while(1);
		from--;
		*from++=0;
	}	

	//	GET RID OF GARBAGE AT END OF LINE
	for(j=0; j<nline; j++){
		from=line[j];
		n=strlen(from);
		doneit=0;
		for(;n>=0;n--){
			letter=from[n];
			switch(letter){
			case 0: case '	':case ' ':
				from[n]=0;
				break;
			default:
				doneit=1;
				break;
			}
			if(doneit)break;
		}
	}

	//////////////////////////////////////
	//									//
	//	GET TYPES						//
	//									//
	//////////////////////////////////////
	p->NType=0;
	for(j=0; j<nline; j++){
		str=line[j];
		str=strstr(str,"/");
		if(!str)continue;	
		do{
			str2=strstr(str+1,"/");
			if(!str2)break;
			nletter=((int)str2)-((int)str)+1;
			for(t=TypeData; t; t=(TYPE_DATA *)t->Next){
				if(nletter!=strlen(t->String))continue;
				if( !memcmp(str,t->String,nletter) )break;
			}
			if(!t){
				p->NType++;
				t=(TYPE_DATA *)GetMem(sizeof(TYPE_DATA), 0);
				t->Next=TypeData;
				TypeData=t;
				t->String=(char *)GetMem(nletter+1, 0);
				memcpy(t->String, str, nletter);
				t->String[nletter]=0;
			}
			str=str2;
		}while(1);
	}
	p->Type=(TYPE *)GetMem(p->NType*sizeof(TYPE), 0);
	memset(p->Type, 0, p->NType*sizeof(TYPE));
	t=TypeData;
	for(j=0; j<p->NType; j++){
		p->Type[j].String=t->String;
		t=(TYPE_DATA *)t->Next;
	}

	//////////////////////////////////////
	//									//
	//	READ EXCLAMATIONS				//
	//									//
	//////////////////////////////////////
	start=FindLine(line, nline, "&EXCLAMATIONS");
	if(start==nline)FAIL("Couldnt find &EXCLAMATIONS\n");

	end=FindLine(line, nline, "&ENDEXCLAMATIONS");
	if(end==nline)FAIL("Couldnt find &ENDEXCLAMATIONS\n");
	p->NExclamation=end-start-1;
	if(p->NExclamation<=0)FAIL("Dodgy exclamation data\n");

	p->Exclamation=(char **)GetMem(p->NExclamation*sizeof(char *), "Trouble allocating memory for exclamation data\n");
	for(j=0; j<p->NExclamation; j++){
		from=line[start+j+1];
		p->Exclamation[j]=(char *)GetMem(strlen(from) + 1, "Couldnt allocate memory for exclamation data\n");
		strcpy(p->Exclamation[j], from);
	}

	//////////////////////////////////////
	//									//
	//	GET NOUNS						//
	//									//
	//////////////////////////////////////
	start=FindLine(line, nline, "&NOUNS");
	if(start==nline)FAIL("Couldnt find &NOUNS\n");
	end=FindLine(line, nline, "&ENDNOUNS");
	if(end==nline)FAIL("Couldnt find &ENDNOUNS\n");
	p->NNoun=end-start-1;
	if(p->NNoun<=0)FAIL("No nouns found\n");

	noun=p->Noun=(NOUN *)GetMem(p->NNoun*sizeof(NOUN), "Ran out of memory\n");
	for(j=0; j<p->NNoun; j++, noun++){
		from=line[start+j+1];
		ReadNoun(from, noun, p);

	}

	//////////////////////////////////////
	//									//
	//	GET VERBS						//
	//									//
	//////////////////////////////////////
	start=FindLine(line, nline, "&VERBS");
	if(start==nline)FAIL("Couldnt find &VERBS\n");
	end=FindLine(line, nline, "&ENDVERBS");
	if(end==nline)FAIL("Couldnt find &ENDVERBS\n");

	//	COUNT VERBS & ALLOCATE SPACE FOR THEM
	p->NVerb=0;
	for(j=start+1; j<end; j++){
		if(!strstr(line[j],"/")){
			p->NVerb++;
		}
	}
	if(!p->NVerb)FAIL("There arent any verbs\n");
	v=p->Verb=(VERB *)GetMem(p->NVerb*sizeof(VERB), "Ran out of space allocating memory for verbs\n");
	j=start+1;
	iverb=0;
	finished=0;
	while(!finished){
		if(!strstr(line[j],"/"))FAIL("corrupt verb data 1\n");
		sub_type=obj_type=-1;
		for(k=0; k<p->NType; k++){
			str=strstr(line[j],p->Type[k].String);
			if(!str)continue;
			if(str==line[j])sub_type=k;
			ss=line[j]+1;
			str=strstr(line[j],p->Type[k].String);
			if(str)obj_type=k;
		}
		if( (sub_type==-1)||(obj_type==-1) ){
			if(sub_type!=-1)printf("Subject = %s\n",p->Type[sub_type].String);
			if(obj_type!=-1)printf("Object = %s\n",p->Type[obj_type].String);
			FAIL("Corrupt verb data 2\n");
		}
		j++;
		while(!strstr(line[j],"/")){
			v->String=CloneString(line[j]);
			v->Subject=sub_type;
			v->Object=obj_type;
			v++;
			iverb++;
			if(iverb==p->NVerb){
				finished=1;
				break;
			}
			j++;
		}
	}
	//	MAKE SURE ALL VERBS HAVE SUBJECT & OBJECT
	v=p->Verb;
	for(j=0; j<p->NVerb; j++,v++){
		k=0;
		if(!strstr(v->String,"*sub"))k+=5;
		if(!strstr(v->String,"*obj"))k+=5;
		if(k){
			to=(char *)GetMem(strlen(v->String)+k+1,"Low memory\n");
			*to=0;
			if(!strstr(v->String,"*sub"))
				strcat(to,"*sub ");
			strcat(to, v->String);
			if(!strstr(v->String,"*obj"))
				strcat(to," *obj");
			FreeMem(v->String);
			v->String=to;
		}
	}	

	//////////////////////////////////////
	//									//
	//	GET QUALITIES					//
	//									//
	//////////////////////////////////////
	start=FindLine(line, nline, "&QUALITIES");
	if(start==nline)FAIL("Couldnt find &QUALITIES\n");
	end=FindLine(line, nline, "&ENDQUALITIES");
	if(end==nline)FAIL("Couldnt find &ENDQUALITIES\n");
	j=start+1;
	while(j<end){
		if( strstr(line[j],"(") )FAIL("Corrupt quality data\n");
		for(k=0; k<p->NType; k++){
			if(!strcmp(p->Type[k].String,line[j]))break;
		}
		if(k==p->NType)FAIL("Failed to find type\n");
		tt=&p->Type[k];

		//	COUNT NUMBER OF QUALITIES
		tt->NQuality=0;
		k=j+1;
		while(strstr(line[k],"(")){
			tt->NQuality++;
			k++;
			if(k==end)break;
		}
		noun=tt->Quality=(NOUN *)GetMem(tt->NQuality*sizeof(NOUN), 0);
		for(k=0; k<tt->NQuality; k++){
			ReadNoun(line[k+j+1], noun, p);
			noun++;
		}
		j+=(tt->NQuality+1);
	}

	return p;
fail:
	ErrorExit("Couldnt load poet\n");
	return 0;
}

//***********************************************
//	Make a copy of a string
//***********************************************
//	Input:		String to copy
//	Output:		Copy of string
//***********************************************
char	*CloneString(char *from)
{
	char *to;

	to=(char *)GetMem(strlen(from)+1, 0);
	strcpy(to, from);
	return to;
}


//***********************************************
//	Find line equal to given string
//***********************************************
//	Input:		list of lines, number of lines &
//				string to be searched for.
//	Output:		number of line on which string is 
//				to be found or nlines if it isnt
//				found.
//***********************************************
int	FindLine(char **lines, int nlines, char *str)
{
	int	j;

	for(j=0; j<nlines; j++){
		if(!strcmp(str, lines[j]))break;
	}
	return j;
}

//***********************************************
//	Allocate memory	
//***********************************************
//	Input:		Amount to allocate & message to
//				print if allocation fails
//	Output:		pointer to memory allocated
//***********************************************
void	*GetMem(size_t amount, char *ErrorMessage)
{
	void 		*data=NULL;
	MEMBLOCK	*mb=NULL;

	data=malloc(amount);
	if(data==NULL)goto fail;
	mb=(MEMBLOCK *)malloc(sizeof(MEMBLOCK));
	if(mb==NULL)goto fail;
	mb->Data=data;
	mb->Amount=amount;
	mb->Next=MemList;
	MemList=mb;
	TotalMemory+=amount;	
	return data;
fail:
	if(data!=NULL)free(data);
	if(mb!=NULL)free(mb);
	if(ErrorMessage)printf(ErrorMessage);
	printf("Couldnt allocate %d bytes\n",(int)amount);
	ErrorExit("Ran out of memory\n");
}

//***********************************************
//	Free memory
//***********************************************
//	Input:		Pointer to memory to free
//	Output:		None
//***********************************************
void	FreeMem(void *data)
{
	MEMBLOCK	*m,*last;

	m=MemList;
	if(m->Data==data){
		MemList=(MEMBLOCK *)m->Next;
	}else{
		last=m;
		m=(MEMBLOCK *)m->Next;
		while(m){
			if(m->Data==data)break;
			last=m;
			m=(MEMBLOCK *)m->Next;
		}
		if(!m)ErrorExit("Tried to free non existant memory block\n");
		last->Next=m->Next;
	}
	TotalMemory-=m->Amount;
	free(m->Data);
	free(m);
}

//***********************************************
//	Read data for noun out of string
//***********************************************
//	Input:		Data, output for noun & poet data
//	Output:		None
//***********************************************
void	ReadNoun(char *from, NOUN *noun, POET *p)
{
	char	*str;
	int		nletter, n, k;

	//	GET GENDA
	if( strstr(from,"(he)") ){
		noun->Genda=GENDA_HE;			
	}else if( strstr(from,"(she)") ){
		noun->Genda=GENDA_SHE;			
	}else if( strstr(from,"(it)") ){
		noun->Genda=GENDA_IT;			
	}else if( strstr(from,"(they)") ){
		noun->Genda=GENDA_THEY;			
	}else if( strstr(from,"(i)") ){
		noun->Genda=GENDA_I;			
	}else if( strstr(from,"(we)") ){
		noun->Genda=GENDA_WE;			
	}else{
		printf("Trouble on line:\n%s\n",from);
		FAIL("Couldnt find genda of noun\n");
	}

	//	GET STRING
	str=from;
	nletter=0;
	while(*str){
		if(*str=='(')break;
		str++;
		nletter++;
	}
	if(!*str)FAIL("Couldnt get noun string\n");
	noun->String=(char *)GetMem(nletter+1, 0);
	noun->String[nletter]=0;
	memcpy(noun->String, from, nletter);

	//	COUNT TYPES & ALLOCATE SPACE FOR THEM
	str=from;
	noun->NTypes=0;
	while(*str){
		if(*str=='/')noun->NTypes++;
		str++;
	}
	noun->NTypes--;
	if(!noun->NTypes)FAIL("No types found for verb\b");
	noun->Types=(int *)GetMem(noun->NTypes*sizeof(int), 0);

	//	SET TYPES ARRAY
	str=from;
	k=0;
	for(n=0; n<p->NType; n++){
		if(strstr(from, p->Type[n].String)){
			if(k==noun->NTypes)FAIL("Something went wrong\n");
			noun->Types[k]=n;
			k++;
		}
	}

	for(n=0; n<noun->NTypes; n++){
		k=noun->Types[n];
	}
	return;
fail:
	ErrorExit("It went wrong\n");
}

//***********************************************
//	Convert ASCII string to integer value
//***********************************************
//	Input:		String
//	Output:		Value
//***********************************************
int	StringToBin(char *str)
{
	int	sum=0,letter;

	while( (letter=*str++) ){
		letter-='0';
		if( (letter<0)||(letter>9) )break;
		sum=(sum*10)+letter;
	}
	return sum;
}
