/*
***************************************************************************
*
* Datei:
*    RSysInitData.c
*
* Inhalt:
*
*      --- Globale Routinen ---
*
*    int ChooseNewFile ( char *oldfile , char *header );
*    ValidMemoryNode *CheckNode ( ULONG memoryptr );
*    void BuildAllDataEntries ( void );
*    void BuildHardwareList ( void );
*    void BuildHelpList ( void );
*    void BuildLibOffsetList ( void );
*    void BuildValidAddressList ( void );
*    void FreeAmigaGuideContextMemory ( void );
*    void FreeHardwareData ( void );
*    void FreeLibOffData ( void );
*    void FreeValidAddressList ( void );
*    void SaveConfig ( void );
*
*      --- Lokale  Routinen ---
*
*    static int AllocLineBuffer ( void );
*    static int MarkAddress ( ULONG start , ULONG length , char type , char *comment );
*    static int ReadCompanies ( BPTR hfile );
*    static int ReadContextFile ( UBYTE *filename );
*    static int ReadHardwareData ( BPTR hfile );
*    static int ReadLibOff ( BPTR lofile );
*    static int SplitFunction ( char *data , FUNCTION *func , LIBRARY *lib );
*    static STRPTR CheckHardwareEntry ( STRPTR buffer , int *type );
*    static STRPTR CheckLibOffEntry ( STRPTR buffer , int *type );
*    static UBYTE *myFGets ( BPTR file , STRPTR buffer , long size );
*    static void FreeLineBuffer ( void );
*
* Bemerkungen:
*    Enthält die Routinen zur Initialisierung der externen Daten.
*
* Erstellungsdatum:
*    20-Jul-93    Rolf Böhme
*
* Änderungen:
*    20-Jul-93    Rolf Böhme    Erstellung
*
***************************************************************************
*/

#include "RSys.h"
/*#include "I.c"*/

static struct Remember *HWKey = NULL;
static struct Remember *LOKey = NULL;
static struct Remember *VMKey = NULL;
static struct Remember *ContextKey = NULL;

char **company_str;

struct Manufacturer *manu;

static char *datatype[]=
{
   "END", "MANUFACTURER", "PRODUCT", "TYPE", "NAME", "COMPANY", "UNKNOWN"
};

static char *libofftype[]=
{
   "END", "LIBNAME", "TYP", "BASE", "FUNCTION"
};

UBYTE *context[MONITOR + 1];

int   hardwarecnt = 0;

struct List Libraries;
struct List ValidMemoryList;

static UBYTE *filebuffer;
#define MAXLINE 256

static int
AllocLineBuffer(void)
{
   if(filebuffer = MyAllocVec((MAXLINE+1) * sizeof(UBYTE), MEMF_CLEAR, NO_KILL))
      return TRUE;

   ErrorHandle("No file buffer for reading", MEMORY_ERR, ALLOC_FAIL, NO_KILL);

   return FALSE;
}

static void
FreeLineBuffer(void)
{
   MyFreeVec(filebuffer);

   return;
}

int
ChooseNewFile(char *oldfile, char *header)
{
   char dir[MAXFULLNAME], file[MAXFULLNAME];
/*
   char *dir = NULL,
        *file = NULL;
*/
   int   ok = TRUE;

   if (!SysWnd) return ok;

/*
   if ((dir = MyAllocVec(MAXFULLNAME, MEMF_CLEAR, NO_KILL)) &&
       (file = MyAllocVec(MAXFULLNAME, MEMF_CLEAR, NO_KILL)))
   {
*/
      strncpy(file, (char *)FilePart((STRPTR) oldfile), MAXFULLNAME);
      strncpy(dir, oldfile, (int)((ULONG) PathPart((STRPTR) oldfile) - (ULONG) oldfile));

      if (GetFile(SysWnd, dir, file, "#?", header, "Load"))
         strncpy(oldfile, _fullpath, MAXFULLNAME);
      else ok = FALSE;
/*
   }
   else
   {
      ok = FALSE;
      ErrorHandle(oldfile, MEMORY_ERR, ALLOC_FAIL, NO_KILL);
   }

   MyFreeVec(file);
   MyFreeVec(dir);
*/

   return ok;
}


