📄 url.c
字号:
/** * Duplicate the url. * * The function url_dup() copies the url structure @a src and the strings * attached to it to @a url. The non-constant strings in @a src are copied * to @a buf. If the size of duplicated strings exceed @a bufsize, the * corresponding string fields in @a url are set to NULL. * * The calling function can calculate the size of buffer required by calling * url_dup() with zero as @a bufsize and NULL as @a dst. * @param buf Buffer for non-constant strings copied from @a src. * @param bufsize Size of @a buf. * @param dst Destination URL structure. *燖param src Source URL structure. * * @return Number of characters required for * duplicating the strings in @a str, or -1 if an error * occurred. */issize_t url_dup(char *buf, isize_t bufsize, url_t *dst, url_t const *src){ if (!src && !dst) return -1; else if (URL_STRING_P(src)) { size_t n = strlen((char *)src) + 1; if (n > bufsize || dst == NULL) return n; strcpy(buf, (char *)src); memset(dst, 0, sizeof(*dst)); if (url_d(dst, buf) < 0) return -1; return n; } else { char *b = buf; char *end = b + bufsize; char const **dstp; char const * const *srcp; url_t dst0[1]; if (dst == NULL) dst = dst0; memset(dst, 0, sizeof(*dst)); if (!src) return 0; memset(dst->url_pad, 0, sizeof dst->url_pad); dst->url_type = src->url_type; dst->url_root = src->url_root; dstp = &dst->url_scheme; srcp = &src->url_scheme; if (dst->url_type > url_unknown) *dstp = url_scheme(dst->url_type); if (*dstp != NULL) dstp++, srcp++; /* Skip scheme if it is constant */ if (dst != dst0 && buf != NULL && bufsize != 0) for (; srcp <= &src->url_fragment; srcp++, dstp++) if (*srcp) { char *next = copy(b, end, *srcp); if (next > end) break; *dstp = b, b = next; } for (; srcp <= &src->url_fragment; srcp++) if (*srcp) { b += strlen(*srcp) + 1; } return b - buf; }}/**@def URL_DUP(buf, end, dst, src) * Duplicate the url: use @a buf up to @a end. @HI * * The macro URL_DUP() duplicates the url. The non-constant strings in @a * src are copied to @a buf. However, no strings are copied past @a end. * In other words, the size of buffer is @a end - @a buf. * * The macro updates the buffer pointer @a buf, so that it points to the * first unused byte in the buffer. The buffer pointer @a buf is updated, * even if the buffer is too small for the duplicated strings. * * @param buf Buffer for non-constant strings copied from @a src. * @param end End of @a buf. * @param dst Destination URL structure. *燖param src Source URL structure. * * @return * The macro URL_DUP() returns pointer to first unused byte in the * buffer @a buf. *//** Duplicate the url to memory allocated via home. * * The function url_hdup() duplicates (deep copies) an #url_t structure. * Alternatively, it can be passed a string; string is then copied and * parsed to the #url_t structure. * * The function url_hdup() allocates the destination structure from @a home * as a single memory block. It is possible to free the copied url structure * and all the associated strings using a single call to su_free(). * * @param home memory home used to allocate new url object * @param src pointer to URL (or string) * * @return * The function url_hdup() returns a pointer to the newly allocated #url_t * structure, or NULL upon an error. */ url_t *url_hdup(su_home_t *home, url_t const *src){ if (src) { size_t len = sizeof(*src) + url_xtra(src); url_t *dst = su_alloc(home, len); if (dst) { ssize_t actual; actual = url_dup((char *)(dst + 1), len - sizeof(*src), dst, src); if (actual < 0) su_free(home, dst), dst = NULL; else assert(len == sizeof(*src) + actual); } return dst; } else return NULL;}/** Convert an string to an url */ url_t *url_make(su_home_t *h, char const *str){ return url_hdup(h, URL_STRING_MAKE(str)->us_url);}/** Print an URL */ url_t *url_format(su_home_t *h, char const *fmt, ...){ url_t *url; char *us; va_list ap; va_start(ap, fmt); us = su_vsprintf(h, fmt, ap); va_end(ap); if (us == NULL) return NULL; url = url_hdup(h, URL_STRING_MAKE(us)->us_url); su_free(h, us); return url;}/** Convert @a url to a string allocated from @a home. * * @param home memory home to allocate the new string * @param url url to convert to string * * The @a url can be a string, too. * * @return Newly allocated conversion result, or NULL upon an error. */char *url_as_string(su_home_t *home, url_t const *url){ if (url) { int len = url_e(NULL, 0, url); char *b = su_alloc(home, len + 1); url_e(b, len + 1, url); return b; } else { return NULL; }}/** Test if param @a tag matches to parameter string @a p. */#define URL_PARAM_MATCH(p, tag) \ (strncasecmp(p, tag, strlen(tag)) == 0 && \ (p[strlen(tag)] == '\0' || p[strlen(tag)] == ';' || p[strlen(tag)] == '='))/** * Search for a parameter. * * This function searches for a parameter from a parameter list. * * If you want to test if there is parameter @b user=phone, * call this function like * @code if (url_param(url->url_param, "user=phone", NULL, 0)) * @endcode * * @param params URL parameter string (excluding first semicolon) * @param tag parameter name * @param value string to which the parameter value is copied * @param vlen length of string reserved for value * * @retval positive length of parameter value (including final NUL) if found * @retval zero if not found. */isize_t url_param(char const *params, char const *tag, char value[], isize_t vlen){ size_t n, tlen, flen; char *p; if (!params) return 0; tlen = strlen(tag); if (tlen && tag[tlen - 1] == '=') tlen--; for (p = (char *)params; *p; p += n + 1) { n = strcspn(p, ";"); if (n < tlen) { if (p[n]) continue; else break; } if (strncasecmp(p, tag, tlen) == 0) { if (n == tlen) { if (vlen > 0) value[0] = '\0'; return 1; } if (p[tlen] != '=') continue; flen = n - tlen - 1; if (flen >= (size_t)vlen) return flen + 1; memcpy(value, p + tlen + 1, flen); value[flen] = '\0'; return flen + 1; } if (!p[n]) break; } return 0;}/** Check for a parameter. * * @deprecated * Bad grammar. Use url_has_param(). */isize_t url_have_param(char const *params, char const *tag){ return url_param(params, tag, NULL, 0);}/** Check for a parameter. */int url_has_param(url_t const *url, char const *tag){ return url && url->url_params && url_param(url->url_params, tag, NULL, 0);}/** Add an parameter. */int url_param_add(su_home_t *h, url_t *url, char const *param){ /* XXX - should remove existing parameters with same name? */ size_t n = url->url_params ? strlen(url->url_params) + 1: 0; size_t nn = strlen(param) + 1; char *s = su_alloc(h, n + nn); if (!s) return -1; if (url->url_params) strcpy(s, url->url_params)[n - 1] = ';'; strcpy(s + n, param); url->url_params = s; return 0;}/** Remove a named parameter from url_param string. * * Remove a named parameter and its possible value from the URL parameter * string (url_s##url_param). * * @return Pointer to modified string, or NULL if nothing is left in there. */char *url_strip_param_string(char *params, char const *name){ if (params && name) { size_t i, n = strlen(name), remove, rest; for (i = 0; params[i];) { if (strncasecmp(params + i, name, n) || (params[i + n] != '=' && params[i + n] != ';' && params[i + n])) { i = i + strcspn(params + i, ";"); if (!params[i++]) break; continue; } remove = n + strcspn(params + i + n, ";"); if (params[i + remove] == ';') remove++; if (i == 0) { params += remove; continue; } rest = strlen(params + i + remove); if (!rest) { if (i == 0) return NULL; /* removed everything */ params[i - 1] = '\0'; break; } memmove(params + i, params + i + remove, rest + 1); } if (!params[0]) return NULL; } return params;}int url_string_p(url_string_t const *url){ return URL_STRING_P(url);}int url_is_string(url_string_t const *url){ return URL_IS_STRING(url);}/** Strip transport-specific stuff. */staticint url_strip_transport2(url_t *url, int modify){ char *p, *d; size_t n; int semi; if (url->url_type != url_sip && url->url_type != url_sips) return 0; if (url->url_port != NULL) { if (!modify) return 1; url->url_port = NULL; } if (!url->url_params) return 0; for (d = p = (char *)url->url_params; *p; p += n + semi) { n = strcspn(p, ";"); semi = (p[n] != '\0'); if (modify && n == 0) continue; if (URL_PARAM_MATCH(p, "method")) continue; if (URL_PARAM_MATCH(p, "maddr")) continue; if (URL_PARAM_MATCH(p, "ttl")) continue; if (URL_PARAM_MATCH(p, "transport")) continue; if (p != d) { if (d != url->url_params) d++; if (p != d) { if (!modify) return 1; memmove(d, p, n + 1); } } d += n; } if (d == p) return 0; else if (d + 1 == p) /* empty param */ return 0; else if (!modify) return 1; if (d != url->url_params) *d = '\0'; else url->url_params = NULL; return 1;}/** Strip transport-specific stuff. * * The function url_strip_transport() removes transport-specific parameters * from a SIP or SIPS URI. These parameters include: * - the port number * - "maddr=" parameter * - "transport=" parameter * - "ttl=" parameter * - "method=" parameter * * @note * The @a url must be a pointer to a URL structure. It is stripped in-place. * * @note * If the parameter string contains empty parameters, they are stripped, too. * * @return * The function url_strip_transport() returns @e true, if the URL was * modified, @e false otherwise. */int url_strip_transport(url_t *url){ return url_strip_transport2(url, 1);}/** Check for transport-specific stuff. * * The function url_have_transport() tests if there are transport-specific * parameters in a SIP or SIPS URI. These parameters include: * - the port number * - "maddr=" parameters * - "transport=" parameters * * @note * The @a url must be a pointer to a URL structure. * * @return The function url_have_transport() returns @e true, if the URL * contains transport parameters, @e false otherwise. */int url_have_transport(url_t const *url){ return url_strip_transport2((url_t *)url, 0);}/**Lazily compare two URLs. * * Compare essential parts of URLs: schema, host, port, and username. * * any_url compares 0 with any other URL. * * pres: and im: URIs compares 0 with SIP URIs. * * @note * The @a a and @a b must be pointers to URL structures. * * @note Currently, the url parameters are not compared. This is because the * url_cmp() is used to sort URLs: taking parameters into account makes that * impossible. */int url_cmp(url_t const *a, url_t const *b){ int rv; int url_type; if ((a && a->url_type == url_any) || (b && b->url_type == url_any)) return 0; if (!a || !b) return (a != NULL) - (b != NULL); if ((rv = a->url_type - b->url_type)) {#if 0 /* presence and instant messaging URLs match magically with SIP */ enum url_type_e a_type = a->url_type; enum url_type_e b_type = b->url_type; if (a_type == url_im || a_type == url_pres) a_type = url_sip; if (b_type == url_im || b_type == url_pres) b_type = url_sip; if (a_type != b_type)#endif return rv; } url_type = a->url_type; /* Or b->url_type, they are equal! */ if (url_type <= url_unknown && ((rv = !a->url_scheme - !b->url_scheme) || (a->url_scheme && b->url_scheme && (rv = strcasecmp(a->url_scheme, b->url_scheme))))) return rv; if ((rv = host_cmp(a->url_host, b->url_host))) return rv; if (a->url_port != b->url_port) { char const *a_port; char const *b_port; if (url_type != url_sip && url_type != url_sips) a_port = b_port = url_port_default(url_type); else if (host_is_ip_address(a->url_host)) a_port = b_port = url_port_default(url_type); else a_port = b_port = ""; if (a->url_port) a_port = a->url_port; if (b->url_port) b_port = b->url_port; if ((rv = strcmp(a_port, b_port))) return rv; } if (a->url_user != b->url_user) { if (a->url_user == NULL) return -1; if (b->url_user == NULL) return +1; switch (url_type) { case url_tel: case url_modem: case url_fax: rv = url_tel_cmp_numbers(a->url_user, b->url_user);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -