02cd65abd4171f6978680064beeac85d27fc03f4
[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
51
52 static int autobuf_enlarge(struct autobuf *autobuf, int new_size);
53
54
55 int
56 abuf_init(struct autobuf *autobuf, int initial_size)
57 {
58   autobuf->len = 0;
59   if (initial_size <= 0) {
60     autobuf->size = 0;
61     autobuf->buf = NULL;
62     return 0;
63   }
64   autobuf->size = ROUND_UP_TO_POWER_OF_2(initial_size, AUTOBUFCHUNK);
65   autobuf->buf = calloc(autobuf->size, 1);
66   if (autobuf->buf == NULL) {
67     autobuf->size = 0;
68     return -1;
69   }
70   *autobuf->buf = '\0';
71   return 0;
72 }
73
74 void
75 abuf_free(struct autobuf *autobuf)
76 {
77   free(autobuf->buf);
78   autobuf->buf = NULL;
79   autobuf->len = 0;
80   autobuf->size = 0;
81 }
82
83 static int
84 autobuf_enlarge(struct autobuf *autobuf, int new_size)
85 {
86   new_size++;
87
88   if (autobuf->size >= INT_MAX) {
89     return -1;
90   }
91
92   if (new_size > autobuf->size) {
93     char *p;
94     int roundUpSize = ROUND_UP_TO_POWER_OF_2(new_size, AUTOBUFCHUNK);
95     p = realloc(autobuf->buf, roundUpSize);
96     if (p == NULL) {
97 #ifdef _WIN32
98       WSASetLastError(ENOMEM);
99 #else /* _WIN32 */
100       errno = ENOMEM;
101 #endif /* _WIN32 */
102       return -1;
103     }
104     autobuf->buf = p;
105
106     memset(&autobuf->buf[autobuf->size], 0, roundUpSize - autobuf->size);
107     autobuf->size = roundUpSize;
108   }
109   return 0;
110 }
111
112 int
113 abuf_vappendf(struct autobuf *autobuf, const char *format, va_list ap)
114 {
115   int rc;
116   int min_size;
117   va_list ap2;
118   va_copy(ap2, ap);
119   rc = vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap);
120   va_end(ap);
121   min_size = autobuf->len + rc;
122   if (min_size >= autobuf->size) {
123     if (autobuf_enlarge(autobuf, min_size) < 0) {
124       autobuf->buf[autobuf->len] = '\0';
125       va_end(ap2);
126       return -1;
127     }
128     vsnprintf(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, ap2);
129   }
130   va_end(ap2);
131   autobuf->len = min_size;
132   return 0;
133 }
134
135 int
136 abuf_appendf(struct autobuf *autobuf, const char *fmt, ...)
137 {
138   int rv;
139   va_list ap;
140   va_start(ap, fmt);
141   rv = abuf_vappendf(autobuf, fmt, ap);
142   va_end(ap);
143   return rv;
144 }
145
146 int
147 abuf_puts(struct autobuf *autobuf, const char *s)
148 {
149   int len; 
150
151   if (NULL == s) return 0;
152   len = strlen(s);
153   if (autobuf_enlarge(autobuf, autobuf->len + len + 1) < 0) {
154     return -1;
155   }
156   strscpy(autobuf->buf + autobuf->len, s, len);
157   autobuf->len += len;
158   return len;
159 }
160
161 int
162 abuf_strftime(struct autobuf *autobuf, const char *format, const struct tm *tm)
163 {
164   int rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
165   if (rc == 0) {
166     /* we had an error! Probably the buffer too small. So we add some bytes. */
167     if (autobuf_enlarge(autobuf, autobuf->size + AUTOBUFCHUNK) < 0) {
168       autobuf->buf[autobuf->len] = '\0';
169       return -1;
170     }
171     rc = strftime(autobuf->buf + autobuf->len, autobuf->size - autobuf->len, format, tm);
172   }
173   autobuf->len += rc;
174   return rc;
175 }
176
177 int
178 abuf_memcpy(struct autobuf *autobuf, const void *p, const unsigned int len)
179 {
180   if (autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
181     return -1;
182   }
183   memcpy(autobuf->buf + autobuf->len, p, len);
184   autobuf->len += len;
185   return len;
186 }
187
188 int
189 abuf_memcpy_prefix(struct autobuf *autobuf, const void *p, const unsigned int len)
190 {
191   if (autobuf_enlarge(autobuf, autobuf->len + len) < 0) {
192     return -1;
193   }
194   memmove(&autobuf->buf[len], autobuf->buf, autobuf->len);
195   memcpy(autobuf->buf, p, len);
196   autobuf->len += len;
197   return len;
198 }
199
200 int
201 abuf_pull(struct autobuf * autobuf, int len) {
202   char *p;
203   size_t newsize;
204
205   if (len != autobuf->len) {
206     memmove(autobuf->buf, &autobuf->buf[len], autobuf->len - len);
207   }
208   autobuf->len -= len;
209
210   newsize = ROUND_UP_TO_POWER_OF_2(autobuf->len + 1, AUTOBUFCHUNK);
211   p = realloc(autobuf->buf, newsize);
212   if (p == NULL) {
213 #ifdef _WIN32
214     WSASetLastError(ENOMEM);
215 #else /* _WIN32 */
216     errno = ENOMEM;
217 #endif /* _WIN32 */
218     return -1;
219   }
220   autobuf->buf = p;
221   autobuf->size = newsize;
222   return 0;
223 }
224 /*
225  * Local Variables:
226  * mode: c
227  * style: linux
228  * c-basic-offset: 4
229  * indent-tabs-mode: nil
230  * End:
231  */