/*************************************************************************
 *																		 *
 *					(C)Copyright 1989 Torstein Pettersen.				 *
 *																		 *
 *	Subrutine  :	getfile.c											 *
 *																		 *
 *	Beskrivelse:	Subrutinen åpner et vindu med en liste over alle	 *
 *					filer i en katalog. Brukeren kan så bla fram og		 *
 *					tilbake i denne og velge en fil eller en ny katalog	 *
 *					som rutinen da skifter til og viser. Når brukeren	 *
 *					har valgt ønsket fil, trykkes OK eller Cancel for å	 *
 *					avbryte.											 *
 *																		 *
 *	Parametere :	1. Peker til custom screen eller NULL hvis Workbench *
 *					2. Lock på den katalogen som skal vises				 *
 *					3. Peker til teksten som skal benyttes i OK gadget	 *
 *					4. Peker til buffer for valgt filnavn				 *
 *																		 *
 *  Returnerer :	Rutinen returnerer følgende status koder:			 *
 *					0: Filnavn ok										 *
 *					1: Cancel trykket									 *
 *					2: Andre feil under lesing av katalog, sansynligvis	 *
 *					   enten lese-feil eller for lite ledig minne.		 *
 *																		 *
 *	Rutinen er laget med Lattice C 5.02, men det er også definering for	 *
 *	bruk under Lattice C 4.0, men dette er ikke testet.					 *
 *																		 *
 *	Rutinen kan fritt kopieres og brukes i andre programmer så lenge	 *
 *	som Copyright'en og denne beskrivelse er inkludert.					 *
 *																		 *
 *	Gjør gjerne endringer og forbedringer av denne fil-requesteren,		 *
 *	eller send meg et brev med forslag til endringer og forbedringer.	 *
 *																		 *
 *	Min adresse er:														 *
 *		Torstein Pettersen												 *
 *		Galnåsmyra 94B													 *
 *		8015 HUNSTAD													 *
 *																		 *
 *************************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/sprite.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <string.h>
#include <dos.h>

#ifdef LATTICE_50
#define CHIP chip
#else
#define CHIP
#endif

/* Image data til scroll-pilene */

static USHORT CHIP DownImageData[] = {
	0xFFFF,0xE000,0xFFFF,0xE000,0xE000,0xE000,0xF001,0xE000,
	0xF803,0xE000,0xFC07,0xE000,0xFE0F,0xE000,0xFF1F,0xE000,
	0xFFBF,0xE000,0xFFFF,0xE000,0xFFFF,0xE000
};
static USHORT CHIP UpImageData[] = {
	0xFFFF,0xE000,0xFFFF,0xE000,0xFFBF,0xE000,0xFF1F,0xE000,
	0xFE0F,0xE000,0xFC07,0xE000,0xF803,0xE000,0xF001,0xE000,
	0xE000,0xE000,0xFFFF,0xE000,0xFFFF,0xE000
};

/* Image data til snorke pointeren */

static USHORT CHIP WaitSpriteData[] = {
	0x0000,0x0000,0x0000,0x0FE0,0x0740,0x18B0,0x0FE0,0x7018,
	0x3FF0,0xC008,0x7FF0,0x9E0C,0x7FF8,0x8406,0x7FFC,0x8802,
	0xFFFC,0x1E03,0x7FFE,0x80F1,0x7FFE,0x8021,0x3FFF,0x4040,
	0x7FFE,0x80F1,0x3FFE,0xC001,0x1FFC,0x6003,0x0FF8,0x3006,
	0x03F0,0x1C0C,0x00E0,0x0718,0x0780,0x0870,0x0FE0,0x1010,
	0x0740,0x0820,0x0000,0x0FE0,0x01C0,0x0220,0x03E0,0x0410,
	0x00C0,0x0330,0x0000,0x00E0,0x0000,0x0000
};

/* Border data for tegning av file-requesteren */

static SHORT BorderVectors8[] = {0,0,22,0,22,58,0,58,0,1,21,1,21,57,1,57,1,1};
static SHORT BorderVectors7[] = {0,0,22,0};
static SHORT BorderVectors6[] = {0,12,22,12};
static SHORT BorderVectors5[] = {0,0,189,0,189,58,0,58,0,1,188,1,188,57,1,57,1,1};
static SHORT BorderVectors4[] = {0,0,217,0,217,12,0,12,0,0,216,0,216,12,1,12,1,0};
static SHORT BorderVectors3[] = {0,0,217,0,217,12,0,12,0,0,216,0,216,12,1,12,1,0};
static SHORT BorderVectors2[] = {0,0,103,0,103,12,0,12,0,0,102,0,102,12,1,12,1,0};
static SHORT BorderVectors1[] = {0,0,103,0,103,12,0,12,0,0,102,0,102,12,1,12,1,0};

/* buffer til katalog og fil gadget'ene */

static UBYTE FileGadgetIBuff[31];
static UBYTE DrawerGadgetIBuff[257];

static char outfbuff[25];

#ifdef LATTICE_50
static struct Image DownImage = { 0,0,19,11,1,DownImageData,0x0001,0x0000,NULL };
static struct Image UpImage = { 0,0,19,11,1,UpImageData,0x0001,0x0000,NULL };
#else
static struct Image DownImage = { 0,0,19,11,1,NULL,0x0001,0x0000,NULL };
static struct Image UpImage = { 0,0,19,11,1,NULL,0x0001,0x0000,NULL };
#endif

/* Image og Border strukturer for tegning av file-requester'en */

static struct Image Image6 = { 0,0,19,7,1,NULL,0x0000,0x0000,NULL };
static struct Image Image5 = { 14,97,214,11,0,NULL,0x0000,0x0000,NULL };
static struct Image Image4 = { 14,21,214,11,0,NULL,0x0000,0x0000,&Image5 };
static struct Image Image3 = { 128,6,100,11,0,NULL,0x0000,0x0003,&Image4 };
static struct Image Image2 = { 14,6,100,11,0,NULL,0x0000,0x0003,&Image3 };
static struct Image Image1 = { 2,1,238,112,0,NULL,0x0000,0x0001,&Image2 };
static struct Border Border8 = {207,35,2,0,JAM1,9,BorderVectors8,NULL};
static struct Border Border7 = {207,80,2,0,JAM1,2,BorderVectors7,&Border8};
static struct Border Border6 = {207,36,2,0,JAM1,2,BorderVectors6,&Border7};
static struct Border Border5 = {12,35,2,0,JAM1,9,BorderVectors5,&Border6};
static struct Border Border4 = {12,96,2,0,JAM1,9,BorderVectors4,&Border5};
static struct Border Border3 = {12,20,2,0,JAM1,9,BorderVectors3,&Border4};
static struct Border Border2 = {126,5,2,0,JAM1,9,BorderVectors2,&Border3};
static struct Border Border1 = {12,5,2,0,JAM1,9,BorderVectors1,&Border2};

/* Info strukturer for katalog og fil- gadget'ene */

static struct StringInfo FileGadgetSInfo = {FileGadgetIBuff,NULL,0,31,0,0,0,0,0,0,0,0,NULL};
static struct StringInfo DrawerGadgetSInfo = {DrawerGadgetIBuff,NULL,0,257,0,0,0,0,0,0,0,0,NULL};

/* Info struktur til scrollbar'en */

static struct PropInfo DrawerPosGadgetSInfo = {AUTOKNOB|FREEVERT|PROPBORDERLESS,-1,0,0,0x1000,0,0,0,0,0,0};

/* Info struktur til teksten i 'Cancel' gadget'en */

static struct IntuiText CancelIText = {1,3,JAM2,19,2,NULL,"Cancel",NULL};

/* Info struktur til teksten i 'Ok' gadget'en */

static struct IntuiText OkIText = {1,3,JAM2,30,2,NULL,NULL,NULL};

static struct IntuiText outftext = {3,1,JAM2,14,39,NULL,outfbuff,NULL};

/* Dummy gadget's som brukes for automatisk tegning og fylling av
   file-requester vinduet. */

static struct Gadget Dummy1 = {
	NULL,0,0,1,1,
	GADGHBOX|GADGHIMAGE|GADGIMAGE,NULL,BOOLGADGET,
	(APTR)&Image1,NULL,NULL,NULL,NULL,NULL,NULL
};
static struct Gadget Dummy2 = {
	&Dummy1,0,0,1,1,
	GADGHBOX|GADGHIMAGE,NULL,BOOLGADGET,
	(APTR)&Border1,NULL,NULL,NULL,NULL,NULL,NULL
};

/* Fil-valg-linjene i requesteren */

static struct Gadget Line5Gadget = {			/* Linje 5 */
	&Dummy2,14,81,186,11,
	GADGIMAGE,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,12,NULL
};
static struct Gadget Line4Gadget = {			/* Linje 4 */
	&Line5Gadget,14,70,186,11,
	GADGIMAGE,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,11,NULL
};
static struct Gadget Line3Gadget = {			/* Linje 3 */
	&Line4Gadget,14,59,186,11,
	GADGIMAGE,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,10,NULL
};
static struct Gadget Line2Gadget = {			/* Linje 2 */
	&Line3Gadget,14,48,186,11,
	GADGIMAGE,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,9,NULL
};
static struct Gadget Line1Gadget = {			/* Linje 1 */
	&Line2Gadget,14,37,186,11,
	GADGIMAGE,RELVERIFY,BOOLGADGET,
	NULL,NULL,NULL,NULL,NULL,8,NULL
};
static struct Gadget FileGadget = {				/* Fil String */
	&Line1Gadget,19,99,204,9,
	GADGIMAGE,RELVERIFY,STRGADGET,
	NULL,NULL,NULL,NULL,(APTR)&FileGadgetSInfo,7,NULL
};
static struct Gadget DrawerGadget = {			/* Katalog String */
	&FileGadget,19,23,204,9,
	GADGIMAGE,RELVERIFY|GADGIMMEDIATE,STRGADGET,
	NULL,NULL,NULL,NULL,(APTR)&DrawerGadgetSInfo,6,NULL
};
static struct Gadget DrawerPosGadget = {		/* Scroll Bar */
	&DrawerGadget,209,49,19,31,
	GADGIMAGE,RELVERIFY|GADGIMMEDIATE|FOLLOWMOUSE,PROPGADGET,
	(APTR)&Image6,NULL,NULL,NULL,(APTR)&DrawerPosGadgetSInfo,5,NULL
};
static struct Gadget DownGadget = {				/* Ned pil */
	&DrawerPosGadget,209,81,19,11,
	GADGIMAGE,RELVERIFY|GADGIMMEDIATE,BOOLGADGET,
	(APTR)&DownImage,NULL,NULL,NULL,NULL,4,NULL
};
static struct Gadget UpGadget = {				/* Opp pil */
	&DownGadget,209,37,19,11,
	GADGIMAGE,RELVERIFY|GADGIMMEDIATE,BOOLGADGET,
	(APTR)&UpImage,NULL,NULL,NULL,NULL,3,NULL
};
static struct Gadget CancelGadget = {			/* Cancel */
	&UpGadget,128,6,100,11,
	NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,&CancelIText,NULL,NULL,2,NULL
};
static struct Gadget OkGadget = {				/* Ok */
	&CancelGadget,14,6,100,11,
	NULL,RELVERIFY,BOOLGADGET,
	NULL,NULL,&OkIText,NULL,NULL,1,NULL
};

#define GadgetList1 OkGadget

static struct NewWindow NewReqWindow = {
	159,55,242,114,3,2,
	GADGETDOWN|GADGETUP|MOUSEMOVE|VANILLAKEY,
	SMART_REFRESH|ACTIVATE|RMBTRAP,
	&GadgetList1,NULL,NULL,NULL,NULL,
	242,114,242,114,WBENCHSCREEN
};

