/* ---------------------------------------------------------------------
   (c) ED 1995-2006
   Projet       : CLIB
   Fonction     : Fonctions 'systeme' (actually, a huge garbage...)
   Module       : SYS
   Fichier      : SYS.C
   Creation     : 05-01-1995
   Modification : 16-06-2006
   --------------------------------------------------------------------- */

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

   1.33 16-06-2006 deplace ASSERT() dans ed/inc/assert.h
   1.32 22-03-2006 Protection de SIZE_T_MAX
   1.31 15-11-2005 Ajout de la macro STR()
   1.30 25-06-2004 Differencie DJGPP de GCC
   1.29 15-12-2003 Ajout de SYS_get_str()
   1.28 01-12-2003 Suppression de la macro NOT_USED()
   1.27 11-07-2003 Recupere sys_time() et sys_clock() qui etaient dans
   .               sysalloc
   1.26 10-06-2003 Les macros MIN et MAX deviennent min() max()
   1.25 28-05-2003 Ajoute macros MIN et MAX (si non definies)
   1.24 15-04-2003 Ajoute compilateur _TMS320C5XX.
   1.23 04-01-2003 Ajoute (size_t) a l'init de SYS_G_stack_min.
   1.22 26-11-2002 Supprime macro PERR() C'est de la responsabilite des
   .               applications
   1.21 15-11-2002 Ajoute macros STACK_xxx()
   1.20 04-10-2002 Ajoute macros INFO(), EN_TRAVAUX() et PERR().
   .               ASIZE() devient NELEM()
   1.19 13-07-2002 LCLint
   1.18 26-04-2002 Supprime definitions de BYTE WORD LONG
   1.17 26-09-2001 Ajout definition U8 U16 et U32
   1.16 17-02-2001 SYS_dump() en stderr.
   1.15 01-12-2000 Ajout macro ENUM_CHECK()
   1.14 22-11-2000 Ajout macro ALIGN2() La macro PAR devient PAR_
   1.13 17-11-2000 dans ASET(), i devient aset_i
   1.12 16-11-2000 ajoute macros OCT_INTEGER_MAX etc...
   1.11 29-06-2000 ajoute LIM_STR()
   1.10 19-06-2000 ajoute ASET()
   1.9 16-06-2000 ajoute CHK_STR() et CHK_PTR()
   1.8 31-05-2000 les bits telecom (B1-B8) deviennent uint
   1.7 04-04-2000 TSIZE() devient ASIZE()
   1.6 30-03-2000 ajoute () dans les macros
   1.5 23-11-1999 dans SYS_print_dbg(), remplace free() par sys_free()
   1.4 17-11-1999 Mise en conformite ANSI de SYS_dump().
   .              Renforce' les controles
   1.3 15-01-1999 Normalisation
   1.2 29-12-1998 Ajout de SYS_StrDllExitType()
   1.1 09-09-1998 Ajout de SYS_FindInt()
   1.0 13-08-1998 SYS_sz_dbg() devient SYS_print_dbg

   0.5 09-08-1998 Ajout de SYS_sz_dbg()
   0.4 16-02-1998 le type de SYS_dump passe de (BYTE*) a (void*)
   0.3 22-01-1998 Ajout de SYS_in()
   0.2 09-01-1995 Compilation ANSI (suppression des "far")
   0.1 05-01-1995 Version Operationelle

   Specifications
   --------------

   --------------------------------------------------------------------- */

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

#include <stdio.h>

#include <ctype.h>
#include <string.h>

#ifdef _Windows
#include <windows.h>
#endif

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

/* public data ========================================================= */
/* macros ============================================================== */
#define VER "1.33"
#define ID "SYS (c) ED 1995-2006"
#define MODULE "SYS: "

#define DATA16_INT(a, i) \
   (((a[(i) + 1] << 8) | a[(i) + 0]) & 0xFFFFU)

#define DATA16_MOT(a, i) \
   (((a[(i) + 0] << 8) | a[(i) + 1]) & 0xFFFFU)

#if defined (__BORLANDC__)

#define FMT "%p"
#define CAST (void const *)

