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

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


/****** patch.library/GetPatchA ***************************************
*
*   NAME
*        GetPatchA -- Returns certain attributes of a patch. (V3)
*        GetPatch -- varargs stub for GetPatchA(). (V3)
*
*   SYNOPSIS
*        Result = GetPatchA( patch, taglist )
*        D0                  A0     A1
*
*        ULONG Result GetPatchA( struct Patch *, struct TagItem *);
*
*        Result = GetPatch( patch, ...)
*
*        ULONG Result GetPatch( struct Patch *, ...);
*
*   FUNCTION
*        Returns certain attributes and lists connected to a patch (see TAGS).
*
*   INPUTS
*        patch = pointer to a patch structure or NULL for no action
*        taglist = pointer to array of tags
*
*   TAGS
*        PATT_Result2 (ULONG *) - An optional pointer to a longword,
*                which will contain an errorcode as defined patch.h,
*                when the function returns.
*                Assembler programmers can get the same value from d1.
*
*        Only one of the following tags may be specified at a time:
*
*        PATT_PatchName (BOOL) - Return a pointer to a copy of the name of
*                the patch in a null-terminated string.
*                This pointer must be passed to PatchFreeVec(), if
*                the string is no longer needed.
*                Type of Result is STRPTR.
*        PATT_TaskListType (BOOL) - Return the type of the internal TaskList
*                Possible results:
*                TL_TYPE_INCLUDE: all specified tasks will use
*                                 the patchroutine, all others will ignore it.
*                TL_TYPE_EXCLUDE: all specified tasks will ignore
*                                 the patchroutine, all others will use it.
*                NULL:            An error occurred (this includes the absence
*                                 of a TaskList). Check the secondary
*                                 errorcode for more information.
*                Type of Result is ULONG.
*        PATT_TaskList (BOOL) - Return a pointer to a taglist containing all
*                tasknames, taskids or patterns attached to a patch.
*                The tagitems are PATT_AddTaskName, PATT_AddTaskID or
*                PATT_AddTaskPattern(new for V5).
*                Unknown tags must be ignored.
*                This pointer must be passed to PatchFreeVec(), if
*                the tasklist is no longer needed.
*                Type of Result is taglist.
*        PATT_Disabled (V4) (BOOL) - Return a number representing the current
*                disable nesting counter of a patch. Null means the patch is
*                enabled and will be used, by any tasks using the
*                library function.
*                Type of Result is ULONG.
*        PATT_UserData (V5) (BOOL) - Return userdata attached to a patch.
*                Type of Result is ULONG.
*        PATT_Priority (V5) (BOOL) - Return the priority of a patch.
*                Type of Result is BYTE.
*        PATT_Original (V6) (BOOL) - Return a pointer to the original
*                function.
*                Only possible, if patch was installed with PATT_Original
*                Type of Result is (* )().
*
*
*   RESULT
*        Result = Pointer or longword depending on specified tags.
*
*        Possible errorcodes returned with PATT_Result2 or in register d1:
*                PATERR_Ok
*                        Indicates success of the operation.
*                PATERR_OutOfMem
*                        Indicates that there was not enough memory to
*                        complete the operation.
*                PATERR_InvalidHandle
*                        Indicates that the pointer to the patch passed
*                        to the function was not or is no longer valid.
*                        This might happen, if you pass a wrong pointer or
*                        you got the pointer via FindPatch() and another
*                        task has removed the patch before this task called
*                        RemovePatchTags().
*                PATERR_NoTaskList
*                        No valid TaskList is attached to the patch.
*                        The SetPatchA() function with the PATT_CreateTaskList
*                        tag specified, must be called to allocate a TaskList.
*                PATERR_PatchUnnamed
*                        The patch has no identification string attached
*                        to it.
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*        InstallPatchTags(), PatchFreeVec(), patch.h, patchtags.h
*
******************************************************************************
*
*/

