diff options
Diffstat (limited to 'src/core/librcutil/dynbuf.c')
-rw-r--r-- | src/core/librcutil/dynbuf.c | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/src/core/librcutil/dynbuf.c b/src/core/librcutil/dynbuf.c new file mode 100644 index 0000000..b6f6cdc --- /dev/null +++ b/src/core/librcutil/dynbuf.c @@ -0,0 +1,407 @@ +/* + * dynbuf.c + * + * Dynamic allocated buffers. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "rcscripts/rcutil.h" + +static dyn_buf_t *reallocate_dyn_buf (dyn_buf_t *dynbuf, size_t needed); + +dyn_buf_t * +new_dyn_buf (void) +{ + dyn_buf_t *dynbuf = NULL; + + dynbuf = xmalloc (sizeof (dyn_buf_t)); + if (NULL == dynbuf) + return NULL; + + dynbuf->data = xmalloc (DYNAMIC_BUFFER_SIZE); + if (NULL == dynbuf->data) + { + free (dynbuf); + return NULL; + } + + dynbuf->length = DYNAMIC_BUFFER_SIZE; + dynbuf->rd_index = 0; + dynbuf->wr_index = 0; + dynbuf->file_map = FALSE; + + return dynbuf; +} + +dyn_buf_t * +new_dyn_buf_mmap_file (const char *name) +{ + dyn_buf_t *dynbuf = NULL; + + dynbuf = xmalloc (sizeof (dyn_buf_t)); + if (NULL == dynbuf) + return NULL; + + if (-1 == rc_file_map (name, &dynbuf->data, &dynbuf->length)) + { + DBG_MSG ("Failed to mmap file '%s'\n", name); + free (dynbuf); + + return NULL; + } + + dynbuf->wr_index = dynbuf->length; + dynbuf->rd_index = 0; + dynbuf->file_map = TRUE; + + return dynbuf; +} + +dyn_buf_t * +reallocate_dyn_buf (dyn_buf_t *dynbuf, size_t needed) +{ + int len; + + if (!check_arg_dyn_buf (dynbuf)) + return NULL; + + if (dynbuf->file_map) + { + errno = EPERM; + DBG_MSG ("Cannot reallocate mmap()'d file!\n"); + + return NULL; + } + + len = sizeof (char) * (dynbuf->wr_index + needed + 1); + + if (dynbuf->length < len) + { + char *new_ptr; + + /* Increase size in chunks to minimize reallocations */ + if (len < (dynbuf->length + DYNAMIC_BUFFER_SIZE)) + len = dynbuf->length + DYNAMIC_BUFFER_SIZE; + + new_ptr = xrealloc (dynbuf->data, len); + if (NULL == new_ptr) + return NULL; + + dynbuf->data = new_ptr; + dynbuf->length = len; + } + + return dynbuf; +} + +void +free_dyn_buf (dyn_buf_t *dynbuf) +{ + if (NULL == dynbuf) + return; + + if (!dynbuf->file_map) + { + if (NULL != dynbuf->data) + { + free (dynbuf->data); + dynbuf->data = NULL; + } + } + else + { + save_errno (); + rc_file_unmap (dynbuf->data, dynbuf->length); + restore_errno (); + } + + dynbuf->length = 0; + dynbuf->rd_index = 0; + dynbuf->wr_index = 0; + + free (dynbuf); + dynbuf = NULL; +} + +int +write_dyn_buf (dyn_buf_t *dynbuf, const char *buf, size_t length) +{ + int len; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_str (buf)) + return -1; + + if (dynbuf->file_map) + { + errno = EPERM; + DBG_MSG ("Cannot write to readonly mmap()'d file!\n"); + + return -1; + } + + if (NULL == reallocate_dyn_buf (dynbuf, length)) + { + DBG_MSG ("Could not reallocate dynamic buffer!\n"); + return -1; + } + + len = snprintf ((dynbuf->data + dynbuf->wr_index), length + 1, "%s", buf); + + /* If len is less than length, it means the string was shorter than + * given length */ + if (length > len) + length = len; + + if (0 < length) + dynbuf->wr_index += length; + + if (-1 == length) + DBG_MSG ("Failed to write to dynamic buffer!\n"); + + return length; +} + +int write_dyn_buf_from_fd (int fd, dyn_buf_t *dynbuf, size_t length) +{ + int len = length; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_fd (fd)) + return -1; + + if (dynbuf->file_map) + { + errno = EPERM; + DBG_MSG ("Cannot write to readonly mmap()'d file!\n"); + + return -1; + } + + if (NULL == reallocate_dyn_buf (dynbuf, length)) + { + DBG_MSG ("Could not reallocate dynamic buffer!\n"); + return -1; + } + + len = read (fd, (dynbuf->data + dynbuf->wr_index), len); + + if (length > len) + length = len; + + if (0 < length) + dynbuf->wr_index += length; + + dynbuf->data[dynbuf->wr_index] = '\0'; + + if (-1 == length) + DBG_MSG ("Failed to write to dynamic buffer!\n"); + + return length; +} + +int +sprintf_dyn_buf (dyn_buf_t *dynbuf, const char *format, ...) +{ + va_list arg1, arg2; + char test_str[10]; + int needed, written = 0; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_str (format)) + return -1; + + if (dynbuf->file_map) + { + errno = EPERM; + DBG_MSG ("Cannot write to readonly mmap()'d file!\n"); + + return -1; + } + + va_start (arg1, format); + va_copy (arg2, arg1); + + /* XXX: Lame way to try and figure out how much space we need */ + needed = vsnprintf (test_str, sizeof (test_str), format, arg2); + va_end (arg2); + + if (NULL == reallocate_dyn_buf (dynbuf, needed)) + { + DBG_MSG ("Could not reallocate dynamic buffer!\n"); + return -1; + } + + written = vsnprintf ((dynbuf->data + dynbuf->wr_index), needed + 1, + format, arg1); + va_end (arg1); + + if (0 < written) + dynbuf->wr_index += written; + + if (-1 == written) + DBG_MSG ("Failed to write to dynamic buffer!\n"); + + return written; +} + +int +read_dyn_buf (dyn_buf_t *dynbuf, char *buf, size_t length) +{ + int len = length; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_ptr (buf)) + return -1; + + if (dynbuf->rd_index >= dynbuf->length) + return 0; + + if (dynbuf->wr_index < (dynbuf->rd_index + length)) + len = dynbuf->wr_index - dynbuf->rd_index; + + len = snprintf (buf, len + 1, "%s", (dynbuf->data + dynbuf->rd_index)); + + /* If len is less than length, it means the string was shorter than + * given length */ + if (length > len) + length = len; + + if (0 < length) + dynbuf->rd_index += length; + + if (-1 == length) + DBG_MSG ("Failed to write from dynamic buffer!\n"); + + return length; +} + +int +read_dyn_buf_to_fd (int fd, dyn_buf_t *dynbuf, size_t length) +{ + int len = length; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_fd (fd)) + return -1; + + if (dynbuf->rd_index >= dynbuf->length) + return 0; + + if (dynbuf->wr_index < (dynbuf->rd_index + length)) + len = dynbuf->wr_index - dynbuf->rd_index; + + len = write (fd, (dynbuf->data + dynbuf->rd_index), len); + if (length > len) + length = len; + + if (0 < length) + dynbuf->rd_index += length; + + if (-1 == length) + DBG_MSG ("Failed to write from dynamic buffer!\n"); + + return length; +} + +char * +read_line_dyn_buf (dyn_buf_t *dynbuf) +{ + char *buf = NULL; + size_t count = 0; + + if (!check_arg_dyn_buf (dynbuf)) + return NULL; + + if (dynbuf->rd_index == dynbuf->wr_index) + return NULL; + + for (count = dynbuf->rd_index; count < dynbuf->wr_index && dynbuf->data[count] != '\n'; count++); + + if (count <= dynbuf->wr_index) + { + buf = xstrndup ((dynbuf->data + dynbuf->rd_index), + (count - dynbuf->rd_index)); + if (NULL == buf) + return NULL; + + dynbuf->rd_index = count; + + /* Also skip the '\n' .. */ + if (dynbuf->rd_index < dynbuf->wr_index) + dynbuf->rd_index++; + } + + return buf; +} + +bool +dyn_buf_rd_eof (dyn_buf_t *dynbuf) +{ + if (!check_arg_dyn_buf (dynbuf)) + return FALSE; + + if (dynbuf->rd_index >= dynbuf->wr_index) + return TRUE; + + return FALSE; +} + +inline bool +check_dyn_buf (dyn_buf_t *dynbuf) +{ + if ((NULL == dynbuf) || (NULL == dynbuf->data) || (0 == dynbuf->length)) + return FALSE; + + return TRUE; +} + +inline bool +__check_arg_dyn_buf (dyn_buf_t *dynbuf, const char *file, const char *func, + size_t line) +{ + if (!check_dyn_buf (dynbuf)) + { + errno = EINVAL; + + debug_message (file, func, line, "Invalid dynamic buffer passed!\n"); + + return FALSE; + } + + return TRUE; +} + |