📄 msg_parser_util.c
字号:
* 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 home memory home used to allocate memory for list pointers [in] * @param ss pointer to pointer to string to be parsed [in/out] * @param return_list return-value parameter for parsed list [in/out] * @param scanner pointer to function scanning a single item (optional) [in] * * @retval 0 if successful. * @retval -1 upon an error. */int msg_commalist_d(su_home_t *home, char **ss, msg_param_t **return_list, int (*scanner)(char *s)){ scanner = scanner ? scanner : msg_comma_scanner; return msg_any_list_d(home, ss, return_list, scanner, ',');}/** Token scanner for msg_commalist_d() accepting also empty entries. */int 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 */staticint msg_comma_scanner(char *start){ int 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. */int 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 */int msg_quoted_d(char **ss, char **return_quoted){ char *s = *ss; int 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 0;}#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 */ int 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;}/** 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); 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 @b does @b 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); 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 name name of 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); 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 * parameter is found, it returns a non-NULL pointer to the parameter value. * If there is no value for the parameter (the parameter is of form "name" * or "name="), the returned pointer points to a NUL character. * * @param params list (or vector) of parameters * @param token parameter name (with or without "=" sign) * * @return * A pointer to parameter value, or NULL if parameter was not found. */msg_param_t msg_params_find(msg_param_t const params[], msg_param_t token){ if (params && token) { int i, n = strcspn(token, "="); assert(n > 0); for (i = 0; params[i]; i++) { msg_param_t param = params[i]; if (strncasecmp(param, token, n) == 0) { if (param[n] == '=') return param + n + 1; else if (param[n] == 0) return param + n; } } } return NULL;}/** Find a slot for parameter from a parameter list. * * Searches for given parameter @a token from the parameter list. If * parameter is found, it returns a non-NULL pointer to the item containing * the parameter. * * @param params list (or vector) of parameters * @param token parameter name (with or without "=" sign) * * @return * A pointer to parameter slot, or NULL if parameter was not found. */msg_param_t *msg_params_find_slot(msg_param_t params[], msg_param_t token){ if (params && token) { int i, n = strlen(token); assert(n > 0); for (i = 0; params[i]; i++) { msg_param_t param = params[i]; if (strncasecmp(param, token, n) == 0) { if (param[n] == '=') return params + i; else if (param[n] == 0 || token[n - 1] == '=') return params + i; } } } return NULL;}/** 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 **inout_params, msg_param_t param){ msg_param_t *params; int i, n; assert(inout_params); if (param == NULL || param[0] == '=' || param[0] == '\0') return -1; params = *inout_params; n = strcspn(param, "="); assert(n > 0); if (params) { /* Existing list, try to replace or remove */ for (i = 0; params[i]; i++) { msg_param_t maybe = params[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -