]> git.meshlink.io Git - catta/blob - avahi-common/strlst.c
* allow the user to specify a static browse domain list in the configuration file
[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(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;
74     
75     assert(data);
76     assert(ret);
77
78     r = NULL;
79
80     c = data;
81     while (size > 0) {
82         size_t k;
83         
84         k = *(c++);
85         size--;
86
87         if (k > size)
88             goto fail; /* Overflow */
89
90         if (k > 0) { /* Ignore empty strings */
91             AvahiStringList *n;
92
93             if (!(n = avahi_string_list_add_arbitrary(r, c, k)))  
94                 goto fail; /* OOM */
95
96             r = n;
97         }
98             
99         c += k;
100         size -= k;
101     }
102
103     *ret = r;
104     
105     return 0;
106
107 fail:
108     avahi_string_list_free(*ret);
109     return -1;
110 }
111
112 void avahi_string_list_free(AvahiStringList *l) {
113     AvahiStringList *n;
114
115     while (l) {
116         n = l->next;
117         avahi_free(l);
118         l = n;
119     }
120 }
121
122 AvahiStringList* avahi_string_list_reverse(AvahiStringList *l) {
123     AvahiStringList *r = NULL, *n;
124
125     while (l) {
126         n = l->next;
127         l->next = r;
128         r = l;
129         l = n;
130     }
131
132     return r;
133 }
134
135 char* avahi_string_list_to_string(AvahiStringList *l) {
136     AvahiStringList *n;
137     size_t s = 0;
138     char *t, *e;
139
140     for (n = l; n; n = n->next) {
141         if (n != l)
142             s ++;
143
144         s += n->size+2;
145     }
146
147     if (!(t = e = avahi_new(char, s+1)))
148         return NULL;
149
150     l = avahi_string_list_reverse(l);
151     
152     for (n = l; n; n = n->next) {
153         if (n != l)
154             *(e++) = ' ';
155
156         *(e++) = '"';
157         strncpy(e, (char*) n->text, n->size);
158         e[n->size] = 0;
159         e = strchr(e, 0);
160         *(e++) = '"';
161
162         assert(e);
163     }
164
165     l = avahi_string_list_reverse(l);
166     
167     *e = 0;
168
169     return t;
170 }
171
172 size_t avahi_string_list_serialize(AvahiStringList *l, void *data, size_t size) {
173     size_t used = 0;
174
175     if (data) {
176     
177         if (l) {
178             uint8_t *c;
179             AvahiStringList *n;
180         
181             l = avahi_string_list_reverse(l);
182             c = data;
183             
184             for (n = l; n; n = n->next) {
185                 size_t k;
186                 if (size < 1)
187                     break;
188                 
189                 k = n->size;
190                 if (k > 255)
191                     k = 255;
192                 
193                 if (k > size-1)
194                     k = size-1;
195                 
196                 *(c++) = k;
197                 memcpy(c, n->text, k);
198                 c += k;
199                 
200                 used += 1+ k;
201             }
202         
203             l = avahi_string_list_reverse(l);
204             
205         } else {
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             if (size > 0) {
212                 *(uint8_t*) data = 0;
213                 used = 1;
214             }
215             
216         }
217             
218     } else {
219         AvahiStringList *n;
220
221         if (!l)
222             used = 1;
223         else {
224
225             for (n = l; n; n = n->next) {
226                 size_t k;
227                 
228                 k = n->size;
229                 if (k > 255)
230                     k = 255;
231                 
232                 used += 1+k;
233             }
234         }
235     }
236
237     return used;
238 }
239
240 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
241
242     for (;;) {
243         if (!a && !b)
244             return 1;
245
246         if (!a || !b)
247             return 0;
248
249         if (a->size != b->size)
250             return 0;
251
252         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
253             return 0;
254
255         a = a->next;
256         b = b->next;
257     }
258 }
259
260 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
261     va_list va;
262
263     va_start(va, r);
264     r = avahi_string_list_add_many_va(r, va);
265     va_end(va);
266     
267     return r;
268 }
269
270 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
271     const char *txt;
272
273     while ((txt = va_arg(va, const char*)))
274         r = avahi_string_list_add(r, txt);
275
276     return r;
277 }
278
279 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
280     va_list va;
281     AvahiStringList *r = NULL;
282
283     if (txt) {
284         r = avahi_string_list_add(r, txt);
285
286         va_start(va, txt);
287         r = avahi_string_list_add_many_va(r, va);
288         va_end(va);
289     }
290
291     return r;
292 }
293
294 AvahiStringList *avahi_string_list_new_va(va_list va) {
295     return avahi_string_list_add_many_va(NULL, va);
296 }
297
298 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
299     AvahiStringList *r = NULL;
300
301     for (; l; l = l->next)
302         if (!(r = avahi_string_list_add_arbitrary(r, l->text, l->size))) {
303             avahi_string_list_free(r);
304             return NULL;
305         }
306
307     return avahi_string_list_reverse(r);
308 }
309
310 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
311     AvahiStringList *r = NULL;
312     int i;
313
314     assert(array);
315
316     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
317         r = avahi_string_list_add(r, array[i]);
318
319     return r;
320 }
321
322 unsigned avahi_string_list_length(const AvahiStringList *l) {
323     unsigned n = 0;
324
325     for (; l; l = l->next)
326         n++;
327
328     return n;
329 }
330
331 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
332     size_t len = 80;
333     AvahiStringList *r;
334     
335     assert(format);
336
337     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
338         return NULL;
339
340     for (;;) {
341         int n;
342         AvahiStringList *nr;
343         
344         n = vsnprintf((char*) r->text, len+1, format, va);
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     
363     r->next = l;
364     r->size = strlen((char*) r->text); 
365
366     return r;
367 }
368
369 AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
370     va_list va;
371     
372     assert(format);
373
374     va_start(va, format);
375     l  = avahi_string_list_add_vprintf(l, format, va);
376     va_end(va);
377
378     return l;    
379 }
380
381 AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
382     size_t n;
383     
384     assert(key);
385     n = strlen(key);
386
387     for (; l; l = l->next) {
388         if (strcasecmp((char*) l->text, key) == 0)
389             return l;
390
391         if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
392             return l;
393     }
394
395     return NULL;
396 }
397
398 AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
399     assert(key);
400
401     if (value)
402         return avahi_string_list_add_printf(l, "%s=%s", key, value);
403     else
404         return avahi_string_list_add(l, key);
405 }
406
407 AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
408     size_t n;
409     assert(key);
410
411     if (!value)
412         return avahi_string_list_add(l, key);
413
414     n = strlen(key);
415     
416     if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
417         return NULL;
418
419     memcpy(l->text, key, n);
420     l->text[n] = '=';
421     memcpy(l->text + n + 1, value, size);
422
423     return l;
424 }
425
426 int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
427     char *e;
428     
429     assert(l);
430
431     if (!(e = memchr(l->text, '=', l->size))) {
432
433         if (key) 
434             if (!(*key = avahi_strdup((char*) l->text)))
435                 return -1;
436
437         if (value)
438             *value = NULL;
439
440         if (size)
441             *size = 0;
442
443     } else {
444         size_t n;
445
446         if (key)
447             if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
448                 return -1;
449
450         e++; /* Advance after '=' */
451         
452         n = l->size - (e - (char*) l->text);
453         
454         if (value) {
455
456             if (!(*value = avahi_memdup(e, n+1))) {
457                 if (key)
458                     avahi_free(*key);
459                 return -1;
460             }
461
462             (*value)[n] = 0;
463         }
464
465         if (size)
466             *size = n;
467     }
468
469     return 0;
470 }
471
472 AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
473     assert(l);
474     return l->next;
475 }
476
477 uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
478     assert(l);
479     return l->text;
480 }
481
482 size_t avahi_string_list_get_size(AvahiStringList *l) {
483     assert(l);
484     return l->size;
485 }
486
487 uint32_t avahi_string_list_get_service_cookie(AvahiStringList *l) {
488     AvahiStringList *f;
489     char *value = NULL, *end = NULL;
490     uint32_t ret;
491     
492     if (!(f = avahi_string_list_find(l, AVAHI_SERVICE_COOKIE)))
493         return AVAHI_SERVICE_COOKIE_INVALID;
494
495     if (avahi_string_list_get_pair(f, NULL, &value, NULL) < 0 || !value)
496         return AVAHI_SERVICE_COOKIE_INVALID;
497
498     ret = (uint32_t) strtoll(value, &end, 0);
499
500     if (*value && end && *end != 0) {
501         avahi_free(value);
502         return AVAHI_SERVICE_COOKIE_INVALID;
503     }
504
505     avahi_free(value);
506     
507     return ret;
508 }