/*- - - - - - - - - - YAFR - Yet Another File Requester - - - - - - - - -*/
/*- - - - - - - - - - - - - - Version  1.10 - - - - - - - - - - - - - - -*/
/*YAFR V1.1 Copyright ©1989 by Dave  Schreiber.  All rights reserved.    */
/*YAFR may be freely distributed, but may not be sold.  Exceptions to    */
/*are reasonable copying, media, and shipping fees.  This copyright      */
/*message must be included (including when YAFR is used as a part of     */
/*another program).                                                      */

/*Compiled under Lattice C V5.02                                         */
/*Command line:  1> lc -cw -j30 yafr                                     */
/*Generates YAFR.o which is linked into the host program                 */
/*You must assign YAFR: to the directory where the YAFR source is stored */

/*If you have any comments, suggestions, etc. I can be reached at:       */
/*Dave Schreiber                                                         */
/*1234 Collins Lane                                                      */
/*San Jose, CA   95129-4208                                              */
/*Usenet:  davids@ucscb.ucsc.edu (during the school year)                */


#include <YAFR:yafrHead.h>
             /*^^^^system includes, structure definitions, etc.*/
#define CRNT header.current->fib

/*Parameters are:  fn-string for filename (33 characters)                */
/*dn-string for directory name (150 characters)                          */
/*en-string for filename extension (.c, .pic, etc. 18 characters)        */
/*cn-string for combined directory and filename (183 characters)         */
/*(NULL if you don't want the combined filename)                         */
/*X,Y-YAFR's window's X,Y location (relative to the screen               */
/*wn-text for YAFR's window's title bar                                  */
/*scr-Pointer to screen that window should appear on (NULL for           */
/*Workbench) filepen-Pen color that filenames should be displayed in     */
/*dirpen-Pen color that directory names should be displayed in           */
/*DisableInfo-Boolean; TRUE-files ending in .info aren't displayed       */
/*                     FALSE-.info files are displayed                   */

/*Version 1.1, completed October 30, 1989*/
/*Directory and filename string gadgets now auto-activate and appropriate*/
/*times.  A bug that caused an incorrect filename to be returned when the*/
/*user pressed CANCEL has been fixed                                     */

GetFilename(fn,dn,en,cn,X,Y,wn,scr,filepen,dirpen,DisableInfo)
char *fn,*dn,*en,*cn,*wn;
USHORT X,Y,filepen,dirpen;
BYTE DisableInfo;
struct Screen *scr;
{
   int status=GN_NEWDIR;
   struct FileLock *DirLock;

   if(DisableInfo)
      yf_Info.Flags|=SELECTED;
   else
      yf_Info.Flags=GADGHIMAGE|GADGIMAGE;

   yafr_e_FilenamePenColor = filepen;
   yafr_e_DirnamePenColor = dirpen;
   DirLock=(struct FileLock *)Lock(dn,ACCESS_READ);

   strcpy(yf_DirNameSIBuff,dn);
   strcpy(yf_ExtNameSIBuff,en);
   strcpy(yf_filenameSIBuff,fn);
   NewFNWindow.LeftEdge=X;
   NewFNWindow.TopEdge=Y;
   NewFNWindow.Title=(char *)wn;
   NewFNWindow.Screen=(struct Screen *) scr;
   NewFNWindow.Type= (scr) ? CUSTOMSCREEN : WBENCHSCREEN;

   if((FNWindow=(struct Window *)OpenWindow(&NewFNWindow))==NULL)
      {
      UnLock(DirLock);
      return(FALSE);
      }
   SetWindowTitles(FNWindow,-1,"YAFR V1.10 ©1989 by Dave Schreiber");
   SetAPen(FNWindow->RPort,1);
   Move(FNWindow->RPort,6,19);
   Text(FNWindow->RPort,"Directory",9);
   Move(FNWindow->RPort,6,154);
   Text(FNWindow->RPort,"Extension",9);
   Move(FNWindow->RPort,6,165);
   Text(FNWindow->RPort,"Filename",8);

   ActivateGadget(&yf_DirName,FNWindow,NULL);
   while((status = yf_GetName(DirLock)) == GN_NEWDIR)
      {
      UnLock(DirLock);
      DirLock=(struct FileLock *)Lock(yf_DirNameSIBuff,ACCESS_READ);
      ActivateGadget(&yf_filename,FNWindow,NULL);
      }

