44762d8c3b8e63ff02efd8cddbfb769d7905a12a
[fw/sdcc] / support / Util / dbuf.c
1 /*
2   dbuf.c - Dynamic buffer implementation
3   version 1.1.3, December 17th, 2006
4
5   Copyright (c) 2002-2006 Borut Razem
6
7   This software is provided 'as-is', without any express or implied
8   warranty.  In no event will the authors be held liable for any damages
9   arising from the use of this software.
10
11   Permission is granted to anyone to use this software for any purpose,
12   including commercial applications, and to alter it and redistribute it
13   freely, subject to the following restrictions:
14
15   1. The origin of this software must not be misrepresented; you must not
16      claim that you wrote the original software. If you use this software
17      in a product, an acknowledgment in the product documentation would be
18      appreciated but is not required.
19   2. Altered source versions must be plainly marked as such, and must not be
20      misrepresented as being the original software.
21   3. This notice may not be removed or altered from any source distribution.
22
23   Borut Razem
24   borut.razem@siol.net
25 */
26
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include "dbuf.h"
32
33
34 /*
35  * Assure that the buffer is large enough to hold
36  * size bytes; enlarge it if necessary.
37  */
38
39 static int dbuf_expand(struct dbuf_s *dbuf, size_t size)
40 {
41   assert(dbuf->alloc != 0);
42   assert(dbuf->buf != NULL);
43
44   if (dbuf->len + size > dbuf->alloc) {
45     /* new_allocated_size = current_allocated_size * 2^n */
46     /* can this be optimized? */
47     do {
48       dbuf->alloc += dbuf->alloc;
49     }
50     while (dbuf->len + size > dbuf->alloc);
51
52     if ((dbuf->buf = realloc(dbuf->buf, dbuf->alloc)) == NULL)
53       return 0;
54   }
55
56   return 1;
57 }
58
59
60 /*
61  * Initialize the dbuf structure and
62  * allocate buffer to hold size bytes.
63  */
64
65 int dbuf_init(struct dbuf_s *dbuf, size_t size)
66 {
67   assert(size != 0);
68
69   if (size == 0)
70     size = 1;
71
72   dbuf->len = 0;
73   dbuf->alloc = size;
74   return ((dbuf->buf = malloc(dbuf->alloc)) != NULL);
75 }
76
77
78 /*
79  * Allocate new dbuf structure on the heap
80  * and initialize it.
81  *
82  * See: dbuf_delete()
83  */
84
85 struct dbuf_s *dbuf_new(size_t size)
86 {
87   struct dbuf_s *dbuf;
88
89   dbuf = (struct dbuf_s *)malloc(sizeof(struct dbuf_s));
90   if (dbuf != NULL) {
91     if (dbuf_init(dbuf, size) == 0) {
92       free(dbuf);
93       return NULL;
94     }
95   }
96   return dbuf;
97 }
98
99
100 /*
101  * Set the buffer size. Buffer size can be only decreased.
102  */
103
104 int dbuf_set_size(struct dbuf_s *dbuf, size_t size)
105 {
106   assert(dbuf != NULL);
107   assert(dbuf->alloc != 0);
108   assert(size <= dbuf->len);
109
110   if (size <= dbuf->len) {
111     dbuf->len = size;
112     return 1;
113   }
114
115   return 0;
116 }
117
118
119 /*
120  * Append the buf to the end of the buffer.
121  */
122
123 int dbuf_append(struct dbuf_s *dbuf, const void *buf, size_t size)
124 {
125   assert(dbuf != NULL);
126   assert(dbuf->alloc != 0);
127   assert(dbuf->buf != NULL);
128
129   if (dbuf_expand(dbuf, size) != 0) {
130     memcpy(&(((char *)dbuf->buf)[dbuf->len]), buf, size);
131     dbuf->len += size;
132     return 1;
133   }
134
135   return 0;
136 }
137
138
139 /*
140  * Add '\0' character at the end of the buffer without
141  * count it in the dbuf->len.
142  */
143
144 const char *dbuf_c_str(struct dbuf_s *dbuf)
145 {
146   assert(dbuf != NULL);
147   assert(dbuf->alloc != 0);
148   assert(dbuf->buf != NULL);
149
150   dbuf_expand(dbuf, 1);
151   ((char *)dbuf->buf)[dbuf->len] = '\0';
152
153   return dbuf->buf;
154 }
155
156
157 /*
158  * Get the buffer pointer.
159  */
160
161 const void *dbuf_get_buf(struct dbuf_s *dbuf)
162 {
163   assert(dbuf != NULL);
164   assert(dbuf->alloc != 0);
165   assert(dbuf->buf != NULL);
166
167   return dbuf->buf;
168 }
169
170
171 /*
172  * Get the buffer size.
173  */
174
175 size_t dbuf_get_size(struct dbuf_s *dbuf)
176 {
177   assert(dbuf != NULL);
178   assert(dbuf->alloc != 0);
179   assert(dbuf->buf != NULL);
180
181   return dbuf->len;
182 }
183
184
185 /*
186  * Trim the allocated buffer to required size
187  */
188
189 int dbuf_trim(struct dbuf_s *dbuf)
190 {
191   void *buf;
192
193   assert(dbuf != NULL);
194   assert(dbuf->alloc != 0);
195   assert(dbuf->buf != NULL);
196
197   buf = realloc(dbuf->buf, dbuf->len);
198
199   if (buf != NULL) {
200     dbuf->alloc = dbuf->len;
201     dbuf->buf = buf;
202   }
203
204   return buf != NULL;
205 }
206
207
208 /*
209  * Detach the buffer from dbuf structure.
210  * The dbuf structure can be reused by
211  * reinitializing it.
212  *
213  * See: dbuf_init()
214  */
215
216 void *dbuf_detach(struct dbuf_s *dbuf)
217 {
218   void *ret;
219
220   assert(dbuf != NULL);
221   assert(dbuf->alloc != 0);
222   assert(dbuf->buf != NULL);
223
224   ret = dbuf->buf;
225   dbuf->buf = NULL;
226   dbuf->len = 0;
227   dbuf->alloc = 0;
228
229   return ret;
230 }
231
232
233 /*
234  * Destroy the dbuf structure and
235  * free the buffer
236  */
237
238 void dbuf_destroy(struct dbuf_s *dbuf)
239 {
240   free(dbuf_detach(dbuf));
241 }
242
243
244 /*
245  * Delete dbuf structure on the heap:
246  * destroy it and free the allocated space.
247  * The user's responsablity is not to use
248  * the pointer any more: the best think to do
249  * is to set the pointer to NULL value.
250  *
251  * See dbuf_new()
252  */
253
254 void dbuf_delete(struct dbuf_s *dbuf)
255 {
256   dbuf_destroy(dbuf);
257   free(dbuf);
258 }