buf.c revision 187475
1212795Sdim/*-
2212795Sdim * Copyright (c) 2005 Max Okumoto
3212795Sdim * Copyright (c) 1988, 1989, 1990, 1993
4212795Sdim *	The Regents of the University of California.  All rights reserved.
5212795Sdim * Copyright (c) 1988, 1989 by Adam de Boor
6212795Sdim * Copyright (c) 1989 by Berkeley Softworks
7212795Sdim * All rights reserved.
8212795Sdim *
9212795Sdim * This code is derived from software contributed to Berkeley by
10212795Sdim * Adam de Boor.
11212795Sdim *
12212795Sdim * Redistribution and use in source and binary forms, with or without
13212795Sdim * modification, are permitted provided that the following conditions
14212795Sdim * are met:
15212795Sdim * 1. Redistributions of source code must retain the above copyright
16212795Sdim *    notice, this list of conditions and the following disclaimer.
17212795Sdim * 2. Redistributions in binary form must reproduce the above copyright
18212795Sdim *    notice, this list of conditions and the following disclaimer in the
19212795Sdim *    documentation and/or other materials provided with the distribution.
20212795Sdim * 3. All advertising materials mentioning features or use of this software
21212795Sdim *    must display the following acknowledgement:
22218893Sdim *	This product includes software developed by the University of
23212795Sdim *	California, Berkeley and its contributors.
24212795Sdim * 4. Neither the name of the University nor the names of its contributors
25212795Sdim *    may be used to endorse or promote products derived from this software
26212795Sdim *    without specific prior written permission.
27212795Sdim *
28212795Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29212795Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30226633Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31226633Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32226633Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33226633Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34226633Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35226633Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36226633Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37212795Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38212795Sdim * SUCH DAMAGE.
39218893Sdim *
40226633Sdim * @(#)buf.c	8.1 (Berkeley) 6/6/93
41212795Sdim */
42212795Sdim
43226633Sdim#include <sys/cdefs.h>
44226633Sdim__FBSDID("$FreeBSD: head/usr.bin/make/buf.c 187475 2009-01-20 17:15:12Z rdivacky $");
45226633Sdim
46212795Sdim/*
47212795Sdim * buf.c
48212795Sdim *	Functions for automatically-expanded buffers.
49218893Sdim */
50212795Sdim
51212795Sdim#include <string.h>
52226633Sdim#include <stdlib.h>
53212795Sdim
54212795Sdim#include "buf.h"
55212795Sdim#include "util.h"
56212795Sdim
57212795Sdim/**
58212795Sdim * Returns the number of bytes in the buffer.  Doesn't include the
59212795Sdim * null-terminating byte.
60212795Sdim */
61212795Sdimsize_t
62212795SdimBuf_Size(const Buffer *buf)
63212795Sdim{
64218893Sdim
65226633Sdim	return (buf->end - buf->buf);
66218893Sdim}
67218893Sdim
68212795Sdim/**
69212795Sdim * Returns a reference to the data contained in the buffer.
70212795Sdim *
71 * @note Adding data to the Buffer object may invalidate the reference.
72 */
73char *
74Buf_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 */
84static inline void
85BufExpand(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 */
101void
102Buf_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 */
115void
116Buf_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 */
135Byte *
136Buf_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 */
152char *
153Buf_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 */
174Buffer *
175Buf_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 */
198void
199Buf_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 * intially, then a new byte will be added.
210 */
211void
212Buf_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 */
225void
226Buf_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 */
235void
236Buf_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 */
245void
246Buf_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 */
256void
257Buf_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 */
285void
286Buf_Clear(Buffer *bp)
287{
288
289	bp->end = bp->buf;
290	*bp->end = '\0';
291}
292