/*
**	patch.library
**
**	Copyright © 1993-1997 by Stefan Fuchs
**		Freely distributable.
*/

#ifndef _PATCH_INCLUDES_H
#include "patch_includes.h"
#endif


/****** patch.library/FindPatchTagsA ***************************************
*
*   NAME
*        FindPatchTagsA -- find a patch structure with certain criteria. (V3)
*        FindPatchTags -- varargs stub for FindPatchTagsA(). (V3)
*
*   SYNOPSIS
*        object = FindPatchTagsA( taglist )
*        D0                       A0
*
*        APTR FindPatchTagsA( struct TagItem *);
*
*        object = FindPatchTags( ...)
*
*        APTR FindPatchTags( ...);
*
*   FUNCTION
*        This function will search the patch.library lists for a
*        patch structure, that matches the criteria specified in the taglist.
*        The first matching patch will be returned.
*
*   INPUTS
*        taglist = pointer to array of tags
*
*   TAGS
*        Specify only one of these at a time:
*        PATT_PatchName (STRPTR) - Specifies that patch.library should
*                search for the patch with the given name.
*        PATT_ProjectName (V4) (STRPTR) - Specifies that patch.library should
*                search for the project with the given name.
*
*
*        PATT_NoCase (V4) (BOOL) - If specified with PATT_PatchName or
*                PATT_ProjectName string-comparison will be case-independent.
*                International characters are not respected with this version
*                of patch.library.
*                This may or may not change in the future.
*        PATT_LastObject (V4) (APTR) - This tag allows to search for multiple
*                matching objects. Simply specify the result of a previous
*                call to FindPatchTags() to continue searching with this tag.
*                You may also specify NULL to start searching the lists from
*                the beginning. Keep in mind, that you must make sure, that
*                the pointer is valid (see notes).
*
*   RESULT
*        object = a pointer to the object as requested within the taglist or
*                 NULL to indicate that no match was found.
*
*   NOTES
*        If your task is not the owner of the patch, the
*        pointer is only valid as long as the system is in forbid().
*        You may also lock the patch.library semaphore
*        before calling this function. In this case a pointer to
*        a patch structure is guaranteed to be valid, until you
*        release the semaphore. The semaphore, however, should be kept
*        locked only for short periods of time in order not to block
*        other tasks.
*
******************************************************************************
*
*/

APTR LIBFUNC FindPatchTagsA( REGA0 struct TagItem *taglist GNUC_REGA0)
{
APTR Result;
WORD LVO;
APTR lastobject;
APTR object;
ULONG NoCase;
struct MasterPatch *master;
struct Patch *patch;
struct List *header;

	Result = (APTR)SAVEObtainSemaphoreShared();
	if( Result == 0L)
	{
		lastobject = (APTR)GetTagData(PATT_LastObject, 0L, taglist);
		NoCase = GetTagData(PATT_NoCase, 0L, taglist);



		if( object = (APTR)GetTagData(PATT_PatchName, 0L, taglist))
		{
			if( lastobject == NULL)
			{
				header = &(PatchBase->PB_MasterPatchHeader);
			}
			else
			{
				header = (struct List *)GetMasterPatch(lastobject);
			}
			for( master = (struct MasterPatch *)header->lh_Head;
			     master->MPS_Node.ln_Succ;
			     master = (struct MasterPatch *)master->MPS_Node.ln_Succ)
			{
				if( NoCase)
				{
					Result = FindNameNoCase( (struct List *)&( master->MPS_PatchHeader), (STRPTR)object);
				}
				else
				{
					Result = FindName( (struct List *)&(master->MPS_PatchHeader), (STRPTR)object);
				}
				if( Result) break;
			}
			goto Ende;
		}



		if( object = (APTR)GetTagData(PATT_ProjectName, 0L, taglist))
		{
			if( lastobject == NULL)
			{
				header = &(PatchBase->PB_ProjectHeader);
			}
			else header = lastobject;
			if( NoCase)
			{
				Result = FindNameNoCase( header, (STRPTR)object);
			}
			else
			{
				Result = FindName( header, (STRPTR)object);
			}
			goto Ende;
		}



		if( object = (APTR)GetTagData(PATT_SYSTEM, 0L, taglist))
		{
			if( lastobject == NULL)
			{
				header = &(PatchBase->PB_MasterPatchHeader);
			}
			else
			{
				header = (struct List *)GetMasterPatch(lastobject);
			}
			for( master = (struct MasterPatch *)header->lh_Head;
			     master->MPS_Node.ln_Succ;
			     master = (struct MasterPatch *)master->MPS_Node.ln_Succ)
			{
				for( patch = (struct Patch *)master->MPS_PatchHeader.mlh_Head;
				     patch->PS_Node.ln_Succ;
			   	     patch= (struct Patch *)patch->PS_Node.ln_Succ)
				{
					if( patch->PS_Node.ln_Type == PS_TYPE_SYSTEM)
					{
						if( patch->PS_SystemEntry == object)
						{
							Result = patch;
							goto SystemExit;
						}
					}
				}
			}
SystemExit:
			goto Ende;
		}



		if( object = (APTR)GetTagData(PATT_LibraryBase, 0L, taglist))
		{
			if( lastobject == NULL)
			{
				header = &(PatchBase->PB_MasterPatchHeader);
			}
			else header = lastobject;
			if( LVO = GetTagData(PATT_LVO, 0L, taglist))
			{
				for (master = (struct MasterPatch *)header->lh_Head;
				     master->MPS_Node.ln_Succ;
				     master = (struct MasterPatch *)master->MPS_Node.ln_Succ)
				{
					if( master->MPS_PatchedLibraryBase == object && master->MPS_PatchedLVO == LVO)
					{
						Result = master;
						break;
					}
				}
			}
			goto Ende;
		}



		if( object = (APTR)GetTagData(PATT_LibraryName, 0L, taglist))
		{
			if( lastobject == NULL)
			{
				header = &(PatchBase->PB_MasterPatchHeader);
			}
			else header = lastobject;
			if( LVO = GetTagData(PATT_LVO, 0L, taglist))
			{
				for(;;)
				{
					master = (struct MasterPatch *)FindName(header, (STRPTR)object);
					if( master == NULL)
						break;
					if(master->MPS_PatchedLVO == LVO)
					{
						Result = master;
						break;
					}
					header = (struct List *)master;
				}
			}
			goto Ende;
		}



Ende:
		ReleaseSemaphore(&(PatchBase->PB_Semaphore));
	}
	return(Result);
}
