===========================================================================
=                                                                         =
=                 ARP FileRequester a More Detailed Look                  =
=                                                                         =
=                              By S Marshall                              =
=                                                                         =
===========================================================================

    Mark asked for a more detailed description  of the ARP FileRequester as
he couldn't seem to follow the source code  that appeared on Disk 4. This I
think shows how difficult it can be  for  other people to follow your code.
For this reason, and because Mark says  the disk is to be released into the
Public Domain, I think that  it  is  important  that  source  code sent for
inclusion on the disk should be well commented  and have a separate article
which describes the program what it is  trying to achieve and how. This way
we can all make more use of the  source  included  on the disk. It may seem
quite simple and obvious to you, but  it  can be very confusing for someone
else. Even if he/she is a  competent  programmer.  Just  try to read an old
file of your own, pick one about six months  or so old with no comments and
see how long it takes you to fully understand the code. Failing that take a
look at someone else's code, I think you'll see what I mean.

    O.K. ( gets of soap box ) back to the FileRequester. 

 retstr = FileRequest( filereqstruct )
   D0                       A0
       
    Where  filereqstruct  is  a  pointer   to  an  initialized  FileRequest
structure. On return D0 will be zero if the user cancelled the requester or 
a pointer to the File Buffer (  the  value  held  in fr_File ). This buffer
contains the the name ( and only the  name,  not the full pathname ) of the
file selected. The FileRequest structure is as follows :

 fr_Hail           LONG               
 fr_File           LONG
 fr_Dir            LONG
 fr_Window         LONG         
 fr_FuncFlags      BYTE
 fr_reserved1      BYTE
 fr_Function       LONG
 fr_reserved2      LONG 

    
 fr_Hail
~~~~~~~~
    This is simply a pointer to a  null  terminated  string  which  will be
displayed in the requesters window title/drag bar.
                
 fr_File  
~~~~~~~~
    This is a pointer to a buffer which will be used to store the filename. 
The buffer must be at least  FCHARS+1 ( 32+1 = 33 ) in size.

 fr_Dir
~~~~~~~
    This is a pointer  to  the  buffer  which  will  be  used  to store the
pathname of the file. The buffer must be  at least DSIZE+1 ( 33+1 = 34 ) in
size.
    
 fr_Window
~~~~~~~~~~
    This is a pointer to  the  calling  window.  If  your  window is on the
workbench then you may set this  to  NULL.  If  your  window is on a custom
screen then you should point  this  to  the  windows Window structure. This
will allow the requester to open on the custom screen.
         
 fr_FuncFlags
~~~~~~~~~~~~~
    This variable allows us to customize  the  requester  to our own needs.
The flags are :

 FRB_DoWildFunc (Bit 7)
    This flag is used for wildcards etc.For  each file in the directory the
function pointed to by fr_Function  will  be  called.You get a pointer to a
FileInfoBlock or are  supposed  to,  I  find  that  the pointer is 20 bytes
short, so you will have to add 20 to this  pointer - dunno why. If you want
this file to be added to the file requester  display, return ZERO. Non zero
returns will prevent  this  name  from  being  displayed.  Devpac uses this
option to stop icons or '.info files' from being displayed. I will show how
to do this in the demo code. I will  add  a  complete wildcarding system to
the requester using gadgets.

 FRB_DoMsgFunc  (Bit 6)
    Ordinarily if  FileRequest()  receives  an  IntuiMessage  that does not
apply to the FileRequest() gadgets  and  windows,  it will send the message
back to Intuition without  doing  anything  else  to  it. This can occur if
FileRequest was passed a fr_Window  pointer  and  created a shared IDCMP on
that windows ports  (see  FDB_NewIDCMP).  If  you want to get your hands on
these messages, set this bit  in  fr_FuncFlags,  and  you  will be passed a
pointer to the IntuiMessage that FileRequest()  didn't recognize. Note that
it now becomes your responsibility to return  it to Intuition. Returns from
this function are ignored.
 
 FRB_DoColor   (Bit 5)
    This controls the background color, you get one of two choices, with or
without the DoColor bit set.   This  is  useful  to emphasize two different
uses of the FileRequester in  the  same  program,  for example, Loading and
saving files might use  different  colored  file  requester  backgrounds to
emphasize the difference. By convention  this flag will be clear for a Load
requester and set for  a  Save  requester.  Note  this  flag DOES NOT cause
fr_Function to be called. 

 FRB_NewIDCMP  (Bit 4) 
    This is used  only  if  you  have  specified  a  value  for  fr_Window.
Ordinarily, FileRequest()  will  create  a  shared  IDCMP using the already
opened  IDCMP  ports  of  your  window,   since  this  requires  much  less
overhead.  If you do not wish this  to  occur,  you may set this bit, which
will cause the FileRequest()  function  to create its own IDCMP ports. Note
this flag (along with FRB_DoColor) does not cause fr_Function to be called.

 FRB_NewWindFunc (Bit 3)
    You get a pointer to the  NewWindow  structure  that  FileRequest()  is
