/* Convert all autodoc files to hypertext files */

#include "global.h"
#include "misc.h"
#include "readdir.h"
#include "incfile.h"
#include "adfile.h"
#include "shortad.h"
#include "convertad.h"

/***********************************************/

static BOOL ConvertContents(void)
{
	BOOL FirstLine;
	struct AutodocNode *AutodocNode;
	char *Temp;

	do
	{
		if (!ReadLine(FALSE, FALSE))
			return (FALSE);
	}
	while (stricmp(Buffer, "TABLE OF CONTENTS"));
	FirstLine = TRUE;
	do
	{
		if (!ReadLine(FALSE, FALSE))
			return (FALSE);
		if (Buffer[0] != '\x0c' && Buffer[0])
		{
			if (FirstLine && !WriteSomething("@NODE Main \x22"))
				return (FALSE);
			for (Temp = Buffer; *Temp && *Temp != '/'; Temp++)
			{
				if (FirstLine && !WriteSomething("%lc", *Temp))
					return (FALSE);
			}
			if (FirstLine && !WriteSomething("\x22\n"))
				return (FALSE);
			if (!*Temp)
			{
				WriteError("Error: Missing '/' in file %s, line %ld\n"
						   "       Operation aborted.\n", CurrentSource, CurrentLine);
				return (FALSE);
			}
			FirstLine = FALSE;
			if (!(AutodocNode = (struct AutodocNode *) SearchNameCase((struct AnyNode **) AutodocArray, Buffer)))
			{
				WriteError("Error: File %s changed.\n"
						   "       Operation aborted.\n", CurrentSource);
				return (FALSE);
			}
			Temp = AutodocNode->Node.Name;
			if (Arguments.ShortTOC)
			{
				if (Temp = FindSlash(Temp))
				{
					Temp++;
				}
				else
				{
					Temp = AutodocNode->Node.Name;
				}
			}
			if (!WriteSomething("    @{\x22 %s", Temp))
				return (FALSE);
			if (AutodocNode->Type == 1 && !WriteSomething("()"))
				return (FALSE);
			if (!WriteSomething(" \x22 LINK \x22%s\x22}\n", FindSlash(AutodocNode->Node.Name) + 1))
				return (FALSE);
		}
	}
	while (Buffer[0] != '\x0c');
	if (!WriteSomething("@ENDNODE\n\n"))
		return (FALSE);
	return (TRUE);
}

/***********************************************/

