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(®, pattern, REG_EXTENDED);
204 if (err) {
205 regerror(err, ®, err_msg, sizeof(err_msg));
206 LOGE("failed to regcomp - %s\n", err_msg);
207 return -1;
208 }
209
210 err = regexec(®, str, sizeof(pm)/sizeof(regmatch_t), pm, 0);
211 regfree(®);
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, ®) == -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