/* * Copyright (C) 2018-2022 Intel Corporation. * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "log_sys.h" #include "fsutils.h" /** * Find the first line containing specified string in given area. * * @param str A pointer to the string contained by target line. * @param str_size String length of str. * @param area A pointer to the area where target line may be located. * This pointer will be returned if the specified string is in * the first line of area (There is not '\n' located between area * and the head of searched string). * @param area_size String length of area. * @param search_from A pointer where searching starts. It should be greater * than or equal to area, and less than area + area_size. * @param[out] len The length of target line (excludes \n), it only be modified * when function returns successfully. * * @return a pointer to the head of target line within area (it may be greater * than search_from). * NULL will be returned if the specified string is not found in * any lines (lines must end with '\n'. It means the real searching * scope is from search_from to the last '\n' in area). */ char *get_line(const char *str, size_t str_size, const char *area, size_t area_size, const char *search_from, size_t *len) { char *p; char *match; char *tail; ssize_t search_size = area + area_size - search_from; if (!str || !str_size || !area || !area_size || !search_from || !len) return NULL; if (search_from < area || search_from >= area + area_size || (size_t)search_size < str_size) return NULL; match = memmem(search_from, search_size, str, str_size); if (!match) return NULL; tail = memchr(match + str_size, '\n', area + area_size - match - str_size); if (!tail) return NULL; for (p = match; p >= area; p--) { if (*p == '\n') { *len = tail - p - 1; return (char *)(p + 1); } } *len = tail - area; return (char *)area; } /** * Get the length of line. * * @param str Start address of line. * @param size Size of searched space. * * @return the length of line (excludes \n) if successful, or -1 if not. * This function return -1 if string doesn't contain \n. */ ssize_t strlinelen(const char *str, size_t size) { char *tail; if (!str) return -1; tail = memchr(str, '\n', size); if (tail) return tail - str; return -1; } /** * Find the last occurrence of the substring str in the string s. * * @param s Range of search. * @param substr String to be found. * * @return a pointer to the beginning of the substring, * or NULL if the substring is not found. */ char *strrstr(const char *s, const char *substr) { const char *found; const char *p = s; while ((found = strstr(p, substr))) p = found + 1; if (p != s) return (char *)(p - 1); return NULL; } char *strtrim(char *str, size_t len) { size_t h_del = 0; size_t reserve; char *p; if (!len) return str; for (p = str; p < str + len && *p == ' '; p++) h_del++; reserve = len - h_del; if (!reserve) { *str = '\0'; return str; } for (p = str + len - 1; p >= str && *p == ' '; p--) reserve--; memmove(str, str + h_del, reserve); *(str + reserve) = '\0'; return str; } int strcnt(char *str, char c) { int cnt = 0; char *p = str; char *found; if (!str) return -EINVAL; while ((found = strchr(p, c))) { p = found + 1; cnt++; } return cnt; } char *strings_ind(char *strings, size_t size, int index, size_t *slen) { int i = 0; size_t len; char *start = strings; char *str_tail; size_t left; if (!strings || !size) return NULL; str_tail = memchr((void *)strings, '\0', size); if (!str_tail) return NULL; while (1) { len = str_tail - start; if (i++ == index) break; left = strings + size - str_tail - 1; if (!left) return NULL; start = str_tail + 1; str_tail = memchr((void *)start, '\0', left); if (!str_tail) break; } if (slen) *slen = len; return start; } static int reg_match(const char *str, const char *pattern, char *matched_sub, size_t matched_space, size_t *end_off) { int err; regex_t reg; char err_msg[128]; regmatch_t pm[1]; size_t matched_len; LOGD("reg: %s\n", pattern); err = regcomp(®, pattern, REG_EXTENDED); if (err) { regerror(err, ®, err_msg, sizeof(err_msg)); LOGE("failed to regcomp - %s\n", err_msg); return -1; } err = regexec(®, str, sizeof(pm)/sizeof(regmatch_t), pm, 0); regfree(®); if (err == REG_NOMATCH) { LOGE("failed to match with reg (%s) str (%s)\n", pattern, str); return -1; } if (pm[0].rm_so == -1) return -1; *end_off = pm[0].rm_eo; if (matched_space == 0 || matched_sub == NULL) /* get offset only */ return 0; matched_len = pm[0].rm_eo - pm[0].rm_so; *(char *)mempcpy(matched_sub, str + pm[0].rm_so, MIN(matched_len, matched_space - 1)) = '\0'; return 0; } static char *exp_end(const char *fmt, size_t flen, const char *exp_s) { /* supports %[regex..] and %*[regex..] */ int flag = 0; const char *p; if (exp_s < fmt || exp_s >= fmt + flen) return NULL; for (p = exp_s; p < fmt + flen; p++) { if (*p == '[') flag++; if (*p == ']') { flag--; if (flag == 0) return (char *)(p + 1); else if (flag < 0) return NULL; } } return NULL; } static int exp2reg(const char *s, const char *e, int *ignore_flag, char **reg) { const char *oreg_s; int flag_tmp; char *buf; if (memcmp(s, "%*[", 3) == 0) { flag_tmp = 1; oreg_s = s + 3; } else if (memcmp(s, "%[", 2) == 0) { flag_tmp = 0; oreg_s = s + 2; } else { LOGE("invalid exp - exp must start with \"%%[\" or \"%%*[\"\n"); return -1; } if (oreg_s >= e) { LOGE("invalid exp - exp empty\n"); return -1; } buf = malloc(e - oreg_s + 1); if (!buf) { LOGE("out-of-mem\n"); return -1; } buf[0] = '^'; memcpy(&buf[1], oreg_s, e - oreg_s - 1); buf[e - oreg_s] = '\0'; *reg = buf; *ignore_flag = flag_tmp; return 0; } int str_split_ere(const char *str, size_t slen, const char *fmt, size_t flen, ...) { va_list v; char *_str, *_fmt; const char *exp_s, *exp_e; int ignore_flag; char *reg; size_t str_off = 0; size_t off; char *sreq; size_t sreqsize; int ret = 0; if (!str || !slen || !fmt || !flen) return ret; _str = strndup(str, slen); if (!_str) return ret; _fmt = strndup(fmt, flen); if (!_fmt) { free(_str); return ret; } va_start(v, flen); /* supports %[regex..] and %*[regex..] */ exp_s = _fmt; while (str_off < slen && *exp_s) { exp_e = exp_end(_fmt, flen, exp_s); if (!exp_e) { LOGE("invalid exp - failed to find the end of exp\n"); goto out; } if (exp2reg(exp_s, exp_e, &ignore_flag, ®) == -1) { LOGE("failed to translate exp to reg\n"); goto out; } if (ignore_flag == 1) { sreq = NULL; sreqsize = 0; } else { sreq = va_arg(v, char *); sreqsize = va_arg(v, size_t); } if (reg_match(_str + str_off, reg, sreq, sreqsize, &off) == -1) { LOGE("failed to match reg\n"); free(reg); goto out; } else { if (ignore_flag == 0) ret++; } exp_s = exp_e; str_off += off; free(reg); } out: va_end(v); free(_str); free(_fmt); return ret; }