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 "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
40static const AvahiAllocator *allocator = NULL;
41
42static void oom(void) AVAHI_GCC_NORETURN;
43
44static 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() */
62static 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() */
75static 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() */
89static 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
101void *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
113void *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
132void 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
146void *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
160char *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
175char *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 */
196void avahi_set_allocator(const AvahiAllocator *a) {
197    allocator = a;
198}
199
200char *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
235char *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
248void *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