#define LARGE		0	/* 0 = width = 320, 1 = width = 640 */

/*
Copyright (c) 1986	AMWare Development & DesignTech Inc.

File Reqester Deluxe!	Version 1.2	for 1.2

Last modified:		Jan. 13, 1987

"Logic is a systematic method of coming to the wrong conclusion
 with confidence."


NAME
	FileRequest - request a file selection

SYNOPSIS
	string = FileRequest(screen, title, x, y, path, name, okname,
		extension, general_pointer, wait_pointer);

	UBYTE	*string;
	UBYTE	*FileRequest();
	struct Screen *screen;
	UBYTE	*title;
	UWORD	x, y;
	UBYTE	*path;
	UBYTE	*name;
	UBYTE	*okname;
	UBYTE	*extension;
	struct FRPointer *general_pointer;
	struct FRPointer *wait_pointer;

FUNCTION
	This function allows an application program to receive from
	the user a directory file selection.  File selection is made
	quite intuitively through the use of gadgets and mouse
	selections.

INPUTS
	screen = a pointer to the screen in which the file request
		window will appear;  NULL if WORKBENCHSCREEN
	title = pointer to the null-terminated string which the file
		request window will display;  the default is
		"File Requester"
	x, y = x and y coordinates of the top left corner of the file
		request window;  beware:  the width of the window is
		320 pixels and the height 180 pixels
	path = pointer to the null-terminated default directory path
		specification;  e.g. "df0:devs/printers", "ram:";
		if NULL, then defaults to the current directory

	name =	pointer to the null-terminated default filename;
		e.g. "filename","untitled",etc.
		if NULL, then no filename.

	okname = pointer to the null-terminated name for the "ok" gadget.
		e.g. "LOAD","SAVE","DELETE",etc.
		if NULL, then defaults to OK.

	extension = pointer to an extension.  e.g. "c","info",etc.
		only files with that extension & directories will
		be displayed.  If pattern = "" or NULL, all files
		are displayed.
	general_pointer = pointer to a FRPointer structure, which contains
		the data for the general use mouse pointer. NULL if use
		intuition default pointer.  See below for a description
		of the FRPointer structure.
	wait_pointer = pointer to a FRPointer stucture, which contains
		the data for a wait state mouse pointer. NULL if use
		general_pointer or standard pointer.  See below for a
		description of the FRPointer structure.


RESULT
	pointer (UBYTE *) to a null-terminated string containing the
		full path name of the selected file
	NULL if an error has occured or no file selection was made

NOTES
	Include the file FileRequest.h if you wish to define your own
	pointers for the file request use.  It might be a good idea to
	have at least a wait pointer, to let the user know that the
	program is busy.

	The FRPointer structure is as follows:

	struct FRPointer {
		UWORD *Pointer;
		WORD Height;
		WORD Width;
		WORD XOffset;
		WORD YOffset;
	};
	
	where	Pointer = pointer to the data definition of a Sprite
		Height = height of the pointer in pixels
		Width = width of the pointer
		XOffset = x offset of the sprite from the pointer "hot-spot"
		YOffset = y offset of the sprite from the pointer "hot-spot"

BUGS
	none (hopefully)

*/

/* Modification History *************************************************
 *									*
 * Date			By			Done			*
 * ----			--			----			*
 *									*
 * Nov. 15, 1986	Anson Mah		Completed preliminary	*
 *						internal version with	*
 *						Lattice version 3.03	*
 *									*
 * Nov. 18, 1986	Kris Hatlelid		Now works with Lattice	*
 *						version 3.10		*
 *									*
 * Nov. 19, 1986	Kris Hatlelid		Added recognition of	*
 *						dos devices, remove the	*
 *						gadget if device is not	*
 *						active.			*
 *									*
 *						Added LARGE definition	*
 *						allowing a 640*200	*
 *						window			*
 *									*
 * Nov. 20, 1986	Kris Hatlelid		Added Repeating Arrows	*
 *						for filebox via the	*
 *						GADGIMMEDIATE flag for	*
 *						the arrows and a flag	*
 *						for scrolling called	*
 *						ScrollFlag		*
 *									*
 *						Added "name" parameter	*
 *						for a default filename	*
 *						and "okname" parameter	*
 *						for the name of the OK	*
 *						gadget.			*
 *									*
 * Nov. 22, 1986	Kris Hatlelid		Added extension detect	*
 *									*
 * Jan. 02, 1987	Anson Mah		For LARGE = 0, names	*
 *						are device names, drive	*
 *						and parent gadgets are	*
 *						positioned properly	*
 *									*
 *						Centered okname in OK	*
 *						gadget			*
 *									*
 *						Requester/Window will	*
 *						open if a dos error	*
 *						occurs initially, but	*
 *						it will be cleared. At	*
 *						least there is a chance	*
 *						to correct and continue.*
 *									*
 *						To speed scrolling of	*
 *						filenames a bit, used	*
 *						Text() instead of Print-*
 *						IText().  Changes com-	*
 *						mented out in Display-	*
 *						List() and ListSelect()	*
 *									*
 *						Added string gadget for	*
 *						filename extension	*
 *									*
 *						Added ability to attach	*
 *						general purpose and	*
 *						wait state pointers.	*
 *						Needs FileRequest.h for	*
 *						proper use.		*
 *									*
 * Jan. 13, 1987	Anson Mah		rid of 3.10 specific	*
 *						calls;  do my own rou-	*
 *						tines where required	*
 *									*
 *						corrected extensions so	*
 *						the default extension	*
 *						is added to a file name	*
 *						entered by a user if no	*
 *						extension is supplied	*
 *						in the file name	*
 *									*
 ************************************************************************/



#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include "FileRequest.h"


/* ==================================================================== */
/* =========================  File Requester  ========================= */
/* ==================================================================== */


/* Global Variables */
STATIC struct IntuiMessage *msg;
STATIC struct Window *FileWindow;
STATIC struct RastPort *rp;
STATIC struct FileInfoBlock *fib;

#define DIRBUFSIZE	100
#define FILEBUFSIZE	35
#define MAXLIST		100
#define MAXDEVICES	7

STATIC UBYTE	dirbuf[DIRBUFSIZE],	/* buffer for directory string */
		filebuf[FILEBUFSIZE],	/* buffer for filename string */
		list[MAXLIST][FILEBUFSIZE];

#define MAXEXTENSIZE	15
STATIC UBYTE	extename[MAXEXTENSIZE];	/* buffer for file extension */

STATIC BOOL	entrytype[MAXLIST];
STATIC UBYTE	ScrollFlag;

STATIC UWORD
	listsize = 0,		/* size of file list */
	upsinglesize,		/* pot value for moving up one entry */
	downsinglesize,		/* pot value for moving down one entry */
	firstshown = MAXLIST;	/* first file at top of list area */
				/* kludge;  > 1 will do at this point */

STATIC UBYTE *device[] = { "RAM:", "DF0:", "DF1:", "DF2:", "DF3:", "DH0:",
			 "DH1:" };	/* standard Amiga devices */

STATIC UWORD  /* image data arrays */
	*dramoff = NULL,	*dramon = NULL,
	*ddriveoff = NULL,	*ddriveon = NULL,
	*dhdoff = NULL,		*dhdon = NULL,
	*duparrow = NULL,	*ddownarrow = NULL;

/* General purpose and wait state pointers */
STATIC struct FRPointer *gptr, *wptr;

/* Forward References */
VOID	CheckDevices(), DisplayList(), ResetList(), ClearListArea(),
	ExtendPath(), GetParentDir(), CloseUp(), StringCopyLen(),
	StringCopyPad(), CopyImage(), SortList(),
	GetExtension(), AddExtension();
