string.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include "string2.h"
  3. #include <linux/kernel.h>
  4. #include <linux/string.h>
  5. #include <stdlib.h>
  6. #include <linux/ctype.h>
  7. const char *graph_dotted_line =
  8. "---------------------------------------------------------------------"
  9. "---------------------------------------------------------------------"
  10. "---------------------------------------------------------------------";
  11. const char *dots =
  12. "....................................................................."
  13. "....................................................................."
  14. ".....................................................................";
  15. /*
  16. * perf_atoll()
  17. * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
  18. * and return its numeric value
  19. */
  20. s64 perf_atoll(const char *str)
  21. {
  22. s64 length;
  23. char *p;
  24. char c;
  25. if (!isdigit(str[0]))
  26. goto out_err;
  27. length = strtoll(str, &p, 10);
  28. switch (c = *p++) {
  29. case 'b': case 'B':
  30. if (*p)
  31. goto out_err;
  32. fallthrough;
  33. case '\0':
  34. return length;
  35. default:
  36. goto out_err;
  37. /* two-letter suffices */
  38. case 'k': case 'K':
  39. length <<= 10;
  40. break;
  41. case 'm': case 'M':
  42. length <<= 20;
  43. break;
  44. case 'g': case 'G':
  45. length <<= 30;
  46. break;
  47. case 't': case 'T':
  48. length <<= 40;
  49. break;
  50. }
  51. /* we want the cases to match */
  52. if (islower(c)) {
  53. if (strcmp(p, "b") != 0)
  54. goto out_err;
  55. } else {
  56. if (strcmp(p, "B") != 0)
  57. goto out_err;
  58. }
  59. return length;
  60. out_err:
  61. return -1;
  62. }
  63. /* Character class matching */
  64. static bool __match_charclass(const char *pat, char c, const char **npat)
  65. {
  66. bool complement = false, ret = true;
  67. if (*pat == '!') {
  68. complement = true;
  69. pat++;
  70. }
  71. if (*pat++ == c) /* First character is special */
  72. goto end;
  73. while (*pat && *pat != ']') { /* Matching */
  74. if (*pat == '-' && *(pat + 1) != ']') { /* Range */
  75. if (*(pat - 1) <= c && c <= *(pat + 1))
  76. goto end;
  77. if (*(pat - 1) > *(pat + 1))
  78. goto error;
  79. pat += 2;
  80. } else if (*pat++ == c)
  81. goto end;
  82. }
  83. if (!*pat)
  84. goto error;
  85. ret = false;
  86. end:
  87. while (*pat && *pat != ']') /* Searching closing */
  88. pat++;
  89. if (!*pat)
  90. goto error;
  91. *npat = pat + 1;
  92. return complement ? !ret : ret;
  93. error:
  94. return false;
  95. }
  96. /* Glob/lazy pattern matching */
  97. static bool __match_glob(const char *str, const char *pat, bool ignore_space,
  98. bool case_ins)
  99. {
  100. while (*str && *pat && *pat != '*') {
  101. if (ignore_space) {
  102. /* Ignore spaces for lazy matching */
  103. if (isspace(*str)) {
  104. str++;
  105. continue;
  106. }
  107. if (isspace(*pat)) {
  108. pat++;
  109. continue;
  110. }
  111. }
  112. if (*pat == '?') { /* Matches any single character */
  113. str++;
  114. pat++;
  115. continue;
  116. } else if (*pat == '[') /* Character classes/Ranges */
  117. if (__match_charclass(pat + 1, *str, &pat)) {
  118. str++;
  119. continue;
  120. } else
  121. return false;
  122. else if (*pat == '\\') /* Escaped char match as normal char */
  123. pat++;
  124. if (case_ins) {
  125. if (tolower(*str) != tolower(*pat))
  126. return false;
  127. } else if (*str != *pat)
  128. return false;
  129. str++;
  130. pat++;
  131. }
  132. /* Check wild card */
  133. if (*pat == '*') {
  134. while (*pat == '*')
  135. pat++;
  136. if (!*pat) /* Tail wild card matches all */
  137. return true;
  138. while (*str)
  139. if (__match_glob(str++, pat, ignore_space, case_ins))
  140. return true;
  141. }
  142. return !*str && !*pat;
  143. }
  144. /**
  145. * strglobmatch - glob expression pattern matching
  146. * @str: the target string to match
  147. * @pat: the pattern string to match
  148. *
  149. * This returns true if the @str matches @pat. @pat can includes wildcards
  150. * ('*','?') and character classes ([CHARS], complementation and ranges are
  151. * also supported). Also, this supports escape character ('\') to use special
  152. * characters as normal character.
  153. *
  154. * Note: if @pat syntax is broken, this always returns false.
  155. */
  156. bool strglobmatch(const char *str, const char *pat)
  157. {
  158. return __match_glob(str, pat, false, false);
  159. }
  160. bool strglobmatch_nocase(const char *str, const char *pat)
  161. {
  162. return __match_glob(str, pat, false, true);
  163. }
  164. /**
  165. * strlazymatch - matching pattern strings lazily with glob pattern
  166. * @str: the target string to match
  167. * @pat: the pattern string to match
  168. *
  169. * This is similar to strglobmatch, except this ignores spaces in
  170. * the target string.
  171. */
  172. bool strlazymatch(const char *str, const char *pat)
  173. {
  174. return __match_glob(str, pat, true, false);
  175. }
  176. /**
  177. * strtailcmp - Compare the tail of two strings
  178. * @s1: 1st string to be compared
  179. * @s2: 2nd string to be compared
  180. *
  181. * Return 0 if whole of either string is same as another's tail part.
  182. */
  183. int strtailcmp(const char *s1, const char *s2)
  184. {
  185. int i1 = strlen(s1);
  186. int i2 = strlen(s2);
  187. while (--i1 >= 0 && --i2 >= 0) {
  188. if (s1[i1] != s2[i2])
  189. return s1[i1] - s2[i2];
  190. }
  191. return 0;
  192. }
  193. char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
  194. {
  195. /*
  196. * FIXME: replace this with an expression using log10() when we
  197. * find a suitable implementation, maybe the one in the dvb drivers...
  198. *
  199. * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
  200. */
  201. size_t size = nints * 28 + 1; /* \0 */
  202. size_t i, printed = 0;
  203. char *expr = malloc(size);
  204. if (expr) {
  205. const char *or_and = "||", *eq_neq = "==";
  206. char *e = expr;
  207. if (!in) {
  208. or_and = "&&";
  209. eq_neq = "!=";
  210. }
  211. for (i = 0; i < nints; ++i) {
  212. if (printed == size)
  213. goto out_err_overflow;
  214. if (i > 0)
  215. printed += scnprintf(e + printed, size - printed, " %s ", or_and);
  216. printed += scnprintf(e + printed, size - printed,
  217. "%s %s %d", var, eq_neq, ints[i]);
  218. }
  219. }
  220. return expr;
  221. out_err_overflow:
  222. free(expr);
  223. return NULL;
  224. }
  225. /* Like strpbrk(), but not break if it is right after a backslash (escaped) */
  226. char *strpbrk_esc(char *str, const char *stopset)
  227. {
  228. char *ptr;
  229. do {
  230. ptr = strpbrk(str, stopset);
  231. if (!ptr) {
  232. /* stopset not in str. */
  233. break;
  234. }
  235. if (ptr == str) {
  236. /* stopset character is first in str. */
  237. break;
  238. }
  239. if (ptr == str + 1 && str[0] != '\\') {
  240. /* stopset chacter is second and wasn't preceded by a '\'. */
  241. break;
  242. }
  243. str = ptr + 1;
  244. } while (ptr[-1] == '\\' && ptr[-2] != '\\');
  245. return ptr;
  246. }
  247. /* Like strpbrk_esc(), but not break if it is quoted with single/double quotes */
  248. char *strpbrk_esq(char *str, const char *stopset)
  249. {
  250. char *_stopset = NULL;
  251. char *ptr;
  252. const char *squote = "'";
  253. const char *dquote = "\"";
  254. if (asprintf(&_stopset, "%s%c%c", stopset, *squote, *dquote) < 0)
  255. return NULL;
  256. do {
  257. ptr = strpbrk_esc(str, _stopset);
  258. if (!ptr)
  259. break;
  260. if (*ptr == *squote)
  261. ptr = strpbrk_esc(ptr + 1, squote);
  262. else if (*ptr == *dquote)
  263. ptr = strpbrk_esc(ptr + 1, dquote);
  264. else
  265. break;
  266. str = ptr + 1;
  267. } while (ptr);
  268. free(_stopset);
  269. return ptr;
  270. }
  271. /* Like strdup, but do not copy a single backslash */
  272. char *strdup_esc(const char *str)
  273. {
  274. char *s, *d, *p, *ret = strdup(str);
  275. if (!ret)
  276. return NULL;
  277. d = strchr(ret, '\\');
  278. if (!d)
  279. return ret;
  280. s = d + 1;
  281. do {
  282. if (*s == '\0') {
  283. *d = '\0';
  284. break;
  285. }
  286. p = strchr(s + 1, '\\');
  287. if (p) {
  288. memmove(d, s, p - s);
  289. d += p - s;
  290. s = p + 1;
  291. } else
  292. memmove(d, s, strlen(s) + 1);
  293. } while (p);
  294. return ret;
  295. }
  296. /* Remove backslash right before quote and return next quote address. */
  297. static char *remove_consumed_esc(char *str, int len, int quote)
  298. {
  299. char *ptr = str, *end = str + len;
  300. while (*ptr != quote && ptr < end) {
  301. if (*ptr == '\\' && *(ptr + 1) == quote) {
  302. memmove(ptr, ptr + 1, end - (ptr + 1));
  303. /* now *ptr is `quote`. */
  304. end--;
  305. }
  306. ptr++;
  307. }
  308. return *ptr == quote ? ptr : NULL;
  309. }
  310. /*
  311. * Like strdup_esc, but keep quoted string as it is (and single backslash
  312. * before quote is removed). If there is no closed quote, return NULL.
  313. */
  314. char *strdup_esq(const char *str)
  315. {
  316. char *d, *ret;
  317. /* If there is no quote, return normal strdup_esc() */
  318. d = strpbrk_esc((char *)str, "\"'");
  319. if (!d)
  320. return strdup_esc(str);
  321. ret = strdup(str);
  322. if (!ret)
  323. return NULL;
  324. d = ret;
  325. do {
  326. d = strpbrk(d, "\\\"\'");
  327. if (!d)
  328. break;
  329. if (*d == '"' || *d == '\'') {
  330. /* This is non-escaped quote */
  331. int quote = *d;
  332. int len = strlen(d + 1) + 1;
  333. /*
  334. * Remove the start quote and remove consumed escape (backslash
  335. * before quote) and remove the end quote. If there is no end
  336. * quote, it is the input error.
  337. */
  338. memmove(d, d + 1, len);
  339. d = remove_consumed_esc(d, len, quote);
  340. if (!d)
  341. goto error;
  342. memmove(d, d + 1, strlen(d + 1) + 1);
  343. }
  344. if (*d == '\\') {
  345. memmove(d, d + 1, strlen(d + 1) + 1);
  346. if (*d == '\\') {
  347. /* double backslash -- keep the second one. */
  348. d++;
  349. }
  350. }
  351. } while (*d != '\0');
  352. return ret;
  353. error:
  354. free(ret);
  355. return NULL;
  356. }
  357. unsigned int hex(char c)
  358. {
  359. if (c >= '0' && c <= '9')
  360. return c - '0';
  361. if (c >= 'a' && c <= 'f')
  362. return c - 'a' + 10;
  363. return c - 'A' + 10;
  364. }
  365. /*
  366. * Replace all occurrences of character 'needle' in string 'haystack' with
  367. * string 'replace'
  368. *
  369. * The new string could be longer so a new string is returned which must be
  370. * freed.
  371. */
  372. char *strreplace_chars(char needle, const char *haystack, const char *replace)
  373. {
  374. int replace_len = strlen(replace);
  375. char *new_s, *to;
  376. const char *loc = strchr(haystack, needle);
  377. const char *from = haystack;
  378. int num = 0;
  379. /* Count occurrences */
  380. while (loc) {
  381. loc = strchr(loc + 1, needle);
  382. num++;
  383. }
  384. /* Allocate enough space for replacements and reset first location */
  385. new_s = malloc(strlen(haystack) + (num * (replace_len - 1) + 1));
  386. if (!new_s)
  387. return NULL;
  388. loc = strchr(haystack, needle);
  389. to = new_s;
  390. while (loc) {
  391. /* Copy original string up to found char and update positions */
  392. memcpy(to, from, 1 + loc - from);
  393. to += loc - from;
  394. from = loc + 1;
  395. /* Copy replacement string and update positions */
  396. memcpy(to, replace, replace_len);
  397. to += replace_len;
  398. /* needle next occurrence or end of string */
  399. loc = strchr(from, needle);
  400. }
  401. /* Copy any remaining chars + null */
  402. strcpy(to, from);
  403. return new_s;
  404. }