fixed bug #702907
[fw/sdcc] / support / Util / dbuf.c
1 /*
2   dbuf.c - Dynamic buffer implementation
3   version 1.1.0, March 28th, 2003
4
5   Copyright (c) 2003 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 (((char *)dbuf->buf)[dbuf->len] != '\0') {
150     dbuf_expand(dbuf, 1);
151     ((char *)dbuf->buf)[dbuf->len] = '\0';
152   }
153
154   return dbuf->buf;
155 }
156
157
158 /*
159  * Get the buffer pointer.
160  */
161
162 const void *dbuf_get_buf(struct dbuf_s *dbuf)
163 {
164   assert(dbuf != NULL);
165   assert(dbuf->alloc != 0);
166   assert(dbuf->buf != NULL);
167
168   return dbuf->buf;
169 }
170
171
172 /*
173  * Get the buffer size.
174  */
175
176 size_t dbuf_get_size(struct dbuf_s *dbuf)
177 {
178   assert(dbuf != NULL);
179   assert(dbuf->alloc != 0);
180   assert(dbuf->buf != NULL);
181
182   return dbuf->len;
183 }
184
185
186 /*
187  * Trim the allocated buffer to required size
188  */
189
190 int dbuf_trim(struct dbuf_s *dbuf)
191 {
192   void *buf;
193
194   assert(dbuf != NULL);
195   assert(dbuf->alloc != 0);
196   assert(dbuf->buf != NULL);
197
198   buf = realloc(dbuf->buf, dbuf->len);
199
200   if (buf != NULL) {
201     dbuf->alloc = dbuf->len;
202     dbuf->buf = buf;
203   }
204
205   return buf != NULL;
206 }
207
208
209 /*
210  * Detach the buffer from dbuf structure.
211  * The dbuf structure can be reused by
212  * reinitializing it.
213  *
214  * See: dbuf_init()
215  */
216
217 void *dbuf_detach(struct dbuf_s *dbuf)
218 {
219   void *ret;
220
221   assert(dbuf != NULL);
222   assert(dbuf->alloc != 0);
223   assert(dbuf->buf != NULL);
224
225   ret = dbuf->buf;
226   dbuf->buf = NULL;
227   dbuf->len = 0;
228   dbuf->alloc = 0;
229
230   return ret;
231 }
232
233
234 /*
235  * Destroy the dbuf structure and
236  * free the buffer
237  */
238
239 void dbuf_destroy(struct dbuf_s *dbuf)
240 {
241   free(dbuf_detach(dbuf));
242 }
243
244
245 /*
246  * Delete dbuf structure on the heap:
247  * destroy it and free the allocated space.
248  * The user's responsablity is not to use
249  * the pointer any more: the best think to do
250  * is to set the pointer to NULL value.
251  *
252  * See dbuf_new()
253  */
254
255 void dbuf_delete(struct dbuf_s *dbuf)
256 {
257   dbuf_destroy(dbuf);
258   free(dbuf);
259 }