/*
 * config.c   V1.4
 *
 * configuration file handling
 *
 * (c) 1991 by Stefan Becker
 *
 */
#include "ToolManager.h"

/* Tool type keywords in the configuration file, must end with a ':'!! */
static char IconKey[]="ICON:";
static char DummyKey[]="DUMMY:";
static char CLIKey[]="CLI:";
static char WBKey[]="WB:";
#define CONFIGBLOCKEND '#'

/* Config entry keywords */
static char AssignKey[]=" = ";
char AliasKey[]="Alias   ";
char RealKey[]="RealName";
char DirKey[]="WorkDir ";
char MenuKey[]="Menu    ";
char HotKKey[]="HotKey  ";
char StackKey[]="Stack   ";
static char ArgsKey[]="Args    ";
char ITypeKey[]="IconType";
char IFileKey[]="IconFile";
static char IPosKey[]="IconPos ";
static char OffKey[]="OFF";
char BrushKey[]="Brush";
char DObjKey[]="Icon";

/* miscellaneous */
extern char *ConfigName;
struct Library *AslBase;                     /* Library for file requester */
static char ReqTitle[]="Save Configuration"; /* file requester title */

/* Data for syntax error requester */
static struct EasyStruct SyntaxErrES={sizeof(struct EasyStruct),0,MyName,
                                      "Syntax error in configuration file\n"\
                                      "%s, line %ld\n'%s'","Ok"};

/* Set the name of the config file */
void SetConfigFileName(char *s)
{
 if (ConfigName) free(ConfigName);
 ConfigName=strdup(s);
}

/* Init a config block struct */
void InitConfigBlock(struct ConfigBlock *cb)
{
 cb->cb_Type=255;
 cb->cb_Flags=TNFLAGS_MENU|TNFLAGS_DOBJ;
 cb->cb_Stack=STACKMIN;
 cb->cb_IconX=NO_ICON_POSITION;
 cb->cb_IconY=NO_ICON_POSITION;
 cb->cb_Alias[0]='\0';
 cb->cb_Alias[BUFLEN-1]='\0';
 cb->cb_RealName[0]='\0';
 cb->cb_RealName[BUFLEN-1]='\0';
 cb->cb_WorkDir[0]='\0';
 cb->cb_WorkDir[BUFLEN-1]='\0';
 cb->cb_HotKey[0]='\0';
 cb->cb_HotKey[BUFLEN-1]='\0';
 cb->cb_IconFile[0]='\0';
 cb->cb_IconFile[BUFLEN-1]='\0';
}

/* Read one config file entry */
static void ReadConfigBlock(FILE *fh, struct ConfigBlock *cb, int *lines)
{
 register char *cp=cb->cb_TempLine;

 while (!feof(fh)) /* if not end of file, read one line into buffer */
  {
   (*lines)++;

   if (fgets(cp,BUFLEN+20,fh) && (strlen(cp)>1)) /* Skip empty lines */
    if (*cp==CONFIGBLOCKEND) return;             /* End of entry reached */
    else
     {
      register char *parm;

      /* Remove trailing newline */
      if (cp[strlen(cp)-1]=='\n') cp[strlen(cp)-1]='\0';

      /* Scan line for '=' */
      parm=strchr(cp,'=');

      /* Skip white space */
      if (parm)
       {
        parm++;
        while (*parm && isspace(*parm)) parm++;
       }

      /* Valid parameter? */
      if (!parm && !*parm)
       {
        /* No --> Syntax error */
        EasyRequest(NULL,&SyntaxErrES,NULL,ConfigName,*lines,cp);

        /* Next line */
        continue;
       }

      /* Extract parameter value */
      if (!strnicmp(cp,AliasKey,5))                  /* Alias    = <string> */
       strncpy(cb->cb_Alias,parm,BUFLEN-1);
      else if (!strnicmp(cp,RealKey,8))              /* RealName = <string> */
            strncpy(cb->cb_RealName,parm,BUFLEN-1);
      else if (!strnicmp(cp,DirKey,7))               /* WorkDir  = <string> */
            strncpy(cb->cb_WorkDir,parm,BUFLEN-1);
      else if (!strnicmp(cp,HotKKey,6))              /* HotKey   = <string> */
            strncpy(cb->cb_HotKey,parm,BUFLEN-1);
      else if (!strnicmp(cp,IFileKey,8))             /* IconFile = <string> */
            {
             cb->cb_Flags|=TNFLAGS_ICON;             /* Set icon flag */
             strncpy(cb->cb_IconFile,parm,BUFLEN-1);
            }
      else if (!strnicmp(cp,StackKey,5))             /* Stack    = <number> */
            {
             char *cp1;

             cb->cb_Stack=strtol(parm,&cp1,10);
            }
      else if (!strnicmp(cp,ArgsKey,4))              /* Args     = OFF */
            {
             if (!stricmp(parm,OffKey)) cb->cb_Flags|=TNFLAGS_NARG;
            }
      else if (!strnicmp(cp,MenuKey,4))              /* Menu     = OFF */
            {
             if (!stricmp(parm,OffKey)) cb->cb_Flags&=~TNFLAGS_MENU;
            }
      else if (!strnicmp(cp,ITypeKey,8))             /* IconType = Brush */
            {
             cb->cb_Flags|=TNFLAGS_ICON;             /* Set icon flag */
             if (!stricmp(parm,BrushKey)) cb->cb_Flags&=~TNFLAGS_DOBJ;
            }
      else if (!strnicmp(cp,IPosKey,7))              /* IconPos  = <x,y> */
            {
             char *cp1;

             cb->cb_Flags|=TNFLAGS_ICON;             /* Set icon flag */
             cb->cb_IconX=strtol(parm,&cp1,10);
             cb->cb_IconY=strtol(cp1+1,&cp1,10);
            }
      else                                           /* Unknown keyword */
       EasyRequest(NULL,&SyntaxErrES,NULL,ConfigName,*lines,cp);
     }
  }
}

