1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * linux/tools/lib/string.c |
4 | * |
5 | * Copied from linux/lib/string.c, where it is: |
6 | * |
7 | * Copyright (C) 1991, 1992 Linus Torvalds |
8 | * |
9 | * More specifically, the first copied function was strtobool, which |
10 | * was introduced by: |
11 | * |
12 | * d0f1fed29e6e ("Add a strtobool function matching semantics of existing in kernel equivalents") |
13 | * Author: Jonathan Cameron <jic23@cam.ac.uk> |
14 | */ |
15 | |
16 | #include <stdlib.h> |
17 | #include <string.h> |
18 | #include <errno.h> |
19 | #include <linux/string.h> |
20 | #include <linux/ctype.h> |
21 | #include <linux/compiler.h> |
22 | |
23 | /** |
24 | * memdup - duplicate region of memory |
25 | * |
26 | * @src: memory region to duplicate |
27 | * @len: memory region length |
28 | */ |
29 | void *memdup(const void *src, size_t len) |
30 | { |
31 | void *p = malloc(len); |
32 | |
33 | if (p) |
34 | memcpy(p, src, len); |
35 | |
36 | return p; |
37 | } |
38 | |
39 | /** |
40 | * strtobool - convert common user inputs into boolean values |
41 | * @s: input string |
42 | * @res: result |
43 | * |
44 | * This routine returns 0 iff the first character is one of 'Yy1Nn0', or |
45 | * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value |
46 | * pointed to by res is updated upon finding a match. |
47 | */ |
48 | int strtobool(const char *s, bool *res) |
49 | { |
50 | if (!s) |
51 | return -EINVAL; |
52 | |
53 | switch (s[0]) { |
54 | case 'y': |
55 | case 'Y': |
56 | case '1': |
57 | *res = true; |
58 | return 0; |
59 | case 'n': |
60 | case 'N': |
61 | case '0': |
62 | *res = false; |
63 | return 0; |
64 | case 'o': |
65 | case 'O': |
66 | switch (s[1]) { |
67 | case 'n': |
68 | case 'N': |
69 | *res = true; |
70 | return 0; |
71 | case 'f': |
72 | case 'F': |
73 | *res = false; |
74 | return 0; |
75 | default: |
76 | break; |
77 | } |
78 | default: |
79 | break; |
80 | } |
81 | |
82 | return -EINVAL; |
83 | } |
84 | |
85 | /** |
86 | * strlcpy - Copy a C-string into a sized buffer |
87 | * @dest: Where to copy the string to |
88 | * @src: Where to copy the string from |
89 | * @size: size of destination buffer |
90 | * |
91 | * Compatible with *BSD: the result is always a valid |
92 | * NUL-terminated string that fits in the buffer (unless, |
93 | * of course, the buffer size is zero). It does not pad |
94 | * out the result like strncpy() does. |
95 | * |
96 | * If libc has strlcpy() then that version will override this |
97 | * implementation: |
98 | */ |
99 | #ifdef __clang__ |
100 | #pragma clang diagnostic push |
101 | #pragma clang diagnostic ignored "-Wignored-attributes" |
102 | #endif |
103 | size_t __weak strlcpy(char *dest, const char *src, size_t size) |
104 | { |
105 | size_t ret = strlen(src); |
106 | |
107 | if (size) { |
108 | size_t len = (ret >= size) ? size - 1 : ret; |
109 | memcpy(dest, src, len); |
110 | dest[len] = '\0'; |
111 | } |
112 | return ret; |
113 | } |
114 | #ifdef __clang__ |
115 | #pragma clang diagnostic pop |
116 | #endif |
117 | |
118 | /** |
119 | * skip_spaces - Removes leading whitespace from @str. |
120 | * @str: The string to be stripped. |
121 | * |
122 | * Returns a pointer to the first non-whitespace character in @str. |
123 | */ |
124 | char *skip_spaces(const char *str) |
125 | { |
126 | while (isspace(*str)) |
127 | ++str; |
128 | return (char *)str; |
129 | } |
130 | |
131 | /** |
132 | * strim - Removes leading and trailing whitespace from @s. |
133 | * @s: The string to be stripped. |
134 | * |
135 | * Note that the first trailing whitespace is replaced with a %NUL-terminator |
136 | * in the given string @s. Returns a pointer to the first non-whitespace |
137 | * character in @s. |
138 | */ |
139 | char *strim(char *s) |
140 | { |
141 | size_t size; |
142 | char *end; |
143 | |
144 | size = strlen(s); |
145 | if (!size) |
146 | return s; |
147 | |
148 | end = s + size - 1; |
149 | while (end >= s && isspace(*end)) |
150 | end--; |
151 | *(end + 1) = '\0'; |
152 | |
153 | return skip_spaces(str: s); |
154 | } |
155 | |
156 | /** |
157 | * strreplace - Replace all occurrences of character in string. |
158 | * @s: The string to operate on. |
159 | * @old: The character being replaced. |
160 | * @new: The character @old is replaced with. |
161 | * |
162 | * Returns pointer to the nul byte at the end of @s. |
163 | */ |
164 | char *strreplace(char *s, char old, char new) |
165 | { |
166 | for (; *s; ++s) |
167 | if (*s == old) |
168 | *s = new; |
169 | return s; |
170 | } |
171 | |
172 | static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) |
173 | { |
174 | while (bytes) { |
175 | if (*start != value) |
176 | return (void *)start; |
177 | start++; |
178 | bytes--; |
179 | } |
180 | return NULL; |
181 | } |
182 | |
183 | /** |
184 | * memchr_inv - Find an unmatching character in an area of memory. |
185 | * @start: The memory area |
186 | * @c: Find a character other than c |
187 | * @bytes: The size of the area. |
188 | * |
189 | * returns the address of the first character other than @c, or %NULL |
190 | * if the whole buffer contains just @c. |
191 | */ |
192 | void *memchr_inv(const void *start, int c, size_t bytes) |
193 | { |
194 | u8 value = c; |
195 | u64 value64; |
196 | unsigned int words, prefix; |
197 | |
198 | if (bytes <= 16) |
199 | return check_bytes8(start, value, bytes); |
200 | |
201 | value64 = value; |
202 | value64 |= value64 << 8; |
203 | value64 |= value64 << 16; |
204 | value64 |= value64 << 32; |
205 | |
206 | prefix = (unsigned long)start % 8; |
207 | if (prefix) { |
208 | u8 *r; |
209 | |
210 | prefix = 8 - prefix; |
211 | r = check_bytes8(start, value, bytes: prefix); |
212 | if (r) |
213 | return r; |
214 | start += prefix; |
215 | bytes -= prefix; |
216 | } |
217 | |
218 | words = bytes / 8; |
219 | |
220 | while (words) { |
221 | if (*(u64 *)start != value64) |
222 | return check_bytes8(start, value, bytes: 8); |
223 | start += 8; |
224 | words--; |
225 | } |
226 | |
227 | return check_bytes8(start, value, bytes: bytes % 8); |
228 | } |
229 | |