void
FreeHardwareData(void)
{
   FreeRemember(HWKEY, TRUE);
   return;
}

static UBYTE *
myFGets(BPTR file, STRPTR buffer, long size)
{
   UBYTE *retval = (UBYTE *) NULL;
   char *nlpos;

   retval = FGets(file, buffer, size);

   if (retval && (nlpos = strchr((char *)retval, '\n'))) *nlpos = STRINGEND;

   while (retval && strchr(";#\f\t\0", (int)(*retval)))
   {
      retval = FGets(file, buffer, size);

      if (retval && (nlpos = strchr((char *)retval, '\n'))) *nlpos = STRINGEND;
   }

   return retval;
}

static int
ReadCompanies(BPTR hfile)
{
   UBYTE *check;
   int   count,
         loop = 0;

   check = myFGets(hfile, filebuffer, MAXLINE);
   if (check)
   {
      count = atoi((char *)check);

      if (count == 0)
         return FALSE;

      if (company_str = (char **)ALLOCHW(count * sizeof(char *)))
      {
         check = myFGets(hfile, filebuffer, MAXLINE);

         while ((loop < count) && check)
         {
            if (*check)
            {
               company_str[loop] = ALLOCHW(strlen((char *)check) + 1);

               if (!company_str[loop]) return FALSE;

               strcpy(company_str[loop++], (char *)check);
            }

            if (loop < count) check = myFGets(hfile, filebuffer, MAXLINE);
         }

         if ((loop < count) || (check == NULL)) return FALSE;

         return TRUE;
      }
   }

   return FALSE;
}

static STRPTR
CheckHardwareEntry(STRPTR buffer, int *type)
{
   char *eqpos = NULL;
   int   i;

   *type = END;

   if (!strcmp((char *)buffer, datatype[END]))
      return (STRPTR) eqpos;

   *type = UNKNOWN;

   for (i = MANU_NR; i < UNKNOWN; i++)
      if (!strncmp((char *)buffer, datatype[i], strlen(datatype[i])))
      {
         eqpos = strchr((char *)buffer, '\=');

         eqpos++;

         while (*eqpos == ' ')
            eqpos++;

         *type = i;

         return (STRPTR) eqpos;
      }

   return (STRPTR) eqpos;
}

static int
ReadHardwareData(BPTR hfile)
{
   UBYTE *check,
         *data;
   int   count = 0,
         loop = 0;
   int   type,
         err;

   check = myFGets(hfile, filebuffer, MAXLINE);
   if (check)
   {
      count = atoi((char *)check);

      hardwarecnt = count;

      if (count == 0)
         return FALSE;

      if (manu = ALLOCHW((count + 1) * sizeof(struct Manufacturer)))
      {
         err = FALSE;

         check = myFGets(hfile, filebuffer, MAXLINE);

         while (loop < count && check && !err)
         {
            data = CheckHardwareEntry(check, &type);

            switch (type)
            {
               case MANU_NR:
                  manu[loop].manu_nr = (WORD) atoi((char *)data);
                  break;

               case PROD_NR:
                  manu[loop].prod_nr = (WORD) atoi((char *)data);
                  break;

               case TYPE_NR:
                  manu[loop].type_nr = (WORD) atoi((char *)data);
                  break;

               case COMPANY:
                  manu[loop].company = atoi((char *)data);
                  break;

               case NAME_STR:
                  manu[loop].name = ALLOCHW(strlen((char *)data)+1);

                  if (manu[loop].name)
                     strcpy(manu[loop].name, (char *)data);
                  else
                  {
                     ErrorHandle((char *)data, MEMORY_ERR, ALLOC_FAIL, NO_KILL);
                     err = TRUE;
                  }
                  break;

               case END:
                  loop++;
                  break;

               default:
                  ErrorHandle((char *)check, DATA_ENTRY_ERR, TYPE_FAIL, NO_KILL);
                  break;
            }

            if (!err) check = myFGets(hfile, filebuffer, MAXLINE);
         }

         if (err || loop < count) return FALSE;

         return TRUE;
      }
      else
      {
         ErrorHandle((char *)RSysFiles.Hardware, MEMORY_ERR, ALLOC_FAIL, NO_KILL);
         return FALSE;
      }
   }

   return FALSE;
}

