// MPIndex - AmigaGuide Indexing program
// Copyright (C) © 1996 Mark John Paddock

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

// mark@topic.demon.co.uk
// mpaddock@cix.compulink.co.uk

// Change following line to #define MPINDEXPRINT 1 to allow printing (for debugging)
#undef MPINDEXPRINT

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <exec/memory.h>
#include <proto/locale.h>

extern struct Library *LocaleBase = NULL;
extern struct Catalog *Catalog=NULL;

#define CATCOMP_BLOCK
#define CATCOMP_NUMBERS
#include "Mmessages.h"

extern long __oslibversion=39;

extern long __stack = 16000;

struct IgnoreWord {
	char *Word;
	BOOL ReallyIgnore;
	struct IgnoreWord *Left;
	struct IgnoreWord *Right;
};

struct IgnoreWord *TopIgnore;

const char Version[]="$VER: MakeMPIndex 5.5 (26.2.97)";

static int NodeCount = 0;

extern void *Chain = NULL;
#define PUDDLE 64000
#define THRESH 3000

struct RDArgs *rdargs = NULL;

#ifdef MPINDEXPRINT
#define TEMPLATE "TO/A,MERGE/K,IGNORE/K,IGNORETO/K,MAXNODE/K/N,NODE/S,NODE2/S,TITLE/S,FILE/K,FROM/M,PRINT/S"
#else
#define TEMPLATE "TO/A,MERGE/K,IGNORE/K,IGNORETO/K,MAXNODE/K/N,NODE/S,NODE2/S,TITLE/S,FILE/K,FROM/M"
#endif
#define OPT_TO			0
#define OPT_MERGE		1
#define OPT_IGNORE	2
#define OPT_IGNORETO	3
#define OPT_MAX		4
#define OPT_NODE		5
#define OPT_NODE2		6
#define OPT_TITLE		7
#define OPT_FILE		8
#define OPT_FROM		9

#ifdef MPINDEXPRINT
#define OPT_PRINT		10
#define OPT_COUNT		11
#else
#define OPT_COUNT		10
#endif

long opts[OPT_COUNT] = {
	0
};

int MaxNodes = 0;

FILE *ignoreto = NULL;

char
*GetMessage(UWORD message) {
	LONG   *l;
	UWORD  *w;
	STRPTR  builtIn;

   l = (LONG *)CatCompBlock;

	while (*l != message)  {
		w = (UWORD *)((ULONG)l + 4);
		l = (LONG *)((ULONG)l + (ULONG)*w + 6);
	}
	builtIn = (STRPTR)((ULONG)l + 6);
	return(GetCatalogStr(Catalog,message,builtIn));
}

void __regargs _CXBRK(void) {
	printf("**Break\n");
	if (ignoreto) {
		fclose(ignoreto);
		ignoreto = NULL;
	}
	DeletePool(Chain);
	FreeArgs(rdargs);
	CloseCatalog(Catalog);
	CloseLibrary(LocaleBase);
	exit(10);
}	

APTR
Mycalloc(ULONG size) {
	APTR res;
	res = AllocPooled(Chain,size);
	if (res) {
		return res;
	}
	DeletePool(Chain);
	FreeArgs(rdargs);
	printf(GetMessage(MSG_NOMEM));
	CloseCatalog(Catalog);
	CloseLibrary(LocaleBase);
	exit(10);
}

APTR
Mystrdup(UBYTE *str) {
	return strcpy(Mycalloc(strlen(str)+1),str);
}

struct Link {
	struct MyNode *MyNode;
	struct Word *Word;
	struct Link *NextNodeLink;
	struct Link *NextWordLink;
	int Count;
};

struct MyNode {
	char *Title;
	char *Name;
	char *Name2;
	struct MyNode *Left;
	struct MyNode *Right;
	struct Link *FirstLink;
	int Count;
	USHORT Num;
	USHORT seq;
};

static struct MyNode *TopNode = NULL;

struct Word {
	char *Word;
	ULONG Offset;
	struct Word *Left;
	struct Word *Right;
	struct Word *Owner;
	struct Link *FirstLink;
	int Count;
};

static struct Word *TopWord = NULL;