BOOL	AllocStuff(), OpenFileWindow(), GetList(), GetDir(), ListSelect(),
	GetVolumeName();
UWORD	ProcessGadget(), MyAddGList();
UBYTE	*GetCurrentDir();

#define PEN0	0
#define PEN1	1
#define PEN2	2
#define PEN3	3

#define TYPE_DIR	1
#define TYPE_FILE	2

#if LARGE
#define FR_WIDTH	640	/* width of file request window */
#else
#define FR_WIDTH	320	/* width of file request window */
#endif

#define FR_HEIGHT	180	/* height of file request window */
#define WBARHEIGHT	9	/* height of window drag bar */
#define WBORDERWIDTH	1	/* width of window border */
#define LEFTEDGE	25	/* leftmost x for text and gadgets */

#define TOPOFLIST	60	/* y of top of list region */
#define BOTTOMOFLIST	149	/* y of bottom of list region */

#if LARGE
#define RIGHTOFLIST	266	/* x of right of list region */
#else
#define RIGHTOFLIST	178	/* x of right of list region */
#endif

#define MAXLISTSHOWN	11	/* max. size of list displayable */
#define CHARHEIGHT	8	/* height of character in pixels */

#if LARGE
#define LISTWIDTH	30	/* width of list area in characters */
#else
#define LISTWIDTH	19	/* width of list area in characters */
#endif

#define NUMGADGETS	16	/* total no. of gadgets */

#define GADWIDTH	64	/* actual image width in bits */
#define BGADWIDTH	60	/* width of the boolean gadgets */
#define BGADHEIGHT	10	/* height of the boolean gadgets */

#if LARGE
#define SGADWIDTH	256	/* width of the string gadgets */
#else
#define SGADWIDTH	200	/* width of the string gadgets */
#endif

#define SGADHEIGHT	8	/* height of the string gadgets */
#define RGADWIDTH	58	/* width of the ram: gadget */
#define RGADHEIGHT	17	/* height of the ram: gadget */
#define DGADWIDTH	56	/* width of the drive gadgets */
#define DGADHEIGHT	13	/* height of the drive gadgets */
#define HGADWIDTH	56	/* width of hard drive gadgets */
#define HGADHEIGHT	11	/* height of hard drive gadgets */
#define ARROWWIDTH	16	/* width of the arrow gadgets */
#define ARROWHEIGHT	11	/* height of the arrow gadgets */
#define PGADWIDTH	18	/* width of the proportional gadget */
#define PGADHEIGHT	70	/* height of the proportional gadget */
#define EGADWIDTH	32	/* width of extension string gadget */
#define EGADLEFT	LEFTEDGE + SGADWIDTH + 15

#if LARGE
#define DRIVELEFT	432	/* left pixel of drives */
#define PARENTLEFT	DRIVELEFT	/* left pixel of parent gadget */
#else
#define DRIVELEFT	210	/* left pixel of drives */
#define PARENTLEFT	DRIVELEFT + 30	/* left pixel of parent gadget */
#endif

/* The Gadgets */

#define G_PROP		0
#define G_DIRECTORY	1
#define G_FILENAME	2
#define G_CANCEL	3
#define G_OK		4
#define G_PARENT	5
#define G_UPARROW	6
#define G_DOWNARROW	7
#define G_RAM		8
#define G_DF0		9
#define G_DF1		10
#define G_DF2		11
#define G_DF3		12
#define G_DH0		13
#define G_DH1		14
#define G_EXTENSION	15


/* Border Coordinates */
STATIC WORD bgad_coords1[] = { -1,-1, -1,BGADHEIGHT, BGADWIDTH,BGADHEIGHT,
			BGADWIDTH,-1,  -1,-1 };
STATIC WORD bgad_coords2[] = { -2,-3, -2,BGADHEIGHT+2, BGADWIDTH+1,BGADHEIGHT+2,
			BGADWIDTH+1,-3, -2,-3 };
STATIC WORD sgad_coords[]  = { -1,-1, -1,SGADHEIGHT, SGADWIDTH,SGADHEIGHT,
			SGADWIDTH,-1, -1,-1 };
STATIC WORD egad_coords[]  = { -1,-1, -1,SGADHEIGHT, EGADWIDTH,SGADHEIGHT,
			EGADWIDTH,-1, -1,-1 };

STATIC struct Border fr_border[] = {
/* BOOL Gadget Borders */
	0, 0, PEN0, 0, JAM1, 5, bgad_coords1, NULL,
	0, 0, PEN3, 0, JAM1, 5, bgad_coords2, &fr_border[0],
/* STRING Gadget Borders */
	0, 0, PEN0, 0, JAM1, 5, sgad_coords, NULL,
/* Extension STRING Gadget Border */
	0, 0, PEN0, 0, JAM1, 5, egad_coords, NULL
};

/* File Requester Text */
STATIC struct TextAttr taPlain = { "topaz.font", 8, FS_NORMAL, FPF_ROMFONT };

STATIC struct IntuiText list_text = { PEN1, PEN0, JAM2, 0, 0, &taPlain, NULL, NULL };

/* name buffer for the OK gadget */

STATIC char okbuffer [10];
STATIC char defok [] = "OK";

STATIC struct IntuiText fr_text[] = {
	PEN0, PEN1, JAM1, LEFTEDGE, 15, &taPlain, "Directory:", NULL,
	PEN0, PEN1, JAM1, LEFTEDGE, 36, &taPlain, "File name:", &fr_text[0],
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "ram:", NULL,
#if LARGE
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "Drive 0", NULL,
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "Drive 1", NULL,
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "Drive 2", NULL,
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "Drive 3", NULL,
#else
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "df0:", NULL,
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "df1:", NULL,
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "df2:", NULL,
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "df3:", NULL,
#endif
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "dh0:", NULL,
	PEN0, PEN1, JAM1, 65, 2, &taPlain, "dh1:", NULL,
	PEN0, PEN1, JAM1,  7, 1, &taPlain, "Cancel", NULL,
	PEN0, PEN1, JAM1, 21, 1, &taPlain, okbuffer, NULL,
	PEN0, PEN1, JAM1,  7, 1, &taPlain, "Parent", NULL,
	PEN0, PEN1, JAM1, EGADLEFT, 36, &taPlain, "Ext:", &fr_text[1]
};

/* Gadget Image Info */

STATIC UWORD gramoff[] = {
	0xFFF0,0xFFFF,0xFFFF,0xFFFF,
	0xFF00,0x3FF,0xFFFF,0xFFFF,
	0xF000,0xF,0xFFFF,0xFFFF,
	0x3E00,0x0,0x3FFF,0xFFFF,
	0x3F0,0x0,0xFF,0xFFFF,
	0x3C0F,0xC000,0x3,0xFFFF,
	0x30F0,0x3F00,0x0,0xFFF,
	0x30C3,0xC0FC,0x0,0x33F,
	0xFCC3,0xF03,0xF000,0x3C3F,
	0xFFF3,0xC3C,0xFC3,0xC03F,
	0xFFFF,0xCC30,0xF03C,0x3F,
	0xFFFF,0xFF30,0xC3C8,0x3F,
	0xFFFF,0xFFFC,0xC308,0x3FF,
	0xFFFF,0xFFFF,0xF308,0x3FFF,
	0xFFFF,0xFFFF,0xFFCB,0xFFFF,
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,

	0xF,0x0,0x0,0x0,
	0xFF,0xFC00,0x0,0x0,
	0xFFF,0xFFF0,0x0,0x0,
	0xC1FF,0xFFFF,0xC000,0x0,
	0xFC0F,0xFFFF,0xFF00,0x0,
	0xF3F0,0x3FFF,0xFFFC,0x0,
	0xFFCF,0xC0FF,0xFFFF,0xF000,
	0xFFFF,0x3F03,0xFFFF,0xFCC0,
	0x33FF,0xFCFC,0xFFF,0xC3C0,
	0x30CF,0xFFF3,0xF03C,0x3FC0,
	0x30C3,0x3FFF,0xCFC3,0xFFC0,
	0xC3,0xCFF,0xFF37,0xFFC0,
	0x3,0xC33,0xFFF7,0xFE00,
	0x0,0xC30,0xCFF7,0xC600,
	0x0,0x30,0xC334,0x0,
	0x0,0x0,0xC300,0x0,
	0x0,0x0,0x300,0x0
};


