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