/*
***************************************************************************
*
* Datei:
*    RSysFormatFind.c
*
* Inhalt:
*    int OpenFindFileWindow(void);
*    void FindFile(void);
*    int OpenFormatDiskWindow(void);
*    void FormatDisk(void);
*
* Bemerkungen:
*    Disk-Format-Untersützung und Dateisuchroutinen.
*
* Erstellungsdatum:
*    07-Jul-93    Rolf Böhme
*
* Änderungen:
*    07-Jul-93    Rolf Böhme    Erstellung
*
***************************************************************************
*/

#include "RSysFunc.h"
#include "RSysDebug.h"

static enum gadid
{
   GD_DeviceLV,
   GD_SelDevLV,
   GD_PatternGad,
   GD_StartStopGad,
   GD_FoundLV,
   GD_SaveFoundListGad,
   GD_AllGad,
   GD_NoneGad,
   GD_CaseCYGad,
   GD_DirFileCYGad
};

static struct Window *FindFileWnd = NULL;
static struct Gadget *FindFileGList = NULL;
static UWORD FindFileZoom[4];
static struct Gadget *FindFileGadgets[10];
static UWORD FindFileLeft = 153;
static UWORD FindFileTop = 27;
static UWORD FindFileWidth = 330;
static UWORD FindFileHeight = 200;
static UBYTE *FindFileWdt = (UBYTE *) NAME " " VERSION " - Find File";
static UBYTE *CaseCYGad0Labels[]=
{
   (UBYTE *) "No case sense",
   (UBYTE *) "Case sense",
   NULL
};
static UBYTE *DirFileCYGad0Labels[] = {
	(UBYTE *)"Dirs + Files",
	(UBYTE *)"Files",
	(UBYTE *)"Directories",
	NULL };

#define DF 0
#define FI 1
#define DI 2

static struct List DevList;
static struct List SelDevList,
      FoundList;

struct Remember *DevKey = NULL;
static struct Remember *FileKey = NULL;

static char pat[PATTERNLEN],
      parsepat[PARSEPATLEN];
static int  match_case = NO_CASE,
      match_type = DF;

#define DEVKEY    ((struct Remember **)&DevKey)
#define FILEKEY   ((struct Remember **)&FileKey)

#define FindFile_CNT 10

static UWORD FindFileGTypes[] = {
	LISTVIEW_KIND,
	LISTVIEW_KIND,
	STRING_KIND,
	BUTTON_KIND,
	LISTVIEW_KIND,
	BUTTON_KIND,
	BUTTON_KIND,
	BUTTON_KIND,
	CYCLE_KIND,
	CYCLE_KIND
};

int gl[] = {GD_DeviceLV,GD_SelDevLV,GD_PatternGad,GD_FoundLV};

static struct NewGadget FindFileNGad[] = {
	4, 17, 157, 60, (UBYTE *)"Devices", NULL, GD_DeviceLV, PLACETEXT_ABOVE, NULL, NULL,
	168, 17, 157, 60, (UBYTE *)"Selected Devices", NULL, GD_SelDevLV, PLACETEXT_ABOVE|NG_HIGHLABEL, NULL, NULL,
	74, 113, 87, 13, (UBYTE *)"Pattern", NULL, GD_PatternGad, PLACETEXT_LEFT, NULL, NULL,
	4, 97, 157, 13, (UBYTE *)"Start/Stop Search", NULL, GD_StartStopGad, PLACETEXT_IN, NULL, NULL,
	4, 144, 321, 52, (UBYTE *)"Found files/dirs", NULL, GD_FoundLV, PLACETEXT_ABOVE|NG_HIGHLABEL, NULL, NULL,
	168, 97, 157, 13, (UBYTE *)"Save found list", NULL, GD_SaveFoundListGad, PLACETEXT_IN, NULL, NULL,
	168, 81, 77, 13, (UBYTE *)"Sel all", NULL, GD_AllGad, PLACETEXT_IN, NULL, NULL,
	248, 81, 77, 13, (UBYTE *)"Sel none", NULL, GD_NoneGad, PLACETEXT_IN, NULL, NULL,
	4, 81, 157, 13, NULL, NULL, GD_CaseCYGad, 0, NULL, NULL,
	168, 113, 157, 13, NULL, NULL, GD_DirFileCYGad, 0, NULL, NULL
};

static ULONG *FindFileGTags[] = {
	(ULONG *)(GTLV_Labels), (ULONG *)&DevList, (ULONG *)(TAG_DONE),
	(ULONG *)(GTLV_Labels), (ULONG *)&SelDevList, (ULONG *)(TAG_DONE),
	(ULONG *)(GTST_MaxChars), (ULONG *)256, (ULONG *)(TAG_DONE),
	(ULONG *)(GA_Disabled), (ULONG *)TRUE, (ULONG *)(TAG_DONE),
	(ULONG *)(GTLV_Labels), (ULONG *)&FoundList, (ULONG *)(GTLV_ReadOnly), (ULONG *)TRUE, (ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE),
	(ULONG * )(GTCY_Labels), (ULONG *)&CaseCYGad0Labels[ 0 ], (ULONG *)(TAG_DONE),
	(ULONG * )(GTCY_Labels), (ULONG *)&DirFileCYGad0Labels[ 0 ], (ULONG *)(TAG_DONE)
};

   /*
    * OpenFindFileWindow() öffnet ein Window mit Gadgets, mit
    * denen die Auswahl- und Suchkriterien eingegeben werden
    * können
    */