/* Read configuration file */
void ReadConfigFile()
{
 struct ConfigBlock *cb;  /* Memory block for one config file entry */
 FILE *fh;                /* Filehandle for config file */
 int lines=0;             /* Line counter */

 if (cb=malloc(sizeof(struct ConfigBlock)))  /* Get memory */
  {
   register char *cp=cb->cb_TempLine;

   if (ConfigName && (fh=fopen(ConfigName,"r"))) /* Scan config file */
    {
     while (!feof(fh)) /* if not end of file, read one line into buffer */
      {
       lines++;

       if (fgets(cp,BUFLEN,fh) && (strlen(cp)>1)) /* Skip empty lines */
        {
         InitConfigBlock(cb);

         /* Extract tool type */
         if (!strnicmp(cp,IconKey,sizeof(IconKey)-1))        /* ICON: */
          {
           char *cp1;

           IconXPos=strtol(cp+sizeof(IconKey)-1,&cp1,10);
           IconYPos=strtol(cp1+1,&cp1,10);
          }
         else if (!strnicmp(cp,DummyKey,sizeof(DummyKey)-1)) /* DUMMY: */
          cb->cb_Type=TNTYPE_DUMMY;
         else if (!strnicmp(cp,CLIKey,sizeof(CLIKey)-1))     /* CLI: */
          cb->cb_Type=TNTYPE_CLI;
         else if (!strnicmp(cp,WBKey,sizeof(WBKey)-1))       /* WB: */
          cb->cb_Type=TNTYPE_WB;
         else                                                /* Syntax error */
          {
           /* Display error requester */
           EasyRequest(NULL,&SyntaxErrES,NULL,ConfigName,lines,cp);

           /* Try to skip to end of current block */
           while (!feof(fh))
            {
             lines++;
             fgets(cp,BUFLEN,fh);
             if (*cp==CONFIGBLOCKEND) break;
            }
          }

         /* Does a valid config block follow? */
         if (cb->cb_Type!=255)
          {
           /* Read in one config file entry */
           ReadConfigBlock(fh,cb,&lines);

           /* Special check for empty dummy tool entries */
           if ((cb->cb_Type==TNTYPE_DUMMY) && (cb->cb_Alias[0]=='\0') &&
               (cb->cb_RealName[0]=='\0'))
            strcpy(cb->cb_Alias," ");

           /* Add tool */
           AddToolNode(cb,StartupCD);
          }
        }
      }
     fclose(fh);
    }

   free(cb);
  }
}

/* Tiny long to string conversion routine */
static void ltoa(char *s, long n)
{
 long i=1000000000;     /* Divisor */
 BOOL inumber=FALSE;    /* Flag */

 if (n==-2147483648)    /* Handle special case 2^31*/
  {
   strcpy(s,"-2147483648");
   return;
  }

 if (n<0)               /* Handle negativ numbers */
  {
   n=-n;
   *s++='-';
  }

 if (n==0) *s++='0';    /* Zero is a special case */
 else while (i)         /* Every other numer goes here */
       {
        *s=n/i+'0';     /* Retrieve leading digit */
        if (*s!='0') inumber=TRUE; /* Suppress leading zero's */
        if (inumber) s++;
        n%=i;           /* Remove digit from number */
        i/=10;          /* next divisor */
       }

 *s='\0';               /* Append string terminator */
}

/* Write one parameter keyword */
static void WriteParamKey(char *cp, FILE *fh)
{
 fputs(cp,fh);        /* Write keyword */
 fputs(AssignKey,fh); /* Write " = " */
}

/* Write one complete config line */
static void WriteConfigLine(char *key, char *parm, FILE *fh)
{
 WriteParamKey(key,fh); /* Write keyword */
 fputs(parm,fh);        /* Write parameter */
 fputc('\n',fh);        /* Write newline */
}

