1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-03-10 Meco Man the first version
9 */
10
11 #include <rtthread.h>
12
13 #if defined(RT_KLIBC_USING_LIBC_MEMSET) || \
14 defined(RT_KLIBC_USING_LIBC_MEMCPY) || \
15 defined(RT_KLIBC_USING_LIBC_MEMMOVE) || \
16 defined(RT_KLIBC_USING_LIBC_MEMCMP) || \
17 defined(RT_KLIBC_USING_LIBC_STRSTR) || \
18 defined(RT_KLIBC_USING_LIBC_STRNCPY) || \
19 defined(RT_KLIBC_USING_LIBC_STRCPY) || \
20 defined(RT_KLIBC_USING_LIBC_STRNCMP) || \
21 defined(RT_KLIBC_USING_LIBC_STRCMP) || \
22 defined(RT_KLIBC_USING_LIBC_STRLEN)
23 #include <string.h>
24 #endif
25
26 /**
27 * @brief This function will set the content of memory to specified value.
28 *
29 * @param s is the address of source memory, point to the memory block to be filled.
30 *
31 * @param c is the value to be set. The value is passed in int form, but the function
32 * uses the unsigned character form of the value when filling the memory block.
33 *
34 * @param count number of bytes to be set.
35 *
36 * @return The address of source memory.
37 */
38 #ifndef RT_KLIBC_USING_USER_MEMSET
rt_memset(void * s,int c,rt_ubase_t count)39 void *rt_memset(void *s, int c, rt_ubase_t count)
40 {
41 #if defined(RT_KLIBC_USING_LIBC_MEMSET)
42 return memset(s, c, count);
43 #elif defined(RT_KLIBC_USING_TINY_MEMSET)
44 char *xs = (char *)s;
45
46 while (count--)
47 *xs++ = c;
48
49 return s;
50 #else
51
52 #define LBLOCKSIZE (sizeof(rt_ubase_t))
53 #define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
54 #define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
55
56 unsigned int i = 0;
57 char *m = (char *)s;
58 unsigned long buffer = 0;
59 unsigned long *aligned_addr = RT_NULL;
60 unsigned char d = (unsigned int)c & (unsigned char)(-1); /* To avoid sign extension, copy C to an
61 unsigned variable. (unsigned)((char)(-1))=0xFF for 8bit and =0xFFFF for 16bit: word independent */
62
63 RT_ASSERT(LBLOCKSIZE == 2 || LBLOCKSIZE == 4 || LBLOCKSIZE == 8);
64
65 if (!TOO_SMALL(count) && !UNALIGNED(s))
66 {
67 /* If we get this far, we know that count is large and s is word-aligned. */
68 aligned_addr = (unsigned long *)s;
69
70 /* Store d into each char sized location in buffer so that
71 * we can set large blocks quickly.
72 */
73 for (i = 0; i < LBLOCKSIZE; i++)
74 {
75 *(((unsigned char *)&buffer)+i) = d;
76 }
77
78 while (count >= LBLOCKSIZE * 4)
79 {
80 *aligned_addr++ = buffer;
81 *aligned_addr++ = buffer;
82 *aligned_addr++ = buffer;
83 *aligned_addr++ = buffer;
84 count -= 4 * LBLOCKSIZE;
85 }
86
87 while (count >= LBLOCKSIZE)
88 {
89 *aligned_addr++ = buffer;
90 count -= LBLOCKSIZE;
91 }
92
93 /* Pick up the remainder with a bytewise loop. */
94 m = (char *)aligned_addr;
95 }
96
97 while (count--)
98 {
99 *m++ = (char)d;
100 }
101
102 return s;
103
104 #undef LBLOCKSIZE
105 #undef UNALIGNED
106 #undef TOO_SMALL
107 #endif /* RT_KLIBC_USING_LIBC_MEMSET */
108 }
109 #endif /* RT_KLIBC_USING_USER_MEMSET */
110 RTM_EXPORT(rt_memset);
111
112 /**
113 * @brief This function will copy memory content from source address to destination address.
114 *
115 * @param dst is the address of destination memory, points to the copied content.
116 *
117 * @param src is the address of source memory, pointing to the data source to be copied.
118 *
119 * @param count is the copied length.
120 *
121 * @return The address of destination memory
122 */
123 #ifndef RT_KLIBC_USING_USER_MEMCPY
rt_memcpy(void * dst,const void * src,rt_ubase_t count)124 void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
125 {
126 #if defined(RT_KLIBC_USING_LIBC_MEMCPY)
127 return memcpy(dst, src, count);
128 #elif defined(RT_KLIBC_USING_TINY_MEMCPY)
129 char *tmp = (char *)dst, *s = (char *)src;
130 rt_ubase_t len = 0;
131
132 if (tmp <= s || tmp > (s + count))
133 {
134 while (count--)
135 *tmp ++ = *s ++;
136 }
137 else
138 {
139 for (len = count; len > 0; len --)
140 tmp[len - 1] = s[len - 1];
141 }
142
143 return dst;
144 #else
145
146 #define UNALIGNED(X, Y) \
147 (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
148 #define BIGBLOCKSIZE (sizeof (long) << 2)
149 #define LITTLEBLOCKSIZE (sizeof (long))
150 #define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
151
152 char *dst_ptr = (char *)dst;
153 char *src_ptr = (char *)src;
154 long *aligned_dst = RT_NULL;
155 long *aligned_src = RT_NULL;
156 rt_ubase_t len = count;
157
158 /* If the size is small, or either SRC or DST is unaligned,
159 then punt into the byte copy loop. This should be rare. */
160 if (!TOO_SMALL(len) && !UNALIGNED(src_ptr, dst_ptr))
161 {
162 aligned_dst = (long *)dst_ptr;
163 aligned_src = (long *)src_ptr;
164
165 /* Copy 4X long words at a time if possible. */
166 while (len >= BIGBLOCKSIZE)
167 {
168 *aligned_dst++ = *aligned_src++;
169 *aligned_dst++ = *aligned_src++;
170 *aligned_dst++ = *aligned_src++;
171 *aligned_dst++ = *aligned_src++;
172 len -= BIGBLOCKSIZE;
173 }
174
175 /* Copy one long word at a time if possible. */
176 while (len >= LITTLEBLOCKSIZE)
177 {
178 *aligned_dst++ = *aligned_src++;
179 len -= LITTLEBLOCKSIZE;
180 }
181
182 /* Pick up any residual with a byte copier. */
183 dst_ptr = (char *)aligned_dst;
184 src_ptr = (char *)aligned_src;
185 }
186
187 while (len--)
188 *dst_ptr++ = *src_ptr++;
189
190 return dst;
191 #undef UNALIGNED
192 #undef BIGBLOCKSIZE
193 #undef LITTLEBLOCKSIZE
194 #undef TOO_SMALL
195 #endif /* RT_KLIBC_USING_LIBC_MEMCPY */
196 }
197 #endif /* RT_KLIBC_USING_USER_MEMCPY */
198 RTM_EXPORT(rt_memcpy);
199
200 /**
201 * @brief This function will move memory content from source address to destination
202 * address. If the destination memory does not overlap with the source memory,
203 * the function is the same as memcpy().
204 *
205 * @param dest is the address of destination memory, points to the copied content.
206 *
207 * @param src is the address of source memory, point to the data source to be copied.
208 *
209 * @param n is the copied length.
210 *
211 * @return The address of destination memory.
212 */
213 #ifndef RT_KLIBC_USING_USER_MEMMOVE
rt_memmove(void * dest,const void * src,rt_size_t n)214 void *rt_memmove(void *dest, const void *src, rt_size_t n)
215 {
216 #ifdef RT_KLIBC_USING_LIBC_MEMMOVE
217 return memmove(dest, src, n);
218 #else
219 char *tmp = (char *)dest, *s = (char *)src;
220
221 if (s < tmp && tmp < s + n)
222 {
223 tmp += n;
224 s += n;
225
226 while (n--)
227 *(--tmp) = *(--s);
228 }
229 else
230 {
231 while (n--)
232 *tmp++ = *s++;
233 }
234
235 return dest;
236 #endif /* RT_KLIBC_USING_LIBC_MEMMOVE */
237 }
238 #endif /* RT_KLIBC_USING_USER_MEMMOVE */
239 RTM_EXPORT(rt_memmove);
240
241 /**
242 * @brief This function will compare two areas of memory.
243 *
244 * @param cs is a block of memory.
245 *
246 * @param ct is another block of memory.
247 *
248 * @param count is the size of the area.
249 *
250 * @return Compare the results:
251 * If the result < 0, cs is smaller than ct.
252 * If the result > 0, cs is greater than ct.
253 * If the result = 0, cs is equal to ct.
254 */
255 #ifndef RT_KLIBC_USING_USER_MEMCMP
rt_memcmp(const void * cs,const void * ct,rt_size_t count)256 rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_size_t count)
257 {
258 #ifdef RT_KLIBC_USING_LIBC_MEMCMP
259 return memcmp(cs, ct, count);
260 #else
261 const unsigned char *su1 = RT_NULL, *su2 = RT_NULL;
262 int res = 0;
263
264 for (su1 = (const unsigned char *)cs, su2 = (const unsigned char *)ct; 0 < count; ++su1, ++su2, count--)
265 if ((res = *su1 - *su2) != 0)
266 break;
267
268 return res;
269 #endif /* RT_KLIBC_USING_LIBC_MEMCMP */
270 }
271 #endif /* RT_KLIBC_USING_USER_MEMCMP */
272 RTM_EXPORT(rt_memcmp);
273
274 /**
275 * @brief This function will return the first occurrence of a string, without the
276 * terminator '\0'.
277 *
278 * @param s1 is the source string.
279 *
280 * @param s2 is the find string.
281 *
282 * @return The first occurrence of a s2 in s1, or RT_NULL if no found.
283 */
284 #ifndef RT_KLIBC_USING_USER_STRSTR
rt_strstr(const char * s1,const char * s2)285 char *rt_strstr(const char *s1, const char *s2)
286 {
287 #ifdef RT_KLIBC_USING_LIBC_STRSTR
288 return strstr(s1, s2);
289 #else
290 int l1 = 0, l2 = 0;
291
292 l2 = rt_strlen(s2);
293 if (!l2)
294 {
295 return (char *)s1;
296 }
297
298 l1 = rt_strlen(s1);
299 while (l1 >= l2)
300 {
301 l1 --;
302 if (!rt_memcmp(s1, s2, l2))
303 {
304 return (char *)s1;
305 }
306
307 s1 ++;
308 }
309
310 return RT_NULL;
311 #endif /* RT_KLIBC_USING_LIBC_STRSTR */
312 }
313 #endif /* RT_KLIBC_USING_USER_STRSTR */
314 RTM_EXPORT(rt_strstr);
315
316 /**
317 * @brief This function will compare two strings while ignoring differences in case
318 *
319 * @param a is the string to be compared.
320 *
321 * @param b is the string to be compared.
322 *
323 * @return Compare the results:
324 * If the result < 0, a is smaller than a.
325 * If the result > 0, a is greater than a.
326 * If the result = 0, a is equal to a.
327 */
328 #ifndef RT_KLIBC_USING_USER_STRCASECMP
rt_strcasecmp(const char * a,const char * b)329 rt_int32_t rt_strcasecmp(const char *a, const char *b)
330 {
331 int ca = 0, cb = 0;
332
333 do
334 {
335 ca = *a++ & 0xff;
336 cb = *b++ & 0xff;
337 if (ca >= 'A' && ca <= 'Z')
338 ca += 'a' - 'A';
339 if (cb >= 'A' && cb <= 'Z')
340 cb += 'a' - 'A';
341 }
342 while (ca == cb && ca != '\0');
343
344 return ca - cb;
345 }
346 #endif /* RT_KLIBC_USING_USER_STRCASECMP */
347 RTM_EXPORT(rt_strcasecmp);
348
349 /**
350 * @brief This function will copy string no more than n bytes.
351 *
352 * @param dst points to the address used to store the copied content.
353 *
354 * @param src is the string to be copied.
355 *
356 * @param n is the maximum copied length.
357 *
358 * @return The address where the copied content is stored.
359 */
360 #ifndef RT_KLIBC_USING_USER_STRNCPY
rt_strncpy(char * dst,const char * src,rt_size_t n)361 char *rt_strncpy(char *dst, const char *src, rt_size_t n)
362 {
363 #ifdef RT_KLIBC_USING_LIBC_STRNCPY
364 return strncpy(dst, src, n);
365 #else
366 if (n != 0)
367 {
368 char *d = dst;
369 const char *s = src;
370
371 do
372 {
373 if ((*d++ = *s++) == 0)
374 {
375 /* NUL pad the remaining n-1 bytes */
376 while (--n != 0)
377 {
378 *d++ = 0;
379 }
380
381 break;
382 }
383 } while (--n != 0);
384 }
385
386 return (dst);
387 #endif /* RT_KLIBC_USING_LIBC_STRNCPY */
388 }
389 #endif /* RT_KLIBC_USING_USER_STRNCPY */
390 RTM_EXPORT(rt_strncpy);
391
392 /**
393 * @brief This function will copy string.
394 *
395 * @param dst points to the address used to store the copied content.
396 *
397 * @param src is the string to be copied.
398 *
399 * @return The address where the copied content is stored.
400 */
401 #ifndef RT_KLIBC_USING_USER_STRCPY
rt_strcpy(char * dst,const char * src)402 char *rt_strcpy(char *dst, const char *src)
403 {
404 #ifdef RT_KLIBC_USING_LIBC_STRCPY
405 return strcpy(dst, src);
406 #else
407 char *dest = dst;
408
409 while (*src != '\0')
410 {
411 *dst = *src;
412 dst++;
413 src++;
414 }
415
416 *dst = '\0';
417 return dest;
418 #endif /* RT_KLIBC_USING_LIBC_STRCPY */
419 }
420 #endif /* RT_KLIBC_USING_USER_STRCPY */
421 RTM_EXPORT(rt_strcpy);
422
423 /**
424 * @brief This function will compare two strings with specified maximum length.
425 *
426 * @param cs is the string to be compared.
427 *
428 * @param ct is the string to be compared.
429 *
430 * @param count is the maximum compare length.
431 *
432 * @return Compare the results:
433 * If the result < 0, cs is smaller than ct.
434 * If the result > 0, cs is greater than ct.
435 * If the result = 0, cs is equal to ct.
436 */
437 #ifndef RT_KLIBC_USING_USER_STRNCMP
rt_strncmp(const char * cs,const char * ct,rt_size_t count)438 rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_size_t count)
439 {
440 #ifdef RT_KLIBC_USING_LIBC_STRNCMP
441 return strncmp(cs, ct, count);
442 #else
443 signed char res = 0;
444
445 while (count)
446 {
447 if ((res = *cs - *ct++) != 0 || !*cs++)
448 {
449 break;
450 }
451
452 count --;
453 }
454
455 return res;
456 #endif /* RT_KLIBC_USING_LIBC_STRNCMP */
457 }
458 #endif /* RT_KLIBC_USING_USER_STRNCMP */
459 RTM_EXPORT(rt_strncmp);
460
461 /**
462 * @brief This function will compare two strings without specified length.
463 *
464 * @param cs is the string to be compared.
465 *
466 * @param ct is the string to be compared.
467 *
468 * @return Compare the results:
469 * If the result < 0, cs is smaller than ct.
470 * If the result > 0, cs is greater than ct.
471 * If the result = 0, cs is equal to ct.
472 */
473 #ifndef RT_KLIBC_USING_USER_STRCMP
rt_strcmp(const char * cs,const char * ct)474 rt_int32_t rt_strcmp(const char *cs, const char *ct)
475 {
476 #ifdef RT_KLIBC_USING_LIBC_STRCMP
477 return strcmp(cs, ct);
478 #else
479 while (*cs && *cs == *ct)
480 {
481 cs++;
482 ct++;
483 }
484
485 return (*cs - *ct);
486 #endif /* RT_KLIBC_USING_LIBC_STRCMP */
487 }
488 #endif /* RT_KLIBC_USING_USER_STRCMP */
489 RTM_EXPORT(rt_strcmp);
490
491 /**
492 * @brief This function will return the length of a string, which terminate will
493 * null character.
494 *
495 * @param s is the string
496 *
497 * @return The length of string.
498 */
499 #ifndef RT_KLIBC_USING_USER_STRLEN
rt_strlen(const char * s)500 rt_size_t rt_strlen(const char *s)
501 {
502 #ifdef RT_KLIBC_USING_LIBC_STRLEN
503 return strlen(s);
504 #else
505 const char *sc = RT_NULL;
506 for (sc = s; *sc != '\0'; ++sc);
507 return sc - s;
508 #endif /* RT_KLIBC_USING_LIBC_STRLEN */
509 }
510 #endif /* RT_KLIBC_USING_USER_STRLEN */
511 RTM_EXPORT(rt_strlen);
512
513 /**
514 * @brief The strnlen() function returns the number of characters in the
515 * string pointed to by s, excluding the terminating null byte ('\0'),
516 * but at most maxlen. In doing this, strnlen() looks only at the
517 * first maxlen characters in the string pointed to by s and never
518 * beyond s+maxlen.
519 *
520 * @param s is the string.
521 *
522 * @param maxlen is the max size.
523 *
524 * @return The length of string.
525 */
526 #ifndef RT_KLIBC_USING_USER_STRNLEN
rt_strnlen(const char * s,rt_ubase_t maxlen)527 rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen)
528 {
529 const char *sc;
530 for (sc = s; *sc != '\0' && (rt_ubase_t)(sc - s) < maxlen; ++sc);
531 return sc - s;
532 }
533 #endif /* RT_KLIBC_USING_USER_STRNLEN */
534 RTM_EXPORT(rt_strnlen);
535
536 #ifdef RT_USING_HEAP
537 /**
538 * @brief This function will duplicate a string.
539 *
540 * @param s is the string to be duplicated.
541 *
542 * @return The string address of the copy.
543 */
rt_strdup(const char * s)544 char *rt_strdup(const char *s)
545 {
546 rt_size_t len = rt_strlen(s) + 1;
547 char *tmp = (char *)rt_malloc(len);
548
549 if (!tmp)
550 {
551 return RT_NULL;
552 }
553
554 rt_memcpy(tmp, s, len);
555
556 return tmp;
557 }
558 RTM_EXPORT(rt_strdup);
559 #endif /* RT_USING_HEAP */
560