int
OpenFindFileWindow( void )
{
	struct NewGadget	ng;
	struct Gadget	*g;
	UWORD		lc, tc;
	UWORD		wleft = FindFileLeft, wtop = FindFileTop, ww, wh;
   int gl[] = {GD_DeviceLV,GD_SelDevLV,GD_PatternGad,GD_FoundLV};

   DPOS;

	ComputeFont( Scr,FindFileWidth, FindFileHeight );

	ww = ComputeX( FindFileWidth );
	wh = ComputeY( FindFileHeight );

	if (( wleft + ww + OffX + Scr->WBorRight ) > Scr->Width ) wleft = Scr->Width - ww;
	if (( wtop + wh + OffY + Scr->WBorBottom ) > Scr->Height ) wtop = Scr->Height - wh;

   ww = compute((UWORD) (OffX + Scr->WBorRight), FontX, (int)FindFileWidth);
   wh = compute((UWORD) (OffY + Scr->WBorBottom), FontY, (int)FindFileHeight);

   CenterWindow(Scr, &wtop, &wleft, ww, wh);

	if ( ! ( g = CreateContext( &FindFileGList )))
		return( 1L );

	for( lc = 0, tc = 0; lc < FindFile_CNT; lc++ ) {

		CopyMem((char * )&FindFileNGad[ lc ], (char * )&ng, (long)sizeof( struct NewGadget ));

		ng.ng_VisualInfo = VisualInfo;
		ng.ng_TextAttr   = Font;
		ng.ng_LeftEdge   = OffX + ComputeX( ng.ng_LeftEdge );
		ng.ng_TopEdge    = OffY + ComputeY( ng.ng_TopEdge );
		ng.ng_Width      = ComputeX( ng.ng_Width );
		ng.ng_Height     = ComputeY( ng.ng_Height);

		FindFileGadgets[ lc ] = g = CreateGadgetA((ULONG)FindFileGTypes[ lc ], g, &ng, ( struct TagItem * )&FindFileGTags[ tc ] );

      makelabelvisible(FindFileGadgets[lc]);

		while( FindFileGTags[ tc ] ) tc += 2;
		tc++;

		if ( NOT g )
			return( 2L );
	}

	FindFileZoom[2] = TextLength( &Scr->RastPort, (UBYTE *)FindFileWdt, strlen((char *)FindFileWdt )) + 80;
	FindFileZoom[0] = FindFileZoom[1] = 0;
	FindFileZoom[3] = Scr->WBorTop + Scr->RastPort.TxHeight + 1;

	if ( ! ( FindFileWnd = OpenWindowTags( NULL,
				WA_Left,	wleft,
				WA_Top,		wtop,
				WA_Width,	ww, /* + OffX + Scr->WBorRight,*/
				WA_Height,	wh, /* + OffY + Scr->WBorBottom,*/
				WA_IDCMP,	IDCMP_VANILLAKEY|
                        LISTVIEWIDCMP|
                        STRINGIDCMP|
                        BUTTONIDCMP|
                        CYCLEIDCMP|
                        IDCMP_CLOSEWINDOW|
                        IDCMP_CHANGEWINDOW|
                        IDCMP_REFRESHWINDOW,
				WA_Flags,	WFLG_DRAGBAR|
                        WFLG_DEPTHGADGET|
                        WFLG_CLOSEGADGET|
                        WFLG_RMBTRAP|
                        WFLG_ACTIVATE |
                        WFLG_SMART_REFRESH,
            WA_Gadgets,	FindFileGList,
            WA_Title,	FindFileWdt,
            WA_Zoom,	FindFileZoom,
            WA_PubScreenFallBack,TRUE,
            WA_PubScreen, Scr,
            TAG_DONE )))
   	return( 4L );

	FindFileZoom[0] = FindFileWnd->LeftEdge;
	FindFileZoom[1] = FindFileWnd->TopEdge;
	FindFileZoom[2] = FindFileWnd->Width;
	FindFileZoom[3] = FindFileWnd->Height;

   RefreshRastPort(FindFileWnd,FindFileGadgets,gl, 4);

	return( 0L );
}

   /*
    * MyDevAllocRem() reserviert Speicher aus einer Remember-Liste
    * für die Verzeichnis-Einträge
    */
static void *
MyDevAllocRem(long size)
{
   void *ptr = (void *)AllocRemember(DEVKEY, size, MEMF_CLEAR | MEMF_ANY);

   if (NOT(ptr))
   {
      ErrorHandle(MEMORY_ERR, ALLOC_FAIL, NO_KILL);
      Flags.quit_ff = 1;
   }

   return (ptr);
}

   /*
    * MyFileAllocRem() reserviert Speicher aus einer Remember-Liste
    * für die Datei-Einträge
    */
