su_tagarg.h 6.32 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
1 2 3 4 5 6 7
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2005 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
8
 * This library is free software; you can redistribute it and/or
Pekka Pessi's avatar
Pekka Pessi committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 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
 *
 */

Pekka Pessi's avatar
Pekka Pessi committed
25 26
#ifndef SU_TAGARG_H
/** Defined when <sofia-sip/su_tagarg.h> has been included. */
Pekka Pessi's avatar
Pekka Pessi committed
27
#define SU_TAGARG_H
Pekka Pessi's avatar
Pekka Pessi committed
28

29
/**@SU_TAG
Pekka Pessi's avatar
Pekka Pessi committed
30
 * @file sofia-sip/su_tagarg.h  Tagged argument lists
Pekka Pessi's avatar
Pekka Pessi committed
31 32
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
33
 *
Pekka Pessi's avatar
Pekka Pessi committed
34 35 36 37
 * @date Created: Tue Feb 20 19:48:18 2001 ppessi
 */

#ifndef SU_TAG_H
38
#include <sofia-sip/su_tag.h>
Pekka Pessi's avatar
Pekka Pessi committed
39 40
#endif

41 42
SOFIA_BEGIN_DECLS

Pekka Pessi's avatar
Pekka Pessi committed
43 44 45
/**@page tagarg Tagarg Functions
 *
 * A @em tagarg function may be called with a varying number of tagged
Pekka Pessi's avatar
Pekka Pessi committed
46
 * arguments.  The include file <sofia-sip/su_tagarg.h> declares a type ta_list and
Pekka Pessi's avatar
Pekka Pessi committed
47 48 49 50 51 52 53 54 55 56
 * defines four macros (ta_start(), ta_args(), ta_tags() and ta_end()) for
 * accessing the argument list.
 *
 * An example of prototype of a a @em tagarg function is as follows:
 * @code
 * int tag_print(FILE *f, tag_type_t tag, tag_value_t value, ...);
 * @endcode
 *
 * Such a function could be called as follows:
 * @code
57 58
 *   tag_print(stdout,
 *             TAG_STRING("a is"), TAG_INT(a),
Pekka Pessi's avatar
Pekka Pessi committed
59 60 61 62 63
 *             TAG_STRING("b is"), URLTAG_URL(b),
 *             TAG_IF(c, TAG_STRING("and c is true")),
 *             TAG_END());
 * @endcode
 *
64
 * @note
Pekka Pessi's avatar
Pekka Pessi committed
65 66 67 68
 * The tagged argument list @b must be terminated by a TAG_END(),
 * TAG_NULL() or TAG_NEXT().
 */

Pekka Pessi's avatar
Pekka Pessi committed
69
/**Structure for accessing tagged argument lists.
Pekka Pessi's avatar
Pekka Pessi committed
70
 *
Pekka Pessi's avatar
Pekka Pessi committed
71 72 73
 * The function called with tagged arguments must declare an object of type
 * ta_list which is used by the macros ta_start(), ta_args(), ta_tags(), and
 * ta_end().
Pekka Pessi's avatar
Pekka Pessi committed
74 75 76 77 78 79 80 81 82 83 84
 *
 * If a tagged list is not finished with TAG_END(), TAG_NULL(), or
 * TAG_NEXT() items, random errors may occur.
 *
 * @hideinitializer
 */
typedef struct {
  tagi_t  tl[2];
  va_list ap;
} ta_list;

85 86 87 88 89 90 91 92
#if defined(va_copy)
#define su_va_copy(dst, src) va_copy((dst), (src))
#elif defined(__va_copy)
#define su_va_copy(dst, src) __va_copy((dst), (src))
#else
#define su_va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
#endif

Pekka Pessi's avatar
Pekka Pessi committed
93 94 95 96 97 98 99 100 101 102 103 104 105
/**Macro initializing a ta_list object.
 *
 * The ta_start() macro initializes @a ta for subsequent use by ta_args(),
 * ta_tags() and ta_end(), and must be called first.
 *
 * The parameters @a t and @a v are the names of the @c tag and @c value in
 * the first tag list item before the variable argument list (...).
 *
 * The ta_start() macro returns no value.
 *
 * @hideinitializer
 */
#if SU_HAVE_TAGSTACK
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
/* All arguments are saved into stack (left-to-right) */
#define ta_start(ta, t, v)						\
   do {									\
    tag_type_t ta_start__tag = (t); tag_value_t ta_start__value = (v);	\
    va_start((ta).ap, (v));						\
    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 == NULL)		\
	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 != NULL &&					\
	ta_start__tag != tag_null &&					\
	ta_start__tag != tag_next) {					\
      (ta).tl[1].t_tag = tag_next;					\
      (ta).tl[1].t_value = (tag_value_t)(&(v) + 1);			\
    } else {								\
129
      (ta).tl[1].t_tag = 0; (ta).tl[1].t_value = (tag_value_t)0;	\
130 131
    }									\
  } while(0)
Pekka Pessi's avatar
Pekka Pessi committed
132
#else
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
/* Tagged arguments are in registers - copy all of them. */
#define ta_start(ta, t, v)						\
   do {									\
    tag_type_t ta_start__tag = (t); tag_value_t ta_start__value = (v);	\
    va_start((ta).ap, (v));						\
    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 == NULL)		\
	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 != NULL &&					\
	ta_start__tag != tag_null &&					\
	ta_start__tag != tag_next) {					\
153
      va_list ta_start__ap;						\
154
      su_va_copy(ta_start__ap, (ta).ap);				\
155
      (ta).tl[1].t_tag = tag_next;					\
156 157
      (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap);		\
      va_end(ta_start__ap);						\
158 159 160 161
    } else {								\
      (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0;	\
    }									\
  } while(0)
Pekka Pessi's avatar
Pekka Pessi committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
#endif

/**Macro accessing tagged argument list.
 *
 * The ta_args() returns a pointer to tag list containing the arguments.
 *
 * @hideinitializer
 */
#define ta_args(ta) (ta).tl

/**Macro passing tagged argument list as an argument to another function.
 *
 * The ta_tags() macro expands to an tag list that can be given as arguments
 * to a function taking an variable tag item list as an argument.
 *
 * @hideinitializer
 */
#define ta_tags(ta) \
  (ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).tl[1].t_value

/**Handle return from function with tagged argument list
183
 *
Pekka Pessi's avatar
Pekka Pessi committed
184 185 186 187 188 189 190 191 192 193
 * The ta_end() macro handles return from function whose tagged argument
 * list was initialized by ta_start().
 *
 * The ta_end() macro returns no value.
 *
 * @hideinitializer
 */
#if SU_HAVE_TAGSTACK
#define ta_end(ta) (va_end((ta).ap), (ta).tl->t_tag = NULL, 0)
#else
194 195
#define ta_end(ta)					   \
  ((((ta).tl[1].t_value) ?				   \
Pekka Pessi's avatar
Pekka Pessi committed
196 197 198 199
    (tl_vfree((tagi_t *)((ta).tl[1].t_value))) : (void)0), \
   (ta).tl[1].t_value = 0, va_end((ta).ap), 0)
#endif

200 201
SOFIA_END_DECLS

Pekka Pessi's avatar
Pekka Pessi committed
202
#endif /* !defined(SU_TAGARG_H) */