buf.c revision 141133
1/*-
2 * Copyright (c) 1988, 1989, 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1988, 1989 by Adam de Boor
5 * Copyright (c) 1989 by Berkeley Softworks
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Adam de Boor.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)buf.c	8.1 (Berkeley) 6/6/93
40 */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/usr.bin/make/buf.c 141133 2005-02-02 07:36:18Z harti $");
44
45/*-
46 * buf.c --
47 *	Functions for automatically-expanded buffers.
48 */
49
50#include <string.h>
51#include <stdlib.h>
52
53#include "buf.h"
54#include "sprite.h"
55#include "util.h"
56
57#ifndef max
58#define	max(a,b)  ((a) > (b) ? (a) : (b))
59#endif
60
61/*
62 * BufExpand --
63 * 	Expand the given buffer to hold the given number of additional
64 *	bytes.
65 *	Makes sure there's room for an extra NULL byte at the end of the
66 *	buffer in case it holds a string.
67 */
68#define	BufExpand(bp, nb) do {						\
69 	if ((bp)->left < (nb) + 1) {					\
70		int newSize = (bp)->size + max((nb) + 1, BUF_ADD_INC);	\
71		Byte *newBuf = erealloc((bp)->buffer, newSize);		\
72									\
73		(bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer);	\
74		(bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);	\
75		(bp)->buffer = newBuf;					\
76		(bp)->size = newSize;					\
77		(bp)->left = newSize - ((bp)->inPtr - (bp)->buffer);	\
78	}								\
79    } while (0)
80
81#define	BUF_DEF_SIZE	256 	/* Default buffer size */
82#define	BUF_ADD_INC	256 	/* Expansion increment when Adding */
83#define	BUF_UNGET_INC	16  	/* Expansion increment when Ungetting */
84
85/*-
86 *-----------------------------------------------------------------------
87 * Buf_OvAddByte --
88 *	Add a single byte to the buffer.  left is zero or negative.
89 *
90 * Results:
91 *	None.
92 *
93 * Side Effects:
94 *	The buffer may be expanded.
95 *
96 *-----------------------------------------------------------------------
97 */
98void
99Buf_OvAddByte(Buffer *bp, Byte byte)
100{
101
102	bp->left = 0;
103	BufExpand(bp, 1);
104
105	*bp->inPtr++ = byte;
106	bp->left--;
107
108	/*
109	 * Null-terminate
110	 */
111	*bp->inPtr = 0;
112}
113
114/*-
115 *-----------------------------------------------------------------------
116 * Buf_AddBytes --
117 *	Add a number of bytes to the buffer.
118 *
119 * Results:
120 *	None.
121 *
122 * Side Effects:
123 *	Guess what?
124 *
125 *-----------------------------------------------------------------------
126 */
127void
128Buf_AddBytes(Buffer *bp, size_t numBytes, const Byte *bytesPtr)
129{
130
131	BufExpand(bp, numBytes);
132
133	memcpy(bp->inPtr, bytesPtr, numBytes);
134	bp->inPtr += numBytes;
135	bp->left -= numBytes;
136
137	/*
138	 * Null-terminate
139	 */
140	*bp->inPtr = 0;
141}
142
143/*-
144 *-----------------------------------------------------------------------
145 * Buf_UngetByte --
146 *	Place the byte back at the beginning of the buffer.
147 *
148 * Results:
149 *	SUCCESS if the byte was added ok. FAILURE if not.
150 *
151 * Side Effects:
152 *	The byte is stuffed in the buffer and outPtr is decremented.
153 *
154 *-----------------------------------------------------------------------
155 */
156void
157Buf_UngetByte(Buffer *bp, Byte byte)
158{
159
160	if (bp->outPtr != bp->buffer) {
161		bp->outPtr--;
162		*bp->outPtr = byte;
163
164	} else if (bp->outPtr == bp->inPtr) {
165		*bp->inPtr = byte;
166		bp->inPtr++;
167		bp->left--;
168		*bp->inPtr = 0;
169
170	} else {
171		/*
172		 * Yech. have to expand the buffer to stuff this thing in.
173		 * We use a different expansion constant because people don't
174		 * usually push back many bytes when they're doing it a byte at
175		 * a time...
176		 */
177		size_t numBytes = bp->inPtr - bp->outPtr;
178		Byte *newBuf;
179
180		newBuf = emalloc(bp->size + BUF_UNGET_INC);
181		memcpy(newBuf + BUF_UNGET_INC, bp->outPtr, numBytes + 1);
182		bp->outPtr = newBuf + BUF_UNGET_INC;
183		bp->inPtr = bp->outPtr + numBytes;
184		free(bp->buffer);
185		bp->buffer = newBuf;
186		bp->size += BUF_UNGET_INC;
187		bp->left = bp->size - (bp->inPtr - bp->buffer);
188		bp->outPtr -= 1;
189		*bp->outPtr = byte;
190	}
191}
192
193/*-
194 *-----------------------------------------------------------------------
195 * Buf_UngetBytes --
196 *	Push back a series of bytes at the beginning of the buffer.
197 *
198 * Results:
199 *	None.
200 *
201 * Side Effects:
202 *	outPtr is decremented and the bytes copied into the buffer.
203 *
204 *-----------------------------------------------------------------------
205 */
206void
207Buf_UngetBytes(Buffer *bp, size_t numBytes, Byte *bytesPtr)
208{
209
210	if ((size_t)(bp->outPtr - bp->buffer) >= numBytes) {
211		bp->outPtr -= numBytes;
212		memcpy(bp->outPtr, bytesPtr, numBytes);
213	} else if (bp->outPtr == bp->inPtr) {
214		Buf_AddBytes(bp, numBytes, bytesPtr);
215	} else {
216		size_t curNumBytes = bp->inPtr - bp->outPtr;
217		Byte *newBuf;
218		size_t newBytes = max(numBytes, BUF_UNGET_INC);
219
220		newBuf = emalloc(bp->size + newBytes);
221		memcpy(newBuf + newBytes, bp->outPtr, curNumBytes + 1);
222		bp->outPtr = newBuf + newBytes;
223		bp->inPtr = bp->outPtr + curNumBytes;
224		free(bp->buffer);
225		bp->buffer = newBuf;
226		bp->size += newBytes;
227		bp->left = bp->size - (bp->inPtr - bp->buffer);
228		bp->outPtr -= numBytes;
229		memcpy(bp->outPtr, bytesPtr, numBytes);
230	}
231}
232
233/*-
234 *-----------------------------------------------------------------------
235 * Buf_GetByte --
236 *	Return the next byte from the buffer. Actually returns an integer.
237 *
238 * Results:
239 *	Returns BUF_ERROR if there's no byte in the buffer, or the byte
240 *	itself if there is one.
241 *
242 * Side Effects:
243 *	outPtr is incremented and both outPtr and inPtr will be reset if
244 *	the buffer is emptied.
245 *
246 *-----------------------------------------------------------------------
247 */
248int
249Buf_GetByte(Buffer *bp)
250{
251	int res;
252
253	if (bp->inPtr == bp->outPtr)
254		return (BUF_ERROR);
255
256	res = (int)*bp->outPtr;
257	bp->outPtr += 1;
258	if (bp->outPtr == bp->inPtr) {
259		bp->outPtr = bp->inPtr = bp->buffer;
260		bp->left = bp->size;
261		*bp->inPtr = 0;
262	}
263	return (res);
264}
265
266/*-
267 *-----------------------------------------------------------------------
268 * Buf_GetBytes --
269 *	Extract a number of bytes from the buffer.
270 *
271 * Results:
272 *	The number of bytes gotten.
273 *
274 * Side Effects:
275 *	The passed array is overwritten.
276 *
277 *-----------------------------------------------------------------------
278 */
279int
280Buf_GetBytes(Buffer *bp, size_t numBytes, Byte *bytesPtr)
281{
282
283	if ((size_t)(bp->inPtr - bp->outPtr) < numBytes)
284		numBytes = bp->inPtr - bp->outPtr;
285
286	memcpy(bytesPtr, bp->outPtr, numBytes);
287	bp->outPtr += numBytes;
288
289	if (bp->outPtr == bp->inPtr) {
290		bp->outPtr = bp->inPtr = bp->buffer;
291		bp->left = bp->size;
292		*bp->inPtr = 0;
293	}
294	return (numBytes);
295}
296
297/*-
298 *-----------------------------------------------------------------------
299 * Buf_GetAll --
300 *	Get all the available data at once.
301 *
302 * Results:
303 *	A pointer to the data and the number of bytes available.
304 *
305 * Side Effects:
306 *	None.
307 *
308 *-----------------------------------------------------------------------
309 */
310Byte *
311Buf_GetAll(Buffer *bp, size_t *numBytesPtr)
312{
313
314	if (numBytesPtr != NULL)
315		*numBytesPtr = bp->inPtr - bp->outPtr;
316
317	return (bp->outPtr);
318}
319
320/*-
321 *-----------------------------------------------------------------------
322 * Buf_Discard --
323 *	Throw away bytes in a buffer.
324 *
325 * Results:
326 *	None.
327 *
328 * Side Effects:
329 *	The bytes are discarded.
330 *
331 *-----------------------------------------------------------------------
332 */
333void
334Buf_Discard(Buffer *bp, size_t numBytes)
335{
336
337	if ((size_t)(bp->inPtr - bp->outPtr) <= numBytes) {
338		bp->inPtr = bp->outPtr = bp->buffer;
339		bp->left = bp->size;
340		*bp->inPtr = 0;
341	} else
342		bp->outPtr += numBytes;
343}
344
345/*-
346 *-----------------------------------------------------------------------
347 * Buf_Size --
348 *	Returns the number of bytes in the given buffer. Doesn't include
349 *	the null-terminating byte.
350 *
351 * Results:
352 *	The number of bytes.
353 *
354 * Side Effects:
355 *	None.
356 *
357 *-----------------------------------------------------------------------
358 */
359size_t
360Buf_Size(Buffer *buf)
361{
362
363	return (buf->inPtr - buf->outPtr);
364}
365
366/*-
367 *-----------------------------------------------------------------------
368 * Buf_Init --
369 *	Initialize a buffer. If no initial size is given, a reasonable
370 *	default is used.
371 *
372 * Results:
373 *	A buffer to be given to other functions in this library.
374 *
375 * Side Effects:
376 *	The buffer is created, the space allocated and pointers
377 *	initialized.
378 *
379 *-----------------------------------------------------------------------
380 */
381Buffer *
382Buf_Init(size_t size)
383{
384	Buffer *bp;	  	/* New Buffer */
385
386	bp = emalloc(sizeof(*bp));
387
388	if (size <= 0)
389		size = BUF_DEF_SIZE;
390
391	bp->left = bp->size = size;
392	bp->buffer = emalloc(size);
393	bp->inPtr = bp->outPtr = bp->buffer;
394	*bp->inPtr = 0;
395
396	return (bp);
397}
398
399/*-
400 *-----------------------------------------------------------------------
401 * Buf_Destroy --
402 *	Destroy a buffer, and optionally free its data, too.
403 *
404 * Results:
405 *	None.
406 *
407 * Side Effects:
408 *	The buffer is freed.
409 *
410 *-----------------------------------------------------------------------
411 */
412void
413Buf_Destroy(Buffer *buf, Boolean freeData)
414{
415
416	if (freeData)
417		free(buf->buffer);
418	free(buf);
419}
420
421/*-
422 *-----------------------------------------------------------------------
423 * Buf_ReplaceLastByte --
424 *     Replace the last byte in a buffer.
425 *
426 * Results:
427 *     None.
428 *
429 * Side Effects:
430 *     If the buffer was empty intially, then a new byte will be added.
431 *     Otherwise, the last byte is overwritten.
432 *
433 *-----------------------------------------------------------------------
434 */
435void
436Buf_ReplaceLastByte(Buffer *buf, Byte byte)
437{
438	if (buf->inPtr == buf->outPtr)
439		Buf_AddByte(buf, byte);
440	else
441		*(buf->inPtr - 1) = byte;
442}
443