void
BuildHardwareList(void)
{
   int   ok;
   BPTR  hfile;

   DPOS;
   if (!ChooseNewFile((char *)RSysFiles.Hardware, "Select new Hardware data file..."))
      return;

   DPOS;
   if (Flags.dummy1) FreeHardwareData();

   DPOS;
   Flags.dummy1 = 0;

   DPOS;
   if (!exist((char *)RSysFiles.Hardware)) return;

   DPOS;
   if(!AllocLineBuffer()) return;

   DPOS;
   if (hfile = Open(RSysFiles.Hardware, MODE_OLDFILE))
   {
      PrintInfo("Read hardware datas...", SPEAK, NULL);

   DPOS;
      ok = ReadCompanies(hfile);
      if (ok)
      {
   DPOS;
         ok = ReadHardwareData(hfile);

         if (ok) Flags.dummy1 = 1;
         else
            ErrorHandle((char *)RSysFiles.Hardware, FILE_ERR, READ_FAIL, NO_KILL);
      }
      else ErrorHandle((char *)RSysFiles.Hardware, FILE_ERR, READ_FAIL, NO_KILL);

   DPOS;
      Close(hfile);

   DPOS;
      if (Flags.dummy1) PrintInfo("Hardware Datas updated", SPEAK, SEC);

   }
   else ErrorHandle((char *)RSysFiles.Hardware, FILE_ERR, OPEN_FAIL, NO_KILL);

   DPOS;
   FreeLineBuffer();

   DPOS;
   PrintStatistics();

   return;
}

void
FreeLibOffData(void)
{
   FreeRemember(LOKEY, TRUE);

   return;
}

static STRPTR
CheckLibOffEntry(STRPTR buffer, int *type)
{
   char *eqpos = NULL;
   int   i;

   *type = LO_END;

   if (!strcmp((char *)buffer, libofftype[LO_END]))
      return (STRPTR) eqpos;

   *type = LO_UNKNOWN;

   for (i = LO_LIBNAME; i <= LO_FUNCTION; i++)
      if (!strncmp((char *)buffer, libofftype[i], strlen(libofftype[i])))
      {
         eqpos = strchr((char *)buffer, '\=');

         eqpos++;

         while (*eqpos == ' ')
            eqpos++;

         *type = i;

         return (STRPTR) eqpos;
      }

   return (STRPTR) eqpos;
}

static int
SplitFunction(char *data, FUNCTION * func, LIBRARY * lib)
{
   char  f[BUFSIZE],
         b[5],
        *dptr = data;
   int   fc = 0,
         bc = 0,
         dc = 0,
         public,
         ok = TRUE;

   while ((fc < BUFSIZE - 1) && (((f[fc++] = *(dptr++))) != ',')) ;
   f[fc - 1] = STRINGEND;

   while ((bc < 5) && ((b[bc++] = (char)(*(dptr++))) != ',')) ;
   b[bc - 1] = STRINGEND;

   public = atoi(dptr);

   if (!(func->f_name = ALLOCLO(strlen(f) + 1)))
      ok = FALSE;
   else
   {
      strcpy(func->f_name, f);
      func->f_bias = atoi(b);
      func->f_public = (char)((public == 1) ? 1 : 0);

      AddTail(&(lib->l_functions), &(func->f_node));
   }

   return ok;
}

