Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c
Location:line 156, column 48
Description:Access to field 't_value' results in a dereference of a null pointer (loaded from variable 't')

Annotated Source Code

1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@SU_TAG
26 *
27 * @CFILE su_taglist.c
28 *
29 * Implementation of tag items and lists.
30 *
31 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
32 *
33 * @date Created: Tue Feb 20 20:03:38 2001 ppessi
34 */
35
36#include "config.h"
37
38#include <stdlib.h>
39#include <string.h>
40#include <stdarg.h>
41#include <stdio.h>
42#include <limits.h>
43
44#if defined(va_copy)
45/* Xyzzy */
46#elif defined(__va_copy)
47#define va_copy(dst, src)__builtin_va_copy(dst, src) __va_copy((dst), (src))__builtin_va_copy((dst),(src))
48#else
49#define va_copy(dst, src)__builtin_va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
50#endif
51
52#include <assert.h>
53
54#include <sofia-sip/su_config.h>
55
56#include <sofia-sip/su_tag.h>
57#include <sofia-sip/su_tag_class.h>
58#include <sofia-sip/su_tag_inline.h>
59#include <sofia-sip/su_tagarg.h>
60#include <sofia-sip/su_string.h>
61
62#ifndef HAVE_STRTOULL1
63#if !((defined(WIN32) || defined(_WIN32)) && (_MSC_VER >= 1800))
64unsigned longlonglong long strtoull(const char *, char **, int);
65#endif
66#endif
67
68/**@defgroup su_tag Tag Item Lists
69 *
70 * Object-oriented tag routines for Sofia utility library.
71 *
72 * The <sofia-sip/su_tag.h> defines a interface to object-oriented tag list routines.
73 * A tag list is a linear list (array) of tag items, tagi_t structures,
74 * terminated by a TAG_END() item. Each tag item has a label, tag, (@c
75 * t_tag) and a value (@c t_value). The tag is a pointer (tag_type_t) to a
76 * structure defining how the value should be interpreted, in other words,
77 * the name and the type of the value. The value or pointer to the actual
78 * value is stored as opaque data (tag_value_t). The tag item structure is
79 * defined as follows:
80 *
81 * @code
82 * typedef struct {
83 * tag_type_t t_tag;
84 * tag_value_t t_value;
85 * } tagi_t;
86 * @endcode
87 *
88 * The tag lists are central concept in the Sofia APIs. The tags lists can
89 * be used to a list of named arguments to a @ref tagarg "@em tagarg"
90 * function, to store variable amount of data in a memory area, and pass
91 * data between processes and threads.
92 *
93 * The tagged argument lists can be used like named arguments in
94 * higher-level languages. The argument list consists of tag-value pairs;
95 * tags specify the name and type of the value. All the tag items are not
96 * necessarily interpreted by the called function, but it can pass the list
97 * to other functions. This feature is used also by the Sofia APIs, the
98 * lower-layer settings and options are frequently passed through the
99 * upper-layer API in the tag lists.
100 *
101 * The tagged argument lists are constructed using special macros that
102 * expand to two function arguments, tag and value. Each tag item macro
103 * checks its arguments type so the tagged argument lists are typesafe if
104 * the list is correctly constructed.
105 *
106 * Each function documents the tags it accepts and also the tags it may pass
107 * to the lower layers (at least in theory).
108 *
109 * @par Special Tags
110 *
111 * There are a new special tags that are used to control and modify the tag
112 * list processing itself. These special tags are as follows:
113 * - TAG_NULL() or TAG_END() - indicates the end of tag list
114 * - TAG_SKIP() - indicates an empty (overwritten) tag item
115 * - TAG_NEXT() - contains a pointer to the next tag list.
116 *
117 * The tag type structures are declared as tag_typedef_t. They can be
118 * defined by the macros found in <sofia-sip/su_tag_class.h>. See nta_tag.c or
119 * su_tag_test.c for an example.
120 *
121 */
122
123/**@class tag_class_s sofia-sip/su_tag_class.h <sofia-sip/su_tag_class.h>
124 *
125 * @brief Virtual function table for @ref su_tag "tags".
126 *
127 * The struct tag_class_s contains virtual function table for tags,
128 * specifying non-default behaviour of different tags. It provides functions
129 * for copying, matching, printing and converting the tagged values.
130 */
131
132#ifdef longlonglong long
133typedef longlonglong long unsigned llu;
134#else
135typedef long unsigned llu;
136#endif
137
138/** Print a tag. */
139int t_snprintf(tagi_t const *t, char b[], size_t size)
140{
141 tag_type_t tt = TAG_TYPE_OF(t)((t) && (t)->t_tag ? (t)->t_tag : tag_null);
1
Within the expansion of the macro 'TAG_TYPE_OF':
a
Assuming pointer value is null
142 int n, m;
143
144 n = snprintf(b, size, "%s::%s: ",
145 tt->tt_ns ? tt->tt_ns : "",
2
'?' condition is false
146 tt->tt_name ? tt->tt_name : "null");
3
'?' condition is false
147 if (n < 0)
4
Assuming 'n' is >= 0
5
Taking false branch
148 return n;
149
150 if ((size_t)n > size)
6
Taking false branch
151 size = n;
152
153 if (tt->tt_snprintftt_class->tc_snprintf)
7
Taking false branch
154 m = tt->tt_snprintftt_class->tc_snprintf(t, b + n, size - n);
155 else
156 m = snprintf(b + n, size - n, "%llx", (llu)t->t_value);
8
Access to field 't_value' results in a dereference of a null pointer (loaded from variable 't')
157
158 if (m < 0)
159 return m;
160
161 if (m == 0 && 0 < n && (size_t)n < size)
162 b[--n] = '\0';
163
164 return n + m;
165}
166
167/** Get next tag item from list.
168 */
169tagi_t *tl_next(tagi_t const *t)
170{
171 tag_type_t tt;
172
173 t = t_next(t);
174
175 for (tt = TAG_TYPE_OF(t)((t) && (t)->t_tag ? (t)->t_tag : tag_null); t && tt->tt_nexttt_class->tc_next; tt = TAG_TYPE_OF(t)((t) && (t)->t_tag ? (t)->t_tag : tag_null)) {
176 t = tt->tt_nexttt_class->tc_next(t);
177 }
178
179 return (tagi_t *)t;
180}
181
182/**Move a tag list.
183 *
184 * The function tl_tmove() moves the tag list arguments to @a dst. The @a
185 * dst must have big enough for all arguments.
186 *
187 * @param dst pointer to the destination buffer
188 * @param size sizeof @a dst
189 * @param t_tag,t_value,... tag list
190 *
191 * @return
192 * The function tl_tmove() returns number of tag list items initialized.
193 */
194size_t tl_tmove(tagi_t *dst, size_t size,
195 tag_type_t t_tag, tag_value_t t_value, ...)
196{
197 size_t n = 0, N = size / sizeof(tagi_t);
198 tagi_t tagi[1];
199 va_list ap;
200
201 va_start(ap, t_value)__builtin_va_start(ap, t_value);
202
203 tagi->t_tag = t_tag, tagi->t_value = t_value;
204
205 for (;;) {
206 assert((size_t)((char *)&dst[n] - (char *)dst) < size)(((size_t)((char *)&dst[n] - (char *)dst) < size) ? (void
) (0) : __assert_fail ("(size_t)((char *)&dst[n] - (char *)dst) < size"
, "su_taglist.c", 206, __PRETTY_FUNCTION__))
;
207 if (n < N)
208 dst[n] = *tagi;
209 n++;
210 if (t_end(tagi))
211 break;
212
213 tagi->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
214 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
215 }
216
217 va_end(ap)__builtin_va_end(ap);
218
219 return n;
220}
221
222/**Move a tag list.
223 *
224 * The function tl_move() copies the tag list @a src to the buffer @a
225 * dst. The size of the @a dst list must be at least @c tl_len(src) bytes.
226 *
227 * @param dst pointer to the destination buffer
228 * @param src tag list to be moved
229 *
230 * @return
231 * The function tl_move() returns a pointer to the @a dst list after last
232 * moved element.
233 */
234tagi_t *tl_move(tagi_t *dst, tagi_t const src[])
235{
236 do {
237 dst = t_move(dst, src);
238 }
239 while ((src = t_next(src)));
240
241 return dst;
242}
243
244/** Calculate effective length of a tag list as bytes. */
245size_t tl_len(tagi_t const lst[])
246{
247 size_t len = 0;
248
249 do {
250 len += t_len(lst);
251 }
252 while ((lst = t_next(lst)));
253
254 return len;
255}
256
257/** Calculate the size of extra memory areas associated with tag list. */
258size_t tl_xtra(tagi_t const lst[], size_t offset)
259{
260 size_t xtra = offset;
261
262 for (; lst; lst = t_next(lst))
263 xtra += t_xtra(lst, xtra);
264
265 return xtra - offset;
266}
267
268/** Duplicate a tag list.
269 *
270 * Deep copy the tag list @a src to the buffer @a dst. Memory areas
271 * associated with @a src are copied to buffer at @a **bb.
272 *
273 * This is a rather low-level function. See tl_adup() for a more convenient
274 * functionality.
275 *
276 * The size of the @a dst buffer must be at least @c tl_len(src) bytes. The
277 * size of buffer @a **bb must be at least @c tl_dup_xtra(src) bytes.
278 *
279 * @param[out] dst pointer to the destination buffer
280 * @param[in] src tag list to be duplicated
281 * @param[in,out] bb pointer to pointer to buffer
282 *
283 * @return
284 * A pointer to the @a dst list after last
285 * duplicated taglist element.
286 *
287 * The pointer at @a *bb is updated to the byte after last duplicated memory
288 * area.
289 */
290tagi_t *tl_dup(tagi_t dst[], tagi_t const src[], void **bb)
291{
292 do {
293 dst = t_dup(dst, src, bb);
294 } while ((src = t_next(src)));
295
296 return dst;
297}
298
299
300/** Free a tag list.
301 *
302 * The function tl_free() frees resources associated with a tag list.
303 * In other words, it calls t_free on each tag item on the list.
304 *
305 */
306void tl_free(tagi_t list[])
307{
308 while (list)
309 list = t_free(list);
310}
311
312/** Allocate and duplicate a tag list using memory home. */
313tagi_t *tl_adup(su_home_t *home, tagi_t const lst[])
314{
315 size_t len = tl_len(lst);
316 size_t xtra = tl_xtra(lst, 0);
317 void *b = su_alloc(home, len + xtra);
318 tagi_t *d, *newlst = b;
319
320 void *end = (char *)b + len + xtra;
321 tagi_t *tend = (tagi_t*)((char *)b + len);
322
323 b = (char *)b + len;
324
325 d = tl_dup(newlst, lst, &b);
326
327 assert(b == end)((b == end) ? (void) (0) : __assert_fail ("b == end", "su_taglist.c"
, 327, __PRETTY_FUNCTION__))
; assert(tend == d)((tend == d) ? (void) (0) : __assert_fail ("tend == d", "su_taglist.c"
, 327, __PRETTY_FUNCTION__))
; (void)end; (void)tend;
328
329 return newlst;
330}
331
332/** Allocate and duplicate tagged arguments as a tag list using memory home. */
333tagi_t *tl_tlist(su_home_t *home, tag_type_t tag, tag_value_t value, ...)
334{
335 tagi_t *tl;
336 ta_list ta;
337
338 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
339 tl = tl_adup(home, ta_args(ta)(ta).tl);
340 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
341
342 return tl;
343}
344
345/** Find first tag item with type @a tt from list. */
346tagi_t *tl_find(tagi_t const lst[], tag_type_t tt)
347{
348 return (tagi_t *)t_find(tt, lst);
349}
350
351/** Find last tag item with type @a tt from list. */
352tagi_t *tl_find_last(tagi_t const lst[], tag_type_t tt)
353{
354 tagi_t const *last, *next;
355
356 for (next = last = t_find(tt, lst); next; next = t_find(tt, t_next(last)))
357 last = next;
358
359 return (tagi_t *)last;
360}
361
362su_inlinestatic inline
363int t_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
364{
365 if (value == NULL((void*)0))
366 return 0;
367
368 if (tt->tt_class->tc_ref_set)
369 return tt->tt_class->tc_ref_set(tt, ref, value);
370
371 *(tag_value_t *)ref = value->t_value;
372
373 return 1;
374}
375
376static int tl_get(tag_type_t tt, void *p, tagi_t const lst[])
377{
378 tagi_t const *t, *latest = NULL((void*)0);
379
380 assert(tt)((tt) ? (void) (0) : __assert_fail ("tt", "su_taglist.c", 380
, __PRETTY_FUNCTION__))
;
381
382 if (tt == NULL((void*)0) || p == NULL((void*)0))
383 return 0;
384
385 if (tt->tt_class == ref_tag_class)
386 tt = (tag_type_t)tt->tt_magic;
387
388 for (t = t_find(tt, lst); t; t = t_find(tt, t_next(t)))
389 latest = t;
390
391 return t_ref_set(tt, p, latest);
392}
393
394/** Find tags from given list. */
395int tl_gets(tagi_t const lst[], tag_type_t tag, tag_value_t value, ...)
396{
397 int n = 0;
398 tagi_t *t;
399 ta_list ta;
400
401 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
402
403 for (t = ta_args(ta)(ta).tl; t; t = (tagi_t *)t_next(t)) {
404 tag_type_t tt = t->t_tag;
405
406 if (!tt)
407 continue;
408
409 if (tt->tt_class == ref_tag_class) {
410 assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set)((((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set) ?
(void) (0) : __assert_fail ("((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set"
, "su_taglist.c", 410, __PRETTY_FUNCTION__))
;
411 n += tl_get(tt, (void *)t->t_value, lst);
412 }
413#if !defined(NDEBUG)
414 else if (tt->tt_class && tt->tt_class->tc_ref_set) {
415 fprintf(stderrstderr, "WARNING: tag %s::%s directly used by tl_gets()\n",
416 tt->tt_ns ? tt->tt_ns : "", tt->tt_name ? tt->tt_name : "");
417 assert(tt->tt_class == ref_tag_class)((tt->tt_class == ref_tag_class) ? (void) (0) : __assert_fail
("tt->tt_class == ref_tag_class", "su_taglist.c", 417, __PRETTY_FUNCTION__
))
;
418 }
419#endif
420 }
421
422 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
423
424 return n;
425}
426
427/** Find tags from given list.
428 *
429 * Copies values of argument tag list into the reference tags in the tag
430 * list @a lst.
431 *
432 * @sa tl_gets()
433 */
434int tl_tgets(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
435{
436 int n = 0;
437 tagi_t *t;
438
439 ta_list ta;
440 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
441
442 for (t = lst; t; t = (tagi_t *)t_next(t)) {
443 tag_type_t tt = t->t_tag;
444
445 if (!tt)
446 continue;
447
448 if (tt->tt_class == ref_tag_class) {
449 assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set)((((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set) ?
(void) (0) : __assert_fail ("((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set"
, "su_taglist.c", 449, __PRETTY_FUNCTION__))
;
450 n += tl_get(tt, (void *)t->t_value, ta_args(ta)(ta).tl);
451 }
452#if !defined(NDEBUG)
453 else if (tt->tt_class->tc_ref_set) {
454 fprintf(stderrstderr, "WARNING: tag %s::%s used in tl_tgets(lst)\n",
455 tt->tt_ns, tt->tt_name);
456 assert(tt->tt_class == ref_tag_class)((tt->tt_class == ref_tag_class) ? (void) (0) : __assert_fail
("tt->tt_class == ref_tag_class", "su_taglist.c", 456, __PRETTY_FUNCTION__
))
;
457 }
458#endif
459 }
460
461 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
462
463 return n;
464}
465
466
467/** Filter an element in tag list */
468tagi_t *t_filter(tagi_t *dst,
469 tagi_t const filter[],
470 tagi_t const *src,
471 void **bb)
472{
473 tag_type_t tt = TAG_TYPE_OF(src)((src) && (src)->t_tag ? (src)->t_tag : tag_null
)
;
474 tagi_t const *f;
475
476 if (dst) {
477 for (f = filter; f; f = t_next(f)) {
478 if (TAG_TYPE_OF(f)((f) && (f)->t_tag ? (f)->t_tag : tag_null)->tt_filtertt_class->tc_filter)
479 dst = TAG_TYPE_OF(f)((f) && (f)->t_tag ? (f)->t_tag : tag_null)->tt_filtertt_class->tc_filter(dst, f, src, bb);
480 else if (f->t_tag == tt)
481 dst = t_dup(dst, src, bb);
482 }
483 }
484 else {
485 size_t d = 0;
486
487 for (f = filter; f; f = t_next(f)) {
488 if (TAG_TYPE_OF(f)((f) && (f)->t_tag ? (f)->t_tag : tag_null)->tt_filtertt_class->tc_filter)
489 d += (size_t)TAG_TYPE_OF(f)((f) && (f)->t_tag ? (f)->t_tag : tag_null)->tt_filtertt_class->tc_filter(NULL((void*)0), f, src, bb);
490 else if (tt == f->t_tag) {
491 d += t_len(src);
492 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
493 }
494 }
495
496 dst = (tagi_t *)d;
497 }
498
499 return dst;
500}
501
502/** Make filtered copy of a tag list @a src with @a filter to @a dst.
503 *
504 * Each tag in @a src is checked against tags in list @a filter. If the tag
505 * is in the @a filter list, or there is a special filter tag in the list
506 * which matches with the tag in @a src, the tag is duplicated to @a dst using
507 * memory buffer in @a b.
508 *
509 * When @a dst is NULL, this function calculates the size of the filtered list.
510 *
511 * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
512 * TAG_FILTER(), TAG_ANY(), #ns_tag_class
513 */
514tagi_t *tl_filter(tagi_t dst[],
515 tagi_t const filter[],
516 tagi_t const src[],
517 void **b)
518{
519 tagi_t const *s;
520 tagi_t *d;
521
522 if (dst) {
523 for (s = src, d = dst; s; s = t_next(s))
524 d = t_filter(d, filter, s, b);
525 }
526 else {
527 size_t rv = 0;
528
529 for (s = src, d = dst; s; s = t_next(s)) {
530 d = t_filter(NULL((void*)0), filter, s, b);
531 rv += (char *)d - (char *)NULL((void*)0);
532 }
533
534 d = (tagi_t *)rv;
535 }
536
537 return d;
538}
539
540
541
542/**Filter a tag list.
543 *
544 * The function tl_afilter() will build a tag list containing tags specified
545 * in @a filter and extracted from @a src. It will allocate the memory used by
546 * tag list via the specified memory @a home, which may be also @c NULL.
547 *
548 * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
549 * TAG_FILTER(), TAG_ANY(), #ns_tag_class
550 */
551tagi_t *tl_afilter(su_home_t *home, tagi_t const filter[], tagi_t const src[])
552{
553 tagi_t *dst, *d, *t_end = NULL((void*)0);
554 void *b, *end = NULL((void*)0);
555 size_t len;
556
557 /* Calculate length of the result */
558 t_end = tl_filter(NULL((void*)0), filter, src, &end);
559 len = ((char *)t_end - (char *)NULL((void*)0)) + ((char *)end - (char*)NULL((void*)0));
560
561 if (len == 0)
562 return NULL((void*)0);
563
564 /* Allocate the result */
565 if (!(dst = su_alloc(home, len)))
566 return NULL((void*)0);
567
568 /* Build the result */
569 b = (dst + (t_end - (tagi_t *)NULL((void*)0)));
570 d = tl_filter(dst, filter, src, (void **)&b);
571
572 /* Ensure that everything is consistent */
573 assert(d == dst + (t_end - (tagi_t *)NULL))((d == dst + (t_end - (tagi_t *)((void*)0))) ? (void) (0) : __assert_fail
("d == dst + (t_end - (tagi_t *)((void*)0))", "su_taglist.c"
, 573, __PRETTY_FUNCTION__))
;
574 assert(b == (char *)dst + len)((b == (char *)dst + len) ? (void) (0) : __assert_fail ("b == (char *)dst + len"
, "su_taglist.c", 574, __PRETTY_FUNCTION__))
;
575
576 return dst;
577}
578
579/** Filter tag list @a src with given tags.
580 *
581 * @sa tl_afilter(), tl_filtered_tlist(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
582 */
583tagi_t *tl_tfilter(su_home_t *home, tagi_t const src[],
584 tag_type_t tag, tag_value_t value, ...)
585{
586 tagi_t *tl;
587 ta_list ta;
588 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
589 tl = tl_afilter(home, ta_args(ta)(ta).tl, src);
590 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
591 return tl;
592}
593
594/** Create a filtered tag list.
595 *
596 * @sa tl_afilter(), tl_tfilter(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
597 */
598tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[],
599 tag_type_t tag, tag_value_t value, ...)
600{
601 tagi_t *tl;
602 ta_list ta;
603
604 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
605 tl = tl_afilter(home, filter, ta_args(ta)(ta).tl);
606 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
607
608 return tl;
609}
610
611
612/** Remove listed tags from the list @a lst. */
613int tl_tremove(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
614{
615 tagi_t *l, *l_next;
616 int retval = 0;
617 ta_list ta;
618
619 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
620
621 for (l = lst; l; l = l_next) {
622 if ((l_next = (tagi_t *)t_next(l))) {
623 if (tl_find(ta_args(ta)(ta).tl, l->t_tag))
624 l->t_tag = tag_skip;
625 else
626 retval++;
627 }
628 }
629
630 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
631
632 return retval;
633}
634
635/** Calculate length of a tag list with a @c va_list. */
636size_t tl_vlen(va_list ap)
637{
638 size_t len = 0;
639 tagi_t tagi[2] = {{ NULL((void*)0) }};
640
641 do {
642 tagi->t_tag = va_arg(ap, tag_type_t )__builtin_va_arg(ap, tag_type_t);
643 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
644 len += sizeof(tagi_t);
645 } while (!t_end(tagi));
646
647 return len;
648}
649
650/** Convert va_list to tag list */
651tagi_t *tl_vlist(va_list ap)
652{
653 tagi_t *t, *rv;
654 va_list aq;
655
656 va_copy(aq, ap)__builtin_va_copy(aq, ap);
657 rv = malloc(tl_vlen(aq));
658 va_end(aq)__builtin_va_end(aq);
659
660 for (t = rv; t; t++) {
661 t->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
662 t->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
663
664 if (t_end(t))
665 break;
666 }
667
668 return rv;
669}
670
671tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap)
672{
673 tagi_t *t, *rv;
674 tagi_t tagi[1];
675 size_t size;
676
677 tagi->t_tag = tag, tagi->t_value = value;
678
679 if (!t_end(tagi)) {
680 va_list aq;
681 va_copy(aq, ap)__builtin_va_copy(aq, ap);
682 size = sizeof(tagi) + tl_vlen(aq);
683 va_end(aq)__builtin_va_end(aq);
684 }
685 else
686 size = sizeof(tagi);
687
688 t = rv = malloc(size);
689
690 for (;t;) {
691 *t++ = *tagi;
692
693 if (t_end(tagi))
694 break;
695
696 tagi->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
697 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
698 }
699
700 assert((char *)rv + size == (char *)t)(((char *)rv + size == (char *)t) ? (void) (0) : __assert_fail
("(char *)rv + size == (char *)t", "su_taglist.c", 700, __PRETTY_FUNCTION__
))
;
701
702 return rv;
703}
704
705/** Make a tag list until TAG_NEXT() or TAG_END() */
706tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...)
707{
708 va_list ap;
709 tagi_t *t;
710
711 va_start(ap, value)__builtin_va_start(ap, value);
712 t = tl_vlist2(tag, value, ap);
713 va_end(ap)__builtin_va_end(ap);
714
715 return t;
716}
717
718/** Calculate length of a linear tag list. */
719size_t tl_vllen(tag_type_t tag, tag_value_t value, va_list ap)
720{
721 size_t len = sizeof(tagi_t);
722 tagi_t const *next;
723 tagi_t tagi[3];
724
725 tagi[0].t_tag = tag;
726 tagi[0].t_value = value;
727 tagi[1].t_tag = tag_any;
728 tagi[1].t_value = 0;
729
730 for (;;) {
731 next = tl_next(tagi);
732 if (next != tagi + 1)
733 break;
734
735 if (tagi->t_tag != tag_skip)
736 len += sizeof(tagi_t);
737 tagi->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
738 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
739 }
740
741 for (; next; next = tl_next(next))
742 len += sizeof(tagi_t);
743
744 return len;
745}
746
747/** Make a linear tag list. */
748tagi_t *tl_vllist(tag_type_t tag, tag_value_t value, va_list ap)
749{
750 va_list aq;
751 tagi_t *t, *rv;
752 tagi_t const *next;
753 tagi_t tagi[2];
754
755 size_t size;
756
757 va_copy(aq, ap)__builtin_va_copy(aq, ap);
758 size = tl_vllen(tag, value, aq);
759 va_end(aq)__builtin_va_end(aq);
760
761 t = rv = malloc(size);
762 if (rv == NULL((void*)0))
763 return rv;
764
765 tagi[0].t_tag = tag;
766 tagi[0].t_value = value;
767 tagi[1].t_tag = tag_any;
768 tagi[1].t_value = 0;
769
770 for (;;) {
771 next = tl_next(tagi);
772 if (next != tagi + 1)
773 break;
774
775 if (tagi->t_tag != tag_skip)
776 *t++ = *tagi;
777
778 tagi->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
779 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
780 }
781
782 for (; next; next = tl_next(next))
783 *t++ = *next;
784
785 t->t_tag = NULL((void*)0); t->t_value = 0; t++;
786
787 assert((char *)rv + size == (char *)t)(((char *)rv + size == (char *)t) ? (void) (0) : __assert_fail
("(char *)rv + size == (char *)t", "su_taglist.c", 787, __PRETTY_FUNCTION__
))
;
788
789 return rv;
790}
791
792/** Make a linear tag list until TAG_END().
793 *
794 */
795tagi_t *tl_llist(tag_type_t tag, tag_value_t value, ...)
796{
797 va_list ap;
798 tagi_t *t;
799
800 va_start(ap, value)__builtin_va_start(ap, value);
801 t = tl_vllist(tag, value, ap);
802 va_end(ap)__builtin_va_end(ap);
803
804 return t;
805}
806
807/** Free a tag list allocated by tl_list(), tl_llist() or tl_vlist(). */
808void tl_vfree(tagi_t *t)
809{
810 if (t)
811 free(t);
812}
813
814/** Convert a string to the a value of a tag. */
815int t_scan(tag_type_t tt, su_home_t *home, char const *s,
816 tag_value_t *return_value)
817{
818 if (tt == NULL((void*)0) || s == NULL((void*)0) || return_value == NULL((void*)0))
819 return -1;
820
821 if (tt->tt_class->tc_scan) {
822 return tt->tt_class->tc_scan(tt, home, s, return_value);
823 }
824 else { /* Not implemented */
825 *return_value = (tag_value_t)0;
826 return -2;
827 }
828}
829
830
831/* ====================================================================== */
832/* null tag */
833
834static
835tagi_t const *t_null_next(tagi_t const *t)
836{
837 return NULL((void*)0);
838}
839
840static
841tagi_t *t_null_move(tagi_t *dst, tagi_t const *src)
842{
843 memset(dst, 0, sizeof(*dst));
844 return dst + 1;
845}
846
847static
848tagi_t *t_null_dup(tagi_t *dst, tagi_t const *src, void **bb)
849{
850 memset(dst, 0, sizeof(*dst));
851 return dst + 1;
852}
853
854static
855tagi_t const * t_null_find(tag_type_t tt, tagi_t const lst[])
856{
857 return NULL((void*)0);
858}
859
860tagi_t *t_null_filter(tagi_t *dst,
861 tagi_t const filter[],
862 tagi_t const *src,
863 void **bb)
864{
865 if (TAG_TYPE_OF(src)((src) && (src)->t_tag ? (src)->t_tag : tag_null
)
== tag_null) {
866 if (dst) {
867 dst->t_tag = NULL((void*)0);
868 dst->t_value = 0;
869 }
870 return dst + 1;
871 }
872 return dst;
873}
874
875tag_class_t null_tag_class[1] =
876 {{
877 sizeof(null_tag_class),
878 /* tc_next */ t_null_next,
879 /* tc_len */ NULL((void*)0),
880 /* tc_move */ t_null_move,
881 /* tc_xtra */ NULL((void*)0),
882 /* tc_dup */ t_null_dup,
883 /* tc_free */ NULL((void*)0),
884 /* tc_find */ t_null_find,
885 /* tc_snprintf */ NULL((void*)0),
886 /* tc_filter */ t_null_filter,
887 /* tc_ref_set */ NULL((void*)0),
888 /* tc_scan */ NULL((void*)0),
889 }};
890
891tag_typedef_t tag_null = TAG_TYPEDEF(tag_null, null){{ "", "tag_null", null_tag_class, 0 }};
892
893/* ====================================================================== */
894/* end tag */
895
896tagi_t *t_end_filter(tagi_t *dst,
897 tagi_t const filter[],
898 tagi_t const *src,
899 void **bb)
900{
901 return dst;
902}
903
904tag_class_t end_tag_class[1] =
905 {{
906 sizeof(end_tag_class),
907 /* tc_next */ NULL((void*)0),
908 /* tc_len */ NULL((void*)0),
909 /* tc_move */ NULL((void*)0),
910 /* tc_xtra */ NULL((void*)0),
911 /* tc_dup */ NULL((void*)0),
912 /* tc_free */ NULL((void*)0),
913 /* tc_find */ NULL((void*)0),
914 /* tc_snprintf */ NULL((void*)0),
915 /* tc_filter */ t_end_filter,
916 /* tc_ref_set */ NULL((void*)0),
917 /* tc_scan */ NULL((void*)0),
918 }};
919
920/* ====================================================================== */
921/* skip tag - placeholder in tag list */
922
923static
924tagi_t const *t_skip_next(tagi_t const *t)
925{
926 return t + 1;
927}
928
929static
930tagi_t *t_skip_move(tagi_t *dst, tagi_t const *src)
931{
932 return dst;
933}
934
935static
936size_t t_skip_len(tagi_t const *t)
937{
938 return 0;
939}
940
941static
942tagi_t *t_skip_dup(tagi_t *dst, tagi_t const *src, void **bb)
943{
944 return dst;
945}
946
947static
948tagi_t *t_skip_filter(tagi_t *dst,
949 tagi_t const filter[],
950 tagi_t const *src,
951 void **bb)
952{
953 return dst;
954}
955
956tag_class_t skip_tag_class[1] =
957 {{
958 sizeof(skip_tag_class),
959 /* tc_next */ t_skip_next,
960 /* tc_len */ t_skip_len,
961 /* tc_move */ t_skip_move,
962 /* tc_xtra */ NULL((void*)0),
963 /* tc_dup */ t_skip_dup,
964 /* tc_free */ NULL((void*)0),
965 /* tc_find */ t_null_find,
966 /* tc_snprintf */ NULL((void*)0),
967 /* tc_filter */ t_skip_filter,
968 /* tc_ref_set */ NULL((void*)0),
969 /* tc_scan */ NULL((void*)0),
970 }};
971
972tag_typedef_t tag_skip = TAG_TYPEDEF(tag_skip, skip){{ "", "tag_skip", skip_tag_class, 0 }};
973
974/* ====================================================================== */
975/* next tag - jump to next tag list */
976
977static
978tagi_t const *t_next_next(tagi_t const *t)
979{
980 return (tagi_t *)(t->t_value);
981}
982
983static
984tagi_t *t_next_move(tagi_t *dst, tagi_t const *src)
985{
986 if (!src->t_value)
987 return t_null_move(dst, src);
988 return dst;
989}
990
991static
992size_t t_next_len(tagi_t const *t)
993{
994 if (!t->t_value)
995 return sizeof(*t);
996 return 0;
997}
998
999static
1000tagi_t *t_next_dup(tagi_t *dst, tagi_t const *src, void **bb)
1001{
1002 if (!src->t_value)
1003 return t_null_dup(dst, src, bb);
1004 return dst;
1005}
1006
1007static
1008tagi_t *t_next_filter(tagi_t *dst,
1009 tagi_t const filter[],
1010 tagi_t const *src,
1011 void **bb)
1012{
1013 return dst;
1014}
1015
1016tag_class_t next_tag_class[1] =
1017 {{
1018 sizeof(next_tag_class),
1019 /* tc_next */ t_next_next,
1020 /* tc_len */ t_next_len,
1021 /* tc_move */ t_next_move,
1022 /* tc_xtra */ NULL((void*)0),
1023 /* tc_dup */ t_next_dup,
1024 /* tc_free */ NULL((void*)0),
1025 /* tc_find */ t_null_find,
1026 /* tc_snprintf */ NULL((void*)0),
1027 /* tc_filter */ t_next_filter,
1028 /* tc_ref_set */ NULL((void*)0),
1029 /* tc_scan */ NULL((void*)0),
1030 }};
1031
1032tag_typedef_t tag_next = TAG_TYPEDEF(tag_next, next){{ "", "tag_next", next_tag_class, 0 }};
1033
1034/* ====================================================================== */
1035/* filter tag - use function to filter tag */
1036
1037static
1038tagi_t *t_filter_with(tagi_t *dst,
1039 tagi_t const *t,
1040 tagi_t const *src,
1041 void **bb)
1042{
1043 tag_filter_f *function;
1044
1045 if (!src || !t)
1046 return dst;
1047
1048 function = (tag_filter_f *)t->t_value;
1049
1050 if (!function || !function(t, src))
1051 return dst;
1052
1053 if (dst) {
1054 return t_dup(dst, src, bb);
1055 }
1056 else {
1057 dst = (tagi_t *)((char *)dst + t_len(src));
1058 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
1059 return dst;
1060 }
1061}
1062
1063tag_class_t filter_tag_class[1] =
1064 {{
1065 sizeof(filter_tag_class),
1066 /* tc_next */ NULL((void*)0),
1067 /* tc_len */ NULL((void*)0),
1068 /* tc_move */ NULL((void*)0),
1069 /* tc_xtra */ NULL((void*)0),
1070 /* tc_dup */ NULL((void*)0),
1071 /* tc_free */ NULL((void*)0),
1072 /* tc_find */ NULL((void*)0),
1073 /* tc_snprintf */ NULL((void*)0),
1074 /* tc_filter */ t_filter_with,
1075 /* tc_ref_set */ NULL((void*)0),
1076 /* tc_scan */ NULL((void*)0),
1077 }};
1078
1079/** Filter tag - apply function in order to filter tag. */
1080tag_typedef_t tag_filter = TAG_TYPEDEF(tag_filter, filter){{ "", "tag_filter", filter_tag_class, 0 }};
1081
1082/* ====================================================================== */
1083/* any tag - match to any tag when filtering */
1084
1085static
1086tagi_t *t_any_filter(tagi_t *dst,
1087 tagi_t const filter[],
1088 tagi_t const *src,
1089 void **bb)
1090{
1091 if (!src)
1092 return dst;
1093 else if (dst) {
1094 return t_dup(dst, src, bb);
1095 }
1096 else {
1097 dst = (tagi_t *)((char *)dst + t_len(src));
1098 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
1099 return dst;
1100 }
1101}
1102
1103tag_class_t any_tag_class[1] =
1104 {{
1105 sizeof(any_tag_class),
1106 /* tc_next */ NULL((void*)0),
1107 /* tc_len */ NULL((void*)0),
1108 /* tc_move */ NULL((void*)0),
1109 /* tc_xtra */ NULL((void*)0),
1110 /* tc_dup */ NULL((void*)0),
1111 /* tc_free */ NULL((void*)0),
1112 /* tc_find */ NULL((void*)0),
1113 /* tc_snprintf */ NULL((void*)0),
1114 /* tc_filter */ t_any_filter,
1115 /* tc_ref_set */ NULL((void*)0),
1116 /* tc_scan */ NULL((void*)0),
1117 }};
1118
1119/** Any tag - match any tag when filtering. */
1120tag_typedef_t tag_any = TAG_TYPEDEF(tag_any, any){{ "", "tag_any", any_tag_class, 0 }};
1121
1122/* ====================================================================== */
1123/* ns tag - match to any tag with same namespace when filtering */
1124
1125static
1126tagi_t *t_ns_filter(tagi_t *dst,
1127 tagi_t const filter[],
1128 tagi_t const *src,
1129 void **bb)
1130{
1131 char const *match, *ns;
1132
1133 if (!src)
1134 return dst;
1135
1136 assert(filter)((filter) ? (void) (0) : __assert_fail ("filter", "su_taglist.c"
, 1136, __PRETTY_FUNCTION__))
;
1137
1138 match = TAG_TYPE_OF(filter)((filter) && (filter)->t_tag ? (filter)->t_tag :
tag_null)
->tt_ns;
1139 ns = TAG_TYPE_OF(src)((src) && (src)->t_tag ? (src)->t_tag : tag_null
)
->tt_ns;
1140
1141 if (match == NULL((void*)0))
1142 /* everything matches with this */;
1143 else if (match == ns)
1144 /* namespaces matche */;
1145 else if (ns == NULL((void*)0))
1146 /* no match */
1147 return dst;
1148 else if (strcmp(match, ns)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(match) && __builtin_constant_p (ns) && (__s1_len
= __builtin_strlen (match), __s2_len = __builtin_strlen (ns)
, (!((size_t)(const void *)((match) + 1) - (size_t)(const void
*)(match) == 1) || __s1_len >= 4) && (!((size_t)(
const void *)((ns) + 1) - (size_t)(const void *)(ns) == 1) ||
__s2_len >= 4)) ? __builtin_strcmp (match, ns) : (__builtin_constant_p
(match) && ((size_t)(const void *)((match) + 1) - (size_t
)(const void *)(match) == 1) && (__s1_len = __builtin_strlen
(match), __s1_len < 4) ? (__builtin_constant_p (ns) &&
((size_t)(const void *)((ns) + 1) - (size_t)(const void *)(ns
) == 1) ? __builtin_strcmp (match, ns) : (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(ns); int __result = (((const unsigned char *) (const char *
) (match))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
match))[1] - __s2[1]); if (__s1_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
match))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (match
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
ns) && ((size_t)(const void *)((ns) + 1) - (size_t)(const
void *)(ns) == 1) && (__s2_len = __builtin_strlen (ns
), __s2_len < 4) ? (__builtin_constant_p (match) &&
((size_t)(const void *)((match) + 1) - (size_t)(const void *
)(match) == 1) ? __builtin_strcmp (match, ns) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (match); int __result = (((const unsigned char *) (const
char *) (ns))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
ns))[1] - __s2[1]); if (__s2_len > 1 && __result ==
0) { __result = (((const unsigned char *) (const char *) (ns
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (ns))[3
] - __s2[3]); } } __result; })))) : __builtin_strcmp (match, ns
)))); })
)
1149 /* no match */
1150 return dst;
1151
1152 if (dst) {
1153 return t_dup(dst, src, bb);
1154 }
1155 else {
1156 dst = (tagi_t *)((char *)dst + t_len(src));
1157 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
1158 return dst;
1159 }
1160}
1161
1162/** Namespace filtering class */
1163tag_class_t ns_tag_class[1] =
1164 {{
1165 sizeof(ns_tag_class),
1166 /* tc_next */ NULL((void*)0),
1167 /* tc_len */ NULL((void*)0),
1168 /* tc_move */ NULL((void*)0),
1169 /* tc_xtra */ NULL((void*)0),
1170 /* tc_dup */ NULL((void*)0),
1171 /* tc_free */ NULL((void*)0),
1172 /* tc_find */ NULL((void*)0),
1173 /* tc_snprintf */ NULL((void*)0),
1174 /* tc_filter */ t_ns_filter,
1175 /* tc_ref_set */ NULL((void*)0),
1176 /* tc_scan */ NULL((void*)0),
1177 }};
1178
1179/* ====================================================================== */
1180/* int tag - pass integer value */
1181
1182int t_int_snprintf(tagi_t const *t, char b[], size_t size)
1183{
1184 return snprintf(b, size, "%i", (int)t->t_value);
1185}
1186
1187int t_int_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1188{
1189 *(int *)ref = (int)value->t_value;
1190
1191 return 1;
1192}
1193
1194int t_int_scan(tag_type_t tt, su_home_t *home,
1195 char const *s,
1196 tag_value_t *return_value)
1197{
1198 int value;
1199 char *rest;
1200
1201 value = strtol(s, &rest, 0);
1202
1203 if (s != rest) {
1204 *return_value = (tag_value_t)value;
1205 return 1;
1206 }
1207 else {
1208 *return_value = (tag_value_t)0;
1209 return -1;
1210 }
1211}
1212
1213tag_class_t int_tag_class[1] =
1214 {{
1215 sizeof(int_tag_class),
1216 /* tc_next */ NULL((void*)0),
1217 /* tc_len */ NULL((void*)0),
1218 /* tc_move */ NULL((void*)0),
1219 /* tc_xtra */ NULL((void*)0),
1220 /* tc_dup */ NULL((void*)0),
1221 /* tc_free */ NULL((void*)0),
1222 /* tc_find */ NULL((void*)0),
1223 /* tc_snprintf */ t_int_snprintf,
1224 /* tc_filter */ NULL((void*)0),
1225 /* tc_ref_set */ t_int_ref_set,
1226 /* tc_scan */ t_int_scan,
1227 }};
1228
1229/* ====================================================================== */
1230/* uint tag - pass unsigned integer value */
1231
1232int t_uint_snprintf(tagi_t const *t, char b[], size_t size)
1233{
1234 return snprintf(b, size, "%u", (unsigned)t->t_value);
1235}
1236
1237int t_uint_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1238{
1239 *(unsigned *)ref = (unsigned)value->t_value;
1240
1241 return 1;
1242}
1243
1244int t_uint_scan(tag_type_t tt, su_home_t *home,
1245 char const *s,
1246 tag_value_t *return_value)
1247{
1248 unsigned value;
1249 char *rest;
1250
1251 value = strtoul(s, &rest, 0);
1252
1253 if (s != rest) {
1254 *return_value = (tag_value_t)value;
1255 return 1;
1256 }
1257 else {
1258 *return_value = (tag_value_t)0;
1259 return -1;
1260 }
1261}
1262
1263tag_class_t uint_tag_class[1] =
1264 {{
1265 sizeof(int_tag_class),
1266 /* tc_next */ NULL((void*)0),
1267 /* tc_len */ NULL((void*)0),
1268 /* tc_move */ NULL((void*)0),
1269 /* tc_xtra */ NULL((void*)0),
1270 /* tc_dup */ NULL((void*)0),
1271 /* tc_free */ NULL((void*)0),
1272 /* tc_find */ NULL((void*)0),
1273 /* tc_snprintf */ t_uint_snprintf,
1274 /* tc_filter */ NULL((void*)0),
1275 /* tc_ref_set */ t_uint_ref_set,
1276 /* tc_scan */ t_uint_scan,
1277 }};
1278
1279
1280/* ====================================================================== */
1281/* size tag - pass size_t value @NEW_1_12_5 */
1282
1283static
1284int t_size_snprintf(tagi_t const *t, char b[], size_t size)
1285{
1286 return snprintf(b, size, MOD_ZU"%zu", (size_t)t->t_value);
1287}
1288
1289static
1290int t_size_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1291{
1292 *(size_t *)ref = (size_t)value->t_value;
1293
1294 return 1;
1295}
1296
1297static
1298int t_size_scan(tag_type_t tt, su_home_t *home,
1299 char const *s,
1300 tag_value_t *return_value)
1301{
1302 unsigned longlonglong long value;
1303 char *rest;
1304
1305 value = strtoull(s, &rest, 0);
1306
1307 if (s != rest && value <= SIZE_MAX(18446744073709551615UL)) {
1308 *return_value = (tag_value_t)value;
1309 return 1;
1310 }
1311 else {
1312 *return_value = (tag_value_t)0;
1313 return -1;
1314 }
1315}
1316
1317/** Tag class for tags with size_t value. @NEW_1_12_5. */
1318tag_class_t size_tag_class[1] =
1319 {{
1320 sizeof(int_tag_class),
1321 /* tc_next */ NULL((void*)0),
1322 /* tc_len */ NULL((void*)0),
1323 /* tc_move */ NULL((void*)0),
1324 /* tc_xtra */ NULL((void*)0),
1325 /* tc_dup */ NULL((void*)0),
1326 /* tc_free */ NULL((void*)0),
1327 /* tc_find */ NULL((void*)0),
1328 /* tc_snprintf */ t_size_snprintf,
1329 /* tc_filter */ NULL((void*)0),
1330 /* tc_ref_set */ t_size_ref_set,
1331 /* tc_scan */ t_size_scan,
1332 }};
1333
1334/* ====================================================================== */
1335/* usize tag - pass usize_t value */
1336
1337static
1338int t_usize_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1339{
1340 *(usize_t *)ref = (usize_t)value->t_value;
1341
1342 return 1;
1343}
1344
1345static
1346int t_usize_scan(tag_type_t tt, su_home_t *home,
1347 char const *s,
1348 tag_value_t *return_value)
1349{
1350 unsigned longlonglong long value;
1351 char *rest;
1352
1353 value = strtoull(s, &rest, 0);
1354
1355 if (s != rest && value <= USIZE_MAX(2147483647 *2U +1U)) {
1356 *return_value = (tag_value_t)value;
1357 return 1;
1358 }
1359 else {
1360 *return_value = (tag_value_t)0;
1361 return -1;
1362 }
1363}
1364
1365/** Tag class for tags with usize_t value. @NEW_1_12_5. */
1366tag_class_t usize_tag_class[1] =
1367 {{
1368 sizeof(int_tag_class),
1369 /* tc_next */ NULL((void*)0),
1370 /* tc_len */ NULL((void*)0),
1371 /* tc_move */ NULL((void*)0),
1372 /* tc_xtra */ NULL((void*)0),
1373 /* tc_dup */ NULL((void*)0),
1374 /* tc_free */ NULL((void*)0),
1375 /* tc_find */ NULL((void*)0),
1376 /* tc_snprintf */ t_size_snprintf,
1377 /* tc_filter */ NULL((void*)0),
1378 /* tc_ref_set */ t_usize_ref_set,
1379 /* tc_scan */ t_usize_scan,
1380 }};
1381
1382
1383/* ====================================================================== */
1384/* bool tag - pass boolean value */
1385
1386int t_bool_snprintf(tagi_t const *t, char b[], size_t size)
1387{
1388 return snprintf(b, size, "%s", t->t_value ? "true" : "false");
1389}
1390
1391int t_bool_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1392{
1393 *(int *)ref = (value->t_value != 0);
1394
1395 return 1;
1396}
1397
1398int t_bool_scan(tag_type_t tt, su_home_t *home,
1399 char const *s,
1400 tag_value_t *return_value)
1401{
1402 int retval;
1403 int value = 0;
1404
1405 if (su_casenmatch(s, "true", 4)
1406 && strlen(s + 4) == strspn(s + 4, " \t\r\n")__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" \t\r\n") && ((size_t)(const void *)((" \t\r\n") +
1) - (size_t)(const void *)(" \t\r\n") == 1) ? ((__builtin_constant_p
(s + 4) && ((size_t)(const void *)((s + 4) + 1) - (size_t
)(const void *)(s + 4) == 1)) ? __builtin_strspn (s + 4, " \t\r\n"
) : ((__a0 = ((const char *) (" \t\r\n"))[0], __a0 == '\0') ?
((void) (s + 4), (size_t) 0) : ((__a1 = ((const char *) (" \t\r\n"
))[1], __a1 == '\0') ? __strspn_c1 (s + 4, __a0) : ((__a2 = (
(const char *) (" \t\r\n"))[2], __a2 == '\0') ? __strspn_c2 (
s + 4, __a0, __a1) : (((const char *) (" \t\r\n"))[3] == '\0'
? __strspn_c3 (s + 4, __a0, __a1, __a2) : __builtin_strspn (
s + 4, " \t\r\n")))))) : __builtin_strspn (s + 4, " \t\r\n"))
; })
) {
1407 value = 1, retval = 1;
1408 } else if (su_casenmatch(s, "false", 5)
1409 && strlen(s + 5) == strspn(s + 5, " \t\r\n")__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" \t\r\n") && ((size_t)(const void *)((" \t\r\n") +
1) - (size_t)(const void *)(" \t\r\n") == 1) ? ((__builtin_constant_p
(s + 5) && ((size_t)(const void *)((s + 5) + 1) - (size_t
)(const void *)(s + 5) == 1)) ? __builtin_strspn (s + 5, " \t\r\n"
) : ((__a0 = ((const char *) (" \t\r\n"))[0], __a0 == '\0') ?
((void) (s + 5), (size_t) 0) : ((__a1 = ((const char *) (" \t\r\n"
))[1], __a1 == '\0') ? __strspn_c1 (s + 5, __a0) : ((__a2 = (
(const char *) (" \t\r\n"))[2], __a2 == '\0') ? __strspn_c2 (
s + 5, __a0, __a1) : (((const char *) (" \t\r\n"))[3] == '\0'
? __strspn_c3 (s + 5, __a0, __a1, __a2) : __builtin_strspn (
s + 5, " \t\r\n")))))) : __builtin_strspn (s + 5, " \t\r\n"))
; })
) {
1410 value = 0, retval = 1;
1411 } else {
1412 retval = t_int_scan(tt, home, s, return_value);
1413 value = *return_value != 0;
1414 }
1415
1416 if (retval == 1)
1417 *return_value = (tag_value_t)value;
1418 else
1419 *return_value = (tag_value_t)0;
1420
1421 return retval;
1422}
1423
1424tag_class_t bool_tag_class[1] =
1425 {{
1426 sizeof(bool_tag_class),
1427 /* tc_next */ NULL((void*)0),
1428 /* tc_len */ NULL((void*)0),
1429 /* tc_move */ NULL((void*)0),
1430 /* tc_xtra */ NULL((void*)0),
1431 /* tc_dup */ NULL((void*)0),
1432 /* tc_free */ NULL((void*)0),
1433 /* tc_find */ NULL((void*)0),
1434 /* tc_snprintf */ t_bool_snprintf,
1435 /* tc_filter */ NULL((void*)0),
1436 /* tc_ref_set */ t_bool_ref_set,
1437 /* tc_scan */ t_bool_scan,
1438 }};
1439
1440/* ====================================================================== */
1441/* ptr tag - pass pointer value */
1442
1443int t_ptr_snprintf(tagi_t const *t, char b[], size_t size)
1444{
1445 return snprintf(b, size, "%p", (void *)t->t_value);
1446}
1447
1448int t_ptr_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1449{
1450 *(void **)ref = (void *)value->t_value;
1451
1452 return 1;
1453}
1454
1455/* This is not usually very safe, so it is not used */
1456int t_ptr_scan(tag_type_t tt, su_home_t *home,
1457 char const *s,
1458 tag_value_t *return_value)
1459{
1460 int retval;
1461 void *ptr;
1462
1463 retval = sscanf(s, "%p", &ptr);
1464
1465 if (retval == 1)
1466 *return_value = (tag_value_t)ptr;
1467 else
1468 *return_value = (tag_value_t)NULL((void*)0);
1469
1470 return retval;
1471}
1472
1473tag_class_t ptr_tag_class[1] =
1474 {{
1475 sizeof(ptr_tag_class),
1476 /* tc_next */ NULL((void*)0),
1477 /* tc_len */ NULL((void*)0),
1478 /* tc_move */ NULL((void*)0),
1479 /* tc_xtra */ NULL((void*)0),
1480 /* tc_dup */ NULL((void*)0),
1481 /* tc_free */ NULL((void*)0),
1482 /* tc_find */ NULL((void*)0),
1483 /* tc_snprintf */ t_ptr_snprintf,
1484 /* tc_filter */ NULL((void*)0),
1485 /* tc_ref_set */ t_ptr_ref_set,
1486 /* tc_scan */ NULL((void*)0),
1487 }};
1488
1489/* ====================================================================== */
1490/* socket tag - pass socket */
1491
1492#include <sofia-sip/su.h>
1493
1494int t_socket_snprintf(tagi_t const *t, char b[], size_t size)
1495{
1496 /* socket can be int or DWORD (or QWORD on win64?) */
1497 return snprintf(b, size, LLI"%lli", (longlonglong long)t->t_value);
1498}
1499
1500int t_socket_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1501{
1502 *(su_socket_t *)ref = (su_socket_t)value->t_value;
1503
1504 return 1;
1505}
1506
1507tag_class_t socket_tag_class[1] =
1508 {{
1509 sizeof(socket_tag_class),
1510 /* tc_next */ NULL((void*)0),
1511 /* tc_len */ NULL((void*)0),
1512 /* tc_move */ NULL((void*)0),
1513 /* tc_xtra */ NULL((void*)0),
1514 /* tc_dup */ NULL((void*)0),
1515 /* tc_free */ NULL((void*)0),
1516 /* tc_find */ NULL((void*)0),
1517 /* tc_snprintf */ t_socket_snprintf,
1518 /* tc_filter */ NULL((void*)0),
1519 /* tc_ref_set */ t_socket_ref_set,
1520 /* tc_scan */ NULL((void*)0),
1521 }};
1522
1523/* ====================================================================== */
1524/* str tag - pass string value */
1525
1526int t_str_snprintf(tagi_t const *t, char b[], size_t size)
1527{
1528 if (t->t_value)
1529 return snprintf(b, size, "\"%s\"", (char const *)t->t_value);
1530 else
1531 return snprintf(b, size, "<null>");
1532}
1533
1534int t_str_scan(tag_type_t tt, su_home_t *home,
1535 char const *s,
1536 tag_value_t *return_value)
1537{
1538 int retval;
1539
1540 s = su_strdup(home, s);
1541
1542 if (s)
1543 *return_value = (tag_value_t)s, retval = 1;
1544 else
1545 *return_value = (tag_value_t)NULL((void*)0), retval = -1;
1546
1547 return retval;
1548}
1549
1550tagi_t *t_str_dup(tagi_t *dst, tagi_t const *src, void **bb)
1551{
1552 dst->t_tag = src->t_tag;
1553 if (src->t_value) {
1554 char const *s = (char const *)src->t_value;
1555 size_t len = strlen(s) + 1;
1556 dst->t_value = (tag_value_t)strcpy(*bb, s);
1557 *bb = (char *)*bb + len;
1558 }
1559 else
1560 dst->t_value = (tag_value_t)0;
1561
1562 return dst + 1;
1563}
1564
1565size_t t_str_xtra(tagi_t const *t, size_t offset)
1566{
1567 return t->t_value ? strlen((char *)t->t_value) + 1 : 0;
1568}
1569
1570tag_class_t str_tag_class[1] =
1571 {{
1572 sizeof(str_tag_class),
1573 /* tc_next */ NULL((void*)0),
1574 /* tc_len */ NULL((void*)0),
1575 /* tc_move */ NULL((void*)0),
1576 /* tc_xtra */ t_str_xtra,
1577 /* tc_dup */ t_str_dup,
1578 /* tc_free */ NULL((void*)0),
1579 /* tc_find */ NULL((void*)0),
1580 /* tc_snprintf */ t_str_snprintf,
1581 /* tc_filter */ NULL((void*)0),
1582 /* tc_ref_set */ t_ptr_ref_set,
1583 /* tc_scan */ t_str_scan,
1584 }};
1585
1586/* ====================================================================== */
1587/* cstr tag - pass constant string value (no need to dup) */
1588
1589/** Tag class for constant strings */
1590tag_class_t cstr_tag_class[1] =
1591 {{
1592 sizeof(cstr_tag_class),
1593 /* tc_next */ NULL((void*)0),
1594 /* tc_len */ NULL((void*)0),
1595 /* tc_move */ NULL((void*)0),
1596 /* tc_xtra */ NULL((void*)0),
1597 /* tc_dup */ NULL((void*)0),
1598 /* tc_free */ NULL((void*)0),
1599 /* tc_find */ NULL((void*)0),
1600 /* tc_snprintf */ t_str_snprintf,
1601 /* tc_filter */ NULL((void*)0),
1602 /* tc_ref_set */ t_ptr_ref_set,
1603 /* tc_scan */ t_str_scan,
1604 }};
1605
1606/* ====================================================================== */
1607/* ref tag - pass reference */
1608
1609tag_class_t ref_tag_class[1] =
1610 {{
1611 sizeof(ref_tag_class),
1612 /* tc_next */ NULL((void*)0),
1613 /* tc_len */ NULL((void*)0),
1614 /* tc_move */ NULL((void*)0),
1615 /* tc_xtra */ NULL((void*)0),
1616 /* tc_dup */ NULL((void*)0),
1617 /* tc_free */ NULL((void*)0),
1618 /* tc_find */ NULL((void*)0),
1619 /* tc_snprintf */ t_ptr_snprintf,
1620 /* tc_filter */ NULL((void*)0),
1621 /* tc_ref_set */ t_ptr_ref_set,
1622 /* tc_scan */ NULL((void*)0),
1623 }};
1624
1625