18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/tools/lib/string.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copied from linux/lib/string.c, where it is: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * More specifically, the first copied function was strtobool, which 108c2ecf20Sopenharmony_ci * was introduced by: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * d0f1fed29e6e ("Add a strtobool function matching semantics of existing in kernel equivalents") 138c2ecf20Sopenharmony_ci * Author: Jonathan Cameron <jic23@cam.ac.uk> 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <stdlib.h> 178c2ecf20Sopenharmony_ci#include <string.h> 188c2ecf20Sopenharmony_ci#include <errno.h> 198c2ecf20Sopenharmony_ci#include <linux/string.h> 208c2ecf20Sopenharmony_ci#include <linux/ctype.h> 218c2ecf20Sopenharmony_ci#include <linux/compiler.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/** 248c2ecf20Sopenharmony_ci * memdup - duplicate region of memory 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * @src: memory region to duplicate 278c2ecf20Sopenharmony_ci * @len: memory region length 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_civoid *memdup(const void *src, size_t len) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci void *p = malloc(len); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (p) 348c2ecf20Sopenharmony_ci memcpy(p, src, len); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return p; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/** 408c2ecf20Sopenharmony_ci * strtobool - convert common user inputs into boolean values 418c2ecf20Sopenharmony_ci * @s: input string 428c2ecf20Sopenharmony_ci * @res: result 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * This routine returns 0 iff the first character is one of 'Yy1Nn0', or 458c2ecf20Sopenharmony_ci * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value 468c2ecf20Sopenharmony_ci * pointed to by res is updated upon finding a match. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciint strtobool(const char *s, bool *res) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci if (!s) 518c2ecf20Sopenharmony_ci return -EINVAL; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci switch (s[0]) { 548c2ecf20Sopenharmony_ci case 'y': 558c2ecf20Sopenharmony_ci case 'Y': 568c2ecf20Sopenharmony_ci case '1': 578c2ecf20Sopenharmony_ci *res = true; 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci case 'n': 608c2ecf20Sopenharmony_ci case 'N': 618c2ecf20Sopenharmony_ci case '0': 628c2ecf20Sopenharmony_ci *res = false; 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci case 'o': 658c2ecf20Sopenharmony_ci case 'O': 668c2ecf20Sopenharmony_ci switch (s[1]) { 678c2ecf20Sopenharmony_ci case 'n': 688c2ecf20Sopenharmony_ci case 'N': 698c2ecf20Sopenharmony_ci *res = true; 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci case 'f': 728c2ecf20Sopenharmony_ci case 'F': 738c2ecf20Sopenharmony_ci *res = false; 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci default: 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci default: 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return -EINVAL; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/** 868c2ecf20Sopenharmony_ci * strlcpy - Copy a C-string into a sized buffer 878c2ecf20Sopenharmony_ci * @dest: Where to copy the string to 888c2ecf20Sopenharmony_ci * @src: Where to copy the string from 898c2ecf20Sopenharmony_ci * @size: size of destination buffer 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * Compatible with *BSD: the result is always a valid 928c2ecf20Sopenharmony_ci * NUL-terminated string that fits in the buffer (unless, 938c2ecf20Sopenharmony_ci * of course, the buffer size is zero). It does not pad 948c2ecf20Sopenharmony_ci * out the result like strncpy() does. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * If libc has strlcpy() then that version will override this 978c2ecf20Sopenharmony_ci * implementation: 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci#ifdef __clang__ 1008c2ecf20Sopenharmony_ci#pragma clang diagnostic push 1018c2ecf20Sopenharmony_ci#pragma clang diagnostic ignored "-Wignored-attributes" 1028c2ecf20Sopenharmony_ci#endif 1038c2ecf20Sopenharmony_cisize_t __weak strlcpy(char *dest, const char *src, size_t size) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci size_t ret = strlen(src); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (size) { 1088c2ecf20Sopenharmony_ci size_t len = (ret >= size) ? size - 1 : ret; 1098c2ecf20Sopenharmony_ci memcpy(dest, src, len); 1108c2ecf20Sopenharmony_ci dest[len] = '\0'; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci return ret; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci#ifdef __clang__ 1158c2ecf20Sopenharmony_ci#pragma clang diagnostic pop 1168c2ecf20Sopenharmony_ci#endif 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * skip_spaces - Removes leading whitespace from @str. 1208c2ecf20Sopenharmony_ci * @str: The string to be stripped. 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * Returns a pointer to the first non-whitespace character in @str. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cichar *skip_spaces(const char *str) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci while (isspace(*str)) 1278c2ecf20Sopenharmony_ci ++str; 1288c2ecf20Sopenharmony_ci return (char *)str; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * strim - Removes leading and trailing whitespace from @s. 1338c2ecf20Sopenharmony_ci * @s: The string to be stripped. 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * Note that the first trailing whitespace is replaced with a %NUL-terminator 1368c2ecf20Sopenharmony_ci * in the given string @s. Returns a pointer to the first non-whitespace 1378c2ecf20Sopenharmony_ci * character in @s. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_cichar *strim(char *s) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci size_t size; 1428c2ecf20Sopenharmony_ci char *end; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci size = strlen(s); 1458c2ecf20Sopenharmony_ci if (!size) 1468c2ecf20Sopenharmony_ci return s; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci end = s + size - 1; 1498c2ecf20Sopenharmony_ci while (end >= s && isspace(*end)) 1508c2ecf20Sopenharmony_ci end--; 1518c2ecf20Sopenharmony_ci *(end + 1) = '\0'; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return skip_spaces(s); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/** 1578c2ecf20Sopenharmony_ci * strreplace - Replace all occurrences of character in string. 1588c2ecf20Sopenharmony_ci * @s: The string to operate on. 1598c2ecf20Sopenharmony_ci * @old: The character being replaced. 1608c2ecf20Sopenharmony_ci * @new: The character @old is replaced with. 1618c2ecf20Sopenharmony_ci * 1628c2ecf20Sopenharmony_ci * Returns pointer to the nul byte at the end of @s. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_cichar *strreplace(char *s, char old, char new) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci for (; *s; ++s) 1678c2ecf20Sopenharmony_ci if (*s == old) 1688c2ecf20Sopenharmony_ci *s = new; 1698c2ecf20Sopenharmony_ci return s; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci while (bytes) { 1758c2ecf20Sopenharmony_ci if (*start != value) 1768c2ecf20Sopenharmony_ci return (void *)start; 1778c2ecf20Sopenharmony_ci start++; 1788c2ecf20Sopenharmony_ci bytes--; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci return NULL; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/** 1848c2ecf20Sopenharmony_ci * memchr_inv - Find an unmatching character in an area of memory. 1858c2ecf20Sopenharmony_ci * @start: The memory area 1868c2ecf20Sopenharmony_ci * @c: Find a character other than c 1878c2ecf20Sopenharmony_ci * @bytes: The size of the area. 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * returns the address of the first character other than @c, or %NULL 1908c2ecf20Sopenharmony_ci * if the whole buffer contains just @c. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_civoid *memchr_inv(const void *start, int c, size_t bytes) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci u8 value = c; 1958c2ecf20Sopenharmony_ci u64 value64; 1968c2ecf20Sopenharmony_ci unsigned int words, prefix; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (bytes <= 16) 1998c2ecf20Sopenharmony_ci return check_bytes8(start, value, bytes); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci value64 = value; 2028c2ecf20Sopenharmony_ci value64 |= value64 << 8; 2038c2ecf20Sopenharmony_ci value64 |= value64 << 16; 2048c2ecf20Sopenharmony_ci value64 |= value64 << 32; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci prefix = (unsigned long)start % 8; 2078c2ecf20Sopenharmony_ci if (prefix) { 2088c2ecf20Sopenharmony_ci u8 *r; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci prefix = 8 - prefix; 2118c2ecf20Sopenharmony_ci r = check_bytes8(start, value, prefix); 2128c2ecf20Sopenharmony_ci if (r) 2138c2ecf20Sopenharmony_ci return r; 2148c2ecf20Sopenharmony_ci start += prefix; 2158c2ecf20Sopenharmony_ci bytes -= prefix; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci words = bytes / 8; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci while (words) { 2218c2ecf20Sopenharmony_ci if (*(u64 *)start != value64) 2228c2ecf20Sopenharmony_ci return check_bytes8(start, value, 8); 2238c2ecf20Sopenharmony_ci start += 8; 2248c2ecf20Sopenharmony_ci words--; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return check_bytes8(start, value, bytes % 8); 2288c2ecf20Sopenharmony_ci} 229