1 /*
2  * Copyright (C) 2018-2022 Intel Corporation.
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include <string.h>
7 #include <errno.h>
8 #include <regex.h>
9 #include <stdarg.h>
10 #include <stdlib.h>
11 #include "log_sys.h"
12 #include "fsutils.h"
13 
14 /**
15  * Find the first line containing specified string in given area.
16  *
17  * @param str A pointer to the string contained by target line.
18  * @param str_size String length of str.
19  * @param area A pointer to the area where target line may be located.
20  *             This pointer will be returned if the specified string is in
21  *             the first line of area (There is not '\n' located between area
22  *             and the head of searched string).
23  * @param area_size String length of area.
24  * @param search_from A pointer where searching starts. It should be greater
25  *                    than or equal to area, and less than area + area_size.
26  * @param[out] len The length of target line (excludes \n), it only be modified
27  *             when function returns successfully.
28  *
29  * @return a pointer to the head of target line within area (it may be greater
30  *         than search_from).
31  *         NULL will be returned if the specified string is not found in
32  *         any lines (lines must end with '\n'. It means the real searching
33  *         scope is from search_from to the last '\n' in area).
34  */
get_line(const char * str,size_t str_size,const char * area,size_t area_size,const char * search_from,size_t * len)35 char *get_line(const char *str, size_t str_size,
36 		const char *area, size_t area_size,
37 		const char *search_from, size_t *len)
38 {
39 	char *p;
40 	char *match;
41 	char *tail;
42 	ssize_t search_size = area + area_size - search_from;
43 
44 	if (!str || !str_size || !area || !area_size || !search_from || !len)
45 		return NULL;
46 
47 	if (search_from < area || search_from >= area + area_size ||
48 	    (size_t)search_size < str_size)
49 		return NULL;
50 
51 	match = memmem(search_from, search_size, str, str_size);
52 	if (!match)
53 		return NULL;
54 	tail = memchr(match + str_size, '\n',
55 		      area + area_size - match - str_size);
56 	if (!tail)
57 		return NULL;
58 
59 	for (p = match; p >= area; p--) {
60 		if (*p == '\n') {
61 			*len = tail - p - 1;
62 			return (char *)(p + 1);
63 		}
64 	}
65 
66 	*len = tail - area;
67 	return (char *)area;
68 }
69 
70 /**
71  * Get the length of line.
72  *
73  * @param str Start address of line.
74  * @param size Size of searched space.
75  *
76  * @return the length of line (excludes \n) if successful, or -1 if not.
77  *	   This function return -1 if string doesn't contain \n.
78  */
strlinelen(const char * str,size_t size)79 ssize_t strlinelen(const char *str, size_t size)
80 {
81 	char *tail;
82 
83 	if (!str)
84 		return -1;
85 
86 	tail = memchr(str, '\n', size);
87 	if (tail)
88 		return tail - str;
89 
90 	return -1;
91 }
92 
93 /**
94  * Find the last occurrence of the substring str in the string s.
95  *
96  * @param s Range of search.
97  * @param substr String to be found.
98  *
99  * @return a pointer to the beginning of the substring,
100  *	   or NULL if the substring is not found.
101  */
strrstr(const char * s,const char * substr)102 char *strrstr(const char *s, const char *substr)
103 {
104 	const char *found;
105 	const char *p = s;
106 
107 	while ((found = strstr(p, substr)))
108 		p = found + 1;
109 
110 	if (p != s)
111 		return (char *)(p - 1);
112 
113 	return NULL;
114 }
115 
strtrim(char * str,size_t len)116 char *strtrim(char *str, size_t len)
117 {
118 	size_t h_del = 0;
119 	size_t reserve;
120 	char *p;
121 
122 	if (!len)
123 		return str;
124 
125 	for (p = str; p < str + len && *p == ' '; p++)
126 		h_del++;
127 
128 	reserve = len - h_del;
129 	if (!reserve) {
130 		*str = '\0';
131 		return str;
132 	}
133 
134 	for (p = str + len - 1; p >= str && *p == ' '; p--)
135 		reserve--;
136 
137 	memmove(str, str + h_del, reserve);
138 	*(str + reserve) = '\0';
139 	return str;
140 }
141 
strcnt(char * str,char c)142 int strcnt(char *str, char c)
143 {
144 	int cnt = 0;
145 	char *p = str;
146 	char *found;
147 
148 	if (!str)
149 		return -EINVAL;
150 
151 	while ((found = strchr(p, c))) {
152 		p = found + 1;
153 		cnt++;
154 	}
155 
156 	return cnt;
157 }
158 
strings_ind(char * strings,size_t size,int index,size_t * slen)159 char *strings_ind(char *strings, size_t size, int index, size_t *slen)
160 {
161 	int i = 0;
162 	size_t len;
163 	char *start = strings;
164 	char *str_tail;
165 	size_t left;
166 
167 	if (!strings || !size)
168 		return NULL;
169 
170 	str_tail = memchr((void *)strings, '\0', size);
171 	if (!str_tail)
172 		return NULL;
173 
174 	while (1) {
175 		len = str_tail - start;
176 		if (i++ == index)
177 			break;
178 		left = strings + size - str_tail - 1;
179 		if (!left)
180 			return NULL;
181 		start = str_tail + 1;
182 		str_tail = memchr((void *)start, '\0', left);
183 		if (!str_tail)
184 			break;
185 	}
186 
187 	if (slen)
188 		*slen = len;
189 	return start;
190 }
191 
reg_match(const char * str,const char * pattern,char * matched_sub,size_t matched_space,size_t * end_off)192 static int reg_match(const char *str, const char *pattern,
193 		char *matched_sub, size_t matched_space,
194 		size_t *end_off)
195 {
196 	int err;
197 	regex_t reg;
198 	char err_msg[128];
199 	regmatch_t pm[1];
200 	size_t matched_len;
201 
202 	LOGD("reg: %s\n", pattern);
203 	err = regcomp(&reg, pattern, REG_EXTENDED);
204 	if (err) {
205 		regerror(err, &reg, err_msg, sizeof(err_msg));
206 		LOGE("failed to regcomp - %s\n", err_msg);
207 		return -1;
208 	}
209 
210 	err = regexec(&reg, str, sizeof(pm)/sizeof(regmatch_t), pm, 0);
211 	regfree(&reg);
212 	if (err == REG_NOMATCH) {
213 		LOGE("failed to match with reg (%s) str (%s)\n", pattern, str);
214 		return -1;
215 	}
216 	if (pm[0].rm_so == -1)
217 		return -1;
218 
219 	*end_off = pm[0].rm_eo;
220 	if (matched_space == 0 || matched_sub == NULL)
221 		/* get offset only */
222 		return 0;
223 
224 	matched_len = pm[0].rm_eo - pm[0].rm_so;
225 	*(char *)mempcpy(matched_sub, str + pm[0].rm_so,
226 			 MIN(matched_len, matched_space - 1)) = '\0';
227 	return 0;
228 }
229 
exp_end(const char * fmt,size_t flen,const char * exp_s)230 static char *exp_end(const char *fmt, size_t flen, const char *exp_s)
231 {
232 	/* supports %[regex..] and %*[regex..] */
233 	int flag = 0;
234 	const char *p;
235 
236 	if (exp_s < fmt || exp_s >= fmt + flen)
237 		return NULL;
238 
239 	for (p = exp_s; p < fmt + flen; p++) {
240 		if (*p == '[')
241 			flag++;
242 
243 		if (*p == ']') {
244 			flag--;
245 			if (flag == 0)
246 				return (char *)(p + 1);
247 			else if (flag < 0)
248 				return NULL;
249 		}
250 	}
251 	return NULL;
252 }
253 
exp2reg(const char * s,const char * e,int * ignore_flag,char ** reg)254 static int exp2reg(const char *s, const char *e, int *ignore_flag, char **reg)
255 {
256 	const char *oreg_s;
257 	int flag_tmp;
258 	char *buf;
259 
260 	if (memcmp(s, "%*[", 3) == 0) {
261 		flag_tmp = 1;
262 		oreg_s = s + 3;
263 	} else if (memcmp(s, "%[", 2) == 0) {
264 		flag_tmp = 0;
265 		oreg_s = s + 2;
266 	} else {
267 		LOGE("invalid exp - exp must start with \"%%[\" or \"%%*[\"\n");
268 		return -1;
269 	}
270 
271 	if (oreg_s >= e) {
272 		LOGE("invalid exp - exp empty\n");
273 		return -1;
274 	}
275 
276 	buf = malloc(e - oreg_s + 1);
277 	if (!buf) {
278 		LOGE("out-of-mem\n");
279 		return -1;
280 	}
281 
282 	buf[0] = '^';
283 	memcpy(&buf[1], oreg_s, e - oreg_s - 1);
284 	buf[e - oreg_s] = '\0';
285 
286 	*reg = buf;
287 	*ignore_flag = flag_tmp;
288 	return 0;
289 }
290 
str_split_ere(const char * str,size_t slen,const char * fmt,size_t flen,...)291 int str_split_ere(const char *str, size_t slen,
292 		const char *fmt, size_t flen, ...)
293 {
294 	va_list v;
295 	char *_str, *_fmt;
296 	const char *exp_s, *exp_e;
297 	int ignore_flag;
298 	char *reg;
299 	size_t str_off = 0;
300 	size_t off;
301 	char *sreq;
302 	size_t sreqsize;
303 	int ret = 0;
304 
305 	if (!str || !slen || !fmt || !flen)
306 		return ret;
307 
308 	_str = strndup(str, slen);
309 	if (!_str)
310 		return ret;
311 	_fmt = strndup(fmt, flen);
312 	if (!_fmt) {
313 		free(_str);
314 		return ret;
315 	}
316 
317 	va_start(v, flen);
318 	/* supports %[regex..] and %*[regex..] */
319 	exp_s = _fmt;
320 	while (str_off < slen && *exp_s) {
321 		exp_e = exp_end(_fmt, flen, exp_s);
322 		if (!exp_e) {
323 			LOGE("invalid exp - failed to find the end of exp\n");
324 			goto out;
325 		}
326 
327 		if (exp2reg(exp_s, exp_e, &ignore_flag, &reg) == -1) {
328 			LOGE("failed to translate exp to reg\n");
329 			goto out;
330 		}
331 
332 		if (ignore_flag == 1) {
333 			sreq = NULL;
334 			sreqsize = 0;
335 		} else {
336 			sreq = va_arg(v, char *);
337 			sreqsize = va_arg(v, size_t);
338 		}
339 
340 		if (reg_match(_str + str_off, reg, sreq, sreqsize,
341 			      &off) == -1) {
342 			LOGE("failed to match reg\n");
343 			free(reg);
344 			goto out;
345 		} else {
346 			if (ignore_flag == 0)
347 				ret++;
348 		}
349 
350 		exp_s = exp_e;
351 		str_off += off;
352 		free(reg);
353 	}
354 
355 out:
356 	va_end(v);
357 	free(_str);
358 	free(_fmt);
359 	return ret;
360 }
361