/*
**	termBuffer.c
**
**	Auxilary routines for text buffer/capture management.
**
**	Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Search string window gadgets. */

enum	{	GAD_STRING,GAD_FORWARD,GAD_OK,GAD_CANCEL };

	/* Maximum size of an allocated line string. */

#define STRING_SIZE	(1 + 255 + 1)

	/* How many strings to include in a single puddle. */

#define STRING_COUNT	10

	/* The number of lines the buffer will grow. */

#define BUFFER_GROW	100

	/* Memory allocation routines. */

STATIC STRPTR		(* __regargs AllocString)(STRPTR,LONG);
STATIC VOID		(* __regargs FreeString)(STRPTR);

	/* Memory pool header (Kickstart 3.0 required). */

STATIC APTR		BufferPoolHeader;

	/* CreateAllGadgets():
	 *
	 *	Create the gadgets for the search string window.
	 */

STATIC struct Gadget *
CreateAllGadgets(BYTE Forward,WORD MaxChars,STRPTR String,STRPTR Prompt,struct Gadget **GadgetArray,struct Gadget **GadgetList,APTR VisualInfo,struct Screen *Screen)
{
	struct Gadget		*Gadget;
	struct NewGadget	 NewGadget;

	if(MaxChars < 1)
		MaxChars = 255;

	memset(&NewGadget,0,sizeof(struct NewGadget));

	SZ_SizeSetup(Screen,&UserFont,TRUE);

	if(Gadget = CreateContext(GadgetList))
	{
		WORD Width = SZ_TextWidth(Prompt),Counter = 0;

		if(Width < SZ_Width(STRING_KIND,NULL,60,NULL))
			Width = SZ_Width(STRING_KIND,NULL,60,NULL);

		SZ_SetWidth(Width);

		NewGadget . ng_GadgetText	= Prompt;
		NewGadget . ng_TextAttr		= &UserFont;
		NewGadget . ng_VisualInfo	= VisualInfo;
		NewGadget . ng_GadgetID		= Counter;
		NewGadget . ng_Flags		= PLACETEXT_ABOVE;

		GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget,
			SZ_Adjust,	TRUE,
			SZ_AutoWidth,	TRUE,

			GTST_MaxChars,	MaxChars,
			GTST_String,	String,
			GA_TabCycle,	FALSE,
		TAG_DONE);

		NewGadget . ng_GadgetText	= LocaleString(MSG_TERMBUFFER_SEARCH_FORWARD_TXT);
		NewGadget . ng_GadgetID		= Counter;
		NewGadget . ng_Flags		= PLACETEXT_RIGHT;

		GadgetArray[Counter++] = Gadget = CreateGadget(CHECKBOX_KIND,Gadget,&NewGadget,
			SZ_Adjust,	TRUE,
			SZ_AutoWidth,	TRUE,

			GTCB_Checked,	Forward,
		TAG_DONE);

		SZ_UpdateMaxWidth(BUTTON_KIND,LocaleString(MSG_TERMXPR_OKAY_GAD),0,NULL);
		SZ_UpdateMaxWidth(BUTTON_KIND,LocaleString(MSG_GLOBAL_CANCEL_GAD),0,NULL);

		SZ_SetWidth(SZ_ResetMaxWidth());

		NewGadget . ng_GadgetText	= LocaleString(MSG_TERMXPR_OKAY_GAD);
		NewGadget . ng_GadgetID		= Counter;
		NewGadget . ng_Flags		= 0;

		GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
			SZ_Adjust,	TRUE,
			SZ_AutoWidth,	TRUE,
			SZ_AlignExtra,	TRUE,
			SZ_AlignLeft,	TRUE,
			SZ_AlignBottom,	TRUE,
		TAG_DONE);

		NewGadget . ng_GadgetText	= LocaleString(MSG_GLOBAL_CANCEL_GAD);
		NewGadget . ng_GadgetID		= Counter;

		GadgetArray[Counter] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget,
			SZ_Adjust,	TRUE,
			SZ_AutoWidth,	TRUE,
			SZ_AlignRight,	TRUE,
		TAG_DONE);
	}

	return(Gadget);
}

	/* OldAllocString(STRPTR String,WORD Len):
	 *
	 +	Allocate space for a string, old flavour.
	 */

STATIC STRPTR __regargs
OldAllocString(STRPTR String,LONG Len)
{
	STRPTR Mem;

	if(Len > 255)
		Len = 255;

	if(Mem = (STRPTR)AllocMem(1 + Len + 1,MEMF_ANY | MEMF_PUBLIC))
	{
		*Mem++ = Len;

		memcpy(Mem,String,Len);

		Mem[Len] = 0;

		return((STRPTR)Mem);
	}
	else
		return(NULL);
}

	/* OldFreeString(STRPTR String):
	 *
	 *	Free the space occupied by a string, old flavour.
	 */

STATIC VOID __regargs
OldFreeString(STRPTR String)
{
	FreeMem(&String[-1],1 + String[-1] + 1);
}

	/* NewAllocString(STRPTR String,WORD Len):
	 *
	 +	Allocate space for a string, new pooled version.
	 */

STATIC STRPTR __regargs
NewAllocString(STRPTR String,LONG Len)
{
	STRPTR Mem;

	if(Len > 255)
		Len = 255;

	if(Mem = (STRPTR)AllocPooled(BufferPoolHeader,1 + Len + 1))
	{
		*Mem++ = Len;

		memcpy(Mem,String,Len);

		Mem[Len] = 0;

		return((STRPTR)Mem);
	}
	else
		return(NULL);
}

	/* NewFreeString(STRPTR String):
	 *
	 *	Free the space occupied by a string, new pooled version.
	 */

STATIC VOID __regargs
NewFreeString(STRPTR String)
{
	FreePooled(BufferPoolHeader,&String[-1],1 + String[-1] + 1);
}

	/* AddLine(STRPTR Line,LONG Size):
	 *
	 *	Add a line to the display buffer.
	 */

