Show misc_buf.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* implementation of 'buf_t'
*
* $Id: misc_buf.c,v 1.41 2006/10/29 17:55:55 girod Exp $
*/
char misc_buf_c_cvsid[] = "$Id: misc_buf.c,v 1.41 2006/10/29 17:55:55 girod Exp $";
#include <stdarg.h>
#include <errno.h>
/*
* Documentation on how to use a buf_t is found in include/misc_buf.h
*/
/**********************************************************************/
/*
* this EASYBUILD craziness is to break a circular dependency between
* libmisc and easybuild -- I want to use buf_t's as part of
* easybuild, but easybuild is needed to compile libmisc
*/
#ifdef EASYBUILD
#include "libmisc/include/misc_buf.h"
#include "libmisc/include/comparisons.h"
#else
#include "misc.h"
#endif
/*
* initialize an already allocated (e.g. stack-alloced) buf_t
*/
void buf_init(buf_t *b)
{
memset(b, 0, sizeof(buf_t));
bufcpy(b, "", 0);
}
/*
* create a new buf_t
*/
buf_t *buf_new()
{
buf_t *b = malloc(sizeof(buf_t));
if (b == NULL) {
#ifndef EASYBUILD
elog(LOG_CRIT, "Unable to alloc for buf!");
#endif
exit(1);
}
if (b)
buf_init(b);
return b;
}
/*
* destroy a buf_t
*/
void buf_free(buf_t *b)
{
if (b) {
if (b->buf)
free(b->buf);
free(b);
}
}
/*
* append additional information to a buf, possibly resizing it.
*
* NOTE: if src is NULL, it will just alloc space
* NOTE: These functions leave a null-termination at the end of all
* buffers, even for binary data.
*/
void bufcpy(buf_t *b, const void *src, int len)
{
if (len < 0)
return;
if (!b)
return;
/* if there's enough room in the current buffer (including one space
for terminating null), just copy into the existing buffer */
if (b->len + len < b->alloc_size) {
if (src) {
memcpy(b->empty, src, len);
buf_subsume(b, len);
}
} else {
/* otherwise, make the buffer bigger by allocing a new one. */
char *new_buf;
int new_size = exponential_roundup(b->len + len + 1);
if ((new_buf = realloc(b->buf, new_size)) == NULL) {
#ifndef EASYBUILD
elog(LOG_CRIT, "out of memory");
#endif
exit(1);
}
// printf("MALLOCING %d bytes\n", new_size);
/* change over */
b->buf = new_buf;
b->alloc_size = new_size;
b->empty = b->buf + b->len;
if (src) {
/* add the data from the buf the user just supplied */
memcpy(new_buf + b->len, src, len);
buf_subsume(b, len);
}
}
/* set the space after the last character to null */
*(b->empty) = '\0';
}
void bufcpy_zeroes(buf_t *b, int len)
{
bufcpy(b, NULL, len);
memset(b->empty, 0, len);
buf_subsume(b, len);
}
int buf_clear(buf_t *b, int dealloc)
{
if (dealloc) {
if (b->buf) free(b->buf);
buf_init(b);
return 0;
}
return buf_shorten(b, b->len);
}
void buf_swap(buf_t *a, buf_t *b)
{
buf_t tmp;
memmove(&tmp, a, sizeof(buf_t));
memmove(a, b, sizeof(buf_t));
memmove(b, &tmp, sizeof(buf_t));
}
void steal_to_buf(buf_t *a, char *mem_to_steal, int size)
{
if (a->buf) free(a->buf);
a->buf = mem_to_steal;
a->len = a->alloc_size = size;
a->empty = a->buf + size;
}
int buf_shorten(buf_t *b, int count)
{
if (count > b->len) {
#ifndef EASYBUILD
elog(LOG_WARNING, "buf is %d bytes long, can't shorten by %d bytes",
b->len, count);
#endif
return -1;
}
b->len -= count;
b->empty -= count;
return b->len;
}
int buf_remove(buf_t *buf, int start, int count)
{
if (buf_shorten(buf, count) >= 0) {
memmove(buf->buf + start,
buf->buf + start + count, buf->len - start);
return buf->len;
}
return -1;
}
void bufprintf(buf_t *b, const char *fmt, ...)
{
va_list ap;
char tmp[32768];
int len;
/* print the string to a temp buffer. too bad we don't have
* asprintf generally available yet. */
va_start(ap, fmt);
len = vsnprintf(tmp, sizeof(tmp), fmt, ap);
bufcpy(b, tmp, len);
va_end(ap);
}
int bufcmp(buf_t *buf1, buf_t *buf2)
{
int buf1_missing = (buf1 == NULL || buf1->len == 0);
int buf2_missing = (buf2 == NULL || buf2->len == 0);
int min_len;
int result;
/* both missing */
if (buf1_missing && buf2_missing)
return 0;
/* one missing */
if (buf1_missing) return -1;
if (buf2_missing) return +1;
/* both strings present, differ */
min_len = i_min(buf1->len, buf2->len);
result = memcmp(buf1->buf, buf2->buf, min_len);
if (result) return result;
/* one is prefix of other */
if (buf1->len > min_len) return +1;
if (buf2->len > min_len) return -1;
return 0;
}
void buf_print_raw(buf_t *buf, char *str, int len)
{
int i;
for (i=0; i<len; i++) {
if (str[i] == '%')
bufprintf(buf, "%%25");
else if (isprint(str[i]))
bufprintf(buf, "%c", str[i]);
else
bufprintf(buf, "%%%02X", (uint8_t)str[i]);
}
}
char *buf_get(buf_t *buf)
{ return buf->buf; }
size_t buf_len(buf_t *buf)
{ return buf->len; }
void bufcat(buf_t *to, const buf_t *from)
{
bufcpy(to, from->buf, from->len);
}
void buf_insert(buf_t *b, uint32_t offset, const void *src, uint32_t len)
{
if (offset > b->len) {
#ifndef EASYBUILD
elog(LOG_WARNING, "inserting past end of buf");
#endif
return;
}
/* copy to maybe extend */
bufcpy(b, src, len);
if (src == NULL)
buf_subsume(b, len);
/* open space and copy */
int move_length = b->len - offset - len;
if (move_length > 0) {
memmove(b->buf + offset + len, b->buf + offset, move_length);
if (src)
memmove(b->buf + offset, src, len);
else
memset(b->buf + offset, 0, len);
}
}
int file_to_buf(buf_t *buf, const char *filename)
{
int status;
char rd_buf[4096];
int fd = open(filename, O_RDONLY);
if (fd < 0) return -1;
while (1) {
status = read(fd, rd_buf, sizeof(rd_buf));
if (status < 0) {
close(fd);
return -1;
}
if (status == 0) {
close(fd);
return buf->len;
}
bufcpy(buf, rd_buf, status);
}
}
int buf_to_file(const char *filename, buf_t *buf)
{
int status = 0;
int temp = 0;
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
if (fd <= 0) {
return errno;
}
while (status < buf->len) {
temp = write(fd, buf->buf + status, buf->len - status);
if (temp < 0) {
close(fd);
return errno;
}
status += temp;
}
close(fd);
return 0;
}
int buf_pop_chars(buf_t *buf, int count)
{
if (count == 0)
return 0;
if (buf->len < count)
return -1;
buf_shorten(buf, count);
memmove(buf->buf, buf->buf+count, buf->len);
return count;
}
/*
* pre-allocation support
*/
void buf_prealloc(buf_t *buf, size_t space)
{
if (buf_get_prealloc_len(buf) < space) {
bufcpy(buf, NULL, space - buf_get_prealloc_len(buf));
}
}
int buf_subsume(buf_t *b, size_t len)
{
if (len <= buf_get_prealloc_len(b)) {
b->len += len;
b->empty += len;
return 0;
}
return -1;
}
char *buf_get_prealloc_buf(buf_t *buf)
{
return buf->buf + buf->len;
}
size_t buf_get_prealloc_len(buf_t *buf)
{
return buf->alloc_size - buf->len - 1;
}
size_t buf_get_allocated_len(buf_t *buf)
{
return buf->alloc_size;
}
/*
* buf_t item iterators
* the buf_t item iterator appends and traverses a buf_t composed of a
* series of items, each of which is preceded by a length field.
*/
struct buf_iter {
buf_t *buf;
int cursor;
};
buf_iter_t *buf_item_iter_new(buf_t *buf)
{
buf_iter_t *iter = (buf_iter_t*)malloc(sizeof(buf_iter_t));
iter->buf = buf;
iter->cursor = 0;
return iter;
}
void buf_item_iter_set(buf_iter_t *to, buf_iter_t *from)
{
memmove(to, from, sizeof(buf_iter_t));
}
void buf_item_iter_destroy(buf_iter_t *iter, int free_buf)
{
if (iter) {
if (free_buf && iter->buf) buf_free(iter->buf);
free(iter);
}
}
static
item_size_t buf_item_iter_length_aux(buf_iter_t *iter)
{
item_size_t len;
memmove(&len, iter->buf->buf + iter->cursor, sizeof(item_size_t));
return len;
}
int buf_item_iter_valid(buf_iter_t *iter)
{
if (iter && ((iter->buf->len - iter->cursor) >= sizeof(item_size_t))) {
item_size_t len = buf_item_iter_length_aux(iter);
if (len + iter->cursor + sizeof(item_size_t) > iter->buf->len)
return -1;
return 1;
}
return 0;
}
item_size_t buf_item_iter_length(buf_iter_t *iter)
{
if (buf_item_iter_valid(iter))
return buf_item_iter_length_aux(iter);
return 0;
}
int buf_item_iter_next(buf_iter_t *iter)
{
if (buf_item_iter_valid(iter))
iter->cursor += (sizeof(item_size_t) + buf_item_iter_length_aux(iter));
return buf_item_iter_valid(iter);
}
void buf_item_iter_top(buf_iter_t *iter)
{
iter->cursor = 0;
}
void buf_item_iter_remove(buf_iter_t *iter)
{
if (buf_item_iter_valid(iter)) {
buf_remove(iter->buf, iter->cursor,
buf_item_iter_length_aux(iter) + sizeof(item_size_t));
}
}
buf_t *buf_item_iter_get_buf(buf_iter_t *iter, buf_t *into)
{
if (buf_item_iter_valid(iter)) {
if (into == NULL)
into = buf_new();
bufcpy(into, iter->buf->buf + iter->cursor + sizeof(item_size_t),
buf_item_iter_length_aux(iter));
return into;
}
return NULL;
}
char *buf_item_iter_get_pointer(buf_iter_t *iter, int min_valid_length)
{
if ((min_valid_length < 0) ||
(buf_item_iter_length(iter) >= min_valid_length))
return iter->buf->buf + iter->cursor + sizeof(item_size_t);
return NULL;
}
void buf_item_iter_append_str(buf_iter_t *iter, const char *str, int len)
{
item_size_t length = len;
bufcpy(iter->buf, (char*)&length, sizeof(length));
bufcpy(iter->buf, str, len);
}
void buf_item_iter_append_buf(buf_iter_t *iter, buf_t *buf)
{
buf_item_iter_append_str(iter, buf->buf, buf->len);
}
See more files for this project here