static int
ReadLibOff(BPTR lofile)
{
   UBYTE *check,
         *data;
   int   ok = TRUE;
   FUNCTION *func = NULL;
   LIBRARY *lib = NULL;
   int   type;

   check = myFGets(lofile, filebuffer, MAXLINE);
   while (check && ok != FALSE)
   {
      data = CheckLibOffEntry(check, &type);

      switch (type)
      {
         case LO_END:
            AddTail(&Libraries, &(lib->l_node));
            break;

         case LO_LIBNAME:
            lib = ALLOCLO(sizeof(LIBRARY));

            if (!lib)
               ok = FALSE;
            else
            {
               NewList(&(lib->l_functions));

               lib->l_name = ALLOCLO(strlen((char *)data) + 1);

               if (!lib->l_name)
                  ok = FALSE;
               else
               {
                  strcpy((char *)lib->l_name, (char *)data);
                  lib->l_node.ln_Name = (char *)lib->l_name;
               }
            }
            break;

         case LO_TYP:
            lib->l_typ = (*data == 'L') ? 1 : 0;
            break;

         case LO_BASE:
            lib->l_base = ALLOCLO(strlen((char *)data) + 1);

            if (!lib->l_base)
               ok = FALSE;
            else
               strcpy(lib->l_base, (char *)data);
            break;

         case LO_FUNCTION:
            func = ALLOCLO(sizeof(LIBRARY));

            if (func)
               ok = SplitFunction((char *)data, func, lib);
            else
               ok = FALSE;
            break;

         default:
            ErrorHandle((char *)check, DATA_ENTRY_ERR, TYPE_FAIL, NO_KILL);
            break;
      }

      if (ok == TRUE) check = myFGets(lofile, filebuffer, MAXLINE);
      else
         ErrorHandle((char *)RSysFiles.LibOffsets, FILE_ERR, READ_FAIL, NO_KILL);
   }

   return ok;
}

void
BuildLibOffsetList(void)
{
   int   ok;
   BPTR  lofile;

   if (!ChooseNewFile((char *)RSysFiles.LibOffsets, "Select new Library offsets file..."))
      return;

   if (Flags.dummy2) FreeLibOffData();

   NewList(&Libraries);

   Flags.dummy2 = 0;

   if(!exist((char *)RSysFiles.LibOffsets)) return;

   if(!AllocLineBuffer()) return;

   if (lofile = Open(RSysFiles.LibOffsets, MODE_OLDFILE))
   {
      PrintInfo("Read library offsets...", SPEAK, NULL);

      ok = ReadLibOff(lofile);
      if (ok == TRUE)
      {
         Flags.dummy2 = 1;
         PrintInfo("Library offsets updated", SPEAK, SEC);
      }
      else ErrorHandle((char *)RSysFiles.LibOffsets, FILE_ERR, READ_FAIL, NO_KILL);

      Close(lofile);
   }
   else ErrorHandle((char *)RSysFiles.LibOffsets, FILE_ERR, OPEN_FAIL, NO_KILL);

   FreeLineBuffer();

   PrintStatistics();

   return;
}

void
FreeAmigaGuideContextMemory(void)
{
   FreeRemember((struct Remember **) & ContextKey, TRUE);

   return;
}

static int
ReadContextFile(UBYTE * filename)
{
   BPTR  file;
   UBYTE *check;
   int   i = 0,
         noerror = TRUE,
         retval = TRUE;

   if (exist((char *)filename))
   {
      if (file = Open(filename, MODE_OLDFILE))
      {
         check = myFGets(file, filebuffer, MAXLINE);

         while ((i < MAXENTRY) && check && noerror)
         {
            if (context[i] = AllocRemember((struct Remember **) & ContextKey,
                                           strlen((char *)check) + 1,
                                           MEMF_CLEAR | MEMF_PUBLIC))
            {
               strcpy((char *)(context[i++]), (char *)check);

               check = myFGets(file, filebuffer, MAXLINE);
            }
            else noerror = FALSE;
         }

         Close(file);

         if (!noerror)
         {
            ErrorHandle("AGuide nodes", MEMORY_ERR, ALLOC_FAIL, NO_KILL);
            retval = FALSE;
         }

         if (!check && (i < MAXENTRY))
         {
            ErrorHandle((char *)filename, DATA_ENTRY_ERR, SIZE_FAIL, NO_KILL);
            retval = FALSE;
         }

         context[MAXENTRY] = (UBYTE *) NULL;

         return retval;
      }
      else ErrorHandle((char *)filename, FILE_ERR, OPEN_FAIL, NO_KILL);
   }

   return FALSE;
}

