first commit for chrg

This commit is contained in:
wmano
2025-08-16 22:58:22 +08:00
commit 52a3ed5862
2306 changed files with 1021208 additions and 0 deletions
+258
View File
@@ -0,0 +1,258 @@
menu "klibc options"
menu "rt_vsnprintf options"
config RT_KLIBC_USING_LIBC_VSNPRINTF
bool "Enable rt_vsnprintf to use libc vsnprintf"
default n
config RT_KLIBC_USING_VSNPRINTF_LONGLONG
bool "Enable rt_vsnprintf function to support long-long format"
depends on !RT_KLIBC_USING_LIBC_VSNPRINTF
default n
help
Support for the long long integral types (with the ll, z and t length modifiers for specifiers
%d,%i,%o,%x,%X,%u, and with the %p specifier). Note: 'L' (long double) is not supported.
menuconfig RT_KLIBC_USING_VSNPRINTF_STANDARD
bool "Enable standard rt_vsnprintf version"
default y if ARCH_CPU_64BIT
default n
select RT_KLIBC_USING_VSNPRINTF_LONGLONG
depends on !RT_KLIBC_USING_LIBC_VSNPRINTF
help
Standard version of rt_vsnprintf, which is full function but higher stack usage.
if RT_KLIBC_USING_VSNPRINTF_STANDARD
config RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
bool "Support decimal notation floating point conversion specifiers (%f, %F)"
default y
help
Support for the decimal notation floating point conversion specifiers (%f, %F)
config RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
bool "Support exponential notation floating point conversion specifiers (%e, %g, %E, %G)"
default y
help
Support for the exponential notation floating point conversion specifiers (%e, %g, %E, %G)
config RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
bool "Support length write-back specifier (%n)"
default y
help
Support for the length write-back specifier (%n)
config RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER
bool "safety check: no NULL end string"
default y if RT_USING_DEBUG
default n
help
Be extra-safe, and don't assume format specifiers are completed correctly
before the format string end.
config RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
bool "Support MSVC style integer specifiers"
default n
help
the integer format specifiers used in Microsoft's Visual C++ (MSVC) compiler.
These specifiers, like %I64d for 64-bit integers, deviate slightly from the standard
C format specifiers and are specific to MSVC. They allow for controlled formatting of
integers in printf()-like functions, accommodating different integer sizes and ensuring
compatibility with MSVC's environment. It's important to note that these specifiers might
not be recognized or function in other compilers due to their MSVC-specific nature.
config RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE
int "'ntoa' conversion buffer size"
default 32
help
'ntoa' conversion buffer size, this must be big enough to hold one converted
numeric number including padded zeros (dynamically created on stack)
config RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE
int "printing individual decimal numbers buffer size"
default 32
help
size of the fixed (on-stack) buffer for printing individual decimal numbers.
this must be big enough to hold one converted floating-point value including
padded zeros.
config RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION
int "floating point conversion specifiers"
default 6
help
Default precision for the floating point conversion specifiers (the C standard sets this at 6)
config RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL
int "integral nums printed as float in rt_vsnprint"
default 9
help
According to the C languages standard, printf() and related functions must be able to print any
integral number in floating-point notation, regardless of length, when using the %f specifier -
possibly hundreds of characters, potentially overflowing your buffers. In this implementation,
all values beyond this threshold are switched to exponential notation.
config RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS
int "the number of terms in a Taylor series expansion of log_10(x)"
default 4
range 2 99
help
The number of terms in a Taylor series expansion of log_10(x) to
use for approximation - including the power-zero term (i.e. the
value at the point of expansion).
endif
endmenu # rt_vsnprintf options
menu "rt_vsscanf options"
config RT_KLIBC_USING_LIBC_VSSCANF
bool "Enable rt_vsscanf to use libc vsscanf"
default n
endmenu # rt_vsscanf options
menu "rt_memset options"
config RT_KLIBC_USING_USER_MEMSET
bool "Enable rt_memset to use user-defined version"
default n
if !RT_KLIBC_USING_USER_MEMSET
config RT_KLIBC_USING_LIBC_MEMSET
bool "Enable rt_memset to use libc memset"
default n
config RT_KLIBC_USING_TINY_MEMSET
bool "Enable rt_memset to use tiny version"
depends on !RT_KLIBC_USING_LIBC_MEMSET
default n
endif
endmenu # rt_memset options
menu "rt_memcpy options"
config RT_KLIBC_USING_USER_MEMCPY
bool "Enable rt_memcpy to use user-defined version"
default n
if !RT_KLIBC_USING_USER_MEMCPY
config RT_KLIBC_USING_LIBC_MEMCPY
bool "Enable rt_memcpy to use libc memcpy"
default n
config RT_KLIBC_USING_TINY_MEMCPY
bool "Enable rt_memcpy to use tiny version"
depends on !RT_KLIBC_USING_LIBC_MEMCPY
default n
endif
endmenu # rt_memcpy options
menu "rt_memmove options"
config RT_KLIBC_USING_USER_MEMMOVE
bool "Enable rt_memmove to use user-defined version"
default n
if !RT_KLIBC_USING_USER_MEMMOVE
config RT_KLIBC_USING_LIBC_MEMMOVE
bool "Enable rt_memmove to use libc memmove"
default n
endif
endmenu # rt_memmove options
menu "rt_memcmp options"
config RT_KLIBC_USING_USER_MEMCMP
bool "Enable rt_memcmp to use user-defined version"
default n
if !RT_KLIBC_USING_USER_MEMCMP
config RT_KLIBC_USING_LIBC_MEMCMP
bool "Enable rt_memcmp to use libc memcmp"
default n
endif
endmenu # rt_memcmp options
menu "rt_strstr options"
config RT_KLIBC_USING_USER_STRSTR
bool "Enable rt_strstr to use user-defined version"
default n
if !RT_KLIBC_USING_USER_STRSTR
config RT_KLIBC_USING_LIBC_STRSTR
bool "Enable rt_strstr to use libc strstr"
default n
endif
endmenu # rt_strstr options
menu "rt_strcasecmp options"
config RT_KLIBC_USING_USER_STRCASECMP
bool "Enable rt_strcasecmp to use user-defined version"
default n
endmenu # rt_strcasecmp options
menu "rt_strncpy options"
config RT_KLIBC_USING_USER_STRNCPY
bool "Enable rt_strncpy to use user-defined version"
default n
if !RT_KLIBC_USING_USER_STRNCPY
config RT_KLIBC_USING_LIBC_STRNCPY
bool "Enable rt_strncpy to use libc strncpy"
default n
endif
endmenu # rt_strncpy options
menu "rt_strcpy options"
config RT_KLIBC_USING_USER_STRCPY
bool "Enable rt_strcpy to use user-defined version"
default n
if !RT_KLIBC_USING_USER_STRCPY
config RT_KLIBC_USING_LIBC_STRCPY
bool "Enable rt_strcpy to use libc strcpy"
default n
endif
endmenu # rt_strcpy options
menu "rt_strncmp options"
config RT_KLIBC_USING_USER_STRNCMP
bool "Enable rt_strncmp to use user-defined version"
default n
if !RT_KLIBC_USING_USER_STRNCMP
config RT_KLIBC_USING_LIBC_STRNCMP
bool "Enable rt_strncmp to use libc strncmp"
default n
endif
endmenu # rt_strncmp options
menu "rt_strcmp options"
config RT_KLIBC_USING_USER_STRCMP
bool "Enable rt_strcmp to use user-defined version"
default n
if !RT_KLIBC_USING_USER_STRCMP
config RT_KLIBC_USING_LIBC_STRCMP
bool "Enable rt_strcmp to use libc strcmp"
default n
endif
endmenu # rt_strcmp options
menu "rt_strlen options"
config RT_KLIBC_USING_USER_STRLEN
bool "Enable rt_strlen to use user-defined version"
default n
if !RT_KLIBC_USING_USER_STRLEN
config RT_KLIBC_USING_LIBC_STRLEN
bool "Enable rt_strlen to use libc strlen"
default n
endif
endmenu # rt_strlen options
menu "rt_strnlen options"
config RT_KLIBC_USING_USER_STRNLEN
bool "Enable rt_strnlen to use user-defined version"
default n
endmenu # rt_strnlen options
config RT_UTEST_TC_USING_KLIBC
bool "Enable klibc utest cases"
select RT_USING_UTEST
default n
endmenu
+23
View File
@@ -0,0 +1,23 @@
from building import *
import os
cwd = GetCurrentDir()
src = ['kerrno.c', 'kstdio.c', 'kstring.c']
if not GetDepend(['RT_KLIBC_USING_LIBC_VSNPRINTF']):
if GetDepend(['RT_KLIBC_USING_VSNPRINTF_STANDARD']):
src += ['rt_vsnprintf_std.c']
else:
src += ['rt_vsnprintf_tiny.c']
if not GetDepend(['RT_KLIBC_USING_LIBC_VSSCANF']):
src += ['rt_vsscanf.c']
group = DefineGroup('klibc', src, depend = [''])
list = os.listdir(cwd)
for item in list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
group = group + SConscript(os.path.join(item, 'SConscript'))
Return('group')
+161
View File
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-09-22 Meco Man the first version
*/
#include <rtthread.h>
/**
* @brief A global variable used to store the error code.
*
* This volatile static integer is used to store the most recent error code globally.
* Its volatile nature ensures that every read operation fetches the most current value,
* providing real-time error status across different parts of the program.
*/
static volatile int __rt_errno;
/**
* @struct _errno_str_t
* @brief Structure for mapping error codes to corresponding error strings.
*
* This structure is used to create a mapping that associates an rt_err_t type error code
* with a corresponding error description string.
*/
struct _errno_str_t
{
rt_err_t error; /**< Error code of type rt_err_t, representing different kinds of errors. */
const char *str; /**< Pointer to the error description string. */
};
/**
* @brief An array containing mappings of error codes to their corresponding error strings.
*
* This array uses the _errno_str_t structure to define several error codes and their
* corresponding error description strings. These mappings can be used at runtime
* to provide more readable error information.
*/
static struct _errno_str_t rt_errno_strs[] =
{
{RT_EOK , "OK "}, /**< Operation successful. */
{RT_ERROR , "ERROR "}, /**< General error. */
{RT_ETIMEOUT, "ETIMOUT"}, /**< Operation timed out. */
{RT_EFULL , "ERSFULL"}, /**< Resource is full. */
{RT_EEMPTY , "ERSEPTY"}, /**< Resource is empty. */
{RT_ENOMEM , "ENOMEM "}, /**< Not enough memory. */
{RT_ENOSYS , "ENOSYS "}, /**< Function not implemented. */
{RT_EBUSY , "EBUSY "}, /**< Resource is busy. */
{RT_EIO , "EIO "}, /**< Input/output error. */
{RT_EINTR , "EINTRPT"}, /**< Interrupted system call. */
{RT_EINVAL , "EINVAL "}, /**< Invalid argument. */
{RT_ENOENT , "ENOENT "}, /**< No such file or directory. */
{RT_ENOSPC , "ENOSPC "}, /**< No space left on device. */
{RT_EPERM , "EPERM "}, /**< Operation not permitted. */
{RT_ETRAP , "ETRAP "}, /**< Trap error. */
};
/**
* @brief This function return a pointer to a string that contains the
* message of error.
*
* @param error the errorno code
* @return a point to error message string
*/
const char *rt_strerror(rt_err_t error)
{
int i = 0;
if (error < 0)
error = -error;
for (i = 0; i < sizeof(rt_errno_strs) / sizeof(rt_errno_strs[0]); i++)
{
if (rt_errno_strs[i].error == error)
return rt_errno_strs[i].str;
}
return "EUNKNOW";
}
RTM_EXPORT(rt_strerror);
/**
* @brief This function gets the global errno for the current thread.
*
* @return errno
*/
rt_err_t rt_get_errno(void)
{
rt_thread_t tid = RT_NULL;
if (rt_interrupt_get_nest() != 0)
{
/* it's in interrupt context */
return __rt_errno;
}
tid = rt_thread_self();
if (tid == RT_NULL)
{
return __rt_errno;
}
return tid->error;
}
RTM_EXPORT(rt_get_errno);
/**
* @brief This function sets the global errno for the current thread.
*
* @param error is the errno shall be set.
*/
void rt_set_errno(rt_err_t error)
{
rt_thread_t tid = RT_NULL;
if (rt_interrupt_get_nest() != 0)
{
/* it's in interrupt context */
__rt_errno = error;
return;
}
tid = rt_thread_self();
if (tid == RT_NULL)
{
__rt_errno = error;
return;
}
tid->error = error;
}
RTM_EXPORT(rt_set_errno);
/**
* @brief This function returns the address of the current thread errno.
*
* @return The errno address.
*/
int *_rt_errno(void)
{
rt_thread_t tid = RT_NULL;
if (rt_interrupt_get_nest() != 0)
{
return (int *)&__rt_errno;
}
tid = rt_thread_self();
if (tid != RT_NULL)
{
return (int *) & (tid->error);
}
return (int *)&__rt_errno;
}
RTM_EXPORT(_rt_errno);
+116
View File
@@ -0,0 +1,116 @@
/*
* 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 <rtthread.h>
#if defined(RT_KLIBC_USING_LIBC_VSSCANF) || \
defined(RT_KLIBC_USING_LIBC_VSNPRINTF)
#include <stdio.h>
#endif
/**
* @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);
#ifdef RT_KLIBC_USING_LIBC_VSNPRINTF
int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
{
return vsnprintf(buf, size, fmt, args);
}
#endif /* RT_KLIBC_USING_LIBC_VSNPRINTF */
RTM_EXPORT(rt_vsnprintf);
#ifdef RT_KLIBC_USING_LIBC_VSSCANF
int rt_vsscanf(const char *buffer, const char *format, va_list ap)
{
return vsscanf(buffer, format, ap);
}
#endif /* RT_KLIBC_USING_LIBC_VSSCANF */
RTM_EXPORT(rt_vsscanf);
/**
* @brief This function parses a formatted string from the input string.
*
* @param str the input string to be parsed.
*
* @param format the format string that specifies how to interpret the input.
*
* @return The number of input items successfully matched and assigned.
*/
int rt_sscanf(const char *str, const char *format, ...)
{
va_list ap;
int rv;
va_start(ap, format);
rv = rt_vsscanf(str, format, ap);
va_end(ap);
return rv;
}
RTM_EXPORT(rt_sscanf);
+559
View File
@@ -0,0 +1,559 @@
/*
* 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 <rtthread.h>
#if defined(RT_KLIBC_USING_LIBC_MEMSET) || \
defined(RT_KLIBC_USING_LIBC_MEMCPY) || \
defined(RT_KLIBC_USING_LIBC_MEMMOVE) || \
defined(RT_KLIBC_USING_LIBC_MEMCMP) || \
defined(RT_KLIBC_USING_LIBC_STRSTR) || \
defined(RT_KLIBC_USING_LIBC_STRNCPY) || \
defined(RT_KLIBC_USING_LIBC_STRCPY) || \
defined(RT_KLIBC_USING_LIBC_STRNCMP) || \
defined(RT_KLIBC_USING_LIBC_STRCMP) || \
defined(RT_KLIBC_USING_LIBC_STRLEN)
#include <string.h>
#endif
/**
* @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.
*/
#ifndef RT_KLIBC_USING_USER_MEMSET
void *rt_memset(void *s, int c, rt_ubase_t count)
{
#if defined(RT_KLIBC_USING_LIBC_MEMSET)
return memset(s, c, count);
#elif defined(RT_KLIBC_USING_TINY_MEMSET)
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_KLIBC_USING_LIBC_MEMSET */
}
#endif /* RT_KLIBC_USING_USER_MEMSET */
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
*/
#ifndef RT_KLIBC_USING_USER_MEMCPY
void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
{
#if defined(RT_KLIBC_USING_LIBC_MEMCPY)
return memcpy(dst, src, count);
#elif defined(RT_KLIBC_USING_TINY_MEMCPY)
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_KLIBC_USING_LIBC_MEMCPY */
}
#endif /* RT_KLIBC_USING_USER_MEMCPY */
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.
*/
#ifndef RT_KLIBC_USING_USER_MEMMOVE
void *rt_memmove(void *dest, const void *src, rt_size_t n)
{
#ifdef RT_KLIBC_USING_LIBC_MEMMOVE
return memmove(dest, src, n);
#else
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;
#endif /* RT_KLIBC_USING_LIBC_MEMMOVE */
}
#endif /* RT_KLIBC_USING_USER_MEMMOVE */
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.
*/
#ifndef RT_KLIBC_USING_USER_MEMCMP
rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_size_t count)
{
#ifdef RT_KLIBC_USING_LIBC_MEMCMP
return memcmp(cs, ct, count);
#else
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;
#endif /* RT_KLIBC_USING_LIBC_MEMCMP */
}
#endif /* RT_KLIBC_USING_USER_MEMCMP */
RTM_EXPORT(rt_memcmp);
/**
* @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.
*/
#ifndef RT_KLIBC_USING_USER_STRSTR
char *rt_strstr(const char *s1, const char *s2)
{
#ifdef RT_KLIBC_USING_LIBC_STRSTR
return strstr(s1, s2);
#else
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;
#endif /* RT_KLIBC_USING_LIBC_STRSTR */
}
#endif /* RT_KLIBC_USING_USER_STRSTR */
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.
*/
#ifndef RT_KLIBC_USING_USER_STRCASECMP
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;
}
#endif /* RT_KLIBC_USING_USER_STRCASECMP */
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.
*/
#ifndef RT_KLIBC_USING_USER_STRNCPY
char *rt_strncpy(char *dst, const char *src, rt_size_t n)
{
#ifdef RT_KLIBC_USING_LIBC_STRNCPY
return strncpy(dst, src, n);
#else
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);
#endif /* RT_KLIBC_USING_LIBC_STRNCPY */
}
#endif /* RT_KLIBC_USING_USER_STRNCPY */
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.
*/
#ifndef RT_KLIBC_USING_USER_STRCPY
char *rt_strcpy(char *dst, const char *src)
{
#ifdef RT_KLIBC_USING_LIBC_STRCPY
return strcpy(dst, src);
#else
char *dest = dst;
while (*src != '\0')
{
*dst = *src;
dst++;
src++;
}
*dst = '\0';
return dest;
#endif /* RT_KLIBC_USING_LIBC_STRCPY */
}
#endif /* RT_KLIBC_USING_USER_STRCPY */
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.
*/
#ifndef RT_KLIBC_USING_USER_STRNCMP
rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_size_t count)
{
#ifdef RT_KLIBC_USING_LIBC_STRNCMP
return strncmp(cs, ct, count);
#else
signed char res = 0;
while (count)
{
if ((res = *cs - *ct++) != 0 || !*cs++)
{
break;
}
count --;
}
return res;
#endif /* RT_KLIBC_USING_LIBC_STRNCMP */
}
#endif /* RT_KLIBC_USING_USER_STRNCMP */
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.
*/
#ifndef RT_KLIBC_USING_USER_STRCMP
rt_int32_t rt_strcmp(const char *cs, const char *ct)
{
#ifdef RT_KLIBC_USING_LIBC_STRCMP
return strcmp(cs, ct);
#else
while (*cs && *cs == *ct)
{
cs++;
ct++;
}
return (*cs - *ct);
#endif /* RT_KLIBC_USING_LIBC_STRCMP */
}
#endif /* RT_KLIBC_USING_USER_STRCMP */
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.
*/
#ifndef RT_KLIBC_USING_USER_STRLEN
rt_size_t rt_strlen(const char *s)
{
#ifdef RT_KLIBC_USING_LIBC_STRLEN
return strlen(s);
#else
const char *sc = RT_NULL;
for (sc = s; *sc != '\0'; ++sc);
return sc - s;
#endif /* RT_KLIBC_USING_LIBC_STRLEN */
}
#endif /* RT_KLIBC_USING_USER_STRLEN */
RTM_EXPORT(rt_strlen);
/**
* @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.
*/
#ifndef RT_KLIBC_USING_USER_STRNLEN
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);
return sc - s;
}
#endif /* RT_KLIBC_USING_USER_STRNLEN */
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 */
File diff suppressed because it is too large Load Diff
+611
View File
@@ -0,0 +1,611 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-11-19 Meco Man the first version
*/
#include <rtthread.h>
#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_KLIBC_USING_VSNPRINTF_LONGLONG
rt_inline int divide(unsigned long long *n, int base)
#else
rt_inline int divide(unsigned long *n, int base)
#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
{
int res;
/* optimized for processor which does not support divide instructions. */
#ifdef RT_KLIBC_USING_VSNPRINTF_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_KLIBC_USING_VSNPRINTF_LONGLONG
unsigned long long num,
#else
unsigned long num,
#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
int base,
int qualifier,
int s,
int precision,
int type)
{
char c = 0, sign = 0;
#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
char tmp[64] = {0};
#else
char tmp[32] = {0};
#endif /* RT_KLIBC_USING_VSNPRINTF_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 */) && (__GNUC__ >= 7)
/* Disable "-Wimplicit-fallthrough" below GNUC V7 */
#pragma GCC diagnostic push
/* ignore warning: this statement may fall through */
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif /* (defined(__GNUC__) && !defined(__ARMCC_VERSION)) && (__GNUC__ >= 7 */
/**
* @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.
*/
int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
{
#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
unsigned long long num = 0;
#else
unsigned long num = 0;
#endif /* RT_KLIBC_USING_VSNPRINTF_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_KLIBC_USING_VSNPRINTF_LONGLONG
*fmt == 'L' ||
#endif /* RT_KLIBC_USING_VSNPRINTF_LONGLONG */
*fmt == 'z')
{
qualifier = *fmt;
++fmt;
#ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
if (qualifier == 'l' && *fmt == 'l')
{
qualifier = 'L';
++fmt;
}
#endif /* RT_KLIBC_USING_VSNPRINTF_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;
}
#if (defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */) && (__GNUC__ >= 7)
#pragma GCC diagnostic pop /* ignored "-Wimplicit-fallthrough" */
#endif /* (defined(__GNUC__) && !defined(__ARMCC_VERSION)) && (__GNUC__ >= 7 */
+700
View File
@@ -0,0 +1,700 @@
/*
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-11-24 Meco Man port to klibc
* 2025-01-04 Meco Man using Phoenix version
*/
/*
* Copyright 2017, 2022-2023 Phoenix Systems
* Author: Adrian Kepka, Gerard Swiderski
*/
#include <rtthread.h>
#include <stdlib.h> /* for strtod */
#include <ctype.h> /* for isspace */
#include <stdarg.h> /* for va_list */
#define FORMAT_NIL_STR "(nil)"
#define FORMAT_NIL_STR_LEN (sizeof(FORMAT_NIL_STR) - 1)
#define LONG 0x01 /* l: long or double */
#define LONGDOUBLE 0x02 /* L: long double */
#define SHORT 0x04 /* h: short */
#define SUPPRESS 0x08 /* *: suppress assignment */
#define POINTER 0x10 /* p: void * (as hex) */
#define NOSKIP 0x20 /* [ or c: do not skip blanks */
#define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */
#define PTRDIFF 0x800 /* t: ptrdiff_t */
#define SHORTSHORT 0x4000 /* hh: char */
#define UNSIGNED 0x8000 /* %[oupxX] conversions */
#define SIGNOK 0x40 /* +/- is (still) legal */
#define NDIGITS 0x80 /* no digits detected */
#define PFXOK 0x100 /* 0x prefix is (still) legal */
#define NZDIGITS 0x200 /* no zero digits detected */
#define CT_CHAR 0 /* %c conversion */
#define CT_CCL 1 /* %[...] conversion */
#define CT_STRING 2 /* %s conversion */
#define CT_INT 3 /* %[dioupxX] conversion */
#define CT_FLOAT 4 /* %[aefgAEFG] conversion */
#define CT_NONE 5 /* No conversion (ex. %n) */
static const unsigned char *__sccl(char *tab, const unsigned char *fmt)
{
int c, n, v;
c = *fmt++;
if (c == '^') {
v = 1;
c = *fmt++;
}
else {
v = 0;
}
rt_memset(tab, (uint8_t)v, 256);
if (c == 0) {
return (fmt - 1);
}
v = 1 - v;
tab[c] = v;
for (;;) {
n = *fmt++;
switch (n) {
case 0:
return (fmt - 1);
case '-':
n = *fmt;
if ((n == ']') || (n < c)) {
c = '-';
tab[c] = v;
break;
}
fmt++;
do {
tab[++c] = v;
} while (c < n);
c = n;
break;
case ']':
return (fmt);
default:
c = n;
tab[c] = v;
break;
}
}
}
static int scanf_parse(char *ccltab, const char *inp, int *inr, char const *fmt0, va_list ap)
{
const unsigned char *fmt = (const unsigned char *)fmt0;
int c, n, flags, nassigned, nconversions, nread, base;
rt_size_t width;
char *p, *p0;
char buf[32];
static const short basefix[17] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
*inr = rt_strlen(inp);
nassigned = 0;
nconversions = 0;
nread = 0;
base = 0;
for (;;) {
int convType = CT_NONE;
c = *fmt++;
if (c == '\0') {
return (nassigned);
}
if (isspace(c) != 0) {
while ((*inr > 0) && (isspace((int)*inp) != 0)) {
nread++;
(*inr)--;
inp++;
}
continue;
}
if (c != '%') {
if (*inr <= 0) {
return (nconversions != 0 ? nassigned : -1);
}
if (*inp != c) {
return nassigned;
}
nread++;
(*inr)--;
inp++;
continue;
}
width = 0;
flags = 0;
for (;;) {
c = *fmt++;
if (c == '\0') {
return nassigned;
}
if (c == '%') {
if (*inr <= 0) {
return (nconversions != 0 ? nassigned : -1);
}
if (*inp != c) {
return nassigned;
}
nread++;
(*inr)--;
inp++;
break;
}
switch (c) {
case '*':
flags |= SUPPRESS;
continue;
case 'l':
if ((flags & LONG) != 0) {
flags &= ~LONG;
flags |= LONGLONG;
}
else {
flags |= LONG;
}
continue;
case 'L':
flags |= LONGDOUBLE;
continue;
case 'q':
case 'j':
flags |= LONGLONG;
continue;
case 't':
flags |= PTRDIFF;
continue;
case 'z':
if (sizeof(rt_size_t) == sizeof(uint64_t)) {
flags |= LONGLONG;
}
continue;
case 'h':
if ((flags & SHORT) != 0) {
flags &= ~SHORT;
flags |= SHORTSHORT;
}
else {
flags |= SHORT;
}
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
width = width * 10 + c - '0';
continue;
default:
break;
}
/* conversions */
switch (c) {
case 'd':
convType = CT_INT;
base = 10;
break;
case 'i':
convType = CT_INT;
base = 0;
break;
case 'o':
convType = CT_INT;
flags |= UNSIGNED;
base = 8;
break;
case 'u':
convType = CT_INT;
flags |= UNSIGNED;
base = 10;
break;
case 'X':
case 'x':
flags |= PFXOK; /* enable 0x prefixing */
convType = CT_INT;
flags |= UNSIGNED;
base = 16;
break;
case 'A':
case 'E':
case 'F':
case 'G':
case 'a':
case 'e':
case 'f':
case 'g':
convType = CT_FLOAT;
break;
case 's':
convType = CT_STRING;
break;
case '[':
fmt = __sccl(ccltab, fmt);
flags |= NOSKIP;
convType = CT_CCL;
break;
case 'c':
flags |= NOSKIP;
convType = CT_CHAR;
break;
case 'p':
flags |= POINTER | PFXOK | UNSIGNED;
convType = CT_INT;
base = 16;
break;
case 'n':
nconversions++;
if ((flags & SUPPRESS) != 0) {
break;
}
if ((flags & SHORTSHORT) != 0) {
*va_arg(ap, char *) = nread;
}
else if ((flags & SHORT) != 0) {
*va_arg(ap, short *) = nread;
}
else if ((flags & LONG) != 0) {
*va_arg(ap, long *) = nread;
}
else if ((flags & LONGLONG) != 0) {
*va_arg(ap, long long *) = nread;
}
else if ((flags & PTRDIFF) != 0) {
*va_arg(ap, ptrdiff_t *) = nread;
}
else {
*va_arg(ap, int *) = nread;
}
break;
default:
/* Character not a conversion specifier; end parsing */
return nassigned;
}
break;
}
if (convType == CT_NONE) {
continue;
}
if (*inr <= 0) {
return (nconversions != 0 ? nassigned : -1);
}
if ((flags & NOSKIP) == 0) {
while (isspace((int)*inp) != 0) {
nread++;
if (--(*inr) > 0) {
inp++;
}
else {
return (nconversions != 0 ? nassigned : -1);
}
}
}
/* do the conversion */
switch (convType) {
case CT_CHAR:
if (width == 0) {
width = 1;
}
if (*inr <= 0) {
return (nconversions != 0 ? nassigned : -1);
}
if (width > *inr) {
width = *inr;
}
if ((flags & SUPPRESS) == 0) {
rt_memcpy(va_arg(ap, char *), inp, width);
nassigned++;
}
*inr -= width;
inp += width;
nread += width;
nconversions++;
break;
case CT_CCL:
if (width == 0) {
width = (rt_size_t)~0;
}
if ((flags & SUPPRESS) != 0) {
n = 0;
while (ccltab[(unsigned char)*inp] != 0) {
n++;
(*inr)--;
inp++;
if (--width == 0) {
break;
}
if (*inr <= 0) {
if (n == 0) {
return (nconversions != 0 ? nassigned : -1);
}
break;
}
}
if (n == 0) {
return nassigned;
}
}
else {
p0 = p = va_arg(ap, char *);
while (ccltab[(unsigned char)*inp] != 0) {
(*inr)--;
*p++ = *inp++;
if (--width == 0) {
break;
}
if (*inr <= 0) {
if (p == p0) {
return (nconversions != 0 ? nassigned : -1);
}
break;
}
}
n = p - p0;
if (n == 0) {
return nassigned;
}
*p = 0;
nassigned++;
}
nread += n;
nconversions++;
break;
case CT_STRING:
if (width == 0) {
width = (rt_size_t)~0;
}
if ((flags & SUPPRESS) != 0) {
while (isspace((int)*inp) == 0) {
nread++;
(*inr)--;
inp++;
if (--width == 0) {
break;
}
if (*inr <= 0) {
break;
}
}
}
else {
p0 = p = va_arg(ap, char *);
while (isspace((int)*inp) == 0) {
(*inr)--;
*p++ = *inp++;
if (--width == 0) {
break;
}
if (*inr <= 0) {
break;
}
}
*p = 0;
nread += p - p0;
nassigned++;
}
nconversions++;
continue;
case CT_INT:
if (((flags & POINTER) != 0) && ((*inr) >= FORMAT_NIL_STR_LEN) && (rt_strncmp(FORMAT_NIL_STR, inp, FORMAT_NIL_STR_LEN) == 0)) {
*va_arg(ap, void **) = RT_NULL;
nassigned++;
nconversions++;
nread += FORMAT_NIL_STR_LEN;
inp += FORMAT_NIL_STR_LEN;
(*inr) -= FORMAT_NIL_STR_LEN;
break;
}
if (--width > (sizeof(buf) - 2)) {
width = sizeof(buf) - 2;
}
width++;
if ((flags & SUPPRESS) != 0) {
width = ~0;
}
flags |= SIGNOK | NDIGITS | NZDIGITS;
for (p = buf; width; width--) {
int ok = 0;
c = *inp;
switch (c) {
case '0':
if (base == 0) {
base = 8;
flags |= PFXOK;
}
if ((flags & NZDIGITS) != 0) {
flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
}
else {
flags &= ~(SIGNOK | PFXOK | NDIGITS);
}
ok = 1;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
base = basefix[base];
flags &= ~(SIGNOK | PFXOK | NDIGITS);
ok = 1;
break;
case '8':
case '9':
base = basefix[base];
if (base <= 8) {
break; /* not legal here */
}
flags &= ~(SIGNOK | PFXOK | NDIGITS);
ok = 1;
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
if (base <= 10) {
break;
}
flags &= ~(SIGNOK | PFXOK | NDIGITS);
ok = 1;
break;
case '+':
case '-':
if ((flags & SIGNOK) != 0) {
flags &= ~SIGNOK;
ok = 1;
}
break;
case 'x':
case 'X':
if (((flags & PFXOK) != 0) && (p == buf + 1)) {
base = 16; /* if %i */
flags &= ~PFXOK;
ok = 1;
}
break;
}
if (!ok)
break;
if ((flags & SUPPRESS) == 0) {
*p++ = c;
}
if (--(*inr) > 0) {
inp++;
}
else {
break;
}
}
if ((flags & NDIGITS) != 0) {
return (nconversions != 0 ? nassigned : -1);
}
c = ((unsigned char *)p)[-1];
if ((c == 'x') || (c == 'X')) {
--p;
inp--;
(*inr)++;
}
if ((flags & SUPPRESS) == 0) {
uint64_t res;
*p = 0;
if ((flags & UNSIGNED) == 0) {
res = strtoll(buf, (char **)RT_NULL, base);
}
else {
res = strtoull(buf, (char **)RT_NULL, base);
}
if ((flags & POINTER) != 0) {
*va_arg(ap, void **) = (void *)(unsigned long)res;
}
else if ((flags & SHORTSHORT) != 0) {
*va_arg(ap, char *) = res;
}
else if ((flags & SHORT) != 0) {
*va_arg(ap, short *) = res;
}
else if ((flags & LONG) != 0) {
*va_arg(ap, long *) = res;
}
else if ((flags & LONGLONG) != 0) {
*va_arg(ap, long long *) = res;
}
else if ((flags & PTRDIFF) != 0) {
*va_arg(ap, ptrdiff_t *) = res;
}
else {
*va_arg(ap, int *) = res;
}
nassigned++;
}
nread += p - buf;
nconversions++;
break;
case CT_FLOAT: {
union {
float f;
double d;
long double ld;
} res;
const char *srcbuf = inp;
if ((width != 0) && (width < *inr)) {
/* TODO: handle larger widths */
if (width > (sizeof(buf) - 1)) {
return (nconversions != 0 ? nassigned : -1);
}
rt_memcpy(buf, inp, width);
buf[width] = '\0';
srcbuf = buf;
}
int is_zero;
if ((flags & LONGDOUBLE) != 0) {
res.ld = strtold(srcbuf, &p);
is_zero = res.ld == 0;
}
else if ((flags & LONG) != 0) {
res.d = strtod(srcbuf, &p);
is_zero = res.d == 0;
}
else {
res.f = strtof(srcbuf, &p);
is_zero = res.f == 0;
}
if (is_zero && (srcbuf == p)) {
return (nconversions != 0 ? nassigned : -1);
}
int consumed = p - srcbuf;
*inr -= consumed;
inp += consumed;
nread += consumed;
nconversions++;
if ((flags & SUPPRESS) == 0) {
if ((flags & LONGDOUBLE) != 0) {
*va_arg(ap, long double *) = res.ld;
}
else if ((flags & LONG) != 0) {
*va_arg(ap, double *) = res.d;
}
else {
*va_arg(ap, float *) = res.f;
}
nassigned++;
}
break;
}
default:
break;
}
}
/* never reached */
}
int rt_vsscanf(const char *str, const char *format, va_list ap)
{
int ret, nremain;
char *ccltab = rt_malloc(256);
if (ccltab == RT_NULL) {
return -1;
}
ret = scanf_parse(ccltab, str, &nremain, format, ap);
rt_free(ccltab);
return ret;
}
+10
View File
@@ -0,0 +1,10 @@
from building import *
src = []
if GetDepend('RT_UTEST_USING_ALL_CASES') or GetDepend('RT_UTEST_TC_USING_KLIBC'):
src += Glob('TC_*.c')
group = DefineGroup('utestcases', src, depend = [''])
Return('group')
+161
View File
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-05-06 Phillip Johnston the first version
* 2024-12-24 Meco Man port to utest
*/
#include <rtklibc.h>
#include <utest.h>
static void TC_rt_memcmp_str(void)
{
const char* s = "abc 123";
uassert_int_equal(rt_memcmp("abc", "abc", 4), 0);
uassert_int_equal(rt_memcmp(s, "abc", 3), 0);
uassert_int_equal(rt_memcmp("abc", s, 3), 0);
/* The following tests intentionally use a length > 3 */
/* To test what rt_memcmp does in such a situation */
uassert_value_greater(rt_memcmp(s, "abc", 6), 0);
uassert_value_less(rt_memcmp("abc", s, 6), 0);
}
static void TC_rt_memcmp_int_array(void)
{
int arr1[] = {1, 2, 3, 4, 5};
int arr2[] = {1, 2, 3, 4, 5};
int arr3[] = {1, 2, 3, 4, 6};
uassert_int_equal(rt_memcmp(arr1, arr2, sizeof(arr1)), 0);
uassert_value_less(rt_memcmp(arr1, arr3, sizeof(arr1)), 0);
uassert_value_greater(rt_memcmp(arr3, arr1, sizeof(arr1)), 0);
}
static void TC_rt_memcmp_float_array(void)
{
float arr1[] = {1.0f, 2.0f, 3.0f};
float arr2[] = {1.0f, 2.0f, 3.0f};
float arr3[] = {1.0f, 2.0f, 3.1f};
uassert_int_equal(rt_memcmp(arr1, arr2, sizeof(arr1)), 0);
uassert_value_less(rt_memcmp(arr1, arr3, sizeof(arr1)), 0);
uassert_value_greater(rt_memcmp(arr3, arr1, sizeof(arr1)), 0);
}
typedef struct {
int id;
float value;
} Item;
static void TC_rt_memcmp_struct_array(void)
{
Item arr1[] = {{1, 1.0f}, {2, 2.0f}};
Item arr2[] = {{1, 1.0f}, {2, 2.0f}};
Item arr3[] = {{1, 1.0f}, {2, 2.1f}};
uassert_int_equal(rt_memcmp(arr1, arr2, sizeof(arr1)), 0);
uassert_value_less(rt_memcmp(arr1, arr3, sizeof(arr1)), 0);
uassert_value_greater(rt_memcmp(arr3, arr1, sizeof(arr1)), 0);
}
typedef struct {
int id;
float value;
char name[10];
} MixedItem;
static void TC_rt_memcmp_mixed_array(void)
{
MixedItem arr1[] = {{1, 1.0f, "item1"}, {2, 2.0f, "item2"}};
MixedItem arr2[] = {{1, 1.0f, "item1"}, {2, 2.0f, "item2"}};
MixedItem arr3[] = {{1, 1.0f, "item1"}, {2, 2.1f, "item2"}};
uassert_int_equal(rt_memcmp(arr1, arr2, sizeof(arr1)), 0);
uassert_value_less(rt_memcmp(arr1, arr3, sizeof(arr1)), 0);
uassert_value_greater(rt_memcmp(arr3, arr1, sizeof(arr1)), 0);
}
typedef struct {
int id;
float score;
} Student;
typedef struct {
Student students[3];
char className[10];
} Class;
static void TC_rt_memcmp_nested_struct_array(void)
{
Class class1 = {
.students = {{1, 90.5}, {2, 85.0}, {3, 92.0}},
.className = "ClassA"
};
Class class2 = {
.students = {{1, 90.5}, {2, 85.0}, {3, 92.0}},
.className = "ClassA"
};
Class class3 = {
.students = {{1, 90.5}, {2, 85.1}, {3, 92.0}},
.className = "ClassA"
};
uassert_int_equal(rt_memcmp(&class1, &class2, sizeof(Class)), 0);
uassert_int_not_equal(rt_memcmp(&class1, &class3, sizeof(Class)), 0);
}
static void TC_rt_memcmp_partial_match(void)
{
char arr1[] = "abcdefghijklmnopqrstuvwxyz";
char arr2[] = "abcdefghijklmxyznopqrstuvw";
uassert_int_equal(rt_memcmp(arr1, arr2, 13), 0);
uassert_int_not_equal(rt_memcmp(arr1, arr2, sizeof(arr1)), 0);
}
#define LARGE_ARRAY_SIZE 500
static void TC_rt_memcmp_large_array(void)
{
int *arr1 = rt_calloc(LARGE_ARRAY_SIZE, sizeof(int));
int *arr2 = rt_calloc(LARGE_ARRAY_SIZE, sizeof(int));
uassert_not_null(arr1);
uassert_not_null(arr2);
for (int i = 0; i < LARGE_ARRAY_SIZE; i++) {
arr1[i] = i;
arr2[i] = i;
}
uassert_int_equal(rt_memcmp(arr1, arr2, LARGE_ARRAY_SIZE * sizeof(int)), 0);
arr2[LARGE_ARRAY_SIZE - 1] = LARGE_ARRAY_SIZE;
uassert_value_less(rt_memcmp(arr1, arr2, LARGE_ARRAY_SIZE * sizeof(int)), 0);
uassert_value_greater(rt_memcmp(arr2, arr1, LARGE_ARRAY_SIZE * sizeof(int)), 0);
rt_free(arr1);
rt_free(arr2);
}
static void utest_do_tc(void)
{
UTEST_UNIT_RUN(TC_rt_memcmp_str);
UTEST_UNIT_RUN(TC_rt_memcmp_int_array);
UTEST_UNIT_RUN(TC_rt_memcmp_float_array);
UTEST_UNIT_RUN(TC_rt_memcmp_struct_array);
UTEST_UNIT_RUN(TC_rt_memcmp_mixed_array);
UTEST_UNIT_RUN(TC_rt_memcmp_nested_struct_array);
UTEST_UNIT_RUN(TC_rt_memcmp_partial_match);
UTEST_UNIT_RUN(TC_rt_memcmp_large_array);
}
UTEST_TC_EXPORT(utest_do_tc, "klibc.rt_memcmp", RT_NULL, RT_NULL, 1000);
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-05-06 Phillip Johnston the first version
* 2024-12-24 Meco Man port to utest
*/
#include <rtthread.h>
#include <utest.h>
#define N 80 /**< Define the constant N for buffer size as 80 */
#define TEST_BUF_SIZE 512 /**< Define the constant TEST_BUF_SIZE as 512 */
static char *buf; /**< Define a static buffer of 512 bytes, initialized to 0 */
static rt_err_t utest_tc_init(void)
{
buf = rt_malloc(TEST_BUF_SIZE * sizeof(char)); /**< Allocate memory for the buffer */
uassert_not_null(buf);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_free(buf);
return RT_EOK;
}
/**
* Test memory copy with alignment.
* @param dalign The alignment offset for the destination buffer.
* @param salign The alignment offset for the source buffer.
* @param len The length of data to copy.
*/
static void test_align(unsigned dalign, unsigned salign, size_t len)
{
char *src = (char *)RT_ALIGN((rt_ubase_t)buf, 64); /**< Source buffer starting address, 64-byte aligned */
char *dst = (char *)RT_ALIGN(((rt_ubase_t)buf + 128), 64); /**< Destination buffer starting address, 64-byte aligned from buf+128 */
char *want = (char *)RT_ALIGN(((rt_ubase_t)buf + 256), 64); /**< Expected result buffer starting address, 64-byte aligned from buf+256 */
char *p; /**< Pointer to receive the return value of rt_memcpy */
unsigned i;
/** Assert that the source alignment offset plus length does not exceed N */
uassert_false(salign + len > N);
/** Assert that the destination alignment offset plus length does not exceed N */
uassert_false(dalign + len > N);
/** Initialize all buffers with '#' or ' ' */
for(i = 0; i < N; i++)
{
src[i] = '#';
dst[i] = want[i] = ' ';
}
/** Set data in the specified alignment offsets of the source and expected result buffers */
for(i = 0; i < len; i++)
{
src[salign + i] = want[dalign + i] = (char)('0' + i);
}
/** Call rt_memcpy to copy data */
p = rt_memcpy(dst + dalign, src + salign, len);
/** Assert that the return value of rt_memcpy is the pointer to the start of the copied data in the destination buffer */
uassert_ptr_equal(p, dst + dalign);
/** Assert that the content of the destination buffer matches the expected result buffer */
for(i = 0; i < N; i++)
{
uassert_int_equal(dst[i], want[i]);
}
}
/**
* Test case to iterate over all possible alignment offsets and length combinations.
*/
static void TC_rt_memcpy_align(void)
{
for(unsigned i = 0; i < 16; i++) /**< Iterate over source alignment offsets from 0 to 15 */
{
for(unsigned j = 0; j < 16; j++) /**< Iterate over destination alignment offsets from 0 to 15 */
{
for(size_t k = 0; k < 64; k++) /**< Iterate over data lengths from 0 to 63 */
{
test_align(i, j, k); /**< Call the test_align function */
}
}
}
}
static void TC_rt_memcpy_str(void)
{
const char src[] = "Hello, memcpy!";
char dest[20] = {0};
rt_memcpy(dest, src, sizeof(src));
uassert_true(rt_strcmp(src, dest) == 0);
}
static void utest_do_tc(void)
{
UTEST_UNIT_RUN(TC_rt_memcpy_str);
UTEST_UNIT_RUN(TC_rt_memcpy_align);
}
UTEST_TC_EXPORT(utest_do_tc, "klibc.rt_memcpy", utest_tc_init, utest_tc_cleanup, 1000);
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-12-25 Meco Man first version
*/
#include <rtthread.h>
#include <utest.h>
/* Basic move with no overlap */
static void TC_rt_memmove_basic(void)
{
char src[] = "Hello";
char dest[10] = {0};
rt_memmove(dest, src, rt_strlen(src) + 1);
uassert_str_equal(dest, "Hello");
}
/* Move with overlap (src before dest) */
static void TC_rt_memmove_overlap_src_before(void)
{
char buffer[] = "1234567890";
rt_memmove(&buffer[3], buffer, 5);
uassert_str_equal(buffer, "1231234590");
}
/* Move with overlap (src after dest) */
static void TC_rt_memmove_overlap_src_after(void)
{
char buffer[] = "1234567890";
rt_memmove(&buffer[2], &buffer[5], 5);
uassert_str_equal(buffer, "1267890890");
}
/* Move with zero length */
static void TC_rt_memmove_zero_length(void)
{
char src[] = "Hello";
char dest[10] = "World";
rt_memmove(dest, src, 0);
uassert_str_equal(dest, "World");
}
/* Move to the same location */
static void TC_rt_memmove_same_location(void)
{
char buffer[] = "Hello";
rt_memmove(buffer, buffer, rt_strlen(buffer) + 1);
uassert_str_equal(buffer, "Hello");
}
/* Move from NULL */
static void TC_rt_memmove_null_src(void)
{
char dest[10];
rt_memset(dest, 'A', sizeof(dest));
rt_memmove(dest, RT_NULL, 0); /* Should not crash and do nothing */
uassert_buf_equal(dest, "AAAAAAAAAA", 10);
}
/* Move to NULL */
static void TC_rt_memmove_null_dest(void)
{
char src[] = "Hello";
rt_memmove(RT_NULL, src, 0); /* Should not crash and do nothing */
}
/* Move more than source size */
static void TC_rt_memmove_too_long(void)
{
char src[] = "Short";
char dest[10] = {0};
rt_memmove(dest, src, sizeof(src) + 5); /* Should only copy up to src length */
uassert_str_equal(dest, "Short");
uassert_int_equal(dest[5], 0); /* Ensure no buffer overflow */
}
/* Move empty string */
static void TC_rt_memmove_empty_string(void)
{
char src[] = "";
char dest[10] = "Unchanged";
rt_memmove(dest, src, rt_strlen(src) + 1);
/* Expect dest to only contain '\0' at the start */
uassert_str_equal(dest, ""); /* Destination should now be an empty string */
uassert_int_equal(dest[0], '\0'); /* First character should be '\0' */
}
/* Utest function to run all test cases */
static void utest_do_tc(void)
{
UTEST_UNIT_RUN(TC_rt_memmove_basic);
UTEST_UNIT_RUN(TC_rt_memmove_overlap_src_before);
UTEST_UNIT_RUN(TC_rt_memmove_overlap_src_after);
UTEST_UNIT_RUN(TC_rt_memmove_zero_length);
UTEST_UNIT_RUN(TC_rt_memmove_same_location);
UTEST_UNIT_RUN(TC_rt_memmove_null_src);
UTEST_UNIT_RUN(TC_rt_memmove_null_dest);
UTEST_UNIT_RUN(TC_rt_memmove_too_long);
UTEST_UNIT_RUN(TC_rt_memmove_empty_string);
}
UTEST_TC_EXPORT(utest_do_tc, "klibc.rt_memmove", RT_NULL, RT_NULL, 1000);
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-05-06 Phillip Johnston the first version
* 2024-12-24 Meco Man port to utest
*/
#include <rtthread.h>
#include <utest.h>
#define TEST_BUF_SIZE 400
static char *buf;
static char *buf2;
static rt_err_t utest_tc_init(void)
{
buf = rt_malloc(TEST_BUF_SIZE * sizeof(char));
uassert_not_null(buf);
buf2 = rt_malloc(TEST_BUF_SIZE * sizeof(char));
uassert_not_null(buf2);
return RT_EOK;
}
static rt_err_t utest_tc_cleanup(void)
{
rt_free(buf);
rt_free(buf2);
return RT_EOK;
}
static void test_align(int align, size_t len)
{
char *s = (char *)RT_ALIGN(((rt_ubase_t)buf + 64), 64) + align;
char *want = (char *)RT_ALIGN(((rt_ubase_t)buf2 + 64), 64) + align;
char *p;
int i;
uassert_false(len + 64 > (size_t)(buf + TEST_BUF_SIZE - s));
uassert_false(len + 64 > (size_t)(buf2 + TEST_BUF_SIZE - want));
for(i = 0; i < TEST_BUF_SIZE; i++)
{
buf[i] = buf2[i] = ' ';
}
for(i = 0; i < (int)len; i++)
{
want[i] = '#';
}
p = rt_memset(s, '#', len);
uassert_ptr_equal(p, s);
for(i = -64; i < (int)len + 64; i++)
{
uassert_int_equal(s[i], want[i]);
}
}
static void TC_rt_memcpy_align(void)
{
for(int i = 0; i < 16; i++)
{
for(size_t j = 0; j < 200; j++)
{
test_align(i, j);
}
}
}
static void test_input(char c)
{
rt_memset(buf, c, 10);
for(int i = 0; i < 10; i++)
{
uassert_int_equal(buf[i], c);
}
}
static void TC_rt_memcpy_input(void)
{
test_input('c');
test_input(0);
test_input(-1);
test_input(0xab);
test_input((char)RT_UINT32_MAX);
test_input((char)-RT_UINT32_MAX);
}
static void utest_do_tc(void)
{
UTEST_UNIT_RUN(TC_rt_memcpy_align);
UTEST_UNIT_RUN(TC_rt_memcpy_input);
}
UTEST_TC_EXPORT(utest_do_tc, "klibc.rt_memset", utest_tc_init, utest_tc_cleanup, 1000);
File diff suppressed because it is too large Load Diff
+250
View File
@@ -0,0 +1,250 @@
/*
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-01-04 Meco Man the first version
*/
#include <rtklibc.h>
#include "utest.h"
static void TC_rt_sscanf_char(void)
{
const char str[] = "A B";
char a, b;
rt_sscanf(str, "%c %c", &a, &b);
uassert_true(a == 'A' && b == 'B');
/* Move to the next character after space for the second %c */
rt_sscanf(str + 2, "%c", &b);
uassert_true(b == 'B');
}
static void TC_rt_sscanf_basic_int(void)
{
const char str[] = "12345";
int value;
int result = rt_sscanf(str, "%d", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 12345);
}
static void TC_rt_sscanf_basic_float(void)
{
const char str[] = "123.45";
float value;
int result = rt_sscanf(str, "%f", &value);
uassert_int_equal(result, 1);
uassert_float_equal(value, 123.45);
}
static void TC_rt_sscanf_basic_string(void)
{
const char str[] = "Hello, World!";
char buffer[20];
int result = rt_sscanf(str, "%s", buffer);
uassert_int_equal(result, 1);
uassert_str_equal(buffer, "Hello,");
}
static void TC_rt_sscanf_string_with_space(void)
{
const char str[] = "Hello World";
char a[20];
rt_sscanf(str, "%*s %s", a);
uassert_str_equal(a, "World");
}
static void TC_rt_sscanf_basic_char(void)
{
const char str[] = "A";
char value;
int result = rt_sscanf(str, "%c", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 'A');
}
static void TC_rt_sscanf_hex_1(void)
{
const char str[] = "0x1A3F";
int value;
int result = rt_sscanf(str, "%x", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 0x1A3F);
}
static void TC_rt_sscanf_hex_2(void)
{
const char str[] = "0x1A 0XFF";
int a, b;
rt_sscanf(str, "%x %x", &a, &b);
uassert_true(a == 0x1A && b == 0XFF);
}
static void TC_rt_sscanf_oct_1(void)
{
const char str[] = "0755";
int value;
int result = rt_sscanf(str, "%o", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 0755);
}
static void TC_rt_sscanf_oct_2(void)
{
const char str[] = "012 077";
int a, b;
rt_sscanf(str, "%o %o", &a, &b);
uassert_true(a == 012 && b == 077);
}
static void TC_rt_sscanf_multiple_args(void)
{
const char str[] = "123 Hello";
int int_value;
char str_value[20];
int result = rt_sscanf(str, "%d %s", &int_value, str_value);
uassert_int_equal(result, 2);
uassert_int_equal(int_value, 123);
uassert_str_equal(str_value, "Hello");
}
static void TC_rt_sscanf_pointer(void)
{
const char str[] = "0x12345678";
void *ptr;
int result = rt_sscanf(str, "%p", &ptr);
uassert_int_equal(result, 1);
uassert_ptr_equal(ptr, (void *)0x12345678);
}
static void TC_rt_sscanf_width_specifier(void)
{
const char str[] = "123456789";
int value;
int result = rt_sscanf(str, "%4d", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 1234);
}
static void TC_rt_sscanf_suppression(void)
{
const char str[] = "123 456";
int second_value;
int result = rt_sscanf(str, "%*d %d", &second_value);
uassert_int_equal(result, 1);
uassert_int_equal(second_value, 456);
}
static void TC_rt_sscanf_match_set(void)
{
const char str[] = "abc123";
char buffer[10] = {0};
int result = rt_sscanf(str, "%[a-z]", buffer);
uassert_int_equal(result, 1);
uassert_str_equal(buffer, "abc");
}
static void TC_rt_sscanf_match_set_negated(void)
{
const char str[] = "abc123";
char buffer[10];
int result = rt_sscanf(str, "%[^0-9]", buffer);
uassert_int_equal(result, 1);
uassert_str_equal(buffer, "abc");
}
static void TC_rt_sscanf_match_set_range(void)
{
const char str[] = "a-zA-Z";
char buffer[10];
int result = rt_sscanf(str, "%[a-z-A-Z]", buffer);
uassert_int_equal(result, 1);
uassert_str_equal(buffer, "a-zA-Z");
}
static void TC_rt_sscanf_whitespace_skip(void)
{
const char str[] = " 12345";
int value;
int result = rt_sscanf(str, "%d", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 12345);
}
static void TC_rt_sscanf_unsigned_int(void)
{
const char str[] = "4294967295";
unsigned int value;
int result = rt_sscanf(str, "%u", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 4294967295U);
}
static void TC_rt_sscanf_long_long_int(void)
{
const char str[] = "9223372036854775807";
long long value;
int result = rt_sscanf(str, "%lld", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 9223372036854775807LL);
}
static void TC_rt_sscanf_short_int(void)
{
const char str[] = "32767";
short value;
int result = rt_sscanf(str, "%hd", &value);
uassert_int_equal(result, 1);
uassert_int_equal(value, 32767);
}
static void TC_rt_sscanf_null_string(void)
{
const char str[] = "";
int value;
int result = rt_sscanf(str, "%d", &value);
uassert_int_equal(result, -1);
}
/* https://github.com/RT-Thread/rt-thread/issues/9853 */
static void TC_rt_sscanf_issue_9853(void)
{
int device_socket = 255;
int bfsz = 255;
const char str[] = "+MIPURC: \"rtcp\",0,240,HTTP/1.1 200 OK";
rt_sscanf(str, "+MIPURC:%*[^,],%d,%d", &device_socket, (int *)&bfsz);
uassert_int_equal(device_socket, 0);
uassert_int_equal(bfsz, 240);
}
static void utest_do_tc(void)
{
UTEST_UNIT_RUN(TC_rt_sscanf_char);
UTEST_UNIT_RUN(TC_rt_sscanf_basic_int);
UTEST_UNIT_RUN(TC_rt_sscanf_basic_float);
UTEST_UNIT_RUN(TC_rt_sscanf_basic_string);
UTEST_UNIT_RUN(TC_rt_sscanf_string_with_space);
UTEST_UNIT_RUN(TC_rt_sscanf_basic_char);
UTEST_UNIT_RUN(TC_rt_sscanf_hex_1);
UTEST_UNIT_RUN(TC_rt_sscanf_hex_2);
UTEST_UNIT_RUN(TC_rt_sscanf_oct_1);
UTEST_UNIT_RUN(TC_rt_sscanf_oct_2);
UTEST_UNIT_RUN(TC_rt_sscanf_multiple_args);
UTEST_UNIT_RUN(TC_rt_sscanf_pointer);
UTEST_UNIT_RUN(TC_rt_sscanf_width_specifier);
UTEST_UNIT_RUN(TC_rt_sscanf_suppression);
UTEST_UNIT_RUN(TC_rt_sscanf_match_set);
UTEST_UNIT_RUN(TC_rt_sscanf_match_set_negated);
UTEST_UNIT_RUN(TC_rt_sscanf_match_set_range);
UTEST_UNIT_RUN(TC_rt_sscanf_whitespace_skip);
UTEST_UNIT_RUN(TC_rt_sscanf_unsigned_int);
UTEST_UNIT_RUN(TC_rt_sscanf_long_long_int);
UTEST_UNIT_RUN(TC_rt_sscanf_short_int);
UTEST_UNIT_RUN(TC_rt_sscanf_null_string);
UTEST_UNIT_RUN(TC_rt_sscanf_issue_9853);
}
UTEST_TC_EXPORT(utest_do_tc, "klibc.rt_sscanf", RT_NULL, RT_NULL, 1000);