A mail formatter.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

230 lines
4.6 KiB

/*
* sbuffer - Incenp.org Notch Library: string buffer module
* Copyright (C) 2011 Damien Goutte-Gattat
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sbuffer.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef EXIT_ON_ENOMEM
#include <xmem.h>
#endif
struct string_buffer_t
{
char *buffer;
size_t len;
size_t size;
size_t block;
};
#define AVAILABLE_SIZE(s) ((s)->size - (s)->len)
#define CURSOR(s) ((s)->buffer + (s)->len)
#ifdef EXIT_ON_NOMEM
#define GROW(s,l) \
do { \
(s)->size = ((((s)->len + (l)) / (s)->block) + 1) * (s)->block; \
(s)->buffer = xrealloc((s)->buffer, (s)->size); \
} while ( 0 )
#else
#define GROW(s,l) \
do { \
size_t ns = ((((s)->len + (l)) / (s)->block) + 1) * (s)->block; \
char *np = realloc((s)->buffer, ns); \
if ( ! np ) \
return -1; \
(s)->buffer = np; \
(s)->size = ns; \
} while ( 0 )
#endif
string_buffer_t *
sb_new(size_t block_size)
{
string_buffer_t *s;
if ( ! block_size )
block_size = 128;
#ifdef EXIT_ON_ENOMEM
s = xmalloc(sizeof(*s));
s->block = s->size = block_size;
s->buffer = xmalloc(block_size);
sb_empty(s);
#else
if ( (s = malloc(sizeof(*s))) ) {
s->block = s->size = block_size;
if ( (s->buffer = malloc(block_size)) )
sb_empty(s);
else {
free(s);
s = NULL;
}
}
#endif
return s;
}
void
sb_free(string_buffer_t *s)
{
if ( s ) {
free(s->buffer);
free(s);
}
}
const char *
sb_get(string_buffer_t *s)
{
return s ? s->buffer : NULL;
}
char *
sb_get_copy(string_buffer_t *s)
{
char *str = NULL;
if ( s ) {
#ifdef EXIT_ON_ENOMEM
str = xmalloc(s->len + 1);
#else
if ( ! (str = malloc(s->len + 1)) )
return NULL;
#endif
strncpy(str, s->buffer, s->len);
}
return str;
}
size_t
sb_len(string_buffer_t *s)
{
return s ? s->len : 0;
}
int
sb_empty(string_buffer_t *s)
{
if ( ! s ) {
errno = EINVAL;
return -1;
}
s->buffer[0] = '\0';
s->len = 0;
return 0;
}
int
sb_addc(string_buffer_t *s, char c)
{
if ( ! s ) {
errno = EINVAL;
return -1;
}
if ( AVAILABLE_SIZE(s) < 1 )
GROW(s, 1);
*(s->buffer + s->len++) = c;
*(s->buffer + s->len) = '\0';
return 0;
}
int
sb_add(string_buffer_t *s, const char *buffer)
{
if ( ! buffer ) {
errno = EINVAL;
return -1;
}
return sb_addn(s, buffer, strlen(buffer));
}
int
sb_addn(string_buffer_t *s, const char *buffer, size_t len)
{
if ( ! s || ! buffer ) {
errno = EINVAL;
return -1;
}
if ( AVAILABLE_SIZE(s) < len )
GROW(s, len);
strncat(CURSOR(s), buffer, len);
s->len += len;
return 0;
}
int
sb_vaddf(string_buffer_t *s, const char *fmt, va_list ap)
{
int written;
va_list aq;
if ( ! s || ! fmt ) {
errno = EINVAL;
return -1;
}
va_copy(aq, ap);
written = vsnprintf(CURSOR(s), AVAILABLE_SIZE(s), fmt, aq);
va_end(aq);
if ( written >= AVAILABLE_SIZE(s) ) {
GROW(s, written);
vsprintf(CURSOR(s), fmt, ap);
}
s->len += written;
return 0;
}
int
sb_addf(string_buffer_t *s, const char *fmt, ...)
{
int ret;
va_list ap;
if ( ! s || ! fmt ) {
errno = EINVAL;
return -1;
}
va_start(ap, fmt);
ret = sb_vaddf(s, fmt, ap);
va_end(ap);
return ret;
}