diff --git a/src/std/c_path.c b/src/std/c_path.c index 769ac34081..560846e4b9 100644 --- a/src/std/c_path.c +++ b/src/std/c_path.c @@ -17,10 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * vim: ts=2 sw=2 et cindent + * vim: ft=c.doxygen ts=2 sw=2 et cindent */ -#include +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include #include #include @@ -108,3 +113,236 @@ char *c_basename (const char *path) { return newpath; } +int c_parse_uri(const char *uri, + char **scheme, + char **user, char **passwd, + char **host, unsigned int *port, + char **path) { + const char *p, *z; + + if (uri == NULL || *uri == '\0') { + return -1; + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p = z = uri; + + /* check for valid scheme; git+ssh, pop3 */ + while (isalpha((int) *p) || isdigit((int) *p) || + *p == '+' || *p == '-') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p++; + } + + /* get scheme */ + if (*p == ':') { + if (scheme != NULL) { + *scheme = c_strndup(z, p - z); + } + + p++; + z = p; + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p = z; + + /* do we have a hostname */ + if (p[0] == '/' && p[1] == '/') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + z += 2; + p = z; + + /* check for user and passwd */ + while (*p && *p != '@' && *p != '/') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ or ^ + * z = ^ + */ + p++; + } + + /* check for user and password */ + if (*p == '@') { + const char *q; + + q = p; + + /* check if we have a password */ + while (q > z && *q != ':') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + * q = ^ + */ + q--; + } + + /* password found */ + if (*q == ':') { + if (user != NULL) { + *user = c_strndup(z, q - z); + } + + if (passwd != NULL) { + *passwd = c_strndup(q + 1, p - (q + 1)); + } + } else { + /* user only */ + if (user != NULL) { + *user = c_strndup(z, p - z); + } + } + + p++; + z = p; + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + p = z; + + /* check for IPv6 address */ + if (*p == '[') { + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + p++; + + /* check if we have a valid IPv6 address */ + while (*p && (isxdigit((int) *p) || *p == '.' || *p == ':')) { + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + p++; + } + + /* valid IPv6 address found */ + if (*p == ']') { + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + z++; + + if (host != NULL) { + *host = c_strndup(z, p - z); + } + + /* + * uri = scheme://user:password@[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:port/path + * p = ^ + * z = ^ + */ + p++; + } else { + /* invalid IPv6 address, assume a hostname */ + p = z; + + while (*p && *p != ':' && *p != '/') { + p++; + /* + * uri = scheme://user:password@host:port/path + * p = ^ or ^ + * z = ^ + */ + } + + if (host != NULL) { + *host = c_strndup(z, p - z); + } + } + } else { + /* check for hostname */ + while (*p && *p != ':' && *p != '/') { + /* + * uri = scheme://user:password@host:port/path + * p = ^ ^ + * z = ^ + */ + p++; + } + + if (host != NULL) { + *host = c_strndup(z, p - z); + } + } + + z = p; + + /* check for port */ + if (*p == ':') { + char **e; + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + z = ++p; + + /* get only the digits */ + while (isdigit((int) *p)) { + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + e = (char **) &p; + p++; + } + + if (port != NULL) { + *port = strtoul(z, e, 0); + } + + /* + * uri = scheme://user:password@host:port/path + * p = ^ + * z = ^ + */ + z = p; + } + } + + if (*p == '\0') { + return 0; + } + + /* get the path with the leading slash */ + if (*p == '/') { + if (path != NULL) { + *path = c_strdup(p); + } + + return 0; + } + + return -1; +} + diff --git a/src/std/c_path.h b/src/std/c_path.h index c3cad2519e..df9b81f25a 100644 --- a/src/std/c_path.h +++ b/src/std/c_path.h @@ -1,7 +1,7 @@ /* * cynapses libc functions * - * Copyright (c) 2008 by Andreas Schneider + * Copyright (c) 2007-2008 by Andreas Schneider * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -54,7 +54,7 @@ char *c_dirname(const char *path); /** - * @brief dirname - parse filename component. + * @brief basename - parse filename component. * * basename breaks a null-terminated pathname string into a filename component. * c_basename() returns the component following the final '/'. Trailing '/' @@ -68,6 +68,30 @@ char *c_dirname(const char *path); */ char *c_basename (const char *path); +/** + * @brief parse a uri and split it into components. + * + * parse_uri parses an uri in the format + * + * [:][//[[:]@][:]]/[] + * + * into its compoments. If you only want a special component, + * pass NULL for all other components. All components will be allocated if they have + * been found. + * + * @param uri The uri to parse. + * @param scheme String for the scheme component + * @param user String for the username component + * @param passwd String for the password component + * @param host String for the password component + * @param port Integer for the port + * @param path String for the path component with a leading slash. + * + * @return 0 on success, < 0 on error. + */ +int c_parse_uri(const char *uri, char **scheme, char **user, char **passwd, + char **host, unsigned int *port, char **path); + /** * }@ */