ares_strsplit.c 3.5 KB

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