/* Jeg bruker intuition funksjonen AllocRemeber til allokering av
   minne. Dette fordi alt minne som er allokert kan frigjøres med
   en gang med funksjonen FreeRember uten at jeg må holde en liste
   over hva jeg har allokert av minne. */

static struct Remember *memptr = NULL;

/* struktur som brukes til å lage en såkalt 'linked-list' av pekere
   til katalog informasjonen som leses fra disk. Dette gjør det mye
   enklere å sortere listen samtidig som den leses fra disk. */

static struct direntry {
	struct direntry *previous;
	struct direntry *next;
	short type;
	char *name;
} *DirPtr;

/* Funksjons deklarering */

int getfile(struct Screen *,BPTR,UBYTE *,char *);
int ReadDirectory(char *);
struct direntry *GetEntry(int);

/* Hoved rutinen */

int getfile(s,dirlock,okname,filename)
struct Screen *s;
BPTR dirlock;
UBYTE *okname;
char *filename;
{
	register struct Window *rqw;
	register struct RastPort *rp;
	register struct IntuiMessage *msg;
	register struct Gadget *gadget;
	register struct direntry *tptr;
#ifndef LATTICE_50
	USHORT *WaitSpritePtr = NULL;
#endif
	int rlen,i,gline,current;
	int posflag,error,intopened;
	long done,class;

	/* Hent fullt navn på katalogen som skal vises */

#ifdef LATTICE_50
	if (getpath(dirlock,DrawerGadgetIBuff) != NULL)
		goto abort;

	/* Hvis dette er rot-katalogen, føy til ':' */

	if (strchr(DrawerGadgetIBuff,'/') == NULL)
		if (strchr(DrawerGadgetIBuff,':') == NULL)
			strcat(DrawerGadgetIBuff,":");
#else
	DrawerGadgetIBuff[0] = '\0';	/* Set til current dir */
#endif

	/* registrer om vi åpner intuition, slik at vi kan stenge den
	   når vi er ferdig. */

	intopened = 0;

	if (IntuitionBase == NULL)
		if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)) == NULL)
			goto abort;
		else
			intopened = 1;

#ifndef LATTICE_50
	/* Hvis dette ikke er Lattice C versjon 5.0, har ikke denne versjonen
	   støtte for chip-minne. Vi må da allokere chip-minne og kopiere
	   Image dataene til chip-minnet. */

	if ((DownImage.ImageData = (USHORT *)AllocMem(sizeof(DownImageData),MEMF_CHIP)) == NULL)
		goto abort;

	if ((UpImage.ImageData = (USHORT *)AllocMem(sizeof(UpImageData),MEMF_CHIP)) == NULL)
		goto abort;

	if ((WaitSpritePtr = (USHORT *)AllocMem(sizeof(WaitSpriteData),MEMF_CHIP)) == NULL)
		goto abort;

	memcpy((char *)DownImage.ImageData,(char *)DownImageData,sizeof(DownImageData));
	memcpy((char *)UpImage.ImageData,(char *)UpImageData,sizeof(UpImageData));
	memcpy((char *)WaitSpritePtr,(char *)WaitSpriteData,sizeof(WaitSpriteData));
#endif

	OkIText.IText = okname;

	/* Sjekk om dette er en custom screen, i så fall må vindus dataene
	   endres for å tilpasses skjermen. */

	if (s == NULL) {
		NewReqWindow.Screen = NULL;
		NewReqWindow.Type = WBENCHSCREEN;
	}
	else {
		NewReqWindow.Screen = s;
		NewReqWindow.Type = CUSTOMSCREEN;

		if (s->Width > 320)
			NewReqWindow.LeftEdge = 199;
		else
			NewReqWindow.LeftEdge = 39;
	}

	/* Åpne vinduet til fil-requesteren */

	if ((rqw = OpenWindow(&NewReqWindow)) == NULL)
		goto abort;

	rp = rqw->RPort;

newdir:
	/* Slå på snorke-pointeren mens vi leser katalogen */

#ifndef LATTICE_50
	SetPointer(rqw,WaitSpritePtr,25,16,-4,-4);
