/*
***************************************************************************
*
* Datei:
*    RSysUtils.c
*
* Inhalt:
*    char *strncpy(char *dest, char const *src, unsigned long len);
*    char *strcpy(char *dest, char const *src);
*    void *MyAllocVec(unsigned long byteSize, unsigned long requirements, int kill);
*    void MyFreeVec(void *memptr);
*    long Command(struct Node *node, char *file);
*    void ToggleFastMode(void);
*    void ToggleAskingMode(void);
*    void ToggleSortMode(void);
*    void ToggleSpeakMode(void);
*    void ToggleAutoFront(void);
*    void ToggleMouseWindow(void);
*    void ToggleTopazFont(void);
*    void AddNodeSorted(struct List *list, struct Node *node);
*    void AddNodeToList(int i, int sort_in);
*    void CreateEntryList(int sorting);
*    char *B2CStr(char *ret, long inp);
*    void savestrcpy(char *str, struct Node *node, int cnt, int type);
*    struct Node *GetNode(struct List *list, unsigned long offset);
*    long SizeOfFile(char *Name);
*    int SizeOfDir(long lock, long *Size, int *Dirs);
*    struct SE *AllocScrollEntries(int count);
*    long getdisktype(long lock);
*    void FreeBytes(char *Vol, long *free, long *used, long *usedpercent, char *state, char *type);
*    int exist(char *name);
*    void quit(int askyou);
*    int Question(struct Window *wind, char *ask, int def);
*    void OpenLibs(void);
*    void CloseLibs(void);
*    void CloseAll(void);
*
* 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 "RSysDebug.h"
#include "RSysFunc.h"

extern struct Library *IconBase;

   /*
    * strncpy() ersetzt die Compiler-Routine. Im Gegensatz zur
    * Orginalroutine wird der Zielstring korrekt terminiert
    */
char *
strncpy(char *dest, const char *src, size_t len)
{
   register 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);
}

   /*
    * 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(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;
}

extern UBYTE autocon[];

   /*
    * 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(struct Node *node, char *file)
{
   struct TagItem stags[5];
   LONG  result = -2;
   BPTR  fileptr;
   struct _acts *Act = (struct _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(TASK_ERR, CREATE_FAIL, NO_KILL);
      }
   }

   return (result);
}

   /*
    * 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;

   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;

   Flags.saveasking = ~Flags.saveasking;

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

   PrintStatistics();

   return;
}

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

   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;

   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;

   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;

   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;

   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)
{
   extern int ReopenWindow;

   D(kprintf("----------------------------\n"));

   DPOS;

   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;

   DPOS;

   D(kprintf("----------------------------\n"));

   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);
}
    */

   /*
    * 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
    */
void
AddNodeSorted(struct List *list, struct Node *node)
{
   struct Node *head = list->lh_Head,
        *loop_node;
   BOOL  ins = FALSE;

   if (IsListEmpty(list))
      AddHead(list, node);
   else if (head->ln_Succ == NULL)
   {
      if (Stricmp((STRPTR)head->ln_Name, (STRPTR)node->ln_Name) <= 0L)
         AddTail(list, node);
      else
         AddHead(list, node);

      ins = TRUE;
   }
   else
   {
      if (Stricmp((STRPTR)head->ln_Name, (STRPTR)node->ln_Name) > 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((STRPTR)loop_node->ln_Name, (STRPTR)node->ln_Name) <= 0L) &&
             (Stricmp((STRPTR)node->ln_Name, (STRPTR)loop_node->ln_Succ->ln_Name) < 0L))
         {
            Insert(list, node, loop_node);
            ins = TRUE;
         }
      }

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

   return;
}

static ULONG xmin,ymin,xmax,ymax, textx, texty;

   /*
    * 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)
{
   extern long bpp;
   extern int bpc, bgc;
   UWORD pos = RemoveGadget(SysWnd,SysGadgets[18]);
   struct 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;

   textx = xmin + 2 + (SysGadgets[18]->Width - 4 * (FontX + 1)) / 2;
   texty = ymin + 1 + (SysGadgets[18]->Height - 2 - FontY) / 2 +
           RP->TxBaseline;

   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
    * 4. Die Prozentzahl wird entsprechend des Fonts in den
    * Balken gesetzt.
    */