void
BuildHelpList(void)
{
   if (Flags.helpmode) return;

   if (!ChooseNewFile((char *)RSysFiles.Guide, "Select AGuide documentation...") ||
       !ChooseNewFile((char *)RSysFiles.GuideContext, "Select new Context nodes file..."))
      return;

   if (Flags.dummy3) FreeAmigaGuideContextMemory();

   Flags.dummy3 = 0;

   if(!AllocLineBuffer()) return;

   PrintInfo("Read context nodes...", SPEAK, NULL);

   if (!exist((char *)RSysFiles.GuideContext) || !ReadContextFile(RSysFiles.GuideContext))
   {
      if (SysWnd) OffMenu(SysWnd, FULLMENUNUM(0, 1, 0));

      Flags.nohelp = 1;
   }
   else
   {
      if (SysWnd) OnMenu(SysWnd, FULLMENUNUM(0, 1, 0));
      Flags.dummy3 = 1;

      PrintInfo("Context nodes updated", SPEAK, SEC);
   }

   FreeLineBuffer();

   PrintStatistics();

   return;
}

void
SaveConfig(void)
{
   register struct DiskObject *dop;
   char **NewToolTypes,
       **OldToolTypes;
   char *ToolTypes[]=
   {
      /* 00 */ "DONOTWAIT",

      /* 01 */ "CX_HOTKEY=",
      /* 02 */ "CX_CRYPT=",
      /* 03 */ "CX_FINDFILE=",
      /* 04 */ "CX_FORMAT=",
      /* 05 */ "CX_HUNKLIST=",
      /* 06 */ "CX_CRC=",
      /* 07 */ "CX_SAVEWINDOW=",
      /* 08 */ "CX_FILEREQUEST=",

      /* 09 */ "NOFASTMODE",
      /* 10 */ "NOSORT",
      /* 11 */ "WORKINGBAR",
      /* 12 */ "AUTOFRONT",
      /* 13 */ "MOUSEWINDOW",
      /* 14 */ "TOPAZFONT",
      /* 15 */ "NOSAVEASKING",
      /* 16 */ "NOAPPICON",

      /* 17 */ "BACKPATTERNCOL=",
      /* 18 */ "BACKGROUNDCOL=",
      /* 19 */ "BACKPATTERN=",
      /* 20 */ "DETAILPEN=",
      /* 21 */ "BLOCKPEN=",
      /* 22 */ "MENUPEN=",

      /* 23 */ "HARDWAREDATA=",
      /* 24 */ "LIBOFFDATA=",
      /* 25 */ "AGUIDEDOC=",
      /* 26 */ "AGUIDECONTEXT=",
      /* 27 */ "ACTIONFILE=",
      /* 28 */ "OUTWINDOW=",
      /* 29 */ "LISTHEIGHT=",

      /* 30 */ "TEXTFORMATTER",
      /* 31 */ "ICONX=",
      /* 32 */ "ICONY=",
      /* 33 */ NULL,
   };
   int   i;
   struct Remember *ToolTypeKey = NULL;

   if (dop = GetProgramIcon())
   {
      PrintInfo("Write Info file...", SPEAK, NULL);

      NewToolTypes = (char **)AllocRemember(&ToolTypeKey, 35 * sizeof(char *), MEMF_CLEAR | MEMF_PUBLIC);

      if (NewToolTypes)
      {
         for (i = 0; i < 33; i++)
         {
            NewToolTypes[i] = AllocRemember(&ToolTypeKey, 60, MEMF_CLEAR | MEMF_PUBLIC);
            if (!NewToolTypes[i])
            {
               FreeDiskObject(dop);
               FreeRemember(&ToolTypeKey, TRUE);
               ErrorHandle("AllocRemember()", MEMORY_ERR, ALLOC_FAIL, KILL);
            }
         }

         strcpy(NewToolTypes[0], ToolTypes[0]);

         for (i = 1; i < 9; i++)
            sprintf(NewToolTypes[i], "%s%s", ToolTypes[i], hotkey[i - 1]);

#define NEXT 9

         if (!Flags.fastmode)
            strcpy(NewToolTypes[NEXT + 0], ToolTypes[NEXT + 0]);
         else
            sprintf(NewToolTypes[NEXT + 0], "(%s)", ToolTypes[NEXT + 0]);

         if (!Flags.sortmode)
            strcpy(NewToolTypes[NEXT + 1], ToolTypes[NEXT + 1]);
         else
            sprintf(NewToolTypes[NEXT + 1], "(%s)", ToolTypes[NEXT + 1]);

         if (Flags.workingbar)
            strcpy(NewToolTypes[NEXT + 2], ToolTypes[NEXT + 2]);
         else
            sprintf(NewToolTypes[NEXT + 2], "(%s)", ToolTypes[NEXT + 2]);

         if (Flags.autofront)
            strcpy(NewToolTypes[NEXT + 3], ToolTypes[NEXT + 3]);
         else
            sprintf(NewToolTypes[NEXT + 3], "(%s)", ToolTypes[NEXT + 3]);

         if (Flags.mousewindow)
            strcpy(NewToolTypes[NEXT + 4], ToolTypes[NEXT + 4]);
         else
            sprintf(NewToolTypes[NEXT + 4], "(%s)", ToolTypes[NEXT + 4]);

         if (Flags.sysfont)
            strcpy(NewToolTypes[NEXT + 5], ToolTypes[NEXT + 5]);
         else
            sprintf(NewToolTypes[NEXT + 5], "(%s)", ToolTypes[NEXT + 5]);

         if (!Flags.saveasking)
            strcpy(NewToolTypes[NEXT + 6], ToolTypes[NEXT + 6]);
         else
            sprintf(NewToolTypes[NEXT + 6], "(%s)", ToolTypes[NEXT + 6]);

         if (!Flags.appicon)
            strcpy(NewToolTypes[NEXT + 7], ToolTypes[NEXT + 7]);
         else
            sprintf(NewToolTypes[NEXT + 7], "(%s)", ToolTypes[NEXT + 7]);

         if (bpc)
            sprintf(NewToolTypes[NEXT + 8], "%s%ld", ToolTypes[NEXT + 8], bpc);
         else
            sprintf(NewToolTypes[NEXT + 8], "(%s)", ToolTypes[NEXT + 8]);

         if (bgc)
            sprintf(NewToolTypes[NEXT + 9], "%s%ld", ToolTypes[NEXT + 9], bgc);
         else
            sprintf(NewToolTypes[NEXT + 9], "(%s)", ToolTypes[NEXT + 9]);

         if (bpp)
            sprintf(NewToolTypes[NEXT + 10], "%s%08lx", ToolTypes[NEXT + 10], bpp);
         else
            sprintf(NewToolTypes[NEXT + 10], "(%s)", ToolTypes[NEXT + 10]);

         if (winddetail)
            sprintf(NewToolTypes[NEXT + 11], "%s%ld", ToolTypes[NEXT + 11], winddetail);
         else
            sprintf(NewToolTypes[NEXT + 11], "(%s)", ToolTypes[NEXT + 11]);

         if (windblock)
            sprintf(NewToolTypes[NEXT + 12], "%s%ld", ToolTypes[NEXT + 12], windblock);
         else
            sprintf(NewToolTypes[NEXT + 12], "(%s)", ToolTypes[NEXT + 12]);

         if (menudetail)
            sprintf(NewToolTypes[NEXT + 13], "%s%ld", ToolTypes[NEXT + 13], menudetail);
         else
            sprintf(NewToolTypes[NEXT + 13], "(%s)", ToolTypes[NEXT + 13]);

         sprintf(NewToolTypes[NEXT + 14], "%s%s", ToolTypes[NEXT + 14], RSysFiles.Hardware);
         sprintf(NewToolTypes[NEXT + 15], "%s%s", ToolTypes[NEXT + 15], RSysFiles.LibOffsets);
         sprintf(NewToolTypes[NEXT + 16], "%s%s", ToolTypes[NEXT + 16], RSysFiles.Guide);
         sprintf(NewToolTypes[NEXT + 17], "%s%s", ToolTypes[NEXT + 17], RSysFiles.GuideContext);
         sprintf(NewToolTypes[NEXT + 18], "%s%s", ToolTypes[NEXT + 18], RSysFiles.ActionFile);
         sprintf(NewToolTypes[NEXT + 19], "%s%s", ToolTypes[NEXT + 19], autocon);

         sprintf(NewToolTypes[NEXT + 20], "%s%ld", ToolTypes[NEXT + 20], newlvh);

         if (!Flags.textformat)
            strcpy(NewToolTypes[NEXT + 21], ToolTypes[NEXT + 21]);
         else
            sprintf(NewToolTypes[NEXT + 21], "(%s)", ToolTypes[NEXT + 21]);

         if(iconx != NO_ICON_POSITION)
            sprintf(NewToolTypes[NEXT + 22], "%s%ld", ToolTypes[NEXT + 22], iconx);
         else
            sprintf(NewToolTypes[NEXT + 22], "(%s)", ToolTypes[NEXT + 22]);

         if(icony != NO_ICON_POSITION)
            sprintf(NewToolTypes[NEXT + 23], "%s%ld", ToolTypes[NEXT + 23], icony);
         else
            sprintf(NewToolTypes[NEXT + 23], "(%s)", ToolTypes[NEXT + 23]);

         NewToolTypes[NEXT + 24] = NULL;

         OldToolTypes = dop->do_ToolTypes;

         dop->do_ToolTypes = NewToolTypes;

         if (!PutDiskObject((STRPTR) RSysName, dop)) 
            ErrorHandle(RSysName, FILE_ERR, WRITE_FAIL, NO_KILL);
         else
         {
            dop->do_ToolTypes = OldToolTypes;

            FreeRemember(&ToolTypeKey, TRUE);

            PrintInfo("Info file written...", SPEAK, SEC);
         }
      }
      else
      {
         FreeDiskObject(dop);
         FreeRemember(&ToolTypeKey, TRUE);
         ErrorHandle("AllocRemember()", MEMORY_ERR, ALLOC_FAIL, KILL);
      }

      FreeDiskObject(dop);
   }

   PrintStatistics();

   return;
}

