1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2012
3*4882a593Smuzhiyun * Joe Hershberger, National Instruments, joe.hershberger@ni.com
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
9*4882a593Smuzhiyun #include <stdint.h>
10*4882a593Smuzhiyun #include <stdio.h>
11*4882a593Smuzhiyun #include <linux/linux_string.h>
12*4882a593Smuzhiyun #else
13*4882a593Smuzhiyun #include <common.h>
14*4882a593Smuzhiyun #include <slre.h>
15*4882a593Smuzhiyun #endif
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <env_attr.h>
18*4882a593Smuzhiyun #include <errno.h>
19*4882a593Smuzhiyun #include <linux/string.h>
20*4882a593Smuzhiyun #include <malloc.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun * Iterate through the whole list calling the callback for each found element.
24*4882a593Smuzhiyun * "attr_list" takes the form:
25*4882a593Smuzhiyun * attributes = [^,:\s]*
26*4882a593Smuzhiyun * entry = name[:attributes]
27*4882a593Smuzhiyun * list = entry[,list]
28*4882a593Smuzhiyun */
env_attr_walk(const char * attr_list,int (* callback)(const char * name,const char * attributes,void * priv),void * priv)29*4882a593Smuzhiyun int env_attr_walk(const char *attr_list,
30*4882a593Smuzhiyun int (*callback)(const char *name, const char *attributes, void *priv),
31*4882a593Smuzhiyun void *priv)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun const char *entry, *entry_end;
34*4882a593Smuzhiyun char *name, *attributes;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun if (!attr_list)
37*4882a593Smuzhiyun /* list not found */
38*4882a593Smuzhiyun return 1;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun entry = attr_list;
41*4882a593Smuzhiyun do {
42*4882a593Smuzhiyun char *entry_cpy = NULL;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
45*4882a593Smuzhiyun /* check if this is the last entry in the list */
46*4882a593Smuzhiyun if (entry_end == NULL) {
47*4882a593Smuzhiyun int entry_len = strlen(entry);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (entry_len) {
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun * allocate memory to copy the entry into since
52*4882a593Smuzhiyun * we will need to inject '\0' chars and squash
53*4882a593Smuzhiyun * white-space before calling the callback
54*4882a593Smuzhiyun */
55*4882a593Smuzhiyun entry_cpy = malloc(entry_len + 1);
56*4882a593Smuzhiyun if (entry_cpy)
57*4882a593Smuzhiyun /* copy the rest of the list */
58*4882a593Smuzhiyun strcpy(entry_cpy, entry);
59*4882a593Smuzhiyun else
60*4882a593Smuzhiyun return -ENOMEM;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun } else {
63*4882a593Smuzhiyun int entry_len = entry_end - entry;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (entry_len) {
66*4882a593Smuzhiyun /*
67*4882a593Smuzhiyun * allocate memory to copy the entry into since
68*4882a593Smuzhiyun * we will need to inject '\0' chars and squash
69*4882a593Smuzhiyun * white-space before calling the callback
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun entry_cpy = malloc(entry_len + 1);
72*4882a593Smuzhiyun if (entry_cpy) {
73*4882a593Smuzhiyun /* copy just this entry and null term */
74*4882a593Smuzhiyun strncpy(entry_cpy, entry, entry_len);
75*4882a593Smuzhiyun entry_cpy[entry_len] = '\0';
76*4882a593Smuzhiyun } else
77*4882a593Smuzhiyun return -ENOMEM;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun /* check if there is anything to process (e.g. not ",,,") */
82*4882a593Smuzhiyun if (entry_cpy != NULL) {
83*4882a593Smuzhiyun attributes = strchr(entry_cpy, ENV_ATTR_SEP);
84*4882a593Smuzhiyun /* check if there is a ':' */
85*4882a593Smuzhiyun if (attributes != NULL) {
86*4882a593Smuzhiyun /* replace the ':' with '\0' to term name */
87*4882a593Smuzhiyun *attributes++ = '\0';
88*4882a593Smuzhiyun /* remove white-space from attributes */
89*4882a593Smuzhiyun attributes = strim(attributes);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun /* remove white-space from name */
92*4882a593Smuzhiyun name = strim(entry_cpy);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* only call the callback if there is a name */
95*4882a593Smuzhiyun if (strlen(name) != 0) {
96*4882a593Smuzhiyun int retval = 0;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun retval = callback(name, attributes, priv);
99*4882a593Smuzhiyun if (retval) {
100*4882a593Smuzhiyun free(entry_cpy);
101*4882a593Smuzhiyun return retval;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun free(entry_cpy);
107*4882a593Smuzhiyun entry = entry_end + 1;
108*4882a593Smuzhiyun } while (entry_end != NULL);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun return 0;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun #if defined(CONFIG_REGEX)
114*4882a593Smuzhiyun struct regex_callback_priv {
115*4882a593Smuzhiyun const char *searched_for;
116*4882a593Smuzhiyun char *regex;
117*4882a593Smuzhiyun char *attributes;
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun
regex_callback(const char * name,const char * attributes,void * priv)120*4882a593Smuzhiyun static int regex_callback(const char *name, const char *attributes, void *priv)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun int retval = 0;
123*4882a593Smuzhiyun struct regex_callback_priv *cbp = (struct regex_callback_priv *)priv;
124*4882a593Smuzhiyun struct slre slre;
125*4882a593Smuzhiyun char regex[strlen(name) + 3];
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* Require the whole string to be described by the regex */
128*4882a593Smuzhiyun sprintf(regex, "^%s$", name);
129*4882a593Smuzhiyun if (slre_compile(&slre, regex)) {
130*4882a593Smuzhiyun struct cap caps[slre.num_caps + 2];
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (slre_match(&slre, cbp->searched_for,
133*4882a593Smuzhiyun strlen(cbp->searched_for), caps)) {
134*4882a593Smuzhiyun free(cbp->regex);
135*4882a593Smuzhiyun if (!attributes) {
136*4882a593Smuzhiyun retval = -EINVAL;
137*4882a593Smuzhiyun goto done;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun cbp->regex = malloc(strlen(regex) + 1);
140*4882a593Smuzhiyun if (cbp->regex) {
141*4882a593Smuzhiyun strcpy(cbp->regex, regex);
142*4882a593Smuzhiyun } else {
143*4882a593Smuzhiyun retval = -ENOMEM;
144*4882a593Smuzhiyun goto done;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun free(cbp->attributes);
148*4882a593Smuzhiyun cbp->attributes = malloc(strlen(attributes) + 1);
149*4882a593Smuzhiyun if (cbp->attributes) {
150*4882a593Smuzhiyun strcpy(cbp->attributes, attributes);
151*4882a593Smuzhiyun } else {
152*4882a593Smuzhiyun retval = -ENOMEM;
153*4882a593Smuzhiyun free(cbp->regex);
154*4882a593Smuzhiyun cbp->regex = NULL;
155*4882a593Smuzhiyun goto done;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun } else {
159*4882a593Smuzhiyun printf("Error compiling regex: %s\n", slre.err_str);
160*4882a593Smuzhiyun retval = -EINVAL;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun done:
163*4882a593Smuzhiyun return retval;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /*
167*4882a593Smuzhiyun * Retrieve the attributes string associated with a single name in the list
168*4882a593Smuzhiyun * There is no protection on attributes being too small for the value
169*4882a593Smuzhiyun */
env_attr_lookup(const char * attr_list,const char * name,char * attributes)170*4882a593Smuzhiyun int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun if (!attributes)
173*4882a593Smuzhiyun /* bad parameter */
174*4882a593Smuzhiyun return -EINVAL;
175*4882a593Smuzhiyun if (!attr_list)
176*4882a593Smuzhiyun /* list not found */
177*4882a593Smuzhiyun return -EINVAL;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun struct regex_callback_priv priv;
180*4882a593Smuzhiyun int retval;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun priv.searched_for = name;
183*4882a593Smuzhiyun priv.regex = NULL;
184*4882a593Smuzhiyun priv.attributes = NULL;
185*4882a593Smuzhiyun retval = env_attr_walk(attr_list, regex_callback, &priv);
186*4882a593Smuzhiyun if (retval)
187*4882a593Smuzhiyun return retval; /* error */
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (priv.regex) {
190*4882a593Smuzhiyun strcpy(attributes, priv.attributes);
191*4882a593Smuzhiyun free(priv.attributes);
192*4882a593Smuzhiyun free(priv.regex);
193*4882a593Smuzhiyun /* success */
194*4882a593Smuzhiyun return 0;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun return -ENOENT; /* not found in list */
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun #else
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun * Search for the last exactly matching name in an attribute list
202*4882a593Smuzhiyun */
reverse_name_search(const char * searched,const char * search_for,const char ** result)203*4882a593Smuzhiyun static int reverse_name_search(const char *searched, const char *search_for,
204*4882a593Smuzhiyun const char **result)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun int result_size = 0;
207*4882a593Smuzhiyun const char *cur_searched = searched;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun if (result)
210*4882a593Smuzhiyun *result = NULL;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (*search_for == '\0') {
213*4882a593Smuzhiyun if (result)
214*4882a593Smuzhiyun *result = searched;
215*4882a593Smuzhiyun return strlen(searched);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun for (;;) {
219*4882a593Smuzhiyun const char *match = strstr(cur_searched, search_for);
220*4882a593Smuzhiyun const char *prevch;
221*4882a593Smuzhiyun const char *nextch;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* Stop looking if no new match is found */
224*4882a593Smuzhiyun if (match == NULL)
225*4882a593Smuzhiyun break;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun prevch = match - 1;
228*4882a593Smuzhiyun nextch = match + strlen(search_for);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /* Skip spaces */
231*4882a593Smuzhiyun while (*prevch == ' ' && prevch >= searched)
232*4882a593Smuzhiyun prevch--;
233*4882a593Smuzhiyun while (*nextch == ' ')
234*4882a593Smuzhiyun nextch++;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /* Start looking past the current match so last is found */
237*4882a593Smuzhiyun cur_searched = match + 1;
238*4882a593Smuzhiyun /* Check for an exact match */
239*4882a593Smuzhiyun if (match != searched &&
240*4882a593Smuzhiyun *prevch != ENV_ATTR_LIST_DELIM &&
241*4882a593Smuzhiyun prevch != searched - 1)
242*4882a593Smuzhiyun continue;
243*4882a593Smuzhiyun if (*nextch != ENV_ATTR_SEP &&
244*4882a593Smuzhiyun *nextch != ENV_ATTR_LIST_DELIM &&
245*4882a593Smuzhiyun *nextch != '\0')
246*4882a593Smuzhiyun continue;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (result)
249*4882a593Smuzhiyun *result = match;
250*4882a593Smuzhiyun result_size = strlen(search_for);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun return result_size;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /*
257*4882a593Smuzhiyun * Retrieve the attributes string associated with a single name in the list
258*4882a593Smuzhiyun * There is no protection on attributes being too small for the value
259*4882a593Smuzhiyun */
env_attr_lookup(const char * attr_list,const char * name,char * attributes)260*4882a593Smuzhiyun int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun const char *entry = NULL;
263*4882a593Smuzhiyun int entry_len;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (!attributes)
266*4882a593Smuzhiyun /* bad parameter */
267*4882a593Smuzhiyun return -EINVAL;
268*4882a593Smuzhiyun if (!attr_list)
269*4882a593Smuzhiyun /* list not found */
270*4882a593Smuzhiyun return -EINVAL;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun entry_len = reverse_name_search(attr_list, name, &entry);
273*4882a593Smuzhiyun if (entry != NULL) {
274*4882a593Smuzhiyun int len;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* skip the name */
277*4882a593Smuzhiyun entry += entry_len;
278*4882a593Smuzhiyun /* skip spaces */
279*4882a593Smuzhiyun while (*entry == ' ')
280*4882a593Smuzhiyun entry++;
281*4882a593Smuzhiyun if (*entry != ENV_ATTR_SEP)
282*4882a593Smuzhiyun len = 0;
283*4882a593Smuzhiyun else {
284*4882a593Smuzhiyun const char *delim;
285*4882a593Smuzhiyun static const char delims[] = {
286*4882a593Smuzhiyun ENV_ATTR_LIST_DELIM, ' ', '\0'};
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /* skip the attr sep */
289*4882a593Smuzhiyun entry += 1;
290*4882a593Smuzhiyun /* skip spaces */
291*4882a593Smuzhiyun while (*entry == ' ')
292*4882a593Smuzhiyun entry++;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun delim = strpbrk(entry, delims);
295*4882a593Smuzhiyun if (delim == NULL)
296*4882a593Smuzhiyun len = strlen(entry);
297*4882a593Smuzhiyun else
298*4882a593Smuzhiyun len = delim - entry;
299*4882a593Smuzhiyun memcpy(attributes, entry, len);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun attributes[len] = '\0';
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /* success */
304*4882a593Smuzhiyun return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun /* not found in list */
308*4882a593Smuzhiyun return -ENOENT;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun #endif
311