env_attr.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * (C) Copyright 2012
  3. * Joe Hershberger, National Instruments, joe.hershberger@ni.com
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
  8. #include <stdint.h>
  9. #include <stdio.h>
  10. #include <linux/linux_string.h>
  11. #else
  12. #include <common.h>
  13. #endif
  14. #include <env_attr.h>
  15. #include <errno.h>
  16. #include <linux/string.h>
  17. #include <malloc.h>
  18. /*
  19. * Iterate through the whole list calling the callback for each found element.
  20. * "attr_list" takes the form:
  21. * attributes = [^,:\s]*
  22. * entry = name[:attributes]
  23. * list = entry[,list]
  24. */
  25. int env_attr_walk(const char *attr_list,
  26. int (*callback)(const char *name, const char *attributes))
  27. {
  28. const char *entry, *entry_end;
  29. char *name, *attributes;
  30. if (!attr_list)
  31. /* list not found */
  32. return 1;
  33. entry = attr_list;
  34. do {
  35. char *entry_cpy = NULL;
  36. entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
  37. /* check if this is the last entry in the list */
  38. if (entry_end == NULL) {
  39. int entry_len = strlen(entry);
  40. if (entry_len) {
  41. /*
  42. * allocate memory to copy the entry into since
  43. * we will need to inject '\0' chars and squash
  44. * white-space before calling the callback
  45. */
  46. entry_cpy = malloc(entry_len + 1);
  47. if (entry_cpy)
  48. /* copy the rest of the list */
  49. strcpy(entry_cpy, entry);
  50. else
  51. return -ENOMEM;
  52. }
  53. } else {
  54. int entry_len = entry_end - entry;
  55. if (entry_len) {
  56. /*
  57. * allocate memory to copy the entry into since
  58. * we will need to inject '\0' chars and squash
  59. * white-space before calling the callback
  60. */
  61. entry_cpy = malloc(entry_len + 1);
  62. if (entry_cpy) {
  63. /* copy just this entry and null term */
  64. strncpy(entry_cpy, entry, entry_len);
  65. entry_cpy[entry_len] = '\0';
  66. } else
  67. return -ENOMEM;
  68. }
  69. }
  70. /* check if there is anything to process (e.g. not ",,,") */
  71. if (entry_cpy != NULL) {
  72. attributes = strchr(entry_cpy, ENV_ATTR_SEP);
  73. /* check if there is a ':' */
  74. if (attributes != NULL) {
  75. /* replace the ':' with '\0' to term name */
  76. *attributes++ = '\0';
  77. /* remove white-space from attributes */
  78. attributes = strim(attributes);
  79. }
  80. /* remove white-space from name */
  81. name = strim(entry_cpy);
  82. /* only call the callback if there is a name */
  83. if (strlen(name) != 0) {
  84. int retval = 0;
  85. retval = callback(name, attributes);
  86. if (retval) {
  87. free(entry_cpy);
  88. return retval;
  89. }
  90. }
  91. }
  92. free(entry_cpy);
  93. entry = entry_end + 1;
  94. } while (entry_end != NULL);
  95. return 0;
  96. }
  97. /*
  98. * Search for the last matching string in another string with the option to
  99. * start looking at a certain point (i.e. ignore anything beyond that point).
  100. */
  101. static char *reverse_strstr(const char *searched, const char *search_for,
  102. const char *searched_start)
  103. {
  104. char *result = NULL;
  105. if (*search_for == '\0')
  106. return (char *)searched;
  107. for (;;) {
  108. char *match = strstr(searched, search_for);
  109. /*
  110. * Stop looking if no new match is found or looking past the
  111. * searched_start pointer
  112. */
  113. if (match == NULL || (searched_start != NULL &&
  114. match + strlen(search_for) > searched_start))
  115. break;
  116. result = match;
  117. searched = match + 1;
  118. }
  119. return result;
  120. }
  121. /*
  122. * Retrieve the attributes string associated with a single name in the list
  123. * There is no protection on attributes being too small for the value
  124. */
  125. int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
  126. {
  127. const char *entry = NULL;
  128. if (!attributes)
  129. /* bad parameter */
  130. return -1;
  131. if (!attr_list)
  132. /* list not found */
  133. return 1;
  134. entry = reverse_strstr(attr_list, name, NULL);
  135. while (entry != NULL) {
  136. const char *prevch = entry - 1;
  137. const char *nextch = entry + strlen(name);
  138. /* Skip spaces */
  139. while (*prevch == ' ')
  140. prevch--;
  141. while (*nextch == ' ')
  142. nextch++;
  143. /* check for an exact match */
  144. if ((entry == attr_list ||
  145. *prevch == ENV_ATTR_LIST_DELIM) &&
  146. (*nextch == ENV_ATTR_SEP ||
  147. *nextch == ENV_ATTR_LIST_DELIM ||
  148. *nextch == '\0'))
  149. break;
  150. entry = reverse_strstr(attr_list, name, entry);
  151. }
  152. if (entry != NULL) {
  153. int len;
  154. /* skip the name */
  155. entry += strlen(name);
  156. /* skip spaces */
  157. while (*entry == ' ')
  158. entry++;
  159. if (*entry != ENV_ATTR_SEP)
  160. len = 0;
  161. else {
  162. const char *delim;
  163. static const char delims[] = {
  164. ENV_ATTR_LIST_DELIM, ' ', '\0'};
  165. /* skip the attr sep */
  166. entry += 1;
  167. /* skip spaces */
  168. while (*entry == ' ')
  169. entry++;
  170. delim = strpbrk(entry, delims);
  171. if (delim == NULL)
  172. len = strlen(entry);
  173. else
  174. len = delim - entry;
  175. memcpy(attributes, entry, len);
  176. }
  177. attributes[len] = '\0';
  178. /* success */
  179. return 0;
  180. }
  181. /* not found in list */
  182. return 2;
  183. }