Mercurial > code
view buf.c @ 175:73d8f140bc86
Add some getters
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 12 Sep 2013 13:36:12 +0200 |
parents | 7f214f26a4c0 |
children |
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, 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; }