#define __USE_SYSBASE

#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/rdargs.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <dos/dosextens.h>
#include <datatypes/datatypes.h>
#include <datatypes/datatypesclass.h>
#include <support/types.h>
#include <support/exec.h>

#include <string.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/datatypes.h>

#include "examine.rev.h"

#define DOS_NAME		"dos.library"
#define DOS_VERN 		37L
#define DT_NAME			"datatypes.library"
#define DT_VERN			39L

#define TEMPLATE		"FILE/M,GROUPID=G/K,TYPEID=T/K,FULL/S,ID/S,ALL/S"

STATIC CONST TEXT VersionString[]=
	VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);

#define OPT_FILE		0
#define OPT_GID			1
#define OPT_TID			2
#define OPT_FULL		3
#define OPT_ID			4
#define OPT_ALL			5
#define OPT_COUNT		6

#define NAME_SIZE		32
#define PATH_SIZE		256
#define LONG_SIZE		5

STATIC VOID L2S(STRPTR buffer, ULONG x);

ULONG ExamineDT(VOID)
{
	struct ExecBase *SysBase=*((struct ExecBase **)4);
	struct DosLibrary *DOSBase;
	struct Library *DataTypesBase;

	STATIC CONST STRPTR NoArgs[]={"#?",NULL};

	struct RDArgs *Args;
	struct AnchorPath *Anchor;
	struct DataType *DT;
	struct DataTypeHeader *DTH;
	LONG Opts[OPT_COUNT];
	ULONG TempRC,RC=RETURN_FAIL;
	CHAR FName[NAME_SIZE],GroupID[LONG_SIZE],ID[LONG_SIZE];
	STRPTR CurArg,*ArgPtr;
	BPTR CurrLock,OldLock,Handle;
	BOOL ErrOccured=FALSE;

	if(!(DOSBase=(struct DosLibrary *)OpenLibrary(DOS_NAME,DOS_VERN)))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		goto InvalidDOS;
	}

	if(!(DataTypesBase=OpenLibrary(DT_NAME,DT_VERN)))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		goto InvalidDataTypes;
	}

	if(!(Anchor=AllocVec(sizeof(struct AnchorPath)+PATH_SIZE,MEMF_CLEAR)))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto NoMemory;
	}

	clear(&Opts);
	if(!(Args=ReadArgs(TEMPLATE,Opts,NULL)))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto NoArgs;
	}

	ArgPtr=Opts[OPT_FILE] ? (STRPTR *)Opts[OPT_FILE] : (STRPTR *)NoArgs;
	while(CurArg=*ArgPtr++)
	{
		clear(Anchor);
		Anchor->ap_Strlen=PATH_SIZE;
		Anchor->ap_BreakBits=SIGBREAKF_CTRL_C;		/* Allow break */

		TempRC=MatchFirst(CurArg,Anchor);
		while(TempRC==0)
		{
			strcpy(FName,Anchor->ap_Info.fib_FileName);
			if(Anchor->ap_Info.fib_DirEntryType>=0)
			{
				if(Opts[OPT_ALL])
				{
					if(!ftst(Anchor->ap_Flags,APF_DIDDIR))
						fset(Anchor->ap_Flags,APF_DODIR);
					fclr(Anchor->ap_Flags,APF_DIDDIR);
				}
				goto Next;
			}
			CurrLock=DupLock(Anchor->ap_Current->an_Lock);
			OldLock=CurrentDir(CurrLock);
			if(Handle=Lock(FName,ACCESS_READ))
			{
				if(DT=ObtainDataTypeA(DTST_FILE,(APTR)Handle,NULL))
				{
					DTH=DT->dtn_Header;
					L2S(GroupID,DTH->dth_GroupID);
					L2S(ID,DTH->dth_ID);
					if(Opts[OPT_GID] && strcmp(GroupID,(STRPTR)Opts[OPT_GID]))
						goto Release;
					if(Opts[OPT_TID] && strcmp(ID,(STRPTR)Opts[OPT_TID]))
						goto Release;
					if(Opts[OPT_FULL])
						Printf("%s\n",Anchor->ap_Buf);
					else
						Printf("%-30s ",FName);
					Printf("%-12s %-16s",GetDTString(DTH->dth_GroupID),DTH->dth_Name);
					if(Opts[OPT_ID])
						Printf(" %-4s %-4s",GroupID,ID);
					PutStr("\n");
Release:
					ReleaseDataType(DT);
				}
				else
				{
					ErrOccured=TRUE;
					PrintFault(IoErr(),NULL);
				}
				UnLock(Handle);
			}
			else
			{
				ErrOccured=TRUE;
				PrintFault(IoErr(),NULL);
			}
			CurrentDir(OldLock);
			UnLock(CurrLock);
Next:
			TempRC=MatchNext(Anchor);
		}
		if(TempRC==ERROR_NO_MORE_ENTRIES)
			RC=(ErrOccured ? RETURN_ERROR : RETURN_OK);
		else
		{
			PrintFault(TempRC,NULL);
			RC=(TempRC==ERROR_BREAK ? RETURN_WARN : RETURN_FAIL);
		}
		MatchEnd(Anchor);
		if(TempRC==ERROR_BREAK)
			break;
	}

	FreeArgs(Args);
NoArgs:
	FreeVec(Anchor);
NoMemory:
	CloseLibrary(DataTypesBase);
InvalidDataTypes:
	CloseLibrary((struct Library *)DOSBase);
InvalidDOS:
	return(RC);
}

STATIC VOID L2S(STRPTR buffer, ULONG x)
{
	ULONG I;

	for(I=0; I<4; I++)
		buffer[I]=x >> ((3-I) << 3);
	buffer[I]='\0';
}