#define FMT "%p"
#define CAST (void const *)

#define DATA16(a, i) DATA16_INT(a, i)

#elif defined (__GNUC__)

#define FMT "%p"
#define CAST (void const *)

#define DATA16(a, i) DATA16_INT(a, i)

#elif defined (_MSC_VER)

#define FMT "%p"
#define CAST (void const *)

#define DATA16(a, i) DATA16_INT(a, i)

#elif defined (__DIAB)

#define FMT "%p"
#define CAST (void const *)

#define DATA16(a, i) DATA16_MOT(a, i)

#elif defined (_MRI)

#define FMT "%06lX"
#define CAST (ulong const)

#define DATA16(a, i) DATA16_MOT(a, i)

#else
#error "Some definitions are missing for this platform"
#endif

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

#ifdef __BORLANDC__
uint SYS_G_stack_min = (uint) - 1;
uint SYS_G_stack_max;
#endif
/* internal public functions =========================================== */
/* entry points ======================================================== */

/* ---------------------------------------------------------------------
   SYS_sid()
   ---------------------------------------------------------------------
   Role : retourne une chaine avec l'identification du module
   ---------------------------------------------------------------------
   E :
   S : identification
   --------------------------------------------------------------------- */
char const *SYS_sid (void)
{
   return ID;
}

/* ---------------------------------------------------------------------
   SYS_sver()
   ---------------------------------------------------------------------
   Role : retourne une chaine avec la version
   ---------------------------------------------------------------------
   E :
   S : version
   --------------------------------------------------------------------- */
char const *SYS_sver (void)
{
   return VER;
}

/* ---------------------------------------------------------------------
   SYS_dump()
   ---------------------------------------------------------------------
   Role : Dumper une zone memoire vers stdout
   ---------------------------------------------------------------------
   E : adresse de debut de la zone
   E : longueur a dumper (en octets)
   S :
   --------------------------------------------------------------------- */
void SYS_dump (void const *const p, size_t const len)
{
   int ok = 1;
   const char *szErrBuf = NULL;
   const char *szErrLen = NULL;

   ENUM_CHECK ();
   STACK_CHK ();

#if __PC__
   if (p == NULL)
   {
      szErrBuf = "p=NULL";
      ok = 0;
   }
#endif

   if (len == 0)
   {
      szErrLen = "len=0";
      ok = 0;
   }

   if (ok)
   {
#define LEN 16
      uchar const *const ao = p;
      size_t i;

      for (i = 0; i < len; i += LEN)
      {
         size_t j;

         /* Adresse de la ligne */
         printf (FMT " ", CAST (ao + i));

         for (j = i; j < i + LEN; j++)
         {
            if (j < len)
            {
               /* octets en hexa */
               printf ("%02X ", (uint) ao[j] & 0xFF);
            }
            else
            {
               printf ("   ");  /* 3 espaces */
            }
         }

         printf (" '");

         for (j = i; j < (i + LEN) && j < len; j++)
         {
            if (isprint (ao[j]))
            {
               /* octets en caracteres */
               printf ("%c", (int) ao[j]);
            }
            else
            {
               printf (".");
            }
         }
         printf ("'\n");
      }
#undef LEN
   }
   else
   {
      fprintf (stderr
               ,MODULE "SYS_dump (%p, %lu) ERR : "
               ,(void const *) p
               ,(ulong) len);

      if (szErrBuf)
      {
         fprintf (stderr, "%s ", szErrBuf);
      }
      if (szErrLen)
      {
         fprintf (stderr, "%s ", szErrLen);
      }
      fprintf (stderr, "\n");
   }
}

/* ---------------------------------------------------------------------
   SYS_dump16()
   ---------------------------------------------------------------------
   Role : Dumper une zone memoire vers stdout en 16 bits
   ---------------------------------------------------------------------
   E : adresse de debut de la zone
   E : longueur a dumper (en mots de 16 bits)
   S :
   --------------------------------------------------------------------- */
