/****************************************************************************
 *
 *  FileRequest() - File Name Requester
 *
 *  Version 2.1
 *
 *  This version of FileRequest is considerably modified from the
 *  original by Kevin Clague. It has been fixed to work under DOS 1.2 and new
 *  features have been added (such as the DF buttons, sorting of the
 *  file names, the file filter, the default display of the users
 *  current directory (including the path name builder), and scrolling 
 *  of names.
 *  
 *  Original version of FileRequest
 *  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 changes in this version by:
 *       Ray R. Larson
 *       6425 Central Ave. #304
 *       El Cerrito, CA 94530
 *
 *       BitNet  LARSON@UCBCMSA
 *       Well    rrl
 *       CServe  70446,766
 *    
 * This revised version Copyright (c) 1988 by Ray R. Larson
 * 
 * This program may be freely distributed and copied, but may not be sold
 * without the permission of the author. If you modify or enhance it, 
 * please include the above credits (and please send me a copy!).
 *
 ***************************************************************************/

#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <ctype.h>
#include <stdio.h>
#include <workbench/workbench.h>

#define INTUITION_REV      1
#define GRAPHICS_REV      1

#define CHARACTER_WIDTH  8
#define CHARACTER_HEIGHT 8

/* ========================================================================*/
/* File name requester gadget ids                                          */

#define CLASSBITS 8

#define UPDOWNCLASS 1
#define CHOICECLASS 2
#define STRINGCLASS 3
#define BUTTONCLASS 4

#define GADGETNUM 255

#define LOAD   0
#define CANCEL 1
#define TODF0  2 
#define TODF1  3 
#define TODH0  4 
#define TOVD0  5 
#define TORAM  6 
#define PARENT 7

#define DRAWER 0

#define UP     0
#define DOWN   1
#define POT    2

#define FILE0  0
#define FILE1  1
#define FILE2  2
#define FILE3  3
#define FILE4  4
#define FILE5  5
#define FILE6  6
#define FILE7  7

#define LOADGADGET   BUTTONCLASS << CLASSBITS | LOAD
#define CANCELGADGET BUTTONCLASS << CLASSBITS | CANCEL
#define DF0GADGET BUTTONCLASS << CLASSBITS | TODF0
#define DF1GADGET BUTTONCLASS << CLASSBITS | TODF1
#define DH0GADGET BUTTONCLASS << CLASSBITS | TODH0
#define VD0GADGET BUTTONCLASS << CLASSBITS | TOVD0
#define RAMGADGET BUTTONCLASS << CLASSBITS | TORAM
#define PARENTGADGET BUTTONCLASS << CLASSBITS | PARENT

#define UPGADGET     UPDOWNCLASS << CLASSBITS | UP
#define DOWNGADGET   UPDOWNCLASS << CLASSBITS | DOWN
#define POTGADGET    UPDOWNCLASS << CLASSBITS | POT

#define FILE0GADGET  CHOICECLASS << CLASSBITS | FILE0
#define FILE1GADGET  CHOICECLASS << CLASSBITS | FILE1
#define FILE2GADGET  CHOICECLASS << CLASSBITS | FILE2
#define FILE3GADGET  CHOICECLASS << CLASSBITS | FILE3
#define FILE4GADGET  CHOICECLASS << CLASSBITS | FILE4
#define FILE5GADGET  CHOICECLASS << CLASSBITS | FILE5
#define FILE6GADGET  CHOICECLASS << CLASSBITS | FILE6
#define FILE7GADGET  CHOICECLASS << CLASSBITS | FILE7

#define DRAWERGADGET STRINGCLASS << CLASSBITS | DRAWER

#define MAXFILES 100
 
BOOL IsDir();
BOOL WaitRequester();
extern UBYTE  *rindex();
extern struct IntuiMessage *GetMsg();
struct Requester FileRequester;

UBYTE *FullPath;
UBYTE *ExcludeExt;
UBYTE *LimitExt;
UBYTE pathname[100];

struct Window       *window;
struct IntuiMessage *message;
struct RastPort *FileReqRP;
struct FileInfoBlock *FileInfo;

USHORT FileCount;                     /* Number of files in current dir */
UBYTE  FileListEntry[MAXFILES][40];   /* File (dir) names in current dir */

USHORT FirstFile;

#define PATHNAMELEN 120

/****************************************************************************
 *                The Gadget String
 ***************************************************************************/
/******************************
 * The File Name Gadget stuff *
 *****************************/
struct IntuiText FileText =
  {
  0,1, JAM2,              /* frontpen, packpen, drawmode */
  -46,0,                  /* left,top */
  NULL,                   /* font */
  (UBYTE *)"File:",                /* text */
  NULL                    /* next */
  };

UBYTE FileName[40];
UBYTE Backup[100];
struct StringInfo FileString = {
    &FileName[0],               /* input buffer */
    &Backup[0],                 /* undo  buffer */
    0,                       /* Buffer position */
    32,                      /* buffer size  */
    0,                       /* disp position*/
    0,0,0,0,0,NULL,0,NULL    /* undo position*/
  };

SHORT DrawerPoints[] = {
    -2, -2,
    185,-2,
    185,10,
    -2, 10,
    -2, -2
    };
