buf.c revision 138342
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 138342 2004-12-03 12:02:14Z harti $");
44
45/*-
46 * buf.c --
47 *	Functions for automatically-expanded buffers.
48 */
49
50#include "sprite.h"
51#include "make.h"
52#include "buf.h"
53
54#ifndef max
55#define	max(a,b)  ((a) > (b) ? (a) : (b))
56#endif
57
58/*
59 * BufExpand --
60 * 	Expand the given buffer to hold the given number of additional
61 *	bytes.
62 *	Makes sure there's room for an extra NULL byte at the end of the
63 *	buffer in case it holds a string.
64 */
65#define	BufExpand(bp, nb) do {						\
66 	if ((bp)->left < (nb) + 1) {					\
67		int newSize = (bp)->size + max((nb) + 1, BUF_ADD_INC);	\
68		Byte  *newBuf = erealloc((bp)->buffer, newSize);	\
69									\
70		(bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer);	\
71		(bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);	\
72		(bp)->buffer = newBuf;					\
73		(bp)->size = newSize;					\
74		(bp)->left = newSize - ((bp)->inPtr - (bp)->buffer);	\
75	}								\
76    } while (0)
77
78#define	BUF_DEF_SIZE	256 	/* Default buffer size */
79#define	BUF_ADD_INC	256 	/* Expansion increment when Adding */
80#define	BUF_UNGET_INC	16  	/* Expansion increment when Ungetting */
81
82/*-
83 *-----------------------------------------------------------------------
84 * Buf_OvAddByte --
85 *	Add a single byte to the buffer.  left is zero or negative.
86 *
87 * Results:
88 *	None.
89 *
90 * Side Effects:
91 *	The buffer may be expanded.
92 *
93 *-----------------------------------------------------------------------
94 */
95void
96Buf_OvAddByte(Buffer bp, Byte byte)
97{
98
99	bp->left = 0;
100	BufExpand(bp, 1);
101
102	*bp->inPtr++ = byte;
103	bp->left--;
104
105	/*
106	 * Null-terminate
107	 */
108	*bp->inPtr = 0;
109}
110
111/*-
112 *-----------------------------------------------------------------------
113 * Buf_AddBytes --
114 *	Add a number of bytes to the buffer.
115 *
116 * Results:
117 *	None.
118 *
119 * Side Effects:
120 *	Guess what?
121 *
122 *-----------------------------------------------------------------------
123 */
124void
125Buf_AddBytes(Buffer bp, size_t numBytes, const Byte *bytesPtr)
126{
127
128	BufExpand(bp, numBytes);
129
130	memcpy(bp->inPtr, bytesPtr, numBytes);
131	bp->inPtr += numBytes;
132	bp->left -= numBytes;
133
134	/*
135	 * Null-terminate
136	 */
137	*bp->inPtr = 0;
138}
139
140/*-
141 *-----------------------------------------------------------------------
142 * Buf_UngetByte --
143 *	Place the byte back at the beginning of the buffer.
144 *
145 * Results:
146 *	SUCCESS if the byte was added ok. FAILURE if not.
147 *
148 * Side Effects:
149 *	The byte is stuffed in the buffer and outPtr is decremented.
150 *
151 *-----------------------------------------------------------------------
152 */
153void
154Buf_UngetByte(Buffer bp, Byte byte)
155{
156
157	if (bp->outPtr != bp->buffer) {
158		bp->outPtr--;
159		*bp->outPtr = byte;
160
161	} else if (bp->outPtr == bp->inPtr) {
162		*bp->inPtr = byte;
163		bp->inPtr++;
164		bp->left--;
165		*bp->inPtr = 0;
166
167	} else {
168		/*
169		 * Yech. have to expand the buffer to stuff this thing in.
170		 * We use a different expansion constant because people don't
171		 * usually push back many bytes when they're doing it a byte at
172		 * a time...
173		 */
174		size_t numBytes = bp->inPtr - bp->outPtr;
175		Byte *newBuf;
176
177		newBuf = emalloc(bp->size + BUF_UNGET_INC);
178		memcpy(newBuf + BUF_UNGET_INC, bp->outPtr, numBytes + 1);
179		bp->outPtr = newBuf + BUF_UNGET_INC;
180		bp->inPtr = bp->outPtr + numBytes;
181		free(bp->buffer);
182		bp->buffer = newBuf;
183		bp->size += BUF_UNGET_INC;
184		bp->left = bp->size - (bp->inPtr - bp->buffer);
185		bp->outPtr -= 1;
186		*bp->outPtr = byte;
187	}
188}
189
190/*-
191 *-----------------------------------------------------------------------
192 * Buf_UngetBytes --
193 *	Push back a series of bytes at the beginning of the buffer.
194 *
195 * Results:
196 *	None.
197 *
198 * Side Effects:
199 *	outPtr is decremented and the bytes copied into the buffer.
200 *
201 *-----------------------------------------------------------------------
202 */
203void
204Buf_UngetBytes(Buffer bp, size_t numBytes, Byte *bytesPtr)
205{
206
207	if ((size_t)(bp->outPtr - bp->buffer) >= numBytes) {
208		bp->outPtr -= numBytes;
209		memcpy(bp->outPtr, bytesPtr, numBytes);
210	} else if (bp->outPtr == bp->inPtr) {
211		Buf_AddBytes(bp, numBytes, bytesPtr);
212	} else {
213		size_t curNumBytes = bp->inPtr - bp->outPtr;
214		Byte *newBuf;
215		size_t newBytes = max(numBytes, BUF_UNGET_INC);
216
217		newBuf = emalloc(bp->size + newBytes);
218		memcpy(newBuf + newBytes, bp->outPtr, curNumBytes + 1);
219		bp->outPtr = newBuf + newBytes;
220		bp->inPtr = bp->outPtr + curNumBytes;
221		free(bp->buffer);
222		bp->buffer = newBuf;
223		bp->size += newBytes;
224		bp->left = bp->size - (bp->inPtr - bp->buffer);
225		bp->outPtr -= numBytes;
226		memcpy(bp->outPtr, bytesPtr, numBytes);
227	}
228}
229
230/*-
231 *-----------------------------------------------------------------------
232 * Buf_GetByte --
233 *	Return the next byte from the buffer. Actually returns an integer.
234 *
235 * Results:
236 *	Returns BUF_ERROR if there's no byte in the buffer, or the byte
237 *	itself if there is one.
238 *
239 * Side Effects:
240 *	outPtr is incremented and both outPtr and inPtr will be reset if
241 *	the buffer is emptied.
242 *
243 *-----------------------------------------------------------------------
244 */
245int
246Buf_GetByte(Buffer bp)
247{
248	int res;
249
250	if (bp->inPtr == bp->outPtr)
251		return (BUF_ERROR);
252
253	res = (int)*bp->outPtr;
254	bp->outPtr += 1;
255	if (bp->outPtr == bp->inPtr) {
256		bp->outPtr = bp->inPtr = bp->buffer;
257		bp->left = bp->size;
258		*bp->inPtr = 0;
259	}
260	return (res);
261}
262
263/*-
264 *-----------------------------------------------------------------------
265 * Buf_GetBytes --
266 *	Extract a number of bytes from the buffer.
267 *
268 * Results:
269 *	The number of bytes gotten.
270 *
271 * Side Effects:
272 *	The passed array is overwritten.
273 *
274 *-----------------------------------------------------------------------
275 */
276int
277Buf_GetBytes(Buffer bp, size_t numBytes, Byte *bytesPtr)
278{
279
280	if ((size_t)(bp->inPtr - bp->outPtr) < numBytes)
281		numBytes = bp->inPtr - bp->outPtr;
282
283	memcpy(bytesPtr, bp->outPtr, numBytes);
284	bp->outPtr += numBytes;
285
286	if (bp->outPtr == bp->inPtr) {
287		bp->outPtr = bp->inPtr = bp->buffer;
288		bp->left = bp->size;
289		*bp->inPtr = 0;
290	}
291	return (numBytes);
292}
293
294/*-
295 *-----------------------------------------------------------------------
296 * Buf_GetAll --
297 *	Get all the available data at once.
298 *
299 * Results:
300 *	A pointer to the data and the number of bytes available.
301 *
302 * Side Effects:
303 *	None.
304 *
305 *-----------------------------------------------------------------------
306 */
307Byte *
308Buf_GetAll(Buffer bp, size_t *numBytesPtr)
309{
310
311	if (numBytesPtr != NULL)
312		*numBytesPtr = bp->inPtr - bp->outPtr;
313
314	return (bp->outPtr);
315}
316
317/*-
318 *-----------------------------------------------------------------------
319 * Buf_Discard --
320 *	Throw away bytes in a buffer.
321 *
322 * Results:
323 *	None.
324 *
325 * Side Effects:
326 *	The bytes are discarded.
327 *
328 *-----------------------------------------------------------------------
329 */
330void
331Buf_Discard(Buffer bp, size_t numBytes)
332{
333
334	if ((size_t)(bp->inPtr - bp->outPtr) <= numBytes) {
335		bp->inPtr = bp->outPtr = bp->buffer;
336		bp->left = bp->size;
337		*bp->inPtr = 0;
338	} else
339		bp->outPtr += numBytes;
340}
341
342/*-
343 *-----------------------------------------------------------------------
344 * Buf_Size --
345 *	Returns the number of bytes in the given buffer. Doesn't include
346 *	the null-terminating byte.
347 *
348 * Results:
349 *	The number of bytes.
350 *
351 * Side Effects:
352 *	None.
353 *
354 *-----------------------------------------------------------------------
355 */
356size_t
357Buf_Size(Buffer buf)
358{
359
360	return (buf->inPtr - buf->outPtr);
361}
362
363/*-
364 *-----------------------------------------------------------------------
365 * Buf_Init --
366 *	Initialize a buffer. If no initial size is given, a reasonable
367 *	default is used.
368 *
369 * Results:
370 *	A buffer to be given to other functions in this library.
371 *
372 * Side Effects:
373 *	The buffer is created, the space allocated and pointers
374 *	initialized.
375 *
376 *-----------------------------------------------------------------------
377 */
378Buffer
379Buf_Init(size_t size)
380{
381	Buffer bp;	  	/* New Buffer */
382
383	bp = emalloc(sizeof(*bp));
384
385	if (size <= 0)
386		size = BUF_DEF_SIZE;
387
388	bp->left = bp->size = size;
389	bp->buffer = emalloc(size);
390	bp->inPtr = bp->outPtr = bp->buffer;
391	*bp->inPtr = 0;
392
393	return (bp);
394}
395
396/*-
397 *-----------------------------------------------------------------------
398 * Buf_Destroy --
399 *	Destroy a buffer, and optionally free its data, too.
400 *
401 * Results:
402 *	None.
403 *
404 * Side Effects:
405 *	The buffer is freed.
406 *
407 *-----------------------------------------------------------------------
408 */
409void
410Buf_Destroy(Buffer buf, Boolean freeData)
411{
412
413	if (freeData)
414		free(buf->buffer);
415	free(buf);
416}
417
418/*-
419 *-----------------------------------------------------------------------
420 * Buf_ReplaceLastByte --
421 *     Replace the last byte in a buffer.
422 *
423 * Results:
424 *     None.
425 *
426 * Side Effects:
427 *     If the buffer was empty intially, then a new byte will be added.
428 *     Otherwise, the last byte is overwritten.
429 *
430 *-----------------------------------------------------------------------
431 */
432void
433Buf_ReplaceLastByte(Buffer buf, Byte byte)
434{
435	if (buf->inPtr == buf->outPtr)
436		Buf_AddByte(buf, byte);
437	else
438		*(buf->inPtr - 1) = byte;
439}
440