static void *
MyFileAllocRem(long size)
{
   void *ptr = (void *)AllocRemember(FILEKEY, size, MEMF_CLEAR | MEMF_ANY);

   if (NOT(ptr))
   {
      ErrorHandle(MEMORY_ERR, ALLOC_FAIL, NO_KILL);
      Flags.quit_ff = 1;
   }

   return (ptr);
}

   /*
    * refreshdevlists() erneuert die Anzeige der ListViews mit den
    * Inhalten der Listen der selektierten und der nicht selektierten
    * Devices
    */
static void
refreshdevlists(void)
{
   InitListView(FindFileWnd,FindFileGadgets[GD_DeviceLV],
                &DevList,UNSETLVPOS);
   InitListView(FindFileWnd,FindFileGadgets[GD_SelDevLV],
                &SelDevList,UNSETLVPOS);
   return;
}

   /*
    * MakeDevEntry() erzeugt einen neuen Listeneintrag in die
    * Liste der Devices
    */
static void
MakeDevEntry(struct List *list, char *str)
{
   struct Node *node = MyDevAllocRem(sizeof(struct Node));

   if (NOT(node))
      return;

   node->ln_Pri = 0;
   node->ln_Type = NT_USER;
   node->ln_Name = MyDevAllocRem(strlen(str) + 1);

   if (NOT(node->ln_Name))
      return;

   strcpy(node->ln_Name, str);

   AddNodeSorted(list, node);

   return;
}

   /*
    * MakeFileEntry() erzeugt einen Listeneintrag in die Liste der
    * gefundenen Dateien. Der Eintrag wird dann in die bestehende
    * Liste alphabetisch einsortiert
    */
static void
MakeFileEntry(char *str)
{
   struct Node *node = MyFileAllocRem(sizeof(struct Node));

   if (NOT(node))
      return;

   node->ln_Pri = 0;
   node->ln_Type = NT_USER;
   node->ln_Name = MyDevAllocRem(strlen(str) + 1);

   if (NOT(node->ln_Name))
      return;

   strcpy(node->ln_Name, str);

   AddNodeSorted(&FoundList, node);
   InitListView(FindFileWnd,FindFileGadgets[GD_FoundLV],
                &FoundList,UNSETLVPOS);

   return;
}


   /*
    * MakeDevList() erzeugt eine Liste aus angemeldeten Devices
    * (Volumes) und Assigns. Die Devices werden der Reihe nach
    * ausgelesen und in die Liste einsortiert. Assigns werden mit
    * einem führenden "-" versehen, damit sie in der Liste
    * unterschieden werden können
    */
static void
MakeDevList(void)
{
   char  dev[80],
         str[100];
   struct DosList *dl;

   dl = LockDosList(LDF_VOLUMES | LDF_READ);

   while (dl = NextDosEntry(dl, LDF_VOLUMES | LDF_READ))
   {
      sprintf(str, " %s:", B2CStr(dev, dl->dol_Name));
      MakeDevEntry(&DevList, str);
   }

   UnLockDosList(LDF_VOLUMES | LDF_READ);

   dl = LockDosList(LDF_ASSIGNS | LDF_READ);

   while (dl = NextDosEntry(dl, LDF_ASSIGNS | LDF_READ))
   {
      sprintf(str, "\-%s:", B2CStr(dev, dl->dol_Name));
      MakeDevEntry(&DevList, str);
   }

   UnLockDosList(LDF_ASSIGNS | LDF_READ);

   return;
}

static int   breakit = FALSE;

   /*
    * ClickedGadget() prüft, ob das Start/Stop-Gadget betätigt
    * wurde. Mit einem AutoRequester wird nachgefragt, ob die
    * Suche nach Dateien eingestellt werden soll
    */
static BOOL
ClickedGadget(void)
{
   register struct IntuiMessage *mess;
   ULONG class;
   APTR  adr;
   BOOL  ret = FALSE;

   while ((mess = (struct IntuiMessage *)
           GT_GetIMsg(FindFileWnd->UserPort)) != NULL)
   {
      class = mess->Class;
      adr = mess->IAddress;

      GT_ReplyIMsg(mess);

      switch (class)
      {
         case IDCMP_CHANGEWINDOW:
         case IDCMP_REFRESHWINDOW:
            RefreshRastPort(FindFileWnd,FindFileGadgets,gl, 4);
            MakeWindowRefresh(FindFileWnd);
            break;

         case IDCMP_GADGETUP:
            if ((adr == (APTR) FindFileGadgets[GD_StartStopGad]) &&
                Question(FindFileWnd, "Do you want to cancel searching?", YES))
            {
               ret = TRUE;
               breakit = TRUE;
            }
            break;
      }
   }

   return (ret);
}

   /*
    * SearchFile() wird rekursiv mit dem dem Namen eines
    * Verzeichnisses oder Devices aufgerufen. Es durchsucht dann
    * alle Verzeichnisse nach vorgegebenem Suchmuster. Die
    * gefundenen Einträge werden in die entsprechenden Listen
    * eingetragen
    */
