Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/su/su_taglist.c
Location:line 489, column 15
Description:Called function pointer is null (null dereference)

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);
142 int n, m;
143
144 n = snprintf(b, size, "%s::%s: ",
145 tt->tt_ns ? tt->tt_ns : "",
146 tt->tt_name ? tt->tt_name : "null");
147 if (n < 0)
148 return n;
149
150 if ((size_t)n > size)
151 size = n;
152
153 if (tt->tt_snprintftt_class->tc_snprintf)
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);
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) {
6
Taking false branch
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)) {
7
Loop condition is true. Entering loop body
10
Loop condition is true. Entering loop body
13
Loop condition is true. Entering loop body
17
Loop condition is true. Entering loop body
488 if (TAG_TYPE_OF(f)((f) && (f)->t_tag ? (f)->t_tag : tag_null)->tt_filtertt_class->tc_filter)
8
Taking false branch
11
Taking false branch
14
Within the expansion of the macro 'TAG_TYPE_OF':
a
Assuming pointer value is null
15
Taking false branch
18
Taking true branch
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);
19
Within the expansion of the macro 'TAG_TYPE_OF':
a
Called function pointer is null (null dereference)
490 else if (tt == f->t_tag) {
9
Taking false branch
12
Taking false branch
16
Taking false branch
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) {
3
Taking false branch
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)) {
4
Loop condition is true. Entering loop body
530 d = t_filter(NULL((void*)0), filter, s, b);
5
Calling 't_filter'
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);
2
Calling 'tl_filter'
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);
1
Calling 'tl_afilter'
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