env_attr.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * (C) Copyright 2012
  3. * Joe Hershberger, National Instruments, joe.hershberger@ni.com
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <env_attr.h>
  25. #include <errno.h>
  26. #include <linux/string.h>
  27. #include <malloc.h>
  28. /*
  29. * Iterate through the whole list calling the callback for each found element.
  30. * "attr_list" takes the form:
  31. * attributes = [^,:\s]*
  32. * entry = name[:attributes]
  33. * list = entry[,list]
  34. */
  35. int env_attr_walk(const char *attr_list,
  36. int (*callback)(const char *name, const char *attributes))
  37. {
  38. const char *entry, *entry_end;
  39. char *name, *attributes;
  40. if (!attr_list)
  41. /* list not found */
  42. return 1;
  43. entry = attr_list;
  44. do {
  45. char *entry_cpy = NULL;
  46. entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
  47. /* check if this is the last entry in the list */
  48. if (entry_end == NULL) {
  49. int entry_len = strlen(entry);
  50. if (entry_len) {
  51. /*
  52. * allocate memory to copy the entry into since
  53. * we will need to inject '\0' chars and squash
  54. * white-space before calling the callback
  55. */
  56. entry_cpy = malloc(entry_len + 1);
  57. if (entry_cpy)
  58. /* copy the rest of the list */
  59. strcpy(entry_cpy, entry);
  60. else
  61. return -ENOMEM;
  62. }
  63. } else {
  64. int entry_len = entry_end - entry;
  65. if (entry_len) {
  66. /*
  67. * allocate memory to copy the entry into since
  68. * we will need to inject '\0' chars and squash
  69. * white-space before calling the callback
  70. */
  71. entry_cpy = malloc(entry_len + 1);
  72. if (entry_cpy) {
  73. /* copy just this entry and null term */
  74. strncpy(entry_cpy, entry, entry_len);
  75. entry_cpy[entry_len] = '\0';
  76. } else
  77. return -ENOMEM;
  78. }
  79. }
  80. /* check if there is anything to process (e.g. not ",,,") */
  81. if (entry_cpy != NULL) {
  82. attributes = strchr(entry_cpy, ENV_ATTR_SEP);
  83. /* check if there is a ':' */
  84. if (attributes != NULL) {
  85. /* replace the ':' with '\0' to term name */
  86. *attributes++ = '\0';
  87. /* remove white-space from attributes */
  88. attributes = strim(attributes);
  89. }
  90. /* remove white-space from name */
  91. name = strim(entry_cpy);
  92. /* only call the callback if there is a name */
  93. if (strlen(name) != 0) {
  94. int retval = 0;
  95. retval = callback(name, attributes);
  96. if (retval) {
  97. free(entry_cpy);
  98. return retval;
  99. }
  100. }
  101. }
  102. free(entry_cpy);
  103. entry = entry_end + 1;
  104. } while (entry_end != NULL);
  105. return 0;
  106. }
  107. /*
  108. * Search for the last matching string in another string with the option to
  109. * start looking at a certain point (i.e. ignore anything beyond that point).
  110. */
  111. static char *reverse_strstr(const char *searched, const char *search_for,
  112. const char *searched_start)
  113. {
  114. char *result = NULL;
  115. if (*search_for == '\0')
  116. return (char *)searched;
  117. for (;;) {
  118. char *match = strstr(searched, search_for);
  119. /*
  120. * Stop looking if no new match is found or looking past the
  121. * searched_start pointer
  122. */
  123. if (match == NULL || (searched_start != NULL &&
  124. match + strlen(search_for) > searched_start))
  125. break;
  126. result = match;
  127. searched = match + 1;
  128. }
  129. return result;
  130. }
  131. /*
  132. * Retrieve the attributes string associated with a single name in the list
  133. * There is no protection on attributes being too small for the value
  134. */
  135. int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
  136. {
  137. const char *entry = NULL;
  138. if (!attributes)
  139. /* bad parameter */
  140. return -1;
  141. if (!attr_list)
  142. /* list not found */
  143. return 1;
  144. entry = reverse_strstr(attr_list, name, NULL);
  145. while (entry != NULL) {
  146. const char *prevch = entry - 1;
  147. const char *nextch = entry + strlen(name);
  148. /* Skip spaces */
  149. while (*prevch == ' ')
  150. prevch--;
  151. while (*nextch == ' ')
  152. nextch++;
  153. /* check for an exact match */
  154. if ((entry == attr_list ||
  155. *prevch == ENV_ATTR_LIST_DELIM) &&
  156. (*nextch == ENV_ATTR_SEP ||
  157. *nextch == ENV_ATTR_LIST_DELIM ||
  158. *nextch == '\0'))
  159. break;
  160. entry = reverse_strstr(attr_list, name, entry);
  161. }
  162. if (entry != NULL) {
  163. int len;
  164. /* skip the name */
  165. entry += strlen(name);
  166. /* skip spaces */
  167. while (*entry == ' ')
  168. entry++;
  169. if (*entry != ENV_ATTR_SEP)
  170. len = 0;
  171. else {
  172. const char *delim;
  173. static const char delims[] = {
  174. ENV_ATTR_LIST_DELIM, ' ', '\0'};
  175. /* skip the attr sep */
  176. entry += 1;
  177. /* skip spaces */
  178. while (*entry == ' ')
  179. entry++;
  180. delim = strpbrk(entry, delims);
  181. if (delim == NULL)
  182. len = strlen(entry);
  183. else
  184. len = delim - entry;
  185. memcpy(attributes, entry, len);
  186. }
  187. attributes[len] = '\0';
  188. /* success */
  189. return 0;
  190. }
  191. /* not found in list */
  192. return 2;
  193. }