STATIC UWORD gramon[] = {
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,
	0xFFFF,0xFFFF,0xFFFF,0xFFFF,
	0xCFFF,0xFFFF,0xFFFF,0xFFFF,
	0xCF3F,0xFFFF,0xFFFF,0xFFFF,
	0xCF3C,0xFFFF,0xFFFF,0xFFFF,
	0xCF3C,0xF3FF,0xFFFF,0xFFFF,
	0xCF3C,0xF3CF,0xFFFF,0xFFFF,
	0xCF3C,0xF3CF,0x3FFF,0xFFFF,
	0xFF3C,0xF3CF,0x3CFF,0xFFFF,
	0xFFFC,0xF3CF,0x3CFF,0xFDFF,
	0xFFFF,0xF3CF,0x3CFF,0xF9FF,
	0xFFFF,0xFFCF,0x3CFF,0xFFFF,
	0xFFFF,0xFFFF,0x3CFF,0xFFFF,
	0xFFFF,0xFFFF,0xFCFF,0xFFFF,

	0xF,0x0,0x0,0x0,
	0xFF,0xFC00,0x0,0x0,
	0xFFF,0xFFF0,0x0,0x0,
	0xC1FF,0xFFFF,0xC000,0x0,
	0xFC0F,0xFFFF,0xFF00,0x0,
	0xF3F0,0x3FFF,0xFFFC,0x0,
	0xFFCF,0xC0FF,0xFFFF,0xF000,
	0xFFFF,0x3F03,0xFFFF,0xFCC0,
	0x33FF,0xFCFC,0xFFF,0xC3C0,
	0x30CF,0xFFF3,0xF03C,0x3FC0,
	0x30C3,0x3FFF,0xCFC3,0xFFC0,
	0xC3,0xCFF,0xFF37,0xFFC0,
	0x3,0xC33,0xFFF7,0xFE00,
	0x0,0xC30,0xCFF7,0xC600,
	0x0,0x30,0xC334,0x0,
	0x0,0x0,0xC300,0x0,
	0x0,0x0,0x300,0x0
};


STATIC UWORD gdriveoff[] = {
	0xC000,0x0,0x0,0xFF,
	0x3FFF,0xFFFF,0xFFFF,0xFF3F,
	0x3FFF,0xF000,0x3FF,0xFF3F,
	0x3FFF,0xF7FF,0xFBFF,0xFF3F,
	0x3FFF,0xF780,0x7BFF,0xFF3F,
	0x3FE0,0x0,0x1,0xFF3F,
	0x3FFF,0xF780,0x7BFF,0xFF3F,
	0x3FFF,0xF780,0x7B81,0xFF3F,
	0x3FFF,0xF7FF,0xFBFF,0xFF3F,
	0x3FFF,0xF7FF,0xFBFF,0xFF3F,
	0x3000,0x0,0x0,0x33F,
	0x3FFF,0xFFFF,0xFFFF,0xFF3F,
	0xC000,0x0,0x0,0xFF,

	0x3FFF,0xFFFF,0xFFFF,0xFF00,
	0xC000,0x0,0x0,0xC0,
	0xC000,0xFFF,0xFC00,0xC0,
	0xC000,0x800,0x400,0xC0,
	0xC000,0x87F,0x8400,0xC0,
	0xC01F,0xFFFF,0xFFFE,0xC0,
	0xC000,0x87F,0x8400,0xC0,
	0xC000,0x87F,0x847E,0xC0,
	0xC000,0x800,0x400,0xC0,
	0xC000,0x800,0x400,0xC0,
	0xCFFF,0xFFFF,0xFFFF,0xFCC0,
	0xC000,0x0,0x0,0xC0,
	0x3FFF,0xFFFF,0xFFFF,0xFF00
};


STATIC UWORD gdriveon[] = {
	0xC000,0x0,0x0,0xFF,
	0x3FFF,0xFFFF,0xFFFF,0xFF3F,
	0x3FFF,0xF000,0x3FF,0xFF3F,
	0x3FFF,0xF7FF,0xFBFF,0xFF3F,
	0x3FFF,0xF780,0x7BFF,0xFF3F,
	0x3FE0,0x0,0x1,0xFF3F,
	0x3FFF,0xF780,0x7BFF,0xFF3F,
	0x3FFF,0xF780,0x7B81,0xFF3F,
	0x3FFF,0xF7FF,0xFBFF,0xFF3F,
	0x3FFF,0xF7FF,0xFBFF,0xFF3F,
	0x3000,0x0,0x1,0xFB3F,
	0x3FFF,0xFFFF,0xFFFF,0xFF3F,
	0xC000,0x0,0x0,0xFF,

	0x3FFF,0xFFFF,0xFFFF,0xFF00,
	0xC000,0x0,0x0,0xC0,
	0xC000,0xFFF,0xFC00,0xC0,
	0xC000,0x800,0x400,0xC0,
	0xC000,0x87F,0x8400,0xC0,
	0xC01F,0xFFFF,0xFFFE,0xC0,
	0xC000,0x87F,0x8400,0xC0,
	0xC000,0x87F,0x847E,0xC0,
	0xC000,0x800,0x400,0xC0,
	0xC000,0x800,0x400,0xF0C0,
	0xCFFF,0xFFFF,0xFFFF,0xFCC0,
	0xC000,0x0,0x0,0xF0C0,
	0x3FFF,0xFFFF,0xFFFF,0xFF00
};


STATIC UWORD ghdoff[] = {
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x7F1,0xFC7F,0x1FC7,0xF07F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,

	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xF80E,0x380,0xE038,0xF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80
};



STATIC UWORD ghdon[] = {
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x0,0x7F,
	0x0,0x0,0x3,0x807F,
	0x7F1,0xFC7F,0x1FC7,0xF07F,
	0x0,0x0,0x3,0x807F,
	0x0,0x0,0x0,0x7F,

	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xF80E,0x380,0xE03F,0xCF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80,
	0xFFFF,0xFFFF,0xFFFF,0xFF80
};


STATIC UWORD guparrow[] = {
	0xFFFF,
	0x8001,
	0x8181,
	0x83C1,
	0x87E1,
	0x8FF1,
	0x9FF9,
	0x83C1,
	0x83C1,
	0x8001,
	0xFFFF
};

STATIC UWORD gdownarrow[] = {
	0xFFFF,
	0x8001,
	0x83C1,
	0x83C1,
	0x9FF9,
	0x8FF1,
	0x87E1,
	0x83C1,
	0x8181,
	0x8001,
	0xFFFF
};