#else
	SetPointer(rqw,(short *)&WaitSpriteData,25,16,-4,-4);
#endif

	/* Les katalogen */

	if ((rlen = ReadDirectory(DrawerGadgetIBuff)) == NULL)
		goto abort;

	/* Set pointeren tilbake til normal pil */

	ClearPointer(rqw);

	/* Juster høyden på scroll-baren i forhold til antall filer i
	   katalogen. */

	if (rlen <= 5)
		DrawerPosGadgetSInfo.VertBody = MAXBODY;
	else
		DrawerPosGadgetSInfo.VertBody = (MAXBODY / rlen) * 5;

	if (DrawerPosGadgetSInfo.VertBody < KNOBVMIN)
		DrawerPosGadgetSInfo.VertBody = KNOBVMIN;

	current = 0;

newpos:
	/* Juster posisjonen på scroll-baren i henhold til hvor vi befinner
	   oss i katalogen. */

	if (rlen > 5)
		DrawerPosGadgetSInfo.VertPot = (current * MAXBODY) / (rlen - 5);
	else
		DrawerPosGadgetSInfo.VertPot = 0;

	/* Oppdater gadget'en på skjermen */

	RemoveGadget(rqw,&DrawerPosGadget);
	AddGadget(rqw,&DrawerPosGadget,-1);

	ModifyProp(&DrawerPosGadget,rqw,NULL,DrawerPosGadgetSInfo.Flags,
				DrawerPosGadgetSInfo.HorizPot,
				DrawerPosGadgetSInfo.VertPot,
				DrawerPosGadgetSInfo.HorizBody,
				DrawerPosGadgetSInfo.VertBody);

