buf.c revision 144386
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: head/usr.bin/make/buf.c 144386 2005-03-31 11:12:45Z harti $");
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 "sprite.h"
56#include "util.h"
57
58/**
59 * Returns the number of bytes in the buffer.  Doesn't include the
60 * null-terminating byte.
61 */
62inline size_t
63Buf_Size(const Buffer *buf)
64{
65
66	return (buf->end - buf->buf);
67}
68
69/**
70 * Returns a reference to the data contained in the buffer.
71 *
72 * @note Adding data to the Buffer object may invalidate the reference.
73 */
74inline char *
75Buf_Data(const Buffer *bp)
76{
77
78	return (bp->buf);
79}
80
81/**
82 * Expand the buffer to hold the number of additional bytes, plus
83 * space to store a terminating NULL byte.
84 */
85static inline void
86BufExpand(Buffer *bp, size_t nb)
87{
88	size_t	len = Buf_Size(bp);
89	size_t	size;
90
91	if (bp->size < len + nb + 1) {
92		size = bp->size + MAX(nb + 1, BUF_ADD_INC);
93		bp->size = size;
94		bp->buf = erealloc(bp->buf, size);
95		bp->end = bp->buf + len;
96	}
97}
98
99/**
100 * Add a single byte to the buffer.
101 */
102inline void
103Buf_AddByte(Buffer *bp, Byte byte)
104{
105
106	BufExpand(bp, 1);
107
108	*bp->end = byte;
109	bp->end++;
110	*bp->end = '\0';
111}
112
113/**
114 * Add bytes to the buffer.
115 */
116void
117Buf_AddBytes(Buffer *bp, size_t len, const Byte *bytes)
118{
119
120	BufExpand(bp, len);
121
122	memcpy(bp->end, bytes, len);
123	bp->end += len;
124	*bp->end = '\0';
125}
126
127/**
128 * Get a reference to the internal buffer.
129 *
130 * len:
131 *	Pointer to where we return the number of bytes in the internal buffer.
132 *
133 * Returns:
134 *	return A pointer to the data.
135 */
136Byte *
137Buf_GetAll(Buffer *bp, size_t *len)
138{
139
140	if (len != NULL)
141		*len = Buf_Size(bp);
142
143	return (bp->buf);
144}
145
146/**
147 * Get the contents of a buffer and destroy the buffer. If the buffer
148 * is NULL, return NULL.
149 *
150 * Returns:
151 *	the pointer to the data.
152 */
153char *
154Buf_Peel(Buffer *bp)
155{
156	char *ret;
157
158	if (bp == NULL)
159		return (NULL);
160	ret = bp->buf;
161	free(bp);
162	return (ret);
163}
164
165/**
166 * Initialize a buffer. If no initial size is given, a reasonable
167 * default is used.
168 *
169 * Returns:
170 *	A buffer object to be given to other functions in this library.
171 *
172 * Side Effects:
173 *	Space is allocated for the Buffer object and a internal buffer.
174 */
175Buffer *
176Buf_Init(size_t size)
177{
178	Buffer *bp;	/* New Buffer */
179
180	if (size <= 0)
181		size = BUF_DEF_SIZE;
182
183	bp = emalloc(sizeof(*bp));
184	bp->size = size;
185	bp->buf = emalloc(size);
186	bp->end = bp->buf;
187	*bp->end = '\0';
188
189	return (bp);
190}
191
192/**
193 * Destroy a buffer, and optionally free its data, too.
194 *
195 * Side Effects:
196 *	Space for the Buffer object and possibly the internal buffer
197 *	is de-allocated.
198 */
199void
200Buf_Destroy(Buffer *buf, Boolean freeData)
201{
202
203	if (freeData)
204		free(buf->buf);
205	free(buf);
206}
207
208/**
209 * Replace the last byte in a buffer.  If the buffer was empty
210 * intially, then a new byte will be added.
211 */
212void
213Buf_ReplaceLastByte(Buffer *bp, Byte byte)
214{
215
216	if (bp->end == bp->buf) {
217		Buf_AddByte(bp, byte);
218	} else {
219		*(bp->end - 1) = byte;
220	}
221}
222
223/**
224 * Append characters in str to Buffer object
225 */
226void
227Buf_Append(Buffer *bp, const char str[])
228{
229
230	Buf_AddBytes(bp, strlen(str), str);
231}
232
233/**
234 * Append characters in buf to Buffer object
235 */
236void
237Buf_AppendBuf(Buffer *bp, const Buffer *buf)
238{
239
240	Buf_AddBytes(bp, Buf_Size(buf), buf->buf);
241}
242
243/**
244 * Append characters between str and end to Buffer object.
245 */
246void
247Buf_AppendRange(Buffer *bp, const char str[], const char *end)
248{
249
250	Buf_AddBytes(bp, end - str, str);
251}
252
253/**
254 * Convert newlines in buffer to spaces.  The trailing newline is
255 * removed.
256 */
257void
258Buf_StripNewlines(Buffer *bp)
259{
260	char *ptr = bp->end;
261
262	/*
263	 * If there is anything in the buffer, remove the last
264	 * newline character.
265	 */
266	if (ptr != bp->buf) {
267		if (*(ptr - 1) == '\n') {
268			/* shorten buffer */
269			*(ptr - 1) = '\0';
270			--bp->end;
271		}
272		--ptr;
273	}
274
275	/* Convert newline characters to a space characters.  */
276	while (ptr != bp->buf) {
277		if (*ptr == '\n') {
278			*ptr = ' ';
279		}
280		--ptr;
281	}
282}
283/**
284 * Clear the contents of the buffer.
285 */
286void
287Buf_Clear(Buffer *bp)
288{
289
290	bp->end = bp->buf;
291	*bp->end = '\0';
292}
293