/* Write configuration file */
void WriteConfigFile(struct Window *w)
{
 struct FileRequester *req;
 BOOL rc=TRUE;
 char dir[NAMELEN],file[NAMELEN],*cp;

 /* ConfigName was NOT set because of low mem situation --> break */
 if (!ConfigName) goto wce0;

 /* Open ASL library */
 if (!(AslBase=OpenLibrary(AslName,0))) goto wce0;

 /* Split file name */
 cp=FilePart(ConfigName);
 if (cp!=ConfigName) strncpy(dir,ConfigName,cp-ConfigName);
 dir[cp-ConfigName]='\0';
 strncpy(file,cp,NAMELEN);

 /* Alloc file requester structure */
 if (!(req=AllocAslRequestTags(ASL_FileRequest,ASL_Hail,ReqTitle,
                                               ASL_Window,w,
                                               ASL_LeftEdge,w->LeftEdge,
                                               ASL_TopEdge,w->TopEdge,
                                               ASL_Dir,dir,
                                               ASL_File,file,
                                               ASL_FuncFlags,FILF_SAVE,
                                               TAG_DONE)))
  goto wce1;

 /* Open file requester */
 if (AslRequest(req,NULL))
  if (*req->rf_File)                   /* Valid file name? */
   {
    FILE *fh;

    strncpy(dir,req->rf_Dir,NAMELEN);  /* Build complete name */
    AddPart(dir,req->rf_File,NAMELEN);
    SetConfigFileName(dir);

    if (fh=fopen(dir,"w"))             /* Open config file */
     {
      register struct ToolNode *tn;

      /* Write icon position line */
      if ((IconXPos!=NO_ICON_POSITION) || (IconYPos!=NO_ICON_POSITION))
       {
        fputs(IconKey,fh);
        ltoa(dir,IconXPos);
        fputs(dir,fh);
        fputc(',',fh);
        ltoa(dir,IconYPos);
        fputs(dir,fh);
        fputc('\n',fh);
       }

      for (tn=GetHead(&ToolList); tn; tn=GetSucc(tn))
       {
        /* Write tool type */
        switch(tn->tn_Type)
         {
          case TNTYPE_DUMMY:
           fputs(DummyKey,fh);
           break;
          case TNTYPE_CLI:
           fputs(CLIKey,fh);
           break;
          case TNTYPE_WB:
           fputs(WBKey,fh);
           break;
         }
        fputc('\n',fh);

        /* Write alias name */
        WriteConfigLine(AliasKey,tn->tn_Node.ln_Name,fh);

        /* Write real name */
        if (tn->tn_RealName)
         WriteConfigLine(RealKey,tn->tn_RealName,fh);

        /* Write working directory */
        if (tn->tn_WorkDir)
         WriteConfigLine(DirKey,tn->tn_WorkDir,fh);

        /* Write stack size */
        if (tn->tn_Stack>STACKMIN)
         {
          WriteParamKey(StackKey,fh);
          ltoa(dir,tn->tn_Stack);
          fputs(dir,fh);
          fputc('\n',fh);
         }

        /* Write argument passing state */
        if (tn->tn_Flags&TNFLAGS_NARG)
         WriteConfigLine(ArgsKey,OffKey,fh);

        /* Write menu entry status */
        if (!(tn->tn_Flags&TNFLAGS_MENU))
         WriteConfigLine(MenuKey,OffKey,fh);

        /* Write HotKey description */
        if (tn->tn_HotKey)
         WriteConfigLine(HotKKey,tn->tn_HotKey,fh);

        /* Write icon stuff */
        if (tn->tn_Flags&TNFLAGS_ICON)
         {
          if (!(tn->tn_Flags&TNFLAGS_DOBJ))
           WriteConfigLine(ITypeKey,BrushKey,fh);

          if (tn->tn_IconFile)
           WriteConfigLine(IFileKey,tn->tn_IconFile,fh);

          if ((tn->tn_Icon->do_CurrentX!=NO_ICON_POSITION) ||
              (tn->tn_Icon->do_CurrentY!=NO_ICON_POSITION))
           {
            WriteParamKey(IPosKey,fh);
            ltoa(dir,tn->tn_Icon->do_CurrentX);
            fputs(dir,fh);
            fputc(',',fh);
            ltoa(dir,tn->tn_Icon->do_CurrentY);
            fputs(dir,fh);
            fputc('\n',fh);
           }
         }

        fputc(CONFIGBLOCKEND,fh);     /* Append config entry terminator */
        fputc('\n',fh);               /* Append a new line */
       }

      fclose(fh);                      /* Close the config file */
      rc=FALSE;                        /* All OK */
     }
   }

wce2: FreeAslRequest(req);
wce1: CloseLibrary(AslBase);
wce0: if (rc) DisplayBeep(NULL);
}