struct Border DrawerBorder = {
    0,0,
    0,1,JAM1,
    5,
    &DrawerPoints[0],
    NULL
  };

struct Gadget FileGadget =
  { /* File string */
  NULL,                    /* next gadget */
  67,139,                  /* location    */
  185,8,
  GADGHCOMP,               /* flags       */
  0,                       /* activation  */
  STRGADGET|REQGADGET,     /* type        */
  (APTR) &DrawerBorder,    /* rendering   */
  NULL,                    /* rendering   */
  &FileText,               /* text        */
  0,                       /* mutual exlcude */
  (APTR)&FileString,             /* string info */
  NULL,                    /* gadget id   */
  NULL                     /* special info*/
  };

/********************************
 * The Drawer Name Gadget stuff *
 *******************************/
struct IntuiText DrawerText = 
  {
  0,1, JAM2,              /* frontpen, packpen, drawmode */
  -62,0,                  /* left,top */
  NULL,                   /* font */
  (UBYTE *)"Drawer:",              /* text */
  NULL                    /* next */
  };

UBYTE DrawerName[100];
struct StringInfo DrawerString = {
    &DrawerName[0],             /* input buffer */
    &Backup[0],                 /* undo  buffer */
    0,                       /* Buffer position */
    100,                      /* buffer size  */
    0,                       /* disp position*/
    0,0,0,0,0,NULL,0,NULL    /* undo position*/
  };

struct Gadget DrawerGadget =
  { /* Drawer string */
  &FileGadget,             /* next gadget */
  67,124,                   /* location    */
  185,8,
  GADGHCOMP,               /* flags       */
  RELVERIFY,               /* activation  */
  STRGADGET|REQGADGET,     /* type        */
  (APTR) &DrawerBorder,    /* rendering   */
  NULL,                    /* rendering   */
  &DrawerText,             /* text        */
  0,                       /* mutual exlcude */
  (APTR)&DrawerString,           /* string info */
  DRAWERGADGET,            /* gadget id   */
  NULL                     /* special info*/
  };

/****************************************
 * The File list selection Gadget stuff *
 ***************************************/
UBYTE PickNames[8][40];
struct IntuiText FileList[] =
  {
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,14,                    /* left,top */
    NULL,                   /* font */
    &PickNames[0][0],       /* text */
    &FileList[1]            /* next */
    },
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,24,                    /* left,top */
    NULL,                   /* font */
    &PickNames[1][0],       /* text */
    &FileList[2]            /* next */
    },
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,34,                    /* left,top */
    NULL,                   /* font */
    &PickNames[2][0],       /* text */
    &FileList[3]            /* next */
    },
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,44,                    /* left,top */
    NULL,                   /* font */
    &PickNames[3][0],       /* text */
    &FileList[4]            /* next */
    },
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,54,                    /* left,top */
    NULL,                   /* font */
    &PickNames[4][0],       /* text */
    &FileList[5]            /* next */
    },
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,64,                    /* left,top */
    NULL,                   /* font */
    &PickNames[5][0],       /* text */
    &FileList[6]            /* next */
    },
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,74,                    /* left,top */
    NULL,                   /* font */
    &PickNames[6][0],       /* text */
    &FileList[7]            /* next */
    },
    {
    0,1, JAM2,              /* frontpen, packpen, drawmode */
    5,84,                    /* left,top */
    NULL,                   /* font */
    &PickNames[7][0],       /* text */
    NULL                    /* next */
    }
  };

struct Gadget FileListGadget[] =
  {
    { /* File name selection 0 */
    &FileListGadget[1],      /* next gadget */
    5,14,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE0GADGET,             /* gadget id   */
    (APTR)&PickNames[0][0]         /* special info*/
    },
    { /* File name selection 1 */
    &FileListGadget[2],      /* next gadget */
    5,24,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE1GADGET,             /* gadget id   */
    (APTR)&PickNames[1][0]         /* special info*/
    },
    { /* File name selection 2 */
    &FileListGadget[3],      /* next gadget */
    5,34,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE2GADGET,             /* gadget id   */
    (APTR)&PickNames[2][0]         /* special info*/
    },
    { /* File name selection 3 */
    &FileListGadget[4],      /* next gadget */
    5,44,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE3GADGET,             /* gadget id   */
    (APTR)&PickNames[3][0]         /* special info*/
    },
    { /* File name selection 4 */
    &FileListGadget[5],      /* next gadget */
    5,54,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE4GADGET,             /* gadget id   */
    (APTR)&PickNames[4][0]         /* special info*/
    },
    { /* File name selection 5 */
    &FileListGadget[6],      /* next gadget */
    5,64,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE5GADGET,             /* gadget id   */
    (APTR)&PickNames[5][0]         /* special info*/
    },
    { /* File name selection 6 */
    &FileListGadget[7],      /* next gadget */
    5,74,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE6GADGET,             /* gadget id   */
    (APTR)&PickNames[6][0]         /* special info*/
    },
    { /* File name selection 7 */
    &DrawerGadget,           /* next gadget */
    5,84,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    GADGIMMEDIATE,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    NULL,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    FILE7GADGET,             /* gadget id   */
    (APTR)&PickNames[7][0]         /* special info*/
    }
  };


/**********************************************************************
 *  Border Definitions for device gadgets
 **********************************************************************/

