1 /* string.c - common string routines */
2
3 /*
4 * Copyright (c) 2014 Wind River Systems, Inc.
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <string.h>
10 #include <stdint.h>
11 #include <sys/types.h>
12
13 /**
14 *
15 * @brief Copy a string
16 *
17 * @return pointer to destination buffer <d>
18 */
19
strcpy(char * ZRESTRICT d,const char * ZRESTRICT s)20 char *strcpy(char *ZRESTRICT d, const char *ZRESTRICT s)
21 {
22 char *dest = d;
23
24 while (*s != '\0') {
25 *d = *s;
26 d++;
27 s++;
28 }
29
30 *d = '\0';
31
32 return dest;
33 }
34
35 /**
36 *
37 * @brief Copy part of a string
38 *
39 * @return pointer to destination buffer <d>
40 */
41
strncpy(char * ZRESTRICT d,const char * ZRESTRICT s,size_t n)42 char *strncpy(char *ZRESTRICT d, const char *ZRESTRICT s, size_t n)
43 {
44 char *dest = d;
45
46 while ((n > 0) && (*s != '\0')) {
47 *d = *s;
48 s++;
49 d++;
50 n--;
51 }
52
53 while (n > 0) {
54 *d = '\0';
55 d++;
56 n--;
57 }
58
59 return dest;
60 }
61
62 /**
63 *
64 * @brief String scanning operation
65 *
66 * @return pointer to 1st instance of found byte, or NULL if not found
67 */
68
strchr(const char * s,int c)69 char *strchr(const char *s, int c)
70 {
71 char tmp = (char) c;
72
73 while ((*s != tmp) && (*s != '\0')) {
74 s++;
75 }
76
77 return (*s == tmp) ? (char *) s : NULL;
78 }
79
80 /**
81 *
82 * @brief String scanning operation
83 *
84 * @return pointer to last instance of found byte, or NULL if not found
85 */
86
strrchr(const char * s,int c)87 char *strrchr(const char *s, int c)
88 {
89 char *match = NULL;
90
91 do {
92 if (*s == (char)c) {
93 match = (char *)s;
94 }
95 } while (*s++ != '\0');
96
97 return match;
98 }
99
100 /**
101 *
102 * @brief Get string length
103 *
104 * @return number of bytes in string <s>
105 */
106
strlen(const char * s)107 size_t strlen(const char *s)
108 {
109 size_t n = 0;
110
111 while (*s != '\0') {
112 s++;
113 n++;
114 }
115
116 return n;
117 }
118
119 /**
120 *
121 * @brief Compare two strings
122 *
123 * @return negative # if <s1> < <s2>, 0 if <s1> == <s2>, else positive #
124 */
125
strcmp(const char * s1,const char * s2)126 int strcmp(const char *s1, const char *s2)
127 {
128 while ((*s1 == *s2) && (*s1 != '\0')) {
129 s1++;
130 s2++;
131 }
132
133 return *s1 - *s2;
134 }
135
136 /**
137 *
138 * @brief Compare part of two strings
139 *
140 * @return negative # if <s1> < <s2>, 0 if <s1> == <s2>, else positive #
141 */
142
strncmp(const char * s1,const char * s2,size_t n)143 int strncmp(const char *s1, const char *s2, size_t n)
144 {
145 while ((n > 0) && (*s1 == *s2) && (*s1 != '\0')) {
146 s1++;
147 s2++;
148 n--;
149 }
150
151 return (n == 0) ? 0 : (*s1 - *s2);
152 }
153
154 /**
155 * @brief Separate `str` by any char in `sep` and return NULL terminated
156 * sections. Consecutive `sep` chars in `str` are treated as a single
157 * separator.
158 *
159 * @return pointer to NULL terminated string or NULL on errors.
160 */
strtok_r(char * str,const char * sep,char ** state)161 char *strtok_r(char *str, const char *sep, char **state)
162 {
163 char *start, *end;
164
165 start = str ? str : *state;
166
167 /* skip leading delimiters */
168 while (*start && strchr(sep, *start)) {
169 start++;
170 }
171
172 if (*start == '\0') {
173 *state = start;
174 return NULL;
175 }
176
177 /* look for token chars */
178 end = start;
179 while (*end && !strchr(sep, *end)) {
180 end++;
181 }
182
183 if (*end != '\0') {
184 *end = '\0';
185 *state = end + 1;
186 } else {
187 *state = end;
188 }
189
190 return start;
191 }
192
strcat(char * ZRESTRICT dest,const char * ZRESTRICT src)193 char *strcat(char *ZRESTRICT dest, const char *ZRESTRICT src)
194 {
195 strcpy(dest + strlen(dest), src);
196 return dest;
197 }
198
strncat(char * ZRESTRICT dest,const char * ZRESTRICT src,size_t n)199 char *strncat(char *ZRESTRICT dest, const char *ZRESTRICT src,
200 size_t n)
201 {
202 char *orig_dest = dest;
203 size_t len = strlen(dest);
204
205 dest += len;
206 while ((n-- > 0) && (*src != '\0')) {
207 *dest++ = *src++;
208 }
209 *dest = '\0';
210
211 return orig_dest;
212 }
213
214 /**
215 *
216 * @brief Compare two memory areas
217 *
218 * @return negative # if <m1> < <m2>, 0 if <m1> == <m2>, else positive #
219 */
memcmp(const void * m1,const void * m2,size_t n)220 int memcmp(const void *m1, const void *m2, size_t n)
221 {
222 const char *c1 = m1;
223 const char *c2 = m2;
224
225 if (!n) {
226 return 0;
227 }
228
229 while ((--n > 0) && (*c1 == *c2)) {
230 c1++;
231 c2++;
232 }
233
234 return *c1 - *c2;
235 }
236
237 /**
238 *
239 * @brief Copy bytes in memory with overlapping areas
240 *
241 * @return pointer to destination buffer <d>
242 */
243
memmove(void * d,const void * s,size_t n)244 void *memmove(void *d, const void *s, size_t n)
245 {
246 char *dest = d;
247 const char *src = s;
248
249 if ((size_t) (dest - src) < n) {
250 /*
251 * The <src> buffer overlaps with the start of the <dest> buffer.
252 * Copy backwards to prevent the premature corruption of <src>.
253 */
254
255 while (n > 0) {
256 n--;
257 dest[n] = src[n];
258 }
259 } else {
260 /* It is safe to perform a forward-copy */
261 while (n > 0) {
262 *dest = *src;
263 dest++;
264 src++;
265 n--;
266 }
267 }
268
269 return d;
270 }
271
272 /**
273 *
274 * @brief Copy bytes in memory
275 *
276 * @return pointer to start of destination buffer
277 */
278
memcpy(void * ZRESTRICT d,const void * ZRESTRICT s,size_t n)279 void *memcpy(void *ZRESTRICT d, const void *ZRESTRICT s, size_t n)
280 {
281 /* attempt word-sized copying only if buffers have identical alignment */
282
283 unsigned char *d_byte = (unsigned char *)d;
284 const unsigned char *s_byte = (const unsigned char *)s;
285
286 #if !defined(CONFIG_MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE)
287 const uintptr_t mask = sizeof(mem_word_t) - 1;
288
289 if ((((uintptr_t)d ^ (uintptr_t)s_byte) & mask) == 0) {
290
291 /* do byte-sized copying until word-aligned or finished */
292
293 while (((uintptr_t)d_byte) & mask) {
294 if (n == 0) {
295 return d;
296 }
297 *(d_byte++) = *(s_byte++);
298 n--;
299 }
300
301 /* do word-sized copying as long as possible */
302
303 mem_word_t *d_word = (mem_word_t *)d_byte;
304 const mem_word_t *s_word = (const mem_word_t *)s_byte;
305
306 while (n >= sizeof(mem_word_t)) {
307 *(d_word++) = *(s_word++);
308 n -= sizeof(mem_word_t);
309 }
310
311 d_byte = (unsigned char *)d_word;
312 s_byte = (unsigned char *)s_word;
313 }
314 #endif
315
316 /* do byte-sized copying until finished */
317
318 while (n > 0) {
319 *(d_byte++) = *(s_byte++);
320 n--;
321 }
322
323 return d;
324 }
325
326 /**
327 *
328 * @brief Set bytes in memory
329 *
330 * @return pointer to start of buffer
331 */
332
memset(void * buf,int c,size_t n)333 void *memset(void *buf, int c, size_t n)
334 {
335 /* do byte-sized initialization until word-aligned or finished */
336
337 unsigned char *d_byte = (unsigned char *)buf;
338 unsigned char c_byte = (unsigned char)c;
339
340 #if !defined(CONFIG_MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE)
341 while (((uintptr_t)d_byte) & (sizeof(mem_word_t) - 1)) {
342 if (n == 0) {
343 return buf;
344 }
345 *(d_byte++) = c_byte;
346 n--;
347 }
348
349 /* do word-sized initialization as long as possible */
350
351 mem_word_t *d_word = (mem_word_t *)d_byte;
352 mem_word_t c_word = (mem_word_t)c_byte;
353
354 c_word |= c_word << 8;
355 c_word |= c_word << 16;
356 #if Z_MEM_WORD_T_WIDTH > 32
357 c_word |= c_word << 32;
358 #endif
359
360 while (n >= sizeof(mem_word_t)) {
361 *(d_word++) = c_word;
362 n -= sizeof(mem_word_t);
363 }
364
365 /* do byte-sized initialization until finished */
366
367 d_byte = (unsigned char *)d_word;
368 #endif
369
370 while (n > 0) {
371 *(d_byte++) = c_byte;
372 n--;
373 }
374
375 return buf;
376 }
377
378 /**
379 *
380 * @brief Scan byte in memory
381 *
382 * @return pointer to start of found byte
383 */
384
memchr(const void * s,int c,size_t n)385 void *memchr(const void *s, int c, size_t n)
386 {
387 if (n != 0) {
388 const unsigned char *p = s;
389
390 do {
391 if (*p++ == (unsigned char)c) {
392 return ((void *)(p - 1));
393 }
394
395 } while (--n != 0);
396 }
397
398 return NULL;
399 }
400