void
FreeValidAddressList(void)
{
   FreeRemember(VMKEY, TRUE);
   return;
}

ValidMemoryNode *
CheckNode(ULONG memoryptr)
{
   struct Node *node;
   ValidMemoryNode *vmnode;

   for (node = ValidMemoryList.lh_Head; node->ln_Succ; node = node->ln_Succ)
   {
      vmnode = (ValidMemoryNode *) node;
      if (vmnode->vm_startaddress <= memoryptr && memoryptr <= vmnode->vm_endaddress)
         return vmnode;
   }

   return NULL;
}

static int
MarkAddress(ULONG start, ULONG length, char type, char *comment)
{
   ValidMemoryNode *VMNode;

   if (VMNode = ALLOCVM(sizeof(ValidMemoryNode)))
   {
      VMNode->vm_node.ln_Type = NT_USER;
      VMNode->vm_node.ln_Pri = 0;

      VMNode->vm_startaddress = start;
      VMNode->vm_endaddress = start + length;
      VMNode->vm_type = type;

      strncpy(VMNode->vm_comment, comment, BUFSIZE);

      AddTail(&ValidMemoryList, &(VMNode->vm_node));

      return TRUE;
   }
   else ErrorHandle("ValidMemoryNode", MEMORY_ERR, ALLOC_FAIL, NO_KILL);

   return FALSE;
}