STATIC struct Image iramoff   = { 0, 0, 64, 17, 2, &gramoff[0],   0x03, 0x00, NULL };
STATIC struct Image iramon    = { 0, 0, 64, 17, 2, &gramon[0],    0x03, 0x00, NULL };
STATIC struct Image idriveoff = { 0, 0, 64, 13, 2, &gdriveoff[0], 0x03, 0x00, NULL };
STATIC struct Image idriveon  = { 0, 0, 64, 13, 2, &gdriveon[0],  0x03, 0x00, NULL };
STATIC struct Image ihdoff    = { 0, 0, 64, 11, 2, &ghdoff[0],    0x03, 0x00, NULL };
STATIC struct Image ihdon     = { 0, 0, 64, 11, 2, &ghdon[0],     0x03, 0x00, NULL };
STATIC struct Image iuparrow  = { 0, 0, 16, 11, 1, &guparrow[0],  0x01, 0x00, NULL };
STATIC struct Image idownarrow= { 0, 0, 16, 11, 1, &gdownarrow[0],0x01, 0x00, NULL };


/* Gadget Definitions */

STATIC struct StringInfo fr_strinfo[] = {

/* Directory Gadget */
	dirbuf, NULL, 0, DIRBUFSIZE, 0, 0, 0, 0, 0, 0, NULL, 0L, NULL,
/* Filename Gadget */
	filebuf, NULL, 0, FILEBUFSIZE, 0, 0, 0, 0, 0, 0, NULL, 0L, NULL,
/* Extension Gadget */
	extename, NULL, 0, MAXEXTENSIZE, 0, 0, 0, 0, 0, 0, NULL, 0L, NULL
};

STATIC struct PropInfo fr_propinfo = {
	AUTOKNOB | FREEVERT, 0, 0, 0, MAXBODY, 0, 0, 0, 0, 0, 0
};

STATIC struct Image kludge;	/* for prop gadget.... why??? */

STATIC struct Gadget fr_gadget[] = {

/* Proportional */
	&fr_gadget[G_DIRECTORY], RIGHTOFLIST+1, 70, PGADWIDTH, PGADHEIGHT,
	GADGHCOMP, FOLLOWMOUSE, PROPGADGET, (APTR)&kludge,
	NULL, NULL, 0, (APTR)&fr_propinfo, G_PROP, NULL,
/* Directory */
	&fr_gadget[G_FILENAME], LEFTEDGE, 25, SGADWIDTH, SGADHEIGHT, GADGHCOMP,
	RELVERIFY, STRGADGET, (APTR)&fr_border[2], NULL,
	NULL, 0, (APTR)&fr_strinfo[0], G_DIRECTORY, NULL,
/* File */
	NULL, LEFTEDGE, 46, SGADWIDTH, SGADHEIGHT,
	GADGHCOMP, RELVERIFY, STRGADGET, (APTR)&fr_border[2], NULL,
	NULL, 0, (APTR)&fr_strinfo[1], G_FILENAME, NULL,
/* Cancel */
	NULL, 116, 160, BGADWIDTH, BGADHEIGHT, GADGHCOMP,
	RELVERIFY, BOOLGADGET, (APTR)&fr_border[1], NULL,
	&fr_text[9], 0, NULL, G_CANCEL, NULL,
/* OK */
	NULL, LEFTEDGE, 160, BGADWIDTH, BGADHEIGHT,
	GADGHCOMP, RELVERIFY, BOOLGADGET, (APTR)&fr_border[1], NULL,
	&fr_text[10], 0, NULL, G_OK, NULL,
/* Parent Dir */
	NULL, PARENTLEFT, 21, BGADWIDTH, BGADHEIGHT,
	GADGHCOMP, RELVERIFY, BOOLGADGET, (APTR)&fr_border[1], NULL,
	&fr_text[11], 0, NULL, G_PARENT, NULL,
/* Up arrow */
	NULL, RIGHTOFLIST+2, 60, ARROWWIDTH, ARROWHEIGHT,
	GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET, (APTR)&iuparrow,
	NULL, NULL, 0, NULL, G_UPARROW, NULL,
/* Down arrow */
	NULL, RIGHTOFLIST+2, 139, ARROWWIDTH, ARROWHEIGHT,
	GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET, (APTR)&idownarrow,
	NULL, NULL, 0, NULL, G_DOWNARROW, NULL,
/* RAM: */
	NULL, DRIVELEFT, 60,
	RGADWIDTH, RGADHEIGHT, GADGHIMAGE | GADGIMAGE,
	RELVERIFY | TOGGLESELECT, BOOLGADGET, (APTR)&iramoff, (APTR)&iramon,
	&fr_text[2], 0, NULL, G_RAM, NULL,
/* DF0: */
	NULL, DRIVELEFT, 60 + RGADHEIGHT + 3,
	DGADWIDTH, DGADHEIGHT, GADGHIMAGE | GADGIMAGE,
	RELVERIFY | TOGGLESELECT, BOOLGADGET, (APTR)&idriveoff, (APTR)&idriveon,
	&fr_text[3], 0, NULL, G_DF0, NULL,
/* DF1: */
	NULL, DRIVELEFT, 60 + RGADHEIGHT + 3 + DGADHEIGHT + 3,
	DGADWIDTH, DGADHEIGHT, GADGHIMAGE | GADGIMAGE,
	RELVERIFY | TOGGLESELECT, BOOLGADGET, (APTR)&idriveoff, (APTR)&idriveon,
	&fr_text[4], 0, NULL, G_DF1, NULL,
/* DF2: */
	NULL, DRIVELEFT, 60 + RGADHEIGHT + 3 + 2 * (DGADHEIGHT + 3),
	DGADWIDTH, DGADHEIGHT, GADGHIMAGE | GADGIMAGE,
	RELVERIFY | TOGGLESELECT, BOOLGADGET, (APTR)&idriveoff, (APTR)&idriveon,
	&fr_text[5], 0, NULL, G_DF2, NULL,
/* DF3: */
	NULL, DRIVELEFT, 60 + RGADHEIGHT + 3 + 3 * (DGADHEIGHT + 3),
	DGADWIDTH, DGADHEIGHT, GADGHIMAGE | GADGIMAGE,
	RELVERIFY | TOGGLESELECT, BOOLGADGET, (APTR)&idriveoff, (APTR)&idriveon,
	&fr_text[6], 0, NULL, G_DF3, NULL,
/* DH0: */
	NULL, DRIVELEFT, 60 + RGADHEIGHT + 3 + 4 * (DGADHEIGHT + 3),
	HGADWIDTH, HGADHEIGHT, GADGHIMAGE | GADGIMAGE,
	RELVERIFY | TOGGLESELECT, BOOLGADGET, (APTR)&ihdoff, (APTR)&ihdon,
	&fr_text[7], 0, NULL, G_DH0, NULL,
/* DH1: */
	NULL, DRIVELEFT, 60 + RGADHEIGHT + 3 + 4 * (DGADHEIGHT + 3) + HGADHEIGHT + 3,
	HGADWIDTH, HGADHEIGHT, GADGHIMAGE | GADGIMAGE,
	RELVERIFY | TOGGLESELECT, BOOLGADGET, (APTR)&ihdoff, (APTR)&ihdon,
	&fr_text[8], 0, NULL, G_DH1, NULL,
/* Extension */
	NULL, EGADLEFT, 46, EGADWIDTH, SGADHEIGHT,
	GADGHCOMP, RELVERIFY, STRGADGET, (APTR)&fr_border[3], NULL,
	NULL, 0, (APTR)&fr_strinfo[2], G_EXTENSION, NULL
};


/* Requester Window Definition */

STATIC struct NewWindow fr_window = {
	0, 0,			/* LeftEdge, TopEdge; defined later */
	FR_WIDTH, FR_HEIGHT,	/* Width, Height */
	PEN0, PEN1,		/* DetailPen, BlockPen */
	GADGETUP | GADGETDOWN | MOUSEBUTTONS | MOUSEMOVE, /* IDCMPFlags */
	ACTIVATE | SMART_REFRESH | WINDOWDRAG | RMBTRAP, /* Flags */
	NULL,			/* Gadgets: added later */
	NULL,			/* CheckMark */
	"File Requester",	/* Title; default */
	NULL,			/* Screen; default */
	NULL,			/* BitMap */
	0, 0, 640, 320,		/* MinWidth, MinHeight, MaxWidth, MaxHeight */
	WBENCHSCREEN		/* Type */
};



