/*
 * File: strbuf.c
 *
 * Copyright 2003 Sebastian Geerken <s.geerken@ping.de>
 *
 * 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; either version 2 of the License, or
 * (at your option) any later version.
 */

/*
 * A simple structure for fast concatenation of a large number of strings.
 */

#include <string.h>
#include "strbuf.h"


/*
 * Create a new string buffer.
 */
Strbuf_t *a_Strbuf_new (void)
{
   Strbuf_t *strbuf;

   strbuf = g_new (Strbuf_t, 1);
   strbuf->list = NULL;
   strbuf->num_chars = 0;
   strbuf->str = NULL;
   strbuf->str_valid = FALSE;
   return strbuf;
}


/*
 * Free a string buffer.
 */
void a_Strbuf_free (Strbuf_t *strbuf)
{
   GSList *it;

   for (it = strbuf->list; it; it = it->next)
      g_free (it->data);
   g_slist_free (strbuf->list);
   g_free (strbuf->str);
   g_free (strbuf);
}

/*
 * Append a NUL-terminated string to the buffer.
 * A copy is kept in the buffer, so the caller does not have to care
 * about memory management.
 */
void a_Strbuf_append (Strbuf_t *strbuf,
                      gchar *str)
{
   /* Remember that g_slist_prepend is faster than g_slist_prepend! */
   strbuf->list = g_slist_prepend (strbuf->list, g_strdup (str));
   strbuf->num_chars += strlen (str);
   strbuf->str_valid = FALSE;
}

/*
 * Return a NUL-terminated strings containing all appended strings.
 * The caller does not have to free the string, this is done in
 * a_Strbuf_free().
 */
gchar* a_Strbuf_chars (Strbuf_t *strbuf)
{
   /* Note: g_slist_reverse does not create a copy of the old list, instead
    * reversing it twice should leave no memory leaks. */
   GSList *it;
   gchar *p, *s;
   int l;

   if (strbuf->str_valid)
      return strbuf->str;

   g_free (strbuf->str);
   strbuf->str = g_new (gchar, strbuf->num_chars + 1);

   strbuf->list = g_slist_reverse (strbuf->list);
   p = strbuf->str;
   for (it = strbuf->list; it; it = it->next) {
      s = (gchar*)(it->data);
      l = strlen (s);
      memcpy (p, s, l * sizeof (gchar));
      p += l;
   }

   *p = 0;
   strbuf->list = g_slist_reverse (strbuf->list); /* reverse reversion */
   strbuf->str_valid = TRUE;
   
   return strbuf->str;
}
