#include <exec/types.h>
#include <exec/memory.h>
#include <clib/dos_protos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __GNUC__
#include "../shared_defs.h"
#else
#include "/shared_defs.h"
#endif

static char rcsid [] = "$Id: ConvVMMCfg.c,v 3.3 95/12/16 19:05:04 Martin_Apel Rel $";

#define isspace(c) (((c)==' ') || ((c) == '\t') || ((c) == '\n'))

#define AT_LEAST_V1_1 ((Version > 1) || ((Version == 1) && (Revision >= 1)))
#define AT_LEAST_V1_2 ((Version > 1) || ((Version == 1) && (Revision >= 2)))
#define AT_LEAST_V1_3 ((Version > 1) || ((Version == 1) && (Revision >= 3)))
#define AT_LEAST_V2_0 (Version >= 2)
#define AT_LEAST_V2_1 ((Version > 2) || ((Version == 2) && (Revision >= 1)))

/* For version >= 1.1 the first two lines of the config file
 * show the version and revision
 * VERSION v
 * 'v' is the version number
 * REVISION r
 *
 * The next line of the config file is line stating the default value,
 * whether to use virtual memory by default: (<= V1.2)
 * DEFAULT     USE|NO_USE
 * From V1.3 the line contains the minimum values for PUBLIC and
 * non-PUBLIC allocations:
 * DEFAULT     <n1> <n2>
 *
 * Next comes a line to tell how much memory is to be used for paging
 * For versions <= V2.1 it looks like this:
 * MEM         <n>|DYNAMIC
 *
 * Next comes a line to determine whether the statistics task is to
 * to be started or not (<= V1.2)
 * STAT        USE|NO_USE
 * From V1.3 the line looks like this:
 * STAT        USE|NO_USE <z> <zl> <zt> <ul> <ut>
 * <z> is the zoomed state, <zl>... are the left and top edges for the
 * zoomed and unzoomed state.
 *
 * One line for the partition which should be used for paging INCLUDING
 * the terminating colon e.g. DH2:
 * PART        <name>
 * Instead of the last line the following two lines are possible
 * FILE        <name>
 * FILESIZE    <bytes>
 * From V2.0 the keyword FILE may be replaced by PSEUDOPART to indicate
 * usage of a pseudo-partition
 *
 * One line for the priority of the new memlist for virtual memory
 * MEM_PRI     <n>
 *
 * From V1.1 upward here follows a line describing the flags to
 * use for allocation of page frames
 * MEM_FLAGS   <n>
 *
 * From V1.1 upward here follows a line stating whether to cache
 * Zorro II RAM or not.
 * Z2NO_CACHE  USE|NO_USE
 *
 * From V2.0 upward there follow four additional lines:
 * For early beta versions of 2.0 the first entry is missing:
 *
 * WBPATCH     USE|NO_USE
 * MIN_VM_ALLOC <n>
 * ENABLE_HOTKEY <string>
 * DISABLE_HOTKEY <string>
 *
 * For V2.1 there follows the size of the write buffer in bytes
 * WRITE_BUFFER <n>
 *
 * Then there is an unknown number of lines which state for certain
 * tasks if they should be granted virtual memory (<= V1.2)
 * TASK   "task_name"    USE|NO_USE
 * From V1.3 the line contains the minimum values for PUBLIC and
 * non-PUBLIC allocations:
 * TASK   "task_name"    <n1> <n2>
 *
 * That's it, for now
 */

#define CFG_FIRST_LINE_V1_0  \
    "DON'T EDIT !!! THIS FILE IS AUTOMATICALLY GENERATED.\n"

#define CFG_FIRST_LINE_FROM_1_1 \
    "VMM40 CONFIGURATION. DON'T EDIT !!! FILE GENERATED AUTOMATICALLY.\n"

char *UseString = "USE";
char *LargestString = "LARGEST";
char *DynamicString = "DYNAMIC";