about to open for the file requester. You  may modify it as you require. It
is intended for  adjusting the window position  of the filerequester and/or
it's size which  must be  legal  for  the  requested  screen. Note that you
must use this function if you wish to open the requester on a lo-res screen
Why ? - well the default for nw_LeftEdge is 25 and the windows width is set
to 300. Simple maths  will tell  you that this  window will  not open  on a
lo-res screen with a width of 320. When FileRequest() tries to open the
window OpenWindow() will fail and FileRequest() will abort. If you set the
nw_LeftEdge to 10 the requester will be nicely centred on the screen as in
the demo. FileRequest ignores any return value from this function.

 FRB_AddGadFunc (Bit 2)
    You get a pointer to the file requester  window after FileRequest() has
added all of it's standard gadgets, but before they are actually drawn. You
may add/remove your own custom gadgets at this point. Note that your gadget
ID's must be less than FR_FIRST_GADGET ($7680). FileRequest()   ignores any
return value  from  this  function.  When  you  add  a  gadget  list to the
requester with AddGList() be  aware  that  the  gg_NextGadget field of your
last gadget will be altered if you add the gadgets to the top of the gadget 
list (Position = 0). This will cause  a  guru  or make the system hang when
you call the  requester  a  secondtime  unless  you  clear  this field. The
easiest way is to add your gadgets to the end of the list (Position = -1).

 FRB_GEventFunc (Bit 1)
     User  is  doing  something   with   a   gadget  which  is  unknown  to
FileRequest(). You are passed the  gadgetID  of the gadget which caused the
event.  FileRequest() reserves all gadget ID's greater than FR_FIRST_GADGET
for it's own use.  (This has been  made  sufficientlylarge  so that it will
not cause problems in practice.) If you return ZERO, the FileRequest() will
continue, otherwise, it will  exit.  The  exit  status from FileRequest( is
undefined if this occurs.

 FRB_ListFunc   (Bit 0)
    Not yet implemented


 fr_reserved1
~~~~~~~~~~~~~
    Reserved, set to NULL.

 fr_Function
~~~~~~~~~~~~
    This should point to your  function  to  deal  with fr_Flags. When this
function is called D0 will contain  the  Mask, that is a long word with the
Flag of the calling function set. If  you  have  set multiple flags you can
test this to find out which Flag caused this function to be called.
 
fr_reserved2
~~~~~~~~~~~~~~
    Reserved, set to NULL.

    
    Well that's the filerequest  structure,  now  what happens when we call
FileRequest(). Well control of your program will be temporarilybe passed to                
the FileRequest function. On return D0 will contain information on what the
user did with the requester.  If  D0  =  ZERO  then  the user cancelled the
requester. Note even though the user  cancelled  the requester the filename
and/or the directory name may have been altered, be aware of this. If D0 is
NONZERO then the user  either  clicked  on  the OK gadget or pressed return
after editing the FileName string  gadget,  the effect is the same. D0 will
now point to the FileName  buffer,  which  is  useful but we should already
know where it is situated. Note also  that  even  though we have a posative
return we may have a NULL string ie the  user pressed OK without entering a
filename. We can test for this by doing something like :

    move.l       d0,a0
    tst.b        (a0)
    beq          NullString

    OK so now we have the  file  path  and  the  file  name in two separate
buffers, we will most probably  want  the  whole  pathname. We can't simply
copy the two buffers into  one  single  buffer  adding the strings together
because we may need to add a '/'  or  a  ':'  to  the end of the file path.
Luckily for us the developers of ARP  thought  of this and added a function
to do this for us, this function being TackOn(). TackOn() is called thus :

     TackOn("PathName", "FileName")
                A0          A1
                                         
    Most programs that use the  ARP  Filerequester  seem  to  mess up here.
Programs like DME (an editor) by Matt Dillon  and even Devpac have problems
with this. Early versions of DME  really  messed up but later versions were
better (but not perfect). Devpac's  bug  is  only minor, if you load a file
then go back to load another you will find that it is necessary to click on
the Parent gadget twice if you wish to  go to the parent directory. This is
because Devpac leaves an extra '/' on the end of the file path. This causes
no other problems but I do consider  it  a  bug (picky sod). I usually copy
the file path into a separate buffer which is large enough to hold the full
Pathname (about 68 bytes using the  requester).  It is then simply a matter
of passing the address of this buffer in A0 and the address of the filename
in A1, then calling TackOn(). We now  have  a  copy of the full pathname in
our buffer and better still this copy won't  be messed up by the user if he
uses the requester changes  directories  and/or filename then cancels. This
method means that we will  need  about  34  bytes more memory than we would
need if we used TackOn() using the  existing  buffers pointed to by fr_File
and fr_Dir. I think this is a small price  to pay for a FileRequester which
works properly and have a separate 'safe' copy of the pathname.

    The routines used for wildcards are from the ARP library and are :

PreParse  (Source,Destination)
             a0       a1

    Which prepares the string for the next funtion :

PatternMatch  (Pattern,String)
Result = d0      a0      a1
   
    A return of 0 signifies no match while -1 equals a match (Bool true and
false). The pattern  should  be  a  pointer  to  the  destination  used  in
PreParse. 
 
   Along with this explanation I  am  including  two  separate  FileRequest
source files. The first is a simple bare essential program and the second a
more sophisticated example showing  how  to  open the requester on a custom
screen, resize and move  the  requester  window,  add  your own gadgets and
filter out unwanted  files  like  icons  ending  in  in  '.info' or to only
display files ending in '.s'.

  Hope this file and the associated source files prove to be of some use 

                           Thanks Steve Marshall