   UnLock(DirLock);
   if(status)
   {
      strcpy(fn,yf_filenameSIBuff);
      strcpy(dn,yf_DirNameSIBuff);
      strcpy(en,yf_ExtNameSIBuff);
      if(cn)
      {
         strcpy(cn,yf_DirNameSIBuff);
         if( (dn[strlen(dn)-1] != ':') && strlen(dn) )
            strcat(cn,"/");
         strcat(cn,yf_filenameSIBuff);
      }
   }

   CloseWindow(FNWindow);
   return(status);
}

yf_GetName(Lock)
struct FileLock *Lock;
{
   struct fibHeader header;
   int status3,status2,status;
   USHORT FNNumber=0;

   header.first=header.directory=NULL;
   if(yf_GetFib(&header)==FALSE)
      return(FALSE);
   yf_SliderSInfo.VertPot=0;
   yf_UpdateSlider(1,&yf_SliderSInfo,&yf_Slider);
   yf_ClearFileBox();
   if(!yf_ispipedevice(yf_DirNameSIBuff)) /*Check for pipe: device*/
      if(Lock!=NULL)
         {
         Examine(Lock,&(CRNT));
         if(yf_GetFib(&header)==FALSE)  /*Get next node*/
            return(NULL);
         while((status3=ExNext(Lock,&(CRNT))))
            {
            if((status2=((yf_CheckExt(CRNT.fib_FileName,yf_ExtNameSIBuff) ||
                  CRNT.fib_DirEntryType > 0) &&
                  yf_CheckInfo(CRNT.fib_FileName)) ))
               {
               if(FNNumber<10)
                  yf_PrintFileName(&(CRNT),Rp,XBorder,YBorder+(10*FNNumber++));
               else
                  yf_UpdateSlider(++FNNumber,&yf_SliderSInfo,&yf_Slider);
               }
            while((status=yf_CheckIntuiMessages(FNNumber,&header))!=GN_DONE)
               {
               if(status==GN_PARENT)
                  {
                  yf_Parentize(yf_DirNameSIBuff);
                  yf_RefreshGadget(&yf_DirName,FNWindow,NULL);
                  yf_FreeFuncMemory(header.directory);
                  return(GN_NEWDIR);
                  }
               if(status < GN_PARENT)
                  {
                  yf_FreeFuncMemory(header.directory);
                  return(status);   /*For OK,NEWDIR, & CANCEL*/
                  }
               }
            if(status2)
               if(yf_GetFib(&header)==FALSE)
                  return(NULL);
            }
            header.current->prev->next=NULL;
            if(header.directory->next == header.current) /*If no files*/
               header.directory->next=header.first=header.last=
                     header.top=NULL;     /*NULL certain pointers*/
            FreeMem(header.current,sizeof(struct fibNode));
         }
   for(;;)  /*FOREVER*/
      {
      Wait(1<<FNWindow->UserPort->mp_SigBit);
      while((status=yf_CheckIntuiMessages(FNNumber,&header))!=GN_DONE)
         {
         if(status==GN_PARENT)
            if(yf_Parentize(yf_DirNameSIBuff))
               {
               yf_RefreshGadget(&yf_DirName,FNWindow,NULL);
               yf_FreeFuncMemory(header.directory);
               return(GN_NEWDIR);
               }
         if(status < GN_PARENT)
            {
            yf_FreeFuncMemory(header.directory);
            return(status);   /*For OK,NEWDIR, & CANCEL*/
            }
         }
      }
}

yf_CheckInfo(name)  /*Check to see if .info's should be printed*/
char *name;
{
   if(!(yf_Info.Flags & SELECTED))
      return(TRUE);

   return(!(strcmp(&name[strlen(name)-5],".info")==0));
}

yf_ClearFileBox()
{
   SetAPen(Rp,0);
   RectFill(Rp,XBorder,YBorder-6,(25*8)+XBorder,YBorder+(100)-4);
   SetAPen(Rp,1);
}

