/* ---------------------------------------------------------------------
   (c) ED 2004
   Project      : CLIB
   Function     : data block management.
   Module       : BLK
   File         : blk.c
   Created      : 27-10-2004
   Modified     : 27-10-2004
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Log

   0.0 27-10-2004 Created
   1.0 27-10-2004 Initial version

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

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

#include <string.h>
#include <time.h>

/* private macro definitions =========================================== */

#define ID "BLK"
#define VER "1.0"

#define MODULE ID"."

#define CHK(this) \
   check (this, __FILE__, __LINE__)

/* private constants =================================================== */

/* private types ======================================================= */

/* private structures ================================================== */

#if BLK_ADT
struct blk
{

#if BLK_OUT
   blk_out_f *pf;
   void *p_usr;
#endif

   size_t size;
   ulong sentinel;
   uint dyn:1;
   uchar *buf;
};
#endif /* ADT */

/* private functions =================================================== */

/* ---------------------------------------------------------------------
   init ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void init (blk_s * const this
                  ,uchar * const buf
                  ,size_t const size)
{
   this->buf = buf;
   this->size = size;
   this->sentinel = (ulong) time (NULL);
   memset (this->buf, 0, size);
   memcpy (this->buf + size, &this->sentinel, BLK_SZ_SENTINEL);
}

/* ---------------------------------------------------------------------
   check ()
   ---------------------------------------------------------------------
   ultimate check. Should never happen if the construction is solid 
   enough...
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void check (blk_s * this, char const *file, int line)
{
   int ok = memcmp (&this->sentinel
                    ,this->buf + this->size
                    ,BLK_SZ_SENTINEL) == 0;
   if (!ok)
   {
      fprintf (stderr, MODULE "ERROR: blk_check at %s:%d" EOL, file, line);
      exit (EXIT_FAILURE);
   }
}

/* public internal functions =========================================== */

/* entry points ======================================================== */

/* ---------------------------------------------------------------------
   blk_sid ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *blk_sid (void)
{
   return ID;
}

/* ---------------------------------------------------------------------
   blk_sver ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *blk_sver (void)
{
   return VER;
}

/* ---------------------------------------------------------------------
   blk_serr ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *blk_serr (blk_err_e err)
{
   char const *s;

   switch (err)
   {
#define ITEM(n_, s_)  \
   case BLK_ERR_##n_: \
      s = #s_;        \
      break;

#include "ed/inc/blk_err.itm"

#undef ITEM
   default:
      s = ID ".ERR";
   }

   return s;
}

#if BLK_ADT
/* ---------------------------------------------------------------------
   blk_create ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
blk_s *blk_create (size_t size)
{
   blk_s *this = malloc (sizeof *this);
   if (this != NULL)
   {
      CLR (this, blk_s);

      {
         uchar *buf = malloc (size + BLK_SZ_SENTINEL);

         if (buf != NULL)
         {
            init (this, buf, size);
         }
      }
   }
   return this;
}

/* ---------------------------------------------------------------------
   blk_delete ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
void blk_delete (blk_s * this)
{
   if (this != NULL)
   {
      FREE (this->buf);

      free (this);
   }
}
#else
/* ---------------------------------------------------------------------
   blk_init ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
blk_err_e blk_init (blk_s * const this, uchar * const buf, size_t const size)
{
   blk_err_e err = BLK_OK;

   if (this != NULL)
   {
      init (this, buf, size);
   }
   else
   {
      err = BLK_ERR_CONTEXT;
   }
   return err;
}
#endif

#if BLK_OUT
/* ---------------------------------------------------------------------
   blk_install_out ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
blk_err_e blk_install_out (blk_s * this, blk_out_f * pf, void *p_usr)
{
   blk_err_e err = BLK_OK;

   if (this != NULL)
   {
      this->pf = pf;
      this->p_usr = p_usr;
   }
   else
   {
      err = BLK_ERR_CONTEXT;
   }
   return err;
}
#endif

/* ---------------------------------------------------------------------
   blk_write ()
   ---------------------------------------------------------------------
   #if BLK_OUT
   if (this->pf != NULL)
   {
   int ret = (*this->pf) (this->p_usr, data);
   if (ret != 0)

   {
   err = BLK_ERR_CB_OUT;
   }
   }
   #endif
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
blk_err_e blk_write (blk_s * const this
                     ,void const *const p_data
                     ,size_t const offset
                     ,size_t const len)
{
   blk_err_e err = BLK_OK;

   if (this != NULL)
   {
      if (this->buf != NULL)
      {
         if (p_data != NULL)
         {
            if (this->size >= offset + len)
            {
               memcpy (this->buf + offset, p_data, len);
               CHK (this);
            }
            else
            {
               err = BLK_ERR_WRITE_SIZE;
            }
         }
         else
         {
            err = BLK_ERR_WRITE_PDATA;
         }
      }
      else
      {
         err = BLK_ERR_BUFFER;
      }
   }
   else
   {
      err = BLK_ERR_CONTEXT;
   }
   return err;
}

/* ---------------------------------------------------------------------
   blk_read ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
blk_err_e blk_read (blk_s * const this
                    ,void *const p_data
                    ,size_t const size_data
                    ,size_t const offset
                    ,size_t const len)
{
   blk_err_e err = BLK_OK;

   if (this != NULL)
   {
      if (this->buf != NULL)
      {
         if (p_data != NULL)
         {
            if (len <= size_data)
            {
               memcpy (p_data, this->buf + offset, len);
            }
            else
            {
               err = BLK_ERR_READ_SIZE;
            }
         }
         else
         {
            err = BLK_ERR_READ_PDATA;
         }
      }
      else
      {
         err = BLK_ERR_BUFFER;
      }
   }
   else
   {
      err = BLK_ERR_CONTEXT;
   }
   return err;
}

/* ---------------------------------------------------------------------
   blk_buf ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
uchar const *blk_buf (blk_s * this)
{
   uchar *buf = NULL;

   if (this != NULL)
   {
      buf = this->buf;
   }

   return buf;
}

/* ---------------------------------------------------------------------
   blk_size ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
size_t blk_size (blk_s * this)
{
   size_t size = 0;

   if (this != NULL)
   {
      size = this->size;
   }

   return size;
}

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

/* ---------------------------------------------------------------------
   Generated by NEW (c) ED 2.4
   Powered by C-code generator (c) ED 2003 1.0
   --------------------------------------------------------------------- */
