/* ---------------------------------------------------------------------
   (c) ED 1998-2002
   Projet       : CLIB
   Fonction     : Gestionnaire de fichier de configuration
   Module       : INI
   Fichier      : INI.C
   Creation     : 04-09-1998
   Modification : 13-07-2002
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Journal

   0.0 du 04-09-1998 Creation
   1.0 du 07-09-1998 Version operationelle
   .                 - GetSz()
   .                 - GetDw()
   .                 - Cr2Sz()
   1.1 du 07-09-1998 Ajoute commentaire en fin de ligne 'x=y ; comment'
   1.2 du 24-11-1998 Parametres en constante
   1.3 du 16-12-1998 Supprime const dans sGET.par.sz.iLen
   1.4 du 18-12-1998 Rempace GetDw() par GetD() (plus sur...)
   1.5 du 12-01-1999 Mise au point (ligne vide dans le fichier)
   1.6 du 24-01-2001 Rempace GetDw() par Getul()
   1.7 du 13-07-2002 LCLint

   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This source file is not C++ but rather C. Please use a C-compiler
#endif

#include "ed/inc/ini.h"

#include "ed/inc/fic.h"
#include "ed/inc/str.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>

/* ---------------------------------------------------------------------
   Donnees publiques
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Constantes privees
   --------------------------------------------------------------------- */
#define MODULE "INI"
#define VER "1.7"
#define ID "INI Module \"C\" (c) ED 1998-2002"

typedef enum
{
   TYPE_SZ,
   TYPE_UL,
   TYPE_NB
}
eTYPE;

/* ---------------------------------------------------------------------
   Structures privees
   --------------------------------------------------------------------- */
typedef struct
{
   eTYPE eType;
   const char *fname;
   const char *ssection;
   const char *svar;
   union
   {
      struct
      {
         char *svalue;
         size_t len;
      }
      sz;
      struct
      {
         ulong *pvalue;
      }
      ul;
   }
   par;
}
sGET;

/* ---------------------------------------------------------------------
   Donnees privees
   --------------------------------------------------------------------- */

/* =====================================================================
   Fonctions privees
   ===================================================================== */

/* ---------------------------------------------------------------------
   get_num()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
static eINI_CR get_num (char const *const s, ulong * const pVal)
{
   eINI_CR cr;
   ulong val;

   if (sscanf (s, "%lui", &val) == 1)
   {
      cr = INI_CR_OK;
   }
   else
   {
      cr = INI_CR_VAL_ERR;
   }

   if (pVal)
   {
      *pVal = val;
   }

   return cr;
}

/* ---------------------------------------------------------------------
   get()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
static eINI_CR get (sGET * pGet)
{
   eINI_CR cr = INI_CR_SEC_INC;

   assert (pGet != NULL);
   assert (pGet->fname != NULL);

   if (FIC_exist (pGet->fname))
   {
      FILE *f = fopen (pGet->fname, "r");
      char sline[BUFSIZ];
      int SectionTrouve = 0;

      while ((cr == INI_CR_SEC_INC
              || cr == INI_CR_VAR_INC
             )
             && fgets (sline, (int) sizeof sline, f))
      {
         STR_DelBlanks (sline);
         switch (*sline)
         {
         case '\n':            /* ligne vide */
            break;

         case ';':             /* commentaire */
            break;

         case '[':             /* section */
            if (SectionTrouve == 0)
            {
               /* Chercher la section */
               char *const sDeb = sline + 1;
               char *const sFin = strchr (sDeb, ']');

               if (sFin)
               {
                  *sFin = 0;

                  /* Identifier la section */
                  if (strcmp (sDeb, pGet->ssection) == 0)
                  {
                     SectionTrouve = 1;
                     cr = INI_CR_VAR_INC;
                  }
               }
               else
               {
                  cr = INI_CR_SEC_ERR;  /* Erreur */
               }
            }
            else
            {
               SectionTrouve = 0;
            }
            break;

         default:

            if (SectionTrouve == 1)
            {
               /* Chercher la variable */
               char *sDeb = sline;
               char *sFin = strchr (sDeb, '=');

               if (sFin)
               {
                  *sFin = 0;

                  if (strcmp (sDeb, pGet->svar) == 0)
                  {
                     /* Recuperer la valeur */
                     sDeb = sFin + 1;
                     sFin = sDeb;

                     while (*sFin
                            && *sFin != '\n'
                            && *sFin != ';'
                        )
                     {
                        sFin++;
                     }

                     if (*sFin)
                     {
                        *sFin = 0;

                        switch (pGet->eType)
                        {
                        case TYPE_SZ:
                           *pGet->par.sz.svalue = 0;
                           strncat (pGet->par.sz.svalue, sDeb, pGet->par.sz.len - 1);
                           cr = INI_CR_OK;
                           break;

                        case TYPE_UL:
                           {
                              cr = get_num (sDeb, pGet->par.ul.pvalue);
                           }
                           break;

                        default:
                           assert (0);
                        }
                     }
                     else
                     {
                        cr = INI_CR_VAL_ERR;
                     }
                  }
               }                /* else */
            }
         }
      }
      fclose (f);
   }
   else
   {
      cr = INI_CR_FIC_INC;
   }
   return cr;
}

