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 */
28 typedef 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 */
37 static inline void
xo_buf_init(xo_buffer_t * xbp)38 xo_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 */
48 static inline void
xo_buf_reset(xo_buffer_t * xbp)49 xo_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 */
57 static inline int
xo_buf_left(xo_buffer_t * xbp)58 xo_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 */
66 static inline int
xo_buf_is_empty(xo_buffer_t * xbp)67 xo_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 */
75 static inline ssize_t
xo_buf_offset(xo_buffer_t * xbp)76 xo_buf_offset (xo_buffer_t *xbp)
77 {
78 return xbp ? (xbp->xb_curp - xbp->xb_bufp) : 0;
79 }
80
81 static inline char *
xo_buf_data(xo_buffer_t * xbp,ssize_t offset)82 xo_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
89 static inline char *
xo_buf_cur(xo_buffer_t * xbp)90 xo_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 */
100 static inline void
xo_buf_cleanup(xo_buffer_t * xbp)101 xo_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 */
113 static inline int
xo_buf_has_room(xo_buffer_t * xbp,ssize_t len)114 xo_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 */
138 static inline void
xo_buf_append(xo_buffer_t * xbp,const char * str,ssize_t len)139 xo_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 */
151 static inline void
xo_buf_append_str(xo_buffer_t * xbp,const char * str)152 xo_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