summaryrefslogtreecommitdiff
path: root/src/klibc
diff options
context:
space:
mode:
authorMeco Man <[email protected]>2024-03-10 13:39:20 -0400
committerMeco Man <[email protected]>2024-03-20 22:26:11 -0400
commite81978c5dc5ff75257b64da3f9ab0d9a75475ddb (patch)
treef4ea76515f94aeec80c52374abf6c22a9ba62b20 /src/klibc
parente25f287ff30f7bcf3fd8a30cba6c56ae86504c83 (diff)
[kernel] move std libc related to rtklibc.h
Diffstat (limited to 'src/klibc')
-rw-r--r--src/klibc/kstdio.c686
-rw-r--r--src/klibc/kstring.c507
2 files changed, 1193 insertions, 0 deletions
diff --git a/src/klibc/kstdio.c b/src/klibc/kstdio.c
new file mode 100644
index 0000000000..8ed1a9298d
--- /dev/null
+++ b/src/klibc/kstdio.c
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-10 Meco Man the first version
+ */
+
+#include <rtdef.h>
+#include <rtcompiler.h>
+#include <rtklibc.h>
+#include <rtm.h>
+
+#define DBG_TAG "kernel.stdio"
+#ifdef RT_DEBUG_DEVICE
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_WARNING
+#endif /* defined (RT_DEBUG_DEVICE) */
+#include <rtdbg.h>
+
+/* private function */
+#define _ISDIGIT(c) ((unsigned)((c) - '0') < 10)
+
+/**
+ * @brief This function will duplicate a string.
+ *
+ * @param n is the string to be duplicated.
+ *
+ * @param base is support divide instructions value.
+ *
+ * @return the duplicated string pointer.
+ */
+#ifdef RT_KPRINTF_USING_LONGLONG
+rt_inline int divide(unsigned long long *n, int base)
+#else
+rt_inline int divide(unsigned long *n, int base)
+#endif /* RT_KPRINTF_USING_LONGLONG */
+{
+ int res;
+
+ /* optimized for processor which does not support divide instructions. */
+#ifdef RT_KPRINTF_USING_LONGLONG
+ res = (int)((*n) % base);
+ *n = (long long)((*n) / base);
+#else
+ res = (int)((*n) % base);
+ *n = (long)((*n) / base);
+#endif
+
+ return res;
+}
+
+rt_inline int skip_atoi(const char **s)
+{
+ int i = 0;
+ while (_ISDIGIT(**s))
+ i = i * 10 + *((*s)++) - '0';
+
+ return i;
+}
+
+#define ZEROPAD (1 << 0) /* pad with zero */
+#define SIGN (1 << 1) /* unsigned/signed long */
+#define PLUS (1 << 2) /* show plus */
+#define SPACE (1 << 3) /* space if plus */
+#define LEFT (1 << 4) /* left justified */
+#define SPECIAL (1 << 5) /* 0x */
+#define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */
+
+static char *print_number(char *buf,
+ char *end,
+#ifdef RT_KPRINTF_USING_LONGLONG
+ unsigned long long num,
+#else
+ unsigned long num,
+#endif /* RT_KPRINTF_USING_LONGLONG */
+ int base,
+ int qualifier,
+ int s,
+ int precision,
+ int type)
+{
+ char c = 0, sign = 0;
+#ifdef RT_KPRINTF_USING_LONGLONG
+ char tmp[64] = {0};
+#else
+ char tmp[32] = {0};
+#endif /* RT_KPRINTF_USING_LONGLONG */
+ int precision_bak = precision;
+ const char *digits = RT_NULL;
+ static const char small_digits[] = "0123456789abcdef";
+ static const char large_digits[] = "0123456789ABCDEF";
+ int i = 0;
+ int size = 0;
+
+ size = s;
+
+ digits = (type & LARGE) ? large_digits : small_digits;
+ if (type & LEFT)
+ {
+ type &= ~ZEROPAD;
+ }
+
+ c = (type & ZEROPAD) ? '0' : ' ';
+
+ /* get sign */
+ sign = 0;
+ if (type & SIGN)
+ {
+ switch (qualifier)
+ {
+ case 'h':
+ if ((rt_int16_t)num < 0)
+ {
+ sign = '-';
+ num = (rt_uint16_t)-num;
+ }
+ break;
+ case 'L':
+ case 'l':
+ if ((long)num < 0)
+ {
+ sign = '-';
+ num = (unsigned long)-num;
+ }
+ break;
+ case 0:
+ default:
+ if ((rt_int32_t)num < 0)
+ {
+ sign = '-';
+ num = (rt_uint32_t)-num;
+ }
+ break;
+ }
+
+ if (sign != '-')
+ {
+ if (type & PLUS)
+ {
+ sign = '+';
+ }
+ else if (type & SPACE)
+ {
+ sign = ' ';
+ }
+ }
+ }
+
+ if (type & SPECIAL)
+ {
+ if (base == 2 || base == 16)
+ {
+ size -= 2;
+ }
+ else if (base == 8)
+ {
+ size--;
+ }
+ }
+
+ i = 0;
+ if (num == 0)
+ {
+ tmp[i++] = '0';
+ }
+ else
+ {
+ while (num != 0)
+ tmp[i++] = digits[divide(&num, base)];
+ }
+
+ if (i > precision)
+ {
+ precision = i;
+ }
+ size -= precision;
+
+ if (!(type & (ZEROPAD | LEFT)))
+ {
+ if ((sign) && (size > 0))
+ {
+ size--;
+ }
+
+ while (size-- > 0)
+ {
+ if (buf < end)
+ {
+ *buf = ' ';
+ }
+
+ ++ buf;
+ }
+ }
+
+ if (sign)
+ {
+ if (buf < end)
+ {
+ *buf = sign;
+ }
+ -- size;
+ ++ buf;
+ }
+
+ if (type & SPECIAL)
+ {
+ if (base == 2)
+ {
+ if (buf < end)
+ *buf = '0';
+ ++ buf;
+ if (buf < end)
+ *buf = 'b';
+ ++ buf;
+ }
+ else if (base == 8)
+ {
+ if (buf < end)
+ *buf = '0';
+ ++ buf;
+ }
+ else if (base == 16)
+ {
+ if (buf < end)
+ {
+ *buf = '0';
+ }
+
+ ++ buf;
+ if (buf < end)
+ {
+ *buf = type & LARGE ? 'X' : 'x';
+ }
+ ++ buf;
+ }
+ }
+
+ /* no align to the left */
+ if (!(type & LEFT))
+ {
+ while (size-- > 0)
+ {
+ if (buf < end)
+ {
+ *buf = c;
+ }
+
+ ++ buf;
+ }
+ }
+
+ while (i < precision--)
+ {
+ if (buf < end)
+ {
+ *buf = '0';
+ }
+
+ ++ buf;
+ }
+
+ /* put number in the temporary buffer */
+ while (i-- > 0 && (precision_bak != 0))
+ {
+ if (buf < end)
+ {
+ *buf = tmp[i];
+ }
+
+ ++ buf;
+ }
+
+ while (size-- > 0)
+ {
+ if (buf < end)
+ {
+ *buf = ' ';
+ }
+
+ ++ buf;
+ }
+
+ return buf;
+}
+
+#if defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */
+#pragma GCC diagnostic push
+/* ignore warning: this statement may fall through */
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#endif /* defined(__GNUC__) && !defined(__ARMCC_VERSION) */
+/**
+ * @brief This function will fill a formatted string to buffer.
+ *
+ * @param buf is the buffer to save formatted string.
+ *
+ * @param size is the size of buffer.
+ *
+ * @param fmt is the format parameters.
+ *
+ * @param args is a list of variable parameters.
+ *
+ * @return The number of characters actually written to buffer.
+ */
+rt_weak int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
+{
+#ifdef RT_KPRINTF_USING_LONGLONG
+ unsigned long long num = 0;
+#else
+ unsigned long num = 0;
+#endif /* RT_KPRINTF_USING_LONGLONG */
+ int i = 0, len = 0;
+ char *str = RT_NULL, *end = RT_NULL, c = 0;
+ const char *s = RT_NULL;
+
+ rt_uint8_t base = 0; /* the base of number */
+ rt_uint8_t flags = 0; /* flags to print number */
+ rt_uint8_t qualifier = 0; /* 'h', 'l', or 'L' for integer fields */
+ rt_int32_t field_width = 0; /* width of output field */
+ int precision = 0; /* min. # of digits for integers and max for a string */
+
+ str = buf;
+ end = buf + size;
+
+ /* Make sure end is always >= buf */
+ if (end < buf)
+ {
+ end = ((char *) - 1);
+ size = end - buf;
+ }
+
+ for (; *fmt ; ++fmt)
+ {
+ if (*fmt != '%')
+ {
+ if (str < end)
+ {
+ *str = *fmt;
+ }
+
+ ++ str;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+
+ while (1)
+ {
+ /* skips the first '%' also */
+ ++fmt;
+ if (*fmt == '-') flags |= LEFT;
+ else if (*fmt == '+') flags |= PLUS;
+ else if (*fmt == ' ') flags |= SPACE;
+ else if (*fmt == '#') flags |= SPECIAL;
+ else if (*fmt == '0') flags |= ZEROPAD;
+ else break;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (_ISDIGIT(*fmt))
+ {
+ field_width = skip_atoi(&fmt);
+ }
+ else if (*fmt == '*')
+ {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0)
+ {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.')
+ {
+ ++fmt;
+ if (_ISDIGIT(*fmt))
+ {
+ precision = skip_atoi(&fmt);
+ }
+ else if (*fmt == '*')
+ {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ {
+ precision = 0;
+ }
+ }
+
+ qualifier = 0; /* get the conversion qualifier */
+
+ if (*fmt == 'h' || *fmt == 'l' ||
+#ifdef RT_KPRINTF_USING_LONGLONG
+ *fmt == 'L' ||
+#endif /* RT_KPRINTF_USING_LONGLONG */
+ *fmt == 'z')
+ {
+ qualifier = *fmt;
+ ++fmt;
+#ifdef RT_KPRINTF_USING_LONGLONG
+ if (qualifier == 'l' && *fmt == 'l')
+ {
+ qualifier = 'L';
+ ++fmt;
+ }
+#endif /* RT_KPRINTF_USING_LONGLONG */
+ if (qualifier == 'h' && *fmt == 'h')
+ {
+ qualifier = 'H';
+ ++fmt;
+ }
+ }
+
+ /* the default base */
+ base = 10;
+
+ switch (*fmt)
+ {
+ case 'c':
+ if (!(flags & LEFT))
+ {
+ while (--field_width > 0)
+ {
+ if (str < end) *str = ' ';
+ ++ str;
+ }
+ }
+
+ /* get character */
+ c = (rt_uint8_t)va_arg(args, int);
+ if (str < end)
+ {
+ *str = c;
+ }
+ ++ str;
+
+ /* put width */
+ while (--field_width > 0)
+ {
+ if (str < end) *str = ' ';
+ ++ str;
+ }
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ if (!s)
+ {
+ s = "(NULL)";
+ }
+
+ for (len = 0; (len != field_width) && (s[len] != '\0'); len++);
+
+ if (precision > 0 && len > precision)
+ {
+ len = precision;
+ }
+
+ if (!(flags & LEFT))
+ {
+ while (len < field_width--)
+ {
+ if (str < end) *str = ' ';
+ ++ str;
+ }
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ if (str < end) *str = *s;
+ ++ str;
+ ++ s;
+ }
+
+ while (len < field_width--)
+ {
+ if (str < end) *str = ' ';
+ ++ str;
+ }
+ continue;
+
+ case 'p':
+ if (field_width == -1)
+ {
+ field_width = sizeof(void *) << 1;
+ field_width += 2; /* `0x` prefix */
+ flags |= SPECIAL;
+ flags |= ZEROPAD;
+ }
+ str = print_number(str, end, (unsigned long)va_arg(args, void *),
+ 16, qualifier, field_width, precision, flags);
+ continue;
+
+ case '%':
+ if (str < end)
+ {
+ *str = '%';
+ }
+ ++ str;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'b':
+ base = 2;
+ break;
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ case 'e':
+ case 'E':
+ case 'G':
+ case 'g':
+ case 'f':
+ case 'F':
+ va_arg(args, double);
+ default:
+ if (str < end)
+ {
+ *str = '%';
+ }
+ ++ str;
+
+ if (*fmt)
+ {
+ if (str < end)
+ {
+ *str = *fmt;
+ }
+ ++ str;
+ }
+ else
+ {
+ -- fmt;
+ }
+ continue;
+ }
+
+ if (qualifier == 'L')
+ {
+ num = va_arg(args, unsigned long long);
+ }
+ else if (qualifier == 'l')
+ {
+ num = va_arg(args, unsigned long);
+ }
+ else if (qualifier == 'H')
+ {
+ num = (rt_int8_t)va_arg(args, rt_int32_t);
+ if (flags & SIGN)
+ {
+ num = (rt_int8_t)num;
+ }
+ }
+ else if (qualifier == 'h')
+ {
+ num = (rt_uint16_t)va_arg(args, rt_int32_t);
+ if (flags & SIGN)
+ {
+ num = (rt_int16_t)num;
+ }
+ }
+ else if (qualifier == 'z')
+ {
+ num = va_arg(args, rt_size_t);
+ if (flags & SIGN)
+ {
+ num = (rt_ssize_t)num;
+ }
+ }
+ else
+ {
+ num = (rt_uint32_t)va_arg(args, unsigned long);
+ }
+ str = print_number(str, end, num, base, qualifier, field_width, precision, flags);
+ }
+
+ if (size > 0)
+ {
+ if (str < end)
+ {
+ *str = '\0';
+ }
+ else
+ {
+ end[-1] = '\0';
+ }
+ }
+
+ /* the trailing null byte doesn't count towards the total
+ * ++str;
+ */
+ return str - buf;
+}
+RTM_EXPORT(rt_vsnprintf);
+#if defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */
+#pragma GCC diagnostic pop /* ignored "-Wimplicit-fallthrough" */
+#endif /* defined(__GNUC__) && !defined(__ARMCC_VERSION) */
+
+/**
+ * @brief This function will fill a formatted string to buffer.
+ *
+ * @param buf is the buffer to save formatted string.
+ *
+ * @param size is the size of buffer.
+ *
+ * @param fmt is the format parameters.
+ *
+ * @return The number of characters actually written to buffer.
+ */
+int rt_snprintf(char *buf, rt_size_t size, const char *fmt, ...)
+{
+ rt_int32_t n = 0;
+ va_list args;
+
+ va_start(args, fmt);
+ n = rt_vsnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return n;
+}
+RTM_EXPORT(rt_snprintf);
+
+/**
+ * @brief This function will fill a formatted string to buffer.
+ *
+ * @param buf is the buffer to save formatted string.
+ *
+ * @param format is the format parameters.
+ *
+ * @param arg_ptr is a list of variable parameters.
+ *
+ * @return The number of characters actually written to buffer.
+ */
+int rt_vsprintf(char *buf, const char *format, va_list arg_ptr)
+{
+ return rt_vsnprintf(buf, (rt_size_t) - 1, format, arg_ptr);
+}
+RTM_EXPORT(rt_vsprintf);
+
+/**
+ * @brief This function will fill a formatted string to buffer
+ *
+ * @param buf the buffer to save formatted string.
+ *
+ * @param format is the format parameters.
+ *
+ * @return The number of characters actually written to buffer.
+ */
+int rt_sprintf(char *buf, const char *format, ...)
+{
+ rt_int32_t n = 0;
+ va_list arg_ptr;
+
+ va_start(arg_ptr, format);
+ n = rt_vsprintf(buf, format, arg_ptr);
+ va_end(arg_ptr);
+
+ return n;
+}
+RTM_EXPORT(rt_sprintf);
diff --git a/src/klibc/kstring.c b/src/klibc/kstring.c
new file mode 100644
index 0000000000..016412071b
--- /dev/null
+++ b/src/klibc/kstring.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-10 Meco Man the first version
+ */
+
+#include <rtdef.h>
+#include <rtcompiler.h>
+#include <rtklibc.h>
+#include <rtm.h>
+
+#define DBG_TAG "kernel.string"
+#ifdef RT_DEBUG_DEVICE
+#define DBG_LVL DBG_LOG
+#else
+#define DBG_LVL DBG_WARNING
+#endif /* defined (RT_DEBUG_DEVICE) */
+#include <rtdbg.h>
+
+#ifndef RT_KSERVICE_USING_STDLIB_MEMORY
+/**
+ * @brief This function will set the content of memory to specified value.
+ *
+ * @param s is the address of source memory, point to the memory block to be filled.
+ *
+ * @param c is the value to be set. The value is passed in int form, but the function
+ * uses the unsigned character form of the value when filling the memory block.
+ *
+ * @param count number of bytes to be set.
+ *
+ * @return The address of source memory.
+ */
+rt_weak void *rt_memset(void *s, int c, rt_ubase_t count)
+{
+#ifdef RT_KSERVICE_USING_TINY_SIZE
+ char *xs = (char *)s;
+
+ while (count--)
+ *xs++ = c;
+
+ return s;
+#else
+#define LBLOCKSIZE (sizeof(rt_ubase_t))
+#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
+#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
+
+ unsigned int i = 0;
+ char *m = (char *)s;
+ unsigned long buffer = 0;
+ unsigned long *aligned_addr = RT_NULL;
+ unsigned char d = (unsigned int)c & (unsigned char)(-1); /* To avoid sign extension, copy C to an
+ unsigned variable. (unsigned)((char)(-1))=0xFF for 8bit and =0xFFFF for 16bit: word independent */
+
+ RT_ASSERT(LBLOCKSIZE == 2 || LBLOCKSIZE == 4 || LBLOCKSIZE == 8);
+
+ if (!TOO_SMALL(count) && !UNALIGNED(s))
+ {
+ /* If we get this far, we know that count is large and s is word-aligned. */
+ aligned_addr = (unsigned long *)s;
+
+ /* Store d into each char sized location in buffer so that
+ * we can set large blocks quickly.
+ */
+ for (i = 0; i < LBLOCKSIZE; i++)
+ {
+ *(((unsigned char *)&buffer)+i) = d;
+ }
+
+ while (count >= LBLOCKSIZE * 4)
+ {
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ *aligned_addr++ = buffer;
+ count -= 4 * LBLOCKSIZE;
+ }
+
+ while (count >= LBLOCKSIZE)
+ {
+ *aligned_addr++ = buffer;
+ count -= LBLOCKSIZE;
+ }
+
+ /* Pick up the remainder with a bytewise loop. */
+ m = (char *)aligned_addr;
+ }
+
+ while (count--)
+ {
+ *m++ = (char)d;
+ }
+
+ return s;
+
+#undef LBLOCKSIZE
+#undef UNALIGNED
+#undef TOO_SMALL
+#endif /* RT_KSERVICE_USING_TINY_SIZE */
+}
+RTM_EXPORT(rt_memset);
+
+/**
+ * @brief This function will copy memory content from source address to destination address.
+ *
+ * @param dst is the address of destination memory, points to the copied content.
+ *
+ * @param src is the address of source memory, pointing to the data source to be copied.
+ *
+ * @param count is the copied length.
+ *
+ * @return The address of destination memory
+ */
+rt_weak void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
+{
+#ifdef RT_KSERVICE_USING_TINY_SIZE
+ char *tmp = (char *)dst, *s = (char *)src;
+ rt_ubase_t len = 0;
+
+ if (tmp <= s || tmp > (s + count))
+ {
+ while (count--)
+ *tmp ++ = *s ++;
+ }
+ else
+ {
+ for (len = count; len > 0; len --)
+ tmp[len - 1] = s[len - 1];
+ }
+
+ return dst;
+#else
+
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+#define BIGBLOCKSIZE (sizeof (long) << 2)
+#define LITTLEBLOCKSIZE (sizeof (long))
+#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
+
+ char *dst_ptr = (char *)dst;
+ char *src_ptr = (char *)src;
+ long *aligned_dst = RT_NULL;
+ long *aligned_src = RT_NULL;
+ rt_ubase_t len = count;
+
+ /* If the size is small, or either SRC or DST is unaligned,
+ then punt into the byte copy loop. This should be rare. */
+ if (!TOO_SMALL(len) && !UNALIGNED(src_ptr, dst_ptr))
+ {
+ aligned_dst = (long *)dst_ptr;
+ aligned_src = (long *)src_ptr;
+
+ /* Copy 4X long words at a time if possible. */
+ while (len >= BIGBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ *aligned_dst++ = *aligned_src++;
+ len -= BIGBLOCKSIZE;
+ }
+
+ /* Copy one long word at a time if possible. */
+ while (len >= LITTLEBLOCKSIZE)
+ {
+ *aligned_dst++ = *aligned_src++;
+ len -= LITTLEBLOCKSIZE;
+ }
+
+ /* Pick up any residual with a byte copier. */
+ dst_ptr = (char *)aligned_dst;
+ src_ptr = (char *)aligned_src;
+ }
+
+ while (len--)
+ *dst_ptr++ = *src_ptr++;
+
+ return dst;
+#undef UNALIGNED
+#undef BIGBLOCKSIZE
+#undef LITTLEBLOCKSIZE
+#undef TOO_SMALL
+#endif /* RT_KSERVICE_USING_TINY_SIZE */
+}
+RTM_EXPORT(rt_memcpy);
+
+/**
+ * @brief This function will move memory content from source address to destination
+ * address. If the destination memory does not overlap with the source memory,
+ * the function is the same as memcpy().
+ *
+ * @param dest is the address of destination memory, points to the copied content.
+ *
+ * @param src is the address of source memory, point to the data source to be copied.
+ *
+ * @param n is the copied length.
+ *
+ * @return The address of destination memory.
+ */
+void *rt_memmove(void *dest, const void *src, rt_size_t n)
+{
+ char *tmp = (char *)dest, *s = (char *)src;
+
+ if (s < tmp && tmp < s + n)
+ {
+ tmp += n;
+ s += n;
+
+ while (n--)
+ *(--tmp) = *(--s);
+ }
+ else
+ {
+ while (n--)
+ *tmp++ = *s++;
+ }
+
+ return dest;
+}
+RTM_EXPORT(rt_memmove);
+
+/**
+ * @brief This function will compare two areas of memory.
+ *
+ * @param cs is a block of memory.
+ *
+ * @param ct is another block of memory.
+ *
+ * @param count is the size of the area.
+ *
+ * @return Compare the results:
+ * If the result < 0, cs is smaller than ct.
+ * If the result > 0, cs is greater than ct.
+ * If the result = 0, cs is equal to ct.
+ */
+rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_size_t count)
+{
+ const unsigned char *su1 = RT_NULL, *su2 = RT_NULL;
+ int res = 0;
+
+ for (su1 = (const unsigned char *)cs, su2 = (const unsigned char *)ct; 0 < count; ++su1, ++su2, count--)
+ if ((res = *su1 - *su2) != 0)
+ break;
+
+ return res;
+}
+RTM_EXPORT(rt_memcmp);
+#endif /* RT_KSERVICE_USING_STDLIB_MEMORY*/
+
+#ifndef RT_KSERVICE_USING_STDLIB
+/**
+ * @brief This function will return the first occurrence of a string, without the
+ * terminator '\0'.
+ *
+ * @param s1 is the source string.
+ *
+ * @param s2 is the find string.
+ *
+ * @return The first occurrence of a s2 in s1, or RT_NULL if no found.
+ */
+char *rt_strstr(const char *s1, const char *s2)
+{
+ int l1 = 0, l2 = 0;
+
+ l2 = rt_strlen(s2);
+ if (!l2)
+ {
+ return (char *)s1;
+ }
+
+ l1 = rt_strlen(s1);
+ while (l1 >= l2)
+ {
+ l1 --;
+ if (!rt_memcmp(s1, s2, l2))
+ {
+ return (char *)s1;
+ }
+
+ s1 ++;
+ }
+
+ return RT_NULL;
+}
+RTM_EXPORT(rt_strstr);
+
+/**
+ * @brief This function will compare two strings while ignoring differences in case
+ *
+ * @param a is the string to be compared.
+ *
+ * @param b is the string to be compared.
+ *
+ * @return Compare the results:
+ * If the result < 0, a is smaller than a.
+ * If the result > 0, a is greater than a.
+ * If the result = 0, a is equal to a.
+ */
+rt_int32_t rt_strcasecmp(const char *a, const char *b)
+{
+ int ca = 0, cb = 0;
+
+ do
+ {
+ ca = *a++ & 0xff;
+ cb = *b++ & 0xff;
+ if (ca >= 'A' && ca <= 'Z')
+ ca += 'a' - 'A';
+ if (cb >= 'A' && cb <= 'Z')
+ cb += 'a' - 'A';
+ }
+ while (ca == cb && ca != '\0');
+
+ return ca - cb;
+}
+RTM_EXPORT(rt_strcasecmp);
+
+/**
+ * @brief This function will copy string no more than n bytes.
+ *
+ * @param dst points to the address used to store the copied content.
+ *
+ * @param src is the string to be copied.
+ *
+ * @param n is the maximum copied length.
+ *
+ * @return The address where the copied content is stored.
+ */
+char *rt_strncpy(char *dst, const char *src, rt_size_t n)
+{
+ if (n != 0)
+ {
+ char *d = dst;
+ const char *s = src;
+
+ do
+ {
+ if ((*d++ = *s++) == 0)
+ {
+ /* NUL pad the remaining n-1 bytes */
+ while (--n != 0)
+ {
+ *d++ = 0;
+ }
+
+ break;
+ }
+ } while (--n != 0);
+ }
+
+ return (dst);
+}
+RTM_EXPORT(rt_strncpy);
+
+/**
+ * @brief This function will copy string.
+ *
+ * @param dst points to the address used to store the copied content.
+ *
+ * @param src is the string to be copied.
+ *
+ * @return The address where the copied content is stored.
+ */
+char *rt_strcpy(char *dst, const char *src)
+{
+ char *dest = dst;
+
+ while (*src != '\0')
+ {
+ *dst = *src;
+ dst++;
+ src++;
+ }
+
+ *dst = '\0';
+ return dest;
+}
+RTM_EXPORT(rt_strcpy);
+
+/**
+ * @brief This function will compare two strings with specified maximum length.
+ *
+ * @param cs is the string to be compared.
+ *
+ * @param ct is the string to be compared.
+ *
+ * @param count is the maximum compare length.
+ *
+ * @return Compare the results:
+ * If the result < 0, cs is smaller than ct.
+ * If the result > 0, cs is greater than ct.
+ * If the result = 0, cs is equal to ct.
+ */
+rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_size_t count)
+{
+ signed char __res = 0;
+
+ while (count)
+ {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ {
+ break;
+ }
+
+ count --;
+ }
+
+ return __res;
+}
+RTM_EXPORT(rt_strncmp);
+
+/**
+ * @brief This function will compare two strings without specified length.
+ *
+ * @param cs is the string to be compared.
+ *
+ * @param ct is the string to be compared.
+ *
+ * @return Compare the results:
+ * If the result < 0, cs is smaller than ct.
+ * If the result > 0, cs is greater than ct.
+ * If the result = 0, cs is equal to ct.
+ */
+rt_int32_t rt_strcmp(const char *cs, const char *ct)
+{
+ while (*cs && *cs == *ct)
+ {
+ cs++;
+ ct++;
+ }
+
+ return (*cs - *ct);
+}
+RTM_EXPORT(rt_strcmp);
+
+/**
+ * @brief This function will return the length of a string, which terminate will
+ * null character.
+ *
+ * @param s is the string
+ *
+ * @return The length of string.
+ */
+rt_size_t rt_strlen(const char *s)
+{
+ const char *sc = RT_NULL;
+
+ for (sc = s; *sc != '\0'; ++sc) /* nothing */
+ ;
+
+ return sc - s;
+}
+RTM_EXPORT(rt_strlen);
+
+#endif /* RT_KSERVICE_USING_STDLIB */
+
+/**
+ * @brief The strnlen() function returns the number of characters in the
+ * string pointed to by s, excluding the terminating null byte ('\0'),
+ * but at most maxlen. In doing this, strnlen() looks only at the
+ * first maxlen characters in the string pointed to by s and never
+ * beyond s+maxlen.
+ *
+ * @param s is the string.
+ *
+ * @param maxlen is the max size.
+ *
+ * @return The length of string.
+ */
+rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0' && (rt_ubase_t)(sc - s) < maxlen; ++sc) /* nothing */
+ ;
+
+ return sc - s;
+}
+RTM_EXPORT(rt_strnlen);
+
+#ifdef RT_USING_HEAP
+/**
+ * @brief This function will duplicate a string.
+ *
+ * @param s is the string to be duplicated.
+ *
+ * @return The string address of the copy.
+ */
+char *rt_strdup(const char *s)
+{
+ rt_size_t len = rt_strlen(s) + 1;
+ char *tmp = (char *)rt_malloc(len);
+
+ if (!tmp)
+ {
+ return RT_NULL;
+ }
+
+ rt_memcpy(tmp, s, len);
+
+ return tmp;
+}
+RTM_EXPORT(rt_strdup);
+#endif /* RT_USING_HEAP */