Imported Upstream version 1.18.1
[platform/upstream/c-ares.git] / src / lib / ares_strsplit.c
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 #if defined(__MVS__)
17 #include <strings.h>
18 #endif
19
20 #include "ares_setup.h"
21 #include "ares_strsplit.h"
22 #include "ares.h"
23 #include "ares_private.h"
24
25 static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive)
26 {
27   size_t len;
28   size_t i;
29
30   len = strlen(str);
31   for (i=0; i<num_elem; i++)
32   {
33     if (insensitive)
34     {
35 #ifdef WIN32
36       if (strnicmp(list[i], str, len) == 0)
37 #else
38       if (strncasecmp(list[i], str, len) == 0)
39 #endif
40         return 1;
41     }
42     else
43     {
44       if (strncmp(list[i], str, len) == 0)
45         return 1;
46     }
47   }
48
49   return 0;
50 }
51
52 static int is_delim(char c, const char *delims, size_t num_delims)
53 {
54   size_t i;
55
56   for (i=0; i<num_delims; i++)
57   {
58     if (c == delims[i])
59       return 1;
60   }
61   return 0;
62 }
63
64
65 void ares_strsplit_free(char **elms, size_t num_elm)
66 {
67   size_t i;
68
69   if (elms == NULL)
70     return;
71
72   for (i=0; i<num_elm; i++)
73     ares_free(elms[i]);
74   ares_free(elms);
75 }
76
77
78 char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm)
79 {
80   char *parsestr;
81   char **temp;
82   char **out;
83   size_t cnt;
84   size_t nelms;
85   size_t in_len;
86   size_t num_delims;
87   size_t i;
88
89   if (in == NULL || delms == NULL || num_elm == NULL)
90     return NULL;
91
92   *num_elm = 0;
93
94   in_len = strlen(in);
95   num_delims = strlen(delms);
96
97   /* Figure out how many elements. */
98   nelms = 1;
99   for (i=0; i<in_len; i++)
100   {
101     if (is_delim(in[i], delms, num_delims))
102     {
103       nelms++;
104     }
105   }
106
107   /* Copy of input so we can cut it up. */
108   parsestr = ares_strdup(in);
109   if (parsestr == NULL)
110     return NULL;
111
112   /* Temporary array to store locations of start of each element
113    * within parsestr. */
114   temp = ares_malloc(nelms * sizeof(*temp));
115   if (temp == NULL)
116   {
117     ares_free(parsestr);
118     return NULL;
119   }
120   temp[0] = parsestr;
121   cnt = 1;
122   for (i=0; i<in_len && cnt<nelms; i++)
123   {
124     if (!is_delim(parsestr[i], delms, num_delims))
125       continue;
126
127     /* Replace sep with NULL. */
128     parsestr[i] = '\0';
129     /* Add the pointer to the array of elements */
130     temp[cnt] = parsestr+i+1;
131     cnt++;
132   }
133
134   /* Copy each element to our output array. */
135   out = ares_malloc(nelms * sizeof(*out));
136   if (out == NULL)
137   {
138     ares_free(parsestr);
139     ares_free(temp);
140     return NULL;
141   }
142
143   nelms = 0;
144   for (i=0; i<cnt; i++)
145   {
146     if (temp[i][0] == '\0')
147       continue;
148
149     if (make_set && list_contains(out, nelms, temp[i], 1))
150       continue;
151
152     out[nelms] = ares_strdup(temp[i]);
153     if (out[nelms] == NULL)
154     {
155       ares_strsplit_free(out, nelms);
156       ares_free(parsestr);
157       ares_free(temp);
158       return NULL;
159     }
160     nelms++;
161   }
162
163
164   /* If there are no elements don't return an empty allocated
165    * array. */
166   if (nelms == 0)
167   {
168     ares_strsplit_free(out, nelms);
169     out = NULL;
170   }
171
172   /* Get the true number of elements (recalculated because of make_set) */
173   *num_elm = nelms;
174
175   ares_free(parsestr);
176   ares_free(temp);
177   return out;
178 }