host_strchr_internal.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. /*
  2. * Find a character in a string, unless it's a colon contained within
  3. * square brackets. Used for untangling strings of the form
  4. * 'host:port', where host can be an IPv6 literal.
  5. *
  6. * This internal function provides an API that's a bit like strchr (in
  7. * that it returns a pointer to the character it found, or NULL), and
  8. * a bit like strcspn (in that you can give it a set of characters to
  9. * look for, not just one). Also it has an option to return the first
  10. * or last character it finds. Other functions in the utils directory
  11. * provide wrappers on it with APIs more like familiar <string.h>
  12. * functions.
  13. */
  14. #include <stdbool.h>
  15. #include <string.h>
  16. #include "defs.h"
  17. #include "misc.h"
  18. #include "utils/utils.h"
  19. const char *host_strchr_internal(const char *s, const char *set, bool first)
  20. {
  21. int brackets = 0;
  22. const char *ret = NULL;
  23. while (1) {
  24. if (!*s)
  25. return ret;
  26. if (*s == '[')
  27. brackets++;
  28. else if (*s == ']' && brackets > 0)
  29. brackets--;
  30. else if (brackets && *s == ':')
  31. /* never match */ ;
  32. else if (strchr(set, *s)) {
  33. ret = s;
  34. if (first)
  35. return ret;
  36. }
  37. s++;
  38. }
  39. }
  40. #ifdef TEST
  41. int main(void)
  42. {
  43. int passes = 0, fails = 0;
  44. #define TEST1(func, string, arg2, suffix, result) do \
  45. { \
  46. const char *str = string; \
  47. unsigned ret = func(str, arg2) suffix; \
  48. if (ret == result) { \
  49. passes++; \
  50. } else { \
  51. printf("fail: %s(%s,%s)%s = %u, expected %u\n", \
  52. #func, #string, #arg2, #suffix, ret, \
  53. (unsigned)result); \
  54. fails++; \
  55. } \
  56. } while (0)
  57. TEST1(host_strchr, "[1:2:3]:4:5", ':', -str, 7);
  58. TEST1(host_strrchr, "[1:2:3]:4:5", ':', -str, 9);
  59. TEST1(host_strcspn, "[1:2:3]:4:5", "/:",, 7);
  60. TEST1(host_strchr, "[1:2:3]", ':', == NULL, 1);
  61. TEST1(host_strrchr, "[1:2:3]", ':', == NULL, 1);
  62. TEST1(host_strcspn, "[1:2:3]", "/:",, 7);
  63. TEST1(host_strcspn, "[1:2/3]", "/:",, 4);
  64. TEST1(host_strcspn, "[1:2:3]/", "/:",, 7);
  65. printf("passed %d failed %d total %d\n", passes, fails, passes+fails);
  66. return fails != 0 ? 1 : 0;
  67. }
  68. #endif /* TEST */