newpos2:
	posflag = 0;
	tptr = GetEntry(current);

	/* Skriv de neste fem filnavnene i fil-requesteren. */

	for (i = 0; i < 5; i++) {
		/* Hvis vi er på slutten, blank resten av fil-navnene. */

		if (tptr == NULL) {
			strcpy(outfbuff,"                       ");
			outftext.FrontPen = 2;
		}
		else {
			outfbuff[0] = ' ';
			strncpy(&outfbuff[1],tptr->name,22);
			outfbuff[23] = '\0';

			while (strlen(outfbuff) < 23)
				strcat(outfbuff," ");

			/* Hvis dette er fil, katalog eller device merkene,
			   endre fargen til orange. Hvis ikke, set sort farge. */

			if (tptr->type == 1 || tptr->type == 3 || tptr->type == 6) {
				outftext.FrontPen = 3;

				if (i != 0)
					/* marker at en av merkene er i vinduet, og at det
					   ikke er det første merket, slik at vis brukeren
					   velger fil, katalog eller device merket, justeres
					   dette automatisk fra toppen. */

					if (tptr->type == 1)
						posflag |= 1;
					else if (tptr->type == 3)
						posflag |= 2;
					else
						posflag |= 4;
			}
			else
				outftext.FrontPen = 2;

			tptr = tptr->next;
		}

		PrintIText(rp,&outftext,0,i*11);
	}

	done = 0;	/* Vi er ikke ferdig enda. */

	do {
		/* Vent på melding fra intuition så vi får beskjed om hva det er
		   brukeren foretar seg. */

		while ((msg = (struct IntuiMessage *)GetMsg(rqw->UserPort)) == NULL)
			WaitPort(rqw->UserPort);

		gadget = (struct Gadget *)msg->IAddress;	/* Hent adressen til den
													   gadget'en som brukeren
													   eventuelt trykket på. */
		class = msg->Class;							/* Finn ut hva brukeren
													   gjorde. */
		ReplyMsg((struct Message *)msg);			/* Fortell intuition at vi
													   har mottatt meldingen. */

		/* Finn ut hva vi fikk melding om fra intuition */

		switch (class) {
			case MOUSEMOVE:
				/* Vi havner her nå brukeren flytter scroll-baren opp eller
				   ned slik at vi kan finne posisjonen i fil-katalogen. */
checkpos:
				i = (rlen - 5) * DrawerPosGadgetSInfo.VertPot / MAXBODY;

				if (i > (rlen - 5))
					i = rlen - 5;

				if (i < 0)
					i = 0;

				current = i;
				goto newpos2;
			case GADGETUP:
			case GADGETDOWN:
				/* Her har brukeren trykket på en gadget. */

				gline = 0;

				/* Vi skal nå finne ut vilken gadget */

				switch (gadget->GadgetID) {
					case 1:							/* Ok */
						done = 1;
						break;
					case 2:							/* Cancel */
						done = 2;
						break;
					case 3:							/* Up Arrow */
						if (current == 0 || class == GADGETUP)
							break;	/* Kan ikke flytte oppover vis vi
									   allerede er på toppen. */

						current--;
						goto newpos;
					case 4:							/* Down Arrow */
						if (class == GADGETUP)
							break;

						if ((current + 5) < rlen) {
							/* Vi kan bare flytte nedover vis vi ikke
							   allerede er på slutten av katalogen. */

							current++;
							goto newpos;
						}

						break;
					case 5:
						goto checkpos;
					case 6:							/* Drawer String */
						goto newdir;
					case 7:							/* File String */
						done = 1;
						break;
					case 12:						/* Line 5 */
						gline++;
					case 11:						/* Line 4 */
						gline++;
					case 10:						/* Line 3 */
						gline++;
					case 9:							/* Line 2 */
						gline++;
					case 8:							/* Line 1 */
						if ((current + gline) >= rlen)
							break;

						tptr = GetEntry(current + gline);

						switch (tptr->type) {
							case 1:
								/* Hopp til DIRECTORIES hvis ikke på toppen */

								if (posflag & 1)
									current = 0;
								else
									for (current = 0,tptr = DirPtr; tptr->type != 3; current++,tptr = tptr->next);

								goto newpos;
							case 2:
								/* Fil valgt */

								strcpy(FileGadgetIBuff,tptr->name);
								RemoveGadget(rqw,&FileGadget);
								AddGadget(rqw,&FileGadget,-1);
								RefreshGadgets(&FileGadget,rqw,NULL);
								break;
							case 3:
								/* Hopp til Device hvis ikke på toppen */

								if (posflag & 2)
									for (current = 0,tptr = DirPtr; tptr->type != 3; current++,tptr = tptr->next);
								else
									for (current = 0,tptr = DirPtr; tptr->type != 6; current++,tptr = tptr->next);

								goto newpos;
							case 4:
								/* Parent dir */

								for (i = strlen(DrawerGadgetIBuff); i >= 0; --i) {
									if (DrawerGadgetIBuff[i] == ':') {
										DrawerGadgetIBuff[i+1] = '\0';
										break;
									}

									if (DrawerGadgetIBuff[i] == '/') {
										DrawerGadgetIBuff[i] = '\0';
										break;
									}
								}

								goto refreshdrawer;
							case 5:
								/* Katalog valgt, les ny katalog */

								if (DrawerGadgetIBuff[strlen(DrawerGadgetIBuff)-1] != ':' && DrawerGadgetIBuff[0] != '\0')
									strcat(DrawerGadgetIBuff,"/");

								strcat(DrawerGadgetIBuff,tptr->name);

refreshdrawer:
								RemoveGadget(rqw,&DrawerGadget);
								AddGadget(rqw,&DrawerGadget,-1);

								if ((i = strlen(DrawerGadgetIBuff)) > 25)
									DrawerGadgetSInfo.DispPos = i - 25;
								else
									DrawerGadgetSInfo.DispPos = 0;

								DrawerGadgetSInfo.BufferPos =
									DrawerGadgetSInfo.UndoPos =
									DrawerGadgetSInfo.DispPos;
									DrawerGadgetSInfo.NumChars = i;

								RefreshGadgets(&DrawerGadget,rqw,NULL);
								RemoveGadget(rqw,&FileGadget);
								FileGadgetIBuff[0] = '\0';
								AddGadget(rqw,&FileGadget,-1);
								RefreshGadgets(&FileGadget,rqw,NULL);

								goto newdir;
							case 6:
								/* Gå til Files, hvis ikke på toppen */

								if (posflag & 4)
									for (current = 0,tptr = DirPtr; tptr->type != 6; current++,tptr = tptr->next);
								else
									current = 0;

								goto newpos;
							case 7:
								/* Nytt device valgt */

								strcpy(DrawerGadgetIBuff,tptr->name);
								goto refreshdrawer;
						}

						break;
				}
		}
	} while (done == 0);

	error = 0;
	goto done;

