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