blob: 1f889e9cc0851d551fcd11131bfb3806c8e9e47f [file] [log] [blame]
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07001/* string.c - common string routines */
2
3/*
4 * Copyright (c) 2014 Wind River Systems, Inc.
5 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08006 * SPDX-License-Identifier: Apache-2.0
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07007 */
8
9#include <string.h>
Nicolas Pitre03170c02019-05-27 19:26:46 -040010#include <stdint.h>
11#include <sys/types.h>
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070012
Anas Nashifea0d0b22015-07-01 17:22:39 -040013/**
14 *
Anas Nashiff367f072015-07-01 17:51:40 -040015 * @brief Copy a string
Anas Nashifea0d0b22015-07-01 17:22:39 -040016 *
Anas Nashif1362e3c2015-07-01 17:29:04 -040017 * @return pointer to destination buffer <d>
Anas Nashifea0d0b22015-07-01 17:22:39 -040018 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070019
Andrew Boiec2a91b12017-02-02 12:01:59 -080020char *strcpy(char *_MLIBC_RESTRICT d, const char *_MLIBC_RESTRICT s)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070021{
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
Anas Nashifea0d0b22015-07-01 17:22:39 -040035/**
36 *
Anas Nashiff367f072015-07-01 17:51:40 -040037 * @brief Copy part of a string
Anas Nashifea0d0b22015-07-01 17:22:39 -040038 *
Anas Nashif1362e3c2015-07-01 17:29:04 -040039 * @return pointer to destination buffer <d>
Anas Nashifea0d0b22015-07-01 17:22:39 -040040 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070041
Andrew Boiec2a91b12017-02-02 12:01:59 -080042char *strncpy(char *_MLIBC_RESTRICT d, const char *_MLIBC_RESTRICT s, size_t n)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070043{
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';
Peter Mitsis7637d812015-04-28 10:10:42 -040055 d++;
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070056 n--;
57 }
58
59 return dest;
60}
61
Anas Nashifea0d0b22015-07-01 17:22:39 -040062/**
63 *
Anas Nashiff367f072015-07-01 17:51:40 -040064 * @brief String scanning operation
Anas Nashifea0d0b22015-07-01 17:22:39 -040065 *
Anas Nashif1362e3c2015-07-01 17:29:04 -040066 * @return pointer to 1st instance of found byte, or NULL if not found
Anas Nashifea0d0b22015-07-01 17:22:39 -040067 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070068
69char *strchr(const char *s, int c)
70{
71 char tmp = (char) c;
72
Anas Nashif4c322582019-06-04 10:52:23 -040073 while ((*s != tmp) && (*s != '\0')) {
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070074 s++;
Anas Nashif4c322582019-06-04 10:52:23 -040075 }
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070076
77 return (*s == tmp) ? (char *) s : NULL;
78}
79
Anas Nashifea0d0b22015-07-01 17:22:39 -040080/**
81 *
Jaakko Hannikainen24a2fb12016-08-24 14:56:02 +030082 * @brief String scanning operation
83 *
84 * @return pointer to last instance of found byte, or NULL if not found
85 */
86
87char *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++);
96
97 return match;
98}
99
100/**
101 *
Anas Nashiff367f072015-07-01 17:51:40 -0400102 * @brief Get string length
Anas Nashifea0d0b22015-07-01 17:22:39 -0400103 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400104 * @return number of bytes in string <s>
Anas Nashifea0d0b22015-07-01 17:22:39 -0400105 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700106
107size_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
Anas Nashifea0d0b22015-07-01 17:22:39 -0400119/**
120 *
Timo Teräs55dc4812018-09-26 13:02:41 +0300121 * @brief Get fixed-size string length
122 *
123 * @return number of bytes in fixed-size string <s>
124 */
125
126size_t strnlen(const char *s, size_t maxlen)
127{
128 size_t n = 0;
129
130 while (*s != '\0' && n < maxlen) {
131 s++;
132 n++;
133 }
134
135 return n;
136}
137
138/**
139 *
Anas Nashiff367f072015-07-01 17:51:40 -0400140 * @brief Compare two strings
Anas Nashifea0d0b22015-07-01 17:22:39 -0400141 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400142 * @return negative # if <s1> < <s2>, 0 if <s1> == <s2>, else positive #
Anas Nashifea0d0b22015-07-01 17:22:39 -0400143 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700144
145int strcmp(const char *s1, const char *s2)
146{
147 while ((*s1 == *s2) && (*s1 != '\0')) {
148 s1++;
149 s2++;
150 }
151
152 return *s1 - *s2;
153}
154
Anas Nashifea0d0b22015-07-01 17:22:39 -0400155/**
156 *
Anas Nashiff367f072015-07-01 17:51:40 -0400157 * @brief Compare part of two strings
Anas Nashifea0d0b22015-07-01 17:22:39 -0400158 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400159 * @return negative # if <s1> < <s2>, 0 if <s1> == <s2>, else positive #
Anas Nashifea0d0b22015-07-01 17:22:39 -0400160 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700161
162int strncmp(const char *s1, const char *s2, size_t n)
163{
164 while ((n > 0) && (*s1 == *s2) && (*s1 != '\0')) {
165 s1++;
166 s2++;
167 n--;
168 }
169
170 return (n == 0) ? 0 : (*s1 - *s2);
171}
172
Siddharth Chandrasekaran06375952020-08-17 18:46:48 +0530173/**
174 * @brief Separate `str` by any char in `sep` and return NULL terminated
175 * sections. Consecutive `sep` chars in `str` are treated as a single
176 * separator.
177 *
178 * @return pointer to NULL terminated string or NULL on errors.
179 */
180char *strtok_r(char *str, const char *sep, char **state)
181{
182 char *start, *end;
183
184 start = str ? str : *state;
185
186 /* skip leading delimiters */
187 while (*start && strchr(sep, *start)) {
188 start++;
189 }
190
191 if (*start == '\0') {
192 *state = start;
193 return NULL;
194 }
195
196 /* look for token chars */
197 end = start;
198 while (*end && !strchr(sep, *end)) {
199 end++;
200 }
201
202 if (*end != '\0') {
203 *end = '\0';
204 *state = end + 1;
205 } else {
206 *state = end;
207 }
208
209 return start;
210}
211
Andrew Boiec2a91b12017-02-02 12:01:59 -0800212char *strcat(char *_MLIBC_RESTRICT dest, const char *_MLIBC_RESTRICT src)
Anas Nashif9d648eb2015-07-31 06:57:00 -0400213{
214 strcpy(dest + strlen(dest), src);
215 return dest;
216}
217
Andrew Boiec2a91b12017-02-02 12:01:59 -0800218char *strncat(char *_MLIBC_RESTRICT dest, const char *_MLIBC_RESTRICT src,
219 size_t n)
Benjamin Walshf557d712016-04-11 17:14:47 -0400220{
221 char *orig_dest = dest;
222 size_t len = strlen(dest);
223
224 dest += len;
225 while ((n-- > 0) && (*src != '\0')) {
226 *dest++ = *src++;
227 }
228 *dest = '\0';
229
230 return orig_dest;
231}
232
Anas Nashifea0d0b22015-07-01 17:22:39 -0400233/**
234 *
Anas Nashiff367f072015-07-01 17:51:40 -0400235 * @brief Compare two memory areas
Anas Nashifea0d0b22015-07-01 17:22:39 -0400236 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400237 * @return negative # if <m1> < <m2>, 0 if <m1> == <m2>, else positive #
Anas Nashifea0d0b22015-07-01 17:22:39 -0400238 */
Johan Hedberg7fc1c372015-05-19 11:36:53 +0300239int memcmp(const void *m1, const void *m2, size_t n)
240{
241 const char *c1 = m1;
242 const char *c2 = m2;
243
Anas Nashif4c322582019-06-04 10:52:23 -0400244 if (!n) {
Johan Hedbergafffab12015-05-19 20:43:30 +0300245 return 0;
Anas Nashif4c322582019-06-04 10:52:23 -0400246 }
Johan Hedbergafffab12015-05-19 20:43:30 +0300247
248 while ((--n > 0) && (*c1 == *c2)) {
Johan Hedberg7fc1c372015-05-19 11:36:53 +0300249 c1++;
250 c2++;
Johan Hedberg7fc1c372015-05-19 11:36:53 +0300251 }
252
253 return *c1 - *c2;
254}
255
Anas Nashifea0d0b22015-07-01 17:22:39 -0400256/**
257 *
Anas Nashiff367f072015-07-01 17:51:40 -0400258 * @brief Copy bytes in memory with overlapping areas
Anas Nashifea0d0b22015-07-01 17:22:39 -0400259 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400260 * @return pointer to destination buffer <d>
Anas Nashifea0d0b22015-07-01 17:22:39 -0400261 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700262
263void *memmove(void *d, const void *s, size_t n)
264{
265 char *dest = d;
266 const char *src = s;
267
Mark Ruvald Pedersend67096d2018-09-14 14:24:09 +0200268 if ((size_t) (dest - src) < n) {
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700269 /*
270 * The <src> buffer overlaps with the start of the <dest> buffer.
271 * Copy backwards to prevent the premature corruption of <src>.
272 */
273
274 while (n > 0) {
275 n--;
276 dest[n] = src[n];
277 }
278 } else {
279 /* It is safe to perform a forward-copy */
280 while (n > 0) {
281 *dest = *src;
282 dest++;
283 src++;
284 n--;
285 }
286 }
287
288 return d;
289}
290
Anas Nashifea0d0b22015-07-01 17:22:39 -0400291/**
292 *
Anas Nashiff367f072015-07-01 17:51:40 -0400293 * @brief Copy bytes in memory
Anas Nashifea0d0b22015-07-01 17:22:39 -0400294 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400295 * @return pointer to start of destination buffer
Anas Nashifea0d0b22015-07-01 17:22:39 -0400296 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700297
Andrew Boiec2a91b12017-02-02 12:01:59 -0800298void *memcpy(void *_MLIBC_RESTRICT d, const void *_MLIBC_RESTRICT s, size_t n)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700299{
Allan Stephensb52a09f2015-05-25 13:50:16 -0400300 /* attempt word-sized copying only if buffers have identical alignment */
301
302 unsigned char *d_byte = (unsigned char *)d;
303 const unsigned char *s_byte = (const unsigned char *)s;
Michael Hope5d557302021-06-25 20:17:36 +0200304
305#if !defined(CONFIG_MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE)
Nicolas Pitre03170c02019-05-27 19:26:46 -0400306 const uintptr_t mask = sizeof(mem_word_t) - 1;
Allan Stephensb52a09f2015-05-25 13:50:16 -0400307
Nicolas Pitre03170c02019-05-27 19:26:46 -0400308 if ((((uintptr_t)d ^ (uintptr_t)s_byte) & mask) == 0) {
Allan Stephensb52a09f2015-05-25 13:50:16 -0400309
310 /* do byte-sized copying until word-aligned or finished */
311
Nicolas Pitre03170c02019-05-27 19:26:46 -0400312 while (((uintptr_t)d_byte) & mask) {
Allan Stephensb52a09f2015-05-25 13:50:16 -0400313 if (n == 0) {
314 return d;
315 }
316 *(d_byte++) = *(s_byte++);
317 n--;
Flavio Ceolin9fd4ea92021-03-24 16:39:15 -0700318 }
Allan Stephensb52a09f2015-05-25 13:50:16 -0400319
320 /* do word-sized copying as long as possible */
321
Nicolas Pitre03170c02019-05-27 19:26:46 -0400322 mem_word_t *d_word = (mem_word_t *)d_byte;
323 const mem_word_t *s_word = (const mem_word_t *)s_byte;
Allan Stephensb52a09f2015-05-25 13:50:16 -0400324
Nicolas Pitre03170c02019-05-27 19:26:46 -0400325 while (n >= sizeof(mem_word_t)) {
Allan Stephensb52a09f2015-05-25 13:50:16 -0400326 *(d_word++) = *(s_word++);
Nicolas Pitre03170c02019-05-27 19:26:46 -0400327 n -= sizeof(mem_word_t);
Allan Stephensb52a09f2015-05-25 13:50:16 -0400328 }
329
330 d_byte = (unsigned char *)d_word;
331 s_byte = (unsigned char *)s_word;
332 }
Michael Hope5d557302021-06-25 20:17:36 +0200333#endif
Allan Stephensb52a09f2015-05-25 13:50:16 -0400334
335 /* do byte-sized copying until finished */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700336
337 while (n > 0) {
Allan Stephensb52a09f2015-05-25 13:50:16 -0400338 *(d_byte++) = *(s_byte++);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700339 n--;
340 }
341
342 return d;
343}
344
Anas Nashifea0d0b22015-07-01 17:22:39 -0400345/**
346 *
Anas Nashiff367f072015-07-01 17:51:40 -0400347 * @brief Set bytes in memory
Anas Nashifea0d0b22015-07-01 17:22:39 -0400348 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400349 * @return pointer to start of buffer
Anas Nashifea0d0b22015-07-01 17:22:39 -0400350 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700351
Allan Stephensb52a09f2015-05-25 13:50:16 -0400352void *memset(void *buf, int c, size_t n)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700353{
Allan Stephensb52a09f2015-05-25 13:50:16 -0400354 /* do byte-sized initialization until word-aligned or finished */
355
356 unsigned char *d_byte = (unsigned char *)buf;
357 unsigned char c_byte = (unsigned char)c;
358
Michael Hope5d557302021-06-25 20:17:36 +0200359#if !defined(CONFIG_MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE)
Nicolas Pitre03170c02019-05-27 19:26:46 -0400360 while (((uintptr_t)d_byte) & (sizeof(mem_word_t) - 1)) {
Allan Stephensb52a09f2015-05-25 13:50:16 -0400361 if (n == 0) {
362 return buf;
363 }
364 *(d_byte++) = c_byte;
365 n--;
Flavio Ceolin9fd4ea92021-03-24 16:39:15 -0700366 }
Allan Stephensb52a09f2015-05-25 13:50:16 -0400367
368 /* do word-sized initialization as long as possible */
369
Nicolas Pitre03170c02019-05-27 19:26:46 -0400370 mem_word_t *d_word = (mem_word_t *)d_byte;
371 mem_word_t c_word = (mem_word_t)c_byte;
Allan Stephensb52a09f2015-05-25 13:50:16 -0400372
373 c_word |= c_word << 8;
374 c_word |= c_word << 16;
Nicolas Pitre03170c02019-05-27 19:26:46 -0400375#if Z_MEM_WORD_T_WIDTH > 32
376 c_word |= c_word << 32;
377#endif
Allan Stephensb52a09f2015-05-25 13:50:16 -0400378
Nicolas Pitre03170c02019-05-27 19:26:46 -0400379 while (n >= sizeof(mem_word_t)) {
Allan Stephensb52a09f2015-05-25 13:50:16 -0400380 *(d_word++) = c_word;
Nicolas Pitre03170c02019-05-27 19:26:46 -0400381 n -= sizeof(mem_word_t);
Allan Stephensb52a09f2015-05-25 13:50:16 -0400382 }
383
384 /* do byte-sized initialization until finished */
385
386 d_byte = (unsigned char *)d_word;
Michael Hope5d557302021-06-25 20:17:36 +0200387#endif
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700388
389 while (n > 0) {
Allan Stephensb52a09f2015-05-25 13:50:16 -0400390 *(d_byte++) = c_byte;
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700391 n--;
392 }
393
Allan Stephensb52a09f2015-05-25 13:50:16 -0400394 return buf;
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700395}
Jukka Rissanenefed4462015-08-14 15:03:59 +0300396
397/**
398 *
399 * @brief Scan byte in memory
400 *
401 * @return pointer to start of found byte
402 */
403
Nicolas Pitreffab1972019-07-08 23:02:59 -0400404void *memchr(const void *s, int c, size_t n)
Jukka Rissanenefed4462015-08-14 15:03:59 +0300405{
406 if (n != 0) {
407 const unsigned char *p = s;
408
409 do {
Nicolas Pitreffab1972019-07-08 23:02:59 -0400410 if (*p++ == (unsigned char)c) {
Jukka Rissanenefed4462015-08-14 15:03:59 +0300411 return ((void *)(p - 1));
412 }
413
414 } while (--n != 0);
415 }
416
417 return NULL;
418}