SHORT device_Pairs_1[] = {
  0,     0,   
  34,     0,   
  34,     10,   
  0,     10,   
  0,     0    
};
struct Border device_bord_1 = {
  -1,  -1,       /* LeftEdge, TopEdge */
  0,  1,  JAM2,  /* FrontPen, BackPen, DrawMode*/
  5,             /* Count of XY pairs */  
  (SHORT *)&device_Pairs_1, /* XY pairs */
  NULL           /* Next Border */
};


/**********************************************************************
 *  IntuiTexts for the DF0GAD gadget.
 **********************************************************************/

struct IntuiText DF0GAD_Text_0 = {
   0, 1,     /* FrontPen, BackPen */
   JAM2,       /* DrawMode */
   1, 1,     /* LeftEdge, TopEdge */
   NULL, /* ITextFont Pointer */ 
   /* The IText */
   (UBYTE *)"DF0:",
   NULL
 };



/**********************************************************************
 *  Gadget Structure definition for the DF0GAD gadget.
 **********************************************************************/

struct Gadget DF0GAD = {
  &FileListGadget[0],  /* NextGadget pointer */
  20, 97,              /* LeftEdge, TopEdge  */
  33, 9,               /* Width, Height      */
         /* Gadget Flags */
  GADGHCOMP,
       /* Activation Flags */
  GADGIMMEDIATE,
          /* GadgetType */
  BOOLGADGET,
  (APTR)&device_bord_1,/*  GadgetRender      */
  NULL,                /* SelectRender       */
   &DF0GAD_Text_0,     /* GadgetText         */
  0x0,                 /* MutualExclude      */
  NULL,                /* SpecialInfo        */
  DF0GADGET,           /* GadgetID           */
  NULL                 /* UserData Pointer   */
};


/**********************************************************************
 *  IntuiTexts for the DF1GAD gadget.
 **********************************************************************/

struct IntuiText DF1GAD_Text_0 = {
   0, 1,     /* FrontPen, BackPen */
   JAM2,       /* DrawMode */
   1, 1,     /* LeftEdge, TopEdge */
   NULL, /* ITextFont Pointer */ 
   /* The IText */
   (UBYTE *)"DF1:",
   NULL
 };



/**********************************************************************
 *  Gadget Structure definition for the DF1GAD gadget.
 **********************************************************************/

struct Gadget DF1GAD = {
  &DF0GAD,                /* NextGadget pointer */
  68, 97,              /* LeftEdge, TopEdge  */
  33, 9,               /* Width, Height      */
         /* Gadget Flags */
  GADGHCOMP,
       /* Activation Flags */
  GADGIMMEDIATE,
          /* GadgetType */
  BOOLGADGET,
  (APTR)&device_bord_1,/*  GadgetRender      */
  NULL,                /* SelectRender       */
   &DF1GAD_Text_0,     /* GadgetText         */
  0x0,                 /* MutualExclude      */
  NULL,                /* SpecialInfo        */
  DF1GADGET,           /* GadgetID           */
  NULL                 /* UserData Pointer   */
};


/**********************************************************************
 *  IntuiTexts for the DH0GAD gadget.
 **********************************************************************/

struct IntuiText DH0GAD_Text_0 = {
   0, 1,     /* FrontPen, BackPen */
   JAM2,       /* DrawMode */
   1, 1,     /* LeftEdge, TopEdge */
   NULL, /* ITextFont Pointer */ 
   /* The IText */
   (UBYTE *)"DH0:",
   NULL
 };



/**********************************************************************
 *  Gadget Structure definition for the DH0GAD gadget.
 **********************************************************************/

struct Gadget DH0GAD = {
  &DF1GAD,                /* NextGadget pointer */
  116, 97,              /* LeftEdge, TopEdge  */
  33, 9,               /* Width, Height      */
         /* Gadget Flags */
  GADGHCOMP,
       /* Activation Flags */
  GADGIMMEDIATE,
          /* GadgetType */
  BOOLGADGET,
  (APTR)&device_bord_1,/*  GadgetRender      */
  NULL,                /* SelectRender       */
   &DH0GAD_Text_0,     /* GadgetText         */
  0x0,                 /* MutualExclude      */
  NULL,                /* SpecialInfo        */
  DH0GADGET,           /* GadgetID           */
  NULL                 /* UserData Pointer   */
};



/**********************************************************************
 *  IntuiTexts for the VD0GAD gadget.
 **********************************************************************/

struct IntuiText VD0GAD_Text_0 = {
   0, 1,     /* FrontPen, BackPen */
   JAM2,       /* DrawMode */
   1, 1,     /* LeftEdge, TopEdge */
   NULL, /* ITextFont Pointer */ 
   /* The IText */
   (UBYTE *)"VD0:",
   NULL
 };



/**********************************************************************
 *  Gadget Structure definition for the VD0GAD gadget.
 **********************************************************************/