static BOOL ConvertNode(void)
{
	int Index;
	/* int OldBufferIndex; */
	struct AnyNode *AnyNode;
	char *Temp;
	char *Temp2;
	int Periods;
	int Slashes;
	long Character;
	int UppercaseLetters;
	int Underscores;
	BOOL StructMode;
	int SeeAlsoMode;

	StructMode = FALSE;
	SeeAlsoMode = 0;
	Temp = FindSlash(Buffer);
	if (!*Temp)
	{
		WriteError("Error: Missing '/' in file %s, line %ld\n"
				   "       Operation aborted.", CurrentSource, CurrentLine);
		return (FALSE);
	}
	*Temp = '\0';
	stpcpy(CurrentUnit, Buffer);
	*Temp = '/';
	Temp2 = Temp;
	do
		Temp++;
	while (*Temp && *Temp != ' ' && *Temp != '\t' && *Temp != '/');
	if (*Temp == '/')
	{
		stpcpy(Temp2, Temp);
	}
	else
	{
		*Temp = '\0';
	}
	if (!(AnyNode = SearchNameCase((struct AnyNode **) AutodocArray, Buffer)))
	{
		if (!(AnyNode = SearchNameNoCase((struct AnyNode **) AutodocArray, Buffer)))
		{
			WriteError("Error: Node %s not present in table of contents.\n"
					   "       File: %s\n"
					   "       Operation aborted.\n", Buffer, CurrentSource);
			return (FALSE);
		}
		WriteError("Warning: Node %s not present in table of contents.\n"
				   "         File %s\n"
				   "         Assuming %s instead.\n", Buffer, CurrentSource, AnyNode->Name);
	}
	CurrentAutodocNode = (struct AutodocNode *) AnyNode;
	if (CurrentAutodocNode->Type == 1)
	{
		if (!WriteSomething("@NODE \x22%s\x22 \x22%s()\x22\n", FindSlash(CurrentAutodocNode->Node.Name) + 1, CurrentAutodocNode->Node.Name))
			return (FALSE);
	}
	else
	{
		if (!WriteSomething("@NODE \x22%s\x22 \x22%s\x22\n", FindSlash(CurrentAutodocNode->Node.Name) + 1, CurrentAutodocNode->Node.Name))
			return (FALSE);
	}
	BufferIndex = 0;
	Buffer[0] = '\0';
	while (TRUE)
	{
		if (Break())
			return (FALSE);
		/* OldBufferIndex=BufferIndex; */
		Character = fgetc2();
		WordBuffer[0] = '\0';
		if ((Character >= 'a' && Character <= 'z') || (Character >= 'A' && Character <= 'Z'))
		{
			Underscores = 0;
			UppercaseLetters = 0;
			Index = 0;
			Periods = 0;
			Slashes = 0;
			while ((Character >= 'a' && Character <= 'z') ||
				   (Character >= 'A' && Character <= 'Z') ||
				   (Character >= '0' && Character <= '9') ||
				   (Character == '_') ||
				   (Character == '/') ||
				   (Character == '.'))
			{
				WordBuffer[Index++] = Character;
				if (Index == MAX_LEN)
				{
					WriteError("Error, line %ld: line is too long.\n"
							   "       Operation aborted.\n", CurrentLine);
					return (FALSE);
				}
				if (Character == '.')
				{
					Periods++;
				}
				else if (Character == '/')
				{
					Slashes++;
				}
				else if (Character == '_')
				{
					Underscores++;
				}
				else if ((Character >= 'A' && Character <= 'Z') || (Character >= '0' && Character <= '9'))
				{
					UppercaseLetters++;
				}
				Character = fgetc2();
			}
			if (WordBuffer[Index - 1] == '.')
			{
				Index--;
				BufferIndex--;
				Character = '.';
			}
			if (Character == '(')
			{
				StructMode = FALSE;
			}
			WordBuffer[Index] = '\0';
			if (StructMode)
			{
				if (AnyNode = (struct AnyNode *) SearchNameCase((struct AnyNode **) StructArray, WordBuffer))
			  LinkStructure:{
					if (!WriteSomething("@{\x22%s\x22 LINK \x22%s/MAIN\x22 %ld}", WordBuffer, ((struct StructNode *) AnyNode)->File, ((struct StructNode *) AnyNode)->Line))
						return (FALSE);
					IncludeLinks++;
					WordBuffer[0] = '\0';
					Index = 0;
				}
				StructMode = FALSE;
			}
			if (Index >= 2)
			{
				if (!strcmp(WordBuffer, "struct"))
				{
					StructMode = TRUE;
					if (SeeAlsoMode == 1)
						SeeAlsoMode = 0;
				}
				else if (!stricmp(WordBuffer + Index - 2, ".h"))
				{
					if (SeeAlsoMode == 1)
						SeeAlsoMode = 0;
					if (AnyNode = (struct AnyNode *) SearchNameNoCase((struct AnyNode **) IncludeFileArray, WordBuffer))
					{
						if (!WriteSomething("@{\x22%s\x22 LINK \x22%s/MAIN\x22 0}", WordBuffer, ((struct FileNode *) AnyNode)->Node.Name))
							return (FALSE);
						IncludeLinks++;
						WordBuffer[0] = '\0';
					}
				}
				else if (Periods == 1 && Slashes == 1)
				{
					if (SeeAlsoMode == 1)
						SeeAlsoMode = 0;
					if (AnyNode = SearchNameCase((struct AnyNode **) AutodocArray, WordBuffer))
				  LinkAutodoc:{
						if (CurrentAutodocNode != (struct AutodocNode *) AnyNode)
						{
							if (!(Temp = FindSlash(((struct AutodocNode *) AnyNode)->Node.Name)))
							{
								WriteError("INTERNAL ERROR #1\n");
								return (FALSE);
							}
							if (Character == '(')
							{
								if (fgetc2() == ')')
								{
									WordBuffer[Index++] = '(';
									WordBuffer[Index++] = ')';
									WordBuffer[Index] = '\0';
									Character = -2;
								}
								else
								{
									BufferIndex--;
								}
							}
							if (!strcmp(HypertextFilename, ((struct AutodocNode *) AnyNode)->File))
							{
								if (!WriteSomething("@{\x22%s\x22 LINK \x22%s\x22 0}", WordBuffer, Temp + 1))
									return (FALSE);
								InternalLinks++;
								WordBuffer[0] = '\0';
							}
							else
							{
								if (!WriteSomething("@{\x22%s\x22 LINK \x22%s%s\x22 0}", WordBuffer, ((struct AutodocNode *) AnyNode)->File, Temp))
									return (FALSE);
								ExternalLinks++;
								WordBuffer[0] = '\0';
							}
						}
					}
					else
					{
						Temp = WordBuffer + strlen(WordBuffer);
						stpcpy(Temp, "A");
						if (AnyNode = SearchNameCase((struct AnyNode **) AutodocArray, WordBuffer))
						{
							*Temp = '\0';
							goto LinkAutodoc;
						}
						stpcpy(Temp, "Tags");
						if (AnyNode = SearchNameCase((struct AnyNode **) AutodocArray, WordBuffer))
						{
							*Temp = '\0';
							goto LinkAutodoc;
						}
						stpcpy(Temp, "TagList");
						if (AnyNode = SearchNameCase((struct AnyNode **) AutodocArray, WordBuffer))
						{
							*Temp = '\0';
							goto LinkAutodoc;
						}
						*Temp = '\0';
					}
				}
				else if (!strcmp(WordBuffer, "SEE") && !SeeAlsoMode)
				{
					SeeAlsoMode = 1;
				}
				else if (SeeAlsoMode == 1)
				{
					if (!strcmp(WordBuffer, "ALSO"))
					{
						SeeAlsoMode = 2;
					}
					else
					{
						SeeAlsoMode = 0;
					}
				}
				else if (Character == '(' || UppercaseLetters + Underscores > 1)
				{
					if (AnyNode = (struct AnyNode *) SearchShortAutodoc(WordBuffer))
					{
						goto LinkAutodoc;
					}
					if (AnyNode = (struct AnyNode *) SearchNameCase((struct AnyNode **) StructArray, WordBuffer))
					{
						goto LinkStructure;
					}
					if (AnyNode = (struct AnyNode *) SearchNameCase((struct AnyNode **) TypedefArray, WordBuffer))
					{
						goto LinkStructure;
					}
					Temp = WordBuffer + strlen(WordBuffer);
					stpcpy(Temp, "A");
					if (AnyNode = (struct AnyNode *) SearchShortAutodoc(WordBuffer))
					{
						*Temp = '\0';
						goto LinkAutodoc;
					}
					stpcpy(Temp, "Tags");
					if (AnyNode = (struct AnyNode *) SearchShortAutodoc(WordBuffer))
					{
						*Temp = '\0';
						goto LinkAutodoc;
					}
					stpcpy(Temp, "TagList");
					if (AnyNode = (struct AnyNode *) SearchShortAutodoc(WordBuffer))
					{
						*Temp = '\0';
						goto LinkAutodoc;
					}
					*Temp = '\0';
				}
				else if (SeeAlsoMode == 2)
				{
					if ((AnyNode = (struct AnyNode *) SearchShortAutodoc(WordBuffer)) && AnyNode != (struct AnyNode *) CurrentAutodocNode)
					{
						goto LinkAutodoc;
					}
				}
			}
		}
		{
			/* Recognize the titles */
			int counter;

			const static char *typelistboth[] =
			{
				"ALSO",
				"BUGS",
				"EXAMPLE",
				"EXCEPTIONS",
				"FUNCTION",
				"FUNCTIONS",
				"HOST",
				"INPUT",
				"INPUTS",
				"INTERFACE",
				"IO",
				"NAME",
				"NAMES",
				"NOTE",
				"NOTES",
				"OUTPUTS",
				"OVERVIEW",
				"PURPOSE",
				"REQUEST",
				"RESULT",
				"RESULTS",
				"RETURNS",
				"SEE",
				"SYNOPSIS",
				"TAGS",
				"TIMER",
				"WARNING"
			};

			/* Left and right bold */
			for (counter = 0; counter < 27; counter++)
				if (!strcmp(WordBuffer, typelistboth[counter]))
				{
					stpcpy(WordBuffertemp, WordBuffer);
					sprintf(WordBuffer, "@{b}%s@{ub}", WordBuffertemp);
				}
		}

		if (WordBuffer[0] && !WriteSomething("%s", WordBuffer))
			return (FALSE);
		switch (Character)
		{
			case -1:
				if (IoErr())
				{
					return (FALSE);
				}
			case '\x0c':
				return (WriteSomething("@ENDNODE\n\n"));

			case '\n':
				for (Index = 0; Index < BufferIndex - 1; Index++)
				{
					if (Buffer[Index] != ' ' && Buffer[Index] != '\t')
					{
						goto HandleSpace;
					}
				}
				SeeAlsoMode = 0;
				goto HandleSpace;

			default:
				StructMode = FALSE;
				if (SeeAlsoMode == 1)
					SeeAlsoMode = 0;
			HandleSpace: case ' ':
			case '\t':
				if (Character != -2 && !WriteSomething("%lc", Character))
					return (FALSE);
				break;
		}
	}
}

