Mercurial > code
diff C/buf.c @ 186:d4b8416e9ab1
Move C
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 23 Nov 2013 16:14:05 +0100 |
parents | buf.c@7f214f26a4c0 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/buf.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,268 @@ +/* + * 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, const char *txt) +{ + /* Set defaults if needed */ + buf->chksize = (buf->chksize <= 0) ? 128 : buf->chksize; + buf->alsize = buf->chksize + 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; + + if (txt != NULL) + buf_cat(buf, txt); + + memset(buf->text, 0, buf->alsize); + + return 0; +} + +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->chksize = 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) +{ + char str[2] = { c, '\0' }; + + return buf_ncat(buf, str, 1); +} + +/* + * 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->chksize) < 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; +} + +/* + * Remove `n' characters from the buffer, a positive value will cut the string + * from beginning, negative value will cut from end. + */ +void +buf_cut(struct buf *buf, int start) +{ + if ((start > 0 && start >= buf->length) || + (start < 0 && (int)buf->length + start < 0)) + return; + + if (start < 0 && (int)buf->length + start >= 0) + start = buf->length + start; + + buf->text[start] = '\0'; + buf->length -= buf->length - start; +} + +/* + * 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->chksize); + + if (buf->text == NULL) + return -1; + + buf->alsize += buf->chksize; + } + + return 0; +}