STATIC VOID __regargs
AddLine(register STRPTR Line,register LONG Size)
{
		/* Are we still to update the buffer contents? */

	if(!BufferClosed)
	{
			/* Remove trailing spaces. */
/*
		while(Size > 0 && Line[Size - 1] == ' ')
			Size--;
*/
			/* Is the buffer array initialized? */

		if(BufferLines)
		{
			ULONG Signals = 0;

				/* Pick up the global access semaphore
				 * (two tasks are sharing the data).
				 */

			ObtainSemaphore(BufferSemaphore);

				/* Check for limit. */

			if(Config -> CaptureConfig -> MaxBufferSize && BufferSpace >= Config -> CaptureConfig -> MaxBufferSize)
			{
				register LONG i;

				BufferSpace -= BufferLines[0][-1];

				(*FreeString)(BufferLines[0]);

				for(i = 1 ; i < MaxLines ; i++)
					BufferLines[i - 1] = BufferLines[i];

				Lines--;

					/* Tell the buffer task to
					 * refresh the display.
					 */

				Signals = SIG_MOVEUP;
			}
			else
			{
					/* We've reached the last line in the buffer. */

				if(Lines == MaxLines)
				{
					STRPTR *MoreBuffer;

						/* Allocate space for some more lines. */

					if(MoreBuffer = (STRPTR *)AllocVec((MaxLines + BUFFER_GROW) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
					{
						register LONG i;

						BufferChanged = TRUE;

							/* Copy the old lines to the new
							 * buffer.
							 */

						for(i = 0 ; i < Lines ; i++)
							MoreBuffer[i] = BufferLines[i];

							/* Free the old lines. */

						FreeVec(BufferLines);

							/* Set the new buffer. */

						MaxLines += BUFFER_GROW;

						BufferLines = MoreBuffer;
					}
					else
					{
						BufferChanged = TRUE;

							/* We couldn't get enough memory
							 * to extend the number of lines
							 * in the buffer, so we'll have
							 * to wrap the contents of the
							 * buffer around.
							 */

						if(Lines)
						{
							register LONG i;

							BufferSpace -= BufferLines[0][-1];

							(*FreeString)(BufferLines[0]);

							for(i = 1 ; i < MaxLines ; i++)
								BufferLines[i - 1] = BufferLines[i];

							Lines--;

								/* Tell the buffer task to
								 * refresh the display.
								 */

							Signals = SIG_MOVEUP;
						}
					}
				}
			}

				/* Allocate a new line and copy the buffer contents
				 * into it.
				 */

			if(BufferLines[Lines] = (*AllocString)(Line,Size))
			{
				BufferChanged = TRUE;

				Lines++;

				BufferSpace += Size;
			}

			ReleaseSemaphore(BufferSemaphore);

				/* Tell the buffer task to update the display. */

			if(!Signals)
			{
				Signals = SIG_UPDATE;

				UpdateReview(FALSE);
			}
			else
				UpdateReview(TRUE);

			if(BufferProcess && Signals)
			{
				Forbid();

				ClrSignal(SIG_HANDSHAKE);

				Signal(BufferProcess,Signals);

				Wait(SIG_HANDSHAKE);

				Permit();
			}
		}
	}
}

	/* StoreBuffer(APTR Buffer,LONG Size):
	 *
	 *	Store data in the display buffer.
	 */

VOID __regargs
StoreBuffer(register STRPTR Buffer,register LONG Size)
{
	STATIC UBYTE	 LineBuffer[BUFFER_LINE_MAX + 1];
	STATIC LONG 	 BufferCount = 0;

	register UBYTE c;

	while(Size--)
	{
			/* Look which char we are to handle. */

		switch(c = *Buffer++)
		{
				/* Move the cursor one step back. */

			case BKS:

				if(BufferCount)
					BufferCount--;

				break;

				/* Move the cursor to the next tab
				 * stop.
				 */

			case TAB:

				if(((BufferCount + 8) & ~7) < LastColumn)
				{
					register LONG Delta = ((BufferCount + 8) & ~7) - BufferCount;

					memset(&LineBuffer[BufferCount],' ',Delta);

					BufferCount += Delta;
				}
				else
				{
					AddLine(LineBuffer,BufferCount);

					BufferCount = 0;
				}

				break;

				/* Terminate the current line. */

			case ENT:

				AddLine(LineBuffer,BufferCount);

				BufferCount = 0;

				break;

				/* Stuff the character into the buffer. */

			default:

				if(Config -> TerminalConfig -> FontMode == FONT_STANDARD)
				{
					if(IsPrintable[c])
						LineBuffer[BufferCount++] = c;
				}
				else
				{
					if(c)
						LineBuffer[BufferCount++] = c;
				}

				break;
		}

			/* The line is full, add it to the display buffer. */

		if(BufferCount >= LastColumn || BufferCount == Config -> CaptureConfig -> BufferWidth)
		{
			AddLine(LineBuffer,BufferCount);

			BufferCount = 0;
		}
	}
}

	/* DeleteBuffer():
	 *
	 *	Delete buffer resources.
	 */

VOID
DeleteBuffer()
{
	if(BufferLines)
	{
		if(!BufferPoolHeader)
		{
			LONG i;

			for(i = 0 ; i < Lines ; i++)
			{
				if(BufferLines[i])
					(*FreeString)(BufferLines[i]);
			}
		}

		FreeVec(BufferLines);

		BufferLines = NULL;
	}

	if(BufferPoolHeader)
	{
		DeletePool(BufferPoolHeader);

		BufferPoolHeader = NULL;
	}

	if(BufferSemaphore)
	{
		FreeVec(BufferSemaphore);

		BufferSemaphore = NULL;
	}
}

	/* CreateBuffer():
	 *
	 *	Allocate buffer resources.
	 */

BYTE
CreateBuffer()
{
	if(BufferLines = (STRPTR *)AllocVec(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
	{
		if(BufferSemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
		{
			InitSemaphore(BufferSemaphore);

				/* Create a memory pool header if possible. */

			if(Kick30)
			{
				if(BufferPoolHeader = CreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT))
				{
					AllocString	= NewAllocString;
					FreeString	= NewFreeString;

					return(TRUE);
				}
			}

			AllocString	= OldAllocString;
			FreeString	= OldFreeString;

			return(TRUE);
		}

		FreeVec(BufferLines);

		BufferLines = NULL;
	}

	return(FALSE);
}

	/* FreeBuffer():
	 *
	 *	Release the contents of the text buffer.
	 */

VOID
FreeBuffer()
{
		/* Free the contents of the display buffer. */

	if(BufferLines)
	{
		APTR NewPoolHeader;

			/* Simple, create another pool header if possible. */

		if(BufferPoolHeader)
			NewPoolHeader = CreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT);
		else
			NewPoolHeader = NULL;

			/* If a new pool header is available, free the old
			 * pool and replace it with the new pool, else
			 * do it again by hand.
			 */

		if(NewPoolHeader)
		{
			DeletePool(BufferPoolHeader);

			BufferPoolHeader = NewPoolHeader;
		}
		else
		{
			LONG i;

			for(i = 0 ; i < Lines ; i++)
			{
				if(BufferLines[i])
					(*FreeString)(BufferLines[i]);
			}
		}

		FreeVec(BufferLines);

		Lines = 0;

		MaxLines = BUFFER_GROW;

		BufferLines = (STRPTR *)AllocVec(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR);

		UpdateReview(TRUE);
	}

	BufferSpace = 0;

	BufferChanged = FALSE;
}

	/* DeleteSearchInfo(struct SearchInfo *Info):
	 *
	 *	Free buffer allocated by CreateSearchInfo().
	 */

VOID __regargs
DeleteSearchInfo(struct SearchInfo *Info)
{
	if(Info)
		FreeVec(Info);
}

	/* CreateSearchInfo(STRPTR Pattern):
	 *
	 *	Create auxilary data required by SearchTextBuffer().
	 */

struct SearchInfo * __regargs
CreateSearchInfo(STRPTR Pattern,BYTE Forward)
{
	struct SearchInfo *Info;

		/* Allocate the buffer. */

	if(Info = (struct SearchInfo *)AllocVec(sizeof(struct SearchInfo),MEMF_ANY | MEMF_PUBLIC))
	{
		WORD i;

			/* Determine pattern width. */

		Info -> PatternWidth = strlen(Pattern);

			/* Turn the pattern into upper case characters. */

		for(i = 0 ; i <= Info -> PatternWidth ; i++)
			Info -> Pattern[i] = ToUpper(Pattern[i]);

			/* Fill the entire range with the maximum pattern width. */

		for(i = 0 ; i < 256 ; i++)
			Info -> Distance[i] = Info -> PatternWidth;

			/* Fill in the matching distances. */

		if(Forward)
		{
			for(i = 0 ; i < Info -> PatternWidth - 1 ; i++)
				Info -> Distance[Info -> Pattern[i]] = Info -> PatternWidth - 1 - i;
		}
		else
		{
			for(i = Info -> PatternWidth - 1 ; i > 0 ; i--)
				Info -> Distance[Info -> Pattern[i]] = i;
		}

			/* Restart from scratch. */

		Info -> FoundY	= -1;
		Info -> Forward	= Forward;
	}

	return(Info);
}

	/* SearchTextBuffer():
	 *
	 *	String search function, based on the Boyer-Moore search
	 *	algorithm.
	 */

LONG __regargs
SearchTextBuffer(struct SearchInfo *Info)
{
	if(BufferLines)
	{
		UBYTE	*Distance,
			*Pattern;
		WORD	LineWidth,
			PatternWidth;
		STRPTR	Line;

		LONG	i;
		WORD	SearchPosition,PatternIndex,LineIndex,LastSearchPosition;

			/* Extract the relevant data. */

		Distance	= Info -> Distance;
		Pattern		= Info -> Pattern;
		PatternWidth	= Info -> PatternWidth;

			/* Which direction are we to search? */

		if(Info -> Forward)
		{
				/* Update the search positions. */

			if(Info -> FoundY == -1)
			{
				Info -> FoundX		= 0;
				Info -> FoundY		= 0;
				LastSearchPosition	= 0;
			}
			else
			{
					/* Proceed to the next line. */

				if(!(LastSearchPosition = Info -> Index))
					Info -> FoundY = (Info -> FoundY + 1) % Lines;
			}

				/* Run down the buffer. */

			for(i = Info -> FoundY ; i < Lines ; i++)
			{
				Line = BufferLines[i];

					/* Is there anything to search for? */

				if((LineWidth = Line[-1]) >= PatternWidth)
				{
						/* Where are we to start searching? */

					if(LastSearchPosition)
						SearchPosition = LastSearchPosition;
					else
						SearchPosition = PatternWidth;

					do
					{
							/* How many line characters
							 * match the pattern?
							 */

						PatternIndex	= PatternWidth - 1;
						LineIndex	= SearchPosition - 1;

						while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
						{
							LineIndex--;
							PatternIndex--;
						}

							/* Update the line search index
							 * for subsequent searches.
							 */

						SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];

							/* Found the pattern? */

						if(PatternIndex < 0)
						{
								/* Store the position. */

							Info -> FoundX	= LineIndex + 1;
							Info -> FoundY	= i;

								/* Remember column to start
								 * next search attempt at.
								 */

							if(SearchPosition <= LineWidth)
								Info -> Index = SearchPosition;
							else
								Info -> Index = 0;

							return(i);
						}
					}
					while(SearchPosition <= LineWidth);
				}

					/* Reset search column. */

				LastSearchPosition = 0;
			}
		}
		else
		{
				/* Update the search positions. */

			if(Info -> FoundY == -1)
			{
				Info -> FoundX		= 0;
				Info -> FoundY		= Lines - 1;
				LastSearchPosition	= 0;
			}
			else
			{
				if((LastSearchPosition = Info -> Index) < 1)
				{
					if(Info -> FoundY)
						Info -> FoundY--;
					else
						Info -> FoundY = Lines - 1;
				}
			}

				/* Run down the buffer. */

			for(i = Info -> FoundY ; i >= 0 ; i--)
			{
				Line = BufferLines[i];

					/* Is there anything to search for? */

				if((LineWidth = Line[-1]) >= PatternWidth)
				{
						/* Cast the magic spell of Boyer-Moore... */

					if(LastSearchPosition < 1)
						SearchPosition = LineWidth - (PatternWidth - 1);
					else
						SearchPosition = LastSearchPosition;

					do
					{
						PatternIndex = 0;
						LineIndex = SearchPosition - 1;

						while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
						{
							LineIndex++;
							PatternIndex++;
						}

						SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];

						if(PatternIndex == PatternWidth)
						{
							Info -> FoundX	= LineIndex - PatternWidth;
							Info -> FoundY	= i;
							Info -> Index	= SearchPosition;

							return(i);
						}
					}
					while(SearchPosition > 0);
				}

				LastSearchPosition = 0;
			}
		}
	}

	return(-1);
}

	/* GetSearchString():
	 *
	 *	Prompt the user for a search string.
	 */

BYTE __regargs
GetSearchString(struct Window *ParentWindow,BYTE *ParentTerminated,STRPTR Buffer,BYTE *Forward)
{
	BYTE Success = FALSE;
	APTR VisualInfo;

	if(VisualInfo = GetVisualInfo(ParentWindow -> WScreen,TAG_DONE))
	{
		struct Gadget	*GadgetList = NULL;
		struct Gadget	*GadgetArray[GAD_CANCEL + 1];
		struct Window	*PanelWindow;
		UBYTE		 OtherBuffer[256];

		strcpy(OtherBuffer,Buffer);

		if(CreateAllGadgets(*Forward,0,OtherBuffer,LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),GadgetArray,&GadgetList,VisualInfo,ParentWindow -> WScreen))
		{
			if(PanelWindow = OpenWindowTags(NULL,
				WA_Left,		(ParentWindow -> Width	- SZ_GetWindowWidth())	/ 2,
				WA_Top,			(ParentWindow -> Height	- SZ_GetWindowHeight())	/ 2,
				WA_Width,		SZ_GetWindowWidth(),
				WA_Height,		SZ_GetWindowHeight(),

				WA_Activate,		TRUE,
				WA_DragBar,		TRUE,
				WA_DepthGadget,		TRUE,
				WA_CloseGadget,		TRUE,
				WA_RMBTrap,		TRUE,
				WA_CustomScreen,	ParentWindow -> WScreen,

				WA_IDCMP,		IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_GADGETDOWN | BUTTONIDCMP | STRINGIDCMP,

				WA_Title,		LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),
			TAG_DONE))
			{
				struct IntuiMessage	*Massage;
				ULONG			 IClass,Code,Qualifier;
				struct Gadget		*Gadget;
				BYTE			 Terminated = FALSE;
				ULONG			 SignalSet;
				STRPTR			 String;

				AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
				RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
				GT_RefreshWindow(PanelWindow,NULL);

				ActivateGadget(ActiveGadget = GadgetArray[GAD_STRING],PanelWindow,NULL);

				String = SZ_GetString(GadgetArray[GAD_STRING]);

				if(ParentTerminated)
					ClrSignal(SIG_TOFRONT | SIG_KILL);
				else
					ClrSignal(SIG_BREAK);

				while(!Terminated)
				{
					if(ParentTerminated)
					{
						SignalSet = Wait(SIG_TOFRONT | SIG_KILL | PORTMASK(PanelWindow -> UserPort));

						if(SignalSet & SIG_TOFRONT)
							BumpWindow(PanelWindow);

						if(SignalSet & SIG_KILL)
							*ParentTerminated = Terminated = TRUE;
					}
					else
					{
						SignalSet = Wait(PORTMASK(PanelWindow -> UserPort) | SIG_BREAK);

						if(SignalSet & SIG_BREAK)
							Terminated = TRUE;
					}

					if(SignalSet & PORTMASK(PanelWindow -> UserPort))
					{
						while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
						{
							IClass		= Massage -> Class;
							Code		= Massage -> Code;
							Gadget		= (struct Gadget *)Massage -> IAddress;
							Qualifier	= Massage -> Qualifier;

							GT_ReplyIMsg(Massage);

							if(IClass == IDCMP_VANILLAKEY)
								KeySelect(GadgetArray,GAD_CANCEL,Code,PanelWindow,&Gadget,&IClass,&Code);

							if(IClass == IDCMP_RAWKEY && Code == HELP_CODE)
								DisplayBeep(PanelWindow -> WScreen);

							if(IClass == IDCMP_GADGETDOWN)
							{
								if((Gadget -> GadgetType & GTYP_GTYPEMASK) == GTYP_STRGADGET)
									ActiveGadget = Gadget;
							}

							if(IClass == IDCMP_ACTIVEWINDOW && ActiveGadget)
								ActivateGadget(ActiveGadget,PanelWindow,NULL);

							if(IClass == IDCMP_CLOSEWINDOW)
								Terminated = TRUE;

							if(IClass == IDCMP_GADGETUP)
							{
								switch(Gadget -> GadgetID)
								{
									case GAD_OK:

										if(String[0])
										{
											strcpy(Buffer,String);

											Success = TRUE;
										}

										Terminated = TRUE;

										break;

									case GAD_STRING:

										if(!(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
										{
											if(String[0])
											{
												strcpy(Buffer,String);

												Success = TRUE;
											}

											Terminated = TRUE;
										}

										break;

									case GAD_CANCEL:

										Terminated = TRUE;

										break;

									case GAD_FORWARD:

										*Forward = SZ_GetChecked(Gadget);
										break;
								}
							}
						}
					}
				}

				RemoveGList(PanelWindow,GadgetList,(UWORD)-1);

				CloseWindow(PanelWindow);
			}
		}

		FreeGadgets(GadgetList);

		FreeVisualInfo(VisualInfo);
	}

	return(Success);
}
