* support/Util/dbuf.c: fixed bug #1489008 fix dbuf_c_str(),
[fw/sdcc] / support / Util / dbuf.c
1 /*
2   dbuf.c - Dynamic buffer implementation
3   version 1.1.2, May 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     while (dbuf->len + size >= dbuf->alloc)
48       dbuf->alloc += dbuf->alloc;
49
50     if ((dbuf->buf = realloc(dbuf->buf, dbuf->alloc)) == NULL)
51       return 0;
52   }
53
54   return 1;
55 }
56
57
58 /*
59  * Initialize the dbuf structure and
60  * allocate buffer to hold size bytes.
61  */
62
63 int dbuf_init(struct dbuf_s *dbuf, size_t size)
64 {
65   assert(size != 0);
66
67   if (size == 0)
68     size = 1;
69
70   dbuf->len = 0;
71   dbuf->alloc = size;
72   return ((dbuf->buf = malloc(dbuf->alloc)) != NULL);
73 }
74
75
76 /*
77  * Allocate new dbuf structure on the heap
78  * and initialize it.
79  *
80  * See: dbuf_delete()
81  */
82
83 struct dbuf_s *dbuf_new(size_t size)
84 {
85   struct dbuf_s *dbuf;
86
87   dbuf = (struct dbuf_s *)malloc(sizeof(struct dbuf_s));
88   if (dbuf != NULL) {
89     if (dbuf_init(dbuf, size) == 0) {
90       free(dbuf);
91       return NULL;
92     }
93   }
94   return dbuf;
95 }
96
97
98 /*
99  * Set the buffer size. Buffer size can be only decreased.
100  */
101
102 int dbuf_set_size(struct dbuf_s *dbuf, size_t size)
103 {
104   assert(dbuf != NULL);
105   assert(dbuf->alloc != 0);
106   assert(size < dbuf->len);
107
108   if (size <= dbuf->len) {
109     dbuf->len = size;
110     return 1;
111   }
112
113   return 0;
114 }
115
116
117 /*
118  * Append the buf to the end of the buffer.
119  */
120
121 int dbuf_append(struct dbuf_s *dbuf, const void *buf, size_t size)
122 {
123   assert(dbuf != NULL);
124   assert(dbuf->alloc != 0);
125   assert(dbuf->buf != NULL);
126
127   if (dbuf_expand(dbuf, size) != 0) {
128     memcpy(&(((char *)dbuf->buf)[dbuf->len]), buf, size);
129     dbuf->len += size;
130     return 1;
131   }
132
133   return 0;
134 }
135
136
137 /*
138  * Add '\0' character at the end of the buffer without
139  * count it in the dbuf->len.
140  */
141
142 const char *dbuf_c_str(struct dbuf_s *dbuf)
143 {
144   assert(dbuf != NULL);
145   assert(dbuf->alloc != 0);
146   assert(dbuf->buf != NULL);
147
148   /* only if not already null terminated */
149   if (dbuf->len == dbuf->alloc ||
150     ((char *)dbuf->buf)[dbuf->len] != '\0') {
151     dbuf_expand(dbuf, 1);
152     ((char *)dbuf->buf)[dbuf->len] = '\0';
153   }
154
155   return dbuf->buf;
156 }
157
158
159 /*
160  * Get the buffer pointer.
161  */
162
163 const void *dbuf_get_buf(struct dbuf_s *dbuf)
164 {
165   assert(dbuf != NULL);
166   assert(dbuf->alloc != 0);
167   assert(dbuf->buf != NULL);
168
169   return dbuf->buf;
170 }
171
172
173 /*
174  * Get the buffer size.
175  */
176
177 size_t dbuf_get_size(struct dbuf_s *dbuf)
178 {
179   assert(dbuf != NULL);
180   assert(dbuf->alloc != 0);
181   assert(dbuf->buf != NULL);
182
183   return dbuf->len;
184 }
185
186
187 /*
188  * Trim the allocated buffer to required size
189  */
190
191 int dbuf_trim(struct dbuf_s *dbuf)
192 {
193   void *buf;
194
195   assert(dbuf != NULL);
196   assert(dbuf->alloc != 0);
197   assert(dbuf->buf != NULL);
198
199   buf = realloc(dbuf->buf, dbuf->len);
200
201   if (buf != NULL) {
202     dbuf->alloc = dbuf->len;
203     dbuf->buf = buf;
204   }
205
206   return buf != NULL;
207 }
208
209
210 /*
211  * Detach the buffer from dbuf structure.
212  * The dbuf structure can be reused by
213  * reinitializing it.
214  *
215  * See: dbuf_init()
216  */
217
218 void *dbuf_detach(struct dbuf_s *dbuf)
219 {
220   void *ret;
221
222   assert(dbuf != NULL);
223   assert(dbuf->alloc != 0);
224   assert(dbuf->buf != NULL);
225
226   ret = dbuf->buf;
227   dbuf->buf = NULL;
228   dbuf->len = 0;
229   dbuf->alloc = 0;
230
231   return ret;
232 }
233
234
235 /*
236  * Destroy the dbuf structure and
237  * free the buffer
238  */
239
240 void dbuf_destroy(struct dbuf_s *dbuf)
241 {
242   free(dbuf_detach(dbuf));
243 }
244
245
246 /*
247  * Delete dbuf structure on the heap:
248  * destroy it and free the allocated space.
249  * The user's responsablity is not to use
250  * the pointer any more: the best think to do
251  * is to set the pointer to NULL value.
252  *
253  * See dbuf_new()
254  */
255
256 void dbuf_delete(struct dbuf_s *dbuf)
257 {
258   dbuf_destroy(dbuf);
259   free(dbuf);
260 }