Mercurial > code
view buf.c @ 136:c6d9eb5702e8
array:
o add ARRAY_FASTREMOVE, use last object when removing,
o add ARRAY_CLEARBITS, set to 0 the bytes when removing
parray:
o add PARRAY_FASTREMOVE, use last object when removing,
o add PARRAY_NULLEND, always has a last NULL entry
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 26 Mar 2012 10:24:49 +0200 |
parents | d85dd98cb49d |
children | cf738da3ad60 |
line wrap: on
line source
/* * buf.c -- easy way to manipulate strings * * Copyright (c) 2011, 2012, David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "buf.h" #define BUF_AVAIL(buf) ((buf)->alsize - (buf)->length) #define BUF_SAFE(buf) (!((buf)->flags & BUF_UNSAFE)) #define BUF_FIXED(buf) ((buf)->flags & BUF_FIXED) #define BUF_AUTO(buf) (buf->flags == 0) static void copy(struct buf *, const void *, size_t); static int grow(struct buf *, size_t); int buf_init(struct buf *buf) { /* Set defaults if needed */ buf->bsize = (buf->bsize <= 0) ? BUF_DEFAULT_BSIZE : buf->bsize; buf->alsize = buf->bsize + 1; buf->malloc = (buf->malloc == NULL) ? &malloc : buf->malloc; buf->realloc = (buf->realloc == NULL) ? &realloc : buf->realloc; if ((buf->text = buf->malloc(buf->alsize)) == NULL) return -1; memset(buf->text, 0, buf->alsize); return 0; } /* * Valid options that can be set for a buffer : * l -> optional buf block size of type int * m -> malloc function that must matches void * (*malloc)(size_t) * r -> realloc function that must matches void * (*realloc)(void *, size_t) * f -> buffer flags that are OR'ed */ void buf_set(struct buf *buf, const char *fmt, ...) { va_list ap; const char *p; va_start(ap, fmt); for (p = fmt; *p != '\0'; ++p) switch (*p) { case 'l': buf->bsize = va_arg(ap, int); break; case 'm': buf->malloc = va_arg(ap, void *(*)(size_t)); break; case 'r': buf->realloc = va_arg(ap, void *(*)(void *, size_t)); break; case 'f': case 't': buf->flags = va_arg(ap, int); break; default: break; } } /* * This function appends not more than max characters from str. */ int buf_ncat(struct buf *buf, const char *str, size_t max) { size_t tocopy = max; for (tocopy = 0; str[tocopy] != '\0' && tocopy < max; ++tocopy) continue; if (BUF_AVAIL(buf) <= tocopy) { /* Can't add more */ if (BUF_SAFE(buf) && BUF_FIXED(buf)) return -1; if (BUF_AUTO(buf)) { if (grow(buf, tocopy) < 0) return -1; } else { /* String is unsafe, truncate to the available size */ tocopy = BUF_AVAIL(buf) - 1; } } copy(buf, str, tocopy); return 0; } /* * Append the string str to the end of the string buffer. */ int buf_cat(struct buf *buf, const char *str) { return buf_ncat(buf, str, strlen(str)); } /* * Append the caracter c to the end of buffer */ int buf_putc(struct buf *buf, int c) { return buf_printf(buf, "%c", c); } /* * Concatenate the printf(3) like call to the string buffer, this function * returns -1 on fixed safe buffer, otherwise 0 is returned if there * is no allocation failure. */ int buf_vprintf(struct buf *buf, const char *fmt, va_list ap) { int copied, rv = 0, done = 0; if (BUF_FIXED(buf) && BUF_SAFE(buf)) return -1; do { copied = vsnprintf(&buf->text[buf->length], BUF_AVAIL(buf), fmt, ap); if (copied >= (signed int)BUF_AVAIL(buf) || copied == -1) { if (BUF_FIXED(buf)) done = 1; /* * vsnprintf returns -1 on windows, we need to grow * the buffer by block size. */ if (grow(buf, buf->alsize + buf->bsize) < 0) { done = 1; rv = -1; } } else { done = 1; } } while (!done); buf->length = strlen(buf->text); return rv; } int buf_printf(struct buf *buf, const char *fmt, ...) { va_list ap; int rv; va_start(ap, fmt); rv = buf_vprintf(buf, fmt, ap); va_end(ap); return rv; } /* * Realloc the string to it's size and remove useless bytes. */ int buf_trim(struct buf *buf) { if ((buf->text = realloc(buf->text, buf->length + 1)) == NULL) { buf->alsize = 0; return -1; } buf->alsize = buf->length + 1; return 0; } /* * Clear the string buffer. */ void buf_clear(struct buf *buf) { memset(buf->text, 0, buf->alsize); buf->length = 0; } void buf_free(struct buf *buf) { if (buf != NULL) { buf_clear(buf); free(buf->text); buf->text = NULL; buf->alsize = 0; } } /* * Append to the end of buffer the void ptr of count size. */ static void copy(struct buf *buf, const void *ptr, size_t count) { memcpy(buf->text + buf->length, ptr, count); buf->text[buf->length + count] = '\0'; buf->length += count; } /* * Grow the text buffer until the available size fit the needed * size. This function may return -1 on allocation failure. */ static int grow(struct buf *buf, size_t needed) { while (BUF_AVAIL(buf) <= needed) { buf->text = buf->realloc(buf->text, buf->alsize + buf->bsize); if (buf->text == NULL) return -1; buf->alsize += buf->bsize; } return 0; }