struct Word *
AddWord(char *p) {
	struct Word *Word1;
	int strres;
	if (!TopWord) {
		TopWord = Mycalloc(sizeof(struct Word));
		TopWord->Word = Mystrdup(p);
		return TopWord;
	}
	Word1 = TopWord;
	while (1) {
		strres = stricmp(Word1->Word,p);
		if (!strres) {
			// V5.2
			if (isupper(*Word1->Word) && islower(*p)) {
				strcpy(Word1->Word,p);
			}
			return Word1;
		}
		if (strres > 0) {
			if (!Word1->Left) {
				Word1->Left = Mycalloc(sizeof(struct Word));
				Word1->Left->Word = Mystrdup(p);
				Word1->Left->Owner = Word1;
				return Word1->Left;
			}
			Word1 = Word1->Left;
		}
		else {
			if (!Word1->Right) {
				Word1->Right = Mycalloc(sizeof(struct Word));
				Word1->Right->Word = Mystrdup(p);
				Word1->Right->Owner = Word1;
				return Word1->Right;
			}
			Word1 = Word1->Right;
		}
	}
}

static void
LinkInWord(struct MyNode *MyNode,struct Word *Word,struct Link *Link1) {
	struct Link *Link,*Link2;
	Link = Word->FirstLink;
	Link2 = NULL;
	while (Link && 
			 (0 < stricmp(Link->MyNode->Title,MyNode->Title))) {
		Link2 = Link;
		Link = Link->NextWordLink;
	}
	if (Link) {
		Link1->NextWordLink = Link;
		if (Link2) {
			Link2->NextWordLink = Link1;
		}
		else {
			Word->FirstLink = Link1;
		}
	}
	else {
		if (Link2) {
			Link2->NextWordLink = Link1;
		}
		else {
			Link1->NextWordLink = Word->FirstLink;
			Word->FirstLink = Link1;
		}
	}
}

static void
AddIgnore(char *p,BOOL ignore) {
	struct IgnoreWord *Node,*Node1;
	int strres;
	// May not get used if duplicate
	Node = Mycalloc(sizeof(struct IgnoreWord));
	Node->Word = Mystrdup(p);
	Node->ReallyIgnore = ignore;
	if (ignore && ignoreto) {
		fputs(p,ignoreto);
		fputs("\n",ignoreto);
	}
	if (!TopIgnore) {
		TopIgnore = Node;
		if (ignore) {
			printf(" - %s\n",p);
		}
		return;
	}
	Node1 = TopIgnore;
	while (1) {
		strres = stricmp(Node1->Word,Node->Word);
		if (strres > 0) {
			if (!Node1->Left) {
				Node1->Left = Node;
				if (ignore) {
					printf(" - %s\n",p);
				}
				return;
			}
			else {
				Node1 = Node1->Left;
			}
		}
		else {
			if (!strres) {
				// duplicate - must be adding a real ignore
				if (!Node1->ReallyIgnore) {
					printf(" - %s\n",p);
				}
				Node1->ReallyIgnore = TRUE;
				FreePooled(Chain,Node,sizeof(struct IgnoreWord));
				return;
			}
			else {
				if (!Node1->Right) {
					Node1->Right = Node;
					if (ignore) {
						printf(" - %s\n",p);
					}
					return;
				}
				else {
					Node1 = Node1->Right;
				}
			}
		}
	}
}


// Try and remove a word from the tree
static void
FreeWord(struct Word *Word) {
	struct Word *o,*ol,*l,*r;
	o = Word->Owner;
	if (!o) {
		l = Word->Left;
		r = Word->Right;
		if (l && r) {
			return;
		}
		if (l) {
			TopWord = l;
			return;
		}
		if (r) {
			TopWord = r;
			return;
		}
		TopWord = NULL;
		return;
	}
	l = Word->Left;
	r = Word->Right;
	if (l && r) {
		return;
	}
	ol = o->Left;
	if (Word == ol) {
		if (l) {
			o->Left = l;
			return;
		}
		if (r) {
			o->Left = r;
			return;
		}
		o->Left = NULL;
		return;
	}
	if (l) {
		o->Right = l;
			return;
	}
	if (r) {
		o->Right = r;
		return;
	}
	o->Right = NULL;
	return;
}