struct VMMConfig NewConfig =
  {
  CFG_MAGIC,                            /* CfgMagic              */
  3,                                    /* Version               */
  0,                                    /* Revision              */
  DYN_MIN,                              /* MinMem                */
  DYN_MAX,                              /* MaxMem                */
  100 * 1024,                           /* WriteBuffer           */
  40,                                   /* VMPriority            */
  MEMF_FAST | MEMF_PUBLIC,              /* MemFlags              */
  1,                                    /* FileSize              */
  DEFAULT_MINVMSIZE,                    /* MinVMAlloc            */
  0,                                    /* ZLeftEdge             */
  0,                                    /* ZTopEdge              */
  0,                                    /* UnZLeftEdge           */
  0,                                    /* UnZTopEdge            */
  USE_NEVER,                            /* DefaultMinPublic      */
  USE_ALWAYS,                           /* DefaultMinNonPublic   */
  0,                                    /* NumTaskEntries        */
  PD_FILE,                              /* PageDev               */
  DEFAULT_ENABLE_KEY,                   /* EnableHotkey          */
  DEFAULT_DISABLE_KEY,                  /* DisableHotkey         */
  "SYS:page_file",                      /* PartOrFileName        */
  TRUE,                                 /* StatEnabled           */
  FALSE,                                /* StatZoomed            */
  FALSE,                                /* MemTracking           */
  FALSE,                                /* PatchWB               */
  TRUE,                                 /* CacheZ2RAM            */
  CNOSWAP,                              /* DefaultCodePaging     */
  DP_TRUE                               /* DefaultDataPaging     */
  };
  

/************************************************************************/

#define isspace(c) (((c)==' ') || ((c) == '\t') || ((c) == '\n'))

void GetNthString (char *from, char *to, int n)

{
/* Extracts the nth string in the line "from" and copies it to "to".
 * If the nth string does not exist 'to' is set to an empty string.
 */
char *tmp1, *tmp2;

tmp1 = from;
tmp2 = to;
while (*tmp1 != 0 && isspace (*tmp1)) tmp1++;    /* skip leading whitespace */

while (--n > 0)
  {
  while (*tmp1 != 0 && !isspace (*tmp1)) tmp1++; /* skip word */
  while (*tmp1 != 0 &&  isspace (*tmp1)) tmp1++; /* skip blanks */
  }

while (*tmp1 != 0 && !isspace(*tmp1)) *tmp2++ = *tmp1++;
*tmp2 = 0;
}

/***********************************************************************/

static UWORD val_to_dp_type (ULONG MinPublic, ULONG MinNonPublic)

/* Converts MinPublic and MinNonPublic values into the type of data paging
 * used.
 */
{
if (MinPublic != USE_NEVER)
  return (DP_ADVANCED);
else if (MinNonPublic == USE_NEVER)
  return (DP_FALSE);
else if (MinNonPublic == USE_ALWAYS)
  return (DP_TRUE);
else
  return (DP_ADVANCED);
}

/************************************************************************/

BOOL Convert (char *filename)

