/*
***************************************************************************
*
* 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 ( struct Window *wind , char *ask , int def );
*    int SizeOfDir ( BPTR lock , long *Size , int *Dirs );
*    long ahtoi ( char *String );
*    LONG Command ( struct Node *node , char *file );
*    long getdisktype ( BPTR lock );
*    long SizeOfFile ( char *Name );
*    ScrollEntry *AllocScrollEntries ( int count );
*    struct DiskObject *GetProgramIcon ( void );
*    struct Node *GetNode ( struct List *list , ULONG offset );
*    void *MyAllocVec ( unsigned long byteSize , unsigned long requirements , int kill );
*    void AddNodeSorted ( struct List *list , struct 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 , struct 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"

extern struct Library *IconBase;
long maxentries;

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

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

	while(c = *String)
	{
		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;
}

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((char *)cmd, TASK_ERR, CREATE_FAIL, NO_KILL);
		}
	}

	return result;
}

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

struct DiskObject *
GetProgramIcon(void)
{
	struct 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)
{
	extern int ReopenWindow;

	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(struct List *list, struct Node *node, int sortpos)
{
	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(&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)
{
	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;

	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 percent = (100 * curr) / countentries,
			xcurr = xmin + ((xmax-xmin) * curr) / countentries;
	UBYTE percentstr[5] = " ";

	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)
{
	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, 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)
{
	register 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)
{
	register 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, 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("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
	 */
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;
			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)
{
	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 && !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?");

	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 verschiedene Listen 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("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((struct Library *) GfxBase);
	CloseLibrary((struct Library *) WorkbenchBase);
	CloseLibrary((struct Library *) IntuitionBase);
	CloseLibrary((struct 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);
}
