/* ---------------------------------------------------------------------
   (c) ED 1998-2005
   Projet       : CLIB
   Fonction     : Gestion des fichiers
   Module       : FIC
   Fichier      : FIC.C
   Creation     : 31-12-1998
   Modification : 02-05-2005
   --------------------------------------------------------------------- */

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

   1.10 du 02-05-2005 Amelioration portabilite
   .                  (Fonctions POSIX.1 fstat() au lieu de DOS)
   1.9 du 29-04-2005 Homogenisation des formats de dates.
   .                 Suppression de pseudo-trigaphs
   1.8 du 17-01-2005 Mise au point FIC_backup()
   1.7 du 05-03-2003 Amelioration de la gestion des erreurs dans FIC_copy()
   1.6 du 18-02-2003 Ajout de FIC_ext_is()
   1.5 du 12-01-2001 Ajout de FIC_scantext()
   1.4 du 05-10-2000 Amelioration FIC_copy()
   1.3 du 07-06-2000 Ajoute FIC_getline()
   1.2 du 20-04-2000 Ajoute FIC_backup()
   1.1 du 04-04-2000 Restrictions ANSI, compatibilite DJGPP
   1.0 du 31-12-1998 Mise au normes du module
   0.3 du 16-12-98 remplace _open() _close() par fopen() et fclose()

   0.2 du 27-10-98 Ajoute date et time
   0.1 du 10-10-98 Version operationelle

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

#include "ed/inc/fic.h"

#include "ed/inc/str.h"

#if defined (__BORLANDC__)
#include <sys/stat.h>
#elif defined (_MSC_VER)
#include <sys/stat.h>
#elif defined (__GNUC__) && !defined (__STRICT_ANSI__)
#include <sys/stat.h>
#else
#error this environment is not supported
#endif

#include "ed/inc/sys.h"
#include "ed/inc/sysalloc.h"

#include <errno.h>

/* public data ========================================================= */
/* macros ============================================================== */

#define MODULE "FIC"
#define VER "1.10"
#define ID MODULE " Module \"C\" (c) ED 1998-2005"

/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private data ======================================================== */
/* private functions =================================================== */
/* internal public data ================================================ */
/* internal public functions =========================================== */
/* entry points ======================================================== */

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

/* ---------------------------------------------------------------------
   FIC_serr()
   ---------------------------------------------------------------------
   Role : Retourne une chaine erreur
   ---------------------------------------------------------------------
   E :
   S : Pointeur de chaine ASCIIZ
   --------------------------------------------------------------------- */
char const *FIC_serr (eFIC_ERR const err)
{
   static const char *const asErr[] =
   {
#define ITEM(a) #a,
#include "ed/inc/fic_err.itm"
#undef ITEM
   };
   char const *s = NULL;

   if (err < FIC_ERR_NB)
   {
      s = asErr[err];
   }
   return s;
}

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

/* ---------------------------------------------------------------------
   FIC_exist()
   ---------------------------------------------------------------------
   Role : Teste la presence d'un fichier
   ---------------------------------------------------------------------
   E : Fichier
   S : 0=KO 1=OK
   --------------------------------------------------------------------- */
int FIC_exist (const char *const sfile)
{
   int cr = 1;

   ASSERT (sfile != NULL);
   {
      FILE *f = fopen (sfile, "r");
      if (f != NULL)
      {
         fclose (f);
      }
      else
      {
         cr = 0;
      }
   }
   return cr;
}

/* ---------------------------------------------------------------------
   FIC_load()
   ---------------------------------------------------------------------
   Role : Restauration binaire
   ---------------------------------------------------------------------
   E : Fichier
   S : 0=KO 1=OK
   --------------------------------------------------------------------- */
int FIC_load (const char *const sfile, void *p, size_t const n)
{
   int cr = 1;
   uchar *po = p;

   ASSERT (sfile != NULL);
   ASSERT (po != NULL);
   if (po)
   {
      FILE *f = fopen (sfile, "rb");
      if (f)
      {
         fread (po, n, 1, f);   /* Lecture bloc */

         fclose (f);
      }
      else
      {
         cr = 0;
      }
   }
   else
   {
      cr = 0;
   }
   return cr;
}

/* ---------------------------------------------------------------------
   FIC_save()
   ---------------------------------------------------------------------
   Role : Sauvegarde binaire
   ---------------------------------------------------------------------
   E : Fichier
   S :
   --------------------------------------------------------------------- */
void FIC_save (const char *const sfile, void *const p, size_t const n)
{
   ASSERT (sfile != NULL);
   ASSERT (p != NULL);

   {
      FILE *f = fopen (sfile, "wb");
      if (f)
      {
         fwrite (p, n, 1, f);
         fclose (f);
      }
   }
}

/* ---------------------------------------------------------------------
   FIC_copy()
   ---------------------------------------------------------------------
   Role : Duplication d'un fichier
   ---------------------------------------------------------------------
   E : Fichier source
   E : Fichier destination
   S :
   --------------------------------------------------------------------- */
