Bug Summary

File:libsofia-sip-ua/su/su_taglist.c
Warning:line 530, column 19
Although the value stored to 'd' is used in the enclosing expression, the value is never actually read from 'd'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name su_taglist.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/su -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2022-06-23-181620-12-1 -x c su_taglist.c
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)((void) sizeof (((size_t)((char *)&dst[n] - (char *)dst) <
size) ? 1 : 0), __extension__ ({ if ((size_t)((char *)&dst
[n] - (char *)dst) < size) ; else __assert_fail ("(size_t)((char *)&dst[n] - (char *)dst) < size"
, "su_taglist.c", 206, __extension__ __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)((void) sizeof ((b == end) ? 1 : 0), __extension__ ({ if (b ==
end) ; else __assert_fail ("b == end", "su_taglist.c", 327, __extension__
__PRETTY_FUNCTION__); }))
; assert(tend == d)((void) sizeof ((tend == d) ? 1 : 0), __extension__ ({ if (tend
== d) ; else __assert_fail ("tend == d", "su_taglist.c", 327
, __extension__ __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)((void) sizeof ((tt) ? 1 : 0), __extension__ ({ if (tt) ; else
__assert_fail ("tt", "su_taglist.c", 380, __extension__ __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)((void) sizeof ((((tag_type_t)tt->tt_magic)->tt_class->
tc_ref_set) ? 1 : 0), __extension__ ({ if (((tag_type_t)tt->
tt_magic)->tt_class->tc_ref_set) ; else __assert_fail (
"((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set", "su_taglist.c"
, 410, __extension__ __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)((void) sizeof ((tt->tt_class == ref_tag_class) ? 1 : 0), __extension__
({ if (tt->tt_class == ref_tag_class) ; else __assert_fail
("tt->tt_class == ref_tag_class", "su_taglist.c", 417, __extension__
__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)((void) sizeof ((((tag_type_t)tt->tt_magic)->tt_class->
tc_ref_set) ? 1 : 0), __extension__ ({ if (((tag_type_t)tt->
tt_magic)->tt_class->tc_ref_set) ; else __assert_fail (
"((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set", "su_taglist.c"
, 449, __extension__ __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)((void) sizeof ((tt->tt_class == ref_tag_class) ? 1 : 0), __extension__
({ if (tt->tt_class == ref_tag_class) ; else __assert_fail
("tt->tt_class == ref_tag_class", "su_taglist.c", 456, __extension__
__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 tag_type_t tt_f = TAG_TYPE_OF(f)((f) && (f)->t_tag ? (f)->t_tag : tag_null);
489 if (tt_f->tt_filtertt_class->tc_filter)
490 d += (size_t)tt_f->tt_filtertt_class->tc_filter(NULL((void*)0), f, src, bb);
491 else if (tt == f->t_tag) {
492 d += t_len(src);
493 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
494 }
495 }
496
497 dst = (tagi_t *)d;
498 }
499
500 return dst;
501}
502
503/** Make filtered copy of a tag list @a src with @a filter to @a dst.
504 *
505 * Each tag in @a src is checked against tags in list @a filter. If the tag
506 * is in the @a filter list, or there is a special filter tag in the list
507 * which matches with the tag in @a src, the tag is duplicated to @a dst using
508 * memory buffer in @a b.
509 *
510 * When @a dst is NULL, this function calculates the size of the filtered list.
511 *
512 * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
513 * TAG_FILTER(), TAG_ANY(), #ns_tag_class
514 */
515tagi_t *tl_filter(tagi_t dst[],
516 tagi_t const filter[],
517 tagi_t const src[],
518 void **b)
519{
520 tagi_t const *s;
521 tagi_t *d;
522
523 if (dst) {
524 for (s = src, d = dst; s; s = t_next(s))
525 d = t_filter(d, filter, s, b);
526 }
527 else {
528 size_t rv = 0;
529
530 for (s = src, d = dst; s; s = t_next(s)) {
Although the value stored to 'd' is used in the enclosing expression, the value is never actually read from 'd'
531 d = t_filter(NULL((void*)0), filter, s, b);
532 rv += (char *)d - (char *)NULL((void*)0);
533 }
534
535 d = (tagi_t *)rv;
536 }
537
538 return d;
539}
540
541
542
543/**Filter a tag list.
544 *
545 * The function tl_afilter() will build a tag list containing tags specified
546 * in @a filter and extracted from @a src. It will allocate the memory used by
547 * tag list via the specified memory @a home, which may be also @c NULL.
548 *
549 * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(),
550 * TAG_FILTER(), TAG_ANY(), #ns_tag_class
551 */
552tagi_t *tl_afilter(su_home_t *home, tagi_t const filter[], tagi_t const src[])
553{
554 tagi_t *dst, *d, *t_end = NULL((void*)0);
555 void *b, *end = NULL((void*)0);
556 size_t len;
557
558 /* Calculate length of the result */
559 t_end = tl_filter(NULL((void*)0), filter, src, &end);
560 len = ((char *)t_end - (char *)NULL((void*)0)) + ((char *)end - (char*)NULL((void*)0));
561
562 if (len == 0)
563 return NULL((void*)0);
564
565 /* Allocate the result */
566 if (!(dst = su_alloc(home, len)))
567 return NULL((void*)0);
568
569 /* Build the result */
570 b = (dst + (t_end - (tagi_t *)NULL((void*)0)));
571 d = tl_filter(dst, filter, src, (void **)&b);
572
573 /* Ensure that everything is consistent */
574 assert(d == dst + (t_end - (tagi_t *)NULL))((void) sizeof ((d == dst + (t_end - (tagi_t *)((void*)0))) ?
1 : 0), __extension__ ({ if (d == dst + (t_end - (tagi_t *)(
(void*)0))) ; else __assert_fail ("d == dst + (t_end - (tagi_t *)NULL)"
, "su_taglist.c", 574, __extension__ __PRETTY_FUNCTION__); })
)
;
575 assert(b == (char *)dst + len)((void) sizeof ((b == (char *)dst + len) ? 1 : 0), __extension__
({ if (b == (char *)dst + len) ; else __assert_fail ("b == (char *)dst + len"
, "su_taglist.c", 575, __extension__ __PRETTY_FUNCTION__); })
)
;
576
577 return dst;
578}
579
580/** Filter tag list @a src with given tags.
581 *
582 * @sa tl_afilter(), tl_filtered_tlist(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
583 */
584tagi_t *tl_tfilter(su_home_t *home, tagi_t const src[],
585 tag_type_t tag, tag_value_t value, ...)
586{
587 tagi_t *tl;
588 ta_list ta;
589 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)
;
590 tl = tl_afilter(home, ta_args(ta)(ta).tl, src);
591 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))
;
592 return tl;
593}
594
595/** Create a filtered tag list.
596 *
597 * @sa tl_afilter(), tl_tfilter(), TAG_FILTER(), TAG_ANY(), #ns_tag_class
598 */
599tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[],
600 tag_type_t tag, tag_value_t value, ...)
601{
602 tagi_t *tl;
603 ta_list ta;
604
605 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)
;
606 tl = tl_afilter(home, filter, ta_args(ta)(ta).tl);
607 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))
;
608
609 return tl;
610}
611
612
613/** Remove listed tags from the list @a lst. */
614int tl_tremove(tagi_t lst[], tag_type_t tag, tag_value_t value, ...)
615{
616 tagi_t *l, *l_next;
617 int retval = 0;
618 ta_list ta;
619
620 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)
;
621
622 for (l = lst; l; l = l_next) {
623 if ((l_next = (tagi_t *)t_next(l))) {
624 if (tl_find(ta_args(ta)(ta).tl, l->t_tag))
625 l->t_tag = tag_skip;
626 else
627 retval++;
628 }
629 }
630
631 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))
;
632
633 return retval;
634}
635
636/** Calculate length of a tag list with a @c va_list. */
637size_t tl_vlen(va_list ap)
638{
639 size_t len = 0;
640 tagi_t tagi[2] = {{ NULL((void*)0) }};
641
642 do {
643 tagi->t_tag = va_arg(ap, tag_type_t )__builtin_va_arg(ap, tag_type_t);
644 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
645 len += sizeof(tagi_t);
646 } while (!t_end(tagi));
647
648 return len;
649}
650
651/** Convert va_list to tag list */
652tagi_t *tl_vlist(va_list ap)
653{
654 tagi_t *t, *rv;
655 va_list aq;
656
657 va_copy(aq, ap)__builtin_va_copy(aq, ap);
658 rv = malloc(tl_vlen(aq));
659 va_end(aq)__builtin_va_end(aq);
660
661 for (t = rv; t; t++) {
662 t->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
663 t->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
664
665 if (t_end(t))
666 break;
667 }
668
669 return rv;
670}
671
672tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap)
673{
674 tagi_t *t, *rv;
675 tagi_t tagi[1];
676 size_t size;
677
678 tagi->t_tag = tag, tagi->t_value = value;
679
680 if (!t_end(tagi)) {
681 va_list aq;
682 va_copy(aq, ap)__builtin_va_copy(aq, ap);
683 size = sizeof(tagi) + tl_vlen(aq);
684 va_end(aq)__builtin_va_end(aq);
685 }
686 else
687 size = sizeof(tagi);
688
689 t = rv = malloc(size);
690
691 for (;t;) {
692 *t++ = *tagi;
693
694 if (t_end(tagi))
695 break;
696
697 tagi->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
698 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
699 }
700
701 assert((char *)rv + size == (char *)t)((void) sizeof (((char *)rv + size == (char *)t) ? 1 : 0), __extension__
({ if ((char *)rv + size == (char *)t) ; else __assert_fail (
"(char *)rv + size == (char *)t", "su_taglist.c", 701, __extension__
__PRETTY_FUNCTION__); }))
;
702
703 return rv;
704}
705
706/** Make a tag list until TAG_NEXT() or TAG_END() */
707tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...)
708{
709 va_list ap;
710 tagi_t *t;
711
712 va_start(ap, value)__builtin_va_start(ap, value);
713 t = tl_vlist2(tag, value, ap);
714 va_end(ap)__builtin_va_end(ap);
715
716 return t;
717}
718
719/** Calculate length of a linear tag list. */
720size_t tl_vllen(tag_type_t tag, tag_value_t value, va_list ap)
721{
722 size_t len = sizeof(tagi_t);
723 tagi_t const *next;
724 tagi_t tagi[3];
725
726 tagi[0].t_tag = tag;
727 tagi[0].t_value = value;
728 tagi[1].t_tag = tag_any;
729 tagi[1].t_value = 0;
730
731 for (;;) {
732 next = tl_next(tagi);
733 if (next != tagi + 1)
734 break;
735
736 if (tagi->t_tag != tag_skip)
737 len += sizeof(tagi_t);
738 tagi->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
739 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
740 }
741
742 for (; next; next = tl_next(next))
743 len += sizeof(tagi_t);
744
745 return len;
746}
747
748/** Make a linear tag list. */
749tagi_t *tl_vllist(tag_type_t tag, tag_value_t value, va_list ap)
750{
751 va_list aq;
752 tagi_t *t, *rv;
753 tagi_t const *next;
754 tagi_t tagi[2];
755
756 size_t size;
757
758 va_copy(aq, ap)__builtin_va_copy(aq, ap);
759 size = tl_vllen(tag, value, aq);
760 va_end(aq)__builtin_va_end(aq);
761
762 t = rv = malloc(size);
763 if (rv == NULL((void*)0))
764 return rv;
765
766 tagi[0].t_tag = tag;
767 tagi[0].t_value = value;
768 tagi[1].t_tag = tag_any;
769 tagi[1].t_value = 0;
770
771 for (;;) {
772 next = tl_next(tagi);
773 if (next != tagi + 1)
774 break;
775
776 if (tagi->t_tag != tag_skip)
777 *t++ = *tagi;
778
779 tagi->t_tag = va_arg(ap, tag_type_t)__builtin_va_arg(ap, tag_type_t);
780 tagi->t_value = va_arg(ap, tag_value_t)__builtin_va_arg(ap, tag_value_t);
781 }
782
783 for (; next; next = tl_next(next))
784 *t++ = *next;
785
786 t->t_tag = NULL((void*)0); t->t_value = 0; t++;
787
788 assert((char *)rv + size == (char *)t)((void) sizeof (((char *)rv + size == (char *)t) ? 1 : 0), __extension__
({ if ((char *)rv + size == (char *)t) ; else __assert_fail (
"(char *)rv + size == (char *)t", "su_taglist.c", 788, __extension__
__PRETTY_FUNCTION__); }))
;
789
790 return rv;
791}
792
793/** Make a linear tag list until TAG_END().
794 *
795 */
796tagi_t *tl_llist(tag_type_t tag, tag_value_t value, ...)
797{
798 va_list ap;
799 tagi_t *t;
800
801 va_start(ap, value)__builtin_va_start(ap, value);
802 t = tl_vllist(tag, value, ap);
803 va_end(ap)__builtin_va_end(ap);
804
805 return t;
806}
807
808/** Free a tag list allocated by tl_list(), tl_llist() or tl_vlist(). */
809void tl_vfree(tagi_t *t)
810{
811 if (t)
812 free(t);
813}
814
815/** Convert a string to the a value of a tag. */
816int t_scan(tag_type_t tt, su_home_t *home, char const *s,
817 tag_value_t *return_value)
818{
819 if (tt == NULL((void*)0) || s == NULL((void*)0) || return_value == NULL((void*)0))
820 return -1;
821
822 if (tt->tt_class->tc_scan) {
823 return tt->tt_class->tc_scan(tt, home, s, return_value);
824 }
825 else { /* Not implemented */
826 *return_value = (tag_value_t)0;
827 return -2;
828 }
829}
830
831
832/* ====================================================================== */
833/* null tag */
834
835static
836tagi_t const *t_null_next(tagi_t const *t)
837{
838 return NULL((void*)0);
839}
840
841static
842tagi_t *t_null_move(tagi_t *dst, tagi_t const *src)
843{
844 memset(dst, 0, sizeof(*dst));
845 return dst + 1;
846}
847
848static
849tagi_t *t_null_dup(tagi_t *dst, tagi_t const *src, void **bb)
850{
851 memset(dst, 0, sizeof(*dst));
852 return dst + 1;
853}
854
855static
856tagi_t const * t_null_find(tag_type_t tt, tagi_t const lst[])
857{
858 return NULL((void*)0);
859}
860
861tagi_t *t_null_filter(tagi_t *dst,
862 tagi_t const filter[],
863 tagi_t const *src,
864 void **bb)
865{
866 if (TAG_TYPE_OF(src)((src) && (src)->t_tag ? (src)->t_tag : tag_null
)
== tag_null) {
867 if (dst) {
868 dst->t_tag = NULL((void*)0);
869 dst->t_value = 0;
870 }
871 return dst + 1;
872 }
873 return dst;
874}
875
876tag_class_t null_tag_class[1] =
877 {{
878 sizeof(null_tag_class),
879 /* tc_next */ t_null_next,
880 /* tc_len */ NULL((void*)0),
881 /* tc_move */ t_null_move,
882 /* tc_xtra */ NULL((void*)0),
883 /* tc_dup */ t_null_dup,
884 /* tc_free */ NULL((void*)0),
885 /* tc_find */ t_null_find,
886 /* tc_snprintf */ NULL((void*)0),
887 /* tc_filter */ t_null_filter,
888 /* tc_ref_set */ NULL((void*)0),
889 /* tc_scan */ NULL((void*)0),
890 }};
891
892tag_typedef_t tag_null = TAG_TYPEDEF(tag_null, null){{ "", "tag_null", null_tag_class, 0 }};
893
894/* ====================================================================== */
895/* end tag */
896
897tagi_t *t_end_filter(tagi_t *dst,
898 tagi_t const filter[],
899 tagi_t const *src,
900 void **bb)
901{
902 return dst;
903}
904
905tag_class_t end_tag_class[1] =
906 {{
907 sizeof(end_tag_class),
908 /* tc_next */ NULL((void*)0),
909 /* tc_len */ NULL((void*)0),
910 /* tc_move */ NULL((void*)0),
911 /* tc_xtra */ NULL((void*)0),
912 /* tc_dup */ NULL((void*)0),
913 /* tc_free */ NULL((void*)0),
914 /* tc_find */ NULL((void*)0),
915 /* tc_snprintf */ NULL((void*)0),
916 /* tc_filter */ t_end_filter,
917 /* tc_ref_set */ NULL((void*)0),
918 /* tc_scan */ NULL((void*)0),
919 }};
920
921/* ====================================================================== */
922/* skip tag - placeholder in tag list */
923
924static
925tagi_t const *t_skip_next(tagi_t const *t)
926{
927 return t + 1;
928}
929
930static
931tagi_t *t_skip_move(tagi_t *dst, tagi_t const *src)
932{
933 return dst;
934}
935
936static
937size_t t_skip_len(tagi_t const *t)
938{
939 return 0;
940}
941
942static
943tagi_t *t_skip_dup(tagi_t *dst, tagi_t const *src, void **bb)
944{
945 return dst;
946}
947
948static
949tagi_t *t_skip_filter(tagi_t *dst,
950 tagi_t const filter[],
951 tagi_t const *src,
952 void **bb)
953{
954 return dst;
955}
956
957tag_class_t skip_tag_class[1] =
958 {{
959 sizeof(skip_tag_class),
960 /* tc_next */ t_skip_next,
961 /* tc_len */ t_skip_len,
962 /* tc_move */ t_skip_move,
963 /* tc_xtra */ NULL((void*)0),
964 /* tc_dup */ t_skip_dup,
965 /* tc_free */ NULL((void*)0),
966 /* tc_find */ t_null_find,
967 /* tc_snprintf */ NULL((void*)0),
968 /* tc_filter */ t_skip_filter,
969 /* tc_ref_set */ NULL((void*)0),
970 /* tc_scan */ NULL((void*)0),
971 }};
972
973tag_typedef_t tag_skip = TAG_TYPEDEF(tag_skip, skip){{ "", "tag_skip", skip_tag_class, 0 }};
974
975/* ====================================================================== */
976/* next tag - jump to next tag list */
977
978static
979tagi_t const *t_next_next(tagi_t const *t)
980{
981 return (tagi_t *)(t->t_value);
982}
983
984static
985tagi_t *t_next_move(tagi_t *dst, tagi_t const *src)
986{
987 if (!src->t_value)
988 return t_null_move(dst, src);
989 return dst;
990}
991
992static
993size_t t_next_len(tagi_t const *t)
994{
995 if (!t->t_value)
996 return sizeof(*t);
997 return 0;
998}
999
1000static
1001tagi_t *t_next_dup(tagi_t *dst, tagi_t const *src, void **bb)
1002{
1003 if (!src->t_value)
1004 return t_null_dup(dst, src, bb);
1005 return dst;
1006}
1007
1008static
1009tagi_t *t_next_filter(tagi_t *dst,
1010 tagi_t const filter[],
1011 tagi_t const *src,
1012 void **bb)
1013{
1014 return dst;
1015}
1016
1017tag_class_t next_tag_class[1] =
1018 {{
1019 sizeof(next_tag_class),
1020 /* tc_next */ t_next_next,
1021 /* tc_len */ t_next_len,
1022 /* tc_move */ t_next_move,
1023 /* tc_xtra */ NULL((void*)0),
1024 /* tc_dup */ t_next_dup,
1025 /* tc_free */ NULL((void*)0),
1026 /* tc_find */ t_null_find,
1027 /* tc_snprintf */ NULL((void*)0),
1028 /* tc_filter */ t_next_filter,
1029 /* tc_ref_set */ NULL((void*)0),
1030 /* tc_scan */ NULL((void*)0),
1031 }};
1032
1033tag_typedef_t tag_next = TAG_TYPEDEF(tag_next, next){{ "", "tag_next", next_tag_class, 0 }};
1034
1035/* ====================================================================== */
1036/* filter tag - use function to filter tag */
1037
1038static
1039tagi_t *t_filter_with(tagi_t *dst,
1040 tagi_t const *t,
1041 tagi_t const *src,
1042 void **bb)
1043{
1044 tag_filter_f *function;
1045
1046 if (!src || !t)
1047 return dst;
1048
1049 function = (tag_filter_f *)t->t_value;
1050
1051 if (!function || !function(t, src))
1052 return dst;
1053
1054 if (dst) {
1055 return t_dup(dst, src, bb);
1056 }
1057 else {
1058 dst = (tagi_t *)((char *)dst + t_len(src));
1059 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
1060 return dst;
1061 }
1062}
1063
1064tag_class_t filter_tag_class[1] =
1065 {{
1066 sizeof(filter_tag_class),
1067 /* tc_next */ NULL((void*)0),
1068 /* tc_len */ NULL((void*)0),
1069 /* tc_move */ NULL((void*)0),
1070 /* tc_xtra */ NULL((void*)0),
1071 /* tc_dup */ NULL((void*)0),
1072 /* tc_free */ NULL((void*)0),
1073 /* tc_find */ NULL((void*)0),
1074 /* tc_snprintf */ NULL((void*)0),
1075 /* tc_filter */ t_filter_with,
1076 /* tc_ref_set */ NULL((void*)0),
1077 /* tc_scan */ NULL((void*)0),
1078 }};
1079
1080/** Filter tag - apply function in order to filter tag. */
1081tag_typedef_t tag_filter = TAG_TYPEDEF(tag_filter, filter){{ "", "tag_filter", filter_tag_class, 0 }};
1082
1083/* ====================================================================== */
1084/* any tag - match to any tag when filtering */
1085
1086static
1087tagi_t *t_any_filter(tagi_t *dst,
1088 tagi_t const filter[],
1089 tagi_t const *src,
1090 void **bb)
1091{
1092 if (!src)
1093 return dst;
1094 else if (dst) {
1095 return t_dup(dst, src, bb);
1096 }
1097 else {
1098 dst = (tagi_t *)((char *)dst + t_len(src));
1099 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
1100 return dst;
1101 }
1102}
1103
1104tag_class_t any_tag_class[1] =
1105 {{
1106 sizeof(any_tag_class),
1107 /* tc_next */ NULL((void*)0),
1108 /* tc_len */ NULL((void*)0),
1109 /* tc_move */ NULL((void*)0),
1110 /* tc_xtra */ NULL((void*)0),
1111 /* tc_dup */ NULL((void*)0),
1112 /* tc_free */ NULL((void*)0),
1113 /* tc_find */ NULL((void*)0),
1114 /* tc_snprintf */ NULL((void*)0),
1115 /* tc_filter */ t_any_filter,
1116 /* tc_ref_set */ NULL((void*)0),
1117 /* tc_scan */ NULL((void*)0),
1118 }};
1119
1120/** Any tag - match any tag when filtering. */
1121tag_typedef_t tag_any = TAG_TYPEDEF(tag_any, any){{ "", "tag_any", any_tag_class, 0 }};
1122
1123/* ====================================================================== */
1124/* ns tag - match to any tag with same namespace when filtering */
1125
1126static
1127tagi_t *t_ns_filter(tagi_t *dst,
1128 tagi_t const filter[],
1129 tagi_t const *src,
1130 void **bb)
1131{
1132 char const *match, *ns;
1133
1134 if (!src)
1135 return dst;
1136
1137 assert(filter)((void) sizeof ((filter) ? 1 : 0), __extension__ ({ if (filter
) ; else __assert_fail ("filter", "su_taglist.c", 1137, __extension__
__PRETTY_FUNCTION__); }))
;
1138
1139 match = TAG_TYPE_OF(filter)((filter) && (filter)->t_tag ? (filter)->t_tag :
tag_null)
->tt_ns;
1140 ns = TAG_TYPE_OF(src)((src) && (src)->t_tag ? (src)->t_tag : tag_null
)
->tt_ns;
1141
1142 if (match == NULL((void*)0))
1143 /* everything matches with this */;
1144 else if (match == ns)
1145 /* namespaces matche */;
1146 else if (ns == NULL((void*)0))
1147 /* no match */
1148 return dst;
1149 else if (strcmp(match, ns))
1150 /* no match */
1151 return dst;
1152
1153 if (dst) {
1154 return t_dup(dst, src, bb);
1155 }
1156 else {
1157 dst = (tagi_t *)((char *)dst + t_len(src));
1158 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
1159 return dst;
1160 }
1161}
1162
1163/** Namespace filtering class */
1164tag_class_t ns_tag_class[1] =
1165 {{
1166 sizeof(ns_tag_class),
1167 /* tc_next */ NULL((void*)0),
1168 /* tc_len */ NULL((void*)0),
1169 /* tc_move */ NULL((void*)0),
1170 /* tc_xtra */ NULL((void*)0),
1171 /* tc_dup */ NULL((void*)0),
1172 /* tc_free */ NULL((void*)0),
1173 /* tc_find */ NULL((void*)0),
1174 /* tc_snprintf */ NULL((void*)0),
1175 /* tc_filter */ t_ns_filter,
1176 /* tc_ref_set */ NULL((void*)0),
1177 /* tc_scan */ NULL((void*)0),
1178 }};
1179
1180/* ====================================================================== */
1181/* int tag - pass integer value */
1182
1183int t_int_snprintf(tagi_t const *t, char b[], size_t size)
1184{
1185 return snprintf(b, size, "%i", (int)t->t_value);
1186}
1187
1188int t_int_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1189{
1190 *(int *)ref = (int)value->t_value;
1191
1192 return 1;
1193}
1194
1195int t_int_scan(tag_type_t tt, su_home_t *home,
1196 char const *s,
1197 tag_value_t *return_value)
1198{
1199 int value;
1200 char *rest;
1201
1202 value = strtol(s, &rest, 0);
1203
1204 if (s != rest) {
1205 *return_value = (tag_value_t)value;
1206 return 1;
1207 }
1208 else {
1209 *return_value = (tag_value_t)0;
1210 return -1;
1211 }
1212}
1213
1214tag_class_t int_tag_class[1] =
1215 {{
1216 sizeof(int_tag_class),
1217 /* tc_next */ NULL((void*)0),
1218 /* tc_len */ NULL((void*)0),
1219 /* tc_move */ NULL((void*)0),
1220 /* tc_xtra */ NULL((void*)0),
1221 /* tc_dup */ NULL((void*)0),
1222 /* tc_free */ NULL((void*)0),
1223 /* tc_find */ NULL((void*)0),
1224 /* tc_snprintf */ t_int_snprintf,
1225 /* tc_filter */ NULL((void*)0),
1226 /* tc_ref_set */ t_int_ref_set,
1227 /* tc_scan */ t_int_scan,
1228 }};
1229
1230/* ====================================================================== */
1231/* uint tag - pass unsigned integer value */
1232
1233int t_uint_snprintf(tagi_t const *t, char b[], size_t size)
1234{
1235 return snprintf(b, size, "%u", (unsigned)t->t_value);
1236}
1237
1238int t_uint_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1239{
1240 *(unsigned *)ref = (unsigned)value->t_value;
1241
1242 return 1;
1243}
1244
1245int t_uint_scan(tag_type_t tt, su_home_t *home,
1246 char const *s,
1247 tag_value_t *return_value)
1248{
1249 unsigned value;
1250 char *rest;
1251
1252 value = strtoul(s, &rest, 0);
1253
1254 if (s != rest) {
1255 *return_value = (tag_value_t)value;
1256 return 1;
1257 }
1258 else {
1259 *return_value = (tag_value_t)0;
1260 return -1;
1261 }
1262}
1263
1264tag_class_t uint_tag_class[1] =
1265 {{
1266 sizeof(int_tag_class),
1267 /* tc_next */ NULL((void*)0),
1268 /* tc_len */ NULL((void*)0),
1269 /* tc_move */ NULL((void*)0),
1270 /* tc_xtra */ NULL((void*)0),
1271 /* tc_dup */ NULL((void*)0),
1272 /* tc_free */ NULL((void*)0),
1273 /* tc_find */ NULL((void*)0),
1274 /* tc_snprintf */ t_uint_snprintf,
1275 /* tc_filter */ NULL((void*)0),
1276 /* tc_ref_set */ t_uint_ref_set,
1277 /* tc_scan */ t_uint_scan,
1278 }};
1279
1280
1281/* ====================================================================== */
1282/* size tag - pass size_t value @NEW_1_12_5 */
1283
1284static
1285int t_size_snprintf(tagi_t const *t, char b[], size_t size)
1286{
1287 return snprintf(b, size, MOD_ZU"%zu", (size_t)t->t_value);
1288}
1289
1290static
1291int t_size_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1292{
1293 *(size_t *)ref = (size_t)value->t_value;
1294
1295 return 1;
1296}
1297
1298static
1299int t_size_scan(tag_type_t tt, su_home_t *home,
1300 char const *s,
1301 tag_value_t *return_value)
1302{
1303 unsigned longlonglong long value;
1304 char *rest;
1305
1306 value = strtoull(s, &rest, 0);
1307
1308 if (s != rest && value <= SIZE_MAX(18446744073709551615UL)) {
1309 *return_value = (tag_value_t)value;
1310 return 1;
1311 }
1312 else {
1313 *return_value = (tag_value_t)0;
1314 return -1;
1315 }
1316}
1317
1318/** Tag class for tags with size_t value. @NEW_1_12_5. */
1319tag_class_t size_tag_class[1] =
1320 {{
1321 sizeof(int_tag_class),
1322 /* tc_next */ NULL((void*)0),
1323 /* tc_len */ NULL((void*)0),
1324 /* tc_move */ NULL((void*)0),
1325 /* tc_xtra */ NULL((void*)0),
1326 /* tc_dup */ NULL((void*)0),
1327 /* tc_free */ NULL((void*)0),
1328 /* tc_find */ NULL((void*)0),
1329 /* tc_snprintf */ t_size_snprintf,
1330 /* tc_filter */ NULL((void*)0),
1331 /* tc_ref_set */ t_size_ref_set,
1332 /* tc_scan */ t_size_scan,
1333 }};
1334
1335/* ====================================================================== */
1336/* usize tag - pass usize_t value */
1337
1338static
1339int t_usize_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1340{
1341 *(usize_t *)ref = (usize_t)value->t_value;
1342
1343 return 1;
1344}
1345
1346static
1347int t_usize_scan(tag_type_t tt, su_home_t *home,
1348 char const *s,
1349 tag_value_t *return_value)
1350{
1351 unsigned longlonglong long value;
1352 char *rest;
1353
1354 value = strtoull(s, &rest, 0);
1355
1356 if (s != rest && value <= USIZE_MAX(2147483647 *2U +1U)) {
1357 *return_value = (tag_value_t)value;
1358 return 1;
1359 }
1360 else {
1361 *return_value = (tag_value_t)0;
1362 return -1;
1363 }
1364}
1365
1366/** Tag class for tags with usize_t value. @NEW_1_12_5. */
1367tag_class_t usize_tag_class[1] =
1368 {{
1369 sizeof(int_tag_class),
1370 /* tc_next */ NULL((void*)0),
1371 /* tc_len */ NULL((void*)0),
1372 /* tc_move */ NULL((void*)0),
1373 /* tc_xtra */ NULL((void*)0),
1374 /* tc_dup */ NULL((void*)0),
1375 /* tc_free */ NULL((void*)0),
1376 /* tc_find */ NULL((void*)0),
1377 /* tc_snprintf */ t_size_snprintf,
1378 /* tc_filter */ NULL((void*)0),
1379 /* tc_ref_set */ t_usize_ref_set,
1380 /* tc_scan */ t_usize_scan,
1381 }};
1382
1383
1384/* ====================================================================== */
1385/* bool tag - pass boolean value */
1386
1387int t_bool_snprintf(tagi_t const *t, char b[], size_t size)
1388{
1389 return snprintf(b, size, "%s", t->t_value ? "true" : "false");
1390}
1391
1392int t_bool_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1393{
1394 *(int *)ref = (value->t_value != 0);
1395
1396 return 1;
1397}
1398
1399int t_bool_scan(tag_type_t tt, su_home_t *home,
1400 char const *s,
1401 tag_value_t *return_value)
1402{
1403 int retval;
1404 int value = 0;
1405
1406 if (su_casenmatch(s, "true", 4)
1407 && strlen(s + 4) == strspn(s + 4, " \t\r\n")) {
1408 value = 1, retval = 1;
1409 } else if (su_casenmatch(s, "false", 5)
1410 && strlen(s + 5) == strspn(s + 5, " \t\r\n")) {
1411 value = 0, retval = 1;
1412 } else {
1413 retval = t_int_scan(tt, home, s, return_value);
1414 value = *return_value != 0;
1415 }
1416
1417 if (retval == 1)
1418 *return_value = (tag_value_t)value;
1419 else
1420 *return_value = (tag_value_t)0;
1421
1422 return retval;
1423}
1424
1425tag_class_t bool_tag_class[1] =
1426 {{
1427 sizeof(bool_tag_class),
1428 /* tc_next */ NULL((void*)0),
1429 /* tc_len */ NULL((void*)0),
1430 /* tc_move */ NULL((void*)0),
1431 /* tc_xtra */ NULL((void*)0),
1432 /* tc_dup */ NULL((void*)0),
1433 /* tc_free */ NULL((void*)0),
1434 /* tc_find */ NULL((void*)0),
1435 /* tc_snprintf */ t_bool_snprintf,
1436 /* tc_filter */ NULL((void*)0),
1437 /* tc_ref_set */ t_bool_ref_set,
1438 /* tc_scan */ t_bool_scan,
1439 }};
1440
1441/* ====================================================================== */
1442/* ptr tag - pass pointer value */
1443
1444int t_ptr_snprintf(tagi_t const *t, char b[], size_t size)
1445{
1446 return snprintf(b, size, "%p", (void *)t->t_value);
1447}
1448
1449int t_ptr_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1450{
1451 *(void **)ref = (void *)value->t_value;
1452
1453 return 1;
1454}
1455
1456/* This is not usually very safe, so it is not used */
1457int t_ptr_scan(tag_type_t tt, su_home_t *home,
1458 char const *s,
1459 tag_value_t *return_value)
1460{
1461 int retval;
1462 void *ptr;
1463
1464 retval = sscanf(s, "%p", &ptr);
1465
1466 if (retval == 1)
1467 *return_value = (tag_value_t)ptr;
1468 else
1469 *return_value = (tag_value_t)NULL((void*)0);
1470
1471 return retval;
1472}
1473
1474tag_class_t ptr_tag_class[1] =
1475 {{
1476 sizeof(ptr_tag_class),
1477 /* tc_next */ NULL((void*)0),
1478 /* tc_len */ NULL((void*)0),
1479 /* tc_move */ NULL((void*)0),
1480 /* tc_xtra */ NULL((void*)0),
1481 /* tc_dup */ NULL((void*)0),
1482 /* tc_free */ NULL((void*)0),
1483 /* tc_find */ NULL((void*)0),
1484 /* tc_snprintf */ t_ptr_snprintf,
1485 /* tc_filter */ NULL((void*)0),
1486 /* tc_ref_set */ t_ptr_ref_set,
1487 /* tc_scan */ NULL((void*)0),
1488 }};
1489
1490/* ====================================================================== */
1491/* socket tag - pass socket */
1492
1493#include <sofia-sip/su.h>
1494
1495int t_socket_snprintf(tagi_t const *t, char b[], size_t size)
1496{
1497 /* socket can be int or DWORD (or QWORD on win64?) */
1498 return snprintf(b, size, LLI"%lli", (longlonglong long)t->t_value);
1499}
1500
1501int t_socket_ref_set(tag_type_t tt, void *ref, tagi_t const value[])
1502{
1503 *(su_socket_t *)ref = (su_socket_t)value->t_value;
1504
1505 return 1;
1506}
1507
1508tag_class_t socket_tag_class[1] =
1509 {{
1510 sizeof(socket_tag_class),
1511 /* tc_next */ NULL((void*)0),
1512 /* tc_len */ NULL((void*)0),
1513 /* tc_move */ NULL((void*)0),
1514 /* tc_xtra */ NULL((void*)0),
1515 /* tc_dup */ NULL((void*)0),
1516 /* tc_free */ NULL((void*)0),
1517 /* tc_find */ NULL((void*)0),
1518 /* tc_snprintf */ t_socket_snprintf,
1519 /* tc_filter */ NULL((void*)0),
1520 /* tc_ref_set */ t_socket_ref_set,
1521 /* tc_scan */ NULL((void*)0),
1522 }};
1523
1524/* ====================================================================== */
1525/* str tag - pass string value */
1526
1527int t_str_snprintf(tagi_t const *t, char b[], size_t size)
1528{
1529 if (t->t_value)
1530 return snprintf(b, size, "\"%s\"", (char const *)t->t_value);
1531 else
1532 return snprintf(b, size, "<null>");
1533}
1534
1535int t_str_scan(tag_type_t tt, su_home_t *home,
1536 char const *s,
1537 tag_value_t *return_value)
1538{
1539 int retval;
1540
1541 s = su_strdup(home, s);
1542
1543 if (s)
1544 *return_value = (tag_value_t)s, retval = 1;
1545 else
1546 *return_value = (tag_value_t)NULL((void*)0), retval = -1;
1547
1548 return retval;
1549}
1550
1551tagi_t *t_str_dup(tagi_t *dst, tagi_t const *src, void **bb)
1552{
1553 dst->t_tag = src->t_tag;
1554 if (src->t_value) {
1555 char const *s = (char const *)src->t_value;
1556 size_t len = strlen(s) + 1;
1557 dst->t_value = (tag_value_t)strcpy(*bb, s);
1558 *bb = (char *)*bb + len;
1559 }
1560 else
1561 dst->t_value = (tag_value_t)0;
1562
1563 return dst + 1;
1564}
1565
1566size_t t_str_xtra(tagi_t const *t, size_t offset)
1567{
1568 return t->t_value ? strlen((char *)t->t_value) + 1 : 0;
1569}
1570
1571tag_class_t str_tag_class[1] =
1572 {{
1573 sizeof(str_tag_class),
1574 /* tc_next */ NULL((void*)0),
1575 /* tc_len */ NULL((void*)0),
1576 /* tc_move */ NULL((void*)0),
1577 /* tc_xtra */ t_str_xtra,
1578 /* tc_dup */ t_str_dup,
1579 /* tc_free */ NULL((void*)0),
1580 /* tc_find */ NULL((void*)0),
1581 /* tc_snprintf */ t_str_snprintf,
1582 /* tc_filter */ NULL((void*)0),
1583 /* tc_ref_set */ t_ptr_ref_set,
1584 /* tc_scan */ t_str_scan,
1585 }};
1586
1587/* ====================================================================== */
1588/* cstr tag - pass constant string value (no need to dup) */
1589
1590/** Tag class for constant strings */
1591tag_class_t cstr_tag_class[1] =
1592 {{
1593 sizeof(cstr_tag_class),
1594 /* tc_next */ NULL((void*)0),
1595 /* tc_len */ NULL((void*)0),
1596 /* tc_move */ NULL((void*)0),
1597 /* tc_xtra */ NULL((void*)0),
1598 /* tc_dup */ NULL((void*)0),
1599 /* tc_free */ NULL((void*)0),
1600 /* tc_find */ NULL((void*)0),
1601 /* tc_snprintf */ t_str_snprintf,
1602 /* tc_filter */ NULL((void*)0),
1603 /* tc_ref_set */ t_ptr_ref_set,
1604 /* tc_scan */ t_str_scan,
1605 }};
1606
1607/* ====================================================================== */
1608/* ref tag - pass reference */
1609
1610tag_class_t ref_tag_class[1] =
1611 {{
1612 sizeof(ref_tag_class),
1613 /* tc_next */ NULL((void*)0),
1614 /* tc_len */ NULL((void*)0),
1615 /* tc_move */ NULL((void*)0),
1616 /* tc_xtra */ NULL((void*)0),
1617 /* tc_dup */ NULL((void*)0),
1618 /* tc_free */ NULL((void*)0),
1619 /* tc_find */ NULL((void*)0),
1620 /* tc_snprintf */ t_ptr_snprintf,
1621 /* tc_filter */ NULL((void*)0),
1622 /* tc_ref_set */ t_ptr_ref_set,
1623 /* tc_scan */ NULL((void*)0),
1624 }};
1625
1626