#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/exall.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <stdio.h>

#include "scandir.h"
#include "scandir_protos.h"

BOOL ResolveSoftLink(UBYTE *, UBYTE *, UBYTE *, ULONG);
BOOL ResolveHardLink(UBYTE *, UBYTE *, UBYTE *, ULONG);

main(int argc, char **argv)
{
	struct ExAllControl    *eaControl;
	BPTR                    dirLock;
	struct ExAllData       *eaBuffer, *eaData;
	LONG                    eaBuffSize = NUM_OF_BUFS * sizeof(struct ExAllData);
	LONG                    more;
	UBYTE                   linkname[2048];
	BPTR                    linkLock;
	struct FileInfoBlock    linkInfo;

	if (argc < 2)
	{
		printf("usage: %s dir\n", argv[0]);
		exit(0);
	}

	dirLock = Lock(argv[1], ACCESS_READ);

	if (!dirLock)
	{
		printf("the lock failed\n");
		exit(1);
	}

	eaControl = (struct ExAllControl *) AllocDosObject(DOS_EXALLCONTROL,
													   NULL);

	if (!eaControl)
	{
		printf("AllocDosObject failed\n");
		UnLock(dirLock);
		exit(1);
	}

	eaControl->eac_LastKey = 0;
	eaControl->eac_MatchString = (UBYTE *) NULL;
	eaControl->eac_MatchFunc = (struct Hook *) NULL;

	eaBuffer = (struct ExAllData *) AllocMem(eaBuffSize, MEMF_ANY);

	if (!eaBuffer)
	{
		printf("AllocMem(eaBuffer) failed\n");
		FreeDosObject(DOS_EXALLCONTROL, eaControl);
		UnLock(dirLock);
		exit(1);
	}

	do
	{
		more = ExAll(dirLock,
					 eaBuffer,
					 eaBuffSize,
					 ED_COMMENT,
					 eaControl);

		if ((!more) && (IoErr() != ERROR_NO_MORE_ENTRIES))
		{
			printf("ExAll failed abnormally\n");
			break;
		}

		if (eaControl->eac_Entries == 0)
		{
			printf("no more entries\n");
			continue;
		}
		else
		{
			eaData = (struct ExAllData *) eaBuffer;
			while (eaData)
			{
				printf("%s", eaData->ed_Name);

				switch (eaData->ed_Type)
				{
					case ST_ROOT:
					case ST_USERDIR:
						printf(" (Dir) ");
						break;

					case ST_SOFTLINK:
						printf(" -> ");
						if (!ResolveSoftLink(eaData->ed_Name,
											 argv[1],
											 linkname,
											 2048L))
						{
							printf("** error resolving softlink **\n");
						}
						else
						{
							printf("%s (Soft)", linkname);
							linkLock = Lock(linkname, ACCESS_READ);
							if ((linkLock) &&
								Examine(linkLock, &linkInfo) &&
								(linkInfo.fib_DirEntryType > 0))
								printf(" (Dir)");
						}
						break;

					case ST_LINKDIR:
					case ST_LINKFILE:
						printf(" -> ");
						if (!ResolveHardLink(eaData->ed_Name,
											 argv[1],
											 linkname,
											 2048L))
						{
							printf("error resolving link");
						}
						else
						{
							printf("%s (Hard)", linkname);
						}
						if (eaData->ed_Type == ST_LINKDIR)
							printf(" (Dir)");
						break;

					default:
						break;
				}
				printf("\n");

				eaData = eaData->ed_Next;
			}
		}
	}
	while (more);

	FreeMem(eaBuffer, eaBuffSize);
	FreeDosObject(DOS_EXALLCONTROL, eaControl);
	UnLock(dirLock);
	exit(0);
}