/* FileRequest entry point */

UBYTE *FileRequest(screen, title, x, y, path, name, okname, extension,
	general_pointer, wait_pointer)
struct Screen *screen;
UBYTE	*title;
UBYTE	*path;
UWORD	x, y;
UBYTE	*name;
UBYTE	*okname;
UBYTE	*extension;
struct FRPointer *general_pointer;
struct FRPointer *wait_pointer;
{
	ULONG	msg_class;
	UWORD	msg_code, gad;
	struct Gadget *gadget;

	ScrollFlag = NULL;

	if ( !AllocStuff()) {		/* allocate memory and set up */
		CloseUp();		/* images in chip memory */
		return(NULL);
	}
	if (screen) {
		fr_window.Screen = screen;
		fr_window.Type   = CUSTOMSCREEN;
	}
	if (title)
		fr_window.Title  = title;
	if (path) {
		strcpy(dirbuf, path);
		if (dirbuf[0] == NULL) strcpy (dirbuf, GetCurrentDir () );
	} else
		strcpy(dirbuf, GetCurrentDir() );

	if (name)
		strcpy(filebuf, name);
	else
		strcpy(filebuf, "");
/*		strcpy("",name);	Kris's line, no comprendo! */

	if (okname) {
		strcpy(okbuffer, okname);
		fr_text[10].LeftEdge = (BGADWIDTH - IntuiTextLength(&fr_text[10])) / 2;
	} else
		strcpy(okbuffer, defok);

	if (extension)
		strcpy (extename,extension);
	else
		strcpy (extename,"");

	fr_window.LeftEdge = x;
	fr_window.TopEdge  = y;

	if (!OpenFileWindow()) {
		CloseUp();
		return(NULL);
	}
	gptr = general_pointer;
	wptr = wait_pointer;

	if (general_pointer)
		SetPointer(FileWindow, gptr->Pointer, gptr->Height,
			gptr->Width, gptr->XOffset, gptr->YOffset);

	ActivateGadget(&fr_gadget[G_FILENAME],FileWindow,NULL);

	if( !GetList())
		ResetList();

	FOREVER
	{
		if ((msg = (struct IntuiMessage *)
			GetMsg(FileWindow->UserPort)) == NULL)
		{
			if (ScrollFlag == NULL)
			{
				Wait( 1 << FileWindow->UserPort->mp_SigBit);
				continue;
			}
			else ProcessGadget (ScrollFlag,2);
		}
		else
		{
		msg_class = msg->Class;
		msg_code  = msg->Code;
		x = msg->MouseX;
		y = msg->MouseY;

		/* if Class is not MOUSEBUTTONS, a gadget was chosen */
		if (msg_class != MOUSEBUTTONS)
			gadget = (struct Gadget *)(msg->IAddress);
		ReplyMsg(msg);

		switch(msg_class) {
 			case GADGETUP:
				gad = ProcessGadget(gadget->GadgetID,0);
				if (gad == G_CANCEL) {
					CloseUp();
					return(NULL);
				} else
					if (gad == G_OK) {
						CloseUp();
						return(dirbuf);
					}
				break;

			case GADGETDOWN:
				gad = ProcessGadget(gadget->GadgetID,1);
				break;

			case MOUSEBUTTONS:
				if (msg_code == SELECTDOWN)
				  if ((x > LEFTEDGE) && (x < RIGHTOFLIST) &&
				     (y > TOPOFLIST) && (y < BOTTOMOFLIST - 1))
					if (ListSelect(y)) {
						CloseUp();
						return(dirbuf);
					}
				if (msg_code == SELECTUP) ScrollFlag = NULL;
				break;
			case MOUSEMOVE:
				DisplayList();
				break;
		} /* switch */
		if (ScrollFlag != NULL)  ProcessGadget(ScrollFlag, 2);
		} /* else */
	} /* FOREVER */
}



STATIC UWORD ProcessGadget(gadid, flag)
UWORD	gadid;
UBYTE   flag;
{
	struct PropInfo *prop;
	UBYTE	tempdir[DIRBUFSIZE];

	if (gadid >= G_RAM)
		strcpy(tempdir, dirbuf);

	switch (gadid) {

		case G_CANCEL:
			return(G_CANCEL);
			break;
		case G_OK:
			if (filebuf[0] == '\0')
				return(G_CANCEL);
			ExtendPath(filebuf);
			return(G_OK);
			break;
		case G_PARENT:
			GetParentDir();
			break;
		case G_DIRECTORY:
			if ( !GetList()) {
				ResetList();
				if (filebuf[0] != '\0') {
					strcpy(filebuf, "");
					RefreshGadgets(&fr_gadget[G_FILENAME], FileWindow, NULL);
				}
			}
			break;
		case G_FILENAME:
			if (filebuf[0] == '\0')
				return(gadid);
			if (extename[0] != '\0')
				AddExtension(filebuf);	/* if needed */
			ExtendPath(filebuf);
			return(G_OK);
			break;
		case G_EXTENSION:
			strcpy(filebuf, "");
			RefreshGadgets(&fr_gadget[G_FILENAME], FileWindow, NULL);
			if (!GetList())
				ResetList();
			break;
		case G_UPARROW:
			if (flag == 1) ScrollFlag = G_UPARROW;
			if (flag == 0) ScrollFlag = NULL;
			if (flag > 1)
			{
			prop = (struct PropInfo *)fr_gadget[G_PROP].SpecialInfo;
			if (prop->VertPot < upsinglesize)
				prop->VertPot = 0;
			else {
				prop->VertPot -= upsinglesize;
				if (prop->VertPot < upsinglesize)
					prop->VertPot = 0;
			}
			RefreshGadgets(&fr_gadget[G_PROP], FileWindow, NULL);
			DisplayList();
			}
			break;
		case G_DOWNARROW:
			if (flag == 0) ScrollFlag = NULL;
			if (flag == 1) ScrollFlag = G_DOWNARROW;
			if (flag > 1)
			{
			prop = (struct PropInfo *)fr_gadget[G_PROP].SpecialInfo;
			if ((MAXPOT - prop->VertPot) <= downsinglesize)
				prop->VertPot = MAXPOT;
			else
				prop->VertPot += downsinglesize;
			RefreshGadgets(&fr_gadget[G_PROP], FileWindow, NULL);
			DisplayList();
			}
			break;

		case G_RAM:
		case G_DF0:
		case G_DF1:
		case G_DF2:
		case G_DF3:
		case G_DH0:
		case G_DH1:
			fr_gadget[gadid].Flags ^= SELECTED;
			if (GetVolumeName(dirbuf, device[gadid - G_RAM])) {
				if (gadid == G_RAM)
					strcpy(dirbuf, "ram:");
				strcpy(filebuf, "");
	  			fr_strinfo[0].NumChars = strlen(dirbuf); /* 1.1 kludge */
				if (GetList()) {
					fr_strinfo[1].NumChars = strlen(filebuf);
				RefreshGadgets(&fr_gadget[G_FILENAME], FileWindow, NULL);
				} else
					strcpy(dirbuf, tempdir);
			}
			RefreshGadgets(&fr_gadget[gadid], FileWindow, NULL);
			break;
	} /* switch */

	return(gadid);
}