static void
LinkNodeWord(struct MyNode *MyNode,struct Word *Word) {
	struct Link *Link,*Link1,*Link2;
	Link2 = NULL;
	Link = MyNode->FirstLink;
	while (Link && (stricmp(Link->Word->Word,Word->Word) < 0)) {
		Link2 = Link;
		Link = Link->NextNodeLink;
	}
	if (Link) {
		if (!stricmp(Link->Word->Word,Word->Word)) {
			++Link->Count;
		}
		else {
			++Word->Count;
			++MyNode->Count;
			Link1 = Mycalloc(sizeof(struct Link));
			Link1->MyNode = MyNode;
			Link1->Word = Word;
			Link1->Count = 1;
			Link1->NextNodeLink = Link;
			if (Link2) {
				Link2->NextNodeLink = Link1;
			}
			else {
				MyNode->FirstLink = Link1;
			}
			LinkInWord(MyNode,Word,Link1);
			if ((0 != MaxNodes) && (Word->Count > MaxNodes)) {
				AddIgnore(Word->Word,TRUE);
			}
		}
	}
	else {
		++Word->Count;
		++MyNode->Count;
		Link1 = Mycalloc(sizeof(struct Link));
		Link1->MyNode = MyNode;
		Link1->Word = Word;
		Link1->Count = 1;
		if (Link2) {
			Link2->NextNodeLink = Link1;
		}
		else {
			Link1->NextNodeLink = MyNode->FirstLink;
			MyNode->FirstLink = Link1;
		}
		LinkInWord(MyNode,Word,Link1);
		if ((0 != MaxNodes) && (Word->Count > MaxNodes)) {
			AddIgnore(Word->Word,TRUE);
			FreeWord(Word);
		}
	}
}

BOOL
CheckIgnore(char *p) {
	struct IgnoreWord *IgnoreWord;
	int strres;

	IgnoreWord = TopIgnore;
	if (!IgnoreWord) {
		return TRUE;
	}
	while (1) {
		strres = stricmp(IgnoreWord->Word,p);
		if (!strres) {
			return (BOOL)!IgnoreWord->ReallyIgnore;
		}
		if (strres > 0) {
			if (!IgnoreWord->Left) {
				return TRUE;
			}
			IgnoreWord = IgnoreWord->Left;
		}
		else {
			if (!IgnoreWord->Right) {
				return TRUE;
			}
			IgnoreWord = IgnoreWord->Right;
		}
	}
}

static void
AddWords(struct MyNode *MyNode,char *buffer) {
	char tbuff[257];
	struct Word *Word;
	char *p,*p1,*p2;
	int Done = 0;
	strcpy(tbuff,buffer);
	p = tbuff;
	while (!Done) {
		if ('@' == *p) {
			++p;
			while (*p && (isalnum(*p) || ('_' == *p) || ('-' == *p))) {
				++p;
			}
			if (!*p) {
				Done = 1;
			}
		}
		else {
			if (isalnum(*p)) {
				p1 = p;
				while (*p1 && (isalnum(*p1) || ('_' == *p) || ('-' == *p) || ('.' == *p))) {
					++p1;
				}
				p2 = p1;
				--p2;
				while ('.' == *p2) {
					*p2 = 0;
					--p2;
				}
				if (*p1) {
					if ('\n' == *p1) {
						Done = 1;
					}
					*p1 = 0;
				}
				else {
					Done = 1;
				}
				if (CheckIgnore(p)) {
					Word = AddWord(p);
					LinkNodeWord(MyNode,Word);
				}
				p = p1;
			}
			else {
				if (!*p) {
					Done = 1;
				}
			}
		}
		++p;
	}
}

static void
WriteNodes(struct MyNode *MyNode,FILE *fp) {
	if (!MyNode) {
		return;
	}
	if (MyNode->Left) {
		WriteNodes(MyNode->Left,fp);
	}
	if (MyNode->Title) {
		putc('N',fp);
		fwrite(&(MyNode->seq),2,1,fp);
		putc(strlen(MyNode->Name),fp);
		fputs(MyNode->Name,fp);
		putc(strlen(MyNode->Title),fp);
		fputs(MyNode->Title,fp);
	}
	if (MyNode->Right) {
		WriteNodes(MyNode->Right,fp);
	}
}

static void
CountNodes(struct MyNode *MyNode) {
	if (!MyNode) {
		return;
	}
	if (MyNode->Left) {
		CountNodes(MyNode->Left);
	}
	if (MyNode->Title) {
		MyNode->Num = NodeCount;
		++NodeCount;
	}
	if (MyNode->Right) {
		CountNodes(MyNode->Right);
	}
}

