/*
 * Functions for handling string buffers.
 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca>
 *
 * 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.
 *
 * 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.
 */

#include <string.h>

#include "sdorfehs.h"
#include "sbuf.h"

struct sbuf *
sbuf_new(size_t initsz)
{
	struct sbuf *b = xmalloc(sizeof(struct sbuf));

	if (initsz < 1)
		initsz = 1;

	b->data = xmalloc(initsz);
	b->maxsz = initsz;

	b->data[0] = '\0';
	b->len = 0;

	return b;
}

void
sbuf_free(struct sbuf *b)
{
	if (b != NULL) {
		free(b->data);
		free(b);
	}
}

/* Free the structure but return the string. */
char *
sbuf_free_struct(struct sbuf *b)
{
	if (b != NULL) {
		char *tmp;
		tmp = b->data;
		free(b);
		return tmp;
	}
	return NULL;
}

char *
sbuf_nconcat(struct sbuf *b, const char *str, int len)
{
	size_t minsz = b->len + len + 1;

	if (b->maxsz < minsz) {
		b->data = xrealloc(b->data, minsz);
		b->maxsz = minsz;
	}
	memcpy(b->data + b->len, str, minsz - b->len - 1);
	b->len = minsz - 1;
	*(b->data + b->len) = 0;

	return b->data;
}


char *
sbuf_concat(struct sbuf *b, const char *str)
{
	return sbuf_nconcat(b, str, strlen(str));
}

char *
sbuf_copy(struct sbuf *b, const char *str)
{
	b->len = 0;
	return sbuf_concat(b, str);
}

char *
sbuf_clear(struct sbuf *b)
{
	b->len = 0;
	b->data[0] = '\0';
	return b->data;
}

char *
sbuf_get(struct sbuf *b)
{
	return b->data;
}

char *
sbuf_printf(struct sbuf *b, char *fmt,...)
{
	va_list ap;

	free(b->data);

	va_start(ap, fmt);
	b->data = xvsprintf(fmt, ap);
	va_end(ap);

	b->len = strlen(b->data);
	b->maxsz = b->len + 1;

	return b->data;
}

char *
sbuf_printf_concat(struct sbuf *b, char *fmt,...)
{
	char *buffer;
	va_list ap;

	va_start(ap, fmt);
	buffer = xvsprintf(fmt, ap);
	va_end(ap);

	sbuf_concat(b, buffer);
	free(buffer);

	return b->data;
}

/* if width >= 0 then limit the width of s to width chars. */
char *
sbuf_utf8_nconcat(struct sbuf *b, const char *s, int width)
{
	if (width >= 0) {
		int len, nchars;

		len = nchars = 0;
		while (s[len] != '\0' && nchars < width) {
			if (isu8start(s[len]))
				do
					len++;
				while (isu8cont(s[len]));
			else
			len++;
			nchars++;
		}
		sbuf_printf_concat(b, "%.*s", len, s);
	} else
		sbuf_concat(b, s);

	return b->data;
}

void
sbuf_chop(struct sbuf *b)
{
	if (b->len) {
		b->data[--(b->len)] = '\0';
	}
}