struct Gadget VD0GAD = {
  &DH0GAD,                /* NextGadget pointer */
  164, 97,              /* LeftEdge, TopEdge  */
  33, 9,               /* Width, Height      */
         /* Gadget Flags */
  GADGHCOMP,
       /* Activation Flags */
  GADGIMMEDIATE,
          /* GadgetType */
  BOOLGADGET,
  (APTR)&device_bord_1,/*  GadgetRender      */
  NULL,                /* SelectRender       */
   &VD0GAD_Text_0,     /* GadgetText         */
  0x0,                 /* MutualExclude      */
  NULL,                /* SpecialInfo        */
  VD0GADGET,           /* GadgetID           */
  NULL                 /* UserData Pointer   */
};



/**********************************************************************
 *  IntuiTexts for the RAMGAD gadget.
 **********************************************************************/

struct IntuiText RAMGAD_Text_0 = {
   0, 1,     /* FrontPen, BackPen */
   JAM2,       /* DrawMode */
   1, 1,     /* LeftEdge, TopEdge */
   NULL, /* ITextFont Pointer */ 
   /* The IText */
   (UBYTE *)"RAM:",
   NULL
 };



/**********************************************************************
 *  Gadget Structure definition for the RAMGAD gadget.
 **********************************************************************/

struct Gadget RAMGAD = {
  &VD0GAD,                /* NextGadget pointer */
  212, 97,              /* LeftEdge, TopEdge  */
  33, 9,               /* Width, Height      */
         /* Gadget Flags */
  GADGHCOMP,
       /* Activation Flags */
  GADGIMMEDIATE,
          /* GadgetType */
  BOOLGADGET,
  (APTR)&device_bord_1,/*  GadgetRender      */
  NULL,                /* SelectRender       */
   &RAMGAD_Text_0,     /* GadgetText         */
  0x0,                 /* MutualExclude      */
  NULL,                /* SpecialInfo        */
  RAMGADGET,           /* GadgetID           */
  NULL                 /* UserData Pointer   */
};

/**********************************************************************
 *  Border Definitions for Parent gadget
 **********************************************************************/

SHORT PARENT_Pairs_1[] = {
  0,     0,   
  68,     0,   
  68,     10,   
  0,     10,   
  0,     0    
};
struct Border PARENT_bord_1 = {
  -1,  -1,       /* LeftEdge, TopEdge */
  0,  1,  JAM2,  /* FrontPen, BackPen, DrawMode*/
  5,             /* Count of XY pairs */  
  (SHORT *)&PARENT_Pairs_1, /* XY pairs */
  NULL           /* Next Border */
};


/**********************************************************************
 *  IntuiTexts for the PARENTGAD gadget.
 **********************************************************************/

struct IntuiText PARENTGAD_Text_0 = {
   0, 1,     /* FrontPen, BackPen */
   JAM2,       /* DrawMode */
   1, 1,     /* LeftEdge, TopEdge */
   NULL, /* ITextFont Pointer */ 
   /* The IText */
   (UBYTE *)" PARENT ",
   NULL
 };



/**********************************************************************
 *  Gadget Structure definition for the PARENTGAD gadget.
 **********************************************************************/

struct Gadget PARENTGAD = {
  &RAMGAD,  /* NextGadget pointer */
  100, 110,              /* LeftEdge, TopEdge  */
  67, 9,               /* Width, Height      */
         /* Gadget Flags */
  GADGHCOMP,
       /* Activation Flags */
  GADGIMMEDIATE,
          /* GadgetType */
  BOOLGADGET,
  (APTR)&PARENT_bord_1,/*  GadgetRender      */
  NULL,                /* SelectRender       */
   &PARENTGAD_Text_0,     /* GadgetText         */
  0x0,                 /* MutualExclude      */
  NULL,                /* SpecialInfo        */
  PARENTGADGET,           /* GadgetID           */
  NULL                 /* UserData Pointer   */
};



/********************************
 * The Load FRQButton gadget stuff *
 *******************************/
SHORT FRQButtonPoints1[] =
  {
  -4, -4,
  66, -4,
  66, 12,
  -4, 12,
  -4, -4
  };
struct Border FRQButtonBorder1 =
  {
  0,0,
  2,1,JAM1,
  5,
  &FRQButtonPoints1[0],
  NULL
  };
SHORT FRQButtonPoints0[] =
  {
  -3, -2,
  65, -2,
  65, 10,
  -3, 10,
  -3, -2
  };
struct Border FRQButtonBorder0 =
  {
  0,0,
  0,1,JAM1,
  5,
  &FRQButtonPoints0[0],
  &FRQButtonBorder1
  };

struct IntuiText FRQLoadText =
  {
  0,1, JAM2,              /* frontpen, packpen, drawmode */
  0,0,                    /* left,top */
  NULL,                   /* font */
  NULL,                   /* text */
  NULL                    /* next */
  };

struct Gadget FRQLoadGadget =
  { /* FRQLoad FRQButton */
  &PARENTGAD,      /* next gadget */
  14,156,                  /* location    */
  64,8,
  GADGHCOMP,               /* flags       */
  GADGIMMEDIATE|ENDGADGET, /* activation  */
  BOOLGADGET|REQGADGET,    /* type        */
  (APTR) &FRQButtonBorder0,   /* rendering   */
  NULL,                    /* rendering   */
  &FRQLoadText,               /* text        */
  0,                       /* mutual exlcude */
  NULL,                    /* string info */
  LOADGADGET,              /* gadget id   */
  NULL                     /* special info*/
  };

