msg_parser_util.c
来自「Sofia SIP is an open-source SIP User-Age」· C语言 代码 · 共 1,997 行 · 第 1/4 页
C
1,997 行
char *end = b + bsiz, *b0 = b; msg_param_t p; if (pparams) for (i = 0; (p = pparams[i]); i++) { if (p[0]) { MSG_CHAR_E(b, end, ';'); MSG_STRING_E(b, end, p); } } return b - b0;}/** Duplicate a parameter list */char *msg_params_dup(msg_param_t const **d, msg_param_t const s[], char *b, isize_t xtra){ char *end = b + xtra; char **pp; int i; isize_t n; n = msg_params_count(s); if (n == 0) { *d = NULL; return b; } MSG_STRUCT_ALIGN(b); pp = (char **)b; b += sizeof(*pp) * MSG_PARAMS_NUM(n + 1); for (i = 0; s[i]; i++) { MSG_STRING_DUP(b, pp[i], s[i]); } pp[i] = NULL; assert(b <= end); (void)end; *d = (msg_param_t const *)pp; return b;} /** Parse a comma-separated list. * * Parses a comma-separated list. The parsed string is passed in @a *ss, * which is updated to point to the first non-linear-whitespace character * after the list. The function modifies the string as it parses it. * * A pointer to the resulting list is returned in @a *retval. If there * already is a list in @a *retval, new items are appended. Empty list items * are ignored, and are not included in the list. * * The function can be passed an optional scanning function. The scanning * function scans for a legitimate list item, for example, a token. It also * compacts the list item, for instance, if the item consists of @c * name=value parameter definitions. The scanning function returns the * length of the scanned item, including any linear whitespace after it. * * By default, the scanning function accepts tokens, quoted strings or * separators (except comma, of course). * * @param[in] home memory home for allocating list pointers * @param[in,out] ss pointer to pointer to string to be parsed * @param[in,out] append_list pointer to list * where parsed list items are appended * @param[in] scanner pointer to function scanning a single item * (optional) * * @retval 0 if successful. * @retval -1 upon an error. */issize_t msg_commalist_d(su_home_t *home, char **ss, msg_param_t **append_list, issize_t (*scanner)(char *s)){ scanner = scanner ? scanner : msg_comma_scanner; return msg_any_list_d(home, ss, append_list, scanner, ',');}/** Token scanner for msg_commalist_d() accepting also empty entries. */issize_t msg_token_scan(char *start){ char *s = start; skip_token(&s); if (IS_LWS(*s)) *s++ = '\0'; skip_lws(&s); return s - start;}/** Scan and compact a comma-separated item */staticissize_t msg_comma_scanner(char *start){ size_t tlen; char *s, *p; s = p = start; if (s[0] == ',') return 0; for (;;) { /* Grab next section - token, quoted string, or separator character */ char c = *s; if (IS_TOKEN(c)) tlen = span_token(s); else if (c == '"') tlen = span_quoted(s); else /* if (IS_SEPARATOR(c)) */ tlen = 1; if (tlen == 0) return -1; if (p != s) memmove(p, s, tlen); /* Move section to end of paramexter */ p += tlen; s += tlen; skip_lws(&s); /* Skip possible LWS */ if (*s == '\0' || *s == ',') { /* Test for possible end */ if (p != s) *p = '\0'; return s - start; } if (IS_TOKEN(c) && IS_TOKEN(*s)) *p++ = ' '; /* Two tokens must be separated by LWS */ }}/** Parse a comment. * * Parses a multilevel comment. The comment assigned to return-value * parameter @a return_comment is NUL-terminated. The string at return-value * parameter @a ss is updated to point to first non-linear-whitespace * character after the comment. */issize_t msg_comment_d(char **ss, char const **return_comment){ /* skip comment */ int level = 1; char *s = *ss; assert(s[0] == '('); if (*s != '(') return -1; *s++ = '\0'; if (return_comment) *return_comment = s; while (level) switch (*s++) { case '(': level++; break; case ')': level--; break; case '\0': /* ERROR */ return -1; } assert(s[-1] == ')'); s[-1] = '\0'; skip_lws(&s); *ss = s; return 0;}/** Parse a quoted string */issize_t msg_quoted_d(char **ss, char **return_quoted){ char *s= *ss, *s0 = s; ssize_t n = span_quoted(s); if (n <= 0) return -1; *return_quoted = s; s += n; if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); /* skip linear whitespace */ } *ss = s; return s - s0;}#if 0/** Calculate length of string when quoted. */int msg_quoted_len(char const *u){ int rv; if (!u) return 0; rv = span_token_lws(u); if (u[rv]) { /* We need to quote string */ int n; int extra = 2; /* quote chars */ /* Find all characters to quote */ for (n = strcspn(u + rv, "\\\""); u[rv + n]; rv += n) extra++; rv += extra; } return rv;}#endif/**Parse @e host[":"port] pair. * * Parses a @e host[":"port] pair. The caller passes function a pointer to a * string via @a ss, and pointers to which parsed host and port are assigned * via @a hhost and @a pport, respectively. The value-result parameter @a * *pport must be initialized to default value (e.g., NULL). * * @param ss pointer to pointer to string to be parsed * @param return_host value-result parameter for @e host * @param return_port value-result parameter for @e port * @return * Returns zero when successful, and a negative value upon an error. The * parsed values for host and port are assigned via @a return_host and @a * return_port, respectively. The function also updates the pointer @a *ss, * so if call is successful, the @a *ss points to first * non-linear-whitespace character after @e host[":"port] pair. * * @note * If there is no whitespace after @e port, the value in @a *pport may not be * NUL-terminated. The calling function @b must NUL terminate the value by * setting the @a **ss to NUL after first examining its value. */int msg_hostport_d(char **ss, char const **return_host, char const **return_port){ char *host, *s = *ss; char *port = NULL; /* Host name */ host = s; if (s[0] != '[') { skip_token(&s); if (host == s) return -1; } else { /* IPv6 */ size_t n = strspn(++s, HEX ":."); if (s[n] != ']') return -1; s += n + 1; } if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); } if (s[0] == ':') { unsigned long nport; *s++ = '\0'; skip_lws(&s); if (!IS_DIGIT(*s)) return -1; port = s; nport = strtoul(s, &s, 10); if (nport > 65535) return -1; if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); } } *return_host = host; *return_port = port; *ss = s; return 0;}/** Find a header parameter. * * Searches for given parameter @a name from the header. If parameter is * found, it returns a non-NULL pointer to the parameter value. If there is * no value for the name (in form "name" or "name=value"), the returned pointer * points to a NUL character. * * @param h pointer to header structure * @param name parameter name (with or without "=" sign) * * @return * A pointer to parameter value, or NULL if parameter was not found. */char const *msg_header_find_param(msg_common_t const *h, char const *name){ if (h && h->h_class->hc_params) { msg_param_t const **params = (msg_param_t const **) ((char *)h + h->h_class->hc_params); return msg_params_find(*params, name); } return NULL;}/**Modify a parameter value or list item in a header. * * A header parameter @a param can be just a C-string (@a is_item > 0), or * it can have internal format <i>name [ "=" value]</i>. In the latter case, * the value part following = is ignored when replacing or removing the * parameter. * * @param home memory home used to re-allocate parameter list in header * @param h pointer to a header * @param param parameter to be replaced or added * @param is_item how to interpret @a param: * - 1 case-sensitive, no structure * - 0 case-insensitive, <i>name [ "=" value ]</i> * @param remove_replace_add what operation to do: * - -1 remove * - 0 replace * - 1 add * * @retval 1 if parameter was replaced or removed successfully * @retval 0 if parameter was added successfully, * or there was nothing to remove * @retval -1 upon an error */static int msg_header_param_modify(su_home_t *home, msg_common_t *h, char const *param, int is_item, int remove_replace_add){ msg_param_t *params, **pointer_to_params; size_t plen, n; if (!h || !h->h_class->hc_params || !param) return -1; pointer_to_params = (msg_param_t **)((char *)h + h->h_class->hc_params); params = *pointer_to_params; plen = is_item > 0 ? strlen(param) : strcspn(param, "="); n = 0; if (params) { /* Existing list, try to replace or remove */ for (; params[n]; n++) { char const *maybe = params[n]; if (remove_replace_add > 0) continue; if (is_item > 0) { if (strcmp(maybe, param) == 0) { if (remove_replace_add == 0) return 1; } } else { if (strncasecmp(maybe, param, plen) == 0 && (maybe[plen] == '=' || maybe[plen] == 0)) break; } } } /* Not found? */ if (!params || !params[n]) { if (remove_replace_add < 0) return 0; /* Nothing to remove */ else remove_replace_add = 1; /* Add instead of replace */ } if (remove_replace_add < 0) { /* Remove */ for (; params[n]; n++) params[n] = params[n + 1]; } else { if (remove_replace_add > 0) { /* Add */ size_t m_before = MSG_PARAMS_NUM(n + 1); size_t m_after = MSG_PARAMS_NUM(n + 2); assert(!params || !params[n]); if (m_before != m_after || !params) { msg_param_t *p; /* XXX - we should know when to do realloc */ p = su_alloc(home, m_after * sizeof(*p)); if (!p) return -1; if (n > 0) memcpy(p, params, n * sizeof(p[0])); *pointer_to_params = params = p; } params[n + 1] = NULL; } params[n] = param; /* Add .. or replace */ } msg_fragment_clear(h); if (h->h_class->hc_update) { /* Update shortcuts */ size_t namelen; char const *name, *value; name = param; namelen = strcspn(name, "="); if (remove_replace_add < 0) value = NULL; else value = param + namelen + (name[namelen] == '='); h->h_class->hc_update(h, name, namelen, value); } return remove_replace_add <= 0; /* 0 when added, 1 otherwise */}/** Add a parameter to a header. * * You should use this function only when the header accepts multiple * parameters (or list items) with the same name. If that is not the case, * you should use msg_header_replace_param(). * * @note This function @b does @b not duplicate @p param. The caller should * have allocated the @a param from the memory home associated with header * @a h. * * The possible shortcuts to parameter values are updated. For example, the * "received" parameter in @Via header has shortcut in structure #sip_via_t, * the @ref sip_via_s::v_received "v_received" field. The shortcut is usully * a pointer to the parameter value. If the parameter was * "received=127.0.0.1" the @ref sip_via_s::v_received "v_received" field * would be a pointer to "127.0.0.1". If the parameter was "received=" or * "received", the shortcut would be a pointer to an empty string, "". * * @param home memory home used to re-allocate parameter list in header * @param h pointer to a header * @param param parameter to be replaced or added * * @retval 0 if parameter was added * @retval -1 upon an error * * @sa msg_header_replace_param(), msg_header_remove_param(), * msg_header_update_params(), * #msg_common_t, #msg_header_t, * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update */int msg_header_add_param(su_home_t *home, msg_common_t *h, char const *param){ return msg_header_param_modify(home, h, param, 0 /* case-insensitive name=value */, 1 /* add */);}/** Replace or add a parameter to a header. * * A header parameter @a param is a string of format <i>name "=" value</i> * or just name. The value part following "=" is ignored when selecting a * parameter to replace. * * @note This function @b does @b not duplicate @p param. The caller should * have allocated the @a param from the memory home associated with header * @a h. * * The possible shortcuts to parameter values are updated. For example, the * "received" parameter in @Via header has shortcut in structure #sip_via_t, * the @ref sip_via_s::v_received "v_received" field. * * @param home memory home used to re-allocate parameter list in header * @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 * * @sa msg_header_add_param(), msg_header_remove_param(), * msg_header_update_params(), * #msg_common_t, #msg_header_t, * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?