
/*
 *  STDFILE -- Standard File Requestor. Version 2.0a 15 June 1987
 *
 *  AUTHOR -- Peter da Silva	  US (713) 497-4372
 *
 *  Reorganized by Matthew Dillon for use with * and ?.  Added:
 *	-device name in File string gadget transfered to directory
 *	 gadget without closing the window.
 *	-bug when requesting volume ""... current directory lock would
 *	 get unlocked!
 *	-additional intuitive features added
 *	-coding reorganized
 *
 *	Copyright (c) 1987 Peter da Silva, all rights reserved.
 *	Changes (c)Copyright 1987 Matthew Dillon, all rights reserved.
 *
 *	This module may be freely used in any product, commercial or
 *	otherwise, provided credit is given for this module and
 *	and provided this notice remains intact in the source. The
 *	intent of this module is to provide a standard file requestor
 *	such as is available on the Macintosh, in GEM on the IBM-PC
 *	and Atari ST, and in the Microsoft Windows software on the
 *	IBM-PC. The advantage this module has over other requestors
 *	is that it minimises disk accesses: an important consideration
 *	given the structure of AmigaDos directories. If you need to
 *	modify it for your needs, by all means go ahead... but please
 *	conform to the intent of this program as stated above. If you
 *	have suggestions for improvements, by all means call me at
 *	the number listed above.
 *
 * Enhancements in the current version:
 *
 *	Gadgets now boxed. Display generally cleaned up.
 *
 *	True "dictionary order" for searches.
 *
 *	Default pattern can now be specified. Default file name now
 *	specified in a single argument.
 *
 *	Directories always match.
 *
 *	Null pattern converted to "#?" universal wildcard.
 *
 *	If you attempt to build a file name longer than 128 characters the
 *	screen will flash and the operation will be aborted.
 *
 *	"Volumes" gadget, using the device list code in "mounted". This
 *	gadget brings up a list of all currently mounted volumes for
 *	selection. Volumes leaves the directory specification intact, so
 *	you can quickly return to where you left off.
 *
 *	With these enhancements it is now possible to select any file on
 *	any device without touching the keyboard. This is now release 2.0,
 *	as it is significantly better than 1.0.
 *
 * Acknowledgements:
 *
 *	Thanks to Jeff Lydiatt for the pattern matching code in PatMatch.c
 *	Thanks to Jay Miner, =RJ= and the whole Amiga team for the Amiga
 *	itself.
 *
 * Environment:
 *
 *	IntuitionBase and GfxBase must be open. dos.library must be open
 *	under the name "DosLibrary". Link with PatMatch.o and VolList.o.
 *
 * Usage:
 *
 *	#define MAXFILENAME 128
 *
 *	int stdfile(title, default_file, default_pat, name);
 *	char *title;
 *	char *default_file;
 *	char *default_pattern;
 *	char name[MAXFILENAME];
 *
 *	+-----------------------------------+
 *	|o| Title ------------------- |  |  | title parameter, or "File Name"
 *	|-----------------------------------|
 *	| Directory: [			  ] | Directory parameter, or current.
 *	| File name: [			  ] | Default parameter, or empty.
 *	| Pattern:   [			  ] | Initially empty, if the user
 *	| +-------------------------------+ | enters anything here it will
 *	| | [Filename]		       |  | | be used to select files. The
 *	| | [Filename]		       |  | | file display will also be empty
 *	| | [Filename]		       |@@| | to start with to avoid excess
 *	| | [Filename]		       |@@| | disk I/O. If the user selects
 *	| |			       |@@| | here the directory will be
 *	| |			       |@@| | scanned looking for files
 *	| |			       |  | | matching the specified pattern,
 *	| |			       |  | | or "*" if no pattern is given.
 *	| |			       |  | |
 *	| +-------------------------------+ | ACCEPT returns 1. CANCEL
 *	| [ACCEPT]    [VOLUMES]    [CANCEL] | or the close gadget return 0.
 *	+-----------------------------------+ VOLUMES displays volume names.
 *
 *	The number of filenames displayed is specified at compile time in the
 *	constant MAXFILES. The maximum size of a filename is specified in the
 *	constant MAXNAME. The parameter "Default file" will be broken into
 *	directory and file parts.
 */

char *Copyright =
"stdfile V2.0a. Copyright (c) 1987 Peter da Silva. All rights reserved.";

#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>

typedef unsigned char  ubyte;
typedef unsigned short uword;
typedef unsigned long  ulong;
typedef struct FileInfoBlock FIB;
typedef struct DeviceList    DEVLIST;
typedef struct DosLibrary    DOSLIB;
typedef struct DosInfo	     DOSINFO;
typedef struct RootNode      ROOTNODE;
typedef struct IntuiMessage  IMESS;

extern void CalcPropGadget();
extern void ProcessFileName();

extern void *malloc();
extern void *GetMsg();
extern struct Window *OpenWindow();

#define MAXFILES 8
#define MAXNAME 32
#define MAXFULL (MAXNAME*4)

/* SIZING PARAMS */

#define Z	    NULL
#define INDENT	    6
#define LEFTMAR     (INDENT-1)
#define BORDER	    3
#define CHSIZ	    8
#define HT	    CHSIZ
#define BASELINE    6

/* GADGET BORDERS */

#define IN1	    LEFTMAR+10*CHSIZ
#define IN3	    LEFTMAR+3
#define IN4	    -(INDENT+6*CHSIZ+1)
#define IN5	    -(INDENT+CHSIZ*2)
#define IN6	    ((WINWD-WD6)/2)
#define WD1	    -(INDENT+IN1)
#define WD3	    (6*CHSIZ)
#define WD4	    (6*CHSIZ)
#define WD5	    (CHSIZ*2+2)
#define WD6	    (7*CHSIZ)
#define TP1	    (CHSIZ+BORDER)
#define TP2	    (TP1+HT+1)
#define TP3	    (TP2+HT+1)
#define TP4	    -(BORDER+HT4-1)
#define TP5	    (TP3+HT+BORDER)
#define HT4	    (HT+1)
#define HT5	    CHSIZ*MAXFILES+INDENT

#define WINHT	    (TP5 + HT5 + (-TP4) + BORDER)
#define WINWD	    (INDENT*4 + (MAXNAME+2)*CHSIZ)
#define WININ	    (640-WINWD)/2
#define WINTP	    (200-WINHT)/2

#define HOMEX	    (INDENT+LEFTMAR)
#define HOMEY	    (TP5+BORDER)
#define LASTX	    (HOMEX+MAXNAME*CHSIZ)
#define LASTY	    (HOMEY+MAXFILES*CHSIZ)

#define BTP	    TP5
#define BIN	    LEFTMAR
#define BWD	    (WINWD-INDENT-BIN)
#define BHT	    (WINHT-BTP-(-TP4+BORDER+1))

#define SF	    GADGHCOMP|GRELWIDTH
#define SEL	    SELECTED
#define BF1	    GADGHCOMP|GRELBOTTOM
#define BF2	    GADGHCOMP|GRELBOTTOM|GRELRIGHT
#define PF	    GRELRIGHT

#define SA	    RELVERIFY
#define CEN	    STRINGCENTER
#define BA	    RELVERIFY
#define PA	    RELVERIFY

#define SI(n)      (APTR)&STD_String[n]
#define G(n)       &STD_Gadget[n]
#define IMAG	   (APTR)&STD_Image
#define PROP	   (APTR)&STD_Prop

#define SG	   STRGADGET
#define BG	   BOOLGADGET
#define PG	   PROPGADGET

#define FP	   AUTOBACKPEN
#define BP	   AUTOFRONTPEN

#define OKTEXT	   &STD_OK
#define NOTEXT	   &STD_CANCEL
#define VLTEXT	   &STD_VOLUME

static int DoneFlag;

#define DirName    SBuffer[0]
#define FileName   SBuffer[1]
#define PatName    SBuffer[2]
#define STRINGS    3

static UBYTE SBuffer[STRINGS][MAXFULL];
static UBYTE Undo[MAXFULL];

static struct StringInfo STD_String[STRINGS] = {
    {SBuffer[0],Undo,0,MAXFULL,0},
    {SBuffer[1],Undo,0,MAXFULL,0},
    {SBuffer[2],Undo,0,MAXFULL,0}
};

static struct PropInfo STD_Prop = { AUTOKNOB|FREEVERT, 0, 0, 0, 0 };

static struct IntuiText STD_OK =
    { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"ACCEPT", Z };
static struct IntuiText STD_CANCEL =
    { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"CANCEL", Z };
static struct IntuiText STD_VOLUME =
    { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"VOLUMES", Z };

#define BUTTONS 3
#define BUTVEC 8

static SHORT butvecs[BUTTONS][BUTVEC*2] = {
    { -2, HT4, -2, -1, WD3+1,-1, WD3+1,HT4, -3, HT4, -3,-1, WD3+2,-1, WD3+2, HT4 },
    { -2, HT4, -2, -1, WD4+1,-1, WD4+1,HT4, -3, HT4, -3,-1, WD4+2,-1, WD4+2, HT4 },
    { -2, HT4, -2, -1, WD6+1,-1, WD6+1,HT4, -3, HT4, -3,-1, WD6+2,-1, WD6+2, HT4 }
};

static struct Border ButBorder[BUTTONS] = {
    {0, 0, FP, BP, JAM1, BUTVEC, butvecs[0], NULL},
    {0, 0, FP, BP, JAM1, BUTVEC, butvecs[1], NULL},
    {0, 0, FP, BP, JAM1, BUTVEC, butvecs[2], NULL}
};

#define BB(n) (APTR)&ButBorder[n]

static struct Image STD_Image;

#define DIRID 0
#define FILID 1
#define PATID 2
#define YESID 3
#define CANID 4
#define VOLID 5
#define BARID 6
#define GADGETS 7

static struct Gadget STD_Gadget[GADGETS] = {
    /*NEXT, LFT, TP,WDTH, H, FLAG,  ACT, TYP, REND, Z, TXT, Z, SPEC, ID, Z */
    { G(1), IN1,TP1, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(0), 0, 0 },
    { G(2), IN1,TP2, WD1,HT, SF|SEL, SA,  SG,    Z, Z,   Z, Z, SI(1), 1, 0 },
    { G(3), IN1,TP3, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(2), 2, 0 },
    { G(4), IN3,TP4, WD3,HT4,BF1,    BA,  BG,BB(0), Z, OKTEXT, Z,  Z, 3, 0 },
    { G(5), IN4,TP4, WD4,HT4,BF2,    BA,  BG,BB(1), Z, NOTEXT, Z,  Z, 4, 0 },
    { G(6), IN6,TP4, WD6,HT4,BF1,    BA,  BG,BB(2), Z, VLTEXT, Z,  Z, 5, 0 },
    { NULL, IN5,TP5, WD5,HT5,PF,     PA,  PG, IMAG, Z,	 Z, Z,	PROP, 6, 0 }
};

static struct NewWindow STD_NewWindow = {
    WININ, WINTP, WINWD, WINHT, -1, -1,
    REFRESHWINDOW|MOUSEBUTTONS|GADGETUP|CLOSEWINDOW,
    WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SIMPLE_REFRESH|ACTIVATE,
    G(0), NULL, (ubyte *)"File Name Requestor",
    NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
};

static struct Window *STD_Window;

#define NVEC 6

static SHORT Vectors[NVEC*2] = {
    BIN+1, BTP,
    BIN+1, BTP+BHT,
    BIN+BWD, BTP+BHT,
    BIN+BWD, BTP,
    BIN, BTP,
    BIN, BTP+BHT
};

static struct Border STD_FileBox = {
    0, 0, FP, BP, JAM1, NVEC, Vectors, NULL
};

static struct IntuiText STD_Text[3] = {
    { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Directory:", NULL },
    { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"File Name:", NULL },
    { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Pattern:", NULL }
};

static
OpenFileWindow()
{
    extern struct IntuitionBase *IntuitionBase;
    int i;

    /* Rebuild gadget list */

    STD_NewWindow.FirstGadget = &STD_Gadget[0];
    for(i = 0; i < GADGETS; i++)
	STD_Gadget[i].NextGadget = (i==GADGETS-1)?(0):(&STD_Gadget[i+1]);
    for(i = 0; i < STRINGS; i++) {
	STD_String[i].BufferPos = strlen(SBuffer[i]);
	STD_String[i].DispPos = 0;
    }
    STD_Prop.VertBody = 0xFFFF;
    STD_Prop.VertPot = 0;

    if (!(STD_Window = OpenWindow(&STD_NewWindow)))
	return(0);

    /* This optional line will activate a string gadget     */
    if (IntuitionBase->LibNode.lib_Version > 32)
	ActivateGadget(G(1),STD_Window,0L);
    CalcPropGadget();
    PaintFileWindow();
    return (1);
}

static
CloseFileWindow()
{
    STD_NewWindow.LeftEdge = STD_Window->LeftEdge;
    STD_NewWindow.TopEdge = STD_Window->TopEdge;
    if (STD_Window)
	CloseWindow(STD_Window);
}

static int State;

#define INITIAL 0
#define DIRECTORY 1

static
PaintFileWindow()
{
    DrawBorder(STD_Window->RPort, &STD_FileBox, 0, 0);
    PrintIText(STD_Window->RPort, &STD_Text[0], LEFTMAR, TP1);
    PrintIText(STD_Window->RPort, &STD_Text[1], LEFTMAR, TP2);
    PrintIText(STD_Window->RPort, &STD_Text[2], LEFTMAR, TP3);
    if (State == DIRECTORY)
	PrintFileNames();
}

static int FirstFile;
static int Selected;
static int NumFiles;

static struct dirent {
    struct dirent *nextfile;
    SHORT filetype;
    char *filename;
} *NameList, **NameTable;

#define FILETYPE 0
#define DIRTYPE 1
#define VOLTYPE 2

static
PrintFileNames()
{
    int i;

    for (i = 0; i < MAXFILES; ++i) {
	SetBPen(STD_Window->RPort, BP);
	SetAPen(STD_Window->RPort, BP);
	RectFill(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ, LASTX, HOMEY+(i+1)*CHSIZ);
	if (i+FirstFile < NumFiles)
	    PrintName(i+FirstFile, i+FirstFile == Selected);
    }
}

static
PrintName(file, hilite)
int file;
int hilite;
{
    int i;

    i = file - FirstFile;

    Move(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ+BASELINE);
    if (hilite == 0) {
	SetBPen(STD_Window->RPort, BP);
	if(NameTable[file]->filetype == FILETYPE)
	    SetAPen(STD_Window->RPort, FP);
	else
	    SetAPen(STD_Window->RPort, 3);
    } else {
	SetAPen(STD_Window->RPort, BP);
	if(NameTable[file]->filetype == FILETYPE)
	    SetBPen(STD_Window->RPort, FP);
	else
	    SetBPen(STD_Window->RPort, 3);
    }
    Text(STD_Window->RPort, NameTable[file]->filename, strlen(NameTable[file]->filename));
}

static
void
CalcPropGadget()
{
    int VertPot, VertBody;

    if (State == INITIAL)
	return;
    if (NumFiles <= MAXFILES) {
	VertBody = 0xFFFF;
	VertPot = 0;
	FirstFile = 0;
    } else {
	VertBody = ((MAXFILES<<16)-1) / NumFiles;
	VertPot = 0;
	FirstFile = 0;
    }
    ModifyProp(&STD_Gadget[BARID], STD_Window, NULL,
	STD_Prop.Flags, 0, VertPot, 0, VertBody
    );
}

static
void
CalcFilePosition()
{
    short old_pos;

    if (State == INITIAL)
	 return;
    old_pos = FirstFile;
    if (NumFiles<=MAXFILES) {
	FirstFile = 0;
    } else {
	int VertPot = STD_Prop.VertPot;
	FirstFile = ((VertPot+1)*(NumFiles-MAXFILES))>>16;
    }
    if (old_pos != FirstFile)
	PrintFileNames();
}

FreeList(list)
struct dirent *list;
{
    struct dirent *ptr;

    while(list) {
	ptr = list->nextfile;
	if (list->filename)
	    free(list->filename);
	free(list);
	list = ptr;
    }
}

static
ReadNewDir()
{
    struct dirent *NewList, **NewTable, *ptr;
    int NewCount;
    FIB *fib;
    BPTR dirlock;

    if (State != DIRECTORY) {
	NameTable = 0;
	NameList = 0;
    }
    if (DirName[0]) {
	    dirlock = Lock(DirName, ACCESS_READ);
    } else {
	BPTR ram;
	if (ram = Lock("RAM:", ACCESS_READ)) {
	    dirlock = CurrentDir(ram);
	    CurrentDir(dirlock);
	    dirlock = DupLock(dirlock); /*  added */
	    UnLock(ram);
	}
    }
    if (!dirlock)
	return(0);
    if ((fib = (FIB *)malloc(sizeof(FIB))) == NULL) {
	UnLock(dirlock);
	return 0;
    }
    if (!Examine(dirlock, fib)) {
	UnLock(dirlock);
	free(fib);
	return 0;
    }
    if (fib->fib_DirEntryType < 0) {
	UnLock(dirlock);
	free(fib);
	return 0;
    }
    NewList = 0;
    NewCount = 0;
    while(ExNext(dirlock, fib)) {
	NewCount += 1;
	ptr = (struct dirent *)malloc(sizeof(struct dirent));
	if (ptr == 0) {
	    FreeList(NewList);
	    UnLock(dirlock);
	    free(fib);
	    return(0);
	}
	ptr->nextfile = NewList;
	ptr->filetype = (fib->fib_DirEntryType<0)?FILETYPE:DIRTYPE;
	ptr->filename = malloc(strlen(fib->fib_FileName)+1);
	if (ptr->filename == 0) {
	    FreeList(ptr);
	    UnLock(dirlock);
	    free(fib);
	    return(0);
	}
	strcpy(ptr->filename, fib->fib_FileName);
	NewList = ptr;
    }
    free(fib);
    if (DirName[0])
	UnLock(dirlock);
    NewTable = malloc(sizeof(struct dirent *) * NewCount);
    if (NewTable==0) {
	FreeList(NewList);
	return(0);
    }
    FreeList(NameList);
    NameList = NewList;
    if (NameTable)
	free(NameTable);
    NameTable = NewTable;
    if (PatName[0]==0)
	SetPatName("*");
    State = DIRECTORY;
    Selected = -1;
    ReCalcPattern();
}


static
ReadVol()
{
    struct dirent *NewList, **NewTable, *ptr;
    int NewCount;
    char name[MAXNAME];

    if (State != DIRECTORY) {
	NameTable = 0;
	NameList = 0;
    }
    OpenVolList();
    NewList = 0;
    NewCount = 0;
    while(ReadVolList(name)) {
	if (strcmp(name, "RAM Disk:") == 0)
	    strcpy(name, "ram:");
	NewCount += 1;
	ptr = (struct dirent *)malloc(sizeof(struct dirent));
	if (ptr==0) {
	    FreeList(NewList);
	    return(0);
	}
	ptr->nextfile = NewList;
	ptr->filetype = VOLTYPE;
	ptr->filename = malloc(strlen(name)+1);
	if (ptr->filename == 0) {
	    FreeList(ptr);
	    return(0);
	}
	strcpy(ptr->filename, name);
	NewList = ptr;
    }
    CloseVolList();
    NewTable = malloc(sizeof(struct dirent *)*NewCount);
    if (NewTable==0) {
	FreeList(NewList);
	return(0);
    }
    FreeList(NameList);
    NameList = NewList;
    if (NameTable)
	free(NameTable);
    NameTable = NewTable;

    if (PatName[0]==0)
	SetPatName("*");

    State = DIRECTORY;
    Selected = -1;

    ReCalcPattern();
}

/* this routine does a true dictionary search:
 *
 *		Devs < devs but Devs > devices
 */

static
table_compare(p1, p2)
struct dirent **p1, **p2;
{
    char *s1, *s2;
    char c1, c2;
    char firstdiff;

    s1 = (*p1)->filename;
    s2 = (*p2)->filename;
    firstdiff = 0;

    while(*s1 && *s2) {
	c1 = *s1++;
	c2 = *s2++;
	if (firstdiff==0)
	    firstdiff = c1 - c2;
	if (c1 >= 'A' && c1 <= 'Z') c1 = c1+'@';
	if (c2 >= 'A' && c2 <= 'Z') c2 = c2+'@';
	if (c1 != c2)
	    return c1 - c2;
    }
    return firstdiff;
}

static
sort_table()
{
    qsort(NameTable, NumFiles, sizeof(struct dirent *), table_compare);
    return 1;
}

static
ReCalcPattern()
{
    if (State != DIRECTORY) {
	ReadNewDir();
    } else {
	struct dirent *ptr;

	if (!PatName[0])
	    SetPatName("*");
	NumFiles = 0;
	for (ptr = NameList; ptr; ptr=ptr->nextfile) {
	    /* Directories always match. Is this good? */
	    if (ptr->filetype == DIRTYPE || ptr->filetype == VOLTYPE || newwildcmp(PatName, ptr->filename)) {
		NameTable[NumFiles] = ptr;
		NumFiles++;
	    }
	}
	sort_table();
	CalcPropGadget();
	Selected = -1;
	PrintFileNames();
    }
}

static
SetGadgetText(id, text)
int id;
char *text;
{
    int position;

    position = RemoveGadget(STD_Window, G(id));
    if (position != -1) {
	strcpy(SBuffer[id], text);
	STD_String[id].BufferPos = strlen(text);
	position = AddGadget(STD_Window, G(id), -1);
	if (position != -1)
	    RefreshGadgets(G(id), STD_Window, NULL);
    }
}


static
SetDirName(name)
char *name;
{
    char buffer[MAXFULL+1], *ptr;
    int  index;
    char lastchar;

    /* Can't enter a file name too long. */

    if (strlen(DirName) + strlen(name) + 1 > MAXFULL) {
	DisplayBeep();
	return(0);
    }
    index = 0;
    lastchar = 0;
    for (ptr = (char *)DirName; *ptr; ptr++)
	buffer[index++] = lastchar = *ptr;
    if (lastchar != ':' && lastchar != 0)
	buffer[index++] = '/';
    strcpy(&buffer[index], name);
    SetGadgetText(DIRID, buffer);
    SetGadgetText(FILID, "");
    return(1);
}

static
SetFileName(name)
char *name;
{
    /* Can't enter a file name too long. */
    if (strlen(DirName) + strlen(name) + 1 > MAXFULL) {
	DisplayBeep();
	return(0);
    }
    SetGadgetText(FILID, name);
    return(1);
}

static
SetPatName(name)
char *name;
{
    SetGadgetText(PATID, name);
}

static
ProcessGadget(id)
int id;
{
    switch(id) {
    case DIRID: ReadNewDir();       break;
    case FILID: ProcessFileName();  break;
    case PATID: ReCalcPattern();    break;
    case BARID: CalcFilePosition(); break;
    case YESID: DoneFlag = 1;	    break;
    case CANID: DoneFlag = -1;	    break;
    case VOLID: ReadVol();          break;
    }
}

/*
 *  ProcessFileName() added by Matthew Dillon.  If the requested file is
 *  actually a directory, do a ReadNewDir() instead of quiting.
 */

void
ProcessFileName()
{
    register char *ptr;
    register short len;
    BPTR fillock;
    char buf[128];
    FIB *fib = (FIB *)malloc(sizeof(FIB));

    if (fib == NULL) {
	DoneFlag = 1;
	return;
    }
    for (ptr = (char *)FileName; *ptr; ++ptr) {
	if (*ptr == ':') {
	    DirName[0] = '\0';
	    break;
	}
    }
    strcpy(buf, DirName);
    if (FileName[0]) {
	if (len = strlen(buf)) {
	    if (buf[len-1]!=':')
		strcat(buf, "/");
	}
	strcat(buf, FileName);
	if (fillock = Lock(buf, ACCESS_READ)) {
	    if (Examine(fillock, fib)) {
		if (fib->fib_DirEntryType > 0) {
		    SetGadgetText(DIRID, buf);
		    SetGadgetText(FILID, "");
		    ReadNewDir();
		    free(fib);
		    UnLock(fillock);
		    return;
		}
	    }
	    UnLock(fillock);
	}
    }
    free(fib);
    DoneFlag = 1;
}


static
ProcessMouse(x, y, code, seconds, micros)
{
    int NewSelected;
    static int oseconds = 0, omicros = 0;

    if (x < HOMEX || y < HOMEY || x >= LASTX || y >= LASTY)
	return;
    if ((code & SELECTUP) == SELECTUP)
	return;
    if (State != DIRECTORY) {
	ReadNewDir();
	return;
    }
    NewSelected = (y-HOMEY)/CHSIZ + FirstFile;
    if (NewSelected == Selected) {
	if (Selected != -1) {
	    if (DoubleClick(oseconds, omicros, seconds, micros)) {
		if (NameTable[Selected]->filetype == DIRTYPE) {
		    if (SetDirName(NameTable[Selected]->filename))
			ReadNewDir();
		} else if (NameTable[Selected]->filetype == VOLTYPE) {
		    SetGadgetText(DIRID, NameTable[Selected]->filename);
		    SetGadgetText(FILID, "");
		    ReadNewDir();
		} else if (!SetFileName(NameTable[Selected]->filename)) {
		    Selected = -1;
		    DoneFlag = 1;
		}
	    }
	}
    } else {
	if (Selected != -1 && Selected >= FirstFile && Selected < FirstFile+MAXFILES)
	    PrintName(Selected, 0);
	Selected = NewSelected;
	if (Selected >= NumFiles) {
	    Selected = -1;
	} else {
	    if (SetFileName(NameTable[Selected]->filename))
		PrintName(Selected, 1);
	    else
		Selected = -1;
	    if (IntuitionBase->LibNode.lib_Version > 32)
		ActivateGadget(G(1),STD_Window,0L);
	}
    }
    oseconds = seconds;
    omicros = micros;
}

stdfile(title, deffile, defpat, name)
char *title, *deffile, *defpat, *name;
{
    IMESS *im;

    if(title)
	STD_NewWindow.Title = (UBYTE *)title;
    else
	STD_NewWindow.Title = (UBYTE *)"Enter File Name";
    if (deffile) {
	int i;
	for (i = strlen(deffile)-1; i >= 0; --i) {
	    if (deffile[i]==':' || deffile[i]=='/') {
		int hold;
		strcpy(FileName, &deffile[i+1]);
		if (deffile[i]==':')
		    i++;
		hold = deffile[i];
		deffile[i] = 0;
		strcpy(DirName, deffile);
		deffile[i] = hold;
		break;
	    }
	}
	if (i < 0) {
	    strcpy(FileName, deffile);
	    DirName[0] = 0;
	}
    } else {
	DirName[0] = 0;
	FileName[0] = 0;
    }
    if (defpat)
	strcpy(PatName, defpat);
    else
	PatName[0] = 0;

    State = INITIAL;
    NameTable = 0;
    NameList = 0;

    if(!OpenFileWindow())
	return(0);
    DoneFlag = 0;
    while (!DoneFlag) {
	Wait(1<<STD_Window->UserPort->mp_SigBit);
	while(im = GetMsg(STD_Window->UserPort)) {
	    switch(im->Class) {
	    case CLOSEWINDOW:
		DoneFlag = -1;
		break;
	    case MOUSEBUTTONS:
		ProcessMouse(im->MouseX, im->MouseY, im->Code, im->Seconds, im->Micros);
		break;
	    case GADGETUP:
		ProcessGadget(((struct Gadget *)im->IAddress)->GadgetID);
		break;
	    case REFRESHWINDOW:
		BeginRefresh(STD_Window);
		PaintFileWindow();
		EndRefresh(STD_Window, 1);
		break;
	    }
	    ReplyMsg(im);
	}
    }
    CloseFileWindow();
    FreeList(NameList);

    if (NameTable)
	free(NameTable);
    if (DoneFlag == 1) {
	int len;

	strcpy(name, DirName);
	if (FileName[0]) {
	    if (len = strlen(name)) {
		if (name[len-1]!=':')
		    strcat(name, "/");
	    }
	    strcat(name, FileName);
	    return(1);
	}
    }
    return(0);
}

/*
 *  VOLLIST.C
 */

#define toAPTR(b) ((b)<<2)
#define toBPTR(a) ((a)>>2)

struct DeviceList *list;

OpenVolList()
{
    extern DOSLIB *DOSBase;
    ROOTNODE *root;
    DOSINFO  *info;

    root =   (ROOTNODE *)DOSBase->dl_Root;
    info =   (DOSINFO  *)toAPTR(root->rn_Info);
    list = (DEVLIST *)toAPTR(info->di_DevInfo);
}

ReadVolList(name)
char *name;
{
    register DEVLIST *next;

    while(list) {
	next = (DEVLIST *)toAPTR(list->dl_Next);
	if (list->dl_Type == DLT_VOLUME) {
	    char *ptr;
	    int count;
	    ptr = (char *)toAPTR((BPTR)list->dl_Name);
	    count = *ptr++;
	    if (count > 30)
		count = 30;
	    strncpy(name, ptr, count);
	    name[count++] = ':';
	    name[count] = 0;
	    list = next;
	    return(1);
	}
	list = next;
    }
    return(0);
}

CloseVolList()
{
}