{
char buffer [200],
     line [200];
char converted_filename [200];
char *tmp;
ULONG Version,
      Revision;
ULONG NumEntries = 0;
struct OldTaskEntryInFile te;

BPTR old_cfg_file,
     new_cfg_file;

if ((old_cfg_file = Open (filename, MODE_OLDFILE)) == NULL)
  return (FALSE);

strcpy (converted_filename, filename);
strcat (converted_filename, ".new");

line [0] = 0;
FGets (old_cfg_file, line, 200 - 1);
if (strcmp (line, CFG_FIRST_LINE_V1_0) == 0)
  {
  Version = 1;
  Revision = 0;
  }
else if (strcmp (line, CFG_FIRST_LINE_FROM_1_1) == 0)
  {
  FGets (old_cfg_file, line, 200 - 1);
  GetNthString (line, buffer, 2);
  StrToLong (buffer, (LONG*)&Version);
  FGets (old_cfg_file, line, 200 - 1);
  GetNthString (line, buffer, 2);
  StrToLong (buffer, (LONG*)&Revision);
  }
else
  {
  Close (old_cfg_file);
  return (FALSE);
  }

if ((new_cfg_file = Open (converted_filename, MODE_NEWFILE)) == NULL)
  {
  Close (old_cfg_file);
  return (FALSE);
  }

FGets (old_cfg_file, line, 200 - 1);               /* "DEFAULT" line */
GetNthString (line, buffer, 2);

if (AT_LEAST_V1_3)
  {
  StrToLong (buffer, (LONG*)&(NewConfig.DefaultMinPublic));
  GetNthString (line, buffer, 3);
  StrToLong (buffer, (LONG*)&(NewConfig.DefaultMinNonPublic));
  NewConfig.DefaultDataPaging = val_to_dp_type (NewConfig.DefaultMinPublic,
                                   NewConfig.DefaultMinNonPublic);
  }

FGets (old_cfg_file, line, 200 - 1);
GetNthString (line, buffer, 2);          /* "MEM" line */
if ((strcmp (buffer, LargestString) == 0) ||
    (strcmp (buffer, DynamicString) == 0))
  {
  NewConfig.MinMem = DYN_MIN;
  NewConfig.MaxMem = DYN_MAX;
  }
else
  {
  StrToLong (buffer,  (LONG*)&(NewConfig.MinMem));
  NewConfig.MaxMem = NewConfig.MinMem;
  }

FGets (old_cfg_file, line, 200 - 1);
GetNthString (line, buffer, 2);
NewConfig.StatEnabled = (strcmp (buffer, UseString) == 0);

if (AT_LEAST_V1_3)
  {
  GetNthString (line, buffer, 3);
  NewConfig.StatZoomed = (*buffer == '1');
  GetNthString (line, buffer, 4);
  StrToLong (buffer, (LONG*)&(NewConfig.ZLeftEdge));
  GetNthString (line, buffer, 5);
  StrToLong (buffer, (LONG*)&(NewConfig.ZTopEdge));
  GetNthString (line, buffer, 6);
  StrToLong (buffer, (LONG*)&(NewConfig.UnZLeftEdge));
  GetNthString (line, buffer, 7);
  StrToLong (buffer, (LONG*)&(NewConfig.UnZTopEdge));
  }

FGets (old_cfg_file, line, 200 - 1);
if (strncmp (line, "PART", 4) == 0)
  {
  NewConfig.PageDev = PD_PART;
  GetNthString (line, NewConfig.PartOrFileName, 2);

  if ((tmp = strchr (NewConfig.PartOrFileName, ':')) == NULL)
    strcat (NewConfig.PartOrFileName, ":");
  }
else
  {
  /* It's paging to a file */
  if (strncmp (line, "FILE", 4) == 0)
    NewConfig.PageDev = PD_FILE;
  else
    {
    NewConfig.PageDev = PD_PSEUDOPART;
    }

  GetNthString (line, NewConfig.PartOrFileName, 2);

  /* Next line contains the size */
  FGets (old_cfg_file, line, 200 - 1);
  GetNthString (line, buffer, 2);
  StrToLong (buffer, (LONG*)&(NewConfig.FileSize));
  NewConfig.FileSize /= 1024 * 1024;         /* in MByte */
  }

FGets (old_cfg_file, line, 200 - 1);
GetNthString (line, buffer, 2);
StrToLong (buffer, (LONG*)&(NewConfig.VMPriority));

if (AT_LEAST_V1_1)
  {
  FGets (old_cfg_file, line, 200 - 1);
  GetNthString (line, buffer, 2);
  StrToLong (buffer, (LONG*)&(NewConfig.MemFlags));

  FGets (old_cfg_file, line, 200 - 1);
  GetNthString (line, buffer, 2);
  NewConfig.CacheZ2RAM = (strcmp (buffer, UseString) != 0);
  }

if (AT_LEAST_V2_0)
  {
  FGets (old_cfg_file, line, 200 - 1);
  if (strncmp (line, "WBPATCH", 7) == 0)
    {
    GetNthString (line, buffer, 2);
    NewConfig.PatchWB = (strcmp (buffer, UseString) == 0);
    FGets (old_cfg_file, line, 200 - 1);
    }

  GetNthString (line, buffer, 2);
  StrToLong (buffer, (LONG*)&(NewConfig.MinVMAlloc));

  FGets (old_cfg_file, line, 200 - 1);
  tmp = line;
  while (*tmp != 0 && !isspace (*tmp)) tmp++;
  while (*tmp != 0 && isspace (*tmp)) tmp++;
  strcpy (NewConfig.EnableHotkey, tmp);
  if ((tmp = strchr (NewConfig.EnableHotkey, '\n')) != NULL)
    *tmp = 0;

  FGets (old_cfg_file, line, 200 - 1);
  tmp = line;
  while (*tmp != 0 && !isspace (*tmp)) tmp++;
  while (*tmp != 0 && isspace (*tmp)) tmp++;
  strcpy (NewConfig.DisableHotkey, tmp);
  if ((tmp = strchr (NewConfig.DisableHotkey, '\n')) != NULL)
    *tmp = 0;
  }

if (AT_LEAST_V2_1)
  {
  FGets (old_cfg_file, line, 200 - 1);
  GetNthString (line, buffer, 2);
  StrToLong (buffer, (LONG*)&(NewConfig.WriteBuffer));
  }

Write (new_cfg_file, &NewConfig, sizeof (struct VMMConfig));

te.CodePaging = FALSE;
te.IsDefault = FALSE;

while (FGets (old_cfg_file, line, 200 - 1) != NULL)
  {
  char *task_name;

  tmp = &(line [0]);
  while (*tmp != '"') tmp++;
  task_name = ++tmp;
  while (*tmp != '"') tmp++;
  *tmp++ = 0;
  strncpy (te.TaskName, task_name, 39);

  while (isspace(*tmp)) tmp++;
  if (AT_LEAST_V1_3)
    {
    GetNthString (tmp, buffer, 1);
    StrToLong (buffer, (LONG*)&(te.MinPublic));
    GetNthString (tmp, buffer, 2);
    StrToLong (buffer, (LONG*)&(te.MinNonPublic));
    }
  else
    {
    te.MinPublic = USE_NEVER;
    if (strncmp (tmp, UseString, strlen (UseString)) == 0)
      te.MinNonPublic = USE_ALWAYS;
    else
      te.MinNonPublic = USE_NEVER;
    }
  te.DataPaging = val_to_dp_type (te.MinPublic, te.MinNonPublic);

  NumEntries++;

  Write (new_cfg_file, &te, sizeof (struct OldTaskEntryInFile));  
  }

#define OFFSET(x) ((ULONG)&(((struct VMMConfig*)NULL)->x))

Seek (new_cfg_file, OFFSET(NumTaskEntries), OFFSET_BEGINNING);

Write (new_cfg_file, &NumEntries, sizeof (ULONG));

Close (old_cfg_file);
Close (new_cfg_file);

DeleteFile (filename);
Rename (converted_filename, filename);

return (TRUE);
}

/***********************************************************************/

void main (void)

{
if (!Convert ("ENVARC:" CFG_FILEBASE))
  printf ("Couldn't convert " CFG_FILEBASE " in ENVARC:\n");

if (!Convert ("ENV:" CFG_FILEBASE))
  printf ("Couldn't convert " CFG_FILEBASE " in ENV:\n");

printf (PROGNAME " configuration file converted successfully\n");
}