#ifdef MPINDEXPRINT
static void
PrintNode(struct MyNode *MyNode) {
	struct Link *Link;
	if (!MyNode) {
		return;
	}
	if (MyNode->Left) {
		PrintNode(MyNode->Left);
	}
	printf("%s - %s\t%d\n",MyNode->Name,MyNode->Title,MyNode->Count);
	Link = MyNode->FirstLink;
	while (Link) {
		printf("\t%s\t%d\n",Link->Word->Word,Link->Count);
		Link = Link->NextNodeLink;
	}
	if (MyNode->Right) {
		PrintNode(MyNode->Right);
	}
}
#endif

static void
WriteWords(struct Word *Word,FILE *fp) {
	struct Link *Link;
	if (!Word) {
		return;
	}
	if (Word->Left) {
		WriteWords(Word->Left,fp);
	}
	if (Word->Count) {
		putc('W',fp);
		fwrite(&(Word->Offset),4,1,fp);
		Link = Word->FirstLink;
		while (Link) {
			putc('L',fp);
			fwrite(&(Link->MyNode->Num),2,1,fp);
			Link = Link->NextWordLink;
		}
	}
	if (Word->Right) {
		WriteWords(Word->Right,fp);
	}
}

#ifdef MPINDEXPRINT
static void
PrintWord(struct Word *Word) {
	struct Link *Link;
	if (!Word) {
		return;
	}
	if (Word->Left) {
		PrintWord(Word->Left);
	}
	printf("Word - %s\t%d\n",Word->Word,Word->Count);
	Link = Word->FirstLink;
	while (Link) {
		printf("\t%s\t%d\n",Link->MyNode->Title,Link->Count);
		Link = Link->NextWordLink;
	}
	if (Word->Right) {
		PrintWord(Word->Right);
	}
}
#endif

static int InCurly = 0;

static char *
Strip(char *buffer) {

	char *p,*p1,*ps;
	ps = buffer;
	while (isspace(*ps)) {
		++ps;
	}
	p = ps;
	p1 = ps;
	while (*p1) {
		if (InCurly) {
			while (*p1 && (*p1 != '}')) {
				++p1;
			}
			if (*p1) {
				++p1;
				InCurly = 0;
			}
		}
		else {
			if (('@' == *p1) && ('{' == p1[1])) {
				if ('"' == p1[2]) {
					++p1;
					++p1;
					++p1;
					while (*p1 && (*p1 != '"')) {
						*p++ = *p1++;
					}
					InCurly = 1;
				}
				else {
					InCurly = 1;
				}
			}
			else {
				*p++ = *p1++;
			}
		}
	}
	*p = 0;
	while (isspace(*ps)) {
		++ps;
	}
	return ps;
}

void
WriteFile(char *file,FILE *fp) {
	putc('F',fp);
	fputc(strlen(file),fp);	// note not putc
	fputs(file,fp);
}

static void
AddNode(struct MyNode *MyNode) {
	struct MyNode *Node1;
	if (!TopNode) {
		TopNode = MyNode;
		return;
	}
	Node1 = TopNode;
	while (1) {
		if (stricmp(Node1->Name,MyNode->Name) > 0) {
			if (!Node1->Left) {
				Node1->Left = MyNode;
				return;
			}
			else {
				Node1 = Node1->Left;
			}
		}
		else {
			if (!Node1->Right) {
				Node1->Right = MyNode;
				return;
			}
			else {
				Node1 = Node1->Right;
			}
		}
	}
}

static struct MyNode *
FindNode(struct MyNode *MyNode, int i) {
	struct MyNode *Node1;

	if (!MyNode) {
		return NULL;
	}
	if (MyNode->Title) {
		if (MyNode->Num == i) {
			return MyNode;
		}
	}
	if (MyNode->Left) {
		if (Node1 = FindNode(MyNode->Left,i)) {
			return Node1;
		}
	}
	if (MyNode->Right) {
		if (Node1 = FindNode(MyNode->Right,i)) {
			return Node1;
		}
	}
}

