1/* 2 * Copyright (c) 2015, Juniper Networks, Inc. 3 * All rights reserved. 4 * This SOFTWARE is licensed under the LICENSE provided in the 5 * ../Copyright file. By downloading, installing, copying, or otherwise 6 * using the SOFTWARE, you agree to be bound by the terms of that 7 * LICENSE. 8 * Phil Shafer, August 2015 9 */ 10 11/* 12 * This file is an _internal_ part of the libxo plumbing, not suitable 13 * for external use. It is not considered part of the libxo API and 14 * will not be a stable part of that API. Mine, not your's, dude... 15 * The real hope is that something like this will become a standard part 16 * of libc and I can kill this off. 17 */ 18 19#ifndef XO_BUF_H 20#define XO_BUF_H 21 22#define XO_BUFSIZ (8*1024) /* Initial buffer size */ 23#define XO_BUF_HIGH_WATER (XO_BUFSIZ - 512) /* When to auto-flush */ 24/* 25 * xo_buffer_t: a memory buffer that can be grown as needed. We 26 * use them for building format strings and output data. 27 */ 28typedef struct xo_buffer_s { 29 char *xb_bufp; /* Buffer memory */ 30 char *xb_curp; /* Current insertion point */ 31 ssize_t xb_size; /* Size of buffer */ 32} xo_buffer_t; 33 34/* 35 * Initialize the contents of an xo_buffer_t. 36 */ 37static inline void 38xo_buf_init (xo_buffer_t *xbp) 39{ 40 xbp->xb_size = XO_BUFSIZ; 41 xbp->xb_bufp = xo_realloc(NULL, xbp->xb_size); 42 xbp->xb_curp = xbp->xb_bufp; 43} 44 45/* 46 * Reset the buffer to empty 47 */ 48static inline void 49xo_buf_reset (xo_buffer_t *xbp) 50{ 51 xbp->xb_curp = xbp->xb_bufp; 52} 53 54/* 55 * Return the number of bytes left in the buffer 56 */ 57static inline int 58xo_buf_left (xo_buffer_t *xbp) 59{ 60 return xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); 61} 62 63/* 64 * See if the buffer to empty 65 */ 66static inline int 67xo_buf_is_empty (xo_buffer_t *xbp) 68{ 69 return (xbp->xb_curp == xbp->xb_bufp); 70} 71 72/* 73 * Return the current offset 74 */ 75static inline ssize_t 76xo_buf_offset (xo_buffer_t *xbp) 77{ 78 return xbp ? (xbp->xb_curp - xbp->xb_bufp) : 0; 79} 80 81static inline char * 82xo_buf_data (xo_buffer_t *xbp, ssize_t offset) 83{ 84 if (xbp == NULL) 85 return NULL; 86 return xbp->xb_bufp + offset; 87} 88 89static inline char * 90xo_buf_cur (xo_buffer_t *xbp) 91{ 92 if (xbp == NULL) 93 return NULL; 94 return xbp->xb_curp; 95} 96 97/* 98 * Initialize the contents of an xo_buffer_t. 99 */ 100static inline void 101xo_buf_cleanup (xo_buffer_t *xbp) 102{ 103 if (xbp->xb_bufp) 104 xo_free(xbp->xb_bufp); 105 bzero(xbp, sizeof(*xbp)); 106} 107 108/* 109 * Does the buffer have room for the given number of bytes of data? 110 * If not, realloc the buffer to make room. If that fails, we 111 * return 0 to tell the caller they are in trouble. 112 */ 113static inline int 114xo_buf_has_room (xo_buffer_t *xbp, ssize_t len) 115{ 116 if (xbp->xb_curp + len >= xbp->xb_bufp + xbp->xb_size) { 117 /* 118 * Find out how much new space we need, round it up to XO_BUFSIZ 119 */ 120 ssize_t sz = (xbp->xb_curp + len) - xbp->xb_bufp; 121 sz = (sz + XO_BUFSIZ - 1) & ~(XO_BUFSIZ - 1); 122 123 char *bp = xo_realloc(xbp->xb_bufp, sz); 124 if (bp == NULL) 125 return 0; 126 127 xbp->xb_curp = bp + (xbp->xb_curp - xbp->xb_bufp); 128 xbp->xb_bufp = bp; 129 xbp->xb_size = sz; 130 } 131 132 return 1; 133} 134 135/* 136 * Append the given string to the given buffer 137 */ 138static inline void 139xo_buf_append (xo_buffer_t *xbp, const char *str, ssize_t len) 140{ 141 if (str == NULL || len == 0 || !xo_buf_has_room(xbp, len)) 142 return; 143 144 memcpy(xbp->xb_curp, str, len); 145 xbp->xb_curp += len; 146} 147 148/* 149 * Append the given NUL-terminated string to the given buffer 150 */ 151static inline void 152xo_buf_append_str (xo_buffer_t *xbp, const char *str) 153{ 154 ssize_t len = strlen(str); 155 156 if (!xo_buf_has_room(xbp, len)) 157 return; 158 159 memcpy(xbp->xb_curp, str, len); 160 xbp->xb_curp += len; 161} 162 163#endif /* XO_BUF_H */ 164