/* ** OSSP cfg - Configuration Parsing ** Copyright (c) 2002-2006 Ralf S. Engelschall ** Copyright (c) 2002-2006 The OSSP Project (http://www.ossp.org/) ** ** This file is part of OSSP cfg, a configuration parsing ** library which can be found at http://www.ossp.org/pkg/lib/cfg/. ** ** Permission to use, copy, modify, and 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. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** 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. ** ** cfg_buf.c: auto-resizing buffer */ #include #include #include #include "cfg.h" #include "cfg_buf.h" #include "cfg_fmt.h" #include "cfg_global.h" /* opaque buffer data structure */ struct cfg_buf_st { char *buf_ptr; /* pointer to buffer start */ size_t buf_size; /* total size of buffer in bytes */ size_t buf_len; /* character length of string in buffer */ /* (not counting NUL-termination) */ }; /* create a new buffer object */ cfg_rc_t cfg_buf_create(cfg_buf_t **buf) { if (buf == NULL) return CFG_ERR_ARG; if ((*buf = (cfg_buf_t *)malloc(sizeof(cfg_buf_t))) == NULL) return CFG_ERR_SYS; (*buf)->buf_ptr = NULL; (*buf)->buf_len = 0; (*buf)->buf_size = 0; return CFG_OK; } /* resize (destroy, expand or shrink) the buffer */ cfg_rc_t cfg_buf_resize(cfg_buf_t *buf, signed int n) { char *cp; if (buf == NULL) return CFG_ERR_ARG; if (n == 0) { /* special case: destroy buffer */ if (buf->buf_ptr != NULL) free(buf->buf_ptr); buf->buf_ptr = NULL; buf->buf_len = 0; buf->buf_size = 0; } else { /* shrink or grow buffer */ if (buf->buf_ptr == NULL) { if ((buf->buf_ptr = malloc(n+1)) == NULL) return CFG_ERR_SYS; buf->buf_size = n+1; buf->buf_len = 0; *buf->buf_ptr = '\0'; } else { if ((cp = realloc(buf->buf_ptr, buf->buf_size+n)) == NULL) return CFG_ERR_SYS; buf->buf_ptr = cp; buf->buf_size += n; if (buf->buf_len >= buf->buf_size) { buf->buf_len = buf->buf_size-1; *(buf->buf_ptr + buf->buf_len) = '\0'; } } } return CFG_OK; } /* append a string and/or single character to the buffer */ cfg_rc_t cfg_buf_append(cfg_buf_t *buf, const char *str, size_t len, char c) { cfg_rc_t rc; if (buf == NULL) return CFG_ERR_ARG; if (str != NULL) { if (len == 0) len = strlen(str); if ((rc = cfg_buf_resize(buf, len)) != CFG_OK) return rc; memcpy(buf->buf_ptr + buf->buf_len, str, len); buf->buf_len += len; } if (c != '\0') { if ((rc = cfg_buf_resize(buf, 1)) != CFG_OK) return rc; *(buf->buf_ptr + buf->buf_len) = c; buf->buf_len++; } *(buf->buf_ptr + buf->buf_len) = '\0'; return CFG_OK; } /* remove a trailing string from the buffer */ cfg_rc_t cfg_buf_remove(cfg_buf_t *buf, const char *str, size_t len) { if (buf == NULL || len == 0) return CFG_ERR_ARG; if (len > buf->buf_len) return CFG_ERR_USE; if (str != NULL) memcpy((void *)str, buf->buf_ptr + buf->buf_len - len, len + 1); buf->buf_len -= len; *(buf->buf_ptr + buf->buf_len) = '\0'; return CFG_OK; } /* append a formatted string to the buffer */ cfg_rc_t cfg_buf_format(cfg_buf_t *buf, const char *fmt, ...) { va_list ap; cfg_rc_t rc; va_start(ap, fmt); rc = cfg_buf_vformat(buf, fmt, ap); va_end(ap); return rc; } /* append a formatted string to the buffer (va_list based) */ cfg_rc_t cfg_buf_vformat(cfg_buf_t *buf, const char *fmt, va_list ap) { cfg_rc_t rc; int n; if (buf == NULL || fmt == NULL) return CFG_ERR_ARG; if ((n = cfg_fmt_vsprintf(NULL, -1, fmt, ap)) == -1) return CFG_ERR_FMT; if ((rc = cfg_buf_resize(buf, n)) != CFG_OK) return rc; if ((n = cfg_fmt_vsprintf(buf->buf_ptr + buf->buf_len, buf->buf_size - buf->buf_len, fmt, ap)) == -1) return CFG_ERR_FMT; buf->buf_len += n; return CFG_OK; } /* return the buffer string */ cfg_rc_t cfg_buf_content(cfg_buf_t *buf, char **ptr, size_t *len, size_t *size) { if (buf == NULL) return CFG_ERR_ARG; if (len != NULL) *len = buf->buf_len; if (size != NULL) *size = buf->buf_size; if (ptr != NULL) { if (buf->buf_ptr == NULL) *ptr = strdup(""); else { *ptr = buf->buf_ptr; buf->buf_ptr = NULL; buf->buf_size = 0; buf->buf_len = 0; } } return CFG_OK; } /* destroy buffer object */ cfg_rc_t cfg_buf_destroy(cfg_buf_t *buf) { if (buf == NULL) return CFG_ERR_ARG; if (buf->buf_ptr != NULL) free(buf->buf_ptr); free(buf); return CFG_OK; }