/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2002, 2003, 2004 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.  

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

   Perform operations on strings arrays.
   
*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <errno.h>
#include <ctype.h>

#include "xmalloc.h"
#include "rarray.h"
#include "rstring.h"
#include "error.h"
#include <regex.h>
#include "memchunk.h"
#include "str.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/

static regmatch_t matches[1];

/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/

static char *search_line_end (char *txt, size_t line_len);

/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/

static char *
search_line_end (char *txt, size_t line_len)
{
        char *last_space = NULL;
        char *seek;

        for (seek = txt; *seek && seek - txt < line_len; seek++){
                switch (*seek){
                        case ' ': case '\t':
                                last_space = seek;
                                break;

                        case '\n':
                                return seek;
                }
        }

        if (*seek == '\0'){
                return NULL;
        }
  
        if (last_space){
                return last_space;
        }

        return seek;
}



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


rstring_t *
rstring_create_size (int size)
{
        return (rstring_t *) rarray_create_size (size);
}



rstring_t *
rstring_create (void)
{
        return (rstring_t *) rarray_create ();
}



void
rstring_delete (rstring_t *ptr)
{
        if (ptr->allocated_all){
                rstring_free_strings (ptr);
        }
        else if (ptr->allocated_first && ptr->count > 0){
                xfree (ptr->array[0]);
        }
        rarray_destroy ((rarray_t *) ptr);
}



void
rstring_add (rstring_t *ptr, char *txt)
{
        rarray_add ((rarray_t *) ptr, txt);
}



void
rstring_sprintf (rstring_t *ptr, const char *fmt, ...)
{
        va_list  ap;
        str_t   *str = str_create ();

        va_start (ap, fmt);
        str_vsprintf (str, fmt, ap);
        va_end (ap);

        rstring_add (ptr, str_finished (str));
}


void
rstring_remove (rstring_t *ptr, unsigned index)
{
        rarray_remove ((rarray_t *) ptr, index);
}



void
rstring_shrink (rstring_t *ptr)
{
        rarray_shrink ((rarray_t *) ptr);
}



rstring_t *
rstring_split (char *txt, const char *delimiter)
{
        rstring_t *result;
        char      *seek = txt;
        size_t     len  = strlen (delimiter);

        result = rstring_create ();

        while (seek && *seek){
                rstring_add (result, seek);
                seek = strstr (seek, delimiter);
                if (seek){
                        *seek  = '\0';
                        seek  += len;
                }
        }
        return result;
}



rstring_t *
rstring_split_re (char *txt, const char *regexp)
{
        rstring_t *result;
        regex_t    compiled;
        int        ret;
        char      *seek = txt;

        ret = regcomp (&compiled, regexp, REG_ICASE | REG_EXTENDED);

        if (ret){
                result = NULL;
                error_regex (ret, &compiled, regexp);
                regfree (&compiled);
                return NULL;
        }

        result = rstring_create ();

        while (seek && *seek){
                rstring_add (result, seek);
                ret = regexec (&compiled, seek, 1, matches, 0);

                if (ret && ret != REG_NOMATCH){
                        error_regex (ret, &compiled, regexp);
                        rstring_delete (result);
                        regfree (&compiled);
                        return NULL;
                }
                if (ret == REG_NOMATCH)
                        break;
                *(seek + matches[0].rm_so) = '\0';
                seek += matches[0].rm_eo;
        }

        regfree (&compiled);
        return result;
}



rstring_t *
rstring_split_lines (char *txt, size_t line_len)
{
        rstring_t *result;
        char      *seek = txt;

        if (txt == NULL)
                return NULL;
  
        result = rstring_create ();
  
        while (seek && *seek){
                rstring_add (result, seek);
                seek = search_line_end (seek, line_len);
                if (seek){
                        *seek = '\0';
                        seek++;
                }
        }
        return result;
}



rstring_t *
rstring_join (rstring_t *x, rstring_t *y)
{
        return (rstring_t *) rarray_join ((rarray_t *) x, (rarray_t *) y);
}



rstring_t *
rstring_copy (rstring_t *x)
{
        rstring_t  *result = rstring_create_size (x->count + 1);
        char      **txt;

        for (txt = x->array; *txt; txt++){
                rstring_add (result, xstrdup (*txt));
        }
        result->allocated_all = 1;
        return result;
}


void
rstring_free_firstn_strings (rstring_t *x, int n)
{
        char **str;

        for (str = x->array; n && *str; str++){
                xfree (*str);
                n--;
        }
}



void
rstring_free_strings (rstring_t *x)
{
        char **str;

        for (str = x->array; *str; str++)
                xfree (*str);
}



void
rstring_dump (memchunk_t *memchunk, rstring_t *x)
{
        int i;
        int zero = 0;
  
        if (x == NULL){
                memchunk_intdump (memchunk, zero);
                return;
        }
  
        memchunk_intdump (memchunk, x->count);
        for (i = 0; i < x->count; i++)
                memchunk_strdump (memchunk, x->array[i]);
}



rstring_t *
rstring_read (memchunk_t *memchunk)
{
        int        i;
        int        size = memchunk_intget (memchunk);
        rstring_t *result;

        if (size == 0)
                return NULL;

        result = rstring_create_size (size + 1);
        for (i = 0; i < size; i++){
                rstring_add (result, memchunk_strget (memchunk));
        }
        result->allocated_all = 1;
        return result;
}



char *
rstring_flatten (rstring_t *ptr, const char *delim)
{
        int    i;
        str_t *str = str_create ();

        for (i = 0; i < ptr->count - 1; i++){
                str_sprintf (str, "%s%s", ptr->array[i], delim);
        }
        if (ptr->count > 0)
                str_sprintf (str, "%s", ptr->array[ptr->count - 1]);

        return str_finished (str);
}


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


syntax highlighted by Code2HTML, v. 0.9.1