1 /* Copyright (C) 2018 by John Schember <john@nachtimwald.com>
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
14 */
15
16 #include "ares_setup.h"
17 #include "ares_strsplit.h"
18 #include "ares.h"
19 #include "ares_private.h"
20
list_contains(char * const * list,size_t num_elem,const char * str,int insensitive)21 static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive)
22 {
23 size_t len;
24 size_t i;
25
26 len = strlen(str);
27 for (i=0; i<num_elem; i++)
28 {
29 if (insensitive)
30 {
31 #ifdef WIN32
32 if (strnicmp(list[i], str, len) == 0)
33 #else
34 if (strncasecmp(list[i], str, len) == 0)
35 #endif
36 return 1;
37 }
38 else
39 {
40 if (strncmp(list[i], str, len) == 0)
41 return 1;
42 }
43 }
44
45 return 0;
46 }
47
is_delim(char c,const char * delims,size_t num_delims)48 static int is_delim(char c, const char *delims, size_t num_delims)
49 {
50 size_t i;
51
52 for (i=0; i<num_delims; i++)
53 {
54 if (c == delims[i])
55 return 1;
56 }
57 return 0;
58 }
59
60
ares_strsplit_free(char ** elms,size_t num_elm)61 void ares_strsplit_free(char **elms, size_t num_elm)
62 {
63 size_t i;
64
65 if (elms == NULL)
66 return;
67
68 for (i=0; i<num_elm; i++)
69 ares_free(elms[i]);
70 ares_free(elms);
71 }
72
73
ares_strsplit(const char * in,const char * delms,int make_set,size_t * num_elm)74 char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm)
75 {
76 char *parsestr;
77 char **temp;
78 char **out;
79 size_t cnt;
80 size_t nelms;
81 size_t in_len;
82 size_t num_delims;
83 size_t i;
84
85 if (in == NULL || delms == NULL || num_elm == NULL)
86 return NULL;
87
88 *num_elm = 0;
89
90 in_len = strlen(in);
91 num_delims = strlen(delms);
92
93 /* Figure out how many elements. */
94 nelms = 1;
95 for (i=0; i<in_len; i++)
96 {
97 if (is_delim(in[i], delms, num_delims))
98 {
99 nelms++;
100 }
101 }
102
103 /* Copy of input so we can cut it up. */
104 parsestr = ares_strdup(in);
105 if (parsestr == NULL)
106 return NULL;
107
108 /* Temporary array to store locations of start of each element
109 * within parsestr. */
110 temp = ares_malloc(nelms * sizeof(*temp));
111 if (temp == NULL)
112 {
113 ares_free(parsestr);
114 return NULL;
115 }
116 temp[0] = parsestr;
117 cnt = 1;
118 for (i=0; i<in_len && cnt<nelms; i++)
119 {
120 if (!is_delim(parsestr[i], delms, num_delims))
121 continue;
122
123 /* Replace sep with NULL. */
124 parsestr[i] = '\0';
125 /* Add the pointer to the array of elements */
126 temp[cnt] = parsestr+i+1;
127 cnt++;
128 }
129
130 /* Copy each element to our output array. */
131 out = ares_malloc(nelms * sizeof(*out));
132 if (out == NULL)
133 {
134 ares_free(parsestr);
135 ares_free(temp);
136 return NULL;
137 }
138
139 nelms = 0;
140 for (i=0; i<cnt; i++)
141 {
142 if (temp[i][0] == '\0')
143 continue;
144
145 if (make_set && list_contains(out, nelms, temp[i], 1))
146 continue;
147
148 out[nelms] = ares_strdup(temp[i]);
149 if (out[nelms] == NULL)
150 {
151 ares_strsplit_free(out, nelms);
152 ares_free(parsestr);
153 ares_free(temp);
154 return NULL;
155 }
156 nelms++;
157 }
158
159
160 /* If there are no elements don't return an empty allocated
161 * array. */
162 if (nelms == 0)
163 {
164 ares_strsplit_free(out, nelms);
165 out = NULL;
166 }
167
168 /* Get the true number of elements (recalculated because of make_set) */
169 *num_elm = nelms;
170
171 ares_free(parsestr);
172 ares_free(temp);
173 return out;
174 }
175