]> git.meshlink.io Git - catta/blob - avahi-common/strlst.c
add some data access api to string list, and use it in ServiceResolver
[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         if (!l)
204             used = 1;
205         else {
206
207             for (n = l; n; n = n->next) {
208                 size_t k;
209                 
210                 k = n->size;
211                 if (k > 255)
212                     k = 255;
213                 
214                 used += 1+k;
215             }
216         }
217     }
218
219     return used;
220 }
221
222 int avahi_string_list_equal(const AvahiStringList *a, const AvahiStringList *b) {
223
224     for (;;) {
225         if (!a && !b)
226             return 1;
227
228         if (!a || !b)
229             return 0;
230
231         if (a->size != b->size)
232             return 0;
233
234         if (a->size != 0 && memcmp(a->text, b->text, a->size) != 0)
235             return 0;
236
237         a = a->next;
238         b = b->next;
239     }
240 }
241
242 AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) {
243     va_list va;
244
245     va_start(va, r);
246     r = avahi_string_list_add_many_va(r, va);
247     va_end(va);
248     
249     return r;
250 }
251
252 AvahiStringList *avahi_string_list_add_many_va(AvahiStringList *r, va_list va) {
253     const char *txt;
254
255     while ((txt = va_arg(va, const char*)))
256         r = avahi_string_list_add(r, txt);
257
258     return r;
259 }
260
261 AvahiStringList *avahi_string_list_new(const char *txt, ...) {
262     va_list va;
263     AvahiStringList *r = NULL;
264
265     if (txt) {
266         r = avahi_string_list_add(r, txt);
267
268         va_start(va, txt);
269         r = avahi_string_list_add_many_va(r, va);
270         va_end(va);
271     }
272
273     return r;
274 }
275
276 AvahiStringList *avahi_string_list_new_va(va_list va) {
277     return avahi_string_list_add_many_va(NULL, va);
278 }
279
280 AvahiStringList *avahi_string_list_copy(const AvahiStringList *l) {
281     AvahiStringList *r = NULL;
282
283     for (; l; l = l->next)
284         r = avahi_string_list_add_arbitrary(r, l->text, l->size);
285
286     return avahi_string_list_reverse(r);
287 }
288
289 AvahiStringList *avahi_string_list_new_from_array(const char *array[], int length) {
290     AvahiStringList *r = NULL;
291     int i;
292
293     assert(array);
294
295     for (i = 0; length >= 0 ? i < length : !!array[i]; i++)
296         r = avahi_string_list_add(r, array[i]);
297
298     return r;
299 }
300
301 unsigned avahi_string_list_length(const AvahiStringList *l) {
302     unsigned n = 0;
303
304     for (; l; l = l->next)
305         n++;
306
307     return n;
308 }
309
310 AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
311     size_t len = 80;
312     AvahiStringList *r;
313     
314     assert(format);
315
316     if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
317         return NULL;
318
319     for (;;) {
320         int n;
321         AvahiStringList *nr;
322         
323         n = vsnprintf((char*) r->text, len+1, format, va);
324
325         if (n >= 0 && n < (int) len)
326             break;
327
328         if (n >= 0)
329             len = n+1;
330         else
331             len *= 2;
332
333         if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
334             avahi_free(r);
335             return NULL;
336         }
337
338         r = nr;
339     }
340
341     
342     r->next = l;
343     r->size = strlen((char*) r->text); 
344
345     return r;
346 }
347
348 AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
349     va_list va;
350     
351     assert(format);
352
353     va_start(va, format);
354     l  = avahi_string_list_add_vprintf(l, format, va);
355     va_end(va);
356
357     return l;    
358 }
359
360 AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
361     size_t n;
362     
363     assert(key);
364     n = strlen(key);
365
366     for (; l; l = l->next) {
367         if (strcasecmp((char*) l->text, key) == 0)
368             return l;
369
370         if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
371             return l;
372     }
373
374     return NULL;
375 }
376
377 AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
378     assert(key);
379
380     if (value)
381         return avahi_string_list_add_printf(l, "%s=%s", key, value);
382     else
383         return avahi_string_list_add(l, key);
384 }
385
386 AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
387     size_t n;
388     assert(key);
389
390     if (!value)
391         return avahi_string_list_add(l, key);
392
393     n = strlen(key);
394     
395     if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
396         return NULL;
397
398     memcpy(l->text, key, n);
399     l->text[n] = '=';
400     memcpy(l->text + n + 1, value, size);
401
402     return l;
403 }
404
405
406 int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
407     char *e;
408     
409     assert(l);
410     assert(key);
411
412     if (!(e = memchr(l->text, '=', l->size))) {
413         
414         if (!(*key = avahi_strdup((char*) l->text)))
415             return -1;
416
417         if (value)
418             *value = NULL;
419
420         if (size)
421             *size = 0;
422
423     } else {
424         size_t n;
425
426         if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
427             return -1;
428
429         e++; /* Advance after '=' */
430         
431         n = l->size - (e - (char*) l->text);
432         
433         if (value) {
434
435             if (!(*value = avahi_memdup(e, n+1))) {
436                 avahi_free(*key);
437                 return -1;
438             }
439
440             (*value)[n] = 0;
441         }
442
443         if (size)
444             *size = n;
445     }
446
447     return 0;
448 }
449
450 AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
451     assert(l);
452     return l->next;
453 }
454
455 const uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
456     assert(l);
457     return l->text;
458 }
459
460 size_t avahi_string_list_get_size(AvahiStringList *l) {
461     assert(l);
462     return l->size;
463 }