xref: /freebsd/contrib/libxo/libxo/xo_buf.h (revision 76afb20c58adb296f09857aed214b91464242264)
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