STATIC BOOL OpenFileWindow()
{
	UWORD	pos;

	if ((FileWindow = (struct Window *)OpenWindow(&fr_window)) == NULL) {
		puts("Couldn't open window!");
		return(FALSE);
	}

	rp = FileWindow->RPort;

	SetAPen(rp, PEN1);
	SetOPen(rp, PEN0);
	RectFill(rp, WBORDERWIDTH + 2, WBARHEIGHT + 1,
		FR_WIDTH - WBORDERWIDTH - 3, FR_HEIGHT - 2);

	SetAPen(rp, PEN0);
	/* print all the requester labels */
	PrintIText(rp, &fr_text[12], 0, 0);

	ClearListArea(MAXLISTSHOWN);

	CheckDevices ();

	pos = MyAddGList(FileWindow,
		&fr_gadget[NUMGADGETS-1], 100, NUMGADGETS, NULL);

	return(TRUE);
}


STATIC VOID CheckDevices()
/* checks to see what devices are hooked up to the Ami
 * and kill the gadgets of those not present.  Will detect
 * only the standard Ami devices listed earlier in the code.
 */
{
	struct DosLibrary *node;
	struct RootNode *rootnode;
	struct DosInfo *dosinfo;
	struct DeviceList *devicelist;
	UWORD	i;
	UBYTE flag;
	char *name;
	long type;
	UBYTE count;
	UWORD numchrs;
	register int x;
	register int j;
	STATIC UBYTE namearray [20][10];

	node = (struct DosLibrary *) OpenLibrary ("dos.library",NULL);
	/* should check for node == null */
	rootnode = (struct RootNode *) node->dl_Root;
	dosinfo = (struct DosInfo *) (((ULONG) rootnode->rn_Info) << 2);
	devicelist = (struct DeviceList *)
			 (((ULONG) dosinfo->di_DevInfo) << 2); 
	count = 0;
	while (devicelist != NULL)
	{
		type = devicelist->dl_Type;
		if (type == 0)
		{
			name = (char *) (((ULONG)devicelist->dl_Name) << 2);
			numchrs = *name;
			for (x=0;x<numchrs;x++)
			{
				++name;
				namearray [count][x] = *name;
			}
			namearray [count][x] = ':';
			namearray [count][x+1] = 0;
			count ++;
		}
		devicelist = (struct DeviceList *)
				(((ULONG) devicelist->dl_Next) << 2);
	}

	/* start check at 2, df0: & ram always present! */
	for (i = 2; i < MAXDEVICES; i++)
	{
		flag = 0;
		for (x=0;x<count;x++)
		{
			if (strcmp (device[i],namearray[x]) == 0) flag = 1;
		}
		if (flag == 0)
		{
			  
			fr_gadget[G_RAM+i].GadgetRender = NULL;
			fr_gadget[G_RAM+i].SelectRender = NULL;
			fr_gadget[G_RAM+i].GadgetText = NULL;
			fr_gadget[G_RAM+i].Activation = GADGDISABLED;
			for (j=G_RAM+i;j<G_DH1;j++)
			{
				if (fr_gadget[j].TopEdge != 0)
				  fr_gadget[j+1].TopEdge = fr_gadget[j].TopEdge;
			}
			fr_gadget[G_RAM+i].LeftEdge = 0;
			fr_gadget[G_RAM+i].TopEdge = 0;
			fr_gadget[G_RAM+i].Width = 0;
			fr_gadget[G_RAM+i].Height = 0;
		}
	}
	if (node != NULL) CloseLibrary (node);
}



STATIC BOOL GetList()
/* get the directory and put into the file list
 * -- higher level than the function just below
 */
{
	FLOAT	body;

	if ( !GetDir())
		return(FALSE);

	if (listsize <= MAXLISTSHOWN) {
		body = MAXBODY;
		upsinglesize = 0;
		downsinglesize = 0;
	} else {
		body = (FLOAT)MAXBODY / ( ((FLOAT)listsize) / (FLOAT)MAXLISTSHOWN);
		upsinglesize = MAXBODY / (listsize - MAXLISTSHOWN);
		downsinglesize = MAXBODY / (listsize - MAXLISTSHOWN);
		/* need these next lines just so that downsinglesize */
		/* won't end up being MAXBODY++, a no-no */
		if (downsinglesize != MAXBODY)
			downsinglesize++;
	}
	((struct PropInfo *)
		fr_gadget[G_PROP].SpecialInfo)->VertPot  = 0;
	((struct PropInfo *)
		fr_gadget[G_PROP].SpecialInfo)->VertBody = (UWORD)body;

	ClearListArea(MAXLISTSHOWN);

	firstshown = MAXLIST;		/* kludge to force display */
	DisplayList();

	RefreshGadgets(&fr_gadget[G_PROP], FileWindow, NULL);

	return(TRUE);
}


STATIC BOOL GetDir()
/* load up the directory, just like the proc name says! */
{
	struct FileLock *lock, *Lock();
	STATIC UBYTE extension[MAXEXTENSIZE];

	if ((lock = Lock(dirbuf, ACCESS_READ)) == NULL)
		return(FALSE);

	listsize = 0;

	if (wptr)	/* set wait pointer if available */
		SetPointer(FileWindow, wptr->Pointer, wptr->Height,
			wptr->Width, wptr->XOffset, wptr->YOffset);

	Examine(lock, fib);

	while (ExNext(lock, fib)) {
		if (fib->fib_DirEntryType > 0)
			entrytype[listsize] = TYPE_DIR;
		else
			entrytype[listsize] = TYPE_FILE;

		strcpy(list[listsize], fib->fib_FileName);

		if (extename[0] != NULL && entrytype[listsize] != TYPE_DIR) {
			GetExtension(list[listsize], extension);
			if (strcmp(extename, extension)) listsize--;
		}
		listsize++;
	
		if (listsize >= MAXLIST)
			break;
	}
	SortList(listsize);

	if (wptr)	/* reset pointer if changed earlier */
		if (gptr)	/* if general_pointer exists */
			SetPointer(FileWindow, gptr->Pointer, gptr->Height,
				gptr->Width, gptr->XOffset, gptr->YOffset);
		else	/* back to standard pointer */
			ClearPointer(FileWindow);

	return(TRUE);
}



STATIC VOID DisplayList()
/* display the list in the proper position after such things
 * as scrolling, etc.
 */
{
	UWORD	i, pos;
	UBYTE	bufp[LISTWIDTH + 1];

	pos = listsize;
	if (pos > MAXLISTSHOWN)
		pos -= MAXLISTSHOWN;

	pos = ((FLOAT)((struct PropInfo *)fr_gadget[G_PROP].SpecialInfo)->VertPot)
		/ MAXPOT * (FLOAT)pos;

	if (firstshown == pos || pos >= listsize)
		return;

/*	list_text.FrontPen = PEN1;
	list_text.BackPen = PEN0;	*/

	SetAPen(rp, PEN1);
	SetBPen(rp, PEN0);
	SetDrMd(rp, JAM2);

	if ((pos - firstshown) == 1) {
		ScrollRaster(rp, 0, CHARHEIGHT, LEFTEDGE, TOPOFLIST + 1,
			RIGHTOFLIST, BOTTOMOFLIST - 1);
		StringCopyPad(bufp, list[pos + MAXLISTSHOWN - 1], LISTWIDTH);
/*		list_text.IText = bufp;	*/
		if (entrytype[pos + MAXLISTSHOWN - 1] == TYPE_DIR)
/*			list_text.FrontPen = PEN3;	*/
			SetAPen(rp, PEN3);
/*		PrintIText(rp, &list_text, LEFTEDGE, TOPOFLIST + 1 + (MAXLISTSHOWN - 1) * CHARHEIGHT);	*/
		/* slight kludge here: why do I have to add 6??? */
		Move(rp, LEFTEDGE, TOPOFLIST+1+(MAXLISTSHOWN-1) * CHARHEIGHT + 6);
		Text(rp, bufp, LISTWIDTH);
	}
	else if ((firstshown - pos) == 1) {
		ScrollRaster(rp, 0, -CHARHEIGHT, LEFTEDGE, TOPOFLIST + 1,
			RIGHTOFLIST, BOTTOMOFLIST - 1);
		StringCopyPad(bufp, list[pos], LISTWIDTH);
/*		list_text.IText = bufp;	*/
		if (entrytype[pos] == TYPE_DIR)
/*			list_text.FrontPen = PEN3;	*/
			SetAPen(rp, PEN3);
/*		PrintIText(rp, &list_text, LEFTEDGE, TOPOFLIST + 1);	*/
		Move(rp, LEFTEDGE, TOPOFLIST + 7);
		Text(rp, bufp, LISTWIDTH);
	}
	else {
		for (i = 0; i < MAXLISTSHOWN && i < listsize; i++) {
			StringCopyPad(bufp, list[pos + i], LISTWIDTH);
/*			list_text.IText = bufp;	*/
			if (entrytype[pos + i] == TYPE_DIR)
/*				list_text.FrontPen = PEN3;	*/
				SetAPen(rp, PEN3);
			else
/*				list_text.FrontPen = PEN1;	*/
				SetAPen(rp, PEN1);
/*			PrintIText(rp, &list_text, LEFTEDGE, TOPOFLIST + 1 + i * CHARHEIGHT);	*/
			Move(rp, LEFTEDGE, TOPOFLIST + 1 + i * CHARHEIGHT + 6);
			Text(rp, bufp, LISTWIDTH);
		}
	}

	firstshown = pos;
}


STATIC BOOL ListSelect(y)
UWORD	y;
/* do all the hightlighting of the filenames when selected */
{
	UWORD	pos, listmem;
	UBYTE	bufp[LISTWIDTH + 1];

	pos = (y - TOPOFLIST) / CHARHEIGHT;
	listmem = pos + firstshown;
	if (listmem >= listsize)
		return(FALSE);

	StringCopyPad(bufp, list[listmem], LISTWIDTH);
/*	list_text.IText = bufp;
	list_text.BackPen = PEN3;	*/
	SetBPen(rp, PEN3);
	SetDrMd(rp, JAM2);

	if (entrytype[listmem] == TYPE_DIR)
/*		list_text.FrontPen = PEN2;	*/
		SetAPen(rp, PEN2);
	else
/*		list_text.FrontPen = PEN1;	*/
		SetAPen(rp, PEN1);

/*	PrintIText(rp, &list_text, LEFTEDGE, pos * 8 + TOPOFLIST + 1);	*/
	Move(rp, LEFTEDGE, pos * 8 + TOPOFLIST + 7);
	Text(rp, bufp, LISTWIDTH);

	if (entrytype[listmem] == TYPE_DIR) {
		ExtendPath(list[listmem]);
		strcpy(filebuf, "");
	} else {
		if ( !strcmp(filebuf, list[listmem])) {
			ExtendPath(list[listmem]);
			return(TRUE);
		}
		strcpy(filebuf, list[listmem]);
	}
	fr_strinfo[0].NumChars = strlen(dirbuf);  /* 1.1 kludge */
	fr_strinfo[1].NumChars = strlen(filebuf);
	RefreshGadgets(&fr_gadget[G_FILENAME], FileWindow, NULL);

/*	list_text.BackPen = PEN0;	*/
	SetBPen(rp, PEN0);
	if (entrytype[listmem] == TYPE_DIR)
/*		list_text.FrontPen = PEN3;	*/
		SetAPen(rp, PEN3);
	else
/*		list_text.FrontPen = PEN1;	*/
		SetAPen(rp, PEN1);
/*	PrintIText(rp, &list_text, LEFTEDGE, pos * 8 + TOPOFLIST + 1);	*/
	Move(rp, LEFTEDGE, pos * 8 + TOPOFLIST + 7);
	Text(rp, bufp, LISTWIDTH);

	if (entrytype[listmem] == TYPE_DIR)
		if ( !GetList())
			ResetList();

	return(FALSE);
}



STATIC VOID ResetList()
/* clear all from the file request */
{
	listsize = 0;
	ClearListArea(MAXLISTSHOWN);
	strcpy(dirbuf, "");
	strcpy(filebuf, "");
	((struct PropInfo *)fr_gadget[G_PROP].SpecialInfo)->VertBody = MAXBODY;
	RefreshGadgets(&fr_gadget[G_FILENAME], FileWindow, NULL);
}


STATIC VOID ClearListArea(num)
WORD	num;
{
	WORD	topy;

	topy = BOTTOMOFLIST - 1 - CHARHEIGHT * num;

	SetAPen(rp, PEN0);
	RectFill(rp, LEFTEDGE - 1, topy, RIGHTOFLIST, BOTTOMOFLIST);
}


STATIC UWORD MyAddGList(window, gadget, position, numgad, requester)
struct Window *window;
struct Gadget *gadget;
UWORD position;
UWORD numgad;
struct Requester *requester;

/*
The above is the specification of v1.2's AddGList function.
The requester argument is ignored, position is incremented for each
*/

{
	UWORD	i, pos;

	pos = position;

	for (i = 0; i < numgad; i++) {
		AddGadget(window, &fr_gadget[i], position);
		OnGadget(&fr_gadget[i], window, NULL);
		position++;
	}

	return(pos);		/* should be ok */
}



STATIC VOID ExtendPath(string)
UBYTE	*string;
/* build a full path for a selected file */
{
	if ((dirbuf[strlen(dirbuf) - 1] != ':') && (dirbuf[strlen(dirbuf) - 1] != '/'))
		strcat(dirbuf, "/");

	strcat(dirbuf, string);
}


STATIC VOID GetParentDir()
/* get the parent directory --  cheat by just shortening the current path */
{
	UWORD	i;

	i = strlen(dirbuf) - 1;

	if (dirbuf[i] == ':')		/* if root directory */
		return;

	if (dirbuf[i] == '/')
		dirbuf[i] = '\0';

	while ((dirbuf[i] != '/') && (dirbuf[i] != ':'))
		i--;

	if (dirbuf[i] == ':')
		i++;

	dirbuf[i] = '\0';
	strcpy(filebuf, "");
	fr_strinfo[0].NumChars = strlen(dirbuf); /* 1.1 kludge */
	fr_strinfo[1].NumChars = strlen(filebuf);
	RefreshGadgets(&fr_gadget[G_FILENAME], FileWindow, NULL);

	if ( !GetList())
		ResetList();
}



STATIC UBYTE *GetCurrentDir()
/* returns the full path of the current directory */
{
	struct Process *ptr;
	struct Lock *cdlock, *prevlock;
	UBYTE newname[DIRBUFSIZE];
	UBYTE oldname[DIRBUFSIZE];

	ptr = (struct Process *)FindTask(0);   /* Get address of current task */

	cdlock = (struct Lock *)DupLock((ptr->pr_CurrentDir) /* << 2 */ );
	/* NOTE: Book says it's BPTR, but GURU when shifted, not GURU
	   when not shifted.  Explain, please? */
	newname[0] = oldname[0] = '\0';

	do {
		cdlock = (struct Lock *)ParentDir(prevlock = cdlock);
		Examine(prevlock, fib);
		strcpy(newname, fib->fib_FileName);
		UnLock(prevlock);
		if (cdlock == 0) {
		/* prevlock was the root of a disk, and thus the name */
			strcat(newname, ":");
			strcat(newname, oldname);
		} else {
			strcpy(newname, fib->fib_FileName);
			if (oldname[0]) {
				strcat(newname, "/");
				strcat(newname, oldname);
			}
		strcpy(oldname, newname);
		}
	} while (cdlock != 0);

	return(newname);
}