void
BuildValidAddressList(void)
{
   struct MemHeader *mem;
   int   ok;

   NewList(&ValidMemoryList);

   /*
    * Special case the first page of CHIP RAM
    */
   ok = MarkAddress(0, 0x1000, (char)NULL, "First page CHIP-RAM");

   /*
    * Map in the free memory
    */
   Forbid();

   mem = (struct MemHeader *) SysBase->MemList.lh_Head;
   while (mem->mh_Node.ln_Succ && ok)
   {
      ok = MarkAddress((ULONG) (mem->mh_Lower),
                       (ULONG) (mem->mh_Upper) - (ULONG) (mem->mh_Lower),
                       ((MEMF_CHIP & TypeOfMem(mem->mh_Lower)) ?
                        (char)(VALID) : (char)(CACHEABLE | VALID)),
                       "Memory list entry");

      mem = ok ? (struct MemHeader *) (mem->mh_Node.ln_Succ) : NULL;
   }

   Permit();

   /*
    * Map in the autoconfig boards
    */
   if (ok && (ExpansionBase = (struct ExpansionBase *)OpenLibrary((STRPTR) "expansion.library", 0)))
   {
      struct ConfigDev *cd = NULL;

      while ((cd = FindConfigDev(cd, (long)(-1L), (long)(-1L))) != NULL && ok)
      {
         /* Skip memory boards... */
         if (!(cd->cd_Rom.er_Type & ERTF_MEMLIST))
            ok = MarkAddress((ULONG) (cd->cd_BoardAddr),
                             cd->cd_BoardSize,
                             (char)VALID, "Expansion memory");
      }
      CloseLibrary((struct Library *)ExpansionBase);
   }

   /*
    * Now for the control areas...
    */
   if (ok) ok = MarkAddress(0x00BC0000, 0x00040000, (char)VALID, "Control area 1");
   if (ok) ok = MarkAddress(0x00D80000, 0x00080000, (char)VALID, "Control area 2");

   /*
    * and the ROM...
    */
   if (ok) ok = MarkAddress(0x00F80000, 0x00080000,
                    (char)(CACHEABLE | WRITEPROTECT), "ROM-address");

   /*
    * If the credit card resource, make the addresses valid...
    */
   if (ok && OpenResource((STRPTR) "card.resource"))
      ok = MarkAddress(0x00600000, 0x00440002, (char)VALID, "Card resource range");

   /*
    * If CD-based Amiga (CDTV, A570, etc.)
    */
   if (ok && FindResident((STRPTR)"cdstrap"))
   {
     ok = MarkAddress(0x00E00000,0x00080000,(char)VALID, "CDTV-RAM");
     if(ok) ok = MarkAddress(0x00B80000,0x00040000,(char)VALID, "CDTV-RAM");
   }

   /*
    * Check for ReKick/ZKick/KickIt
    */
   if (ok && ((((ULONG) (SysBase->LibNode.lib_Node.ln_Name)) >> 16) == 0x20))
      ok = MarkAddress((ULONG)0x00200000, (ULONG)0x00080000,
                       (char)(VALID | CACHEABLE | WRITEPROTECT),
                       "KickMem-range for ZKick");

   Flags.dummy4 = (ok ? 1 : 0);

   return;
}

void
BuildAllDataEntries(void)
{
   BuildActionList();
   BuildHelpList();
   BuildHardwareList();
   BuildLibOffsetList();

   return;
}