static void
RefreshBar(int curr)
{
   ULONG percent = (100 * curr) / countentries,
         xcurr = xmin + ((xmax-xmin) * curr) / countentries;
   UBYTE percentstr[5] = " ";

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

   if(curr != countentries)
      EraseRect(SysWnd->RPort, xcurr + 1, ymin, xmax, ymax);
/*
   Move(SysWnd->RPort,textx, texty);

   sprintf((char *)percentstr,"%3ld%%", percent);

   SetAPen(SysWnd->RPort,2);
   Text(SysWnd->RPort,percentstr, strlen((char *)percentstr));

   SetAPen(SysWnd->RPort,3);
*/
   if (Flags.fastmode)
      WaitTOF();

   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)
{
   struct List *list = &ListeLVList;
   struct Node *head = list->lh_Head,
               *node = &(Entries[i].se_Node);
   BOOL  ins = FALSE;
   UWORD gadpos;

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

   if (Flags.sortmode && sort_in && head && node->ln_Name)
      AddNodeSorted(list, node);
   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)
{
   register int i;

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

   return;
}

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

   DPOS;

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

   *(ret + i) = STRINGEND;

   return (ret);
}

   /*
    * 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, struct Node *node, int cnt, int type)
{
   register int i = 0;

   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
    */
struct Node *
GetNode(struct List *list, ULONG offset)
{
   struct Node *Node;
   LONG  i;

   DPOS;

   Node = (struct 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)
{
   struct FileInfoBlock *FileInfo;
   LONG  FileSize = 0L;

   DPOS;

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

   if (FileInfo = (struct 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)
{
   struct ExAllControl *eac;
   struct ExAllData *EAData,
        *ead;
   int   cnt = 0,
         more;

   DPOS;

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

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

      if(EAData)
      {
         do
         {
            more = ExAll(lock, EAData, 512 * 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 (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(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
    */
ScrollEntry *
AllocScrollEntries(int count)
{
   register int i;
   static int memcounter = 0;

   DPOS;

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

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

         memcounter = count;

         return (Entries);
      }
   }
   else
      return (Entries);

   return (NULL);
}

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

   return (((struct 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;
   register int i;
   register struct InfoData *ID = NULL;
   union
   {
      LONG  dostype;
      char  dostypestr[5];
   }     convert;

   DPOS;

   if (ID = (struct InfoData *) MyAllocVec(sizeof(struct 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;
   UBYTE *answer = (UBYTE *)(Flags.wb_start ? "Yes|Iconify|No" : "Yes|No");
   DPOS;

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

   switch (check)
   {
      case 1:
         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(struct 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 die ActionList ein
    */
void
OpenLibs(void)
{
   DPOS;

   IntuitionBase = (struct IntuitionBase *)OpenLibrary((UBYTE *) "intuition.library", 36);
   WorkbenchBase = (struct WorkbenchBase *)OpenLibrary((UBYTE *) "workbench.library", 36);
   GfxBase       = (struct 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(LIBRARY_ERR, OPEN_FAIL, KILL);

   InstallBroker();
   BuildActionList();

   return;
}

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

   MyFreeVec(Actions);

   RemoveBroker();

   CloseLibrary(IconBase);
   CloseLibrary(CxBase);
   CloseLibrary(DiskfontBase);
   CloseLibrary(UtilityBase);
   CloseLibrary(GadToolsBase);
   CloseLibrary((struct Library *) GfxBase);
   CloseLibrary((struct Library *) WorkbenchBase);
   CloseLibrary((struct Library *) IntuitionBase);

   return;
}

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

   if (Flags.speakmode)
      RemoveSpeech();

   if (appicon)
      RemoveAppIcon(appicon);

   MyFreeVec(Entries);

   KillList();

   if (SysIdPort)
      DeletePort(SysIdPort);

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

   CloseDownScreen();

   CloseLibs();

   MyFreeVec(RSysName);

   RemoveTrapHandlers();

   exit(0);
}
