/*
**	termTraps.c
**
**	Trap routines
**
**	Copyright © 1990-1994 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#include "termGlobal.h"

struct TrapNode * __regargs
ChangeTrapNode(struct GenericList *TrapList,struct TrapNode *Current,STRPTR Sequence,STRPTR Command)
{
	struct TrapNode *New;

	if(!Sequence)
		Sequence = Current -> Node . ln_Name;

	if(!Command)
		Command = Current -> Command;

	if(New = CreateTrapNode(Sequence,Command))
	{
		Insert((struct List *)TrapList,(struct Node *)New,(struct Node *)Current);

		Remove((struct Node *)Current);

		FreeVecPooled(Current);

		return(New);
	}
	else
		return(Current);
}

struct TrapNode * __regargs
CreateTrapNode(STRPTR SequenceBuffer,STRPTR CommandBuffer)
{
	UBYTE		 LocalBuffer[256];
	LONG		 Len = TranslateString(SequenceBuffer,LocalBuffer);
	struct TrapNode	*Node;

	if(Node = (struct TrapNode *)AllocVecPooled(sizeof(struct TrapNode) + strlen(SequenceBuffer) + 1 + Len + strlen(CommandBuffer) + 1,MEMF_ANY))
	{
		STRPTR String;

		String = Node -> Node . ln_Name = (STRPTR)(Node + 1);

		strcpy(String,SequenceBuffer);

		String += strlen(String) + 1;

		Node -> Sequence = String;

		CopyMem(LocalBuffer,String,Len);

		String += Len;

		Node -> Command = String;

		Node -> SequenceLen = Len;
		Node -> Count = 0;

		strcpy(String,CommandBuffer);
	}

	return(Node);
}

	/* SaveTraps(STRPTR Name):
	 *
	 *	Save the trap list to a file.
	 */