static void
SearchFile(char *name)
{
   struct ExAllControl *eac;
   struct ExAllData *EAData,
        *ead,
        *eadtmp;
   int   more;
   BPTR  lock;
   UBYTE newdir[MAXFULLNAME],
         foundname[MAXFULLNAME];
   BOOL(*matchfunc[2]) (UBYTE *, UBYTE *) =
   {
      MatchPatternNoCase, MatchPattern
   };

   if (ClickedGadget()|| breakit || Flags.quit_ff)
      return;

   if (NOT(lock = Lock((UBYTE *) name, ACCESS_READ)))
      return;

   if (eac = AllocDosObject(DOS_EXALLCONTROL, NULL))
   {
      eac->eac_LastKey = 0;

      EAData = MyAllocVec((MAXLARGEMEM+1) * sizeof(struct ExAllData),
                          MEMF_ANY | MEMF_CLEAR, NO_KILL);

      if (EAData)
      {
         do
         {
            more = ExAll(lock, EAData, MAXLARGEMEM * sizeof(struct ExAllData),
                         ED_SIZE, eac);

            if ((!more) && (IoErr()!= ERROR_NO_MORE_ENTRIES))
            {
               ErrorHandle(DOS_EXALL_ERR, EXALL_FAIL, NO_KILL);
               break;
            }

            if (eac->eac_Entries == 0)
               continue;

            ead = EAData;

            do
            {
               if ((*matchfunc[match_case]) ((UBYTE *) parsepat,
                                             FilePart((UBYTE *) ead->ed_Name)))
               {
                  strncpy((char *)foundname, name, MAXFULLNAME);
                  if (AddPart(foundname, ead->ed_Name, MAXFULLNAME))
                  {
                     if (ead->ed_Type > 0)
                        strcat((char *)foundname, " (dir)");

                     if((match_type == DF) ||
                        ((match_type == FI) && (ead->ed_Type <= 0)) ||
                        ((match_type == DI) && (ead->ed_Type >  0)))
                     MakeFileEntry((char *)foundname);
                  }
               }

               if (ead->ed_Type > 0)
               {
                  strncpy((char *)newdir, name, MAXFULLNAME);

                  if (AddPart(newdir, ead->ed_Name, MAXFULLNAME))
                     SearchFile((char *)newdir);
               }

               ead = ead->ed_Next;
            }
            while (ead && NOT(ClickedGadget())&& NOT(breakit) && NOT(Flags.quit_ff));

         }
         while (more);

         MyFreeVec(EAData);
      }

      FreeDosObject(DOS_EXALLCONTROL, eac);
   }
   else
      ErrorHandle(MEMORY_ERR, ALLOC_FAIL, NO_KILL);

   UnLock(lock);

   return;
}

   /*
    * SaveFoundFiles() speichert die Liste mit den gefunden
    * Dateien und Verzeichnissen in einer Datei ab
    */
static void
SaveFoundFiles(void)
{
   char  head[PARSEPATLEN];

   if (GetFile(FindFileWnd,"RAM:","RSys-FoundFiles.DAT","#?.DAT",
               "Select File for saving list","Save"))
   {
      sprintf(head, "Found files (Pattern: %s)", pat);
      SaveList(FindFileWnd, (char *)_fullpath, head, &FoundList, FALSE);
   }

   return;
}

   /*
    * FindFile() präsentiert eine Benutzeroberfläche, mit der die
    * Suchkriterien eingestellt und das Handling gemanagt wird
    */
void
FindFile(void)
{
   register struct IntuiMessage *message;
   struct Node *clicknode,
        *node,
        *remnode;
   ULONG class,
         code;
   APTR  object;
   APTR  req = NULL;
   register enum gadid i;
   LONG (*parse_func[2]) (UBYTE *, UBYTE *, long)=
   {
      ParsePatternNoCase, ParsePattern
   };

   DPOS;

   NewList(&DevList);
   NewList(&SelDevList);
   NewList(&FoundList);
   Flags.quit_ff = 0;

   if (OpenASysWindow(OpenFindFileWindow,NO_KILL))
   {
      if (SysWnd)
         req = LockWindow(SysWnd);

      MakeDevList();
      InitListView(FindFileWnd,FindFileGadgets[GD_DeviceLV],
                   &DevList,UNSETLVPOS);

      do
      {
         Wait(1L << FindFileWnd->UserPort->mp_SigBit);

         while ((message = (struct IntuiMessage *)
                 GT_GetIMsg(FindFileWnd->UserPort)) != NULL)
         {
            object = message->IAddress;
            class = message->Class;
            code = message->Code;

            GT_ReplyIMsg(message);

            switch (class)
            {
               case IDCMP_GADGETUP:
                  switch (((struct Gadget *) object)->GadgetID)
                  {
                     case GD_DeviceLV:
                        clicknode = GetNode(&DevList, code);
                        Remove(clicknode);
                        AddTail(&SelDevList, clicknode);
                        refreshdevlists();

                        if (strlen(pat))
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], TRUE);
                        break;

                     case GD_SelDevLV:
                        clicknode = GetNode(&SelDevList, code);
                        Remove(clicknode);
                        AddNodeSorted(&DevList, clicknode);
                        refreshdevlists();

                        if (IsListEmpty(&SelDevList))
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], FALSE);
                        break;

                     case GD_PatternGad:
                        strncpy(pat, gadgetbuff(FindFileGadgets[GD_PatternGad]),
                               PATTERNLEN);

                        if (strlen(pat) == 0)
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], FALSE);
                        else if ((*parse_func[match_case]) ((UBYTE *) pat,
                                                            (UBYTE *) parsepat, 162) < 0)
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], FALSE);
                        else if (NOT(IsListEmpty(&SelDevList)))
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], TRUE);

                        break;

                     case GD_StartStopGad:
                        if (NOT(IsListEmpty(&SelDevList)))
                        {
                           if (NOT(IsListEmpty(&FoundList)) &&
                               Question(FindFileWnd, "File list not empty!\n"
                                        "Do you want to save it?", NO))
                              SaveFoundFiles();

                           InitListView(FindFileWnd,FindFileGadgets[GD_FoundLV],
                                        NULL,0);

                           FreeRemember(FILEKEY, TRUE);
                           NewList(&FoundList);

                           InitListView(FindFileWnd,FindFileGadgets[GD_FoundLV],
                                        &FoundList,UNSETLVPOS);

                           for (i = GD_DeviceLV; i <= GD_DirFileCYGad; i++)
                              if ((i != GD_StartStopGad) && (i != GD_FoundLV))
                                 EnableGadget(FindFileWnd,FindFileGadgets[i], FALSE);

                           breakit = FALSE;

                           for (node = SelDevList.lh_Head; node->ln_Succ; node = node->ln_Succ)
                              SearchFile(&(node->ln_Name)[1]);

                           for (i = GD_DeviceLV; i <= GD_DirFileCYGad; i++)
                              if ((i != GD_StartStopGad) && (i != GD_FoundLV))
                                 EnableGadget(FindFileWnd,FindFileGadgets[i], TRUE);
                        }
                        break;

                     case GD_SaveFoundListGad:
                        if (NOT(IsListEmpty(&FoundList)))
                           SaveFoundFiles();
                        break;

                     case GD_AllGad:
                        if (IsListEmpty(&DevList))
                           break;

                        node = DevList.lh_Head;
                        while (node->ln_Succ)
                        {
                           remnode = node->ln_Succ;
                           Remove(node);
                           AddTail(&SelDevList, node);
                           node = remnode;
                        }

                        InitListView(FindFileWnd,FindFileGadgets[GD_DeviceLV],
                                     NULL,0);
                        NewList(&DevList);

                        refreshdevlists();
                        if (strlen(pat))
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], TRUE);
                        break;

                     case GD_NoneGad:
                        if (IsListEmpty(&SelDevList))
                           break;

                        node = SelDevList.lh_Head;
                        while (node->ln_Succ)
                        {
                           remnode = node->ln_Succ;
                           Remove(node);
                           AddNodeSorted(&DevList, node);
                           node = remnode;
                        }

                        InitListView(FindFileWnd,FindFileGadgets[GD_SelDevLV],
                                     NULL,0);
                        NewList(&SelDevList);

                        refreshdevlists();
                        EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], FALSE);
                        break;

                     case GD_CaseCYGad:
                        match_case = ((match_case == CASE) ? NO_CASE : CASE);
                        if (strlen(pat) == 0)
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], FALSE);
                        else if ((*parse_func[match_case]) ((UBYTE *) pat,
                                                            (UBYTE *) parsepat, 162) < 0)
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], FALSE);
                        else
                           EnableGadget(FindFileWnd,FindFileGadgets[GD_StartStopGad], TRUE);
                        break;

                     case GD_DirFileCYGad:
                        match_type = code;
                        break;
                  }
                  break;

               case IDCMP_VANILLAKEY:
                  if (code == ESC)
                  {
                     if (NOT(IsListEmpty(&FoundList)) &&
                         Question(FindFileWnd, "File list not empty!\n"
                                  "Do you want to save it?", NO))
                        SaveFoundFiles();

                     Flags.quit_ff = 1;
                  }
                  break;

               case IDCMP_CHANGEWINDOW:
               case IDCMP_REFRESHWINDOW:
                  if (NOT(FindFileWnd->Flags & WFLG_ZOOMED))
                     RefreshRastPort(FindFileWnd,FindFileGadgets,gl, 4);

                  MakeWindowRefresh(FindFileWnd);
                  break;

               case IDCMP_CLOSEWINDOW:
                  if (NOT(IsListEmpty(&FoundList)) &&
                      Question(FindFileWnd, "File list not empty!\n"
                               "Do you want to save it?", NO))
                     SaveFoundFiles();

                  Flags.quit_ff = 1;
                  break;
            }
         }
      }
      while (NOT(Flags.quit_ff));

      FreeRemember(FILEKEY, TRUE);
      FreeRemember(DEVKEY, TRUE);

      CloseASysWindow(&FindFileWnd, &FindFileGList, NULL);

      if (req)
      {
         UnlockWindow(req);
         RefreshMainWindowPattern();
         RefreshList(LastID);
      }
   }

   return;
}

#define CMDFMT "%s DRIVE %s NAME \"%s\" %s %s %s %s"

