xref: /openbmc/linux/tools/lib/string.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
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