]> git.meshlink.io Git - catta/blob - avahi-common/strlst.c
* fix behaviour of empty TXT lists
[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
31 #include "strlst.h"
32 #include "malloc.h"
33
34 AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) {
35     AvahiStringList *n;
36
37     if (!(n = avahi_malloc(sizeof(AvahiStringList) + size)))
38         return NULL;
39     
40     n->next = l;
41     n->size = size;
42
43     /* NUL terminate strings, just to make sure */
44     n->text[size] = 0;
45
46     return n;
47 }
48
49 AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const uint8_t*text, size_t size) {
50     AvahiStringList *n;
51
52     assert(text);
53
54     if (!(n = avahi_string_list_add_anonymous(l, size)))
55         return NULL;
56
57     if (size > 0)
58         memcpy(n->text, text, size);
59
60     return n;
61 }
62
63 AvahiStringList *avahi_string_list_add(AvahiStringList *l, const char *text) {
64     assert(text);
65
66     return avahi_string_list_add_arbitrary(l, (const uint8_t*) text, strlen(text));
67 }
68
69 AvahiStringList *avahi_string_list_parse(const void* data, size_t size) {
70     AvahiStringList *r = NULL;
71     const uint8_t *c;
72     
73     assert(data);
74
75     c = data;
76     for (;;) {
77         size_t k;
78         
79         if (size < 1)
80             break;
81
82         k = *(c++);
83
84         if (k > 0) /* Ignore empty strings */
85             r = avahi_string_list_add_arbitrary(r, c, k);
86         c += k;
87
88         size -= 1 + k;
89     }
90
91     return r;
92 }
93
94 void avahi_string_list_free(AvahiStringList *l) {
95     AvahiStringList *n;
96
97     while (l) {
98         n = l->next;
99         avahi_free(l);
100         l = n;
101     }
102 }
103
104 AvahiStringList* avahi_string_list_reverse(AvahiStringList *l) {
105     AvahiStringList *r = NULL, *n;
106
107     while (l) {
108         n = l->next;
109         l->next = r;
110         r = l;
111         l = n;
112     }
113
114     return r;
115 }
116
117 char* avahi_string_list_to_string(AvahiStringList *l) {
118     AvahiStringList *n;
119     size_t s = 0;
120     char *t, *e;
121
122     for (n = l; n; n = n->next) {
123         if (n != l)
124             s ++;
125
126         s += n->size+2;
127     }
128
129     if (!(t = e = avahi_new(char, s+1)))
130         return NULL;
131
132     l = avahi_string_list_reverse(l);
133     
134     for (n = l; n; n = n->next) {
135         if (n != l)
136             *(e++) = ' ';
137
138         *(e++) = '"';
139         strncpy(e, (char*) n->text, n->size);
140         e[n->size] = 0;
141         e = strchr(e, 0);
142         *(e++) = '"';
143
144         assert(e);
145     }
146
147     l = avahi_string_list_reverse(l);
148     
149     *e = 0;
150
151     return t;
152 }
153
154 size_t avahi_string_list_serialize(AvahiStringList *l, void *data, size_t size) {
155     size_t used = 0;
156
157     if (data) {
158     
159         if (l) {
160             uint8_t *c;
161             AvahiStringList *n;
162         
163             l = avahi_string_list_reverse(l);
164             c = data;
165             
166             for (n = l; n; n = n->next) {
167                 size_t k;
168                 if (size < 1)
169                     break;
170                 
171                 k = n->size;
172                 if (k > 255)
173                     k = 255;
174                 
175                 if (k > size-1)
176                     k = size-1;
177                 
178                 *(c++) = k;
179                 memcpy(c, n->text, k);
180                 c += k;
181                 
182                 used += 1+ k;
183             }
184         
185             l = avahi_string_list_reverse(l);
186             
187         } else {
188
189             /* Empty lists are treated specially. To comply with
190              * section 6.1 of the DNS-SD spec, we return a single
191              * empty string (i.e. a NUL byte)*/
192
193             if (size > 0) {
194                 *(uint8_t*) data = 0;
195                 used = 1;
196             }
197             
198         }
199             
200     } else {
201         AvahiStringList *n;
202
203         for (n = l; n; n = n->next) {
204             size_t k;
205         
206             k = n->size;
207             if (k > 255)
208                 k = 255;
209             
210             used += 1+k;
211         }
212     }
213
214     return used;
215 }
216
217 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
218
219     for (;;) {
220         if (!a && !b)
221             return 1;
222
223         if (!a || !b)
224             return 0;
225
226         if (a->size != b->size)
227             return 0;
228
229         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
230             return 0;
231
232         a = a->next;
233         b = b->next;
234     }
235 }
236
237 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
238     va_list va;
239
240     va_start(va, r);
241     r = avahi_string_list_add_many_va(r, va);
242     va_end(va);
243     
244     return r;
245 }
246
247 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
248     const char *txt;
249
250     while ((txt = va_arg(va, const char*)))
251         r = avahi_string_list_add(r, txt);
252
253     return r;
254 }
255
256 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
257     va_list va;
258     AvahiStringList *r = NULL;
259
260     if (txt) {
261         r = avahi_string_list_add(r, txt);
262
263         va_start(va, txt);
264         r = avahi_string_list_add_many_va(r, va);
265         va_end(va);
266     }
267
268     return r;
269 }
270
271 AvahiStringList *avahi_string_list_new_va(va_list va) {
272     return avahi_string_list_add_many_va(NULL, va);
273 }
274
275 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
276     AvahiStringList *r = NULL;
277
278     for (; l; l = l->next)
279         r = avahi_string_list_add_arbitrary(r, l->text, l->size);
280
281     return avahi_string_list_reverse(r);
282 }
283
284 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
285     AvahiStringList *r = NULL;
286     int i;
287
288     assert(array);
289
290     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
291         r = avahi_string_list_add(r, array[i]);
292
293     return r;
294 }
295
296 unsigned avahi_string_list_length(const AvahiStringList *l) {
297     unsigned n = 0;
298
299     for (; l; l = l->next)
300         n++;
301
302     return n;
303 }
304
305 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
306     size_t len = 80;
307     AvahiStringList *r;
308     
309     assert(format);
310
311     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
312         return NULL;
313
314     for (;;) {
315         int n;
316         AvahiStringList *nr;
317         
318         n = vsnprintf((char*) r->text, len+1, format, va);
319
320         if (n >= 0 && n < (int) len)
321             break;
322
323         if (n >= 0)
324             len = n+1;
325         else
326             len *= 2;
327
328         if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
329             avahi_free(r);
330             return NULL;
331         }
332
333         r = nr;
334     }
335
336     
337     r->next = l;
338     r->size = strlen((char*) r->text); 
339
340     return r;
341 }
342
343 AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
344     va_list va;
345     
346     assert(format);
347
348     va_start(va, format);
349     l  = avahi_string_list_add_vprintf(l, format, va);
350     va_end(va);
351
352     return l;    
353 }
354
355 AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
356     size_t n;
357     
358     assert(key);
359     n = strlen(key);
360
361     for (; l; l = l->next) {
362         if (strcasecmp((char*) l->text, key) == 0)
363             return l;
364
365         if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
366             return l;
367     }
368
369     return NULL;
370 }
371
372 AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
373     assert(key);
374
375     if (value)
376         return avahi_string_list_add_printf(l, "%s=%s", key, value);
377     else
378         return avahi_string_list_add(l, key);
379 }
380
381 AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
382     size_t n;
383     assert(key);
384
385     if (!value)
386         return avahi_string_list_add(l, key);
387
388     n = strlen(key);
389     
390     if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
391         return NULL;
392
393     memcpy(l->text, key, n);
394     l->text[n] = '=';
395     memcpy(l->text + n + 1, value, size);
396
397     return l;
398 }
399
400
401 int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
402     char *e;
403     
404     assert(l);
405     assert(key);
406
407     if (!(e = memchr(l->text, '=', l->size))) {
408         
409         if (!(*key = avahi_strdup((char*) l->text)))
410             return -1;
411
412         if (value)
413             *value = NULL;
414
415         if (size)
416             *size = 0;
417
418     } else {
419         size_t n;
420
421         if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
422             return -1;
423
424         e++; /* Advance after '=' */
425         
426         n = l->size - (e - (char*) l->text);
427         
428         if (value) {
429
430             if (!(*value = avahi_memdup(e, n+1))) {
431                 avahi_free(*key);
432                 return -1;
433             }
434
435             (*value)[n] = 0;
436         }
437
438         if (size)
439             *size = n;
440     }
441
442     return 0;
443 }