static UBYTE fmtcmd[MAXWRITESIZE],
      parts[7][MAXSTRLEN] =
{
   "SYS:System/Format", "DF0:", "Empty", "OFS", "NOINTL", "NOICONS", ""
};

enum
{
   GD_FormatStrGad,
   GD_SelFormatGad,
   GD_DevLV,
   GD_NameGad,
   GD_IconsGad,
   GD_FSCYGad,
   GD_InterCYGad,
   GD_FmtStrGad,
   GD_FormatGad,
   GD_QuickGad,
   GD_CancelGad
};

static struct Window *FormatDiskWnd = NULL;
static struct Gadget *FormatDiskGList = NULL;
static struct Gadget *FormatDiskGadgets[10];
static UWORD FormatDiskLeft = 161;
static UWORD FormatDiskTop = 49;
static UWORD FormatDiskWidth = 297;
static UWORD FormatDiskHeight = 116;
static UBYTE *FormatDiskWdt = (UBYTE *) NAME " " VERSION " - Format Disk";

static UBYTE *IconsGad0Labels[]=
{
   (UBYTE *) "Icons",
   (UBYTE *) "No Icons",
   NULL};

static UBYTE *FSCYGad0Labels[]=
{
   (UBYTE *) "OFS",
   (UBYTE *) "FFS",
   NULL};

static UBYTE *InterCYGad0Labels[]=
{
   (UBYTE *) "No international",
   (UBYTE *) "International",
   NULL};

#define FormatDisk_CNT 10

static UWORD FormatDiskGTypes[] = {
	STRING_KIND,
	BUTTON_KIND,
	LISTVIEW_KIND,
	STRING_KIND,
	CYCLE_KIND,
	CYCLE_KIND,
	CYCLE_KIND,
	STRING_KIND,
	BUTTON_KIND,
	BUTTON_KIND
};

static struct NewGadget FormatDiskNGad[] = {
	68, 3, 145, 13, (UBYTE *)"Format", NULL, GD_FormatStrGad, PLACETEXT_LEFT, NULL, NULL,
	216, 3, 73, 13, (UBYTE *)"Select", NULL, GD_SelFormatGad, PLACETEXT_IN, NULL, NULL,
	8, 32, 73, 48, (UBYTE *)"Devices", NULL, GD_DevLV, PLACETEXT_ABOVE|NG_HIGHLABEL, NULL, NULL,
	92, 32, 197, 13, (UBYTE *)"Disk label", NULL, GD_NameGad, PLACETEXT_ABOVE|NG_HIGHLABEL, NULL, NULL,
	92, 50, 97, 13, NULL, NULL, GD_IconsGad, 0, NULL, NULL,
	192, 50, 97, 13, NULL, NULL, GD_FSCYGad, 0, NULL, NULL,
	92, 67, 197, 13, NULL, NULL, GD_InterCYGad, 0, NULL, NULL,
	8, 85, 281, 13, NULL, NULL, GD_FmtStrGad, 0, NULL, NULL,
	8, 100, 137, 13, (UBYTE *)"Format", NULL, GD_FormatGad, PLACETEXT_IN, NULL, NULL,
	152, 100, 137, 13, (UBYTE *)"Quick", NULL, GD_QuickGad, PLACETEXT_IN, NULL, NULL
};

static ULONG *FormatDiskGTags[] = {
	(ULONG *)(GTST_String), (ULONG *)parts[0], (ULONG *)(GTST_MaxChars), (ULONG *)256, (ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE),
	(ULONG *)(GTLV_ShowSelected), (ULONG *)NULL, (ULONG *)GTLV_Labels, (ULONG *)&DevList, (ULONG *)GTLV_Selected, (ULONG *)0, (ULONG *)GTLV_Top, (ULONG *)0, (ULONG *)(TAG_DONE),
	(ULONG *)(GTST_String), (ULONG *)parts[2], (ULONG *)(GTST_MaxChars), (ULONG *)256, (ULONG *)(TAG_DONE),
	(ULONG * )(GTCY_Labels), (ULONG *)&IconsGad0Labels[ 0 ], (ULONG *)(TAG_DONE),
	(ULONG * )(GTCY_Labels), (ULONG *)&FSCYGad0Labels[ 0 ], (ULONG *)(TAG_DONE),
	(ULONG * )(GTCY_Labels), (ULONG *)&InterCYGad0Labels[ 0 ], (ULONG *)(TAG_DONE),
	(ULONG *)(GTST_MaxChars), (ULONG *)256, (ULONG *)GTST_String, (ULONG *)fmtcmd, (ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE),
	(ULONG *)(TAG_DONE)
};

   /*
    * OpenFormatDiskWindow() öffnet ein Window mit
    * Kontrollelementen zu Aufruf des FORMAT-Befehls
    */
