/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2003 rzyjontko

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  

   ----------------------------------------------------------------------

   byte chunks allocation
   
*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#include "memblock.h"
#include "xmalloc.h"
#include "error.h"
#include "debug.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/

#define MAX(a,b)  (((a) > (b)) ? (a) : (b))

/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/
/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/

static memblock_t *
resize (memblock_t *block, int size)
{
  memblock_t *add;
  
  if (size > block->size - block->used){
    debug_msg (DEBUG_INFO,
               "resizing block... used %d of %d bytes, need %d bytes",
               block->used, block->size, size);
    add       = memblock_create (2 * MAX (block->size, size));
    add->next = block;
    block     = add;
  }
  return block;
}


static int
get_len (const char *fmt, va_list ap)
{
  int   len = 0;
  char *str;

  while (*fmt){
    if (*fmt == '%'){
      switch (fmt[1]){

        case 's':
          str  = va_arg (ap, char *);
          len += strlen (str);
          fmt++;
          break;

        case 'd':
          va_arg (ap, int);
          len += 10;
          fmt++;
          break;

        case 'c':
          va_arg (ap, int);
          
        case '%':
          fmt++;
          break;
      }
    }
    fmt++;
    len++;
  }

  return len;
}

/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/


memblock_t *
memblock_create (int size)
{
  memblock_t *result = xmalloc (sizeof (memblock_t));

  result->next   = NULL;
  result->size   = size;
  result->memptr = xmalloc (result->size);
  result->used   = 0;
  result->last   = 0;
  result->mark   = -1;
  return result;
}



void
memblock_destroy (memblock_t *block)
{
  int i    = 0;
  int size = 0;
  memblock_t *next;
  
  while (block){
    size += block->size;
    next  = block->next;
    xfree (block->memptr);
    xfree (block);
    block = next;
    i++;
  }
  debug_msg (DEBUG_INFO, "destroyed memblock length %d of total size %d",
             i, size);
}



char *
memblock_strdup (memblock_t **block, const char *str)
{
  int   len;
  char *result;

  if (str == NULL || *block == NULL)
    return NULL;

  len    = strlen (str) + 1;
  *block = resize (*block, len);
  result = (*block)->memptr + (*block)->used;
  
  memcpy ((*block)->memptr + (*block)->used, str, len);
  (*block)->used += len;
  (*block)->last  = len;

  return result;
}



void *
memblock_malloc (memblock_t **block, int size)
{
  void *result;

  if (size == 0)
    return NULL;
  
  *block = resize (*block, size);
  result = (*block)->memptr + (*block)->used;

  (*block)->used += size;
  (*block)->last  = size;

  return result;
}



void
memblock_shrink_last (memblock_t *block, int size)
{
  if (size > block->last)
    return;

  block->used -= size - block->last;
  block->last  = size;
}



void
memblock_free_last (memblock_t *block)
{
  if (block == NULL)
    return;
  block->used -= block->last;
  block->last  = 0;
}



void
memblock_set_mark (memblock_t *block)
{
  if (block == NULL)
    return;
  block->mark = block->used;
}



void
memblock_free_marked (memblock_t **block)
{
  memblock_t *next;
  
  while ((*block)->mark == -1){
    next = (*block)->next;
    xfree ((*block)->memptr);
    xfree (*block);
    *block = next;
  }
  (*block)->used = (*block)->mark;
}



char *
memblock_sprintf (memblock_t **block, const char *fmt, ...)
{
  int      len;
  char    *result;
  va_list  ap;

  va_start (ap, fmt);
  len = get_len (fmt, ap);
  va_end (ap);

  va_start (ap, fmt);
  result = memblock_malloc (block, len + 1);
  vsprintf (result, fmt, ap);
  va_end (ap);
  return result;
}


/****************************************************************************
 *    INTERFACE CLASS BODIES
 ****************************************************************************/
/****************************************************************************
 *
 *    END MODULE memblock.c
 *
 ****************************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1