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

📄 su_taglist.c

📁 this is simple sip stack.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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>#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>/**@defgroup su_tag Tag Item Lists * * Object-oriented tag routines for Sofia utility library. * * The <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 <su_tag_class.h>. See nta_tag.c or * su_tag_test.c for an example. * */#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);  size_t n, m;    n = snprintf(b, size, "%s::%s: ",                tt->tt_ns ? tt->tt_ns : "",	       tt->tt_name ? tt->tt_name : "null");  if (n > (unsigned)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);  assert(m != (size_t)-1);  if (m == 0 && 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((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. */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. *  * The function tl_dup() deep copies the tag list @a src to the buffer @a * dst.  Memory areas associated with @a src are copied to buffer at @a **bb. * * 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 dst pointer to the destination buffer * @param src tag list to be duplicated * @param bb  pointer to pointer to buffer * * @return * The function tl_dup() returns a pointer to the @a dst list after last * duplicated taglist element.   * * The function tl_dup updates the pointer at @a *bb 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;}	       /** Allocate and duplicate a tag list. */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);  return newlst;}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 a tag from given list. */tagi_t const *tl_find(tagi_t const lst[], tag_type_t tt){  if (tt)    return t_find(tt, lst);  return NULL;}static 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->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.  * * The function tl_tgets() copies values of argument tag list into 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;}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;}/**Filter a tag list.  *  * The function tl_afilter() will build a tag list containing tags specified * in @a filter and extracted from @a src.  It will allocate the memory used by * tag list via the specified memory @a home, which may be also @c NULL. */tagi_t *tl_afilter(su_home_t *home, tagi_t const filter[], tagi_t const src[]){  tagi_t *dst, *d, *t_end = NULL;  void *b, *end = NULL;  size_t len;  /* Calculate length of the result */  t_end = tl_filter(NULL, filter, src, &end);  len = ((char *)t_end - (char *)NULL) + ((char *)end - (char*)NULL);  if (len == 0)    return NULL;  /* Allocate the result */  if (!(dst = su_alloc(home, len)))    return NULL;  /* Build the result */  b = (dst + (t_end - (tagi_t *)NULL));  d = tl_filter(dst, filter, src, (void **)&b);  /* Ensure that everything is consistent */  assert(d == dst + (t_end - (tagi_t *)NULL));  assert(b == (char *)dst + len);  return dst;}tagi_t *tl_tfilter(su_home_t *home, tagi_t const src[], 		   tag_type_t tag, tag_value_t value, ...){  tagi_t *tl;  ta_list ta;  ta_start(ta, tag, value);  tl = tl_afilter(home, ta_args(ta), src);  ta_end(ta);  return tl;}/** Create a filtered tag list. */tagi_t *tl_filtered_tlist(su_home_t *home, tagi_t const filter[], 			  tag_type_t tag, tag_value_t value, ...){  tagi_t *tl;  ta_list ta;  ta_start(ta, tag, value);  tl = tl_afilter(home, filter, ta_args(ta));  ta_end(ta);  return tl;}/** Remove listed tags from the list @a lst. */int tl_tremove(tagi_t lst[], tag_type_t tag, tag_value_t value, ...){  tagi_t *l, *l_next;  int retval = 0;  ta_list ta;  ta_start(ta, tag, value);  for (l = lst; l; l = l_next) {    if ((l_next = (tagi_t *)t_next(l))) {      if (tl_find(ta_args(ta), l->t_tag))	l->t_tag = tag_skip;      else	retval++;    }  }  ta_end(ta);  return retval;}/** Calculate length of a tag list with a @c va_list. */size_t tl_vlen(va_list ap){  size_t len = 0;  tagi_t tagi[2] = {{ NULL }};  do {    tagi->t_tag = va_arg(ap, tag_type_t );    tagi->t_value = va_arg(ap, tag_value_t);    len += sizeof(tagi_t);  } while (!t_end(tagi));  return len;}/** Convert va_list to tag list */tagi_t *tl_vlist(va_list ap){  tagi_t *t, *rv;  va_list aq;  va_copy(aq, ap);  rv = malloc(tl_vlen(aq));  va_end(aq);  for (t = rv; t; t++) {    t->t_tag = va_arg(ap, tag_type_t);    t->t_value = va_arg(ap, tag_value_t);    if (t_end(t))      break;  }  return rv;}tagi_t *tl_vlist2(tag_type_t tag, tag_value_t value, va_list ap){  tagi_t *t, *rv;  tagi_t tagi[1];  int size;  tagi->t_tag = tag, tagi->t_value = value;  if (!t_end(tagi)) {    va_list aq;    va_copy(aq, ap);    size = sizeof(tagi) + tl_vlen(aq);    va_end(aq);  }  else    size = sizeof(tagi);  t = rv = malloc(size);  for (;t;) {    *t++ = *tagi;    if (t_end(tagi))       break;    tagi->t_tag = va_arg(ap, tag_type_t);    tagi->t_value = va_arg(ap, tag_value_t);  }    assert((char *)rv + size == (char *)t);  return rv;}/** Make a tag list until TAG_NEXT() or TAG_END() */tagi_t *tl_list(tag_type_t tag, tag_value_t value, ...){  va_list ap;    tagi_t *t;  va_start(ap, value);  t = tl_vlist2(tag, value, ap);  va_end(ap);  return t;}/** Calculate length of a linear tag list. */size_t tl_vllen(tag_type_t tag, tag_value_t value, va_list ap){  size_t len = sizeof(tagi_t);  tagi_t const *next;  tagi_t tagi[3];  tagi[0].t_tag = tag;  tagi[0].t_value = value;  tagi[1].t_tag = tag_any;  tagi[1].t_value = 0;  for (;;) {    next = tl_next(tagi);    if (next != tagi + 1)      break;        if (tagi->t_tag != tag_skip)      len += sizeof(tagi_t);    tagi->t_tag = va_arg(ap, tag_type_t);    tagi->t_value = va_arg(ap, tag_value_t);  }  for (; next; next = tl_next(next))    len += sizeof(tagi_t);  return len;

⌨️ 快捷键说明

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