yf_Parentize(str)
char *str;
{
   int c;

   if(str[strlen(str)-1]==':')
      return(FALSE);
   for(c=strlen(str)-1;c >= 0;c--)
      if(str[c]=='/')
         {
         str[c]=NULL;
         c=0;
         }
      else
         if(str[c]==':')
            {
            str[c+1]=NULL;
            c=0;
            }
   return(TRUE);
}

yf_UpdateSlider(Amt,Info,Gadgt)
USHORT Amt;
struct PropInfo *Info;
struct Gadget *Gadgt;
{
   Info->VertBody=((0xFFFF*10)/Amt);
   RefreshGadgets(Gadgt,FNWindow,NULL);
}

yf_CheckIntuiMessages(Max,header)
USHORT Max;
struct fibHeader *header;
{
   struct fibNode *cur;
   UBYTE c,line;
   struct IntuiMessage *mesg;
   struct Gadget *InUse;
   ULONG Class;
   USHORT Code;
   SHORT X,Y;

   while((mesg=(struct IntuiMessage *)GetMsg(FNWindow->UserPort))!=NULL)
      {
      InUse=(struct Gadget *)mesg->IAddress;
      X=mesg->MouseX;
      Y=mesg->MouseY;
      Class=mesg->Class;
      Code=mesg->Code;
      ReplyMsg(mesg);
      switch(Class)
         {
         case MOUSEMOVE:
            if(Max > 10)
               yf_UpdateList(yf_SliderSInfo.VertPot,Max,header);
            break;
         case GADGETUP:
            if(InUse->GadgetID <= 10)
               {
               strcpy(yf_DirNameSIBuff,InUse->GadgetText->IText);
               yf_RefreshGadget(&yf_DirName,FNWindow,NULL);
               return(GN_NEWDIR);
               }
            switch(InUse->GadgetID)
               {
               case 14:
                  return(GN_CANCEL);
               case 12:
               case 13:
                  return(GN_OK);
               case 15:
                  return(GN_PARENT);
               case 11:
               case 18:
                  return(GN_NEWDIR);
               }
            return(GN_RIEN);     /*Nothing important*/
            break;
         case GADGETDOWN:
         if(InUse->GadgetID == 18)
            return(GN_NEWDIR);

         if((strcmp(yf_DirNameSIBuff,"PIPE:")!=0) &&  /*Don't try & get files*/
          (strcmp(yf_DirNameSIBuff,"pipe:")!=0) && /*from PIPE: (most combos*/
          (strcmp(yf_DirNameSIBuff,"Pipe:") != 0)) /*of upper & lower case)*/
            {
            line=(Y-YBorder+7)/10;    /*Get line clicked on*/
            for(c=0,cur=(struct fibNode *)header->top;c!=line && cur!=NULL;c++)
               cur=(struct fibNode *)cur->next;
            if(cur != NULL)
               if(cur->fib.fib_DirEntryType > 0)
                  {
                  if(yf_DirNameSIBuff[strlen(yf_DirNameSIBuff)-1] != ':')
                     strcat(yf_DirNameSIBuff,"/");
                  strcat(yf_DirNameSIBuff,cur->fib.fib_FileName);
                  yf_RefreshGadget(&yf_DirName,FNWindow,NULL);
                  return(GN_NEWDIR);
                  }
               else   /*Filename clicked upon*/
                  {
                  strcpy(yf_filenameSIBuff,cur->fib.fib_FileName);
                  yf_RefreshGadget(&yf_filename,FNWindow,NULL);
                  }
            }
         }
      }
   return(GN_DONE);
}

yf_UpdateList(Pos,Num,header)
USHORT Pos;
USHORT Num;
struct fibHeader *header;
{
   static USHORT LastFirstItem=30000;
   ULONG FirstItem;
   FirstItem=((Pos)*(Num-10)) >> 16 ;

   if( FirstItem != LastFirstItem)
      yf_RewriteList(FirstItem,header);
   LastFirstItem=FirstItem;
}

yf_RewriteList(First,header)
USHORT First;
struct fibHeader *header;
{
   register struct fibNode *node;
   register USHORT c,Y;

   if(First)
      for(c=0,node=(struct fibNode *)header->first;c <= First;c++)
         node=(struct fibNode *)node->next;
   else
      node=(struct fibNode *)header->first;
   header->top=(struct fibNode *)node;
   for(c=0,Y=YBorder;(c < 10) && (node!=NULL);
         c++,Y+=10,node=(struct fibNode *)node->next)
      yf_PrintFileName(&(node->fib),Rp,XBorder,Y);
}

yf_CheckExt(name,ext)
char *name,*ext;
{
   if(strlen(name) >= strlen(ext))
      if(strcmp(&name[strlen(name)-strlen(ext)],ext)==0)
         return(TRUE);
   return(FALSE);
}

yf_GetFib(header)
struct fibHeader *header;
{
   header->last=(struct fibNode *)header->current;
   if((header->current=(struct fibNode *)
         AllocMem(sizeof(struct fibNode),MEMF_PUBLIC|MEMF_CLEAR))==NULL)
      {
      yf_FreeFuncMemory(header->current);
      return(FALSE);
      }
   if(header->directory==NULL)
      header->directory=(struct fibNode *)header->current;
   else
      {
      if(header->first==NULL)
         {
         header->directory->next=header->first=header->last=header->top=
               (struct fibNode *)header->current;
         yf_CopyFIB(&(header->directory->fib),&(header->current->fib));
         }
      else
         {
         yf_CopyFIB(&(header->last->fib),&(header->current->fib));
         header->last->next=(struct fibNode *)header->current;
         header->current->prev=(struct fibNode *)header->last;
         }
      }
   return(TRUE);
}

yf_CopyFIB(from,to)
struct FileInfoBlock *from,*to;
{
   to->fib_DiskKey=from->fib_DiskKey;
   to->fib_DirEntryType=from->fib_DirEntryType;
   to->fib_Protection=from->fib_Protection;
   to->fib_EntryType=from->fib_EntryType;
   to->fib_Size=from->fib_Size;
   to->fib_NumBlocks=from->fib_NumBlocks;
   strcpy(to->fib_FileName,from->fib_FileName);
   strcpy(to->fib_Comment,from->fib_Comment);
   to->fib_Date.ds_Days=from->fib_Date.ds_Days;
   to->fib_Date.ds_Minute=from->fib_Date.ds_Minute;
   to->fib_Date.ds_Tick=from->fib_Date.ds_Tick;

   return(TRUE);
}

yf_PrintFileName(fib,RPrt,X,Y)
struct FileInfoBlock *fib;
struct RPort *RPrt;
USHORT X,Y;
{
   UWORD len;
   if(fib->fib_DirEntryType > 0)
      SetAPen(RPrt,yafr_e_DirnamePenColor);
   else
      SetAPen(RPrt,yafr_e_FilenamePenColor);
   Move(RPrt,X,Y);
   Text(RPrt,"                         ",25);
   Move(RPrt,X,Y);
   len = (strlen(fib->fib_FileName)<=25) ? strlen(fib->fib_FileName) : 25;
   Text(RPrt,fib->fib_FileName,len);
   if(fib->fib_DirEntryType > 0)
      Text(RPrt,"  (dir)",7);
}

yf_RefreshGadget(Gadg,Wdw,Req)
struct Gadget *Gadg;
struct Window *Wdw;
struct Req *Req;
{
   struct Gadget *next;
   next=(struct Gadget *)Gadg->NextGadget;
   Gadg->NextGadget=NULL;
   RefreshGadgets(Gadg,Wdw,Req);
   Gadg->NextGadget=(struct Gadget *)next;
   return(TRUE);
}

yf_FreeFuncMemory(first)   /*Free a fib list*/
register struct fibNode *first;
{
   register struct fibNode *next,*current;
   next=(struct fibNode *)first->next;
   FreeMem(first,sizeof(struct fibNode));
   while((current=(struct fibNode *)next)!=NULL)
      {
      next=(struct fibNode *)current->next;
      FreeMem(current,sizeof(struct fibNode));
      }
}

yf_ispipedevice(device) /*Checks to see if the device is the PIPE:*/
char *device;
{
   char temp[6];
   int c;
   for(c=0;c<5;c++) /*Convert weird capitalization (pIPe:) to pipe:*/
      temp[c]=tolower(device[c]); /*So as to make it easy to check*/
   temp[5]=NULL;
   if(strcmp(device,"pipe:")==0)
      return(TRUE);
   else
      return(FALSE);  
}
