1 /* MIT License
2 *
3 * Copyright (c) 1998 Massachusetts Institute of Technology
4 * Copyright (c) The c-ares project and its contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * SPDX-License-Identifier: MIT
26 */
27
28 #include "ares_private.h"
29 #include "ares_str.h"
30
31 #ifdef HAVE_STDINT_H
32 # include <stdint.h>
33 #endif
34
ares_strnlen(const char * str,size_t maxlen)35 size_t ares_strnlen(const char *str, size_t maxlen) {
36 const char *p = NULL;
37 if (str == NULL) {
38 return 0;
39 }
40 #ifdef HAVE_STRNLEN
41 (void)p;
42 return strnlen(str, maxlen);
43 #else
44 if ((p = memchr(str, 0, maxlen)) == NULL) {
45 return maxlen;
46 } else {
47 return (size_t)(p - str);
48 }
49 #endif /* HAVE_STRNLEN */
50 }
51
ares_strlen(const char * str)52 size_t ares_strlen(const char *str)
53 {
54 if (str == NULL) {
55 return 0;
56 }
57
58 return strlen(str);
59 }
60
ares_strdup(const char * s1)61 char *ares_strdup(const char *s1)
62 {
63 size_t len;
64 char *out;
65
66 if (s1 == NULL) {
67 return NULL;
68 }
69
70 len = ares_strlen(s1);
71
72 /* Don't see how this is possible */
73 if (len == SIZE_MAX) {
74 return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */
75 }
76
77 out = ares_malloc(len + 1);
78 if (out == NULL) {
79 return NULL;
80 }
81
82 if (len) {
83 memcpy(out, s1, len);
84 }
85
86 out[len] = 0;
87 return out;
88 }
89
ares_strcpy(char * dest,const char * src,size_t dest_size)90 size_t ares_strcpy(char *dest, const char *src, size_t dest_size)
91 {
92 size_t len = 0;
93
94 if (dest == NULL || dest_size == 0) {
95 return 0; /* LCOV_EXCL_LINE: DefensiveCoding */
96 }
97
98 len = ares_strlen(src);
99
100 if (len >= dest_size) {
101 len = dest_size - 1;
102 }
103
104 if (len) {
105 memcpy(dest, src, len);
106 }
107
108 dest[len] = 0;
109 return len;
110 }
111
ares_str_isnum(const char * str)112 ares_bool_t ares_str_isnum(const char *str)
113 {
114 size_t i;
115
116 if (str == NULL || *str == 0) {
117 return ARES_FALSE;
118 }
119
120 for (i = 0; str[i] != 0; i++) {
121 if (!ares_isdigit(str[i])) {
122 return ARES_FALSE;
123 }
124 }
125 return ARES_TRUE;
126 }
127
ares_str_isalnum(const char * str)128 ares_bool_t ares_str_isalnum(const char *str)
129 {
130 size_t i;
131
132 if (str == NULL || *str == 0) {
133 return ARES_FALSE;
134 }
135
136 for (i = 0; str[i] != 0; i++) {
137 if (!ares_isdigit(str[i]) && !ares_isalpha(str[i])) {
138 return ARES_FALSE;
139 }
140 }
141 return ARES_TRUE;
142 }
143
ares_str_rtrim(char * str)144 void ares_str_rtrim(char *str)
145 {
146 size_t len;
147 size_t i;
148
149 if (str == NULL) {
150 return; /* LCOV_EXCL_LINE: DefensiveCoding */
151 }
152
153 len = ares_strlen(str);
154 for (i = len; i > 0; i--) {
155 if (!ares_isspace(str[i - 1])) {
156 break;
157 }
158 }
159 str[i] = 0;
160 }
161
ares_str_ltrim(char * str)162 void ares_str_ltrim(char *str)
163 {
164 size_t i;
165 size_t len;
166
167 if (str == NULL) {
168 return; /* LCOV_EXCL_LINE: DefensiveCoding */
169 }
170
171 for (i = 0; str[i] != 0 && ares_isspace(str[i]); i++) {
172 /* Do nothing */
173 }
174
175 if (i == 0) {
176 return;
177 }
178
179 len = ares_strlen(str);
180 if (i != len) {
181 memmove(str, str + i, len - i);
182 }
183 str[len - i] = 0;
184 }
185
ares_str_trim(char * str)186 void ares_str_trim(char *str)
187 {
188 ares_str_ltrim(str);
189 ares_str_rtrim(str);
190 }
191
192 /* tolower() is locale-specific. Use a lookup table fast conversion that only
193 * operates on ASCII */
194 static const unsigned char ares_tolower_lookup[] = {
195 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
196 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
197 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
198 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33,
199 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
200 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
201 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
202 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
203 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
204 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81,
205 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E,
206 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B,
207 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
208 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5,
209 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2,
210 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
211 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC,
212 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
213 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
214 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
215 };
216
ares_tolower(unsigned char c)217 unsigned char ares_tolower(unsigned char c)
218 {
219 return ares_tolower_lookup[c];
220 }
221
ares_str_lower(char * str)222 void ares_str_lower(char *str)
223 {
224 size_t i;
225
226 if (str == NULL) {
227 return;
228 }
229
230 for (i = 0; str[i] != 0; i++) {
231 str[i] = (char)ares_tolower((unsigned char)str[i]);
232 }
233 }
234
ares_memmem(const unsigned char * big,size_t big_len,const unsigned char * little,size_t little_len)235 unsigned char *ares_memmem(const unsigned char *big, size_t big_len,
236 const unsigned char *little, size_t little_len)
237 {
238 unsigned char *ptr;
239
240 if (big == NULL || little == NULL || big_len == 0 || little_len == 0) {
241 return NULL;
242 }
243
244 #ifdef HAVE_MEMMEM
245 ptr = memmem(big, big_len, little, little_len);
246 return ptr;
247 #else
248 while (1) {
249 ptr = memchr(big, little[0], big_len);
250 if (ptr == NULL) {
251 break;
252 }
253
254 big_len -= (size_t)(ptr - big);
255 big = ptr;
256 if (big_len < little_len) {
257 break;
258 }
259
260 if (memcmp(big, little, little_len) == 0) {
261 return ptr;
262 }
263
264 big++;
265 big_len--;
266 }
267
268 return NULL;
269 #endif
270 }
271
ares_memeq(const unsigned char * ptr,const unsigned char * val,size_t len)272 ares_bool_t ares_memeq(const unsigned char *ptr, const unsigned char *val,
273 size_t len)
274 {
275 return memcmp(ptr, val, len) == 0 ? ARES_TRUE : ARES_FALSE;
276 }
277
ares_memeq_ci(const unsigned char * ptr,const unsigned char * val,size_t len)278 ares_bool_t ares_memeq_ci(const unsigned char *ptr, const unsigned char *val,
279 size_t len)
280 {
281 size_t i;
282 for (i = 0; i < len; i++) {
283 if (ares_tolower_lookup[ptr[i]] != ares_tolower_lookup[val[i]]) {
284 return ARES_FALSE;
285 }
286 }
287 return ARES_TRUE;
288 }
289
ares_is_hostname(const char * str)290 ares_bool_t ares_is_hostname(const char *str)
291 {
292 size_t i;
293
294 if (str == NULL) {
295 return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */
296 }
297
298 for (i = 0; str[i] != 0; i++) {
299 if (!ares_is_hostnamech(str[i])) {
300 return ARES_FALSE;
301 }
302 }
303 return ARES_TRUE;
304 }
305
ares_str_isprint(const char * str,size_t len)306 ares_bool_t ares_str_isprint(const char *str, size_t len)
307 {
308 size_t i;
309
310 if (str == NULL && len != 0) {
311 return ARES_FALSE;
312 }
313
314 for (i = 0; i < len; i++) {
315 if (!ares_isprint(str[i])) {
316 return ARES_FALSE;
317 }
318 }
319 return ARES_TRUE;
320 }
321
ares_strcmp(const char * a,const char * b)322 int ares_strcmp(const char *a, const char *b)
323 {
324 if (a == NULL && b == NULL) {
325 return 0;
326 }
327
328 if (a != NULL && b == NULL) {
329 if (*a == 0) {
330 return 0;
331 }
332 return 1;
333 }
334
335 if (a == NULL && b != NULL) {
336 if (*b == 0) {
337 return 0;
338 }
339 return -1;
340 }
341
342 return strcmp(a, b);
343 }
344
ares_strncmp(const char * a,const char * b,size_t n)345 int ares_strncmp(const char *a, const char *b, size_t n)
346 {
347 if (n == 0) {
348 return 0;
349 }
350
351 if (a == NULL && b == NULL) {
352 return 0;
353 }
354
355 if (a != NULL && b == NULL) {
356 if (*a == 0) {
357 return 0;
358 }
359 return 1;
360 }
361
362 if (a == NULL && b != NULL) {
363 if (*b == 0) {
364 return 0;
365 }
366 return -1;
367 }
368
369 return strncmp(a, b, n);
370 }
371
ares_strcasecmp(const char * a,const char * b)372 int ares_strcasecmp(const char *a, const char *b)
373 {
374 if (a == NULL && b == NULL) {
375 return 0;
376 }
377
378 if (a != NULL && b == NULL) {
379 if (*a == 0) {
380 return 0;
381 }
382 return 1;
383 }
384
385 if (a == NULL && b != NULL) {
386 if (*b == 0) {
387 return 0;
388 }
389 return -1;
390 }
391
392 #if defined(HAVE_STRCASECMP)
393 return strcasecmp(a, b);
394 #elif defined(HAVE_STRCMPI)
395 return strcmpi(a, b);
396 #elif defined(HAVE_STRICMP)
397 return stricmp(a, b);
398 #else
399 {
400 size_t i;
401
402 for (i = 0; i < (size_t)-1; i++) {
403 int c1 = ares_tolower(a[i]);
404 int c2 = ares_tolower(b[i]);
405 if (c1 != c2) {
406 return c1 - c2;
407 }
408 if (!c1) {
409 break;
410 }
411 }
412 }
413 return 0;
414 #endif
415 }
416
ares_strncasecmp(const char * a,const char * b,size_t n)417 int ares_strncasecmp(const char *a, const char *b, size_t n)
418 {
419 if (n == 0) {
420 return 0;
421 }
422
423 if (a == NULL && b == NULL) {
424 return 0;
425 }
426
427 if (a != NULL && b == NULL) {
428 if (*a == 0) {
429 return 0;
430 }
431 return 1;
432 }
433
434 if (a == NULL && b != NULL) {
435 if (*b == 0) {
436 return 0;
437 }
438 return -1;
439 }
440
441 #if defined(HAVE_STRNCASECMP)
442 return strncasecmp(a, b, n);
443 #elif defined(HAVE_STRNCMPI)
444 return strncmpi(a, b, n);
445 #elif defined(HAVE_STRNICMP)
446 return strnicmp(a, b, n);
447 #else
448 {
449 size_t i;
450
451 for (i = 0; i < n; i++) {
452 int c1 = ares_tolower(a[i]);
453 int c2 = ares_tolower(b[i]);
454 if (c1 != c2) {
455 return c1 - c2;
456 }
457 if (!c1) {
458 break;
459 }
460 }
461 }
462 return 0;
463 #endif
464 }
465
ares_strcaseeq(const char * a,const char * b)466 ares_bool_t ares_strcaseeq(const char *a, const char *b)
467 {
468 return ares_strcasecmp(a, b) == 0 ? ARES_TRUE : ARES_FALSE;
469 }
470
ares_strcaseeq_max(const char * a,const char * b,size_t n)471 ares_bool_t ares_strcaseeq_max(const char *a, const char *b, size_t n)
472 {
473 return ares_strncasecmp(a, b, n) == 0 ? ARES_TRUE : ARES_FALSE;
474 }
475
ares_streq(const char * a,const char * b)476 ares_bool_t ares_streq(const char *a, const char *b)
477 {
478 return ares_strcmp(a, b) == 0 ? ARES_TRUE : ARES_FALSE;
479 }
480
ares_streq_max(const char * a,const char * b,size_t n)481 ares_bool_t ares_streq_max(const char *a, const char *b, size_t n)
482 {
483 return ares_strncmp(a, b, n) == 0 ? ARES_TRUE : ARES_FALSE;
484 }
485
ares_free_array(void * arrp,size_t nmembers,void (* freefunc)(void *))486 void ares_free_array(void *arrp, size_t nmembers, void (*freefunc)(void *))
487 {
488 size_t i;
489 void **arr = arrp;
490
491 if (arr == NULL) {
492 return;
493 }
494
495 if (freefunc != NULL) {
496 if (nmembers == SIZE_MAX) {
497 for (i = 0; arr[i] != NULL; i++) {
498 freefunc(arr[i]);
499 }
500 } else {
501 for (i = 0; i < nmembers; i++) {
502 freefunc(arr[i]);
503 }
504 }
505 }
506
507 ares_free(arr);
508 }
509