void SYS_dump16 (void const *const p, size_t const len)
{
   int ok = 1;
   const char *szErrBuf = NULL;
   const char *szErrLen = NULL;

   ENUM_CHECK ();
   STACK_CHK ();

#if __PC__
   if (p == NULL)
   {
      szErrBuf = "p=NULL";
      ok = 0;
   }
#endif

   if (len == 0)
   {
      szErrLen = "len=0";
      ok = 0;
   }

   if (ok)
   {
#define LEN 16
      uchar const *const ao = p;
      size_t i;

      for (i = 0; i < (len * 2); i += LEN)
      {
         size_t j;

         /* Adresse de la ligne */
         printf (FMT " ", CAST (ao + i));

         for (j = i; j < i + LEN; j += 2)
         {
            if (j < (len * 2))
            {
               /* octets en hexa */
               printf ("%04X ", (uint) DATA16 (ao, j));
            }
         }

         printf ("\n");
      }
#undef LEN
   }
   else
   {
      fprintf (stderr
               ,MODULE "SYS_dump (%p, %lu) ERR : "
               ,(void const *) p
               ,(ulong) len);

      if (szErrBuf)
      {
         fprintf (stderr, "%s ", szErrBuf);
      }
      if (szErrLen)
      {
         fprintf (stderr, "%s ", szErrLen);
      }
      fprintf (stderr, "\n");
   }
}

/* ---------------------------------------------------------------------
   SYS_IntIn()
   ---------------------------------------------------------------------
   Role : cherche un 'int' dans un tableau d'entier, et retourne 1 si
   il l'a trouve, ou 0 sinon.
   ---------------------------------------------------------------------
   E : Adresse du tableau
   E : Nombre d'entiers du tableau
   E : Valeur recherchee
   S : 0=Pas trouve 1=Trouve
   --------------------------------------------------------------------- */
int SYS_IntIn (int const *const ai, const size_t size, int const val)
{
   size_t i;

   ENUM_CHECK ();
   STACK_CHK ();

   for (i = 0; (val != ai[i]) && (i < size); i++)
   {
   }

   return (i < size);
}

/* ---------------------------------------------------------------------
   SYS_DwIndex()
   ---------------------------------------------------------------------
   Retourne le rang d'un ulong dans un tableau ou -1 si absent
   ---------------------------------------------------------------------
   E : adresse
   E : npmbre d'elements
   E : valeur cherchee
   S : valeur -1 = absent
   --------------------------------------------------------------------- */
int SYS_DwIndex (const ulong * adw
                 ,const size_t size
                 ,const ulong dw)
{
   int cr = -1;
   size_t i;

   ENUM_CHECK ();
   STACK_CHK ();

   for (i = 0; i < size; i++)
   {
      if (adw[i] == dw)
      {
         cr = (int) i;
         break;
      }
   }

   return cr;
}

/* ---------------------------------------------------------------------
   SYS_FindInt()
   ---------------------------------------------------------------------
   Role : cherche un 'int' dans un tableau d'entier, et retourne son rang
   si il l'a trouve, ou -1 sinon.
   ---------------------------------------------------------------------
   E : Adresse du tableau
   E : Nombre d'entiers du tableau
   E : Valeur recherchee
   S : -1=Pas trouve >0=Rang
   --------------------------------------------------------------------- */
int SYS_FindInt (int const *const ai, size_t const size, int const val)
{
   int cr = -1;
   size_t i;

   ENUM_CHECK ();
   STACK_CHK ();

   for (i = 0; i < size; i++)
   {
      if (ai[i] == val)
      {
         cr = (int) i;
         break;
      }
   }

   return cr;
}

/* --------------------------------------------------------------------
   SYS_get_str()
   --------------------------------------------------------------------
   retourne une chaine en fonction d'un int
   --------------------------------------------------------------------
   E : value
   S : string ou "?" si inconnue
   -------------------------------------------------------------------- */
char const *SYS_get_str (SYS_int_str_s const *const as
                         ,size_t const nb
                         ,int const val)
{
   char const *s = "?";
   size_t i;

   for (i = 0; i < nb; i++)
   {
      SYS_int_str_s const *const p = as + i;

      if (p->value == val)
      {
         s = p->string;
         break;
      }
   }

   return s;
}

