string.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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 "sane_ctype.h"
  7. #define K 1024LL
  8. /*
  9. * perf_atoll()
  10. * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
  11. * and return its numeric value
  12. */
  13. s64 perf_atoll(const char *str)
  14. {
  15. s64 length;
  16. char *p;
  17. char c;
  18. if (!isdigit(str[0]))
  19. goto out_err;
  20. length = strtoll(str, &p, 10);
  21. switch (c = *p++) {
  22. case 'b': case 'B':
  23. if (*p)
  24. goto out_err;
  25. __fallthrough;
  26. case '\0':
  27. return length;
  28. default:
  29. goto out_err;
  30. /* two-letter suffices */
  31. case 'k': case 'K':
  32. length <<= 10;
  33. break;
  34. case 'm': case 'M':
  35. length <<= 20;
  36. break;
  37. case 'g': case 'G':
  38. length <<= 30;
  39. break;
  40. case 't': case 'T':
  41. length <<= 40;
  42. break;
  43. }
  44. /* we want the cases to match */
  45. if (islower(c)) {
  46. if (strcmp(p, "b") != 0)
  47. goto out_err;
  48. } else {
  49. if (strcmp(p, "B") != 0)
  50. goto out_err;
  51. }
  52. return length;
  53. out_err:
  54. return -1;
  55. }
  56. /*
  57. * Helper function for splitting a string into an argv-like array.
  58. * originally copied from lib/argv_split.c
  59. */
  60. static const char *skip_sep(const char *cp)
  61. {
  62. while (*cp && isspace(*cp))
  63. cp++;
  64. return cp;
  65. }
  66. static const char *skip_arg(const char *cp)
  67. {
  68. while (*cp && !isspace(*cp))
  69. cp++;
  70. return cp;
  71. }
  72. static int count_argc(const char *str)
  73. {
  74. int count = 0;
  75. while (*str) {
  76. str = skip_sep(str);
  77. if (*str) {
  78. count++;
  79. str = skip_arg(str);
  80. }
  81. }
  82. return count;
  83. }
  84. /**
  85. * argv_free - free an argv
  86. * @argv - the argument vector to be freed
  87. *
  88. * Frees an argv and the strings it points to.
  89. */
  90. void argv_free(char **argv)
  91. {
  92. char **p;
  93. for (p = argv; *p; p++) {
  94. free(*p);
  95. *p = NULL;
  96. }
  97. free(argv);
  98. }
  99. /**
  100. * argv_split - split a string at whitespace, returning an argv
  101. * @str: the string to be split
  102. * @argcp: returned argument count
  103. *
  104. * Returns an array of pointers to strings which are split out from
  105. * @str. This is performed by strictly splitting on white-space; no
  106. * quote processing is performed. Multiple whitespace characters are
  107. * considered to be a single argument separator. The returned array
  108. * is always NULL-terminated. Returns NULL on memory allocation
  109. * failure.
  110. */
  111. char **argv_split(const char *str, int *argcp)
  112. {
  113. int argc = count_argc(str);
  114. char **argv = calloc(argc + 1, sizeof(*argv));
  115. char **argvp;
  116. if (argv == NULL)
  117. goto out;
  118. if (argcp)
  119. *argcp = argc;
  120. argvp = argv;
  121. while (*str) {
  122. str = skip_sep(str);
  123. if (*str) {
  124. const char *p = str;
  125. char *t;
  126. str = skip_arg(str);
  127. t = strndup(p, str-p);
  128. if (t == NULL)
  129. goto fail;
  130. *argvp++ = t;
  131. }
  132. }
  133. *argvp = NULL;
  134. out:
  135. return argv;
  136. fail:
  137. argv_free(argv);
  138. return NULL;
  139. }
  140. /* Character class matching */
  141. static bool __match_charclass(const char *pat, char c, const char **npat)
  142. {
  143. bool complement = false, ret = true;
  144. if (*pat == '!') {
  145. complement = true;
  146. pat++;
  147. }
  148. if (*pat++ == c) /* First character is special */
  149. goto end;
  150. while (*pat && *pat != ']') { /* Matching */
  151. if (*pat == '-' && *(pat + 1) != ']') { /* Range */
  152. if (*(pat - 1) <= c && c <= *(pat + 1))
  153. goto end;
  154. if (*(pat - 1) > *(pat + 1))
  155. goto error;
  156. pat += 2;
  157. } else if (*pat++ == c)
  158. goto end;
  159. }
  160. if (!*pat)
  161. goto error;
  162. ret = false;
  163. end:
  164. while (*pat && *pat != ']') /* Searching closing */
  165. pat++;
  166. if (!*pat)
  167. goto error;
  168. *npat = pat + 1;
  169. return complement ? !ret : ret;
  170. error:
  171. return false;
  172. }
  173. /* Glob/lazy pattern matching */
  174. static bool __match_glob(const char *str, const char *pat, bool ignore_space,
  175. bool case_ins)
  176. {
  177. while (*str && *pat && *pat != '*') {
  178. if (ignore_space) {
  179. /* Ignore spaces for lazy matching */
  180. if (isspace(*str)) {
  181. str++;
  182. continue;
  183. }
  184. if (isspace(*pat)) {
  185. pat++;
  186. continue;
  187. }
  188. }
  189. if (*pat == '?') { /* Matches any single character */
  190. str++;
  191. pat++;
  192. continue;
  193. } else if (*pat == '[') /* Character classes/Ranges */
  194. if (__match_charclass(pat + 1, *str, &pat)) {
  195. str++;
  196. continue;
  197. } else
  198. return false;
  199. else if (*pat == '\\') /* Escaped char match as normal char */
  200. pat++;
  201. if (case_ins) {
  202. if (tolower(*str) != tolower(*pat))
  203. return false;
  204. } else if (*str != *pat)
  205. return false;
  206. str++;
  207. pat++;
  208. }
  209. /* Check wild card */
  210. if (*pat == '*') {
  211. while (*pat == '*')
  212. pat++;
  213. if (!*pat) /* Tail wild card matches all */
  214. return true;
  215. while (*str)
  216. if (__match_glob(str++, pat, ignore_space, case_ins))
  217. return true;
  218. }
  219. return !*str && !*pat;
  220. }
  221. /**
  222. * strglobmatch - glob expression pattern matching
  223. * @str: the target string to match
  224. * @pat: the pattern string to match
  225. *
  226. * This returns true if the @str matches @pat. @pat can includes wildcards
  227. * ('*','?') and character classes ([CHARS], complementation and ranges are
  228. * also supported). Also, this supports escape character ('\') to use special
  229. * characters as normal character.
  230. *
  231. * Note: if @pat syntax is broken, this always returns false.
  232. */
  233. bool strglobmatch(const char *str, const char *pat)
  234. {
  235. return __match_glob(str, pat, false, false);
  236. }
  237. bool strglobmatch_nocase(const char *str, const char *pat)
  238. {
  239. return __match_glob(str, pat, false, true);
  240. }
  241. /**
  242. * strlazymatch - matching pattern strings lazily with glob pattern
  243. * @str: the target string to match
  244. * @pat: the pattern string to match
  245. *
  246. * This is similar to strglobmatch, except this ignores spaces in
  247. * the target string.
  248. */
  249. bool strlazymatch(const char *str, const char *pat)
  250. {
  251. return __match_glob(str, pat, true, false);
  252. }
  253. /**
  254. * strtailcmp - Compare the tail of two strings
  255. * @s1: 1st string to be compared
  256. * @s2: 2nd string to be compared
  257. *
  258. * Return 0 if whole of either string is same as another's tail part.
  259. */
  260. int strtailcmp(const char *s1, const char *s2)
  261. {
  262. int i1 = strlen(s1);
  263. int i2 = strlen(s2);
  264. while (--i1 >= 0 && --i2 >= 0) {
  265. if (s1[i1] != s2[i2])
  266. return s1[i1] - s2[i2];
  267. }
  268. return 0;
  269. }
  270. /**
  271. * strxfrchar - Locate and replace character in @s
  272. * @s: The string to be searched/changed.
  273. * @from: Source character to be replaced.
  274. * @to: Destination character.
  275. *
  276. * Return pointer to the changed string.
  277. */
  278. char *strxfrchar(char *s, char from, char to)
  279. {
  280. char *p = s;
  281. while ((p = strchr(p, from)) != NULL)
  282. *p++ = to;
  283. return s;
  284. }
  285. /**
  286. * ltrim - Removes leading whitespace from @s.
  287. * @s: The string to be stripped.
  288. *
  289. * Return pointer to the first non-whitespace character in @s.
  290. */
  291. char *ltrim(char *s)
  292. {
  293. while (isspace(*s))
  294. s++;
  295. return s;
  296. }
  297. /**
  298. * rtrim - Removes trailing whitespace from @s.
  299. * @s: The string to be stripped.
  300. *
  301. * Note that the first trailing whitespace is replaced with a %NUL-terminator
  302. * in the given string @s. Returns @s.
  303. */
  304. char *rtrim(char *s)
  305. {
  306. size_t size = strlen(s);
  307. char *end;
  308. if (!size)
  309. return s;
  310. end = s + size - 1;
  311. while (end >= s && isspace(*end))
  312. end--;
  313. *(end + 1) = '\0';
  314. return s;
  315. }
  316. char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
  317. {
  318. /*
  319. * FIXME: replace this with an expression using log10() when we
  320. * find a suitable implementation, maybe the one in the dvb drivers...
  321. *
  322. * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
  323. */
  324. size_t size = nints * 28 + 1; /* \0 */
  325. size_t i, printed = 0;
  326. char *expr = malloc(size);
  327. if (expr) {
  328. const char *or_and = "||", *eq_neq = "==";
  329. char *e = expr;
  330. if (!in) {
  331. or_and = "&&";
  332. eq_neq = "!=";
  333. }
  334. for (i = 0; i < nints; ++i) {
  335. if (printed == size)
  336. goto out_err_overflow;
  337. if (i > 0)
  338. printed += scnprintf(e + printed, size - printed, " %s ", or_and);
  339. printed += scnprintf(e + printed, size - printed,
  340. "%s %s %d", var, eq_neq, ints[i]);
  341. }
  342. }
  343. return expr;
  344. out_err_overflow:
  345. free(expr);
  346. return NULL;
  347. }