From 699ae7589a04b9730823697e6fe8f95e7506db95 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 25 Jan 2014 15:58:47 +0000 Subject: [PATCH] New hostname-handling functions in misc.c. These are intended to make it easier to handle strings of the form "hostname:port" or other colon-separated things including hostnames (such as the -L and -R command-line option arguments), even though the hostname part might be a square-bracketed IPv6 address literal containing colons that have to _not_ be treated as separating the top-level string components. Three of these functions have semantics as much like existing C library functions as I could make them (host_strchr, host_strrchr, host_strcspn) so that it wouldn't be too error-prone to replace existing C functions with them at lots of call sites. The fourth function (host_strduptrim) just strips square brackets off anything that looks like an IPv6 literal. git-svn-id: http://svn.tartarus.org/sgt/putty@10119 cda61777-01e9-0310-a592-d414129be87e --- misc.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ misc.h | 5 +++ 2 files changed, 132 insertions(+) diff --git a/misc.c b/misc.c index b4fff666..d7c32c49 100644 --- a/misc.c +++ b/misc.c @@ -87,6 +87,133 @@ char ctrlparse(char *s, char **next) return c; } +/* + * Find a character in a string, unless it's a colon contained within + * square brackets. Used for untangling strings of the form + * 'host:port', where host can be an IPv6 literal. + * + * We provide several variants of this function, with semantics like + * various standard string.h functions. + */ +static const char *host_strchr_internal(const char *s, const char *set, + int first) +{ + int brackets = 0; + const char *ret = NULL; + + while (1) { + if (!*s) + return ret; + + if (*s == '[') + brackets++; + else if (*s == ']' && brackets > 0) + brackets--; + else if (brackets && *s == ':') + /* never match */ ; + else if (strchr(set, *s)) { + ret = s; + if (first) + return ret; + } + + s++; + } +} +size_t host_strcspn(const char *s, const char *set) +{ + const char *answer = host_strchr_internal(s, set, TRUE); + if (answer) + return answer - s; + else + return strlen(s); +} +char *host_strchr(const char *s, int c) +{ + char set[2]; + set[0] = c; + set[1] = '\0'; + return (char *) host_strchr_internal(s, set, TRUE); +} +char *host_strrchr(const char *s, int c) +{ + char set[2]; + set[0] = c; + set[1] = '\0'; + return (char *) host_strchr_internal(s, set, FALSE); +} + +#ifdef TEST_HOST_STRFOO +int main(void) +{ + int passes = 0, fails = 0; + +#define TEST1(func, string, arg2, suffix, result) do \ + { \ + const char *str = string; \ + unsigned ret = func(string, arg2) suffix; \ + if (ret == result) { \ + passes++; \ + } else { \ + printf("fail: %s(%s,%s)%s = %u, expected %u\n", \ + #func, #string, #arg2, #suffix, ret, result); \ + fails++; \ + } \ +} while (0) + + TEST1(host_strchr, "[1:2:3]:4:5", ':', -str, 7); + TEST1(host_strrchr, "[1:2:3]:4:5", ':', -str, 9); + TEST1(host_strcspn, "[1:2:3]:4:5", "/:",, 7); + TEST1(host_strchr, "[1:2:3]", ':', == NULL, 1); + TEST1(host_strrchr, "[1:2:3]", ':', == NULL, 1); + TEST1(host_strcspn, "[1:2:3]", "/:",, 7); + TEST1(host_strcspn, "[1:2/3]", "/:",, 4); + TEST1(host_strcspn, "[1:2:3]/", "/:",, 7); + + printf("passed %d failed %d total %d\n", passes, fails, passes+fails); + return fails != 0 ? 1 : 0; +} +/* Stubs to stop the rest of this module causing compile failures. */ +void modalfatalbox(char *fmt, ...) {} +int conf_get_int(Conf *conf, int primary) { return 0; } +char *conf_get_str(Conf *conf, int primary) { return NULL; } +#endif /* TEST_HOST_STRFOO */ + +/* + * Trim square brackets off the outside of an IPv6 address literal. + * Leave all other strings unchanged. Returns a fresh dynamically + * allocated string. + */ +char *host_strduptrim(const char *s) +{ + if (s[0] == '[') { + const char *p = s+1; + int colons = 0; + while (*p && *p != ']') { + if (isxdigit((unsigned char)*p)) + /* OK */; + else if (*p == ':') + colons++; + else + break; + p++; + } + if (*p == ']' && !p[1] && colons > 1) { + /* + * This looks like an IPv6 address literal (hex digits and + * at least two colons, contained in square brackets). + * Trim off the brackets. + */ + return dupprintf("%.*s", (int)(p - (s+1)), s+1); + } + } + + /* + * Any other shape of string is simply duplicated. + */ + return dupstr(s); +} + prompts_t *new_prompts(void *frontend) { prompts_t *p = snew(prompts_t); diff --git a/misc.h b/misc.h index aa761999..d6a80bf0 100644 --- a/misc.h +++ b/misc.h @@ -24,6 +24,11 @@ typedef struct FontSpec FontSpec; unsigned long parse_blocksize(const char *bs); char ctrlparse(char *s, char **next); +size_t host_strcspn(const char *s, const char *set); +char *host_strchr(const char *s, int c); +char *host_strrchr(const char *s, int c); +char *host_strduptrim(const char *s); + char *dupstr(const char *s); char *dupcat(const char *s1, ...); char *dupprintf(const char *fmt, ...) -- 2.45.2