int
OpenFormatDiskWindow( void )
{
	struct NewGadget	ng;
	struct Gadget	*g;
	UWORD		lc, tc;
	UWORD		wleft = FormatDiskLeft, wtop = FormatDiskTop, ww, wh;
   int gl[] = {GD_FormatStrGad,GD_DevLV,GD_NameGad,GD_FmtStrGad};

   DPOS;

	ComputeFont( Scr,FormatDiskWidth, FormatDiskHeight );

	ww = ComputeX( FormatDiskWidth );
	wh = ComputeY( FormatDiskHeight );

	if (( wleft + ww + OffX + Scr->WBorRight ) > Scr->Width ) wleft = Scr->Width - ww;
	if (( wtop + wh + OffY + Scr->WBorBottom ) > Scr->Height ) wtop = Scr->Height - wh;

   ww = compute((UWORD) (OffX + Scr->WBorRight), FontX, (int)FormatDiskWidth);
   wh = compute((UWORD) (OffY + Scr->WBorBottom), FontY, (int)FormatDiskHeight);

   CenterWindow(Scr, &wtop, &wleft, ww, wh);

	if ( ! ( g = CreateContext( &FormatDiskGList )))
		return( 1L );

	for( lc = 0, tc = 0; lc < FormatDisk_CNT; lc++ ) {

		CopyMem((char * )&FormatDiskNGad[ lc ], (char * )&ng, (long)sizeof( struct NewGadget ));

		ng.ng_VisualInfo = VisualInfo;
		ng.ng_TextAttr   = Font;
		ng.ng_LeftEdge   = OffX + ComputeX( ng.ng_LeftEdge );
		ng.ng_TopEdge    = OffY + ComputeY( ng.ng_TopEdge );
		ng.ng_Width      = ComputeX( ng.ng_Width );
		ng.ng_Height     = ComputeY( ng.ng_Height);

		FormatDiskGadgets[ lc ] = g = CreateGadgetA((ULONG)FormatDiskGTypes[ lc ], g, &ng, ( struct TagItem * )&FormatDiskGTags[ tc ] );

      makelabelvisible(FormatDiskGadgets[lc]);

		while( FormatDiskGTags[ tc ] ) tc += 2;
		tc++;

		if ( NOT g )
			return( 2L );
	}

	if ( ! ( FormatDiskWnd = OpenWindowTags( NULL,
				WA_Left,	wleft,
				WA_Top,		wtop,
				WA_Width,	ww, /* + OffX + Scr->WBorRight,*/
				WA_Height,	wh, /* + OffY + Scr->WBorBottom,*/
				WA_IDCMP,	STRINGIDCMP|
                        BUTTONIDCMP|
                        LISTVIEWIDCMP|
                        CYCLEIDCMP|
                        IDCMP_CLOSEWINDOW|
                        IDCMP_REFRESHWINDOW|
                        IDCMP_VANILLAKEY,
				WA_Flags,	WFLG_DRAGBAR|
                        WFLG_DEPTHGADGET|
                        WFLG_CLOSEGADGET|
                        WFLG_SMART_REFRESH|
                        WFLG_ACTIVATE|
                        WFLG_RMBTRAP,
				WA_Gadgets,	FormatDiskGList,
				WA_Title,	FormatDiskWdt,
            WA_PubScreenFallBack,TRUE,
            WA_PubScreen, Scr,
				TAG_DONE )))
      return( 4L );

   RefreshRastPort(FormatDiskWnd,FormatDiskGadgets,gl, 4);

	GT_RefreshWindow( FormatDiskWnd, NULL );

	return( 0L );
}

   /*
    * FindDevices() sucht nach formatierbaren Devices im System
    * und baut eine Liste mit deren Namen auf
    */
static void
FindDevices(void)
{
   struct DosList *DosList;
   struct DeviceNode *DevNode;
   char  dev[PATHPARTWIDTH],
         str[MAXFULLNAME];

   DosList = LockDosList(LDF_DEVICES | LDF_READ);

   while (DosList = NextDosEntry(DosList, LDF_DEVICES | LDF_READ))
   {
      DevNode = (struct DeviceNode *) DosList;
      if ((DevNode->dn_Startup > 1000) &&
          (DevNode->dn_Task || DevNode->dn_Handler || DevNode->dn_SegList))
      {
         strncpy(str, B2CStr(dev, DevNode->dn_Name),MAXFULLNAME-1);
         strcat(str, ":");

         MakeDevEntry(&DevList, str);
      }
   }

   UnLockDosList(LDF_DEVICES | LDF_READ);

   return;
}

   /*
    * update() aktualisiert den Aufruf des Formatbefehls nach den
    * Einstellungen des Kontrollfensters
    */
static void
update(void)
{
   sprintf((char *)fmtcmd, CMDFMT, parts[0], parts[1], parts[2], parts[3],
           parts[4], parts[5], parts[6]);

   GT_SetGadgetAttrs(FormatDiskGadgets[GD_FmtStrGad], FormatDiskWnd,
                     NULL,
                     GTST_String, fmtcmd,
                     TAG_DONE);

   return;
}

   /*
    * SelFormatProgram() bietet einen Filerequester an, mit dem
    * ein alternativer Format-Befehl ausgeführt werden kann
    */
static void
SelFormatProgram(void)
{
   if (GetFile(FormatDiskWnd,"SYS:System/","Format","#?",
               "Select Format program","Select"))
      if (exist((char *)_fullpath))
      {
         strncpy((char *)parts[0], (char *)_fullpath, MAXSTRLEN);
         update();
      }
      else
         ErrorHandle(FILE_ERR, READ_FAIL, NO_KILL);

   return;
}

