/* mastring.c -- Implement auto-allocating string functions.
*
* (C) 2001 - 2002 by Matthias Andree <matthias.andree@gmx.de>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 or 2.1 of
* the License. See the file COPYING.LGPL for details.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include "wantassert.h"
#include <assert.h>
#define len PRIVATE__len
#define dat PRIVATE__dat
#define bufsize PRIVATE__bufsize
#include "mastring.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif
#include "getline.h"
static inline /*@exits@*/ void
mastr_oom(void)
#if defined(MASTR_OOM_ABORT) && defined(__GNUC__)
__attribute__ ((noreturn))
#endif
;
/*@noreturn@*/
static inline void
mastr_oom(void)
{
#ifdef MASTR_OOM_ABORT
abort();
#endif
}
#undef min
#define min(a,b) ((a < b) ? (a) : (b))
mastr *
mastr_new(size_t size)
{
mastr *n;
assert(size != 0);
n = (mastr *)malloc(sizeof(mastr));
if (!n) {
mastr_oom();
/*@notreached@*/ return NULL;
}
n->bufsize = size + 1;
if (!(n->dat = (char *)malloc(n->bufsize))) {
free(n);
mastr_oom();
/*@notreached@*/ return NULL;
}
n->dat[0] = '\0';
n->len = 0;
return n;
}
mastr *
mastr_newstr(const char *s)
{
size_t l;
mastr *n;
if (!s)
return NULL;
n = mastr_new((l = strlen(s)));
if (!n)
return NULL;
memcpy(n->dat, s, l + 1);
n->len = l;
return n;
}
int
mastr_cpy(mastr * m, const char *s)
{
size_t l;
if (!m || !s)
return 0;
if ((l = strlen(s)) >= m->bufsize)
if (0 == mastr_resizekill(m, l)) {
mastr_oom();
/*@notreached@*/ return 0;
}
memcpy(m->dat, s, l + 1);
m->len = l;
return 1;
}
int
mastr_cat(mastr * m, /*@unique@*/ /*@observer@*/ const char *const s)
{
size_t li;
if (!m || !s)
return 0;
if ((li = strlen(s)) + m->len >= m->bufsize)
if (0 == mastr_resizekeep(m, li + m->len)) {
mastr_oom();
/*@notreached@*/ return 0;
}
memcpy(m->dat + m->len, s, li + 1);
m->len += li;
return 1;
}
void
mastr_clear(mastr * m)
{
if (!m)
return;
m->len = 0;
m->dat[0] = '\0';
}
int
mastr_vcat(mastr * m, ...)
{
long addlen = 0;
const char *t;
char *u;
va_list v;
if (!m)
return 0;
/* get length */
va_start(v, m);
while ((t = va_arg(v, const char *))) {
addlen += strlen(t);
}
va_end(v);
if (m->len + addlen >= m->bufsize) {
if (!mastr_resizekeep(m, addlen + m->len)) {
mastr_oom();
/*@notreached@*/ return 0;
}
}
va_start(v, m);
u = m->dat + m->len;
while ((t = va_arg(v, const char *))) {
while ((*u = *t++))
u++;
}
m->len += addlen;
va_end(v);
return 1;
}
int
mastr_resizekill(mastr * m, size_t l)
{
char *n;
if (!m)
return 0;
n = (char *)malloc(l + 1);
if (!n) {
mastr_oom();
/*@notreached@*/ return 0;
}
free(m->dat);
m->dat = n;
m->bufsize = l + 1;
m->dat[0] = '\0';
m->len = 0;
return 1;
}
int
mastr_resizekeep(mastr * m, size_t l)
{
char *n;
if (!m)
return 0;
n = (char *)realloc(m->dat, l + 1);
if (!n) {
free(m->dat);
mastr_oom();
/*@notreached@*/ return 0;
}
m->dat = n;
m->bufsize = l + 1;
m->dat[l] = '\0';
if (l < m->len)
m->len = l;
return 1;
}
void
mastr_delete(/*@only@*/ mastr * m)
{
if (m) {
free(m->dat);
free(m);
}
}
void
mastr_triml(mastr * m)
{
char *p, *q;
if (!m)
return;
p = q = m->dat;
while (*p && isspace((unsigned char)*p))
p++;
if (p != q) {
/*@-whileempty@*/
while ((*q++ = *p++));
/*@=whileempty@*/
m->len -= p - q;
}
}
void
mastr_trimr(mastr * m)
{
char *p;
if (!m)
return;
p = m->dat + m->len;
/*@-whileempty@*/
while (--p >= m->dat && isspace((unsigned char)*p));
/*@=whileempty@*/
*++p = '\0';
m->len = (size_t)(p - m->dat);
}
#if LEAFNODE_VERSION > 1
ssize_t
mastr_getln(mastr * m, FILE * f,
ssize_t maxbytes /** if negative: unlimited */ )
{
/* FIXME: make this overflow safe, size_t vs. ssize_t. */
char buf[4096];
ssize_t bufsiz = (ssize_t)sizeof buf;
ssize_t r;
mastr_clear(m);
for (;;) {
r = _getline(buf,
(size_t)(maxbytes > 0 ? min(bufsiz, maxbytes+1) : bufsiz),
f);
if (r < 0)
return r;
if (r == 0)
break;
if (r + m->len >= m->bufsize)
if (!mastr_resizekeep(m, r + m->len)) {
mastr_oom();
/*@notreached@*/ return 0;
}
memcpy(m->dat + m->len, buf, (size_t)r); /* FIXME: avoid this copy */
if (maxbytes > 0)
maxbytes -= r;
m->len += r;
m->dat[m->len] = '\0';
if (memchr(buf, '\n', (size_t)r) != NULL)
break;
}
return (ssize_t)(m->len);
}
#endif
/* chop off last character of string */
static void
choplast(mastr * m)
{
if (m && m->len) {
--m->len;
m->dat[m->len] = '\0';
}
}
/** chop off trailing LF or CRLF */
void
mastr_chop(mastr * m)
{
if (m && m->len && m->dat[m->len - 1] == '\n')
choplast(m);
if (m && m->len && m->dat[m->len - 1] == '\r')
choplast(m);
}
/** return size of buffer */
size_t
mastr_size(mastr * m)
{
return m->bufsize - 1;
}
/** return length of buffer */
size_t
mastr_len(mastr * m)
{
return m->len;
}
syntax highlighted by Code2HTML, v. 0.9.1