From 71876ae098f75b40924f78bf8fbea927fb04d471 Mon Sep 17 00:00:00 2001 From: likun17 Date: Tue, 2 Jan 2024 10:19:33 +0800 Subject: [PATCH] lib_libvscanf.c:Add buffer data type conversion interface. Signed-off-by: likun17 --- include/nuttx/streams.h | 13 ++++ libs/libc/stdio/README.md | 68 +++++++++++++++++-- libs/libc/stdio/lib_libvscanf.c | 115 +++++++++++++++++++++++++------- 3 files changed, 169 insertions(+), 27 deletions(-) diff --git a/include/nuttx/streams.h b/include/nuttx/streams.h index b8fb4ce787..ff6c37ade3 100644 --- a/include/nuttx/streams.h +++ b/include/nuttx/streams.h @@ -746,6 +746,19 @@ int lib_vsprintf(FAR struct lib_outstream_s *stream, int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, FAR const IPTR char *src, va_list ap) scanf_like(3, 0); +/**************************************************************************** + * Name: lib_bscanf + * + * Description: + * Convert data into a structure according to standard formatting protocols. + * For string arrays, please use "%{length}s" or "%{length}c" to specify + * the length. + * + ****************************************************************************/ + +int lib_bscanf(FAR struct lib_instream_s *stream, FAR int *lastc, + FAR const IPTR char *fmt, FAR void *data); + #undef EXTERN #if defined(__cplusplus) } diff --git a/libs/libc/stdio/README.md b/libs/libc/stdio/README.md index 41fbbfbdb3..887c77ca62 100644 --- a/libs/libc/stdio/README.md +++ b/libs/libc/stdio/README.md @@ -1,11 +1,11 @@ -# lib_libbsprintf - This function is mainly used to output the contents of the input structure. Most standards follow the standards of printf and scanf. +# lib_bsprintf + This function is mainly used to output the contents of the input structure. Supports standard formats for printf and scanf. For detailed parameters, see: 1. https://en.cppreference.com/w/c/io/fprintf 2. https://en.cppreference.com/w/c/io/fscanf - **special**: - 1. Float use %hf, and double for all others. + 1. Float use %hf, "%f" or "%lf" is double, "%Lf" is long double. 2. The char array is specified with %.xs. for example: "char t[30]" is specified with "%.30s", char a [20] - " %.20s " 3. "%u" is unsigned int. 4. "%d" is int. @@ -92,4 +92,64 @@ lib_stream_flush(&outstream.common); #endif - ~~~ \ No newline at end of file + ~~~ + +# lib_bscanf + This function adds a formatted standard scanf string to the structure(lib_bscanf). + 1. https://zh.cppreference.com/w/c/io/fscanf + +- **special**: + 1. Please use %lf for double precision, "%hf" or "%f" for float, long double ("%Lf") is not supported. + 2. Please use %hhd or %hhu for a single char or unsigned char. + 3. Use %hd or %hu for short int or unsigned short int. + 4. When using %s or %c, please specify the length of the char array, such as %32s, %32c. + 5. %s will check the string for spaces. When there are spaces in the string, it will be truncated. If you want to use string with spaces, please use %{length}c, but make sure that the length of the string can fill the array, otherwise an error will occur. + 6. %[] collection and %n are not supported. + +- **demo** + 1. **struct**: + Same as above + 1. **format string**: + ~~~ + #define TOSTR(str) #str + #define TONNAME(name) TOSTR(name) + + #define v_uint8_t 97 + #define v_uint16_t 19299 + #define v_uint32_t 22155 + + ...... + + #define v_l_double -9299.9299929912122464755474 + + char bflag[] = "%hhu%hu%u%hhd%hd%d%f%lf%32s%llu%lld%hhd%hhu%hd%hu%d%u%ld%lu%lld%llu%zu%ld"; + + char binput[] = TONNAME(v_uint8_t) \ + " " TONNAME(v_uint16_t) \ + " " TONNAME(v_uint32_t) \ + " " TONNAME(v_int8_t) \ + " " TONNAME(v_int16_t) \ + " " TONNAME(v_int32_t) \ + " " TONNAME(v_float) \ + " " TONNAME(v_double) \ + " " TONNAME(v_char_arr) \ + " " TONNAME(v_uint64_t) \ + " " TONNAME(v_int64_t) \ + " " TONNAME(v_char) \ + " " TONNAME(v_u_char) \ + " " TONNAME(v_s_int) \ + " " TONNAME(v_u_s_int) \ + " " TONNAME(v_int) \ + " " TONNAME(v_u_int) \ + " " TONNAME(v_long) \ + " " TONNAME(v_u_long) \ + " " TONNAME(v_l_l) \ + " " TONNAME(v_u_l_l) \ + " " TONNAME(v_size_t) \ + " " TONNAME(v_l_double); + ~~~ + 3. **use**: + ~~~ + struct test vg; + ret = lib_bscanf(binput, bflag, &vg); + ~~~ \ No newline at end of file diff --git a/libs/libc/stdio/lib_libvscanf.c b/libs/libc/stdio/lib_libvscanf.c index 755f1c3c82..8c6517999b 100644 --- a/libs/libc/stdio/lib_libvscanf.c +++ b/libs/libc/stdio/lib_libvscanf.c @@ -66,6 +66,29 @@ # define fmt_char(fmt) (*(fmt)) #endif +#define buf_arg(buf, type) \ + ((buf) = (FAR char *)(buf) + sizeof(*(type)0), \ + (type)((FAR char *)(buf) - sizeof(*(type)0))) + +#define next_arg(varg, vabuf, type) \ + (varg) ? va_arg((vabuf).ap, type) : buf_arg((vabuf).buf, type) + +#define buf_arg_width(buf, type, width) \ + ((buf) = (FAR char *)(buf) + (width), (type)((FAR char *)(buf) - (width))) + +#define next_arg_width(varg, vabuf, type, width) \ + (varg) ? va_arg((vabuf).ap, type) : buf_arg_width((vabuf).buf, type, width) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +union vabuf_u +{ + FAR const void *buf; + va_list ap; +}; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -190,20 +213,17 @@ doexit: #endif /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: lib_vscanf + * Name: vscanf_internal * * Description: * Stream-oriented implementation that underlies scanf family: scanf, - * fscanf, vfscanf, sscanf, and vsscanf + * fscanf, vfscanf, sscanf, vsscanf and bscanf. * ****************************************************************************/ -int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, - FAR const IPTR char *fmt, va_list ap) +static int vscanf_internal(FAR struct lib_instream_s *stream, FAR int *lastc, + FAR const IPTR char *fmt, bool varg, + union vabuf_u vabuf) { int c; FAR char *tv; @@ -392,7 +412,7 @@ int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, tv = NULL; /* To avoid warnings about begin uninitialized */ if (!noassign) { - tv = va_arg(ap, FAR char *); + tv = next_arg_width(varg, vabuf, FAR char *, width); tv[0] = '\0'; } @@ -454,7 +474,7 @@ int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, tv = NULL; /* To avoid warnings about begin uninitialized */ if (!noassign) { - tv = va_arg(ap, FAR char *); + tv = next_arg_width(varg, vabuf, FAR char *, width); tv[0] = '\0'; } @@ -513,7 +533,7 @@ int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, tv = NULL; /* To avoid warnings about being uninitialized */ if (!noassign) { - tv = va_arg(ap, FAR char *); + tv = next_arg_width(varg, vabuf, FAR char *, width); tv[0] = '\0'; } @@ -583,29 +603,30 @@ int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, switch (modifier) { case HH_MOD: - pchar = va_arg(ap, FAR unsigned char *); + pchar = next_arg(varg, vabuf, FAR unsigned char *); *pchar = 0; break; case H_MOD: - pshort = va_arg(ap, FAR unsigned short *); + pshort = next_arg(varg, vabuf, FAR unsigned short *); *pshort = 0; break; case NO_MOD: - pint = va_arg(ap, FAR unsigned int *); + pint = next_arg(varg, vabuf, FAR unsigned int *); *pint = 0; break; default: case L_MOD: - plong = va_arg(ap, FAR unsigned long *); + plong = next_arg(varg, vabuf, FAR unsigned long *); *plong = 0; break; #ifdef CONFIG_HAVE_LONG_LONG case LL_MOD: - plonglong = va_arg(ap, FAR unsigned long long *); + plonglong = next_arg(varg, vabuf, + FAR unsigned long long *); *plonglong = 0; break; #endif @@ -975,14 +996,14 @@ int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, #ifdef CONFIG_HAVE_DOUBLE if (modifier >= L_MOD) { - pd = va_arg(ap, FAR double *); + pd = next_arg(varg, vabuf, FAR double *); *pd = 0.0; } else #endif #ifdef CONFIG_HAVE_FLOAT { - pf = va_arg(ap, FAR float *); + pf = next_arg(varg, vabuf, FAR float *); *pf = 0.0; } #endif @@ -1178,29 +1199,30 @@ int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, switch (modifier) { case HH_MOD: - pchar = va_arg(ap, FAR unsigned char *); + pchar = next_arg(varg, vabuf, FAR unsigned char *); *pchar = (unsigned char)nchars; break; case H_MOD: - pshort = va_arg(ap, FAR unsigned short *); + pshort = next_arg(varg, vabuf, FAR unsigned short *); *pshort = (unsigned short)nchars; break; case NO_MOD: - pint = va_arg(ap, FAR unsigned int *); + pint = next_arg(varg, vabuf, FAR unsigned int *); *pint = (unsigned int)nchars; break; default: case L_MOD: - plong = va_arg(ap, FAR unsigned long *); + plong = next_arg(varg, vabuf, FAR unsigned long *); *plong = (unsigned long)nchars; break; #ifdef CONFIG_HAVE_LONG_LONG case LL_MOD: - plonglong = va_arg(ap, FAR unsigned long long *); + plonglong = next_arg(varg, vabuf, + FAR unsigned long long *); *plonglong = (unsigned long long)nchars; break; #endif @@ -1268,3 +1290,50 @@ int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, *lastc = c; return (count || !conv) ? assigncount : EOF; } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_vscanf + * + * Description: + * Stream-oriented implementation that underlies scanf family: scanf, + * fscanf, vfscanf, sscanf, and vsscanf + * + ****************************************************************************/ + +int lib_vscanf(FAR struct lib_instream_s *stream, FAR int *lastc, + FAR const IPTR char *fmt, va_list ap) +{ + union vabuf_u vabuf; + int ret; + + va_copy(vabuf.ap, ap); + ret = vscanf_internal(stream, lastc, fmt, true, vabuf); + va_end(vabuf.ap); + + return ret; +} + +/**************************************************************************** + * Name: lib_bscanf + * + * Description: + * Convert data into a structure according to standard formatting protocols. + * For string arrays, please use "%{length}s" or "%{length}c" to specify + * the length. + * + ****************************************************************************/ + +int lib_bscanf(FAR struct lib_instream_s *stream, FAR int *lastc, + FAR const IPTR char *fmt, FAR void *data) +{ + union vabuf_u vabuf = + { + data + }; + + return vscanf_internal(stream, lastc, fmt, false, vabuf); +}