| /* Copyright (C) 2018 by John Schember <john@nachtimwald.com> |
| * |
| * Permission to use, copy, modify, and distribute this |
| * software and its documentation for any purpose and without |
| * fee is hereby granted, provided that the above copyright |
| * notice appear in all copies and that both that copyright |
| * notice and this permission notice appear in supporting |
| * documentation, and that the name of M.I.T. not be used in |
| * advertising or publicity pertaining to distribution of the |
| * software without specific, written prior permission. |
| * M.I.T. makes no representations about the suitability of |
| * this software for any purpose. It is provided "as is" |
| * without express or implied warranty. |
| */ |
| |
| #include "ares_setup.h" |
| #include "ares_strsplit.h" |
| #include "ares.h" |
| #include "ares_private.h" |
| |
| static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive) |
| { |
| size_t len; |
| size_t i; |
| |
| len = strlen(str); |
| for (i=0; i<num_elem; i++) |
| { |
| if (insensitive) |
| { |
| #ifdef WIN32 |
| if (strnicmp(list[i], str, len) == 0) |
| #else |
| if (strncasecmp(list[i], str, len) == 0) |
| #endif |
| return 1; |
| } |
| else |
| { |
| if (strncmp(list[i], str, len) == 0) |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int is_delim(char c, const char *delims, size_t num_delims) |
| { |
| size_t i; |
| |
| for (i=0; i<num_delims; i++) |
| { |
| if (c == delims[i]) |
| return 1; |
| } |
| return 0; |
| } |
| |
| |
| void ares_strsplit_free(char **elms, size_t num_elm) |
| { |
| size_t i; |
| |
| if (elms == NULL) |
| return; |
| |
| for (i=0; i<num_elm; i++) |
| ares_free(elms[i]); |
| ares_free(elms); |
| } |
| |
| |
| char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm) |
| { |
| char *parsestr; |
| char **temp; |
| char **out; |
| size_t cnt; |
| size_t nelms; |
| size_t in_len; |
| size_t num_delims; |
| size_t i; |
| |
| if (in == NULL || delms == NULL || num_elm == NULL) |
| return NULL; |
| |
| *num_elm = 0; |
| |
| in_len = strlen(in); |
| num_delims = strlen(delms); |
| |
| /* Figure out how many elements. */ |
| nelms = 1; |
| for (i=0; i<in_len; i++) |
| { |
| if (is_delim(in[i], delms, num_delims)) |
| { |
| nelms++; |
| } |
| } |
| |
| /* Copy of input so we can cut it up. */ |
| parsestr = ares_strdup(in); |
| if (parsestr == NULL) |
| return NULL; |
| |
| /* Temporary array to store locations of start of each element |
| * within parsestr. */ |
| temp = ares_malloc(nelms * sizeof(*temp)); |
| if (temp == NULL) |
| { |
| ares_free(parsestr); |
| return NULL; |
| } |
| temp[0] = parsestr; |
| cnt = 1; |
| for (i=0; i<in_len && cnt<nelms; i++) |
| { |
| if (!is_delim(parsestr[i], delms, num_delims)) |
| continue; |
| |
| /* Replace sep with NULL. */ |
| parsestr[i] = '\0'; |
| /* Add the pointer to the array of elements */ |
| temp[cnt] = parsestr+i+1; |
| cnt++; |
| } |
| |
| /* Copy each element to our output array. */ |
| out = ares_malloc(nelms * sizeof(*out)); |
| if (out == NULL) |
| { |
| ares_free(parsestr); |
| ares_free(temp); |
| return NULL; |
| } |
| |
| nelms = 0; |
| for (i=0; i<cnt; i++) |
| { |
| if (temp[i][0] == '\0') |
| continue; |
| |
| if (make_set && list_contains(out, nelms, temp[i], 1)) |
| continue; |
| |
| out[nelms] = ares_strdup(temp[i]); |
| if (out[nelms] == NULL) |
| { |
| ares_strsplit_free(out, nelms); |
| ares_free(parsestr); |
| ares_free(temp); |
| return NULL; |
| } |
| nelms++; |
| } |
| |
| |
| /* If there are no elements don't return an empty allocated |
| * array. */ |
| if (nelms == 0) |
| { |
| ares_strsplit_free(out, nelms); |
| out = NULL; |
| } |
| |
| /* Get the true number of elements (recalculated because of make_set) */ |
| *num_elm = nelms; |
| |
| ares_free(parsestr); |
| ares_free(temp); |
| return out; |
| } |