• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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