/*
   ***************************************************************************
   *
   * Datei:
   *      RSysUtils.c
   *
   * Inhalt:
   *
   *      --- Globale Routinen ---
   *
   *    char *B2CStr ( char *ret , BSTR inp );
   *    char *strcpy ( char *dest , const char *src );
   *    char *strncpy ( char *dest , const char *src , size_t len );
   *    int exist ( char *name );
   *    int Question ( WINDOW *wind , char *ask , int def );
   *    int SizeOfDir ( BPTR lock , long *Size , int *Dirs );
   *    long ahtoi ( char *String );
   *    LONG Command ( NODE *node , char *file );
   *    long getdisktype ( BPTR lock );
   *    long SizeOfFile ( char *Name );
   *    ScrollEntry *AllocScrollEntries ( int count );
   *    DISKOBJECT *GetProgramIcon ( void );
   *    NODE *GetNode ( LIST *list , ULONG offset );
   *    void *MyAllocVec ( unsigned long byteSize , unsigned long requirements , int kill );
   *    void AddNodeSorted ( LIST *list , NODE *node , int sortpos );
   *    void AddNodeToList ( int i , int sort_in , int sortpos );
   *    void CloseAll ( void );
   *    void CloseLibs ( void );
   *    void CreateEntryList ( int sorting, int sortpos );
   *    void FreeBytes ( char *Vol , long *free , long *used , long *usedpercent , char *state , char *type );
   *    void MyFreeVec ( void *memptr );
   *    void OpenLibs ( void );
   *    void quit ( int askyou );
   *    void savestrcpy ( char *str , NODE *node , int cnt , int type );
   *    void ToggleAskingMode ( void );
   *    void ToggleAutoFront ( void );
   *    void ToggleFastMode ( void );
   *    void ToggleMouseWindow ( void );
   *    void ToggleSortMode ( void );
   *    void ToggleSpeakMode ( void );
   *    void ToggleTextFormatter ( void );
   *    void ToggleTopazFont ( void );
   *    void ToggleWorkingBar ( void );
   *
   *      --- Lokale  Routinen ---
   *
   *    static int StrICmp ( const char *s1 , char *s2 );
   *    static UWORD InitBar ( void );
   *    static void RefreshBar ( int curr );
   *    static void RemoveBar ( UWORD pos );
   *
   * Bemerkungen:
   *      Utilities, die im ganzen Programm verwendet werden, z.B.
   *      Listen- und Stringverwaltungsroutinen.
   *
   * Erstellungsdatum:
   *      07-Jan-93     Rolf Böhme
   *
   * Änderungen:
   *      07-Jan-93     Rolf Böhme        Erstellung
   *
   ***************************************************************************
 */

#include "RSys.h"
#include "protos.h"

 /*
  * strncpy() ersetzt die Compiler-Routine. Im Gegensatz zur
  * Orginalroutine wird der Zielstring korrekt terminiert
  */
char *
strncpy (char *dest, const char *src, size_t len)
{
  size_t i = len;
  char *tmp = dest;

  if (src)
    while ((*(tmp++) = *(src++)) && --i);

  *tmp = STRINGEND;

  return dest;
}

 /*
  * strcpy() ersetzt die Compiler-Routine. Im Gegensatz zur
  * Orginalroutine wird überprüft, ob der Quellstring
  * überhaupt existiert und kein NULL-Zeiger übergeben
  * wurde
  */
char *
strcpy (char *dest, const char *src)
{
  char *tmp = dest;

  if (src)
    while (*(tmp++) = *(src++));
  else
    *tmp = STRINGEND;

  return dest;
}

long
ahtoi (char *String)
{
  long Value = 0;
  char c;

  while (c = *String)
    {
      Value = Value << 4;

      if (c >= '0' && c <= '9')
	Value |= (c & 15);
      else
	Value |= (c & 15) + 9;

      ++String;
    }

  return Value;
}

 /*
  * MyAllocVec() ist eine Erweiterung der AllocVec()-Routine. In
  * einem Fehlerfall wird eine Meldung ausgegeben und das
  * Programm evtl korrekt beendet
  */