int FIC_copy (const char *const s_src, const char *const s_des)
{
   int ret = EXIT_FAILURE;

   errno = 0;

   if (s_src != NULL && s_des != NULL)
   {
      FILE *const fps = fopen (s_src, "rb");
      if (fps != NULL)
      {
         FILE *const fpd = fopen (s_des, "wb");
         if (fpd != NULL)
         {
            int c;
            ret = EXIT_SUCCESS;

            while ((c = fgetc (fps)) != EOF)
            {
               int err = fputc (c, fpd);

               if (err == EOF)
               {
                  if (ferror (fpd))
                  {
                     fprintf (stderr, "Write error on %s\n", s_des);
                  }

                  if (errno != 0)
                  {
                     perror (s_des);
                  }
                  ret = EXIT_FAILURE;
                  break;
               }
            }
            fclose (fpd);
         }

         if (ferror (fps))
         {
            fprintf (stderr, "Read error on %s\n", s_src);
            ret = EXIT_FAILURE;
         }

         if (errno != 0)
         {
            perror (s_src);
            ret = EXIT_FAILURE;
         }

         fclose (fps);
      }
   }
   return ret;
}

#if (defined (__BORLANDC__) && !defined (__STDC__))  \
 || (defined (__GNUC__)	&& !defined (__STRICT_ANSI__)\
 || (defined (_MSC_VER))\
   )
/* ---------------------------------------------------------------------
   FIC_str_date()
   ---------------------------------------------------------------------
   Role : Recuperer une chaine "Date du fichier"
   ---------------------------------------------------------------------
   E : Fichier
   E : Chaine
   E : Longeur max de la chaine
   S :
   --------------------------------------------------------------------- */
void FIC_str_date (const char *const sfile
                   ,char *const s_date
                   ,size_t const size)
{
#define DEF "dd-mm-yyyy"

   if (s_date != NULL && size >= sizeof DEF)
   {
      FILE *f = fopen (sfile, "r");

      if (f != NULL)
      {
         /* WARNING : not ANSI (but POSIX.1) */
         struct stat sts;

         fstat (fileno (f), &sts);
         fclose (f);

         {
            struct tm t = *localtime (&sts.st_mtime);

            sprintf (s_date
                     ,"%02d-%02d-%04d"
                     ,t.tm_mday
                     ,t.tm_mon + 1
                     ,t.tm_year + 1900);

         }
      }
      else
      {
         strcpy (s_date, DEF);
      }
   }
#undef DEF
}

/* ---------------------------------------------------------------------
   FIC_str_time()
   ---------------------------------------------------------------------
   Role : Recuperer une chaine "Heure du fichier"
   ---------------------------------------------------------------------
   E : Fichier
   E : Chaine
   E : Longeur max de la chaine
   S :
   --------------------------------------------------------------------- */
void FIC_str_time (const char *const sfile
                   ,char *const s_time
                   ,size_t const size)
{
#define DEF "hh:mm:ss"
   if (s_time != NULL && size >= sizeof DEF)
   {
      FILE *f = fopen (sfile, "r");

      LIM_PTR (s_time, size);

      if (f != NULL)
      {
         /* WARNING : not ANSI (but POSIX.1) */
         struct stat sts;

         fstat (fileno (f), &sts);
         fclose (f);

         {
            struct tm t = *localtime (&sts.st_mtime);

            sprintf (s_time
                     ,"%02d:%02d:%02d"
                     ,t.tm_hour
                     ,t.tm_min
                     ,t.tm_sec);

         }
      }
      else
      {
         strcpy (s_time, DEF);
      }
   }
#undef DEF
}
#endif

/* ---------------------------------------------------------------------
   FIC_size ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I: file name
   O: size of the file in bytes
   --------------------------------------------------------------------- */
ulong FIC_size (char const *const fname)
{
   ulong size = 0;
   FILE *fp = fopen (fname, "rb");

   if (fp)
   {
      /* on va a la fin */
      if (fseek (fp, 0, SEEK_END) == 0)
      {

         /* on recupere l'offset a la fin du fichier */
         size = ftell (fp);

         if (ferror (fp))
         {
            perror (fname);
         }
      }
      else
      {
         perror (fname);
      }

      fclose (fp);
   }
   else
   {
      perror (fname);
   }
   return size;
}

/* ---------------------------------------------------------------------
   FIC_str_size()
   ---------------------------------------------------------------------
   Role : Recuperer une chaine "Taille du fichier"
   ---------------------------------------------------------------------
   E : Fichier
   E : Chaine
   E : Longeur max de la chaine
   S :
   --------------------------------------------------------------------- */
void FIC_str_size (const char *const sfile
                   ,char *const ssize
                   ,size_t const size)
{
   if (sfile != NULL && ssize != NULL && size != 0)
   {
      ulong dw = FIC_size (sfile);

      LIM_PTR (ssize, size);

      if (dw != 0)
      {
         sprintf (ssize
                  ,"%03lu %03lu %03lu "
                  ,(ulong) (dw / 1000000UL)
                  ,(ulong) (dw / 1000UL)
                  ,(ulong) (dw % 1000UL));
         CHK_PTR (ssize, size);
      }
      else
      {
         *ssize = 0;
         strncat (ssize, "### ### ###", size - 1);
         CHK_PTR (ssize, size);
      }
   }
}

