1 /***
2 This file is part of avahi.
3
4 avahi is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 avahi is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with avahi; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <stdio.h>
28 #include <unistd.h>
29
30 #include "avahi-malloc.h"
31
32 #ifndef va_copy
33 #ifdef __va_copy
34 #define va_copy(DEST,SRC) __va_copy((DEST),(SRC))
35 #else
36 #define va_copy(DEST,SRC) memcpy(&(DEST), &(SRC), sizeof(va_list))
37 #endif
38 #endif
39
40 static const AvahiAllocator *allocator = NULL;
41
42 static void oom(void) AVAHI_GCC_NORETURN;
43
oom(void)44 static void oom(void) {
45
46 static const char msg[] = "Out of memory, aborting ...\n";
47 const char *n = msg;
48
49 while (strlen(n) > 0) {
50 ssize_t r;
51
52 if ((r = write(2, n, strlen(n))) < 0)
53 break;
54
55 n += r;
56 }
57
58 abort();
59 }
60
61 /* Default implementation for avahi_malloc() */
xmalloc(size_t size)62 static void* xmalloc(size_t size) {
63 void *p;
64
65 if (size == 0)
66 return NULL;
67
68 if (!(p = malloc(size)))
69 oom();
70
71 return p;
72 }
73
74 /* Default implementation for avahi_realloc() */
xrealloc(void * p,size_t size)75 static void *xrealloc(void *p, size_t size) {
76
77 if (size == 0) {
78 free(p);
79 return NULL;
80 }
81
82 if (!(p = realloc(p, size)))
83 oom();
84
85 return p;
86 }
87
88 /* Default implementation for avahi_calloc() */
xcalloc(size_t nmemb,size_t size)89 static void *xcalloc(size_t nmemb, size_t size) {
90 void *p;
91
92 if (size == 0 || nmemb == 0)
93 return NULL;
94
95 if (!(p = calloc(nmemb, size)))
96 oom();
97
98 return p;
99 }
100
avahi_malloc(size_t size)101 void *avahi_malloc(size_t size) {
102
103 if (size <= 0)
104 return NULL;
105
106 if (!allocator)
107 return xmalloc(size);
108
109 assert(allocator->malloc);
110 return allocator->malloc(size);
111 }
112
avahi_malloc0(size_t size)113 void *avahi_malloc0(size_t size) {
114 void *p;
115
116 if (size <= 0)
117 return NULL;
118
119 if (!allocator)
120 return xcalloc(1, size);
121
122 if (allocator->calloc)
123 return allocator->calloc(1, size);
124
125 assert(allocator->malloc);
126 if ((p = allocator->malloc(size)))
127 memset(p, 0, size);
128
129 return p;
130 }
131
avahi_free(void * p)132 void avahi_free(void *p) {
133
134 if (!p)
135 return;
136
137 if (!allocator) {
138 free(p);
139 return;
140 }
141
142 assert(allocator->free);
143 allocator->free(p);
144 }
145
avahi_realloc(void * p,size_t size)146 void *avahi_realloc(void *p, size_t size) {
147
148 if (size == 0) {
149 avahi_free(p);
150 return NULL;
151 }
152
153 if (!allocator)
154 return xrealloc(p, size);
155
156 assert(allocator->realloc);
157 return allocator->realloc(p, size);
158 }
159
avahi_strdup(const char * s)160 char *avahi_strdup(const char *s) {
161 char *r;
162 size_t size;
163
164 if (!s)
165 return NULL;
166
167 size = strlen(s);
168 if (!(r = avahi_malloc(size+1)))
169 return NULL;
170
171 memcpy(r, s, size+1);
172 return r;
173 }
174
avahi_strndup(const char * s,size_t max)175 char *avahi_strndup(const char *s, size_t max) {
176 char *r;
177 size_t size;
178 const char *p;
179
180 if (!s)
181 return NULL;
182
183 for (p = s, size = 0;
184 size < max && *p;
185 p++, size++);
186
187 if (!(r = avahi_new(char, size+1)))
188 return NULL;
189
190 memcpy(r, s, size);
191 r[size] = 0;
192 return r;
193 }
194
195 /* Change the allocator */
avahi_set_allocator(const AvahiAllocator * a)196 void avahi_set_allocator(const AvahiAllocator *a) {
197 allocator = a;
198 }
199
avahi_strdup_vprintf(const char * fmt,va_list ap)200 char *avahi_strdup_vprintf(const char *fmt, va_list ap) {
201 size_t len = 80;
202 char *buf;
203
204 assert(fmt);
205
206 if (!(buf = avahi_malloc(len)))
207 return NULL;
208
209 for (;;) {
210 int n;
211 char *nbuf;
212 va_list ap2;
213
214 va_copy (ap2, ap);
215 n = vsnprintf(buf, len, fmt, ap2);
216 va_end (ap2);
217
218 if (n >= 0 && n < (int) len)
219 return buf;
220
221 if (n >= 0)
222 len = n+1;
223 else
224 len *= 2;
225
226 if (!(nbuf = avahi_realloc(buf, len))) {
227 avahi_free(buf);
228 return NULL;
229 }
230
231 buf = nbuf;
232 }
233 }
234
avahi_strdup_printf(const char * fmt,...)235 char *avahi_strdup_printf(const char *fmt, ... ) {
236 char *s;
237 va_list ap;
238
239 assert(fmt);
240
241 va_start(ap, fmt);
242 s = avahi_strdup_vprintf(fmt, ap);
243 va_end(ap);
244
245 return s;
246 }
247
avahi_memdup(const void * s,size_t l)248 void *avahi_memdup(const void *s, size_t l) {
249 void *p;
250 assert(s);
251
252 if (!(p = avahi_malloc(l)))
253 return NULL;
254
255 memcpy(p, s, l);
256 return p;
257 }
258