^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include "string2.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) const char *graph_dotted_line =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) "---------------------------------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) "---------------------------------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) "---------------------------------------------------------------------";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) const char *dots =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) "....................................................................."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) "....................................................................."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) ".....................................................................";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define K 1024LL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * perf_atoll()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * and return its numeric value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) s64 perf_atoll(const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) s64 length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (!isdigit(str[0]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) length = strtoll(str, &p, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) switch (c = *p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) case 'b': case 'B':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if (*p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) __fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) case '\0':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* two-letter suffices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) case 'k': case 'K':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) length <<= 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) case 'm': case 'M':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) length <<= 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) case 'g': case 'G':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) length <<= 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) case 't': case 'T':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) length <<= 40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* we want the cases to match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (islower(c)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (strcmp(p, "b") != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (strcmp(p, "B") != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) out_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* Character class matching */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static bool __match_charclass(const char *pat, char c, const char **npat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) bool complement = false, ret = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (*pat == '!') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) complement = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) pat++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (*pat++ == c) /* First character is special */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) while (*pat && *pat != ']') { /* Matching */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (*pat == '-' && *(pat + 1) != ']') { /* Range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (*(pat - 1) <= c && c <= *(pat + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (*(pat - 1) > *(pat + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) pat += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) } else if (*pat++ == c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!*pat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ret = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) while (*pat && *pat != ']') /* Searching closing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pat++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (!*pat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) *npat = pat + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return complement ? !ret : ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* Glob/lazy pattern matching */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static bool __match_glob(const char *str, const char *pat, bool ignore_space,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) bool case_ins)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) while (*str && *pat && *pat != '*') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (ignore_space) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Ignore spaces for lazy matching */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (isspace(*str)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (isspace(*pat)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) pat++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (*pat == '?') { /* Matches any single character */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) pat++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) } else if (*pat == '[') /* Character classes/Ranges */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (__match_charclass(pat + 1, *str, &pat)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) else if (*pat == '\\') /* Escaped char match as normal char */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) pat++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (case_ins) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (tolower(*str) != tolower(*pat))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) } else if (*str != *pat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) str++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) pat++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* Check wild card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (*pat == '*') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) while (*pat == '*')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) pat++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!*pat) /* Tail wild card matches all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) while (*str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (__match_glob(str++, pat, ignore_space, case_ins))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return !*str && !*pat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * strglobmatch - glob expression pattern matching
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * @str: the target string to match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * @pat: the pattern string to match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * This returns true if the @str matches @pat. @pat can includes wildcards
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * ('*','?') and character classes ([CHARS], complementation and ranges are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * also supported). Also, this supports escape character ('\') to use special
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * characters as normal character.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * Note: if @pat syntax is broken, this always returns false.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) bool strglobmatch(const char *str, const char *pat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return __match_glob(str, pat, false, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) bool strglobmatch_nocase(const char *str, const char *pat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return __match_glob(str, pat, false, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * strlazymatch - matching pattern strings lazily with glob pattern
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * @str: the target string to match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * @pat: the pattern string to match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * This is similar to strglobmatch, except this ignores spaces in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * the target string.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) bool strlazymatch(const char *str, const char *pat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return __match_glob(str, pat, true, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * strtailcmp - Compare the tail of two strings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * @s1: 1st string to be compared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * @s2: 2nd string to be compared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * Return 0 if whole of either string is same as another's tail part.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) int strtailcmp(const char *s1, const char *s2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) int i1 = strlen(s1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) int i2 = strlen(s2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) while (--i1 >= 0 && --i2 >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (s1[i1] != s2[i2])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return s1[i1] - s2[i2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * FIXME: replace this with an expression using log10() when we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * find a suitable implementation, maybe the one in the dvb drivers...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) size_t size = nints * 28 + 1; /* \0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) size_t i, printed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) char *expr = malloc(size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (expr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) const char *or_and = "||", *eq_neq = "==";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) char *e = expr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (!in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) or_and = "&&";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) eq_neq = "!=";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) for (i = 0; i < nints; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (printed == size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) goto out_err_overflow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (i > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) printed += scnprintf(e + printed, size - printed, " %s ", or_and);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) printed += scnprintf(e + printed, size - printed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) "%s %s %d", var, eq_neq, ints[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return expr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) out_err_overflow:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) free(expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) char *strpbrk_esc(char *str, const char *stopset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) char *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) ptr = strpbrk(str, stopset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (ptr == str ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) (ptr == str + 1 && *(ptr - 1) != '\\'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) str = ptr + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) } while (ptr && *(ptr - 1) == '\\' && *(ptr - 2) != '\\');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* Like strdup, but do not copy a single backslash */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) char *strdup_esc(const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) char *s, *d, *p, *ret = strdup(str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) d = strchr(ret, '\\');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (!d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) s = d + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (*s == '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) *d = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) p = strchr(s + 1, '\\');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) memmove(d, s, p - s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) d += p - s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) s = p + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) memmove(d, s, strlen(s) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) } while (p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }