/****************************************************************************
 *
 *  FileRequest() - File Name Requester
 *
 *  By Kevin Lee Clague
 *     408 Tortolla Way
 *     San Jose, Ca 95033
 *     408-258-9891       work 408-737-5481
 *
 *  Copyright (C) 1986. All rights reserved.
 *
 *  This program is freely distributable as long as this copyright notice
 *  is retained. It intended for personal, non-commercial use.
 *
 *  This file name requester is modeled after Deluxe Paints file name
 *  requester. The dimensions/locations of all borders, gadgets and text were
 *  arrived at empirically. Besides being a great program, Deluxe Paint is a
 *  trade mark of Electronics Arts.
 *
 *  The knowledge on how to get at the entries in the directories was drawn
 *  from Mike (I'll be melow when I'm dead) Meyer's "Browser".
 *
 ***************************************************************************/

/***************************************************************************
 *
 *  Things to do:
 *    1. Dynamically allocate space for file name strings as they are gotten
 *       from the disk, rather than static allocation of them in arrays.
 *    2. Fence off intuition events while getting file names from disk
 *       directory (and put up the zz sleepy cloud in place of the arrow
 *       mouse cursor.)
 *    3. Be a little more diligent with my use of RefreshGadgets.
 *
 ***************************************************************************/

/***************************************************************************
 *
 *   Changes made by:       Randy Finch
 *                          122 West Oak Hill Dr.
 *                          Florence, AL 35630
 *
 *                       Phone -     Day: 205-386-2252
 *                               Evening: 205-767-3528
 *    BIX name: rfinch
 *
 *
 *  1. Eliminated RemoveGadgets() and AddGadgets() so it would work under
 *     AmigaDOS 1.2.
 *  2. Made changes to allow compilation with Lattice.
 *  3. Changed Requester gadgetry to look more like DPaint II.
 *  4. Modified how the proportional gadget is handled.  It now conforms
 *     to the method shown in the Enhancer booklet.
 *  5. Added "/ Parent (dir)" as the first listing in the boolean file
 *     selection gadgets.
 *  6. Added three new boolean gadgets: df0:, df1:, and hd: for selecting
 *     drives quickly.  The hd: device is a special gadget.  It can be
 *     modified by the user.  If the user types his own device into the
 *     Drawer string gadget directly, and it does not match either
 *     df0: or df1:, it will assign this device name to the hd: gadget
 *     (or as I call it, the user gadget).  Thus, if your hard disk is
 *     called dh0:, type this in the Drawer gadget.  When you select
 *     Load or Cancel, this will be assigned to the user gadget.  The next
 *     time the requester is called up, dh0: will appear in the gadget.
 *     NOTE:  The device name including the colon must be 8 characters
 *            or less.
 *  7. The Drawer string now shows the entire path rather than just the
 *     current directory.
 *  8. The function FileRequest() now accepts an additional parameter,
 *     FileExtention.  This allows the function to be called specifying
 *     an extension for the listed filenames.  If a file (does not include
 *     directorys) does not have this extension, it will not be listed
 *     in the file selection gadgets.
 *
 *
 *  Additional notes: The function rindex(), which is used extensively in
 *                    this routine, is not in the Lattice library.  I
 *                    wrote my own version.  It simply returns a pointer
 *                    to the right-most occurance of a character in a
 *                    string.
 *                    Make sure the string you assign for the full path
 *                    name is long enough to handle the maximum path
 *                    you believe the user will need.
 *
 *************************************************************************/

#include "Requester.h"

extern struct IntuitionBase *IntuitionBase;

BOOL IsDir(), IsParent();
BOOL WaitRequester();
void InitFNR(), SetNewDrawer(), SetNewFile(), ListDir(), AttachList();
void ScrollList(), PotScrollList(), ThrowTrailing(), GoParent();
void ChangeDevice(), ToUpper();

struct Requester FileRequester;

UBYTE *FRFullPath;
struct IntuiMessage *message;
struct Window *FRWindow;

struct FileInfoBlock FileInfo;
USHORT FileCount;                     /* Number of files in current dir */
UBYTE  FileListEntry[MAXFILES][40];   /* File (dir) names in current dir */
TEXT   GetUser[80];
TEXT   spaces30[] = "                              ";
UBYTE *FileExt;

USHORT FirstFile;

#define PATHNAMELEN 80
#define MIN(a,b)    ((a)<(b)?(a):(b))

/****************************************************************************
 *                The Gadget String
 ***************************************************************************/
/******************************
 * The File Name Gadget stuff *
 *****************************/
struct IntuiText FileText =
  {
  0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  -46,0,                  /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  "File:",                /* IText */
  NULL                    /* NextText */
  };

UBYTE FileName[40];
UBYTE Backup[40];
struct StringInfo FileString = {
    &FileName,               /* Buffer */
    &Backup,                 /* UndoBuffer */
    0,                       /* BufferPos */
    32,                      /* MaxChars  */
    0,                       /* DispPos */
    0,0,0,0,0,NULL,0,NULL    /* maintained by Intuition */
  };

struct Gadget FileGadget =
  { /* File string */
  NULL,                    /* NextGadget */
  67,113,                  /* LeftEdge, TopEdge */
  185,8,                   /* Width, Height */
  GADGHCOMP,               /* Flags */
  0,                       /* Activation */
  STRGADGET|REQGADGET,     /* GadgetType */
  NULL,                    /* GadgetRender */
  NULL,                    /* SelectRender */
  &FileText,               /* GadgetText */
  0,                       /* MutualExclude */
  &FileString,             /* SpecialInfo */
  NULL,                    /* GadgetID */
  NULL                     /* UserData */
  };

/********************************
 * The Drawer Name Gadget stuff *
 *******************************/
struct IntuiText DrawerText =
  {
  0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  -62,0,                  /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  "Drawer:",              /* IText */
  NULL                    /* NextText */
  };

UBYTE DrawerName[80];
UBYTE Backup2[80];
struct StringInfo DrawerString = {
    &DrawerName,             /* Buffer */
    &Backup2,                /* UndoBuffer */
    0,                       /* BufferPos */
    80,                      /* MaxChars  */
    0,                       /* DispPos*/
    0,0,0,0,0,NULL,0,NULL    /* maintained by Intuition*/
  };

struct Gadget DrawerGadget =
  { /* Drawer string */
  &FileGadget,             /* NextGadget */
  67,98,                   /* LeftEdge, TopEdge */
  185,8,                   /* Width, Height */
  GADGHCOMP,               /* Flags */
  RELVERIFY,               /* Activation */
  STRGADGET|REQGADGET,     /* GadgetType */
  NULL,                    /* GadgetRender */
  NULL,                    /* SelectRender */
  &DrawerText,             /* GadgetText */
  0,                       /* MutualExclude */
  &DrawerString,           /* SpecialInfo */
  DRAWERGADGET,            /* GadgetID */
  NULL                     /* UserData */
  };

/****************************************
 * The File list selection Gadget stuff *
 ***************************************/
UBYTE PickNames[8][40];
struct IntuiText FileList[] =
  {
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[0][0],       /* IText */
    NULL                    /* NextText */
    },
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[1][0],       /* IText */
    NULL                    /* NextText */
    },
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[2][0],       /* IText */
    NULL                    /* NextText */
    },
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[3][0],       /* IText */
    NULL                    /* NextText */
    },
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[4][0],       /* IText */
    NULL                    /* NextText */
    },
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[5][0],       /* IText */
    NULL                    /* NextText */
    },
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[6][0],       /* IText */
    NULL                    /* NextText */
    },
    {
    0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
    0,0,                    /* LeftEdge,TopEdge */
    NULL,                   /* ITextFont */
    &PickNames[7][0],       /* IText */
    NULL                    /* NextText */
    }
  };

struct Gadget FileListGadget[] =
  {
    { /* File name selection 0 */
    &FileListGadget[1],      /* NextGadget */
    5,14,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[0],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE0GADGET,             /* GadgetID */
    NULL                     /* UserData */
    },
    { /* File name selection 1 */
    &FileListGadget[2],      /* NextGadget */
    5,24,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[1],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE1GADGET,             /* GadgetID */
    NULL                     /* UserData */
    },
    { /* File name selection 2 */
    &FileListGadget[3],      /* NextGadget */
    5,34,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[2],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE2GADGET,             /* GadgetID */
    NULL                     /* UserData */
    },
    { /* File name selection 3 */
    &FileListGadget[4],      /* NextGadget */
    5,44,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[3],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE3GADGET,             /* GadgetID */
    NULL                     /* UserData */
    },
    { /* File name selection 4 */
    &FileListGadget[5],      /* NextGadget */
    5,54,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[4],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE4GADGET,             /* GadgetID */
    NULL                     /* UserData */
    },
    { /* File name selection 5 */
    &FileListGadget[6],      /* NextGadget */
    5,64,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[5],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE5GADGET,             /* GadgetID */
    NULL                     /* UserData */
    },
    { /* File name selection 6 */
    &FileListGadget[7],      /* NextGadget */
    5,74,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[6],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE6GADGET,             /* GadgetID */
    NULL                     /* UserData */
    },
    { /* File name selection 7 */
    &DrawerGadget,           /* NextGadget */
    5,84,                    /* LeftEdge, TopEdge */
    244,8,                   /* Width, Height */
    GADGHNONE,               /* Flags */
    GADGIMMEDIATE,           /* Activation */
    BOOLGADGET|REQGADGET,    /* GadgetType */
    NULL,                    /* GadgetRender */
    NULL,                    /* SelectRender */
    &FileList[7],            /* GadgetText */
    0,                       /* MutualExclude */
    NULL,                    /* SpecialInfo */
    FILE7GADGET,             /* GadgetID */
    NULL                     /* UserData */
    }
  };
/********************************
 * The Load Button gadget stuff *
 *******************************/
SHORT ButtonPoints1[] =
  {
  -2, 11,
  66, 11,
  66, -1
  };
struct Border ButtonBorder1 =
  {
  0,0,
  0,1,JAM1,
  3,
  &ButtonPoints1[0],
  NULL
  };
SHORT ButtonPoints0[] =
  {
  -3, -2,
  65, -2,
  65, 10,
  -3, 10,
  -3, -2
  };
struct Border ButtonBorder0 =
  {
  0,0,
  0,1,JAM1,
  5,
  &ButtonPoints0[0],
  &ButtonBorder1
  };

struct IntuiText LoadText =
  {
  0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  0,0,                    /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  NULL,                   /* IText */
  NULL                    /* NextText */
  };

struct Gadget LoadGadget =
  { /* Load button */
  &FileListGadget[0],      /* NextGadget */
  14,148,                  /* LeftEdge, TopEdge */
  64,8,                    /* Width, Height */
  GADGHCOMP,               /* Flags */
  GADGIMMEDIATE|ENDGADGET, /* Activation */
  BOOLGADGET|REQGADGET,    /* GadgetType */
  (APTR) &ButtonBorder0,   /* GadgetRender */
  NULL,                    /* SelectRender */
  &LoadText,               /* GadgetText */
  0,                       /* MutualExclude */
  NULL,                    /* SpecialInfo */
  LOADGADGET,              /* GadgetID */
  NULL                     /* UserData */
  };

/**********************************
 * The Cancel Button gadget stuff *
 *********************************/
struct IntuiText CancelText =
  {
  0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  0,0,                    /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  "Cancel",               /* IText */
  NULL                    /* NextText */
  };

struct Gadget CancelGadget =
  { /* Cancel button */
  &LoadGadget,             /* NextGadget */
  187,148,                 /* LeftEdge, TopEdge */
  64,8,                    /* Width, Height */
  GADGHCOMP,               /* Flags */
  GADGIMMEDIATE|ENDGADGET, /* Activation */
  BOOLGADGET|REQGADGET,    /* GadgetType */
  (APTR) &ButtonBorder0,   /* GadgetRender */
  NULL,                    /* SelectRender */
  &CancelText,             /* GadgetText */
  0,                       /* MutualExclude */
  NULL,                    /* SpecialInfo */
  CANCELGADGET,            /* GadgetID */
  NULL                     /* UserData */
  };


/******************************************
 * The DF0:, DF1:, and User Button Gadget *
 ******************************************/

struct IntuiText DF0Text =
  {
  0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  0,0,                    /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  "DF0:",                 /* IText */
  NULL                    /* NextText */
  };

struct IntuiText DF1Text =
  {
  0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  0,0,                    /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  "DF1:",                 /* IText */
  NULL                    /* NextText */
  };

struct IntuiText UserText =
  {
  0,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  0,0,                    /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  "HD:     ",             /* IText */
  NULL                    /* NextText */
  };

struct Gadget DFGadget[] =
  {
  {
  &CancelGadget,           /* NextGadget */
  14,130,                  /* LeftEdge, TopEdge */
  64,8,                    /* Width, Height */
  GADGHNONE,               /* Flags */
  RELVERIFY,               /* Activation */
  BOOLGADGET|REQGADGET,    /* GadgetType */
  (APTR) &ButtonBorder0,   /* GadgetRender */
  NULL,                    /* SelectRender */
  &DF0Text,                /* GadgetText */
  0,                       /* MutualExclude */
  NULL,                    /* SpecialInfo */
  DF0GADGET,               /* GadgetID */
  NULL                     /* UserData */
  },
  {
  &DFGadget[0],            /* NextGadget */
  101,130,                 /* LeftEdge, TopEdge */
  64,8,                    /* Width, Height */
  GADGHNONE,               /* Flags */
  RELVERIFY,               /* Activation */
  BOOLGADGET|REQGADGET,    /* GadgetType */
  (APTR) &ButtonBorder0,   /* GadgetRender */
  NULL,                    /* SelectRender */
  &DF1Text,                /* GadgetText */
  0,                       /* MutualExclude */
  NULL,                    /* SpecialInfo */
  DF1GADGET,               /* GadgetID */
  NULL                     /* UserData */
  },
  {
  &DFGadget[1],            /* NextGadget */
  187,130,                 /* LeftEdge, TopEdge */
  64,8,                    /* Width, Height */
  GADGHNONE,               /* Flags */
  RELVERIFY,               /* Activation */
  BOOLGADGET|REQGADGET,    /* GadgetType */
  (APTR) &ButtonBorder0,   /* GadgetRender */
  NULL,                    /* SelectRender */
  &UserText,               /* GadgetText */
  0,                       /* MutualExclude */
  NULL,                    /* SpecialInfo */
  USERGADGET,              /* GadgetID */
  NULL                     /* UserData */
  } };


/***********************************************
 * The Scroll Selection List up (arrow) gadget *
 **********************************************/
UWORD UpArrowData[15] = {
   0xfffc,
   0xfcfc,
   0xf87c,
   0xf03c,
   0xe01c,
   0xc00c,
   0x8004,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfffc
};

struct Image UpArrow =
  {
   0,0,
   14,
   14,
   1,
   &UpArrowData[0],
   0x1, 0x0,
   NULL
   };

struct Gadget UpGadget =
  { /* Up a file gadget */
  &DFGadget[2],            /* NextGadget */
  247,13,                  /* LeftEdge, TopEdge */
  12,15,                   /* Width, Height */
  GADGIMAGE|GADGHNONE,     /* Flags */
  GADGIMMEDIATE,           /* Activation */
  BOOLGADGET|REQGADGET,    /* GadgetType */
  (APTR) &UpArrow,         /* GadgetRender */
  NULL,                    /* SelectRender */
  NULL,                    /* GadgetText */
  0,                       /* MutualExclude */
  NULL,                    /* SpecialInfo */
  UPGADGET,                /* GadgetID */
  NULL                     /* UserData */
  };
/*************************************************
 * The Scroll Selection List down (arrow) gadget *
 ************************************************/
UWORD DownArrowData[15] = {
   0xfffc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0x8004,
   0xc00c,
   0xe01c,
   0xf03c,
   0xf87c,
   0xfcfc,
   0xfffc
};

struct Image DownArrow =
  {
   0,0,
   14,
   14,
   1,
   &DownArrowData[0],
   0x1, 0x0,
   NULL
   };

struct Gadget DownGadget =
  { /* Down a file gadget */
  &UpGadget,               /* NextGadget */
  247,79,                  /* LeftEdge, TopEdge */
  12,15,                   /* Width, Height */
  GADGIMAGE|GADGHNONE,     /* Flags */
  GADGIMMEDIATE,           /* Activation */
  BOOLGADGET|REQGADGET,    /* GadgetType */
  (APTR) &DownArrow,       /* GadgetRender */
  NULL,                    /* SelectRender */
  NULL,                    /* GadgetText */
  0,                       /* MutualExclude */
  NULL,                    /* SpecialInfo */
  DOWNGADGET,              /* GadgetID */
  NULL                     /* UserData */
  };

/***************************************************
 * The Scroll Selection list up down Potentiometer *
 **************************************************/
struct PropInfo KnobInfo =
  {
  AUTOKNOB | FREEVERT | PROPBORDERLESS,
  0,
  0, /* VertPot */
  0,
  0x7fff, /* VertBody */
  0,0,0,0,0,0
  };

struct Image KnobImage =
  {
  0,0,
  0,0,0,
  NULL,
  0,0,
  NULL
  };

struct Gadget PotGadget =
  { /* Potentiometer file gadget */
  &DownGadget,             /* NextGadget */
  247,28,                  /* LeftEdge, TopEdge */
  14,50,                   /* Width, Height */
  GADGHNONE,               /* Flags */
  RELVERIFY,               /* Activation */
  PROPGADGET|REQGADGET,    /* GadgetType */
  (APTR) &KnobImage,       /* GadgetRender */
  NULL,                    /* SelectRender */
  NULL,                    /* GadgetText */
  0,                       /* MutualExclude */
  &KnobInfo,               /* SpecialInfo */
  POTGADGET,               /* GadgetID */
  NULL                     /* UserData */
  };
/***************************************************************************
*                  Other Requester structures                              *
***************************************************************************/
struct IntuiText HeadingText =
  {
  2,1, JAM2,              /* FrontPen, BackPen, DrawMode */
  4,3,                    /* LeftEdge,TopEdge */
  NULL,                   /* ITextFont */
  NULL,                   /* IText */
  NULL                    /* NextText */
  };

SHORT Requester0Points[] = {
  2,1,
  261,1,
  261,162,
  2,162,
  2,1
  };
struct Border Requester0Border = {
  0,0,
  0,1,JAM1,
  5,
  &Requester0Points[0],
  NULL
  };

SHORT Requester1Points[] = {
  2,12,
  261,12
  };
struct Border Requester1Border = {
  0,0,
  0,1,JAM1,
  2,
  &Requester1Points[0],
  &Requester0Border
  };

SHORT Requester2Points[] = {
  2,93,
  261,93
  };
struct Border Requester2Border = {
  0,0,
  0,1,JAM1,
  2,
  &Requester2Points[0],
  &Requester1Border
  };

SHORT Requester3Points[] = {
  246,12,
  246,93,
  246,78,
  261,78,
  261,27,
  247,27
  };
struct Border Requester3Border = {
  0,0,
  0,1,JAM1,
  6,
  &Requester3Points[0],
  &Requester2Border
  };

/****************************************************************************
 *                     The Code part of the requester
 ***************************************************************************/
BOOL FileRequest(FileType,Action,FullName,window,FileExtension)
  UBYTE *FileType;
  UBYTE *Action;
  UBYTE *FullName;
  struct Window *window;
  UBYTE *FileExtension;
{
  UBYTE *StrPtr;
  BOOL   RetCode;

  FRFullPath = FullName;
  FRWindow = window;
  FileExt = FileExtension;
  HeadingText.IText = FileType; /* Center requester title */
  HeadingText.LeftEdge = (256-IntuiTextLength(&HeadingText))/2;
  LoadText.IText = Action;

  InitFNR();

  /* Separate the path from the file name. Set the file name in the gadget */
  if (StrPtr = rindex(FRFullPath,'/'))
    {
    strcpy(FileString.Buffer,StrPtr + 1);
    *StrPtr = '\0';
    }
  else
    if (StrPtr = rindex(FRFullPath,':'))
      {
      strcpy(FileString.Buffer,StrPtr + 1);
      *(StrPtr+1) = '\0';
      }
    else
      {
      *FileString.Buffer   = '\0';
      *DrawerString.Buffer = '\0';
      *FRFullPath = '\0';
      }
  strcpy(DrawerString.Buffer,FRFullPath);

  /* Put up the requester and list the dir into it */
  Request(&FileRequester,FRWindow);
  ListDir(FRFullPath);
  SetNewFile(&FileGadget,FileString.Buffer); /* why do I have to do this? */
  SetNewFile(&DrawerGadget,DrawerString.Buffer);

  RetCode = WaitRequester();         /* do everything till Cancel or Load */

  /* Put file name and path back together */
  if (FRFullPath[strlen(FRFullPath)-1] != ':')
    strcat(FRFullPath,"/");
  strcat(FRFullPath,FileString.Buffer);

  /* Put new user device in device gadget */
  strcpy(GetUser, FRFullPath);
  if (StrPtr = rindex(GetUser, ':'))
     {
     *(StrPtr+1) = '\0';
     ToUpper(GetUser);
     if (strcmp(GetUser,DF0Text.IText) != 0 && strcmp(GetUser,DF1Text.IText) != 0 && strlen(GetUser) <= 8)
        strcpy(UserText.IText, GetUser);
     }
  return(RetCode);
} /* LoadRequest */

/*
 *  Init the file name requester
 */
void InitFNR()
{
  InitRequester(&FileRequester);
  FileRequester.LeftEdge  = 6;
  FileRequester.TopEdge   = 12;
  FileRequester.Width     = 264;
  FileRequester.Height    = 164;
  FileRequester.ReqGadget = &PotGadget;
  FileRequester.ReqText   = &HeadingText;
  FileRequester.BackFill  = 1;
  FileRequester.Flags     = 0;
  FileRequester.ReqBorder = &Requester3Border;
} /* InitFNR */

/*
 *  WaitRequester - List dirs, scroll, and set drawer and file strings until
 *                  one of the LOAD(SAVE) or CANCEL buttons pushed.
 */