/***********************************************/

static BOOL ConvertAutodoc(void)
{
	char *AutodocName;
	long AutodocNameLen;

	CurrentLine = 0;
	AutodocNameLen = 500;
	while (TRUE)
	{
		if (AutodocName = AllocVec(AutodocNameLen, 0))
		{
			if (NameFromFH(CurrentFile, AutodocName, AutodocNameLen))
			{
				break;
			}
			FreeVec(AutodocName);
			if (IoErr() == ERROR_LINE_TOO_LONG)
			{
				AutodocNameLen <<= 1;
			}
			else
			{
				PrintFault(IoErr(), CurrentSource);
				return (FALSE);
			}
		}
		else
		{
			PrintFault(ERROR_NO_FREE_STORE, NULL);
			return (FALSE);
		}
	}
	AutodocNameLen = WriteSomething("@DATABASE \"%s\"\n"
									"@INDEX \"Autodoc.guide/Main\"\n"
									"@REMARK created by ADtoHT " VERSION " © 1993/94 by Christian Sieber/Dirk Nehring\n\n", HypertextFilename);
	FreeVec(AutodocName);
	if (AutodocNameLen)
	{
		if (!ConvertContents())
		{
			return (FALSE);
		}
		ExternalLinks = 0;
		IncludeLinks = 0;
		InternalLinks = 0;
		while (TRUE)
		{
			do
			{
				if (!ReadLine(TRUE, FALSE))
				{
					if (IoErr())
					{
						return (FALSE);
					}
					else
					{
						printf("         %ld links were created.\n"
							   "            %ld links within the database\n"
							   "            %ld links to other databases\n"
							   "            %ld links to include files\n", InternalLinks + ExternalLinks + IncludeLinks, InternalLinks, ExternalLinks, IncludeLinks);
						return (TRUE);
					}
				}
				if (Buffer[0] == '\x0c')
				{
					WriteError("Error: Unexpected FormFeed in file %s\n"
							   "       Operation aborted.\n", CurrentSource);
					return (FALSE);
				}
			}
			while (!Buffer[0]);
			if (!ConvertNode())
				return (FALSE);
		}
	}
	else
	{
		return (FALSE);
	}
}

