blob: b9de16f73e75187b6b909eecdf7f4d9367ece057 [file] [log] [blame]
Joe Hershberger60fd3ad2012-12-11 22:16:24 -06001/*
2 * (C) Copyright 2012
3 * Joe Hershberger, National Instruments, joe.hershberger@ni.com
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Joe Hershberger60fd3ad2012-12-11 22:16:24 -06006 */
7
Joe Hershbergerdd7750a2012-12-11 22:16:32 -06008#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
9#include <stdint.h>
10#include <stdio.h>
11#include <linux/linux_string.h>
12#else
Joe Hershberger60fd3ad2012-12-11 22:16:24 -060013#include <common.h>
Joe Hershbergerdd7750a2012-12-11 22:16:32 -060014#endif
15
Joe Hershberger60fd3ad2012-12-11 22:16:24 -060016#include <env_attr.h>
17#include <errno.h>
18#include <linux/string.h>
19#include <malloc.h>
20
21/*
22 * Iterate through the whole list calling the callback for each found element.
23 * "attr_list" takes the form:
24 * attributes = [^,:\s]*
25 * entry = name[:attributes]
26 * list = entry[,list]
27 */
28int env_attr_walk(const char *attr_list,
Joe Hershbergerd741f562015-05-20 14:27:19 -050029 int (*callback)(const char *name, const char *attributes, void *priv),
30 void *priv)
Joe Hershberger60fd3ad2012-12-11 22:16:24 -060031{
32 const char *entry, *entry_end;
33 char *name, *attributes;
34
35 if (!attr_list)
36 /* list not found */
37 return 1;
38
39 entry = attr_list;
40 do {
41 char *entry_cpy = NULL;
42
43 entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
44 /* check if this is the last entry in the list */
45 if (entry_end == NULL) {
46 int entry_len = strlen(entry);
47
48 if (entry_len) {
49 /*
50 * allocate memory to copy the entry into since
51 * we will need to inject '\0' chars and squash
52 * white-space before calling the callback
53 */
54 entry_cpy = malloc(entry_len + 1);
55 if (entry_cpy)
56 /* copy the rest of the list */
57 strcpy(entry_cpy, entry);
58 else
59 return -ENOMEM;
60 }
61 } else {
62 int entry_len = entry_end - entry;
63
64 if (entry_len) {
65 /*
66 * allocate memory to copy the entry into since
67 * we will need to inject '\0' chars and squash
68 * white-space before calling the callback
69 */
70 entry_cpy = malloc(entry_len + 1);
71 if (entry_cpy) {
72 /* copy just this entry and null term */
73 strncpy(entry_cpy, entry, entry_len);
74 entry_cpy[entry_len] = '\0';
75 } else
76 return -ENOMEM;
77 }
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
93 /* only call the callback if there is a name */
94 if (strlen(name) != 0) {
95 int retval = 0;
96
Joe Hershbergerd741f562015-05-20 14:27:19 -050097 retval = callback(name, attributes, priv);
Joe Hershberger60fd3ad2012-12-11 22:16:24 -060098 if (retval) {
99 free(entry_cpy);
100 return retval;
101 }
102 }
103 }
104
105 free(entry_cpy);
106 entry = entry_end + 1;
107 } while (entry_end != NULL);
108
109 return 0;
110}
111
112/*
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500113 * Search for the last exactly matching name in an attribute list
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600114 */
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500115static int reverse_name_search(const char *searched, const char *search_for,
116 const char **result)
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600117{
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500118 int result_size = 0;
119 const char *cur_searched = searched;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600120
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500121 if (result)
122 *result = NULL;
123
124 if (*search_for == '\0') {
125 if (result)
126 *result = searched;
127 return strlen(searched);
128 }
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600129
130 for (;;) {
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500131 const char *match = strstr(cur_searched, search_for);
132 const char *prevch;
133 const char *nextch;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600134
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500135 /* Stop looking if no new match is found */
136 if (match == NULL)
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600137 break;
138
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500139 prevch = match - 1;
140 nextch = match + strlen(search_for);
141
142 /* Skip spaces */
143 while (*prevch == ' ' && prevch >= searched)
144 prevch--;
145 while (*nextch == ' ')
146 nextch++;
147
148 /* Start looking past the current match so last is found */
149 cur_searched = match + 1;
150 /* Check for an exact match */
151 if (match != searched &&
152 *prevch != ENV_ATTR_LIST_DELIM &&
153 prevch != searched - 1)
154 continue;
155 if (*nextch != ENV_ATTR_SEP &&
156 *nextch != ENV_ATTR_LIST_DELIM &&
157 *nextch != '\0')
158 continue;
159
160 if (result)
161 *result = match;
162 result_size = strlen(search_for);
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600163 }
164
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500165 return result_size;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600166}
167
168/*
169 * Retrieve the attributes string associated with a single name in the list
170 * There is no protection on attributes being too small for the value
171 */
172int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
173{
174 const char *entry = NULL;
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500175 int entry_len;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600176
177 if (!attributes)
178 /* bad parameter */
Joe Hershberger253cf4d2015-05-20 14:27:17 -0500179 return -EINVAL;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600180 if (!attr_list)
181 /* list not found */
Joe Hershberger253cf4d2015-05-20 14:27:17 -0500182 return -EINVAL;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600183
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500184 entry_len = reverse_name_search(attr_list, name, &entry);
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600185 if (entry != NULL) {
186 int len;
187
188 /* skip the name */
Joe Hershbergere163e1c2015-05-20 14:27:18 -0500189 entry += entry_len;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600190 /* skip spaces */
191 while (*entry == ' ')
192 entry++;
193 if (*entry != ENV_ATTR_SEP)
194 len = 0;
195 else {
196 const char *delim;
197 static const char delims[] = {
198 ENV_ATTR_LIST_DELIM, ' ', '\0'};
199
200 /* skip the attr sep */
201 entry += 1;
202 /* skip spaces */
203 while (*entry == ' ')
204 entry++;
205
206 delim = strpbrk(entry, delims);
207 if (delim == NULL)
208 len = strlen(entry);
209 else
210 len = delim - entry;
211 memcpy(attributes, entry, len);
212 }
213 attributes[len] = '\0';
214
215 /* success */
216 return 0;
217 }
218
219 /* not found in list */
Joe Hershberger253cf4d2015-05-20 14:27:17 -0500220 return -ENOENT;
Joe Hershberger60fd3ad2012-12-11 22:16:24 -0600221}