/* ---------------------------------------------------------------------
   FIC_backup()
   ---------------------------------------------------------------------
   Role : sauvegarde un fichier en conservant une copie de secours
   ---------------------------------------------------------------------
   E : Fichier original (ancien)
   E : Nouveau fichier (devient l'ancien)
   E : extension pour renommer l'ancien
   S :
   --------------------------------------------------------------------- */
void FIC_backup (char const *const s_old
                 ,char const *const s_new
                 ,char const *const s_bak_ext)
{
   if (FIC_exist (s_old))
   {
      if (FIC_exist (s_new))
      {
         char *const s_bak = malloc (strlen (s_old) + strlen (s_bak_ext) + 1);

         if (s_bak != NULL)
         {
            strcpy (s_bak, s_old);

            {
               char *p = strrchr (s_bak, '.');

               if (p != NULL)
               {
                  p++;
                  *p = 0;
                  strcat (s_bak, s_bak_ext);
               }

               if (FIC_exist (s_bak))
               {
                  remove (s_bak);
               }

               if (rename (s_old, s_bak) != 0)
               {
                  perror (s_old);
               }

               free (s_bak);

               remove (s_old);

               if (rename (s_new, s_old) != 0)
               {
                  perror (s_new);
               }
            }
         }
         else
         {
            fprintf (stderr, "memory error\n");
         }
      }
      else
      {
         perror (s_new);
      }
   }
   else
   {
      perror (s_old);
   }
}

/* ---------------------------------------------------------------------
   FIC_getline()
   ---------------------------------------------------------------------
   Role : sauvegarde un fichier en conservant une copie de secours
   ---------------------------------------------------------------------
   E : Contexte de fichier
   E : ligne
   E : Longeur de la ligne
   S : 0=OK
   1=pas tout lu
   2=err lect
   3=err param
   ---------------------------------------------------------------------- */
eFIC_ERR FIC_getline (FILE * const fp, char *const pline, size_t const len)
{
   eFIC_ERR ret;

   if (fp && pline && len)
   {
      if (fgets (pline, (int) len, fp))
      {
         char *const p = strchr (pline, '\n');

         if (p)
         {
            *p = 0;
            ret = FIC_NO_ERR;
         }
         else
         {
            ret = FIC_ERR_GL_LENGTH;
         }
      }
      else
      {
         if (feof (fp))
         {
            ret = FIC_ERR_GL_EOF;
         }
         else if (ferror (fp))
         {
            ret = FIC_ERR_GL_READ;
         }
         else
         {
            ret = FIC_ERR_GL_UNKNOWN;
         }
      }
   }
   else
   {
      ret = FIC_ERR_PARAM;
   }
   return ret;
}

/* ---------------------------------------------------------------------
   FIC_scantext()
   ---------------------------------------------------------------------
   Role : Lire un fichier. Appeler un traitement a chaque ligne
   ---------------------------------------------------------------------
   E : Fichier
   E : Fonction de traitement de la ligne
   E : contexte utilisateur
   S : code d'erreur eFIC_ERR
   --------------------------------------------------------------------- */
eFIC_ERR FIC_scantext (const char *const sfile
                       ,fFIC_SCANTEXT * const pf
                       ,void *const pdata)
{
   eFIC_ERR gl_cr;

   if (sfile)
   {
      FILE *fp = fopen (sfile, "r");

      if (fp)
      {
         char sline[BUFSIZ] =
         {0};

         while ((gl_cr = FIC_getline (fp, sline, sizeof sline))
                == FIC_NO_ERR)
         {
            /* appeler le callback */
            if (pf != NULL)
            {
               if (pf (pdata, sline, gl_cr))
               {
                  break;
               }
            }
         }

         if (!ferror (fp))
         {
            if (fclose (fp))
            {
               gl_cr = FIC_ERR_CLOSE;
            }
         }
         else
         {
            fclose (fp);
         }
         fp = NULL;
      }
      else
      {
         gl_cr = FIC_ERR_OPEN;
      }
   }
   else
   {
      gl_cr = FIC_ERR_PARAM;
   }
   return gl_cr;
}

/* ---------------------------------------------------------------------
   FIC_ext_is()
   ---------------------------------------------------------------------
   determiner si un fichier a telle ou telle extension
   ---------------------------------------------------------------------
   E : Nom du fichier
   E : extension
   S : 0 = non 1 = oui
   --------------------------------------------------------------------- */
int FIC_ext_is (char const *const fname, char const *const ext)
{
   int is_ext = 0;
   char *fname_dup = STR_dup (fname);

   if (fname_dup)
   {
      char *ext_dup = STR_dup (ext);

      if (ext_dup)
      {
         STR_tolower (fname_dup);
         STR_tolower (ext_dup);

         {
            char *p = strrchr (fname_dup, '.');

            if (p != NULL)
            {
               is_ext = strcmp (p, ext_dup) == 0;
            }
         }

         free (ext_dup);
      }
      free (fname_dup);

   }
   return is_ext;
}

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