/**********************************
 * The Cancel FRQButton gadget stuff *
 *********************************/
struct IntuiText FRQCancelText =
  {
  0,1, JAM2,              /* frontpen, packpen, drawmode */
  0,0,                    /* left,top */
  NULL,                   /* font */
  (UBYTE *)"Cancel",               /* text */
  NULL                    /* next */
  };

struct Gadget FRQCancelGadget =
  { /* Cancel FRQButton */
  &FRQLoadGadget,             /* next gadget */
  187,156,                 /* location    */
  64,8,
  GADGHCOMP,               /* flags       */
  GADGIMMEDIATE|ENDGADGET, /* activation  */
  BOOLGADGET|REQGADGET,    /* type        */
  (APTR) &FRQButtonBorder0,   /* rendering   */
  NULL,                    /* rendering   */
  &FRQCancelText,             /* text        */
  0,                       /* mutual exlcude */
  NULL,                    /* string info */
  CANCELGADGET,            /* gadget id   */
  NULL                     /* special info*/
  };

/***************************************************
 * The Scroll Selection List up (STD arrow) gadget *
 ***************************************************/
extern struct Image UpArrow;
struct Gadget FRQUpGadget =
  { /* Up a file gadget */
  &FRQCancelGadget,           /* next gadget */
  247,13,                     /* location    */
  12,15,
  GADGIMAGE|GADGHNONE,        /* flags       */
  GADGIMMEDIATE | RELVERIFY,  /* activation  */
  BOOLGADGET|REQGADGET,       /* type        */
  (APTR) &UpArrow,            /* rendering   */
  NULL,                       /* rendering   */
  NULL,                       /* text        */
  0,                          /* mutual exlcude */
  NULL,                       /* string info */
  UPGADGET,                   /* gadget id   */
  NULL                        /* special info*/
  };
/*************************************************
 * The Scroll Selection List down (arrow) gadget *
 ************************************************/
extern struct Image DownArrow;
struct Gadget FRQDownGadget =
  { /* Down a file gadget */
  &FRQUpGadget,               /* next gadget */
  247,79,                     /* location    */
  12,15,
  GADGIMAGE|GADGHNONE,        /* flags       */
  GADGIMMEDIATE | RELVERIFY,  /* activation  */
  BOOLGADGET|REQGADGET,       /* type        */
  (APTR) &DownArrow,          /* rendering   */
  NULL,                       /* rendering   */
  NULL,                       /* text        */
  0,                          /* mutual exlcude */
  NULL,                       /* string info */
  DOWNGADGET,                 /* gadget id   */
  NULL                        /* special info*/
  };

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

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

struct Gadget FRQPotGadget =
  { /* Potentiometer file gadget */
  &FRQDownGadget,             /* next gadget */
  247,28,                     /* location    */
  14,50,
  GADGHNONE,                  /* flags       */
  GADGIMMEDIATE | RELVERIFY,  /* activation  */
  PROPGADGET|REQGADGET,       /* type        */
  (APTR) &FRQKnobImage,       /* rendering   */
  NULL,                       /* rendering   */
  NULL,                       /* text        */
  0,                          /* mutual exlcude */
  (APTR)&FRQKnobInfo,         /* string info */
  POTGADGET,                  /* gadget id   */
  NULL                        /* special info*/
  };
/***************************************************************************
*                  Other Requester structures                              *
***************************************************************************/
struct IntuiText FRQHeadingText =
  {
  2,1, JAM2,              /* frontpen, packpen, drawmode */
  4,3,                    /* left,top */
  NULL,                   /* font */
  NULL,                   /* text */
  NULL                    /* next */
  };

SHORT FRQ0Points[] = {
  2,1,
  261,1,
  261,172,
  2,172,
  2,1
  };
struct Border FRQ0Border = {
  0,0,
  0,1,JAM1,
  5,
  &FRQ0Points[0],
  NULL
  };

SHORT FRQ1Points[] = {
  2,12,
  261,12
  };
struct Border FRQ1Border = {
  0,0,
  0,1,JAM1,
  2,
  &FRQ1Points[0],
  &FRQ0Border
  };

SHORT FRQ2Points[] = {
  2,93,
  261,93
  };
struct Border FRQ2Border = {
  0,0,
  0,1,JAM1,
  2,
  &FRQ2Points[0],
  &FRQ1Border
  };

SHORT FRQ3Points[] = {
  246,12,
  246,93,
  246,78,
  261,78,
  261,27,
  247,27
  };
struct Border FRQ3Border = {
  0,0,
  0,1,JAM1,
  6,
  &FRQ3Points[0],
  &FRQ2Border
  };

/****************************************************************************
 *                     The Code part of the requester
 ***************************************************************************/
BOOL FileRequest(FileType,Action,FullName,Exclude,Limit,ReqWindow)
  UBYTE *FileType;
  UBYTE *Action;
  UBYTE *FullName;
  UBYTE *Exclude; 
  UBYTE *Limit;
  struct Window *ReqWindow;
{
  UBYTE *StrPtr;
  BOOL   RetCode;
  APTR  AllocMem(); /* have to use memory allocation for FileInfoBlocks */

  window = ReqWindow;           /* make pointer to window and name global */
  FullPath = FullName;          /* buffer for returned filename           */
  ExcludeExt = Exclude;         /* exclude files with this extension from */
                                /* display. eg ".info"                    */
  LimitExt = Limit;             /* Limit display to files with this ext.  */
  
  FRQHeadingText.IText = FileType; /* Center requester title */
  FRQHeadingText.LeftEdge = (256-IntuiTextLength(&FRQHeadingText))/2;
  FRQLoadText.IText = Action;

  FileInfo = (struct FileInfoBlock *)
               AllocMem((LONG)sizeof(struct FileInfoBlock),MEMF_PUBLIC);

  InitFNR();

  /* if the fullname is a NULL string, get the user's current directory */

  if (FullName[0] == '\0') 
    {
     GetPath(FullName);
     *FileString.Buffer = '\0';
     strcpy(DrawerString.Buffer,FullName);
    }
  else
    {
     /* Separate the path from the file name. Set the file name in the gadget */
     if (StrPtr = rindex(FullName,'/'))
       {
       strcpy(FileString.Buffer,StrPtr + 1);
       *StrPtr = '\0';
       }
     else
       if (StrPtr = rindex(FullName,':'))
         {
         strcpy(FileString.Buffer,StrPtr + 1);
         *(StrPtr+1) = '\0';
         }
       else
         {
         *FileString.Buffer   = '\0';
         *DrawerString.Buffer = '\0';
         *FullName = '\0';
         }
      strcpy(DrawerString.Buffer,FullName);
     }
  /* Put up the requester and list the dir into it */ 
  Request(&FileRequester,window);
  FileReqRP = FileRequester.ReqLayer->rp; /* the requester's rastport */
  ListDir(FullName);
  SetNewFile(&FileGadget,FileString.Buffer); /* why do I have to do this? */
  SetNewFile(&DrawerGadget,DrawerString.Buffer);

  RetCode = WaitRequester();         /* do everything till Cancel or Load */
  
  FreeMem(FileInfo,(LONG)sizeof(struct FileInfoBlock));
  
  /* Put file name and path back together */
  if (FullName[strlen(FullName)-1] != ':')
    strcat(FullName,"/");
  strcat(FullName,FileString.Buffer);
  return(RetCode);
} /* LoadRequest */

/*
 *  Init the file name requester
 */
InitFNR()
{
  InitRequester(&FileRequester);
  FileRequester.Width     = 264;
  FileRequester.Height    = 174;
  FileRequester.LeftEdge  = 20;
  FileRequester.TopEdge   = 12;
  FileRequester.ReqGadget = &FRQPotGadget;
  FileRequester.ReqText   = &FRQHeadingText;
  FileRequester.BackFill  = 1;
  FileRequester.Flags     = 0;
  FileRequester.ReqBorder = &FRQ3Border;
} /* 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;
  UBYTE *lastslash;
  ULONG saveflags;
  SHORT pauseticks;
  BOOL watchpot, watchticks, upmove, downmove;
  
  saveflags = window->IDCMPFlags;
    
  ModifyIDCMP(window, GADGETUP | GADGETDOWN | REQCLEAR | INTUITICKS | MOUSEMOVE);
 
  watchpot = upmove = downmove = watchticks = FALSE;

  while (class != REQCLEAR)
    {
    if ((message=GetMsg(window->UserPort)) == 0L)
      { 
       Wait(1L<<window->UserPort->mp_SigBit);
       continue;
      }
    class  = message->Class;
    gadget = (struct Gadget *) message->IAddress;
    ReplyMsg(message);
    switch (class)
      {
      case GADGETDOWN:
           switch (gadget->GadgetID >> CLASSBITS)
             {
             case UPDOWNCLASS:
                  switch(choice = (gadget->GadgetID & GADGETNUM))
                     { 
                       case UP:   upmove = TRUE; 
                                  break;
                       case DOWN: downmove = TRUE; 
                                  break;
                       case POT : watchpot = TRUE; 
                                  break;
                     }
                  if (upmove || downmove)
                     { watchticks = TRUE;
                       pauseticks = 2;
                       ScrollFileList(gadget,choice);      /* scroll up/down 1 file */
                     }
                  break;
                  
             case CHOICECLASS:             /* set the name in string gads */
                  if (IsDir(gadget->UserData))
                    SetNewDrawer(&DrawerGadget,gadget->UserData);
                  else
                    SetNewFile(&FileGadget,gadget->UserData);
                  break;
             case BUTTONCLASS:             /* LOAD or CANCEL */
                  choice = gadget->GadgetID & GADGETNUM;
		  if (choice < 2) break; /* load or cancel */
                  switch (choice)
                    {
                    case TODF0:
                         strcpy(FullPath,"DF0:");
                         strcpy(DrawerString.Buffer,FullPath);
                         break;

                    case TODF1:
                         strcpy(FullPath,"DF1:");
                         strcpy(DrawerString.Buffer,FullPath);
                         break;

                    case TODH0:
                         strcpy(FullPath,"DH0:");
                         strcpy(DrawerString.Buffer,FullPath);
                         break;

                    case TOVD0:
                         strcpy(FullPath,"VD0:");
                         strcpy(DrawerString.Buffer,FullPath);
                         break;

                    case TORAM:
                         strcpy(FullPath,"RAM:");
                         strcpy(DrawerString.Buffer,FullPath);
                         break;

                    case PARENT:
                         if (FullPath[strlen(FullPath)-1] == ':') break;
                         lastslash = rindex(FullPath,'/');
		         if (lastslash == NULL) 
		           { lastslash = rindex(FullPath,':');
			     if (lastslash == NULL) break;
		             lastslash++;
                           }
                         *lastslash = '\0';
                         strcpy(DrawerString.Buffer,FullPath);
                         break;

                    }
                   SetNewFile(&FileGadget,"");
                   ListDir(DrawerString.Buffer);

             }
             break;

      case GADGETUP:
           switch (gadget->GadgetID >> CLASSBITS)
             {
             case UPDOWNCLASS:             /* Potentiometer scroll */
                  switch(choice = (gadget->GadgetID & GADGETNUM))
                     { 
                       case UP: 
                              watchticks = FALSE; 
                              upmove = FALSE;
                            break;

                       case DOWN: 
                               watchticks = FALSE; 
                               downmove = FALSE;
                            break;

                       case POT : 
                               watchpot = FALSE;
                            break;
                     }
                  if (choice == POT)
                  PotScrollFileList();
                  break;

             case STRINGCLASS:             /* They typed drawer name in */
                  ThrowTrailing(DrawerString.Buffer);
                  strcpy(FullPath,DrawerString.Buffer);
                  SetNewFile(&FileGadget,"");
                  ListDir(DrawerString.Buffer);
             }
             break;

      case INTUITICKS:
             /* wait for pauseticks before starting scrolling */
             if (watchticks) pauseticks--;
             if (pauseticks == 0) watchticks = FALSE;
             else break;
             /* when pauseticks is zero move up or down */
             if (upmove) ScrollFileList(NULL,UP);      /* scroll up 1 file */
             if (downmove) ScrollFileList(NULL,DOWN);  /* scroll down 1 file */
           break;

      case MOUSEMOVE: 
             if (watchpot) PotScrollFileList();

           break;
      }
    }
  /* restore the user's IDCMP flags */ 
  ModifyIDCMP(window, saveflags);
  /* Return whether the load or cancel was selected */
  return(choice==LOAD);
} /* WaitRequester */