STATIC BOOL GetVolumeName(bufp, devname)
UBYTE	*bufp;
UBYTE	*devname;
{
	struct FileLock *devlock;

	devlock = (struct FileLock *)Lock(devname, ACCESS_READ);
	if (devlock == NULL)
		return(FALSE);

	Examine(devlock, fib);
	UnLock(devlock);

	strcpy(bufp, fib->fib_FileName);
	bufp[strlen(fib->fib_FileName)] = ':';
	bufp[strlen(fib->fib_FileName)+1] = '\0';
	return(TRUE);
}



STATIC VOID GetExtension(fname, ext)
UBYTE *fname, *ext;
/* extract the filename extension from a filename
 * (unelegant kludge) */
{
	ULONG	i, len;

	len = strlen(fname);

	for (i = len - 1; i >= 0; i--)
		if (fname[i] == '.')
			break;
	if (i)	strcpy(ext, &fname[i+1]);
	else	ext[0] = '\0';
}


STATIC VOID AddExtension(fname)
UBYTE *fname;
/* add an extension to a user-entered filename only if
 * one is not already present
 * (unelegant kludge) */
{
	int i, len;

	len = strlen(fname);

	if (fname[0] == '.')	return;

	for (i = len - 1; i > 0; i--)
		if (fname[i] == '.')
			break;
	if (i == 0) {		/* add extension */
		strcat(fname, ".");
		strcat(fname, extename);
	}
}



STATIC BOOL AllocStuff()
/* allocate memory for the gadget images
 * (to make all the extra memory users happy,
 * and also so they don't have to ATOMize
 */
{
	if ((dramoff =
		(UWORD *)AllocRaster(GADWIDTH, RGADHEIGHT * 2)) == NULL)
		return(FALSE);
	iramoff.ImageData = dramoff;
	CopyImage(dramoff, gramoff, GADWIDTH/16 * RGADHEIGHT*2);

	if ((dramon =
		(UWORD *)AllocRaster(GADWIDTH, RGADHEIGHT * 2)) == NULL)
		return(FALSE);
	iramon.ImageData = dramon;
	CopyImage(dramon, gramon, GADWIDTH/16 * RGADHEIGHT*2);

	if ((ddriveoff =
		(UWORD *)AllocRaster(GADWIDTH, DGADHEIGHT * 2)) == NULL)
		return(FALSE);
	idriveoff.ImageData = ddriveoff;
	CopyImage(ddriveoff, gdriveoff, GADWIDTH/16 * DGADHEIGHT*2);

	if ((ddriveon =
		(UWORD *)AllocRaster(GADWIDTH, DGADHEIGHT * 2)) == NULL)
		return(FALSE);
	idriveon.ImageData = ddriveon;
	CopyImage(ddriveon, gdriveon, GADWIDTH/16 * DGADHEIGHT*2);

	if ((dhdoff =
		(UWORD *)AllocRaster(GADWIDTH, HGADHEIGHT * 2)) == NULL)
		return(FALSE);
	ihdoff.ImageData = dhdoff;
	CopyImage(dhdoff, ghdoff, GADWIDTH/16 * HGADHEIGHT*2);

	if ((dhdon =
		(UWORD *)AllocRaster(GADWIDTH, HGADHEIGHT * 2)) == NULL)
		return(FALSE);
	ihdon.ImageData = dhdon;
	CopyImage(dhdon, ghdon, GADWIDTH/16 * HGADHEIGHT*2);

	if ((duparrow =
		(UWORD *)AllocRaster(ARROWWIDTH, ARROWHEIGHT)) == NULL)
		return(FALSE);
	iuparrow.ImageData = duparrow;
	CopyImage(duparrow, guparrow, ARROWHEIGHT);

	if ((ddownarrow =
		(UWORD *)AllocRaster(ARROWWIDTH, ARROWHEIGHT)) == NULL)
		return(FALSE);
	idownarrow.ImageData = ddownarrow;
	CopyImage(ddownarrow, gdownarrow, ARROWHEIGHT);

	if ((fib = (struct FileInfoBlock *)AllocMem(sizeof(
		struct FileInfoBlock), MEMF_CHIP | MEMF_CLEAR)) == NULL)
		return(FALSE);

	return(TRUE);
}



STATIC VOID CopyImage(to, from, num)
UWORD	*to, *from;
WORD	num;
{
	WORD	i;

	for (i = 0; i < num; i++)
		to[i] = from[i];
}


STATIC VOID CloseUp()
{
	if (dramoff)	FreeRaster(dramoff, GADWIDTH, RGADHEIGHT * 2);
	if (dramon)	FreeRaster(dramon, GADWIDTH, RGADHEIGHT * 2);
	if (ddriveoff)	FreeRaster(ddriveoff, GADWIDTH, DGADHEIGHT * 2);
	if (ddriveon)	FreeRaster(ddriveon, GADWIDTH, DGADHEIGHT * 2);
	if (dhdoff)	FreeRaster(dhdoff, GADWIDTH, HGADHEIGHT * 2);
	if (dhdon)	FreeRaster(dhdon, GADWIDTH, HGADHEIGHT * 2);
	if (duparrow)	FreeRaster(duparrow, ARROWWIDTH, ARROWHEIGHT);
	if (ddownarrow)	FreeRaster(ddownarrow, ARROWWIDTH, ARROWHEIGHT);

	if (fib)	FreeMem(fib, sizeof(struct FileInfoBlock));

	if (FileWindow)	CloseWindow(FileWindow);
}


STATIC VOID StringCopyLen(to, from, n)
UBYTE	*to, *from;
UWORD	n;
/* copy n characters from the source to the destination string */
{
	while (n--) {
		if (!(*from))
			break;
		*to++ = *from++;
	}
	*to = '\0';
}



STATIC VOID StringCopyPad(to, from, n)
UBYTE	*to, *from;
UWORD	n;
/* pad a string with spaces */
{
	WORD	i;

	StringCopyLen(to, from, n);

	to[n] = '\0';

	if (strlen(from) >= n)
		return;

	for (i = 0; i < n - strlen(from); i++)
		to[n - i - 1] = ' ';
}


/* modified from K&R C Programming Language for case-insensitive sort */
/* (speed not a factor, 'cause arrays are not large) */
/* Quicksort???  What's that? :-)  */

STATIC VOID SortList(size)
WORD	size;
{
	WORD	gap, i, j, k;
	BOOL	ntemp;
	BYTE	stemp[FILEBUFSIZE], s1[FILEBUFSIZE], s2[FILEBUFSIZE];
	BYTE	toupper();

	for (gap = size/2; gap > 0; gap /= 2)
		for (i = gap; i < size; i++)
			for (j = i-gap; j >= 0; j -= gap) {
				strcpy(s1, list[j]);
				strcpy(s2, list[j+gap]);
				for (k = 0; k < strlen(s1); k++)
					s1[k] = toupper(s1[k]);
				for (k = 0; k < strlen(s2); k++)
					s2[k] = toupper(s2[k]);
				if (strcmp(s1, s2) <= 0)
					break;
				strcpy(stemp, list[j]);
				ntemp = entrytype[j];
				strcpy(list[j], list[j+gap]);
				entrytype[j] = entrytype[j+gap];
				strcpy(list[j+gap], stemp);
				entrytype[j+gap] = ntemp;
			}
}