static void
FlagWords(struct Word *Word, ULONG max) {
	if (!Word) {
		return;
	}
	if (Word->Left) {
		FlagWords(Word->Left,max);
	}
	if (!((0 == max) || !(Word->Count > max))) {
		Word->Count = 0;	// Flag word as more than max
	}
	if (Word->Right) {
		FlagWords(Word->Right,max);
	}
}

static void
CountWords(struct Word *Word, ULONG *WordCount) {
	if (!Word) {
		return;
	}
	if (Word->Left) {
		CountWords(Word->Left,WordCount);
	}
	if (Word->Count) {
		++(*WordCount);
	}
	if (Word->Right) {
		CountWords(Word->Right,WordCount);
	}
}	

static void
StoreArray(struct Word *Word, struct Word ***Wordp) {
	if (!Word) {
		return;
	}
	if (Word->Left) {
		StoreArray(Word->Left,Wordp);
	}
	if (Word->Count) {
		**Wordp = Word;
		++(*Wordp);
	}
	if (Word->Right) {
		StoreArray(Word->Right,Wordp);
	}
}

static int
CompareWords(struct Word **wa, struct Word **wb) {
	char *a,*b,*a1,*b1;
	int la,lb;
	a = (*wa)->Word;
	b = (*wb)->Word;
	la = strlen(a);
	lb = strlen(b);
	a1 = a + la;
	b1 = b + lb;
	do {
		--a1;
		--b1;
		if (*a1 < *b1) {
			return -1;
		}
		if (*a1 > *b1) {
			return 1;
		}
	} while ((a1 > a) && (b1 > b));
	if (la < lb) {
		return 1;	// Longest first
	}
	return -1; // can never be =
}

char *GetTitle(char *p) {
	char *p1;
	char *p2;
	p1 = p;
	p2 = p1+strlen(p1)-1;
	*p2-- = 0;
	while (*p1 && isspace(*p1)) {
		++p1;
	}
	while ((p2 > p1) & isspace(*p2)) {
		*p2-- = 0;
	}
	if ('"' == *p1) {
		++p1;
		while (*p1 && isspace(*p1)) {
			++p1;
		}
		if ('"' == *p2) {
			*p2-- = 0;
			while ((p2 > p1) && isspace(*p2)) {
				*p2-- = 0;
			}
		}
	}
	if (*p1) {
		return strdup(p1);
	}
	else {
		return NULL;
	}
}

#define TITLE	1
#define NODE	2
#define NODE2	3
#define GUESS	4

int GuessHow(char *file) {
	FILE *in;
	char buffer[257];
	char *Node22="";
	char *p,*p1,*p2,*p3;
	int i=0;
	int how=0;
	if (in=fopen(file,"r")) {
		p = fgets(buffer,256,in);
		while (p && !how && strnicmp(p,"@node ",6)) {
			p1 = p;
			p2 = p+strlen(p)-1;
			*p2-- = 0;
			while ((p2 > p1+8) && !how) {
				if (!strnicmp(p1,"makeinfo",8)) {
					how = TITLE;
				}
				++p1;
			}
			p = fgets(buffer,256,in);
		}
		while (p && (i<20) && !how) {
			if (!strnicmp(p,"@node ",6)) {
				++i;
				p1 = &(buffer[6]);
				while ((*p1) && isspace(*p1)) {
					++p1;
				}
				if (*p1) {
					if ('"' == *p1) {
						++p1;
					}
					p2 = p1;
					while ((*p2) && !isspace(*p2)) {
						++p2;
					}
					--p2;
					if ('"' != *p2) {
						++p2;
					}
					if (*p2) {
						*p2 = 0;
						++p2;
					}
					while ((*p2) && isspace(*p2)) {
						++p2;
					}
					if (*p2) {
						if ('"' == *p2) {
							++p2;
						}
						p3 = p2;
						while (*p2) {
							++p2;
						}
						--p2;
						if ('\n' == *p2) {
							*p2 = 0;
							--p2;
						}
						if ('"' == *p2) {
							*p2 = 0;
						}
						if (1 == i) {
						}
						else if (2 == i) {
							Node22 = Mystrdup(p3);
						}
						else if (3 == i) {
							if (!stricmp(p3,Node22)) {
								how = NODE;
							}
						}
						else {
							while (!how && *p3) {
								if (isspace(*p3)) {
									how = NODE2;
								}
								++p3;
							}
						}
					}
				}
			}
			p = fgets(buffer,256,in);
		}
		fclose(in);
		if (!how) {
			return NODE;
		}
		return how;
	}
	else {
		printf(GetMessage(MSG_OPEN),file);
		return 0;
	}
}