abort:
	error = 1;

done:
	if (memptr)
		FreeRemember(&memptr,TRUE);

	ClearPointer(rqw);

#ifndef LATTICE_50
	if (DownImage.ImageData)
		FreeMem(DownImage.ImageData,sizeof(DownImageData));

	if (UpImage.ImageData)
		FreeMem(UpImage.ImageData,sizeof(UpImageData));

	if (WaitSpritePtr)
		FreeMem(WaitSpritePtr,sizeof(WaitSpriteData));
#endif

	CloseWindow(rqw);

	if (intopened)
		CloseLibrary((struct Library *)IntuitionBase);

	if (error)
		return(2);	/* Error */

	if (done == 2)
		return(1);	/* Canceled */

	strcpy(filename,DrawerGadgetIBuff);

	if (DrawerGadgetIBuff[strlen(DrawerGadgetIBuff) - 1] != ':')
		strcat(filename,"/");

	strcat(filename,FileGadgetIBuff);
	return(0);		/* Ok */
}

static int ReadDirectory(dirname)
char *dirname;
{
	register struct FileInfoBlock *fib;
	register struct direntry *tptr,*newptr;
	register BPTR dir;
	register int count;
	register struct DosList *doslist;
	char *oname,*iname;
	int i,nlength;

	if (memptr)
		FreeRemember(&memptr,TRUE);

	memptr = NULL;

	if ((fib = (struct FileInfoBlock *)AllocRemember(&memptr,sizeof(struct FileInfoBlock),MEMF_PUBLIC)) == NULL)
		return(0);

	if ((DirPtr = (struct direntry *)AllocRemember(&memptr,sizeof(struct direntry),MEMF_PUBLIC)) == NULL)
		return(0);

	tptr = DirPtr;
	tptr->previous = NULL;
	tptr->type = 1;
	tptr->name = "      - FILES -";

	if ((tptr->next = (struct direntry *)AllocRemember(&memptr,sizeof(struct direntry),MEMF_PUBLIC)) == NULL)
		return(0);

	tptr->next->previous = tptr;
	tptr = tptr->next;
	tptr->type = 3;
	tptr->name = "   - DIRECTORIES -";

	if ((tptr->next = (struct direntry *)AllocRemember(&memptr,sizeof(struct direntry),MEMF_PUBLIC)) == NULL)
		return(0);

	tptr->next->previous = tptr;
	tptr = tptr->next;
	tptr->next = NULL;
	tptr->type = 4;
	tptr->name = "/ (Parent)";

	if ((dir = Lock(dirname,ACCESS_READ)) == NULL)
		return(0);

	if (Examine(dir,fib) == NULL)
		return(0);

	count = 3;

	while (ExNext(dir,fib) != NULL) {
		count++;

		if ((newptr = (struct direntry *)AllocRemember(&memptr,sizeof(struct direntry),MEMF_PUBLIC)) == NULL) {
			UnLock(dir);
			return(0);
		}

		if ((newptr->name = AllocRemember(&memptr,strlen(fib->fib_FileName)+1,MEMF_PUBLIC)) == NULL) {
			UnLock(dir);
			return(0);
		}

		strcpy(newptr->name,fib->fib_FileName);

		if (fib->fib_DirEntryType > 0)
			newptr->type = 5;
		else
			newptr->type = 2;

		for (tptr = DirPtr->next; ; tptr = tptr->next) {
			if (fib->fib_DirEntryType > 0) {
				if (tptr->type < 3)
					continue;

				if (tptr->type == 4 && tptr->next == NULL) {
					tptr->next = newptr;
					newptr->previous = tptr;
					newptr->next = NULL;
					break;
				}

				if (tptr->type == 3 || tptr->type == 4)
					continue;

				if (stricmp(tptr->name,newptr->name) >= 0) {
					newptr->previous = tptr->previous;
					newptr->next = tptr;
					tptr->previous->next = newptr;
					tptr->previous = newptr;
					break;
				}
				else if (tptr->next == NULL) {
					tptr->next = newptr;
					newptr->previous = tptr;
					newptr->next = NULL;
					break;
				}
			}
			else {
				if (tptr->type == 3) {
					newptr->previous = tptr->previous;
					newptr->next = tptr;
					tptr->previous->next = newptr;
					tptr->previous = newptr;
					break;
				}

				if (tptr->type > 2)
					break;

				if (stricmp(tptr->name,newptr->name) >= 0) {
					newptr->previous = tptr->previous;
					newptr->next = tptr;
					tptr->previous->next = newptr;
					tptr->previous = newptr;
					break;
				}
			}
		}
	}

	UnLock(dir);

	for (tptr = DirPtr; tptr->next != NULL; tptr = tptr->next);

	if ((tptr->next = (struct direntry *)AllocRemember(&memptr,sizeof(struct direntry),MEMF_PUBLIC)) == NULL)
		return(0);

	tptr->next->previous = tptr;
	tptr = tptr->next;
	tptr->next = NULL;
	tptr->type = 6;
	tptr->name = "     - VOLUMES -";
	count++;

	doslist = (struct DosList *)BADDR(((struct DosInfo *)
			BADDR(((struct RootNode *)((struct DosLibrary *)
			DOSBase)->dl_Root)->rn_Info))->di_DevInfo);

	while (doslist != NULL) {
		switch (doslist->dol_Type) {
			case DLT_DIRECTORY:
				break;
			case DLT_DEVICE:
				iname = (char *)BADDR(doslist->dol_Name);

				if (*iname++ == '\x03') {
					if (*iname++ == 'R') {
						if (*iname++ == 'A') {
							if (*iname == 'M') {
								goto ramdisk;
							}
						}
					}
				}

				if (doslist->dol_misc.dol_handler.dol_Startup < 0x100L)
					break;
			case DLT_VOLUME:
ramdisk:
				if ((newptr = (struct direntry *)AllocRemember(&memptr,sizeof(struct direntry),MEMF_PUBLIC)) == NULL)
					return(0);

				iname = (char *)BADDR(doslist->dol_Name);
				nlength = (int)*iname++;

				if ((newptr->name = AllocRemember(&memptr,nlength+2,MEMF_PUBLIC)) == NULL)
					return(0);

				count++;
				newptr->type = 7;
				oname = newptr->name;

				for (i = 0; i < nlength; i++)
					*oname++ = *iname++;

				*oname++ = ':';
				*oname = '\0';

				for (tptr = DirPtr; ; tptr = tptr->next) {
					if (tptr->type < 6)
						continue;

					if (tptr->type == 6 && tptr->next == NULL) {
						tptr->next = newptr;
						newptr->previous = tptr;
						newptr->next = NULL;
						break;
					}

					if (tptr->type == 6)
						continue;

					if (stricmp(tptr->name,newptr->name) >= 0) {
						newptr->previous = tptr->previous;
						newptr->next = tptr;
						tptr->previous->next = newptr;
						tptr->previous = newptr;
						break;
					}
					else if (tptr->next == NULL) {
						tptr->next = newptr;
						newptr->previous = tptr;
						newptr->next = NULL;
						break;
					}
				}

				break;
		}

		doslist = (struct DosList *)BADDR(doslist->dol_Next);
	}

	return(count);
}

static struct direntry *GetEntry(entrynum)
int entrynum;
{
	register struct direntry *tptr;
	register int i;

	for (tptr = DirPtr,i = 0; i < entrynum; i++,tptr = tptr->next)
		if (tptr->next == NULL)
			break;

	return(tptr);
}