/*
 *  SetNewDrawer - Used Mouse to pick directory from selection list gadgets.
 */ 
SetNewDrawer(Gadget,Text)
  struct Gadget *Gadget;
  UBYTE  *Text;
{
  SetNewFile(&FileGadget,"");              /* clear file name string */
  if (FullPath[strlen(FullPath)-1] != ':') /* make new path */
    strncat(FullPath,"/",PATHNAMELEN);
  strncat(FullPath,Text,PATHNAMELEN);
  SetNewFile(Gadget,FullPath);             /* set new drawer into gadget */
  ListDir(FullPath);                       /* List new files into Sel List */
} /* SetNewDrawer */

/*
 *  SetNewFile - jams a new filename into the string gadget buffer.
 *               to be really safe we should remove gadgets,
 *               change strings and add them again, but this seems to work.
 *  
 */
SetNewFile(Gadget,Text)
  struct Gadget *Gadget;
  UBYTE  *Text;
{
  USHORT Pos, RemoveGadget();
  struct StringInfo *si;
  if (Text[0] != ' ')
    {
    ThrowTrailing(Text);                    /* get rid of trailing blanks */
    si = (struct StringInfo *)Gadget->SpecialInfo;
    strcpy(si->Buffer,Text);
    RefreshGList(&DrawerGadget,window,&FileRequester,2L);
    }
} /* SetNewFile */

/*
 *  ListDir - List the directory into array of string names.
 */
ListDir(dir)
  char *dir;
{
  struct FileLock *my_lock, *Lock() ;
  int sortcompare();
  UBYTE *ext;
  BOOL OKtoAdd, limitmatch, excludematch;
  LONG IoErr();
  
  FileCount = 0;
  FirstFile = 0;

  if ((my_lock = Lock(dir, ACCESS_READ)) != NULL)
    {
    if (Examine(my_lock, FileInfo))
      { 
      while ( ExNext(my_lock, FileInfo) && FileCount < MAXFILES)
        {  
        if (FileInfo->fib_DirEntryType > 0) /* alway add directories */
           {
            strcpy(&FileListEntry[FileCount][0]," (dir) ");
            strcat(&FileListEntry[FileCount][0], FileInfo->fib_FileName);
            FileCount++;
           }
        else /* not a directory */
           { 
             OKtoAdd = TRUE;
             limitmatch = FALSE;
             excludematch = FALSE;
             if (LimitExt || ExcludeExt)  /* do we have limit or exclude parms?*/
               { 
                 ext = rindex(FileInfo->fib_FileName,'.');
		 if (LimitExt) OKtoAdd = FALSE;
                 if (ext && (strcmp(ext,LimitExt) == 0)) /* matches limit */
                    limitmatch = TRUE;
                 if (ext && (strcmp(ext,ExcludeExt) == 0)) /* matches exclude*/
                    excludematch = TRUE;
                    
                }
             if ((OKtoAdd || limitmatch ) && !excludematch)
                {
                 strcpy(&FileListEntry[FileCount][0], FileInfo->fib_FileName);
                 FileCount++;
                }
            } /* end of normal file processing (else) */
        } /* end of exnext while loop */
      UnLock(my_lock) ;
      }
    }

  /* sort the files */
  qsort(FileListEntry,FileCount,40,sortcompare);
  AttachFileList(FirstFile);
  if (FileCount > 8)
    NewModifyProp(&FRQPotGadget,window,&FileRequester,
                  AUTOKNOB|FREEVERT|PROPBORDERLESS,
                  0L,0L,0L,(LONG)(0xffff/(FileCount-6)*8),1L);
  else
    ModifyProp(&FRQPotGadget,window,&FileRequester,
               AUTOKNOB|FREEVERT|PROPBORDERLESS,
                0L,0L,0L,(LONG)0xffff,1L);
} /* ListDir */

/**********************************************
  Comparsion routine for Manx builtin qsort
***********************************************/
sortcompare(a,b)
char *a,*b;
{   
    return(strcmp(a,b));
}

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

  for (Gadget = 0; Gadget <= 7 && Gadget+Start < FileCount; Gadget++)
    {
    strcpy(FileList[Gadget].IText,&FileListEntry[Start + Gadget][0]);
    strncat(FileList[Gadget].IText,"                                ",24-strlen(FileList[Gadget].IText));
    FileList[Gadget].IText[24] = '\0';
    }
  for (; Gadget <= 7; Gadget++)
    {
    strncpy(FileList[Gadget].IText,"                                ",24);
    FileList[Gadget].IText[24] = '\0';
    }
  PrintIText(FileReqRP,&FileList[0],0L,0L);
  /*RefreshGList(&FRQDownGadget,window,&FileRequester,1L);*/
} /* AttachFileList */

/*
 *  ScrollFileList - Scroll the list up or down 1 file if possible
 */
ScrollFileList(gadget,direction)
  struct Gadget *gadget;
  USHORT direction;
{
  ULONG VertPot = 0;
  
  if (gadget != NULL) direction = gadget->GadgetID & GADGETNUM;

  switch(direction)
    {
    case DOWN:
         if (FileCount > FirstFile + 8)
           ++FirstFile;
         break;
    case UP:
         if (FirstFile > 0)
           --FirstFile;
    }
  if (FileCount > 8)
    VertPot  = 0xffff/(FileCount-6)*FirstFile;
  ModifyProp(&FRQPotGadget,window,&FileRequester,
             AUTOKNOB|FREEVERT|PROPBORDERLESS,
             0L,(LONG)VertPot,0L,(LONG)FRQKnobInfo.VertBody,1L);
  AttachFileList(FirstFile);
} /* ScrollFileList */

/*
 *  PotScrollFileList - Calculate the file number from Pot value and attach
 *                  names to Selector List gadgets.
 */
PotScrollFileList()
{ 
  USHORT tempfile;

         tempfile = (USHORT)((LONG)(FileCount-6)*(LONG)FRQKnobInfo.VertPot >> 16);
         
         if (tempfile == FirstFile) return;
         FirstFile = tempfile;
         AttachFileList(FirstFile);

} /* PotScrollFileList */

/*
 *  IsDir - Simple minded routine to find " (dir)" in file name 
 */
BOOL IsDir(Name)
  UBYTE *Name;
{
  UBYTE *Dir;
  
  if (strncmp(Name," (dir) ",7) == 0)
      {
      Dir = Name + 7;
      strcpy(Name,Dir);
      ThrowTrailing(Name);
      return(TRUE);
      }
    else
      return(FALSE);
} /* IsDir */

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

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



/* 
 *  GetPath - retrieve the full path name for a file or directory
 */
struct Remember *RemBase; /* global root for allocated list */


GetPath(Path)
UBYTE *Path;
{
   struct FileLock *FirstDir, *Parent, *release, *Lock(), *ParentDir();
   struct FileInfoBlock *FBlock;
   APTR AllocRemember();
   
   RemBase = NULL;

   FirstDir = Lock("",ACCESS_READ);
   release = NULL;

   FBlock = (struct FileInfoBlock *) AllocRemember(&RemBase,
             (LONG)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
   Examine(FirstDir,FBlock);
   Parent = ParentDir(FirstDir);

   while (Parent != NULL)
      {
        FBlock = (struct FileInfoBlock *) AllocRemember(&RemBase,
             (LONG)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
        Examine(Parent,FBlock);
        release = Parent;
        Parent = ParentDir(release);
        UnLock(release);
       }
      
   getpathname(Path); 
   FreeRemember(&RemBase,TRUE);
   UnLock(FirstDir);

}


/*
 *  getpathname - Scan the list built by traverse and create pathnames.
 */
getpathname(Path)
UBYTE *Path;
{
  struct Remember *p;
  struct FileInfoBlock *FBlock;
  
  p = RemBase; /* seems the first remember block is garbage */
  FBlock = (struct FileInfoBlock *)p->Memory;
  strcpy(Path,FBlock->fib_FileName);
  strcat(Path,":");
  while (p = p->NextRemember)
     {   FBlock = (struct FileInfoBlock *)p->Memory;
         strcat(Path,FBlock->fib_FileName);
         if (p->NextRemember != NULL) strcat(Path,"/");
      }
}