int FileNo=0;
int merged=0;
FILE *out=NULL;

static BOOL
ICheckTitle(struct MyNode *MyNode,char *p) {
	if (MyNode->Left) {
		if (!ICheckTitle(MyNode->Left,p)) {
			return FALSE;
		}
	}
	if ((MyNode->Title) &&
		 (MyNode->seq == FileNo+merged) &&
		 (!stricmp(MyNode->Title,p))) { 
		return FALSE;
	}
	if (MyNode->Right) {
		if (!ICheckTitle(MyNode->Right,p)) {
			return FALSE;
		}
	}
	return TRUE;
}

static BOOL
CheckTitle(char *p) {
	if (!TopNode) {
		return TRUE;
	}
	return ICheckTitle(TopNode,p);
}

int
AddFile(char *file,int how) {
	FILE *in;
	char *p,*p1,*p2,*p3;
	char buffer[257];
	struct MyNode *MyNode;
	char *title;
	char *newtitle;
	if (GUESS == how) {
		how = GuessHow(file);
	}
	if (!how) {
		return 10;
	}
	if (in=fopen(file,"r")) {
		printf("%s ",file);
		if (NODE==how) {
			printf("NODE\n");
		}
		else if (NODE2==how) {
			printf("NODE2\n");
		}
		else {
			printf("TITLE\n");
		}
		WriteFile(file,out);
		p = fgets(buffer,256,in);
		while (p) {
			while (p && strnicmp(p,"@node ",6)) {
				p = fgets(buffer,256,in);
			}
			if (p) {
				Strip(buffer);
				MyNode = Mycalloc(sizeof(struct MyNode));
				MyNode->seq = FileNo+merged;
				p1 = &(buffer[6]);
				while ((*p1) && isspace(*p1)) {
					++p1;
				}
				if (*p1) {
					if ('"' == *p1) {
						++p1;
						p2 = p1;
						while (*p2 && ('"' != *p2)) {
							++p2;
						}
					}
					else {
						p2 = p1;
						while ((*p2) && !isspace(*p2)) {
							++p2;
						}
					}
					if (*p2) {
						*p2 = 0;
						++p2;
					}
					while ((*p2) && isspace(*p2)) {
						++p2;
					}
					if (*p2) {
						if ('"' == *p2) {
							++p2;
						}
						p3 = p2;
						while (*p2) {
							++p2;
						}
						--p2;
						if ('\n' == *p2) {
							*p2 = 0;
							--p2;
						}
						if ('"' == *p2) {
							*p2 = 0;
						}
//						printf("MyNode - %s",p1);
						MyNode->Name = Mystrdup(p1);
						MyNode->Name2 = Mystrdup(p3);
					}
					else {
//						printf("MyNode - %s",p1);
						MyNode->Name = Mystrdup(p1);
						MyNode->Name2 = MyNode->Name;
					}
					if (stricmp(MyNode->Name,"index")) {
						p = fgets(buffer,256,in);
						title = NULL;
						while (p && (((p = Strip(buffer)),(!*p) || ('@' == *p)) ||
										 isspace(*p) || ('\n' == *p))) {
							if (!strnicmp(p,"@title ",7)) {
								title = GetTitle(p+7);
							}
							p = fgets(buffer,256,in);
						}
						if (p) {
							p[strlen(p) - 1] = 0;
//							printf(" - %s\n",p);
							newtitle = NULL;
							if (title) {
								if (CheckTitle(title)) {
									newtitle = title;
								}
							}
							if (!newtitle) {
								if (TITLE == how) {
									if (CheckTitle(p)) {
										newtitle = Mystrdup(p);
									}
									else if (CheckTitle(MyNode->Name2)) {
										newtitle = MyNode->Name2;
									}
									else {
										newtitle = MyNode->Name;
									}
								}
								else if (NODE2 == how) {
									if (CheckTitle(MyNode->Name2)) {
										newtitle = MyNode->Name2;
									}
									else {
										newtitle = MyNode->Name;
									}
								}
								else {
									newtitle = MyNode->Name;
								}
							}
							MyNode->Title = newtitle;
							printf("   %s\n",MyNode->Title);
							AddNode(MyNode);
							while (p && strnicmp(p,"@endnode",8)) {
								AddWords(MyNode,p);
								if (p = fgets(buffer,256,in)) {
									p = Strip(buffer);
								}
							}
						}
					}
					else {
						free(MyNode);
						while (p && strnicmp(p,"@endnode",8)) {
							p = fgets(buffer,256,in);
						}
					}
				}
				p = fgets(buffer,256,in);
			}
		}
		fclose(in);
		++FileNo;
		return 0;
	}
	else {
		printf(GetMessage(MSG_OPEN),file);
		return 10;
	}
}