#ifdef _Windows
#ifndef WIN32
/* ---------------------------------------------------------------------
   StrDllExitType()
   ---------------------------------------------------------------------
   Get DLL Exit type string
   --------------------------------------------------------------------- */
const char *SYS_StrDllExitType (const int nExitType)
{
   const char *sz;

   ENUM_CHECK ();
   STACK_CHK ();

   switch (nExitType)
   {
   case WEP_FREE_DLL:
      sz = "FREE DLL";
      break;
   case WEP_SYSTEM_EXIT:
      sz = "SYSTEM EXIT";
      break;
   default:
      sz = "Unkwown DLL exit code";
   }
   return sz;
}

#endif /* WIN32 */
#endif /* _Windows */

#if (defined(__TURBOC__) && __TURBOC__ <= VER_MAX_MMODEL)
const char *SYS_Smmodel[MMODEL_NB] =
{
   "TINY",
   "SMALL",
   "MEDIUM",
   "COMPACT",
   "LARGE",
   "HUGE",
   "FLAT",
};

/* ---------------------------------------------------------------------
   Variable du C
   La variable DWORD FAR _MMODEL  contient les infos suivantes :

   b31-16 : reserve
   b15 : Type de pointeur CODE
   0=NEAR
   1=FAR
   b14 : Type de pointeur DATA
   0=NEAR
   1=FAR
   b13-b4 reserve
   b3-b0 : Modele de memoire
   000=TINY,
   001=SMALL,
   010=MEDIUM,
   011=COMPACT,
   100=LARGE,
   101=HUGE,
   110=reserve
   111=reserve
   --------------------------------------------------------------------- */
tMMODEL SYS_mmodel (sMMODEL * pmmodel)
{
#if !defined(__WIN32__) && !defined(__STDC__)
   extern long far _MMODEL;     /* Variable du C */
   ulong dw;

   ENUM_CHECK ();
   STACK_CHK ();

   dw = _MMODEL;
   if (pmmodel)
   {
      pmmodel->model = dw & 0xFF;
      pmmodel->code = (((dw >> 8) & 0xFF) & bit7) == bit7;
/*      pmmodel->data =dw.b.b1&(bit6==bit6); */

      switch (pmmodel->model)
      {
      case MMODEL_TINY:
      case MMODEL_SMALL:
      case MMODEL_MEDIUM:
      case MMODEL_COMPACT:
      case MMODEL_LARGE:
      case MMODEL_HUGE:
         break;

      default:
         ASSERT (0);
      }
   }
   return dw & 0xFF;
#else

   (void) pmmodel;

   return MMODEL_FLAT;
#endif /* __TURBOC__ */
}

#endif

/* ---------------------------------------------------------------------
   SYS_print_stack()
   ---------------------------------------------------------------------
   Prints the stack status
   --------------------------------------------------------------------- */
void SYS_print_stack (void)
{
#ifdef __STDC__
   fprintf (stderr, MODULE "SYS_print_stack() : Undefined in ISO-C\n");
#else

#if defined (__BORLANDC__)

   fprintf (stderr
            ,MODULE "stklen=$%04X\n"
            ,(uint) _stklen
      );
   if (SYS_G_stack_max == 0)
   {
      fprintf (stderr, MODULE "ERR: add STACK_INIT() in main()\n");
   }
   else
   {
      fprintf (stderr
               ,MODULE "stack:   max=$%04X (value of SP in main())\n"
               ,(uint) SYS_G_stack_max
         );
      fprintf (stderr
               ,MODULE "stack:   min=$%04X (lowest known value)\n"
               ,(uint) SYS_G_stack_min
         );
      fprintf (stderr
               ,MODULE "stack: delta=$%04X (best approximation)\n"
               ,(uint) (SYS_G_stack_max - SYS_G_stack_min)
         );
   }

#endif

#endif
}

/* ---------------------------------------------------------------------
   sys_clock()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
clock_t sys_clock (void)
{
   return clock ();
}

/* ---------------------------------------------------------------------
   sys_time()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
time_t sys_time (time_t * timer)
{
   return time (timer);
}
