xref: /OK3568_Linux_fs/u-boot/env/attr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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