960c5266157c9e84217cf0443e9cde148f4007d2
[olsrd.git] / src / common / autobuf.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include "common/autobuf.h"
43 #include "defs.h"
44
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <limits.h>
50 #include <assert.h>
51
52
53 static int autobuf_enlarge(struct autobuf *autobuf, int new_size);
54
55 static int ROUND_UP_TO_POWER_OF_2(int val, int pow2) {
56   assert(val >= 0);
57   assert(pow2 > 0);
58
59   if (val <= (INT32_MAX - (pow2 - 1))) {
60     /* no overflow */
61     return ((val + (pow2 - 1)) & ~(pow2 - 1));
62   }
63
64   /* overflow */
65   return (INT32_MAX & ~(pow2 - 1));
66 }
67
68 int
69 abuf_init(struct autobuf *autobuf, int initial_size)
70 {
71   autobuf->len = 0;
72   if (initial_size <= 0) {
73     autobuf->size = 0;
74     autobuf->buf = NULL;
75     return 0;
76   }
77   autobuf->size = ROUND_UP_TO_POWER_OF_2(initial_size, AUTOBUFCHUNK);
78   autobuf->buf = calloc(autobuf->size, 1);
79   if (autobuf->buf == NULL) {
80     autobuf->size = 0;
81     return -1;
82   }
83   *autobuf->buf = '\0';
84   return 0;
85 }
86
87 void
88 abuf_free(struct autobuf *autobuf)
89 {
90   free(autobuf->buf);
91   autobuf->buf = NULL;
92   autobuf->len = 0;
93   autobuf->size = 0;
94 }
95
96 static int
97 autobuf_enlarge(struct autobuf *autobuf, int new_size)
98 {
99   new_size++;
100
101   if (autobuf->size >= INT_MAX) {
102     return -1;
103   }
104
105   if (new_size > autobuf->size) {
106     char *p;
107     int roundUpSize = ROUND_UP_TO_POWER_OF_2(new_size, AUTOBUFCHUNK);
108     p = realloc(autobuf->buf, roundUpSize);
109     if (p == NULL) {
110 #ifdef _WIN32
111       WSASetLastError(ENOMEM);
112 #else /* _WIN32 */
113       errno = ENOMEM;
114 #endif /* _WIN32 */
115       return -1;
116     }
117     autobuf->buf = p;
118
119     memset(&autobuf->buf[autobuf->size], 0, roundUpSize - autobuf->size);
120     autobuf->size = roundUpSize;
121   }
122   return 0;
123 }
124
125 int
126 abuf_vappendf(struct autobuf *autobuf, const char *format, va_list ap)
127 {
128   int rc;
129   int min_size;
130   va_list ap2;
131   va_copy(ap2, ap);
132   rc = vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap);
133   va_end(ap);
134   min_size = autobuf->len + rc;
135   if (min_size >= autobuf->size) {
136     if (autobuf_enlarge(autobuf, min_size) < 0) {
137       autobuf->buf[autobuf->len] = '\0';
138       va_end(ap2);
139       return -1;
140     }
141     vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap2);
142   }
143   va_end(ap2);
144   autobuf->len = min_size;
145   return 0;
146 }
147
148 int
149 abuf_appendf(struct autobuf *autobuf, const char *fmt, ...)
150 {
151   int rv;
152   va_list ap;
153   va_start(ap, fmt);
154   rv = abuf_vappendf(autobuf, fmt, ap);
155   va_end(ap);
156   return rv;
157 }
158
159 int
160 abuf_puts(struct autobuf *autobuf, const char *s)
161 {
162   int len; 
163
164   if (NULL == s) return 0;
165   len = strlen(s);
166   if (autobuf_enlarge(autobuf, autobuf->len + len + 1) < 0) {
167     return -1;
168   }
169   strcpy(autobuf->buf + autobuf->len, s);
170   autobuf->len += len;
171   return len;
172 }
173
174 int
175 abuf_strftime(struct autobuf *autobuf, const char *format, const struct tm *tm)
176 {
177   int rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
178   if (rc == 0) {
179     /* we had an error! Probably the buffer too small. So we add some bytes. */
180     if (autobuf_enlarge(autobuf, autobuf->size + AUTOBUFCHUNK) < 0) {
181       autobuf->buf[autobuf->len] = '\0';
182       return -1;
183     }
184     rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
185   }
186   autobuf->len += rc;
187   return rc;
188 }
189
190 int
191 abuf_memcpy(struct autobuf *autobuf, const void *p, const unsigned int len)
192 {
193   if (autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
194     return -1;
195   }
196   memcpy(autobuf->buf + autobuf->len, p, len);
197   autobuf->len += len;
198   return len;
199 }
200
201 int
202 abuf_memcpy_prefix(struct autobuf *autobuf, const void *p, const unsigned int len)
203 {
204   if (autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
205     return -1;
206   }
207   memmove(&autobuf->buf[len], autobuf->buf, autobuf->len);
208   memcpy(autobuf->buf, p, len);
209   autobuf->len += len;
210   return len;
211 }
212
213 int
214 abuf_pull(struct autobuf * autobuf, int len) {
215   char *p;
216   size_t newsize;
217
218   if (len != autobuf->len) {
219     memmove(autobuf->buf, &autobuf->buf[len], autobuf->len - len);
220   }
221   autobuf->len -= len;
222
223   newsize = ROUND_UP_TO_POWER_OF_2(autobuf->len + 1, AUTOBUFCHUNK);
224   p = realloc(autobuf->buf, newsize);
225   if (p == NULL) {
226 #ifdef _WIN32
227     WSASetLastError(ENOMEM);
228 #else /* _WIN32 */
229     errno = ENOMEM;
230 #endif /* _WIN32 */
231     return -1;
232   }
233   autobuf->buf = p;
234   autobuf->size = newsize;
235   return 0;
236 }
237 /*
238  * Local Variables:
239  * mode: c
240  * style: linux
241  * c-basic-offset: 4
242  * indent-tabs-mode: nil
243  * End:
244  */