/* =====================================================================
   Fonctions publiques
   ===================================================================== */

/* ---------------------------------------------------------------------
   INI_sver()
   ---------------------------------------------------------------------
   Role : Retourne une chaine "Version"
   ---------------------------------------------------------------------
   E :
   S : Pointeur de chaine ASCIIZ
   --------------------------------------------------------------------- */
const char *INI_sver (void)
{
   return VER;
}

/* ---------------------------------------------------------------------
   INI_sid()
   ---------------------------------------------------------------------
   Role : Retourne une chaine "Identification"
   ---------------------------------------------------------------------
   E :
   S : Pointeur de chaine ASCIIZ
   --------------------------------------------------------------------- */
const char *INI_sid (void)
{
   return ID;
}

#if 0
/* ---------------------------------------------------------------------
   INI_init()
   ---------------------------------------------------------------------
   Role : Creation/Initialisation
   ---------------------------------------------------------------------
   E :
   S : Pointeur de donnees
   --------------------------------------------------------------------- */
sINI *INI_init (void)
{
   sINI *p = calloc (1, sizeof (sINI));
   assert (p != NULL);

   return p;
}

/* ---------------------------------------------------------------------
   INI_end()
   ---------------------------------------------------------------------
   Role : Suppression
   ---------------------------------------------------------------------
   E : Pointeur de donnees
   S :
   --------------------------------------------------------------------- */
void INI_end (sINI * p)
{
   assert (p != NULL);
   free (p);
}
#endif

/* ---------------------------------------------------------------------
   INI_GetSz()
   ---------------------------------------------------------------------
   Role : Recherche d'une variable dans un fichier de configuration
   ---------------------------------------------------------------------
   E : Fichier
   E : Section
   E : Variable
   E : Valeur lue
   E : Longueur max
   S : Trouve|Pas trouve|Erreur.
   Si 'pas trouve', la valeur initiale de la variable est conservee
   --------------------------------------------------------------------- */
eINI_CR INI_GetSz (const char *fname
                   ,const char *ssection
                   ,const char *svar
                   ,char *svalue
                   ,const size_t len)
{
   sGET Get;
   Get.eType = TYPE_SZ;
   Get.fname = fname;
   Get.ssection = ssection;
   Get.svar = svar;
   Get.par.sz.svalue = svalue;
   Get.par.sz.len = len;

   return get (&Get);
}

/* ---------------------------------------------------------------------
   INI_GetW()
   ---------------------------------------------------------------------
   Role : Recherche d'une variable numerique dans un fichier de
   configuration
   ---------------------------------------------------------------------
   E : Fichier
   E : Section
   E : Variable
   E : Ptr pour la valeur lue
   S : 0=Pas trouve 1=Trouve.
   Si 'pas trouve', la valeur initiale de la variable est conservee
   --------------------------------------------------------------------- */
eINI_CR INI_Getul (char const *fname
                   ,char const *ssection
                   ,char const *svar
                   ,ulong * pvalue
)
{
   sGET Get;
   Get.eType = TYPE_UL;
   Get.fname = fname;
   Get.ssection = ssection;
   Get.svar = svar;
   Get.par.ul.pvalue = pvalue;

   return get (&Get);

}

/* ---------------------------------------------------------------------
   INI_Cr2Sz()
   ---------------------------------------------------------------------
   Role : Retourne la chaine du code d'erreur
   ---------------------------------------------------------------------
   E : Erreur
   S : Chaine (ASCIIz)
   --------------------------------------------------------------------- */
char const *INI_Cr2Sz (eINI_CR cr)
{
   char const *sz;
   static char const *asz[] =
   {
#define ITEM(a,b) b,
#include "ed/inc/ini_err.itm"
#undef ITEM
   };
   assert (NELEM (asz) == INI_CR_NB);

   if (cr < INI_CR_NB)
   {
      sz = asz[cr];
   }
   else
   {
      sz = "Erreur inconnue !!!";
   }

   return sz;
}

#if 0
/* ---------------------------------------------------------------------
   INI_PutSz()
   ---------------------------------------------------------------------
   Role : Inscription d'une variable dans un fichier de configuration
   ---------------------------------------------------------------------
   E : Fichier
   E : Section
   E : Variable
   E : Valeur a ecrire
   --------------------------------------------------------------------- */
void INI_PutSz (char *fname, char *ssection, char *svar, char *svalue)
{
}
#endif

/* File generated by 'NEW.EXE' Ver 1.13 (c) ED 1998 */
