1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
27d85c434SWang Nan /*
37d85c434SWang Nan * linux/tools/lib/string.c
47d85c434SWang Nan *
57d85c434SWang Nan * Copied from linux/lib/string.c, where it is:
67d85c434SWang Nan *
77d85c434SWang Nan * Copyright (C) 1991, 1992 Linus Torvalds
87d85c434SWang Nan *
97d85c434SWang Nan * More specifically, the first copied function was strtobool, which
107d85c434SWang Nan * was introduced by:
117d85c434SWang Nan *
127d85c434SWang Nan * d0f1fed29e6e ("Add a strtobool function matching semantics of existing in kernel equivalents")
137d85c434SWang Nan * Author: Jonathan Cameron <jic23@cam.ac.uk>
147d85c434SWang Nan */
157d85c434SWang Nan
164ddd3274SArnaldo Carvalho de Melo #include <stdlib.h>
174ddd3274SArnaldo Carvalho de Melo #include <string.h>
187d85c434SWang Nan #include <errno.h>
194ddd3274SArnaldo Carvalho de Melo #include <linux/string.h>
207bd330deSArnaldo Carvalho de Melo #include <linux/ctype.h>
21ce990917SJosh Poimboeuf #include <linux/compiler.h>
224ddd3274SArnaldo Carvalho de Melo
234ddd3274SArnaldo Carvalho de Melo /**
244ddd3274SArnaldo Carvalho de Melo * memdup - duplicate region of memory
254ddd3274SArnaldo Carvalho de Melo *
264ddd3274SArnaldo Carvalho de Melo * @src: memory region to duplicate
274ddd3274SArnaldo Carvalho de Melo * @len: memory region length
284ddd3274SArnaldo Carvalho de Melo */
memdup(const void * src,size_t len)294ddd3274SArnaldo Carvalho de Melo void *memdup(const void *src, size_t len)
304ddd3274SArnaldo Carvalho de Melo {
314ddd3274SArnaldo Carvalho de Melo void *p = malloc(len);
324ddd3274SArnaldo Carvalho de Melo
334ddd3274SArnaldo Carvalho de Melo if (p)
344ddd3274SArnaldo Carvalho de Melo memcpy(p, src, len);
354ddd3274SArnaldo Carvalho de Melo
364ddd3274SArnaldo Carvalho de Melo return p;
374ddd3274SArnaldo Carvalho de Melo }
387d85c434SWang Nan
397d85c434SWang Nan /**
407d85c434SWang Nan * strtobool - convert common user inputs into boolean values
417d85c434SWang Nan * @s: input string
427d85c434SWang Nan * @res: result
437d85c434SWang Nan *
44b99e4850SArnaldo Carvalho de Melo * This routine returns 0 iff the first character is one of 'Yy1Nn0', or
45b99e4850SArnaldo Carvalho de Melo * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value
46b99e4850SArnaldo Carvalho de Melo * pointed to by res is updated upon finding a match.
477d85c434SWang Nan */
strtobool(const char * s,bool * res)487d85c434SWang Nan int strtobool(const char *s, bool *res)
497d85c434SWang Nan {
50b99e4850SArnaldo Carvalho de Melo if (!s)
51b99e4850SArnaldo Carvalho de Melo return -EINVAL;
52b99e4850SArnaldo Carvalho de Melo
537d85c434SWang Nan switch (s[0]) {
547d85c434SWang Nan case 'y':
557d85c434SWang Nan case 'Y':
567d85c434SWang Nan case '1':
577d85c434SWang Nan *res = true;
58b99e4850SArnaldo Carvalho de Melo return 0;
597d85c434SWang Nan case 'n':
607d85c434SWang Nan case 'N':
617d85c434SWang Nan case '0':
627d85c434SWang Nan *res = false;
637d85c434SWang Nan return 0;
64b99e4850SArnaldo Carvalho de Melo case 'o':
65b99e4850SArnaldo Carvalho de Melo case 'O':
66b99e4850SArnaldo Carvalho de Melo switch (s[1]) {
67b99e4850SArnaldo Carvalho de Melo case 'n':
68b99e4850SArnaldo Carvalho de Melo case 'N':
69b99e4850SArnaldo Carvalho de Melo *res = true;
70b99e4850SArnaldo Carvalho de Melo return 0;
71b99e4850SArnaldo Carvalho de Melo case 'f':
72b99e4850SArnaldo Carvalho de Melo case 'F':
73b99e4850SArnaldo Carvalho de Melo *res = false;
74b99e4850SArnaldo Carvalho de Melo return 0;
75b99e4850SArnaldo Carvalho de Melo default:
76b99e4850SArnaldo Carvalho de Melo break;
77b99e4850SArnaldo Carvalho de Melo }
78b99e4850SArnaldo Carvalho de Melo default:
79b99e4850SArnaldo Carvalho de Melo break;
80b99e4850SArnaldo Carvalho de Melo }
81b99e4850SArnaldo Carvalho de Melo
82b99e4850SArnaldo Carvalho de Melo return -EINVAL;
837d85c434SWang Nan }
84ce990917SJosh Poimboeuf
85ce990917SJosh Poimboeuf /**
86ce990917SJosh Poimboeuf * strlcpy - Copy a C-string into a sized buffer
87ce990917SJosh Poimboeuf * @dest: Where to copy the string to
88ce990917SJosh Poimboeuf * @src: Where to copy the string from
89ce990917SJosh Poimboeuf * @size: size of destination buffer
90ce990917SJosh Poimboeuf *
91ce990917SJosh Poimboeuf * Compatible with *BSD: the result is always a valid
92ce990917SJosh Poimboeuf * NUL-terminated string that fits in the buffer (unless,
93ce990917SJosh Poimboeuf * of course, the buffer size is zero). It does not pad
94ce990917SJosh Poimboeuf * out the result like strncpy() does.
95ce990917SJosh Poimboeuf *
96ce990917SJosh Poimboeuf * If libc has strlcpy() then that version will override this
97ce990917SJosh Poimboeuf * implementation:
98ce990917SJosh Poimboeuf */
996c4798d3SVitaly Chikunov #ifdef __clang__
1006c4798d3SVitaly Chikunov #pragma clang diagnostic push
1016c4798d3SVitaly Chikunov #pragma clang diagnostic ignored "-Wignored-attributes"
1026c4798d3SVitaly Chikunov #endif
strlcpy(char * dest,const char * src,size_t size)103ce990917SJosh Poimboeuf size_t __weak strlcpy(char *dest, const char *src, size_t size)
104ce990917SJosh Poimboeuf {
105ce990917SJosh Poimboeuf size_t ret = strlen(src);
106ce990917SJosh Poimboeuf
107ce990917SJosh Poimboeuf if (size) {
108ce990917SJosh Poimboeuf size_t len = (ret >= size) ? size - 1 : ret;
109ce990917SJosh Poimboeuf memcpy(dest, src, len);
110ce990917SJosh Poimboeuf dest[len] = '\0';
111ce990917SJosh Poimboeuf }
112ce990917SJosh Poimboeuf return ret;
113ce990917SJosh Poimboeuf }
1146c4798d3SVitaly Chikunov #ifdef __clang__
1156c4798d3SVitaly Chikunov #pragma clang diagnostic pop
1166c4798d3SVitaly Chikunov #endif
1177bd330deSArnaldo Carvalho de Melo
1187bd330deSArnaldo Carvalho de Melo /**
1197bd330deSArnaldo Carvalho de Melo * skip_spaces - Removes leading whitespace from @str.
1207bd330deSArnaldo Carvalho de Melo * @str: The string to be stripped.
1217bd330deSArnaldo Carvalho de Melo *
1227bd330deSArnaldo Carvalho de Melo * Returns a pointer to the first non-whitespace character in @str.
1237bd330deSArnaldo Carvalho de Melo */
skip_spaces(const char * str)1247bd330deSArnaldo Carvalho de Melo char *skip_spaces(const char *str)
1257bd330deSArnaldo Carvalho de Melo {
1267bd330deSArnaldo Carvalho de Melo while (isspace(*str))
1277bd330deSArnaldo Carvalho de Melo ++str;
1287bd330deSArnaldo Carvalho de Melo return (char *)str;
1297bd330deSArnaldo Carvalho de Melo }
13045bfd0acSArnaldo Carvalho de Melo
13145bfd0acSArnaldo Carvalho de Melo /**
13245bfd0acSArnaldo Carvalho de Melo * strim - Removes leading and trailing whitespace from @s.
13345bfd0acSArnaldo Carvalho de Melo * @s: The string to be stripped.
13445bfd0acSArnaldo Carvalho de Melo *
13545bfd0acSArnaldo Carvalho de Melo * Note that the first trailing whitespace is replaced with a %NUL-terminator
13645bfd0acSArnaldo Carvalho de Melo * in the given string @s. Returns a pointer to the first non-whitespace
13745bfd0acSArnaldo Carvalho de Melo * character in @s.
13845bfd0acSArnaldo Carvalho de Melo */
strim(char * s)13945bfd0acSArnaldo Carvalho de Melo char *strim(char *s)
14045bfd0acSArnaldo Carvalho de Melo {
14145bfd0acSArnaldo Carvalho de Melo size_t size;
14245bfd0acSArnaldo Carvalho de Melo char *end;
14345bfd0acSArnaldo Carvalho de Melo
14445bfd0acSArnaldo Carvalho de Melo size = strlen(s);
14545bfd0acSArnaldo Carvalho de Melo if (!size)
14645bfd0acSArnaldo Carvalho de Melo return s;
14745bfd0acSArnaldo Carvalho de Melo
14845bfd0acSArnaldo Carvalho de Melo end = s + size - 1;
14945bfd0acSArnaldo Carvalho de Melo while (end >= s && isspace(*end))
15045bfd0acSArnaldo Carvalho de Melo end--;
15145bfd0acSArnaldo Carvalho de Melo *(end + 1) = '\0';
15245bfd0acSArnaldo Carvalho de Melo
15345bfd0acSArnaldo Carvalho de Melo return skip_spaces(s);
15445bfd0acSArnaldo Carvalho de Melo }
1552a60689aSArnaldo Carvalho de Melo
1562a60689aSArnaldo Carvalho de Melo /**
1572a60689aSArnaldo Carvalho de Melo * strreplace - Replace all occurrences of character in string.
1582a60689aSArnaldo Carvalho de Melo * @s: The string to operate on.
1592a60689aSArnaldo Carvalho de Melo * @old: The character being replaced.
1602a60689aSArnaldo Carvalho de Melo * @new: The character @old is replaced with.
1612a60689aSArnaldo Carvalho de Melo *
1622a60689aSArnaldo Carvalho de Melo * Returns pointer to the nul byte at the end of @s.
1632a60689aSArnaldo Carvalho de Melo */
strreplace(char * s,char old,char new)1642a60689aSArnaldo Carvalho de Melo char *strreplace(char *s, char old, char new)
1652a60689aSArnaldo Carvalho de Melo {
1662a60689aSArnaldo Carvalho de Melo for (; *s; ++s)
1672a60689aSArnaldo Carvalho de Melo if (*s == old)
1682a60689aSArnaldo Carvalho de Melo *s = new;
1692a60689aSArnaldo Carvalho de Melo return s;
1702a60689aSArnaldo Carvalho de Melo }
171*b3e45327SJiri Olsa
check_bytes8(const u8 * start,u8 value,unsigned int bytes)172*b3e45327SJiri Olsa static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes)
173*b3e45327SJiri Olsa {
174*b3e45327SJiri Olsa while (bytes) {
175*b3e45327SJiri Olsa if (*start != value)
176*b3e45327SJiri Olsa return (void *)start;
177*b3e45327SJiri Olsa start++;
178*b3e45327SJiri Olsa bytes--;
179*b3e45327SJiri Olsa }
180*b3e45327SJiri Olsa return NULL;
181*b3e45327SJiri Olsa }
182*b3e45327SJiri Olsa
183*b3e45327SJiri Olsa /**
184*b3e45327SJiri Olsa * memchr_inv - Find an unmatching character in an area of memory.
185*b3e45327SJiri Olsa * @start: The memory area
186*b3e45327SJiri Olsa * @c: Find a character other than c
187*b3e45327SJiri Olsa * @bytes: The size of the area.
188*b3e45327SJiri Olsa *
189*b3e45327SJiri Olsa * returns the address of the first character other than @c, or %NULL
190*b3e45327SJiri Olsa * if the whole buffer contains just @c.
191*b3e45327SJiri Olsa */
memchr_inv(const void * start,int c,size_t bytes)192*b3e45327SJiri Olsa void *memchr_inv(const void *start, int c, size_t bytes)
193*b3e45327SJiri Olsa {
194*b3e45327SJiri Olsa u8 value = c;
195*b3e45327SJiri Olsa u64 value64;
196*b3e45327SJiri Olsa unsigned int words, prefix;
197*b3e45327SJiri Olsa
198*b3e45327SJiri Olsa if (bytes <= 16)
199*b3e45327SJiri Olsa return check_bytes8(start, value, bytes);
200*b3e45327SJiri Olsa
201*b3e45327SJiri Olsa value64 = value;
202*b3e45327SJiri Olsa value64 |= value64 << 8;
203*b3e45327SJiri Olsa value64 |= value64 << 16;
204*b3e45327SJiri Olsa value64 |= value64 << 32;
205*b3e45327SJiri Olsa
206*b3e45327SJiri Olsa prefix = (unsigned long)start % 8;
207*b3e45327SJiri Olsa if (prefix) {
208*b3e45327SJiri Olsa u8 *r;
209*b3e45327SJiri Olsa
210*b3e45327SJiri Olsa prefix = 8 - prefix;
211*b3e45327SJiri Olsa r = check_bytes8(start, value, prefix);
212*b3e45327SJiri Olsa if (r)
213*b3e45327SJiri Olsa return r;
214*b3e45327SJiri Olsa start += prefix;
215*b3e45327SJiri Olsa bytes -= prefix;
216*b3e45327SJiri Olsa }
217*b3e45327SJiri Olsa
218*b3e45327SJiri Olsa words = bytes / 8;
219*b3e45327SJiri Olsa
220*b3e45327SJiri Olsa while (words) {
221*b3e45327SJiri Olsa if (*(u64 *)start != value64)
222*b3e45327SJiri Olsa return check_bytes8(start, value, 8);
223*b3e45327SJiri Olsa start += 8;
224*b3e45327SJiri Olsa words--;
225*b3e45327SJiri Olsa }
226*b3e45327SJiri Olsa
227*b3e45327SJiri Olsa return check_bytes8(start, value, bytes % 8);
228*b3e45327SJiri Olsa }
229