/* 
   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.  

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

   resizable strings

*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

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

#include "str.h"
#include "xmalloc.h"

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

#define INITIAL_SIZE 64

#define PREAMBLE do { if (str == NULL) return; } while (0)

/****************************************************************************
 *    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
 ****************************************************************************/
/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/


str_t *
str_create_size (int size)
{
        str_t *result = xmalloc (sizeof (str_t));

        result->len   = 0;
        result->size  = size;
        result->str   = xmalloc (size + 1);
        *result->str  = '\0';

        return result;
}


str_t *
str_create (void)
{
        return str_create_size (INITIAL_SIZE);
}


str_t *
str_dup (const char *str)
{
        int    len;
        str_t *result;
        
        if (str == NULL)
                return NULL;

        len    = strlen (str);
        result = str_create_size (len);
        str_put_string_len (result, str, len);
        return result;
}


str_t *
str_from_str (char *s, int len)
{
        str_t *result = xmalloc (sizeof (str_t));

        result->len  = len;
        result->size = len;
        result->str  = s;

        return result;
}


void
str_destroy (str_t *str)
{
        PREAMBLE;
  
        if (str->str)
                xfree (str->str);
        xfree (str);
}



void
str_clear (str_t *str)
{
        PREAMBLE;
  
        str->len  = 0;
        *str->str = '\0';
}


char *
str_finished (str_t *str)
{
        char *result;

        if (str == NULL)
                return NULL;

        result = xrealloc (str->str, str->len + 1);

        xfree (str);
        return result;
}


void
str_put_nchar (str_t *str, int c, int n)
{
        PREAMBLE;
  
        if (str->len + n > str->size - 1){
                str->size = (str->size + n) * 2;
                str->str  = xrealloc (str->str, str->size + 1);
        }
        memset (str->str + str->len, c, n);
        str->str[str->len + n] = '\0';
        str->len += n;
}


void
str_put_char (str_t *str, int c)
{
        str_put_nchar (str, c, 1);
}



void
str_put_string_len (str_t *str, const char *s, int len)
{
        PREAMBLE;
  
        if (str->len + len > str->size - 1){
                str->size = (str->size + len) * 2;
                str->str  = xrealloc (str->str, str->size + 1);
        }
        memcpy (str->str + str->len, s, len);
        str->str[str->len + len] = '\0';
        str->len += len;
}



void
str_put_string (str_t *str, const char *s)
{
        int len;

        if (s == NULL)
                return;
  
        len = strlen (s);
        str_put_string_len (str, s, len);
}


int
str_vsprintf (str_t *str, const char *fmt, va_list ap)
{
        int     n;
        int     max_size;
        va_list copy;
  
        if (str == NULL || fmt == NULL)
                return -1;
  
        while (1){
                max_size = str->size - str->len - 1;
#if (defined(__FreeBSD__) && __FreeBSD__ < 5)
		copy = ap;
#else
                va_copy (copy, ap);
#endif
                n = vsnprintf (str->str + str->len, max_size, fmt, copy);
                if (n > -1 && n < max_size){
                        str->len += n;
                        return n;
                }
                if (n > -1)
                        while (max_size < n + 1){
                                str->size *= 2;
                                max_size   = str->size - str->len;
                        }
                else {
                        str->size *= 2;
                }

                str->str = xrealloc (str->str, str->size + 1);
        }
}


int
str_sprintf (str_t *str, const char *fmt, ...)
{
        int     ret;
        va_list ap;

        va_start (ap, fmt);
        ret = str_vsprintf (str, fmt, ap);
        va_end (ap);
        return ret;
}


void
str_chop (str_t *str)
{
        int len = str->len;

        if (len == 0)
                return;
        
        str->str[len - 1] = '\0';
        str->len--;
}

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


syntax highlighted by Code2HTML, v. 0.9.1