BYTE __regargs
SaveTraps(STRPTR Name,struct List *TrapList)
{
	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	LONG			 Error = 0;

	if(Handle = (struct IFFHandle *)AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
		{
			InitIFFasDOS(Handle);

			if(!(Error = OpenIFF(Handle,IFFF_WRITE)))
			{
				if(!(Error = PushChunk(Handle,ID_TERM,ID_CAT,IFFSIZE_UNKNOWN)))
				{
					Success = TRUE;

					if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
					{
						if(!(Error = PushChunk(Handle,0,ID_VERS,IFFSIZE_UNKNOWN)))
						{
							struct TermInfo TermInfo;

							TermInfo . Version	= TermVersion;
							TermInfo . Revision	= TermRevision;

							if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
							{
								if(Error = PopChunk(Handle))
									Success = FALSE;
							}
							else
							{
								Error = IoErr();
								
								Success = FALSE;
							}
						}
						else
							Success = FALSE;

						if(Success)
						{
							if(!(Error = PushChunk(Handle,0,ID_TRST,sizeof(struct TrapSettings))))
							{
								struct TrapSettings TrapSettings;
	
								memset(&TrapSettings,0,sizeof(TrapSettings));
	
								TrapSettings . Enabled = WatchTraps;
	
								if(WriteChunkBytes(Handle,&TrapSettings,sizeof(struct TrapSettings)) == sizeof(struct TrapSettings))
								{
									if(Error = PopChunk(Handle))
										Success = FALSE;
								}
								else
								{
									Success = FALSE;
	
									Error = IoErr();
								}
							}
							else
								Success = FALSE;
						}

						if(Success)
						{
							if(Error = PopChunk(Handle))
								Success = FALSE;
						}
					}
					else
						Success = FALSE;

					if(Success)
					{
						struct TrapNode *Node;

						Node = (struct TrapNode *)TrapList -> lh_Head;

						while(Success && Node -> Node . ln_Succ)
						{
							if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
							{
								if(!(Error = PushChunk(Handle,0,ID_SEQN,strlen(Node -> Node . ln_Name))))
								{
									if(WriteChunkBytes(Handle,Node -> Node . ln_Name,strlen(Node -> Node . ln_Name)) != strlen(Node -> Node . ln_Name))
									{
										Error = IoErr();

										Success = FALSE;

										break;
									}
									else
									{
										if(Error = PopChunk(Handle))
										{
											Success = FALSE;

											break;
										}
										else
										{
											if(!(Error = PushChunk(Handle,0,ID_TRAP,strlen(Node -> Command))))
											{
												if(WriteChunkBytes(Handle,Node -> Command,strlen(Node -> Command)) != strlen(Node -> Command))
												{
													Error = IoErr();

													Success = FALSE;

													break;
												}
												else
												{
													if(Error = PopChunk(Handle))
													{
														Success = FALSE;

														break;
													}
												}
											}
										}
									}
								}

								if(Success)
								{
									if(Error = PopChunk(Handle))
									{
										Success = FALSE;

										break;
									}
								}
							}

							Node = (struct TrapNode *)Node -> Node . ln_Succ;
						}
					}

					if(Success)
					{
						if(Error = PopChunk(Handle))
							Success = FALSE;
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}
		else
			Error = IoErr();

		FreeIFF(Handle);
	}
	else
		Error = ERR_NO_MEM;

	if(Success)
		AddProtection(Name,FIBF_EXECUTE);
	else
		DeleteFile(Name);

	if(Error)
		SetIoErr(Error);

	return(Success);
}

	/* LoadTraps(STRPTR Name):
	 *
	 *	Restore the trap list from a file.
	 */

BYTE __regargs
LoadTraps(STRPTR Name,struct GenericList *TrapList)
{
	STATIC ULONG Stops[8] =
	{
		ID_TERM,ID_VERS,
		ID_TERM,ID_SEQN,
		ID_TERM,ID_TRAP,
		ID_TERM,ID_TRST
	};

	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	struct ContextNode	*Chunk;
	LONG			 Error = 0;
	UBYTE			 SequenceBuffer[256],
				 CommandBuffer[256];
	struct TrapSettings	 TrapSettings;
	BYTE			 TrapSettingsFound = FALSE;

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
		{
			InitIFFasDOS(Handle);

			if(!(Error = OpenIFF(Handle,IFFF_READ)))
			{
				if(!(Error = StopChunks(Handle,(LONG *)Stops,4)))
				{
					Success = TRUE;

					SequenceBuffer[0] = CommandBuffer[0] = 0;

					while(!ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

						if(Chunk -> cn_ID == ID_VERS)
						{
							struct TermInfo TermInfo;

							if(ReadChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
							{
								if((TermInfo . Version > TermVersion) || (TermInfo . Version == TermVersion && TermInfo . Revision > TermRevision) || (TermInfo . Version == 1 && TermInfo . Revision < 6))
								{
									Error = ERR_OUTDATED;

									break;
								}
							}
							else
							{
								Success = FALSE;

								Error = IoErr();

								break;
							}
						}

						if(Chunk -> cn_ID == ID_TRST)
						{
							if(ReadChunkBytes(Handle,&TrapSettings,sizeof(struct TrapSettings)) == sizeof(struct TrapSettings))
								TrapSettingsFound = TRUE;
							else
							{
								Success = FALSE;

								Error = IoErr();

								break;
							}
						}

						if(Chunk -> cn_ID == ID_SEQN)
						{
							if(ReadChunkBytes(Handle,SequenceBuffer,Chunk -> cn_Size) == Chunk -> cn_Size)
								SequenceBuffer[Chunk -> cn_Size] = 0;
							else
							{
								Success = FALSE;

								Error = IoErr();

								break;
							}
						}

						if(Chunk -> cn_ID == ID_TRAP)
						{
							if(ReadChunkBytes(Handle,CommandBuffer,Chunk -> cn_Size) == Chunk -> cn_Size)
								CommandBuffer[Chunk -> cn_Size] = 0;
							else
							{
								Success = FALSE;

								Error = IoErr();

								break;
							}
						}

						if(Success && SequenceBuffer[0] && CommandBuffer[0])
						{
							struct TrapNode *Node;

							if(Node = CreateTrapNode(SequenceBuffer,CommandBuffer))
							{
								AddGenericListNode(TrapList,(struct Node *)Node,ADD_GLIST_BOTTOM);

								SequenceBuffer[0] = CommandBuffer[0] = 0;
							}
							else
							{
								Success = FALSE;

								Error = ERR_NO_MEM;

								break;
							}
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}
		else
			Error = IoErr();

		FreeIFF(Handle);
	}
	else
		Error = ERR_NO_MEM;

	if(Error)
		SetIoErr(Error);

	if(Success)
	{
		TrapsChanged = FALSE;

		if(TrapSettingsFound)
			WatchTraps = TrapSettings . Enabled;
	}

	if(!TrapList -> ListCount && WatchTraps)
		WatchTraps = FALSE;

	return(Success);
}