static struct Word **WordArray = 0;

static char Balance[32]="PHXDLT1BFJNRVZ3ACEGIKMOQSUWY024";
//                       1234567890123456789012345678901
//ABCDEFGHIJKLMNOPQRSTUVWXYZ01234"
//               X
//       X               X
//   X       X       X       X
// X   X   X   X   X   X   X   X
//X X X X X X X X X X X X X X X X
         
int
main(int argc, char **argv) {
	FILE *in;
	char *p,*p1,*p2;
	char buffer[257];
	struct MyNode *MyNode,*Node1;
	struct Word *Word=NULL;
	char bbuf[2];
	int resx=0;
	UWORD seq;
	char *file;
	ULONG WordCount = 0;
	ULONG StringLength;
	ULONG Offset;
	char *MergedWords;
	struct Word ** LocalWordArray;
	int l,ll;
	int c;
	int how;
	int i;
	if (!(LocaleBase = OpenLibrary("locale.library",38))) {
		printf("Error Opening locale.library(38)\n");
		return RETURN_FAIL;
	}
	if (!(rdargs = ReadArgs((char *)TEMPLATE, opts, NULL))) {
		PrintFault(IoErr(), NULL);
		CloseLibrary(LocaleBase);
		return 10;
	}
	Catalog = OpenCatalog(NULL,
  								"mp/makempindex.catalog",
  								TAG_END);
	Chain = CreatePool(MEMF_CLEAR,PUDDLE,THRESH);
	if (!Chain) {
		printf(GetMessage(MSG_POOL));
		FreeArgs(rdargs);
		CloseCatalog(Catalog);
		CloseLibrary(LocaleBase);
		exit(10);
	}
	// Try and balance trees
	bbuf[1]=0;
	for (i=0; i<31; ++i) {
		bbuf[0]=Balance[i];
		AddWord(bbuf);
		MyNode = Mycalloc(sizeof(struct MyNode));
		MyNode->Name = bbuf;
		AddNode(MyNode);
		AddIgnore(bbuf,FALSE);
	}
	if (opts[OPT_TITLE]) {
		how = TITLE;
	}
	else if (opts[OPT_NODE2]) {
		how = NODE2;
	}
	else if (opts[OPT_NODE]) {
		how = NODE;
	}
	else {
		how = GUESS;
	}
	if (opts[OPT_IGNORETO]) {
		if (!(ignoreto = fopen((char *)opts[OPT_IGNORETO],"w"))) {
			printf(GetMessage(MSG_OPEN),(char*)(opts[OPT_IGNORETO]));
			resx=10;
		}
	}
	MaxNodes = opts[OPT_MAX]?*((ULONG *)opts[OPT_MAX]):0;
	if (out=fopen((char *)opts[OPT_TO],"w")) {
		if (opts[OPT_IGNORE]) {
			if (in = fopen((char *)(opts[OPT_IGNORE]),"r")) {
				p = fgets(buffer,256,in);
				while (p) {
					buffer[strlen(buffer)-1] = 0;
					AddIgnore(p,TRUE);
					p = fgets(buffer,256,in);
				}
				fclose(in);
			}
			else {
				printf(GetMessage(MSG_OPEN),(char*)(opts[OPT_IGNORE]));
				resx=10;
			}
		}
		if (opts[OPT_MERGE]) {
			if (in=fopen((char*)(opts[OPT_MERGE]),"r")) {
				c = getc(in);
				while (c != EOF) {
					while ((c !=EOF) && (c != 'M')) {
						if ('F' == c) {
							putc('F',out);
							c = getc(in);
							putc(c,out);
							fread(buffer,c,1,in);
							fwrite(buffer,c,1,out);
							++merged;
						}
						else {
							fread(&seq,2,1,in);
							c = getc(in);
							MyNode = Mycalloc(sizeof(struct MyNode));
							MyNode->Name = Mycalloc(c + 1);
							fread(MyNode->Name,c,1,in);
							MyNode->seq = seq;
							c = getc(in);
							MyNode->Title = Mycalloc(c + 1);
							fread(MyNode->Title,c,1,in);
							AddNode(MyNode);
						}
						c = getc(in);
					}
					NodeCount = 0;
					CountNodes(TopNode);
					fread(&StringLength,4,1,in);
					MergedWords = Mycalloc(StringLength);
					fread(MergedWords,StringLength,1,in);
					c = getc(in);
					while (c != EOF) {
						if ('W' == c) {
							fread(&Offset,4,1,in);
							Word = AddWord(MergedWords + Offset);
						}
						else {
							fread(&seq,2,1,in);
							Node1 = FindNode(TopNode,seq);
							LinkNodeWord(Node1,Word);
						}
						c = getc(in);
					}
				}
				fclose(in);
			}
			else {
				printf(GetMessage(MSG_OPEN),(char*)(opts[OPT_MERGE]));
				resx=10;
			}
		}
		if (opts[OPT_FILE]) {
			if (in=fopen((char *)opts[OPT_FILE],"r")) {
				p = fgets(buffer,256,in);
				while (p) {
					buffer[strlen(p)-1] = 0;
					if (AddFile(p,how)) {
						resx = 10;
					}
					p = fgets(buffer,256,in);
				}
				fclose(in);
			}
			else {
				printf(GetMessage(MSG_OPEN),(char*)(opts[OPT_FILE]));
				resx=10;
			}
		}
		for (i=0; opts[OPT_FROM] && ((char**)(opts[OPT_FROM]))[i]; ++i) {
			file = Mystrdup(((char**)(opts[OPT_FROM]))[i]);
			if (AddFile(file,how)) {
				resx = 10;
			}
		}
		NodeCount = 0;
		CountNodes(TopNode);
#ifdef MPINDEXPRINT
		if (opts[OPT_PRINT]) {
			PrintNode(TopNode);
			PrintWord(TopWord);
		}
#endif
//		WriteFiles((char **)opts[OPT_FROM],out);
		WriteNodes(TopNode,out);
		FlagWords(TopWord,opts[OPT_MAX]?*((ULONG *)opts[OPT_MAX]):0);
		CountWords(TopWord,&WordCount);
		WordArray = Mycalloc(sizeof(struct Word *) * WordCount);
		LocalWordArray = WordArray;
		StoreArray(TopWord,&LocalWordArray);
		qsort(WordArray, WordCount, sizeof(struct Word *), CompareWords);
		p = WordArray[0]->Word;
		ll = strlen(p);
		StringLength = strlen(p) + 1;
		for (i=1; i<WordCount; ++i) {
			p1 = WordArray[i]->Word;
			l = strlen(p1);
			if (!(l < ll) || strcmp(p1,p+ll-l)) {
				StringLength += l + 1;
			}
			ll = l;
			p = p1;
		}
		MergedWords = Mycalloc(StringLength);
		p2 = MergedWords;
		p = WordArray[0]->Word;
		ll = strlen(p);
		strcpy(p2,p);
		p2 += ll + 1;
		for (i=1; i<WordCount; ++i) {
			p1 = WordArray[i]->Word;
			l = strlen(p1);
			if (!(l < ll) || strcmp(p1,p+ll-l)) {
				strcpy(p2,p1);
				WordArray[i]->Offset = p2 - MergedWords;
				p2 += l + 1;
			}
			else {
				WordArray[i]->Offset = p2 - MergedWords - l - 1;
			}
			ll = l;
			p = p1;
		}
		putc('M',out);
		fwrite(&StringLength,4,1,out);
		fwrite(MergedWords,StringLength,1,out);
		WriteWords(TopWord,out);
		fclose(out);
	}
	else {
		printf(GetMessage(MSG_OPEN),(char *)opts[OPT_TO]);
		resx = 10;
	}
	if (ignoreto) {
		fclose(ignoreto);
		ignoreto = NULL;
	}
	FreeArgs(rdargs);
	DeletePool(Chain);
	CloseCatalog(Catalog);
	CloseLibrary(LocaleBase);
	return resx;
}