extern UBYTE autocon[];

   /*
    * startformat() führt den zusammengesetzten Format-Befehl mit
    * der System()-Routine aus
    */
static void
startformat(void)
{
   struct TagItem stags[5];
   BPTR  fileptr;

   if (fileptr = Open(autocon, MODE_OLDFILE))
   {
      stags[0].ti_Tag = SYS_Input;
      stags[0].ti_Data = fileptr;
      stags[1].ti_Tag = SYS_Output;
      stags[1].ti_Data = NULL;
      stags[2].ti_Tag = SYS_Asynch;
      stags[2].ti_Data = FALSE;
      stags[3].ti_Tag = SYS_UserShell;
      stags[3].ti_Data = TRUE;
      stags[4].ti_Tag = TAG_DONE;

      if (Question(FormatDiskWnd, (char *)fmtcmd, YES))
         if (System(fmtcmd, stags) == -1L)
         {
            Close(fileptr);
            ErrorHandle(TASK_ERR, CREATE_FAIL, NO_KILL);
         }
   }

   return;
}

   /*
    * FormatDisk() bietet eine kleine Benutzeroberfläche an und
    * verarbeitet die Eingaben, mit denen der Aufruf des
    * Format-Befehls konfiguriert werden kann
    */
void
FormatDisk(void)
{
   register struct IntuiMessage *message;
   struct Node *clicknode;
   ULONG class,
         code;
   APTR  object;
   APTR  req = NULL;
   char *buff;

   DPOS;

   Flags.quit_fd = 0;

   NewList(&DevList);

   FindDevices();

   if (OpenASysWindow(OpenFormatDiskWindow,NO_KILL))
   {
      if (SysWnd)
         req = LockWindow(SysWnd);

      update();

      GT_SetGadgetAttrs(FormatDiskGadgets[GD_DevLV], FormatDiskWnd,
                        NULL,
                        GTLV_Labels, &DevList,
                        TAG_DONE);
      do
      {
         Wait(1L << FormatDiskWnd->UserPort->mp_SigBit);

         while ((message = (struct IntuiMessage *)
                 GT_GetIMsg(FormatDiskWnd->UserPort)) != NULL)
         {
            object = message->IAddress;
            class = message->Class;
            code = message->Code;

            GT_ReplyIMsg(message);

            switch (class)
            {
               case IDCMP_GADGETUP:
                  switch (((struct Gadget *) object)->GadgetID)
                  {
                     case GD_FormatStrGad:
                        buff = gadgetbuff(FormatDiskGadgets[GD_FormatStrGad]);
                        if (exist(buff))
                        {
                           strncpy((char *)parts[0], buff, MAXSTRLEN);
                           update();
                        }
                        else
                           ErrorHandle(FILE_ERR, READ_FAIL, NO_KILL);
                        break;

                     case GD_SelFormatGad:
                        SelFormatProgram();
                        break;

                     case GD_DevLV:
                        clicknode = GetNode(&DevList, code);
                        strncpy((char *)parts[1], clicknode->ln_Name,MAXSTRLEN);
                        update();
                        break;

                     case GD_NameGad:
                        strncpy((char *)parts[2],gadgetbuff(FormatDiskGadgets[GD_NameGad]),
                                MAXSTRLEN);
                        update();
                        break;

                     case GD_IconsGad:
                        if (code == 0)
                           parts[5][0] = STRINGEND;
                        else
                           strcpy((char *)parts[5], "NOICONS");

                        update();
                        break;

                     case GD_FSCYGad:
                        strncpy((char *)parts[3], (char *)FSCYGad0Labels[code],
                               MAXSTRLEN);
                        update();
                        break;

                     case GD_InterCYGad:
                        strcpy((char *)parts[4], (code == 0) ? "NOINTL" : "INTL");
                        update();
                        break;

                     case GD_FmtStrGad:
                        strncpy((char *)fmtcmd,
                               gadgetbuff(FormatDiskGadgets[GD_FmtStrGad]),
                               MAXWRITESIZE);
                        break;

                     case GD_FormatGad:
                        parts[6][0] = STRINGEND;
                        update();
                        startformat();
                        break;

                     case GD_QuickGad:
                        strcpy((char *)parts[6], "QUICK");
                        update();
                        startformat();
                        break;
                  }

                  break;

               case IDCMP_VANILLAKEY:
                  if (code == '\33')
                     Flags.quit_fd = 1;
                  break;

               case IDCMP_REFRESHWINDOW:
                  MakeWindowRefresh(FormatDiskWnd);
                  break;

               case IDCMP_CLOSEWINDOW:
                  Flags.quit_fd = 1;
                  break;
            }
         }
      }
      while (NOT(Flags.quit_fd));

      FreeRemember(DEVKEY, TRUE);

      CloseASysWindow(&FormatDiskWnd, &FormatDiskGList, NULL);

      if (req)
      {
         UnlockWindow(req);
         RefreshMainWindowPattern();
         RefreshList(LastID);
      }
   }

   return;
}