BOOL WaitRequester()
{
  ULONG  class = GADGETDOWN;
  USHORT choice = CANCELGADGET;
  struct Gadget *gadget;

  while (class != REQCLEAR)
    {
    if ((message=(struct IntuiMessage *) GetMsg(FRWindow->UserPort)) == 0L)
      {
      Wait(1L<<FRWindow->UserPort->mp_SigBit);
      continue;
      }
    class  = message->Class;
    gadget = (struct Gadget *) message->IAddress;
    ReplyMsg(message);
    switch (class)
      {
      case GADGETDOWN:
           switch (gadget->GadgetID >> CLASSBITS)
             {
             case UPDOWNCLASS:
                  ScrollList(gadget);      /* scroll up/down 1 file */
                  break;
             case CHOICECLASS:             /* set the name in string gads */
                  if (IsParent(gadget->GadgetText->IText))
                    {
                    GoParent(FRFullPath);
                    SetNewDrawer(&DrawerGadget, FRFullPath);
                    }
                  else if (IsDir(gadget->GadgetText->IText))
                    {
                    if (FRFullPath[strlen(FRFullPath)-1] != ':')
                      strncat(FRFullPath, "/", PATHNAMELEN);
                    strncat(FRFullPath, gadget->GadgetText->IText, PATHNAMELEN);
                    SetNewDrawer(&DrawerGadget, FRFullPath);
                    }
                  else
                    SetNewFile(&FileGadget,gadget->GadgetText->IText);
                  break;
             case BUTTONCLASS:             /* LOAD or CANCEL */
                  choice = gadget->GadgetID & GADGETNUM;
             }
      case GADGETUP:
           switch (gadget->GadgetID >> CLASSBITS)
             {
             case UPDOWNCLASS:             /* Potentiometer scroll */
                  PotScrollList(gadget);
                  break;
             case STRINGCLASS:             /* They typed drawer name in */
                  ThrowTrailing(DrawerString.Buffer);
                  strcpy(FRFullPath,DrawerString.Buffer);
                  SetNewFile(&FileGadget,"");
                  ListDir(DrawerString.Buffer);
                  break;
             case DEVICECLASS:             /* Device change */
                  ChangeDevice(gadget);
             }
      }
    }
  return((BOOL)(choice==LOAD));
} /* WaitRequester */

/*
 *  SetNewDrawer - Used Mouse to pick directory from selection list gadgets.
 */
void SetNewDrawer(Gadget,Text)
  struct Gadget *Gadget;
  UBYTE  *Text;
{
  SetNewFile(&FileGadget,"");          /* clear file name string */
  SetNewFile(Gadget,Text);             /* set new drawer into gadget */
  ListDir(FRFullPath);                 /* List new files into Sel List */
} /* SetNewDrawer */

/*
 *  SetNewFile - Copy text to gadget and refresh
*/
void SetNewFile(gadget,Text)
  struct Gadget *gadget;
  UBYTE  *Text;
{
  struct StringInfo *strinfo;

  if (strcmp(Text, spaces30) != 0)
    {
    ThrowTrailing(Text);           /* get rid of trailing blanks */
    strinfo = (struct StringInfo *)(gadget->SpecialInfo);
    strcpy(strinfo->Buffer,Text);
    RefreshGadgets(&DownGadget,FRWindow,&FileRequester);
    }
} /* SetNewFile */

/*
 *  ListDir - List the directory into array of string names.
 */
void ListDir(dir)
  char *dir;
{
  struct FileLock *my_lock, *Lock() ;

  FileCount = 0;
  FirstFile = 0;

  if ((my_lock = Lock(dir, ACCESS_READ)) != NULL)
    {
    if (Examine(my_lock, &FileInfo))
      {
      strcpy(&FileListEntry[FileCount++][0], "/ Parent (dir)");
      ExNext(my_lock, &FileInfo);

      while (IoErr() != ERROR_NO_MORE_ENTRIES && FileCount < MAXFILES)
        {
        if (strcmp(FileExt, (FileInfo.fib_FileName + strlen(FileInfo.fib_FileName) - strlen(FileExt))) == 0 || FileInfo.fib_DirEntryType > 0)
           {
           strcpy(&FileListEntry[FileCount][0], FileInfo.fib_FileName);
           if (FileInfo.fib_DirEntryType > 0)
             strcat(&FileListEntry[FileCount][0]," (dir)");
           FileCount++;
           }
        ExNext(my_lock, &FileInfo);
        }
      UnLock(my_lock) ;
      }
    }
  AttachList(FirstFile);
  if (FileCount > 8)
    ModifyProp(&PotGadget,FRWindow,&FileRequester,AUTOKNOB|FREEVERT|PROPBORDERLESS,0,0,0,(ULONG)0xffff*8/FileCount);
  else
    ModifyProp(&PotGadget,FRWindow,&FileRequester,AUTOKNOB|FREEVERT|PROPBORDERLESS,0,0,0,0xffff);
} /* ListDir */

/*
 *  AttachList - Attach list of file (directory) names to Selection gadgets
 */
