1 /*-
2 * Copyright (c) 2005 Max Okumoto
3 * Copyright (c) 1988, 1989, 1990, 1993
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1988, 1989 by Adam de Boor
6 * Copyright (c) 1989 by Berkeley Softworks
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Adam de Boor.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)buf.c 8.1 (Berkeley) 6/6/93
41 */
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 /*
47 * buf.c
48 * Functions for automatically-expanded buffers.
49 */
50
51 #include <string.h>
52 #include <stdlib.h>
53
54 #include "buf.h"
55 #include "util.h"
56
57 /**
58 * Returns the number of bytes in the buffer. Doesn't include the
59 * null-terminating byte.
60 */
61 size_t
Buf_Size(const Buffer * buf)62 Buf_Size(const Buffer *buf)
63 {
64
65 return (buf->end - buf->buf);
66 }
67
68 /**
69 * Returns a reference to the data contained in the buffer.
70 *
71 * @note Adding data to the Buffer object may invalidate the reference.
72 */
73 char *
Buf_Data(const Buffer * bp)74 Buf_Data(const Buffer *bp)
75 {
76
77 return (bp->buf);
78 }
79
80 /**
81 * Expand the buffer to hold the number of additional bytes, plus
82 * space to store a terminating NULL byte.
83 */
84 static inline void
BufExpand(Buffer * bp,size_t nb)85 BufExpand(Buffer *bp, size_t nb)
86 {
87 size_t len = Buf_Size(bp);
88 size_t size;
89
90 if (bp->size < len + nb + 1) {
91 size = bp->size + MAX(nb + 1, BUF_ADD_INC);
92 bp->size = size;
93 bp->buf = erealloc(bp->buf, size);
94 bp->end = bp->buf + len;
95 }
96 }
97
98 /**
99 * Add a single byte to the buffer.
100 */
101 void
Buf_AddByte(Buffer * bp,Byte byte)102 Buf_AddByte(Buffer *bp, Byte byte)
103 {
104
105 BufExpand(bp, 1);
106
107 *bp->end = byte;
108 bp->end++;
109 *bp->end = '\0';
110 }
111
112 /**
113 * Add bytes to the buffer.
114 */
115 void
Buf_AddBytes(Buffer * bp,size_t len,const Byte * bytes)116 Buf_AddBytes(Buffer *bp, size_t len, const Byte *bytes)
117 {
118
119 BufExpand(bp, len);
120
121 memcpy(bp->end, bytes, len);
122 bp->end += len;
123 *bp->end = '\0';
124 }
125
126 /**
127 * Get a reference to the internal buffer.
128 *
129 * len:
130 * Pointer to where we return the number of bytes in the internal buffer.
131 *
132 * Returns:
133 * return A pointer to the data.
134 */
135 Byte *
Buf_GetAll(Buffer * bp,size_t * len)136 Buf_GetAll(Buffer *bp, size_t *len)
137 {
138
139 if (len != NULL)
140 *len = Buf_Size(bp);
141
142 return (bp->buf);
143 }
144
145 /**
146 * Get the contents of a buffer and destroy the buffer. If the buffer
147 * is NULL, return NULL.
148 *
149 * Returns:
150 * the pointer to the data.
151 */
152 char *
Buf_Peel(Buffer * bp)153 Buf_Peel(Buffer *bp)
154 {
155 char *ret;
156
157 if (bp == NULL)
158 return (NULL);
159 ret = bp->buf;
160 free(bp);
161 return (ret);
162 }
163
164 /**
165 * Initialize a buffer. If no initial size is given, a reasonable
166 * default is used.
167 *
168 * Returns:
169 * A buffer object to be given to other functions in this library.
170 *
171 * Side Effects:
172 * Space is allocated for the Buffer object and a internal buffer.
173 */
174 Buffer *
Buf_Init(size_t size)175 Buf_Init(size_t size)
176 {
177 Buffer *bp; /* New Buffer */
178
179 if (size <= 0)
180 size = BUF_DEF_SIZE;
181
182 bp = emalloc(sizeof(*bp));
183 bp->size = size;
184 bp->buf = emalloc(size);
185 bp->end = bp->buf;
186 *bp->end = '\0';
187
188 return (bp);
189 }
190
191 /**
192 * Destroy a buffer, and optionally free its data, too.
193 *
194 * Side Effects:
195 * Space for the Buffer object and possibly the internal buffer
196 * is de-allocated.
197 */
198 void
Buf_Destroy(Buffer * buf,Boolean freeData)199 Buf_Destroy(Buffer *buf, Boolean freeData)
200 {
201
202 if (freeData)
203 free(buf->buf);
204 free(buf);
205 }
206
207 /**
208 * Replace the last byte in a buffer. If the buffer was empty
209 * initially, then a new byte will be added.
210 */
211 void
Buf_ReplaceLastByte(Buffer * bp,Byte byte)212 Buf_ReplaceLastByte(Buffer *bp, Byte byte)
213 {
214
215 if (bp->end == bp->buf) {
216 Buf_AddByte(bp, byte);
217 } else {
218 *(bp->end - 1) = byte;
219 }
220 }
221
222 /**
223 * Append characters in str to Buffer object
224 */
225 void
Buf_Append(Buffer * bp,const char str[])226 Buf_Append(Buffer *bp, const char str[])
227 {
228
229 Buf_AddBytes(bp, strlen(str), str);
230 }
231
232 /**
233 * Append characters in buf to Buffer object
234 */
235 void
Buf_AppendBuf(Buffer * bp,const Buffer * buf)236 Buf_AppendBuf(Buffer *bp, const Buffer *buf)
237 {
238
239 Buf_AddBytes(bp, Buf_Size(buf), buf->buf);
240 }
241
242 /**
243 * Append characters between str and end to Buffer object.
244 */
245 void
Buf_AppendRange(Buffer * bp,const char str[],const char * end)246 Buf_AppendRange(Buffer *bp, const char str[], const char *end)
247 {
248
249 Buf_AddBytes(bp, end - str, str);
250 }
251
252 /**
253 * Convert newlines in buffer to spaces. The trailing newline is
254 * removed.
255 */
256 void
Buf_StripNewlines(Buffer * bp)257 Buf_StripNewlines(Buffer *bp)
258 {
259 char *ptr = bp->end;
260
261 /*
262 * If there is anything in the buffer, remove the last
263 * newline character.
264 */
265 if (ptr != bp->buf) {
266 if (*(ptr - 1) == '\n') {
267 /* shorten buffer */
268 *(ptr - 1) = '\0';
269 --bp->end;
270 }
271 --ptr;
272 }
273
274 /* Convert newline characters to a space characters. */
275 while (ptr != bp->buf) {
276 if (*ptr == '\n') {
277 *ptr = ' ';
278 }
279 --ptr;
280 }
281 }
282 /**
283 * Clear the contents of the buffer.
284 */
285 void
Buf_Clear(Buffer * bp)286 Buf_Clear(Buffer *bp)
287 {
288
289 bp->end = bp->buf;
290 *bp->end = '\0';
291 }
292