summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMeco Man <[email protected]>2024-11-24 00:57:32 -0500
committerRbb666 <[email protected]>2024-11-25 09:49:23 +0800
commit8b4d1c0c5d26beb55fd25b53489dcfe74e8aa6d6 (patch)
tree0c0b3207bf90a5e2000634b75373fd1cb2d4d450 /src
parentb7520e262b6b07e72bd18f4280156e324edac11b (diff)
[klibc] add rt_sscanf
cherry-pick from: https://github.com/PetteriAimonen/Baselibc/blob/master/src/vsscanf.c BSD license
Diffstat (limited to 'src')
-rw-r--r--src/SConscript6
-rw-r--r--src/klibc/SConscript14
-rw-r--r--src/klibc/kstdio.c22
-rw-r--r--src/klibc/rt_vsnprintf_std.c2
-rw-r--r--src/klibc/rt_vsscanf.c502
5 files changed, 544 insertions, 2 deletions
diff --git a/src/SConscript b/src/SConscript
index 08a7d81e78..8407e6ef18 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -2,7 +2,6 @@ from building import *
import os
src = Glob('*.c')
-src += Glob('klibc/*.c')
cwd = GetCurrentDir()
inc = [os.path.join(cwd, '..', 'include')]
@@ -49,4 +48,9 @@ group = DefineGroup('Kernel', src, depend=[''], CPPPATH=inc,
LINKFLAGS=LINKFLAGS, LOCAL_CFLAGS=LOCAL_CFLAGS,
CPPDEFINES=['__RTTHREAD__'], LOCAL_CPPDEFINES=['__RT_KERNEL_SOURCE__'])
+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')
diff --git a/src/klibc/SConscript b/src/klibc/SConscript
new file mode 100644
index 0000000000..4a17403c20
--- /dev/null
+++ b/src/klibc/SConscript
@@ -0,0 +1,14 @@
+from building import *
+import os
+
+cwd = GetCurrentDir()
+src = Glob('*.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')
diff --git a/src/klibc/kstdio.c b/src/klibc/kstdio.c
index 0da07ec0bc..ceb891f325 100644
--- a/src/klibc/kstdio.c
+++ b/src/klibc/kstdio.c
@@ -72,3 +72,25 @@ int rt_sprintf(char *buf, const char *format, ...)
return n;
}
RTM_EXPORT(rt_sprintf);
+
+/**
+ * @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);
diff --git a/src/klibc/rt_vsnprintf_std.c b/src/klibc/rt_vsnprintf_std.c
index 3d919d522e..520061d277 100644
--- a/src/klibc/rt_vsnprintf_std.c
+++ b/src/klibc/rt_vsnprintf_std.c
@@ -6,7 +6,7 @@
* Change Logs:
* Date Author Notes
* 2021-11-27 Meco Man porting for rt_vsnprintf as the fully functional version
- * 2024-11-19 Meco Man move into rtklibc
+ * 2024-11-19 Meco Man move to klibc
*/
/**
diff --git a/src/klibc/rt_vsscanf.c b/src/klibc/rt_vsscanf.c
new file mode 100644
index 0000000000..25c25c20a1
--- /dev/null
+++ b/src/klibc/rt_vsscanf.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-11-24 Meco Man port to klibc
+ */
+
+#include <rtklibc.h>
+
+/*
+ * Copyright (c) 2012 Petteri Aimonen <jpa at blc.mail.kapsi.fi>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Kustaa Nyholm or SpareTimeLabs nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h> /* for isspace */
+#include <stdarg.h>
+#include <limits.h> /* for CHAR_BIT */
+
+static inline int digitval(int ch)
+{
+ if (ch >= '0' && ch <= '9') {
+ return ch - '0';
+ } else if (ch >= 'A' && ch <= 'Z') {
+ return ch - 'A' + 10;
+ } else if (ch >= 'a' && ch <= 'z') {
+ return ch - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
+
+static rt_size_t _strntoumax(const char *nptr, char **endptr, int base, rt_size_t n)
+{
+ int minus = 0;
+ rt_size_t v = 0;
+ int d;
+
+ while (n && isspace((unsigned char)*nptr)) {
+ nptr++;
+ n--;
+ }
+
+ /* Single optional + or - */
+ if (n) {
+ char c = *nptr;
+ if (c == '-' || c == '+') {
+ minus = (c == '-');
+ nptr++;
+ n--;
+ }
+ }
+
+ if (base == 0) {
+ if (n >= 2 && nptr[0] == '0' &&
+ (nptr[1] == 'x' || nptr[1] == 'X')) {
+ n -= 2;
+ nptr += 2;
+ base = 16;
+ } else if (n >= 1 && nptr[0] == '0') {
+ n--;
+ nptr++;
+ base = 8;
+ } else {
+ base = 10;
+ }
+ } else if (base == 16) {
+ if (n >= 2 && nptr[0] == '0' &&
+ (nptr[1] == 'x' || nptr[1] == 'X')) {
+ n -= 2;
+ nptr += 2;
+ }
+ }
+
+ while (n && (d = digitval(*nptr)) >= 0 && d < base) {
+ v = v * base + d;
+ n--;
+ nptr++;
+ }
+
+ if (endptr)
+ *endptr = (char *)nptr;
+
+ return minus ? -v : v;
+}
+
+#ifndef LONG_BIT
+#define LONG_BIT (CHAR_BIT*sizeof(long))
+#endif
+
+enum flags {
+ FL_SPLAT = 0x01, /* Drop the value, do not assign */
+ FL_INV = 0x02, /* Character-set with inverse */
+ FL_WIDTH = 0x04, /* Field width specified */
+ FL_MINUS = 0x08, /* Negative number */
+};
+
+enum ranks {
+ rank_char = -2,
+ rank_short = -1,
+ rank_int = 0,
+ rank_long = 1,
+ rank_longlong = 2,
+ rank_ptr = INT_MAX /* Special value used for pointers */
+};
+
+#define MIN_RANK rank_char
+#define MAX_RANK rank_longlong
+
+#define INTMAX_RANK rank_longlong
+#define SIZE_T_RANK rank_long
+#define PTRDIFF_T_RANK rank_long
+
+enum bail {
+ bail_none = 0, /* No error condition */
+ bail_eof, /* Hit EOF */
+ bail_err /* Conversion mismatch */
+};
+
+static inline const char *skipspace(const char *p)
+{
+ while (isspace((unsigned char)*p))
+ p++;
+ return p;
+}
+
+static inline void _set_bit(unsigned long *bitmap, unsigned int bit)
+{
+ bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
+}
+
+static inline int _test_bit(unsigned long *bitmap, unsigned int bit)
+{
+ return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1;
+}
+
+int rt_vsscanf(const char *buffer, const char *format, va_list ap)
+{
+ const char *p = format;
+ char ch;
+ unsigned char uc;
+ const char *q = buffer;
+ const char *qq;
+ rt_size_t val = 0;
+ int rank = rank_int; /* Default rank */
+ unsigned int width = UINT_MAX;
+ int base;
+ enum flags flags = 0;
+ enum {
+ st_normal, /* Ground state */
+ st_flags, /* Special flags */
+ st_width, /* Field width */
+ st_modifiers, /* Length or conversion modifiers */
+ st_match_init, /* Initial state of %[ sequence */
+ st_match, /* Main state of %[ sequence */
+ st_match_range, /* After - in a %[ sequence */
+ } state = st_normal;
+ char *sarg = NULL; /* %s %c or %[ string argument */
+ enum bail bail = bail_none;
+ int sign;
+ int converted = 0; /* Successful conversions */
+ unsigned long matchmap[((1 << CHAR_BIT) + (LONG_BIT - 1)) / LONG_BIT];
+ int matchinv = 0; /* Is match map inverted? */
+ unsigned char range_start = 0;
+ (void)sign;
+
+ while ((ch = *p++) && !bail) {
+ switch (state) {
+ case st_normal:
+ if (ch == '%') {
+ state = st_flags;
+ flags = 0;
+ rank = rank_int;
+ width = UINT_MAX;
+ } else if (isspace((unsigned char)ch)) {
+ q = skipspace(q);
+ } else {
+ if (*q == ch)
+ q++;
+ else
+ bail = bail_err; /* Match failure */
+ }
+ break;
+
+ case st_flags:
+ switch (ch) {
+ case '*':
+ flags |= FL_SPLAT;
+ break;
+ case '0': /* falls-through */
+ case '1': /* falls-through */
+ case '2': /* falls-through */
+ case '3': /* falls-through */
+ case '4': /* falls-through */
+ case '5': /* falls-through */
+ case '6': /* falls-through */
+ case '7': /* falls-through */
+ case '8': /* falls-through */
+ case '9':
+ width = (ch - '0');
+ state = st_width;
+ flags |= FL_WIDTH;
+ break;
+ default:
+ state = st_modifiers;
+ p--; /* Process this character again */
+ break;
+ }
+ break;
+
+ case st_width:
+ if (ch >= '0' && ch <= '9') {
+ width = width * 10 + (ch - '0');
+ } else {
+ state = st_modifiers;
+ p--; /* Process this character again */
+ }
+ break;
+
+ case st_modifiers:
+ switch (ch) {
+ /* Length modifiers - nonterminal sequences */
+ case 'h':
+ rank--; /* Shorter rank */
+ break;
+ case 'l':
+ rank++; /* Longer rank */
+ break;
+ case 'j':
+ rank = INTMAX_RANK;
+ break;
+ case 'z':
+ rank = SIZE_T_RANK;
+ break;
+ case 't':
+ rank = PTRDIFF_T_RANK;
+ break;
+ case 'L':
+ case 'q':
+ rank = rank_longlong; /* long double/long long */
+ break;
+
+ default:
+ /* Output modifiers - terminal sequences */
+ /* Next state will be normal */
+ state = st_normal;
+
+ /* Canonicalize rank */
+ if (rank < MIN_RANK)
+ rank = MIN_RANK;
+ else if (rank > MAX_RANK)
+ rank = MAX_RANK;
+
+ switch (ch) {
+ case 'P': /* Upper case pointer */
+ case 'p': /* Pointer */
+ rank = rank_ptr;
+ base = 0;
+ sign = 0;
+ goto scan_int;
+
+ case 'i': /* Base-independent integer */
+ base = 0;
+ sign = 1;
+ goto scan_int;
+
+ case 'd': /* Decimal integer */
+ base = 10;
+ sign = 1;
+ goto scan_int;
+
+ case 'o': /* Octal integer */
+ base = 8;
+ sign = 0;
+ goto scan_int;
+
+ case 'u': /* Unsigned decimal integer */
+ base = 10;
+ sign = 0;
+ goto scan_int;
+
+ case 'x': /* Hexadecimal integer */
+ case 'X':
+ base = 16;
+ sign = 0;
+ goto scan_int;
+
+ case 'n': /* # of characters consumed */
+ val = (q - buffer);
+ goto set_integer;
+
+ scan_int:
+ q = skipspace(q);
+ if (!*q) {
+ bail = bail_eof;
+ break;
+ }
+ val =
+ _strntoumax(q, (char **)&qq, base,
+ width);
+ if (qq == q) {
+ bail = bail_err;
+ break;
+ }
+ q = qq;
+ if (!(flags & FL_SPLAT))
+ converted++;
+ /* fall through */
+
+ set_integer:
+ if (!(flags & FL_SPLAT)) {
+ switch (rank) {
+ case rank_char:
+ *va_arg(ap,
+ unsigned char *)
+ = val;
+ break;
+ case rank_short:
+ *va_arg(ap,
+ unsigned short
+ *) = val;
+ break;
+ case rank_int:
+ *va_arg(ap,
+ unsigned int *)
+ = val;
+ break;
+ case rank_long:
+ *va_arg(ap,
+ unsigned long *)
+ = val;
+ break;
+ case rank_longlong:
+ *va_arg(ap,
+ unsigned long
+ long *) = val;
+ break;
+ case rank_ptr:
+ *va_arg(ap, void **) =
+ (void *)
+ (uintptr_t)val;
+ break;
+ }
+ }
+ break;
+
+ case 'c': /* Character */
+ /* Default width == 1 */
+ width = (flags & FL_WIDTH) ? width : 1;
+ if (flags & FL_SPLAT) {
+ while (width--) {
+ if (!*q) {
+ bail = bail_eof;
+ break;
+ }
+ }
+ } else {
+ sarg = va_arg(ap, char *);
+ while (width--) {
+ if (!*q) {
+ bail = bail_eof;
+ break;
+ }
+ *sarg++ = *q++;
+ }
+ if (!bail)
+ converted++;
+ }
+ break;
+
+ case 's': /* String */
+ uc = 1; /* Anything nonzero */
+ if (flags & FL_SPLAT) {
+ while (width-- && (uc = *q) &&
+ !isspace(uc)) {
+ q++;
+ }
+ } else {
+ char *sp;
+ sp = sarg = va_arg(ap, char *);
+ while (width-- && (uc = *q) &&
+ !isspace(uc)) {
+ *sp++ = uc;
+ q++;
+ }
+ if (sarg != sp) {
+ /* Terminate output */
+ *sp = '\0';
+ converted++;
+ }
+ }
+ if (!uc)
+ bail = bail_eof;
+ break;
+
+ case '[': /* Character range */
+ sarg = (flags & FL_SPLAT) ? NULL
+ : va_arg(ap, char *);
+ state = st_match_init;
+ matchinv = 0;
+ rt_memset(matchmap, 0, sizeof matchmap);
+ break;
+
+ case '%': /* %% sequence */
+ if (*q == '%')
+ q++;
+ else
+ bail = bail_err;
+ break;
+
+ default: /* Anything else */
+ /* Unknown sequence */
+ bail = bail_err;
+ break;
+ }
+ }
+ break;
+
+ case st_match_init: /* Initial state for %[ match */
+ if (ch == '^' && !(flags & FL_INV)) {
+ matchinv = 1;
+ } else {
+ _set_bit(matchmap, (unsigned char)ch);
+ state = st_match;
+ }
+ break;
+
+ case st_match: /* Main state for %[ match */
+ if (ch == ']') {
+ goto match_run;
+ } else if (ch == '-') {
+ range_start = (unsigned char)ch;
+ state = st_match_range;
+ } else {
+ _set_bit(matchmap, (unsigned char)ch);
+ }
+ break;
+
+ case st_match_range: /* %[ match after - */
+ if (ch == ']') {
+ /* - was last character */
+ _set_bit(matchmap, (unsigned char)'-');
+ goto match_run;
+ } else {
+ int i;
+ for (i = range_start; i < (unsigned char)ch;
+ i++)
+ _set_bit(matchmap, i);
+ state = st_match;
+ }
+ break;
+
+ match_run: /* Match expression finished */
+ qq = q;
+ uc = 1; /* Anything nonzero */
+ while (width && (uc = *q)
+ && _test_bit(matchmap, uc)^matchinv) {
+ if (sarg)
+ *sarg++ = uc;
+ q++;
+ }
+ if (q != qq && sarg) {
+ *sarg = '\0';
+ converted++;
+ } else {
+ bail = bail_err;
+ }
+ if (!uc)
+ bail = bail_eof;
+ break;
+ }
+ }
+
+ if (bail == bail_eof && !converted)
+ converted = -1; /* Return EOF (-1) */
+
+ return converted;
+}