]> git.meshlink.io Git - catta/blob - avahi-common/strlst.c
from now on we enforce a strict whitespace regime
[catta] / avahi-common / strlst.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <stdarg.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "strlst.h"
33 #include "malloc.h"
34 #include "defs.h"
35
36 AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) {
37     AvahiStringList *n;
38
39     if (!(n = avahi_malloc(sizeof(AvahiStringList) + size)))
40         return NULL;
41
42     n->next = l;
43     n->size = size;
44
45     /* NUL terminate strings, just to make sure */
46     n->text[size] = 0;
47
48     return n;
49 }
50
51 AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const uint8_t*text, size_t size) {
52     AvahiStringList *n;
53
54     assert(size == 0 || text);
55
56     if (!(n = avahi_string_list_add_anonymous(l, size)))
57         return NULL;
58
59     if (size > 0)
60         memcpy(n->text, text, size);
61
62     return n;
63 }
64
65 AvahiStringList *avahi_string_list_add(AvahiStringList *l, const char *text) {
66     assert(text);
67
68     return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
69 }
70
71 int avahi_string_list_parse(const void* data, size_t size, AvahiStringList **ret) {
72     const uint8_t *c;
73     AvahiStringList *r = NULL;
74
75     assert(data);
76     assert(ret);
77
78     c = data;
79     while (size > 0) {
80         size_t k;
81
82         k = *(c++);
83         size--;
84
85         if (k > size)
86             goto fail; /* Overflow */
87
88         if (k > 0) { /* Ignore empty strings */
89             AvahiStringList *n;
90
91             if (!(n = avahi_string_list_add_arbitrary(r, c, k)))
92                 goto fail; /* OOM */
93
94             r = n;
95         }
96
97         c += k;
98         size -= k;
99     }
100
101     *ret = r;
102
103     return 0;
104
105 fail:
106     avahi_string_list_free(r);
107     return -1;
108 }
109
110 void avahi_string_list_free(AvahiStringList *l) {
111     AvahiStringList *n;
112
113     while (l) {
114         n = l->next;
115         avahi_free(l);
116         l = n;
117     }
118 }
119
120 AvahiStringList* avahi_string_list_reverse(AvahiStringList *l) {
121     AvahiStringList *r = NULL, *n;
122
123     while (l) {
124         n = l->next;
125         l->next = r;
126         r = l;
127         l = n;
128     }
129
130     return r;
131 }
132
133 char* avahi_string_list_to_string(AvahiStringList *l) {
134     AvahiStringList *n;
135     size_t s = 0;
136     char *t, *e;
137
138     for (n = l; n; n = n->next) {
139         if (n != l)
140             s ++;
141
142         s += n->size+2;
143     }
144
145     if (!(t = e = avahi_new(char, s+1)))
146         return NULL;
147
148     l = avahi_string_list_reverse(l);
149
150     for (n = l; n; n = n->next) {
151         if (n != l)
152             *(e++) = ' ';
153
154         *(e++) = '"';
155         strncpy(e, (char*) n->text, n->size);
156         e[n->size] = 0;
157         e = strchr(e, 0);
158         *(e++) = '"';
159
160         assert(e);
161     }
162
163     l = avahi_string_list_reverse(l);
164
165     *e = 0;
166
167     return t;
168 }
169
170 size_t avahi_string_list_serialize(AvahiStringList *l, void *data, size_t size) {
171     size_t used = 0;
172
173     if (data) {
174         AvahiStringList *n;
175         uint8_t *c;
176
177         l = avahi_string_list_reverse(l);
178         c = data;
179
180         for (n = l; size > 1 && n; n = n->next) {
181             size_t k;
182
183             if ((k = n->size) == 0)
184                 /* Skip empty strings */
185                 continue;
186
187             if (k > 255)
188                 /* Truncate strings at 255 characters */
189                 k = 255;
190
191             if (k > size-1)
192                 /* Make sure this string fits in */
193                 k = size-1;
194
195             *(c++) = (uint8_t) k;
196             memcpy(c, n->text, k);
197             c += k;
198
199             used += 1 + k;
200             size -= 1 + k;
201         }
202
203         l = avahi_string_list_reverse(l);
204
205         if (used == 0 && size > 0) {
206
207             /* Empty lists are treated specially. To comply with
208              * section 6.1 of the DNS-SD spec, we return a single
209              * empty string (i.e. a NUL byte)*/
210
211             *(uint8_t*) data = 0;
212             used = 1;
213         }
214
215     } else {
216         AvahiStringList *n;
217
218         for (n = l; n; n = n->next) {
219             size_t k;
220
221             if ((k = n->size) == 0)
222                 continue;
223
224             if (k > 255)
225                 k = 255;
226
227             used += 1+k;
228         }
229
230         if (used == 0)
231             used = 1;
232     }
233
234     return used;
235 }
236
237 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
238
239     for (;;) {
240         if (!a && !b)
241             return 1;
242
243         if (!a || !b)
244             return 0;
245
246         if (a->size != b->size)
247             return 0;
248
249         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
250             return 0;
251
252         a = a->next;
253         b = b->next;
254     }
255 }
256
257 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
258     va_list va;
259
260     va_start(va, r);
261     r = avahi_string_list_add_many_va(r, va);
262     va_end(va);
263
264     return r;
265 }
266
267 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
268     const char *txt;
269
270     while ((txt = va_arg(va, const char*)))
271         r = avahi_string_list_add(r, txt);
272
273     return r;
274 }
275
276 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
277     va_list va;
278     AvahiStringList *r = NULL;
279
280     if (txt) {
281         r = avahi_string_list_add(r, txt);
282
283         va_start(va, txt);
284         r = avahi_string_list_add_many_va(r, va);
285         va_end(va);
286     }
287
288     return r;
289 }
290
291 AvahiStringList *avahi_string_list_new_va(va_list va) {
292     return avahi_string_list_add_many_va(NULL, va);
293 }
294
295 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
296     AvahiStringList *r = NULL;
297
298     for (; l; l = l->next)
299         if (!(r = avahi_string_list_add_arbitrary(r, l->text, l->size))) {
300             avahi_string_list_free(r);
301             return NULL;
302         }
303
304     return avahi_string_list_reverse(r);
305 }
306
307 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
308     AvahiStringList *r = NULL;
309     int i;
310
311     assert(array);
312
313     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
314         r = avahi_string_list_add(r, array[i]);
315
316     return r;
317 }
318
319 unsigned avahi_string_list_length(const AvahiStringList *l) {
320     unsigned n = 0;
321
322     for (; l; l = l->next)
323         n++;
324
325     return n;
326 }
327
328 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
329     size_t len = 80;
330     AvahiStringList *r;
331
332     assert(format);
333
334     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
335         return NULL;
336
337     for (;;) {
338         int n;
339         AvahiStringList *nr;
340         va_list va2;
341
342         va_copy(va2, va);
343         n = vsnprintf((char*) r->text, len, format, va2);
344         va_end(va2);
345
346         if (n >= 0 && n < (int) len)
347             break;
348
349         if (n >= 0)
350             len = n+1;
351         else
352             len *= 2;
353
354         if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
355             avahi_free(r);
356             return NULL;
357         }
358
359         r = nr;
360     }
361
362     r->next = l;
363     r->size = strlen((char*) r->text);
364
365     return r;
366 }
367
368 AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
369     va_list va;
370
371     assert(format);
372
373     va_start(va, format);
374     l  = avahi_string_list_add_vprintf(l, format, va);
375     va_end(va);
376
377     return l;
378 }
379
380 AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
381     size_t n;
382
383     assert(key);
384     n = strlen(key);
385
386     for (; l; l = l->next) {
387         if (strcasecmp((char*) l->text, key) == 0)
388             return l;
389
390         if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
391             return l;
392     }
393
394     return NULL;
395 }
396
397 AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
398     assert(key);
399
400     if (value)
401         return avahi_string_list_add_printf(l, "%s=%s", key, value);
402     else
403         return avahi_string_list_add(l, key);
404 }
405
406 AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
407     size_t n;
408     assert(key);
409
410     if (!value)
411         return avahi_string_list_add(l, key);
412
413     n = strlen(key);
414
415     if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
416         return NULL;
417
418     memcpy(l->text, key, n);
419     l->text[n] = '=';
420     memcpy(l->text + n + 1, value, size);
421
422     return l;
423 }
424
425 int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
426     char *e;
427
428     assert(l);
429
430     if (!(e = memchr(l->text, '=', l->size))) {
431
432         if (key)
433             if (!(*key = avahi_strdup((char*) l->text)))
434                 return -1;
435
436         if (value)
437             *value = NULL;
438
439         if (size)
440             *size = 0;
441
442     } else {
443         size_t n;
444
445         if (key)
446             if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
447                 return -1;
448
449         e++; /* Advance after '=' */
450
451         n = l->size - (e - (char*) l->text);
452
453         if (value) {
454
455             if (!(*value = avahi_memdup(e, n+1))) {
456                 if (key)
457                     avahi_free(*key);
458                 return -1;
459             }
460
461             (*value)[n] = 0;
462         }
463
464         if (size)
465             *size = n;
466     }
467
468     return 0;
469 }
470
471 AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
472     assert(l);
473     return l->next;
474 }
475
476 uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
477     assert(l);
478     return l->text;
479 }
480
481 size_t avahi_string_list_get_size(AvahiStringList *l) {
482     assert(l);
483     return l->size;
484 }
485
486 uint32_t avahi_string_list_get_service_cookie(AvahiStringList *l) {
487     AvahiStringList *f;
488     char *value = NULL, *end = NULL;
489     uint32_t ret;
490
491     if (!(f = avahi_string_list_find(l, AVAHI_SERVICE_COOKIE)))
492         return AVAHI_SERVICE_COOKIE_INVALID;
493
494     if (avahi_string_list_get_pair(f, NULL, &value, NULL) < 0 || !value)
495         return AVAHI_SERVICE_COOKIE_INVALID;
496
497     ret = (uint32_t) strtoll(value, &end, 0);
498
499     if (*value && end && *end != 0) {
500         avahi_free(value);
501         return AVAHI_SERVICE_COOKIE_INVALID;
502     }
503
504     avahi_free(value);
505
506     return ret;
507 }