void AttachList(Start)
  USHORT Start;
{
  USHORT Gadget;

  for (Gadget = 0; Gadget <= 7 && Gadget+Start < FileCount; Gadget++)
    {
    strcpy(FileList[Gadget].IText,&FileListEntry[Start + Gadget][0]);
    strncat(FileList[Gadget].IText, spaces30, 30-strlen(FileList[Gadget].IText));
    }
  for (; Gadget <= 7; Gadget++)
    strcpy(FileList[Gadget].IText,spaces30);

  RefreshGadgets(&DownGadget,FRWindow,&FileRequester);
} /* AttachList */

/*
 *  ScrollList - Scroll the list up or down 1 file if possible
 */
void ScrollList(gadget)
  struct Gadget *gadget;
{
  ULONG VertPot = 0;

  switch(gadget->GadgetID & GADGETNUM)
    {
    case DOWN:
         if (FileCount > FirstFile + 8)
           ++FirstFile;
         break;
    case UP:
         if (FirstFile > 0)
           --FirstFile;
    }
  if (FileCount > 8)
    VertPot  = MIN(0xffff,((FirstFile<<16))/(FileCount-8));
  ModifyProp(&PotGadget,FRWindow,&FileRequester,AUTOKNOB|FREEVERT|PROPBORDERLESS,0,VertPot,0,KnobInfo.VertBody);
  AttachList(FirstFile);
} /* ScrollList */

/*
 *  PotScrollList - Calculate the file number from Pot value and attach
 *                  names to Selector List gadgets.
 */
void PotScrollList(gadget)
  struct Gadget *gadget;
{
  switch (gadget->GadgetID & GADGETNUM)
    {
    case POT:
         FirstFile = ((ULONG)(FileCount-8)*KnobInfo.VertPot+(1<<15)) >> 16;
         AttachList(FirstFile);
    }
} /* PotScrollList */

/*
 *  IsDir - Simple minded routine to find " (dir)" in file name
 */
BOOL IsDir(Name)
  UBYTE *Name;
{
  UBYTE *Dir;
  if (Dir = rindex(Name,'('))
    {
    ThrowTrailing(Name);
    if (strcmp(Dir,"(dir)") == 0)
      {
      *(Dir-1) = '\0';
      return(TRUE);
      }
    else
      return(FALSE);
    }
  else
    return(FALSE);
} /* IsDir */

/*
 *  ThrowTrailing - Remove trailing blanks from string
 */
void ThrowTrailing(String)
  UBYTE *String;
{
  SHORT I;

  I = strlen(String) - 1;
  while (String[I] == ' ' && I > 0)
    String[I--] = '\0';
} /* ThrowTrailing */

/*
 * IsParent - Check if parent chosen
*/
BOOL IsParent(name)
  UBYTE *name;
  {
  ThrowTrailing(name);
  if (strcmp(name,"/ Parent (dir)") == 0)
     return (TRUE);
  else
     return (FALSE);
  } /* IsParent */


/*
 * GoParent - Change path to parent dir
*/
void GoParent(dir)
  STRPTR dir;
  {
  STRPTR StrPtr;

  if (StrPtr = rindex(dir,'/'))
     *StrPtr = '\0';
  else if (StrPtr = rindex(dir,':'))
     *(StrPtr+1) = '\0';
  } /* GoParent */


/*
 * ChangeDevice - Change to device chosen by buttons
*/
void ChangeDevice(gadget)
  struct Gadget *gadget;
  {
  UBYTE *text;

  text = DFGadget[gadget->GadgetID & GADGETNUM].GadgetText->IText;
  strcpy(FRFullPath, text);
  SetNewDrawer(&DrawerGadget, text);
  } /* ChangeDevice */


/*
 * ToUpper - Convert a string to all upper case
*/
void ToUpper(text)
  STRPTR text;
{
  ULONG i;

  for (i=0 ; i < strlen(text) ; i++)
     *(text+i) = toupper(*(text+i));  /* convert character */
}  /* ToUpper */