/***********************************************/

BOOL ConvertAutodocs(void)
{
	BPTR OldCurrentDir;
	struct FileNode *NextNode;
	int Length;
	BOOL Success;

	Success = TRUE;
	while (AutodocFileList && Success)
	{
		CurrentSource = AutodocFileList->Node.Name;
		Length = strlen(CurrentSource) - 4;
		if (HypertextFilename = AllocVec(Length + strlen(Arguments.Extension) + 1, 0))
		{
			memcpy(HypertextFilename, CurrentSource, Length);
			stpcpy(HypertextFilename + Length, Arguments.Extension);
			printf("      Converting %s to %s\n", CurrentSource, HypertextFilename);
			OldCurrentDir = CurrentDir(HypertextDir);
			if (HypertextFile = CreateFile(HypertextFilename))
			{
				CurrentDir(AutodocDir);
				if (CurrentFile = Open(CurrentSource, MODE_OLDFILE))
				{
					Success = ConvertAutodoc();
					Close(CurrentFile);
				}
				else
				{
					PrintFault(IoErr(), CurrentSource);
					Success = FALSE;
				}
				Close(HypertextFile);
			}
			else
			{
				PrintFault(IoErr(), HypertextFilename);
				Success = FALSE;
			}
			CurrentDir(OldCurrentDir);
			FreeVec(HypertextFilename);
			NextNode = (struct FileNode *) (AutodocFileList->Node.Next);
			FreeVec(AutodocFileList);
			AutodocFileList = NextNode;
		}
		else
		{
			PrintFault(ERROR_NO_FREE_STORE, NULL);
			Success = FALSE;
		}
	}
	return (Success);
}