ULONG LIBFUNC GetPatchA( REGA0 struct Patch *patch GNUC_REGA0, REGA1 struct TagItem *taglist GNUC_REGA1)
{
ULONG Result1 = NULL;
ULONG Result2;
struct TLHeader *tasklist;
struct Node *pointer;
struct TagItem *ntaglist;
ULONG *Result2ptr;
UBYTE *memptr;

	Result2 = SAVEObtainSemaphore();   /* This can't be a shared semaphore, as AllocPolled() can not handle multiple tasks */
	if (Result2 == 0L)
	{
		if ((patch) && (taglist))
		{
			Result2 = TestPatchHandle(patch);
			if (Result2 == 0L)
			{


				if (GetTagData(PATT_PatchName, 0L, taglist))
				{
					if(patch->PS_Node.ln_Name)
					{
						Result1 = (ULONG)BAllocmem( strlen( patch->PS_Node.ln_Name) + 1, MEMF_CLEAR | MEMF_PUBLIC);
						if(Result1)
						{
							strcpy( (char *)Result1, patch->PS_Node.ln_Name);
						}
						else Result2 = PATERR_OutOfMem;
					}
					else	Result2 = PATERR_PatchUnnamed;
					goto Ende;
				}


				if (GetTagData(PATT_TaskListType, 0L, taglist))
				{
					if( tasklist = patch->PS_PatchCode->PC_TaskList)
						Result1 = tasklist->TL_List.lh_Type;
					else
						Result2 = PATERR_NoTaskList;
					goto Ende;
				}


				if (GetTagData(PATT_TaskList, 0L, taglist))
				{
					if( tasklist = patch->PS_PatchCode->PC_TaskList)
					{
						if( Result1 = (ULONG)BAllocmem( GetNumberOfNodes((struct List *)tasklist) * 8 + 4, MEMF_CLEAR))
						{
							ntaglist = (struct TagItem *)Result1;
							for (pointer = (struct Node *)tasklist->TL_List.lh_Head;
							     pointer->ln_Succ;
							     pointer = (struct Node *)pointer->ln_Succ)
							{
								switch(pointer->ln_Type)
								{
									case TLI_TYPE_TASKNAME:
										ntaglist->ti_Tag = PATT_AddTaskName;
										ntaglist->ti_Data = (ULONG)pointer->ln_Name;
										ntaglist++;
										break;
									case TLI_TYPE_TASKID:
										ntaglist->ti_Tag = PATT_AddTaskID;
										ntaglist->ti_Data = (ULONG)pointer->ln_Name;
										ntaglist++;
										break;
									case TLI_TYPE_TASKPATTERN:
										ntaglist->ti_Tag = PATT_AddTaskPattern;
										ntaglist->ti_Data = (ULONG)pointer->ln_Name;
										ntaglist++;
										break;
								}
							}
							ntaglist->ti_Tag = TAG_DONE;
						}
						else
							Result2 = PATERR_OutOfMem;
					}
					else
						Result2 = PATERR_NoTaskList;
					goto Ende;
				}


				if (GetTagData(PATT_Disabled, 0L, taglist))
				{
					Result1 = patch->PS_PatchCode->PC_Disable;
					goto Ende;
				}


				if (GetTagData(PATT_ProjectID, 0L, taglist))
				{
					if (patch->PS_ProjectNode.mln_Succ)
					{
						Result1 = (ULONG)GetListNodeHeader((struct Node *)&(patch->PS_ProjectNode));
						Result1 -= offsetof(struct PatchProject, PPR_PatchListHeader);
					}
					goto Ende;
				}


				if (GetTagData(PATT_UserData, 0L, taglist))
				{
					Result1 = patch->PS_UserData;
					goto Ende;
				}


				if (GetTagData(PATT_Priority, 0L, taglist))
				{
					Result1 = patch->PS_Node.ln_Pri;
					goto Ende;
				}


				/* Note PATT_Original is currently same as PATT_SYSTEM */
				/* So PATT_SYSTEM may go away, if PatchSetFunc requires version v6 */
				if (GetTagData(PATT_Original, 0L, taglist))
				{
					Result1 = (ULONG)patch->PS_SystemEntry;
					goto Ende;
				}


/*** PRIVATE Tags follow here ***/

				if (GetTagData(PATT_NewCode, 0L, taglist))
				{
					memptr = patch->PS_Jsr;
					memptr += 2;
					Result1 = (ULONG)(*((ULONG *)memptr));
					goto Ende;
				}


				if (GetTagData(PATT_SYSTEM, 0L, taglist))
				{
					Result1 = (ULONG)patch->PS_SystemEntry;
					goto Ende;
				}

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

	if (Result2ptr = (ULONG *)GetTagData(PATT_Result2, 0L, taglist))
			*Result2ptr = Result2;

	ReturnD1(Result2);
	return(Result1);
}