void *
MyAllocVec (unsigned long byteSize, unsigned long requirements, int kill)
{
  void *memptr = NULL;

  DPOS;

  if (NOT (memptr = AllocVec (byteSize, requirements)))
    ErrorHandle (__FUNC__ "()", MEMORY_ERR, ALLOC_FAIL, kill);

  return memptr;
}

 /*
  * MyFreeVec() prüft im Gegensatz zu Originalroutine, ob ein
  * NULL-Zeiger übergeben wurde
  */
void
MyFreeVec (void *memptr)
{
  DPOS;

  if (memptr != NULL)
    FreeVec (memptr);
  memptr = NULL;

  return;
}


 /*
  * Command() führt einen Befehl in einem eigenen Prozeß aus.
  * Als Aus- und Eingabekanal wird das Window verwendet, das im
  * RSys-Icon festgelegt wurde
  */
LONG
Command (NODE * node, char *file)
{
  TAGITEM stags[5];
  LONG result = -2;
  BPTR fileptr;
  RSYS_acts *Act = (RSYS_acts *) node;
  UBYTE cmd[512];

  DPOS;

  if (node && strcmp (Act->act_command, field[NO_FIELD]) &&
      (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;

      sprintf ((char *) cmd, "%s \"%s\"", Act->act_command, file);

      result = System (cmd, stags);
      if (result == -1L)
	{
	  Close (fileptr);
	  ErrorHandle ((char *) cmd, TASK_ERR, CREATE_FAIL, NO_KILL);
	}
    }

  return result;
}

 /*
  * GetProgramIcon() ermittelt das aktuelle Icon von RSys
  */

DISKOBJECT *
GetProgramIcon (void)
{
  DISKOBJECT *Icon = NULL;

  DPOS;

  if (Icon = GetDiskObjectNew ((STRPTR) RSysName))
    {
      if (Icon->do_Type != WBTOOL)
	{
	  FreeDiskObject (Icon);
	  Icon = NULL;
	}
    }

  if (!Icon)
    {
      BPTR NewLock;

      /* Move to the directory the
       * program was run from.
       */

      if (NewLock = Lock ((STRPTR) "PROGDIR:", ACCESS_READ))
	{
	  BPTR OldLock;

	  OldLock = CurrentDir (NewLock);

	  /* Try to fetch the icon, use the
	   * default name if necessary.
	   */

	  if (Icon = GetDiskObjectNew ((STRPTR) "RSys"))
	    {
	      if (Icon->do_Type != WBTOOL)
		{
		  FreeDiskObject (Icon);

		  Icon = NULL;
		}
	    }

	  CurrentDir (OldLock);

	  UnLock (NewLock);
	}
    }

  if (!Icon)
    {
      /* Use the default names. */

      Icon = GetDefDiskObject (WBTOOL);
      if (!Icon)
	ErrorHandle ("DefaultIcon", ICON_ERR, ALLOC_FAIL, NO_KILL);
    }

  return Icon;
}

 /*
  * ToggleFastMode() schaltet zwischen der schnellen Anzeige (die
  * Listenelemente werden während der Erzeugung nicht angezeigt)
  * und der langsamen Anzeige (wenn ein Eintrag erzeugt wurde,
  * wird er sofort angezeigt)
  */
void
ToggleFastMode (void)
{
  DPOS;

  HandleHelp (MN_ToggleFastMode);

  Flags.fastmode = ~Flags.fastmode;

  PrintInfo (Flags.fastmode ? "Fast mode on" : "Fast mode off", SPEAK, SEC);

  PrintStatistics ();

  return;
}

 /*
  * ToggleAskingMode() schaltet die Sicherheits-
  * abfrage bei kritischen Aktionen ein oder aus
  */
void
ToggleAskingMode (void)
{
  DPOS;

  HandleHelp (MN_ToggleAskingMode);

  Flags.saveasking = ~Flags.saveasking;

  PrintInfo (Flags.saveasking ? "Save asking mode on" : "Save asking mode off", SPEAK, SEC);

  PrintStatistics ();

  return;
}

void
ToggleTextFormatter (void)
{
  DPOS;

  HandleHelp (MN_TextFormatter);

  Flags.textformat = ~Flags.textformat;

  PrintInfo (Flags.textformat ? "Text formatting on" : "Text formatting off", SPEAK, SEC);

  PrintStatistics ();

  return;
}

 /*
  * ToggleSortMode() schaltet zwischen dem sortierten und
  * direkten Einfügen von Listenelementen um
  */
void
ToggleSortMode (void)
{
  DPOS;

  HandleHelp (MN_ToggleSortMode);

  Flags.sortmode = ~Flags.sortmode;

  PrintInfo (Flags.sortmode ? "List sorting on" : "List sorting off", SPEAK, SEC);

  RefreshList (LastID);

  PrintStatistics ();

  return;
}

 /*
  * ToggleWorkingBar() schaltet die Anzeige des Working Bars
  * (Anzeigestatus in Form eines Laufbalkens) um
  */
void
ToggleWorkingBar (void)
{
  DPOS;

  HandleHelp (MN_ToggleWorkingBar);

  Flags.workingbar = ~Flags.workingbar;

  PrintInfo (Flags.workingbar ? "Working bar on" : "Working bar off", SPEAK, SEC);

  RefreshList (LastID);

  PrintStatistics ();

  return;
}

 /*
  * ToggleSpeakMode() schaltet die Sprachausgabe ein oder aus.
  * Alle Mitteilungen, die im Textgadget unten im Hauptwindow
  * erscheinen, werden über das narrator.device ausgegeben, wenn
  * der Modus eingeschaltet wurde
  */
void
ToggleSpeakMode (void)
{
  DPOS;

  HandleHelp (MN_ToggleSpeakMode);

  Flags.speakmode = ~Flags.speakmode;

  if (NOT (Flags.speakmode))
    RemoveSpeech ();
  else if (NOT (InitSpeech ()))
    Flags.speakmode = ~Flags.speakmode;

  PrintInfo (Flags.speakmode ? "Speak mode on" : "Speak mode off", SPEAK, SEC);

  PrintStatistics ();

  return;
}

 /*
  * ToggleAutoFront() ermöglicht das Öffnen eines Fensters
  * mit anschließendem Nach-Vorne-Bringen dieses Fensters
  */
void
ToggleAutoFront (void)
{
  DPOS;

  HandleHelp (MN_ToggleAutoFront);

  Flags.autofront = ~Flags.autofront;

  PrintInfo (Flags.autofront ? "Auto front on" : "Auto front off", SPEAK, SEC);

  PrintStatistics ();

  return;
}

 /*
  * ToggleMouseWindow() schaltet die Möglichkeit ein oder aus,
  * alle Fenster von RSys unter dem Mauszeiger zu öffnen
  */
void
ToggleMouseWindow (void)
{
  DPOS;

  HandleHelp (MN_ToggleMouseWindow);

  Flags.mousewindow = ~Flags.mousewindow;

  PrintInfo (Flags.mousewindow ? "Mouse window on" : "Mouse window off", SPEAK, SEC);

  PrintStatistics ();

  return;
}

 /*
  * ToggleTopazFont() schaltet zwischen der Verwendung des
  * System-Fonts und dem Topaz-Font um. Wird als
  * System-Workbench-Font ein proportionaler Zeichensatz
  * gewählt, sehen die Listen etwas unformatiert aus. Topaz ist
  * ein unproportionaler Font, der Listen korrekt formatiert
  * darstellt
  */
void
ToggleTopazFont (void)
{

  DPOS;

  HandleHelp (MN_ToggleTopazFont);

  Flags.sysfont = ~Flags.sysfont;

  CloseASysWindow (&SysWnd, &SysGList, &SysMenus);
  CloseDownScreen ();

  OpenMainWindow ();

  RefreshList (LastID);

  PrintInfo (Flags.sysfont ? "Topaz font on" : "Topaz font off", SPEAK, SEC);

  PrintStatistics ();

  ReopenWindow = TRUE;

  return;
}

 /*
  * StrICmp() ersetzt die Utility-Library- und Aztec-C-Routine.
  * Beide liefern enforcer-Hits, falls man sie mit Leer- oder
  * NULL-Strings aufruft
  */
static int
StrICmp (const char *s1, char *s2)
{
  int c1, c2, diff = 0;

  while (s1 && *s1 && s2 && *s2 && (diff == 0))
    {
      c1 = toupper ((int) (*s1));
      c2 = toupper ((int) (*s2));
      diff = c1 - c2;

      s1++;
      s2++;
    }

  return diff;
}

#define STRICMP(src,dest) StrICmp((char *)(src),(char *)(dest))

 /*
  * AddNodeSorted() sortiert ein Listenelement in eine
  * bestehende Liste ein. Da die hier betrachteten Listen
  * ziemlich klein sind, wird hier ein einfaches Sortieren durch
  * Einfügen verwendet. Das Sortieren erfolg ab einer bestimmten
  * Position sortpos.
  */
void
AddNodeSorted (LIST * list, NODE * node, int sortpos)
{
  NODE *head = list->lh_Head, *loop_node;
  BOOL ins = FALSE;

  if (IsListEmpty (list))
    AddHead (list, node);
  else if (head->ln_Succ == NULL)
    {
      if (STRICMP (&head->ln_Name[sortpos], &node->ln_Name[sortpos]) <= 0L)
	AddTail (list, node);
      else
	AddHead (list, node);

      ins = TRUE;
    }
  else
    {
      if (STRICMP (&head->ln_Name[sortpos], &node->ln_Name[sortpos]) > 0L)
	{
	  AddHead (list, node);
	  ins = TRUE;
	}

      for (loop_node = head;
	loop_node->ln_Succ && loop_node->ln_Succ->ln_Succ && (ins == FALSE);
	   loop_node = loop_node->ln_Succ)
	{
	  if ((STRICMP (&loop_node->ln_Name[sortpos], &node->ln_Name[sortpos]) <= 0L) &&
	      (STRICMP (&node->ln_Name[sortpos], &loop_node->ln_Succ->ln_Name[sortpos]) < 0L))
	    {
	      Insert (list, node, loop_node);
	      ins = TRUE;
	    }
	}

      if (ins == FALSE)
	AddTail (list, node);
    }

  return;
}

static ULONG xmin, ymin, xmax, ymax;

 /*
  * InitBar() entfernt das Informationen-Text-Gadget; dabei
  * bleibt der Rahmen stehen (dank Intuition). Dieser Rahmen
  * wird dann als Begrenzung für den Statusbalken verwendet.
  * Der Balkenbereich wird dann gelöscht und die Zeichenmodi
  * eingestellt.
  */
static UWORD
InitBar (void)
{
  UWORD pos = RemoveGadget (SysWnd, SysGadgets[18]);
  RASTPORT *RP;

  RP = SysWnd->RPort;

  xmin = SysGadgets[18]->LeftEdge + 1;
  ymin = SysGadgets[18]->TopEdge + 1;

  xmax = SysGadgets[18]->LeftEdge + SysGadgets[18]->Width - 4;
  ymax = SysGadgets[18]->TopEdge + SysGadgets[18]->Height - 2;

  EraseRect (RP, xmin, ymin, xmax, ymax);

  SetDrMd (RP, JAM1);
  SetAPen (RP, 3);
  SetBPen (RP, 0);

  return (pos);
}

 /*
  * RefreshBar() aktualisiert die Anzeige des Statusbalkens.
  * Dazu wird wie folgt vorgegangen:
  * 1. Neue Breite des Balkens und Prozentzahl berechnen
  * 2. Den Bereich mit Farbe füllen
  * 3. Falls es nicht der letzte Eintrag war, wird
  *     der Rest des Balkenbereichs (rechts) gelöscht
  */
static void
RefreshBar (int curr)
{
  ULONG xcurr = xmin + ((xmax - xmin) * curr) / countentries;

  RectFill (SysWnd->RPort, xmin, ymin, xcurr, ymax);

  return;
}

 /*
  * RemoveBar() löscht den Bereich des für den Statusbalkens
  * entfernten Gadgets und hängt das Gadget wieder ein
  */
static void
RemoveBar (UWORD pos)
{
  SetAPen (SysWnd->RPort, 0);

  EraseRect (SysWnd->RPort, xmin, ymin, xmax, ymax);

  AddGadget (SysWnd, SysGadgets[18], (ULONG) pos);

  RefreshGList (SysGadgets[18], SysWnd, NULL, 1);
  GT_RefreshWindow (SysWnd, NULL);

  return;
}

 /*
  * AddNodeToList() ist eine Schnittstelle zwischen den Routinen
  * AddNodeSorted() und AddTail(). Je nachdem, ob ein Element in
  * die Liste sortiert einfügt werden soll oder nicht, werden
  * die entsprechenden Routinen aufgerufen
  */
void
AddNodeToList (int i, int sort_in, int sortpos)
{
  LIST *list = &ListeLVList;
  NODE *head = list->lh_Head, *node = &(Entries[i].se_Node);
  UWORD gadpos;

  if (Flags.workingbar && (i == 0))
    gadpos = InitBar ();

  if (Flags.sortmode && sort_in && head && node->ln_Name)
    AddNodeSorted (list, node, sortpos);
  else
    AddTail (list, node);

  if (NOT (Flags.fastmode))
    {
      RefreshListView ();
      WaitTOF ();
    }

  if (Flags.workingbar)
    {
      RefreshBar (i);

      if (i == (countentries - 1))
	{
	  RefreshBar (countentries);
	  RemoveBar (gadpos);
	}
    }

  return;
}

 /*
  * CreateEntryList() fügt die Entries in die Anzeigeliste ein.
  */
void
CreateEntryList (int sorting, int sortpos)
{
  int i;

  for (i = 0; i < countentries; i++)
    AddNodeToList (i, sorting, sortpos);

  return;
}

 /*
  * B2CStr() wandelt einen BCPL-String in einen C-String um
  */
char *
B2CStr (char *dest, BSTR inp)
{
  int i;
  char *help = (char *) BADDR (inp);

  DPOS;

  for (i = 0; i < *help; i++)
    *(dest + i) = *(help + i + 1);

  *(dest + i) = STRINGEND;

  return dest;
}

 /*
  * savestrcpy() kopiert eine Anzahl von Zeichen eines
  * Node-Namens in einen Zielstring. Hierbei wird darauf
  * geachtet, daß ein Node-Name überhaupt existiert
  */
void
savestrcpy (char *str, NODE * node, int cnt, int type)
{

  DPOS;

  if (!node || !(node->ln_Name))
    {
      strcpy (str, field[NO_NODE]);
      return;
    }

  if ((type == NT_TASK) && (node->ln_Type == NT_PROCESS))
    type = NT_PROCESS;
  if ((type == NT_SEMAPHORE) && (node->ln_Type == NT_SIGNALSEM))
    type = NT_SIGNALSEM;


  if (node->ln_Type == type)
    strncpy (str, node->ln_Name, cnt);
  else
    sprintf (str, field[WRONG_TYPE_FMT], node->ln_Type);


  return;
}

 /*
  * GetNode() ermittelt einen Eintrag, dessen Abstand vom
  * Listenkopf in offset angegeben wird, also das offset'te
  * Element
  */
NODE *
GetNode (LIST * list, ULONG offset)
{
  NODE *Node;
  LONG i;

  DPOS;

  Node = (NODE *) list->lh_Head;

  for (i = 0; i < offset; i++)
    {
      if (!Node->ln_Succ)
	return NULL;

      Node = Node->ln_Succ;
    }

  return Node;
}

 /*
  * SizeOfFile() ermittelt die Größe einer Datei
  */
long
SizeOfFile (char *Name)
{
  FILEINFOBLOCK *FileInfo;
  LONG FileSize = 0L;

  DPOS;

  if (NOT (exist (Name)))
    return FileSize;

  if (FileInfo = (FILEINFOBLOCK *) AllocDosObject (DOS_FIB, TAG_DONE))
    {
      BPTR FileLock;

      if (FileLock = Lock ((UBYTE *) Name, ACCESS_READ))
	{
	  if (Examine (FileLock, FileInfo))
	    FileSize = FileInfo->fib_Size;

	  UnLock (FileLock);
	}

      FreeDosObject (DOS_FIB, FileInfo);
    }

  return FileSize;
}

 /*
  * SizeOfDir() ermittelt die Größe eines Directories, also die
  * Größe aller in ihr enthaltenen Dateien
  */
int
SizeOfDir (BPTR lock, long *Size, int *Dirs)
{
  EXALLCONTROL *eac;
  EXALLDATA *EAData, *ead;
  int cnt = 0, more;

  DPOS;

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

      EAData = MyAllocVec (513 * sizeof (EXALLDATA),
			   MEMF_ANY | MEMF_CLEAR, NO_KILL);

      if (EAData)
	{
	  do
	    {
	      more = ExAll (lock, EAData, 512 * sizeof (EXALLDATA), ED_SIZE, eac);

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

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

	      ead = EAData;

	      do
		{
		  if (SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
		    {
		      more = FALSE;
		      break;
		    }

		  *Size += ead->ed_Size;

		  if (ead->ed_Type > 0)
		    (*Dirs)++;
		  else
		    cnt++;

		  ead = ead->ed_Next;

		}
	      while (ead);
	    }
	  while (more);
	}

      MyFreeVec (EAData);

      FreeDosObject (DOS_EXALLCONTROL, eac);
    }
  else
    ErrorHandle ("AllocDosObject()", MEMORY_ERR, ALLOC_FAIL, KILL);

  return cnt;
}

 /*
  * AllocScrollEntries() reserviert Speicher für die
  * Listeneinträge des Haupt-ListViews. Werden weniger Einträge
  * angefordert, als zuvor alloziert sind, wird kein neuer
  * Speicher angefordert, sondern ein Zeiger auf die
  * Ursprungs-Liste zurückgegeben, damit die Daten dann
  * überschrieben werden können
  */
RSYS_ScrollEntry *
AllocScrollEntries (int count)
{
  int i;
  static int memcounter = 0;

  DPOS;

  if (count > memcounter)
    {
      if (Entries != NULL)
	{
	  MyFreeVec (Entries);
	  Entries = NULL;
	}

      if (Entries = (RSYS_ScrollEntry *) MyAllocVec (count * sizeof (RSYS_ScrollEntry),
					       MEMF_ANY | MEMF_CLEAR, KILL))
	{
	  for (i = 0; i < count; i++)
	    Entries[i].se_Node.ln_Name = Entries[i].se_Entry;

	  memcounter = count;
	  maxentries = memcounter;

	  return Entries;
	}
    }
  else
    return Entries;

  return NULL;
}

 /*
  * getdisktype() holt aus einem FileLock die Typ-Nummer des
  * angemeldeten Devices heraus
  */
long
getdisktype (BPTR lock)
{
  FILELOCK *fl = (FILELOCK *) BADDR (lock);

  return (((DEVICELIST *) BADDR (fl->fl_Volume))->dl_DiskType);
}

 /*
  * FreeBytes() ermittelt die Daten eines Volumes
  */
void
FreeBytes (char *Vol, long *free, long *used, long *usedpercent,
	   char *state, char *type)
{
  BPTR lock = NULL;
  int i;
  INFODATA *ID = NULL;
  union
    {
      LONG dostype;
      char dostypestr[5];
    }
  convert;

  DPOS;

  if (ID = (INFODATA *) MyAllocVec (sizeof (INFODATA), MEMF_CLEAR, NO_KILL))
    {
      if (lock = Lock ((UBYTE *) Vol, ACCESS_READ))
	{
	  if (Info (lock, ID))
	    {
	      *free = (((ID->id_NumBlocks - ID->id_NumBlocksUsed) *
			ID->id_BytesPerBlock) >> 10);
	      *used = ((ID->id_NumBlocksUsed * ID->id_BytesPerBlock) >> 10);
	      *usedpercent = (100 * ID->id_NumBlocksUsed) / ID->id_NumBlocks;

	      if ((convert.dostype = getdisktype (lock)) == 0L)
		convert.dostype = ID->id_DiskType;

	      if (convert.dostype != (long) (-1))
		{
		  strncpy (type, convert.dostypestr, 4);
		  for (i = 0; i < 4; i++)
		    {
		      type[i] += ((int) type[i] < 10 ? 0x30 : 0x20);
		      type[i] = ToUpper ((int) type[i]);
		    }
		}
	      else
		strcpy (type, "NODI");

	      if (strstr (Vol, "AX") || strstr (Vol, "AMAX"))
		strcpy (type, "AMAX");

	      switch (ID->id_DiskState)
		{
		case ID_WRITE_PROTECTED:
		  strcpy (state, "R/O");
		  break;

		case ID_VALIDATING:
		  strcpy (state, "VAL");
		  break;

		case ID_VALIDATED:
		  strcpy (state, "R/W");
		  break;

		default:
		  strcpy (state, field[NO_FIELD]);
		  break;
		}
	    }
	  else
	    {
	      *free = 0L;
	      *used = 0L;
	      *usedpercent = 0;
	      strcpy (state, "NST");
	      strcpy (type, "NINF");
	    }

	  UnLock (lock);
	}
      else
	{
	  *free = 0L;
	  *used = 0L;
	  *usedpercent = 0;
	  strcpy (type, field[NO_FIELD]);
	  strcpy (state, "NOL");
	}

      MyFreeVec (ID);
    }

  return;
}

 /*
  * exist() prüft, ob ein File oder Directory angegebenen Namens
  * existiert
  */
int
exist (char *name)
{
  BPTR File;

  DPOS;

  if (NOT (name) || NOT (name[0]))
    return FALSE;

  if (File = Lock ((UBYTE *) name, ACCESS_READ))
    {
      UnLock (File);
      return TRUE;
    }

  return FALSE;
}

 /*
  * quit() beendet nach einer Sicherheitsabfrage das Programm
  */
void
quit (int askyou)
{
  WORD check = 1;
/*
   GMD

   UBYTE *answer = (UBYTE *) ((Flags.wb_start && !Flags.helpmode) ? "Yes|Iconify|No" : "Yes|No");
 */

  HandleHelp (MN_quit);

  DPOS;

/*
   if (Flags.saveasking && askyou)
   {
   check = MyEasyRequest (SysWnd, (UBYTE *) NAME " ask you",
   answer, (UBYTE *) "Quit program?");
   }
   GMD
 */

  check = 1;

  switch (check)
    {
    case 1:
/*
   GMD
   PrintInfo ("Bye bye", SPEAK, SEC);
 */
      CloseAll ();
      break;

    case 2:
      if (!appicon)
	Iconify ();
      break;

    default:
      break;
    }

  return;
}

 /*
  * Question() bietet eine Ja-Nein-Abfrage in Form eines
  * System-Requesters an. Ist das Flag saveasking ausgeschaltet,
  * wird der Wert default automatisch an die aufrufende
  * Prozedur zurückgegeben.
  */
int
Question (WINDOW * wind, char *ask, int def)
{
  UBYTE header[MAXSTRLEN];

  DPOS;

  if (Flags.saveasking)
    {
      sprintf ((char *) header, "%s ask you", NAME);

      if (Flags.speakmode)
	Speak (ask);

      return MyEasyRequest (wind, header, (UBYTE *) "Yes|No", (UBYTE *) "%s",
			    (UBYTE *) ask);
    }
  else
    return (WORD) def;
}

 /*
  * OpenLibs() öffnet alle notwendigen Libraries, installiert
  * den Broker und liest verschiedene Listen ein
  */
void
OpenLibs (void)
{
  DPOS;

  IntuitionBase = (INTUITIONBASE *) OpenLibrary ((UBYTE *) "intuition.library", 36);
  WorkbenchBase = (WORKBENCHBASE *) OpenLibrary ((UBYTE *) "workbench.library", 36);
  GfxBase = (GFXBASE *) OpenLibrary ((UBYTE *) "graphics.library", 36);
  GadToolsBase = OpenLibrary ((UBYTE *) "gadtools.library", 36);
  UtilityBase = OpenLibrary ((UBYTE *) "utility.library", 36);
  DiskfontBase = OpenLibrary ((UBYTE *) "diskfont.library", 36);
  CxBase = OpenLibrary ((UBYTE *) "commodities.library", 36);
  IconBase = OpenLibrary ((UBYTE *) "icon.library", 36);

  if (!IntuitionBase || !WorkbenchBase || !GfxBase || !GadToolsBase ||
      !UtilityBase || !DiskfontBase || !CxBase || !IconBase)
    ErrorHandle ("Version error?", LIBRARY_ERR, OPEN_FAIL, KILL);

  InstallBroker ();

  if (Flags.wb_start)
    BuildAllDataEntries ();

  BuildValidAddressList ();

  return;
}

 /*
  * CloseLibs() schließt alle geöffneten Resourcen
  */
void
CloseLibs (void)
{
  DPOS;

  CloseLibrary (IconBase);
  CloseLibrary (CxBase);
  CloseLibrary (DiskfontBase);
  CloseLibrary (UtilityBase);
  CloseLibrary (GadToolsBase);
  CloseLibrary ((LIBRARY *) GfxBase);
  CloseLibrary ((LIBRARY *) WorkbenchBase);
  CloseLibrary ((LIBRARY *) IntuitionBase);
  CloseLibrary ((LIBRARY *) DOSBase);

  return;
}

 /*
  * CloseAll() schließt alle geöffneten und initialisierten
  * Intuitionobjekte und beendet das Programm
  */
void
CloseAll (void)
{
  DPOS;

  if (Flags.helpmode)
    Help ();
  if (Flags.speakmode)
    RemoveSpeech ();
  if (appicon)
    RemoveAppIcon (appicon);
  if (Flags.dummy1)
    FreeHardwareData ();
  if (Flags.dummy2)
    FreeLibOffData ();
  if (Flags.dummy3)
    FreeAmigaGuideContextMemory ();
  if (Flags.dummy4)
    FreeValidAddressList ();

  MyFreeVec (Entries);

  KillList ();

  if (SysIdPort)
    DeletePort (SysIdPort);

  if (SysWnd)
    CloseASysWindow (&SysWnd, &SysGList, &SysMenus);

  CloseDownScreen ();

  MyFreeVec (Actions);

  RemoveBroker ();

  MyFreeVec (RSysName);

  RemoveTrapHandlers ();

  CloseLibs ();

  exit (0);
}
