/* mastring.c -- Implement auto-allocating string functions. * * (C) 2001 - 2002 by Matthias Andree * * 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 #include #include #include #include "wantassert.h" #include #define len PRIVATE__len #define dat PRIVATE__dat #define bufsize PRIVATE__bufsize #include "mastring.h" #ifdef WITH_DMALLOC #include #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; }