Commit 415a5486 authored by Pekka Pessi's avatar Pekka Pessi

Added hc_update member to msg_hclass_t.

The hc_update is used to update shortcuts to well-known parameters.
Updated manipulation functions for header parameters to use hc_update.
Added updating functions for SIP headers.

darcs-hash:20051222130613-65a35-cc639bb9b1e29eaea3fc2c180bfba0520e55a20e.gz
parent 66dc420c
......@@ -66,21 +66,23 @@
#define HTTP_HCLASS_TEST(x) ((x) && (x)->hc_tag == HTTP_PROTOCOL_TAG)
#define HTTP_HDR_TEST(x) ((x)->sh_class && HTTP_HCLASS_TEST((x)->sh_class))
#define http_no_update NULL
/** Define a header class for a HTTP header. */
#define HTTP_HEADER_CLASS(c, l, params, kind, dup) \
MSG_HEADER_CLASS(http_, c, l, "", params, kind, http_ ## dup)
MSG_HEADER_CLASS(http_, c, l, "", params, kind, http_ ## dup, http_no)
/** This is used by headers with no extra data in copy */
#define HTTP_HEADER_CLASS_G(c, l, kind) \
MSG_HEADER_CLASS(http_, c, l, "", g_common, kind, msg_generic)
MSG_HEADER_CLASS(http_, c, l, "", g_common, kind, msg_generic, http_no)
/** Define a header class for a msg_list_t kind of header */
#define HTTP_HEADER_CLASS_LIST(c, l, kind) \
MSG_HEADER_CLASS(http_, c, l, "", k_items, kind, msg_list)
MSG_HEADER_CLASS(http_, c, l, "", k_items, kind, msg_list, http_no)
/** Define a authorization header class */
#define HTTP_HEADER_CLASS_AUTH(c, l, kind) \
MSG_HEADER_CLASS(http_, c, l, "", au_params, kind, msg_auth)
MSG_HEADER_CLASS(http_, c, l, "", au_params, kind, msg_auth, http_no)
/* ---------------------------------------------------------------------------
......
......@@ -52,6 +52,8 @@
#include <msg_parser.h>
#include <msg_header.h>
#define msg_generic_update NULL
/* ====================================================================== */
/**@ingroup msg_headers
......@@ -75,7 +77,8 @@ char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, int xtra);
msg_hclass_t msg_error_class[] =
MSG_HEADER_CLASS(msg_, error, "", "", er_common, append, msg_error);
MSG_HEADER_CLASS(msg_, error, "", "", er_common, append,
msg_error, msg_generic);
int msg_error_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -121,7 +124,8 @@ char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
*/
msg_hclass_t msg_unknown_class[] =
MSG_HEADER_CLASS(msg_, unknown, "", "", un_common, append, msg_unknown);
MSG_HEADER_CLASS(msg_, unknown, "", "", un_common, append,
msg_unknown, msg_generic);
int msg_unknown_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -200,7 +204,8 @@ char *msg_unknown_dup_one(msg_header_t *dst, msg_header_t const *src,
*/
msg_hclass_t msg_payload_class[1] =
MSG_HEADER_CLASS(msg_, payload, NULL, "", pl_common, append, msg_payload);
MSG_HEADER_CLASS(msg_, payload, NULL, "", pl_common, append,
msg_payload, msg_generic);
/** Create a MIME payload */
msg_payload_t *msg_payload_create(su_home_t *home, void const *data, int len)
......@@ -304,7 +309,8 @@ int msg_payload_length(msg_payload_t const *pl)
*/
msg_hclass_t msg_separator_class[] =
MSG_HEADER_CLASS(msg_, separator, NULL, "", sep_common, single, msg_default);
MSG_HEADER_CLASS(msg_, separator, NULL, "", sep_common, single,
msg_default, msg_generic);
/** Calculate length of line ending (0, 1 or 2) */
#define CRLF_TEST(s) ((s[0]) == '\r' ? ((s[1]) == '\n') + 1 : (s[0])=='\n')
......
......@@ -236,6 +236,9 @@ msg_header_t *msg_header_dup_one(su_home_t *home,
return NULL;
}
if (hc->hc_update)
msg_header_update_params(h->sh_common, 1);
assert(end == (char *)h + size + xtra);
return h;
......@@ -280,6 +283,9 @@ msg_header_t *msg_header_dup_as(su_home_t *home, msg_hclass_t *hc,
if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
break; /* error */
if (hc->hc_update)
msg_header_update_params(h->sh_common, 1);
assert(end == (char *)h + size + xtra);
*prev = h;
......
This diff is collapsed.
......@@ -81,7 +81,7 @@ struct msg_accept_s
char const *ac_type; /**< Pointer to type/subtype */
char const *ac_subtype; /**< Points after first slash in type */
msg_param_t const *ac_params; /**< List of parameters */
msg_param_t ac_q; /**< Value of q parameter */
char const *ac_q; /**< Value of q parameter */
};
/**@ingroup msg_accept_encoding
......@@ -106,7 +106,7 @@ struct msg_content_disposition_s
msg_error_t *cd_next; /**< Link to next (dummy) */
char const *cd_type; /**< Disposition type */
msg_param_t const *cd_params; /**< List of parameters */
msg_param_t cd_handling; /**< Value of @b handling parameter */
char const *cd_handling; /**< Value of @b handling parameter */
unsigned cd_required:1; /**< True if handling=required */
unsigned cd_optional:1; /**< True if handling=optional */
unsigned :0; /* pad */
......
......@@ -310,4 +310,9 @@ su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt,
/** @} */
/* Internal prototypes */
MSG_DLL msg_update_f msg_accept_update;
MSG_DLL msg_update_f msg_accept_any_update;
MSG_DLL msg_update_f msg_content_disposition_update;
#endif /** !defined(MSG_MIME_PROTOS_H) */
......@@ -60,8 +60,11 @@
#define msg_status_class NULL
#define mp_status mp_common
#define MSG_MULTIPART_HCLASS \
MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, msg_multipart)
#define msg_multipart_update NULL
#define MSG_MULTIPART_HCLASS \
MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, \
msg_multipart, msg_multipart)
......@@ -2332,6 +2332,9 @@ int msg_header_add_dup(msg_t *msg,
if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
return -1; /* error */
if (hc->hc_update)
msg_header_update_params(h->sh_common, 0);
assert(end == (char *)h + size + xtra);
if (msg_header_add(msg, pub, hh, h) < 0)
......
......@@ -62,28 +62,30 @@
#if HAVE_STRUCT_KEYWORDS
/** Define a header class */
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup) \
{{ \
hc_hash: pr##c##_hash, \
hc_parse: pr##c##_d, \
hc_print: pr##c##_e, \
hc_dxtra: dup##_dup_xtra, \
hc_dup_one: dup##_dup_one, \
hc_name: l, \
hc_len: sizeof(l) - 1, \
hc_short: s, \
hc_size: MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)), \
hc_params: offsetof(pr##c##_t, params), \
hc_kind: msg_kind_##kind, \
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
hc_hash: pr##c##_hash, \
hc_parse: pr##c##_d, \
hc_print: pr##c##_e, \
hc_dxtra: dup##_dup_xtra, \
hc_dup_one: dup##_dup_one, \
hc_update: upd##_update, \
hc_name: l, \
hc_len: sizeof(l) - 1, \
hc_short: s, \
hc_size: MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)), \
hc_params: offsetof(pr##c##_t, params), \
hc_kind: msg_kind_##kind, \
}}
#else
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup) \
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
pr##c##_hash, \
pr##c##_d, \
pr##c##_e, \
dup##_dup_xtra, \
dup##_dup_one, \
upd##_update, \
l, \
sizeof(l) - 1, \
s, \
......@@ -231,6 +233,8 @@ int msg_any_list_d(su_home_t *home, char **ss,
/* Parameter lists */
int msg_header_update_params(msg_common_t *h, int clear);
/** Match a parameter with any value. @HI */
#define MSG_PARAM_MATCH(v, s, name) \
(strncasecmp(s, name "=", sizeof(name)) == 0 ? (v = s + sizeof(name)) : NULL)
......
......@@ -786,41 +786,161 @@ char const *msg_header_find_param(msg_common_t const *h, char const *name)
return NULL;
}
/** Add a parameter to a header.
*
* A header parameter @a param is a string of format name "=" value or just
* name. The caller of msg_header_add_param() should have allocated it from
* memory home associated with header @a h.
*
* @retval 0 if parameter was added
* @retval -1 upon an error
*/
int msg_header_add_param(su_home_t *home, msg_common_t *h, char const *param)
{
if (h && h->h_class->hc_params) {
int retval;
msg_param_t **params = (msg_param_t **)
((char *)h + h->h_class->hc_params);
return msg_params_add(home, params, param);
msg_fragment_clear(h);
retval = msg_params_add(home, params, param);
if (retval < 0)
return -1;
if (h->h_class->hc_update) {
size_t namelen;
char const *name, *value;
name = param;
namelen = strcspn(name, "=");
value = param + namelen + (name[namelen] == '=');
h->h_class->hc_update(h, name, namelen, value);
}
return retval;
}
return -1;
}
/** Replace or add a parameter to a header.
*
* The shortcuts to parameter values are updated accordingly.
*
* @note This function does not duplicate @p param.
*
* @param home memory home
* @param h pointer to a header
* @param param parameter to be replaced or added
*
* @retval 0 if parameter was added
* @retval 1 if parameter was replaced
* @retval -1 upon an error
*/
int msg_header_replace_param(su_home_t *home,
msg_common_t *h,
char const *param)
{
if (h && h->h_class->hc_params) {
int retval;
msg_param_t **params = (msg_param_t **)
((char *)h + h->h_class->hc_params);
return msg_params_replace(home, params, param);
msg_fragment_clear(h);
retval = msg_params_replace(home, params, param);
if (retval < 0)
return -1;
if (h->h_class->hc_update) {
size_t namelen;
char const *name, *value;
name = param;
namelen = strcspn(name, "=");
value = param + namelen + (name[namelen] == '=');
h->h_class->hc_update(h, name, namelen, value);
}
return retval;
}
return -1;
}
/** Remove a parameter from header.
*
* The parameter name is given as token optionally followed by "=" sign and
* value. The "=" and value are ignored.
*
* @param h pointer to a header
* @param param parameter to be removed
*
* @retval 1 if a parameter was removed
* @retval 0 if no parameter was not removed
* @retval -1 upon an error
*/
int msg_header_remove_param(msg_common_t *h, char const *name)
{
if (h && h->h_class->hc_params) {
int retval;
msg_param_t **params = (msg_param_t **)
((char *)h + h->h_class->hc_params);
return msg_params_remove(*params, name);
retval = msg_params_remove(*params, name);
if (retval != 0)
msg_fragment_clear(h);
if (h->h_class->hc_update) {
size_t namelen;
namelen = strcspn(name, "=");
h->h_class->hc_update(h, name, namelen, NULL);
}
return retval;
}
return -1;
}
/** Update all parameters */
int msg_header_update_params(msg_common_t *h, int clear)
{
int retval;
msg_param_t const *params;
size_t n;
char const *p, *v;
if (h == NULL)
return errno = EFAULT, -1;
if (h->h_class->hc_params == 0 ||
h->h_class->hc_update == NULL)
return 0;
if (clear)
h->h_class->hc_update(h, NULL, 0, NULL);
params = *(msg_param_t **)((char *)h + h->h_class->hc_params);
if (params == NULL)
return 0;
retval = 0;
for (p = *params; p; p = *++params) {
n = strcspn(p, "=");
v = p + n + (p[n] == '=');
if (h->h_class->hc_update(h, p, n, v) < 0)
retval = -1;
}
return retval;
}
/** Find a parameter from a parameter list.
*
* Searches for given parameter @a token from the parameter list. If
......@@ -892,20 +1012,32 @@ msg_param_t *msg_params_find_slot(msg_param_t params[], msg_param_t token)
/** Replace or add a parameter from a list.
*
* The parameter list must have been created by @c msg_params_d() or by @c
* msg_params_dup() (or it may contain only @c NULL).
*
* @note This function does not duplicate @p param.
*
* @param home memory home
* @param inout_params pointer to pointer to parameter list
* @param param parameter to be replaced or added
*
* @retval 0 if parameter was added
* @retval 1 if parameter was replaced
* @retval -1 upon an error
*/
int msg_params_replace(su_home_t *home,
msg_param_t **pparams,
msg_param_t **inout_params,
msg_param_t param)
{
msg_param_t *params;
int i, n;
assert(pparams);
assert(inout_params);
if (param == NULL || param[0] == '=' || param[0] == '\0')
return -1;
params = *pparams;
params = *inout_params;
n = strcspn(param, "=");
assert(n > 0);
......@@ -918,13 +1050,14 @@ int msg_params_replace(su_home_t *home,
if (strncasecmp(maybe, param, n) == 0) {
if (maybe[n] == '=' || maybe[n] == 0) {
params[i] = param;
return 0;
return 1;
}
}
}
}
return msg_params_add(home, pparams, param);
/* Not found on list */
return msg_params_add(home, inout_params, param);
}
/** Remove a parameter from a list.
......@@ -940,7 +1073,7 @@ int msg_params_remove(msg_param_t *params, msg_param_t param)
if (!params || !param || !param[0])
return -1;
n = strlen(param);
n = strcspn(param, "=");
assert(n > 0);
for (i = 0; params[i]; i++) {
......@@ -978,26 +1111,25 @@ size_t msg_params_length(msg_param_t const params[])
/**
* Add a parameter to a list.
*
* The function @c msg_params_add() is used add a parameter to the list; the
* list must have been created by @c msg_params_d() or by @c
* msg_params_dup() (or it may contain only @c NULL).
* Add a parameter to the list; the list must have been created by @c
* msg_params_d() or by @c msg_params_dup() (or it may contain only @c
* NULL).
*
* @note This function does not duplicate @p param.
*
* @param home memory home
* @param pparams pointer to pointer to parameter list
* @param inout_params pointer to pointer to parameter list
* @param param parameter to be added
*
* @return
* The function @c msg_params_add() returns 0 if successful, or a negative
* value upon an error.
* @retval 0 if parameter was added
* @retval -1 upon an error
*/
int msg_params_add(su_home_t *home,
msg_param_t **pparams,
msg_param_t **inout_params,
msg_param_t param)
{
int n, m_before, m_after;
msg_param_t *p = *pparams;
msg_param_t *p = *inout_params;
if (param == NULL)
return -1;
......@@ -1013,8 +1145,8 @@ int msg_params_add(su_home_t *home,
p = su_alloc(home, m_after * sizeof(*p));
assert(p); if (!p) return -1;
if (n)
memcpy(p, *pparams, n * sizeof(*p));
*pparams = p;
memcpy(p, *inout_params, n * sizeof(*p));
*inout_params = p;
}
p[n] = param;
......
......@@ -128,7 +128,10 @@ tagi_t *msghdrtag_dup(tagi_t *dst, tagi_t const *src, void **bb)
h->sh_class = hc;
b = hc->hc_dup_one(h, o, b, 65535); /* XXX */
if (hc->hc_update)
msg_header_update_params(h->sh_common, 0);
*hh = h; hh = &h->sh_next;
assert(b != NULL);
......@@ -254,6 +257,8 @@ tagi_t *msgobjtag_dup(tagi_t *dst, tagi_t const *src, void **bb)
memset(h, 0, o->sh_class->hc_size);
h->sh_class = o->sh_class;
b = o->sh_class->hc_dup_one(h, o, b, 65535); /* XXX */
if (o->sh_class->hc_update)
msg_header_update_params(h->sh_common, 0);
assert(b != NULL);
}
......@@ -338,6 +343,8 @@ tagi_t *msgtag_multipart_dup(tagi_t *dst, tagi_t const *src, void **bb)
memset(h, 0, o->sh_class->hc_size);
h->sh_class = o->sh_class;
b = o->sh_class->hc_dup_one(h, o, b, 65535); /* XXX */
if (o->sh_class->hc_update)
msg_header_update_params(h->sh_common, 0);
assert(b != NULL);
}
......
......@@ -263,6 +263,9 @@ typedef char *msg_dup_f(msg_header_t *dst, msg_header_t const *src,
char *buf, int bufsiz);
typedef int msg_xtra_f(msg_header_t const *h, int offset);
typedef int msg_update_f(msg_common_t *, char const *name, int namelen,
char const *value);
/** Factory object for a header.
*
* The #msg_hclass_t object, "header class", defines how a header is
......@@ -277,6 +280,7 @@ struct msg_hclass_s
msg_print_f *hc_print; /**< Print header. */
msg_xtra_f *hc_dxtra; /**< Calculate extra size for dup */
msg_dup_f *hc_dup_one; /**< Duplicate one header. */
msg_update_f *hc_update; /**< Update parameter(s) */
char const *hc_name; /**< Full name. */
short hc_len; /**< Length of hc_name. */
char hc_short[2];/**< Short name, if any. */
......
......@@ -55,6 +55,8 @@ extern msg_mclass_t const *msg_test_default(void)
return msg_test_mclass;
}
#define msg_generic_update NULL
/**@ingroup test_msg
* @defgroup msg_test_request Request Line for Testing
*/
......@@ -64,7 +66,7 @@ static msg_dup_f msg_request_dup_one;
msg_hclass_t msg_request_class[] =
MSG_HEADER_CLASS(msg_, request, NULL, "", rq_common,
single_critical, msg_request);
single_critical, msg_request, msg_generic);
/** Decode a request line */
int msg_request_d(su_home_t *home, msg_header_t *h, char *s, int slen)
......@@ -132,7 +134,7 @@ static msg_dup_f msg_status_dup_one;
msg_hclass_t msg_status_class[1] =
MSG_HEADER_CLASS(msg_, status, NULL, "", st_common,
single_critical, msg_status);
single_critical, msg_status, msg_generic);
/** Parse status line */
int msg_status_d(su_home_t *home, msg_header_t *h, char *s, int slen)
......
......@@ -482,7 +482,7 @@ int test_header_parsing(void)
TEST(msg_header_remove_param(ce->k_common, "zip"), 0);
TEST(msg_header_replace_param(home, ce->k_common, "zip=zap"), 0);
TEST_S(msg_header_find_param(ce->k_common, "zip=1"), "zap");
TEST(msg_header_replace_param(home, ce->k_common, "zip=zup"), 0);
TEST(msg_header_replace_param(home, ce->k_common, "zip=zup"), 1);
TEST_S(msg_header_find_param(ce->k_common, "zip"), "zup");
su_home_deinit(home);
......
......@@ -517,7 +517,7 @@ struct sip_error_info_s
*/
struct sip_event_s
{
sip_common_t o_common; /**< Common fragment info */
sip_common_t o_common[1]; /**< Common fragment info */
sip_error_t *o_next; /**< Link to next (dummy) */
char const * o_type; /**< Event type */
msg_param_t const *o_params; /**< List of parameters */
......@@ -741,8 +741,6 @@ struct sip_via_s
char const *v_port; /**< Port number */
msg_param_t const *v_params; /**< List of via-params */
char const *v_comment; /**< Comment */
unsigned v_hidden; /**< Value of "hidden" parameter */
char const *v_ttl; /**< Value of "ttl" parameter */
char const *v_maddr; /**< Value of "maddr" parameter */
char const *v_received; /**< Value of "received" parameter*/
......@@ -762,7 +760,10 @@ struct sip_security_agree_s
*sa_next; /**< Link to next mechanism */
char const *sa_mec; /**< Security mechanism */
msg_param_t const *sa_params; /**< List of mechanism parameters */
char const *sa_q; /**< Shortcut to q (preference) parameter */
char const *sa_q; /**< Value of q (preference) parameter */
char const *sa_d_alg; /**< Value of d-alg parameter */
char const *sa_d_qop; /**< Value of d-qop parameter */
char const *sa_d_ver; /**< Value of d-ver parameter */
};
/**@ingroup sip_privacy
......
This diff is collapsed.
......@@ -89,8 +89,11 @@
static msg_xtra_f sip_request_disposition_dup_xtra;
static msg_dup_f sip_request_disposition_dup_one;
#define sip_request_disposition_update NULL
msg_hclass_t sip_request_disposition_class[] =
SIP_HEADER_CLASS(request_disposition, "Request-Disposition", "d", rd_items, list, request_disposition);
SIP_HEADER_CLASS(request_disposition, "Request-Disposition", "d", rd_items,
list, request_disposition);
int sip_request_disposition_d(su_home_t *home, sip_header_t *h,
char *s, int slen)
......@@ -125,8 +128,9 @@ int sip_request_disposition_dup_xtra(sip_header_t const *h, int offset)
/** Duplicate one sip_request_disposition_t object */
char *sip_request_disposition_dup_one(sip_header_t *dst, sip_header_t const *src,
char *b, int xtra)
char *sip_request_disposition_dup_one(sip_header_t *dst,
sip_header_t const *src,
char *b, int xtra)
{
char *end = b + xtra;
sip_request_disposition_t *o_dst = dst->sh_request_disposition;
......@@ -141,46 +145,10 @@ char *sip_request_disposition_dup_one(sip_header_t *dst, sip_header_t const *src
}
/* ====================================================================== */
static
void sip_caller_prefs_update_one(sip_caller_prefs_t *cp, char const *p)
{
switch (p[0]) {
case 'e':
MSG_PARAM_MATCH_P(cp->cp_explicit, p, "explicit");
break;
case 'q':
MSG_PARAM_MATCH(cp->cp_q, p, "q");
break;
case 'r':
MSG_PARAM_MATCH_P(cp->cp_require, p, "require");
break;
}
}
static
void sip_caller_prefs_update(sip_header_t *h)
{
sip_caller_prefs_t *cp = h->sh_caller_prefs;
char const *p;
char const *const *pp;
/* Clear existing parameters */
cp->cp_q = NULL;
cp->cp_require = 0;
cp->cp_explicit = 0;
if ((pp = cp->cp_params))
while ((p = pp++[0]))
sip_caller_prefs_update_one(cp, p);
}
/**@ingroup sip_caller_prefs
*
* Add a parameter to a @b Contact header object
*
* The function sip_caller_prefs_add_param() adds a parameter to a contact
* object. It does not copy the contents of the string @c param.
* Add a parameter to a @b Accept-Contact or @b Reject-Contact header object.
*
* @note This function does not duplicate @p param.
*
......@@ -188,21 +156,14 @@ void sip_caller_prefs_update(sip_header_t *h)
* @param cp sip_caller_prefs_t object
* @param param parameter string
*
* @return The function sip_caller_prefs_add_param() returns 0 when successful,
* and -1 upon an error.
* @retval 0 when successful
* @retval -1 upon an error
*/
int sip_caller_prefs_add_param(su_home_t *home,
sip_caller_prefs_t *cp,
char const *param)
{
sip_fragment_clear(cp->cp_common);
if (msg_params_replace(home, (char const ***)&cp->cp_params, param) < 0)
return -1;
sip_caller_prefs_update_one(cp, param);
return 0;
return msg_header_replace_param(home, cp->cp_common, param);
}
static
......@@ -272,7 +233,7 @@ int sip_caller_prefs_d(su_home_t *home, sip_header_t *h, char *s, int slen)
return -1;
if (cp->cp_params)
sip_caller_prefs_update(h);
msg_header_update_params(cp->cp_common, 0);
h = NULL;
}
......@@ -319,12 +280,37 @@ char *sip_caller_prefs_dup_one(sip_header_t *dst, sip_header_t const *src,
assert(b <= end);
if (cp->cp_params)
sip_caller_prefs_update(dst);
return b;
}
static int sip_caller_prefs_update(msg_common_t *h,
char const *name, int namelen,
char const *value)
{
sip_caller_prefs_t *cp = (sip_caller_prefs_t *)h;
if (name == NULL) {
cp->cp_q = NULL;
cp->cp_require = 0;
cp->cp_explicit = 0;
}
#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
else if (MATCH(q)) {
cp->cp_q = value;
}
else if (MATCH(require)) {
cp->cp_require = value != NULL;