⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 su_taglist.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@SU_TAG *  * @CFILE su_taglist.c   * * Implementation of tag items and lists. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Tue Feb 20 20:03:38 2001 ppessi */#include "config.h"#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <stdio.h>#include <limits.h>#if defined(va_copy)/* Xyzzy */#elif defined(__va_copy)#define va_copy(dst, src) __va_copy((dst), (src))#else#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))#endif#include <assert.h>#include <sofia-sip/su_config.h>#include <sofia-sip/su_tag.h>#include <sofia-sip/su_tag_class.h>#include <sofia-sip/su_tag_inline.h>#include <sofia-sip/su_tagarg.h>#ifndef HAVE_STRTOULLunsigned longlong strtoull(const char *, char **, int);#endif/**@defgroup su_tag Tag Item Lists * * Object-oriented tag routines for Sofia utility library. * * The <sofia-sip/su_tag.h> defines a interface to object-oriented tag list routines.  * A tag list is a linear list (array) of tag items, tagi_t structures, * terminated by a TAG_END() item. Each tag item has a label, tag, (@c * t_tag) and a value (@c t_value). The tag is a pointer (tag_type_t) to a * structure defining how the value should be interpreted, in other words, * the name and the type of the value. The value or pointer to the actual * value is stored as opaque data (tag_value_t). The tag item structure is * defined as follows: * * @code * typedef struct { *   tag_type_t   t_tag; *   tag_value_t  t_value; * } tagi_t; * @endcode * * The tag lists are central concept in the Sofia APIs. The tags lists can * be used to a list of named arguments to a @ref tagarg "@em tagarg" * function, to store variable amount of data in a memory area, and pass * data between processes and threads. *  * The tagged argument lists can be used like named arguments in * higher-level languages. The argument list consists of tag-value pairs; * tags specify the name and type of the value. All the tag items are not * necessarily interpreted by the called function, but it can pass the list * to other functions. This feature is used also by the Sofia APIs, the * lower-layer settings and options are frequently passed through the * upper-layer API in the tag lists. *  * The tagged argument lists are constructed using special macros that * expand to two function arguments, tag and value. Each tag item macro * checks its arguments type so the tagged argument lists are typesafe if * the list is correctly constructed. *  * Each function documents the tags it accepts and also the tags it may pass * to the lower layers (at least in theory). *  * @par Special Tags * * There are a new special tags that are used to control and modify the tag * list processing itself. These special tags are as follows: * - TAG_NULL() or TAG_END() - indicates the end of tag list * - TAG_SKIP() - indicates an empty (overwritten) tag item  * - TAG_NEXT() - contains a pointer to the next tag list. * * The tag type structures are declared as tag_typedef_t. They can be * defined by the macros found in <sofia-sip/su_tag_class.h>. See nta_tag.c or * su_tag_test.c for an example. * *//**@class tag_class_s sofia-sip/su_tag_class.h <sofia-sip/su_tag_class.h> * * @brief Virtual function table for @ref su_tag "tags". * * The struct tag_class_s contains virtual function table for tags, * specifying non-default behaviour of different tags. It provides functions * for copying, matching, printing and converting the tagged values. */#ifdef longlongtypedef longlong unsigned llu;#elsetypedef long unsigned llu;#endif/** Print a tag. */int t_snprintf(tagi_t const *t, char b[], size_t size){  tag_type_t tt = TAG_TYPE_OF(t);  int n, m;    n = snprintf(b, size, "%s::%s: ",                tt->tt_ns ? tt->tt_ns : "",	       tt->tt_name ? tt->tt_name : "null");  if (n < 0)    return n;  if ((size_t)n > size)    size = n;  if (tt->tt_snprintf)    m = tt->tt_snprintf(t, b + n, size - n);  else    m = snprintf(b + n, size - n, "%llx", (llu)t->t_value);  if (m < 0)    return m;  if (m == 0 && 0 < n && (size_t)n < size)    b[--n] = '\0';  return n + m;}/** Get next tag item from list. */tagi_t *tl_next(tagi_t const *t){  tag_type_t tt;  t = t_next(t);  for (tt = TAG_TYPE_OF(t); t && tt->tt_next; tt = TAG_TYPE_OF(t)) {    t = tt->tt_next(t);  }  return (tagi_t *)t;}/**Move a tag list. *  * The function tl_tmove() moves the tag list arguments to @a dst.  The @a * dst must have big enough for all arguments. *  * @param dst   pointer to the destination buffer * @param size  sizeof @a dst * @param t_tag,t_value,... tag list * * @return * The function tl_tmove() returns number of tag list items initialized. */size_t tl_tmove(tagi_t *dst, size_t size, 		tag_type_t t_tag, tag_value_t t_value, ...){  size_t n = 0, N = size / sizeof(tagi_t);  tagi_t tagi[1];  va_list ap;    va_start(ap, t_value);   tagi->t_tag = t_tag, tagi->t_value = t_value;  for (;;) {    assert((size_t)((char *)&dst[n] - (char *)dst) < size);    if (n < N)      dst[n] = *tagi;    n++;    if (t_end(tagi))       break;    tagi->t_tag = va_arg(ap, tag_type_t);    tagi->t_value = va_arg(ap, tag_value_t);  }  va_end(ap);  return n;}/**Move a tag list. *  * The function tl_move() copies the tag list @a src to the buffer @a * dst. The size of the @a dst list must be at least @c tl_len(src) bytes. *  * @param dst pointer to the destination buffer * @param src tag list to be moved * * @return * The function tl_move() returns a pointer to the @a dst list after last * moved element.   */tagi_t *tl_move(tagi_t *dst, tagi_t const src[]){  do {    dst = t_move(dst, src);  }  while ((src = t_next(src)));  return dst;}/** Calculate effective length of a tag list as bytes. */size_t tl_len(tagi_t const lst[]){  size_t len = 0;    do {    len += t_len(lst);  }   while ((lst = t_next(lst)));  return len;}/** Calculate the size of extra memory areas associated with tag list. */size_t tl_xtra(tagi_t const lst[], size_t offset){  size_t xtra = offset;  for (; lst; lst = t_next(lst))    xtra += t_xtra(lst, xtra);  return xtra - offset;}/** Duplicate a tag list. * * Deep copy the tag list @a src to the buffer @a dst. Memory areas * associated with @a src are copied to buffer at @a **bb. * * This is a rather low-level function. See tl_adup() for a more convenient * functionality. * * The size of the @a dst buffer must be at least @c tl_len(src) bytes.  The * size of buffer @a **bb must be at least @c tl_dup_xtra(src) bytes.  *  * @param[out] dst pointer to the destination buffer * @param[in] src tag list to be duplicated * @param[in,out] bb  pointer to pointer to buffer * * @return * A pointer to the @a dst list after last * duplicated taglist element.   * * The pointer at @a *bb is updated to the byte after last duplicated memory * area. */tagi_t *tl_dup(tagi_t dst[], tagi_t const src[], void **bb){  do {    dst = t_dup(dst, src, bb);  } while ((src = t_next(src)));  return dst;}	       /** Free a tag list. * * The function tl_free() frees resources associated with a tag list. * In other words, it calls t_free on each tag item on the list.  * */void tl_free(tagi_t list[]){  while (list)    list = t_free(list);}/** Allocate and duplicate a tag list using memory home. */tagi_t *tl_adup(su_home_t *home, tagi_t const lst[]){  size_t len = tl_len(lst);  size_t xtra = tl_xtra(lst, 0);  void *b = su_alloc(home, len + xtra);  tagi_t *d, *newlst = b;  void *end = (char *)b + len + xtra;  tagi_t *tend = (tagi_t*)((char *)b + len);  b = (char *)b + len;  d = tl_dup(newlst, lst, &b);  assert(b == end); assert(tend == d); (void)end; (void)tend;  return newlst;}/** Allocate and duplicate tagged arguments as a tag list using memory home. */tagi_t *tl_tlist(su_home_t *home, tag_type_t tag, tag_value_t value, ...){  tagi_t *tl;  ta_list ta;  ta_start(ta, tag, value);  tl = tl_adup(home, ta_args(ta));  ta_end(ta);  return tl;}/** Find first tag item with type @a tt from list. */tagi_t *tl_find(tagi_t const lst[], tag_type_t tt){  return (tagi_t *)t_find(tt, lst);}/** Find last tag item with type @a tt from list. */tagi_t *tl_find_last(tagi_t const lst[], tag_type_t tt){  tagi_t const *last, *next;    for (next = last = t_find(tt, lst); next; next = t_find(tt, t_next(last)))    last = next;  return (tagi_t *)last;}su_inlineint t_ref_set(tag_type_t tt, void *ref, tagi_t const value[]){  if (value == NULL)    return 0;  if (tt->tt_class->tc_ref_set)    return tt->tt_class->tc_ref_set(tt, ref, value);  *(tag_value_t *)ref = value->t_value;  return 1;}static int tl_get(tag_type_t tt, void *p, tagi_t const lst[]){  tagi_t const *t, *latest = NULL;    assert(tt);    if (tt == NULL || p == NULL)    return 0;  if (tt->tt_class == ref_tag_class)    tt = (tag_type_t)tt->tt_magic;  for (t = t_find(tt, lst); t; t = t_find(tt, t_next(t)))    latest = t;  return t_ref_set(tt, p, latest);}/** Find tags from given list. */int tl_gets(tagi_t const lst[], tag_type_t tag, tag_value_t value, ...){  int n = 0;  tagi_t *t;  ta_list ta;  ta_start(ta, tag, value);  for (t = ta_args(ta); t; t = (tagi_t *)t_next(t)) {    tag_type_t tt = t->t_tag;    if (!tt)      continue;    if (tt->tt_class == ref_tag_class) {      assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set);      n += tl_get(tt, (void *)t->t_value, lst);    }#if !defined(NDEBUG)    else if (tt->tt_class && tt->tt_class->tc_ref_set) {      fprintf(stderr, "WARNING: tag %s::%s directly used by tl_gets()\n",	      tt->tt_ns, tt->tt_name);      assert(tt->tt_class == ref_tag_class);    }#endif  }   ta_end(ta);  return n;}/** Find tags from given list.  * * Copies values of argument tag list into the reference tags in the tag * list @a lst. * * @sa tl_gets() */int tl_tgets(tagi_t lst[], tag_type_t tag, tag_value_t value, ...){  int n = 0;  tagi_t *t;  ta_list ta;  ta_start(ta, tag, value);  for (t = lst; t; t = (tagi_t *)t_next(t)) {    tag_type_t tt = t->t_tag;    if (!tt)      continue;    if (tt->tt_class == ref_tag_class) {      assert(((tag_type_t)tt->tt_magic)->tt_class->tc_ref_set);      n += tl_get(tt, (void *)t->t_value, ta_args(ta));    }#if !defined(NDEBUG)    else if (tt->tt_class->tc_ref_set) {      fprintf(stderr, "WARNING: tag %s::%s used in tl_tgets(lst)\n",	      tt->tt_ns, tt->tt_name);      assert(tt->tt_class == ref_tag_class);    }#endif  }   ta_end(ta);  return n;}/** Filter an element in tag list */tagi_t *t_filter(tagi_t *dst, 		 tagi_t const filter[], 		 tagi_t const *src, 		 void **bb){  tag_type_t tt = TAG_TYPE_OF(src);  tagi_t const *f;  if (dst) {    for (f = filter; f; f = t_next(f)) {      if (TAG_TYPE_OF(f)->tt_filter)	dst = TAG_TYPE_OF(f)->tt_filter(dst, f, src, bb);      else if (f->t_tag == tt)	dst = t_dup(dst, src, bb);     }  }  else {    size_t d = 0;    for (f = filter; f; f = t_next(f)) {      if (TAG_TYPE_OF(f)->tt_filter)	d += (size_t)TAG_TYPE_OF(f)->tt_filter(NULL, f, src, bb);      else if (tt == f->t_tag) {	d += t_len(src);	*bb = (char *)*bb + t_xtra(src, (size_t)*bb);      }    }    dst = (tagi_t *)d;  }  return dst;}/** Make filtered copy of a tag list @a src with @a filter to @a dst. * * Each tag in @a src is checked against tags in list @a filter. If the tag * is in the @a filter list, or there is a special filter tag in the list * which matches with the tag in @a src, the tag is duplicated to @a dst using  * memory buffer in @a b. * * When @a dst is NULL, this function calculates the size of the filtered list. * * @sa tl_afilter(), tl_tfilter(), tl_filtered_tlist(), * TAG_FILTER(), TAG_ANY(), #ns_tag_class */tagi_t *tl_filter(tagi_t dst[], 		  tagi_t const filter[], 		  tagi_t const src[], 		  void **b){  tagi_t const *s;  tagi_t *d;  if (dst) {    for (s = src, d = dst; s; s = t_next(s))      d = t_filter(d, filter, s, b);  }  else {    size_t rv = 0;    for (s = src, d = dst; s; s = t_next(s)) {      d = t_filter(NULL, filter, s, b);      rv += (char *)d - (char *)NULL;    }    d = (tagi_t *)rv;  }  return d;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -