Browse Source

[klibc] add rt_sscanf

cherry-pick from: https://github.com/PetteriAimonen/Baselibc/blob/master/src/vsscanf.c

BSD license
Meco Man 7 months ago
parent
commit
8b4d1c0c5d

+ 1 - 0
include/klibc/kerrno.h

@@ -12,6 +12,7 @@
 #define __RT_KERRNO_H__
 #define __RT_KERRNO_H__
 
 
 #include <rtconfig.h>
 #include <rtconfig.h>
+#include <rttypes.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {

+ 5 - 0
include/klibc/kstdio.h

@@ -11,6 +11,9 @@
 #ifndef __RT_KSTDIO_H__
 #ifndef __RT_KSTDIO_H__
 #define __RT_KSTDIO_H__
 #define __RT_KSTDIO_H__
 
 
+#include <rttypes.h>
+#include <stdarg.h>
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
@@ -19,6 +22,8 @@ int rt_vsprintf(char *dest, const char *format, va_list arg_ptr);
 int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args);
 int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args);
 int rt_sprintf(char *buf, const char *format, ...);
 int rt_sprintf(char *buf, const char *format, ...);
 int rt_snprintf(char *buf, rt_size_t size, const char *format, ...);
 int rt_snprintf(char *buf, rt_size_t size, const char *format, ...);
+int rt_vsscanf(const char *buffer, const char *format, va_list ap);
+int rt_sscanf(const char *str, const char *format, ...);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 3 - 0
include/klibc/kstring.h

@@ -11,6 +11,8 @@
 #ifndef __RT_KSTRING_H__
 #ifndef __RT_KSTRING_H__
 #define __RT_KSTRING_H__
 #define __RT_KSTRING_H__
 
 
+#include <rttypes.h>
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
@@ -19,6 +21,7 @@ void *rt_memset(void *src, int c, rt_ubase_t n);
 void *rt_memcpy(void *dest, const void *src, rt_ubase_t n);
 void *rt_memcpy(void *dest, const void *src, rt_ubase_t n);
 void *rt_memmove(void *dest, const void *src, rt_size_t n);
 void *rt_memmove(void *dest, const void *src, rt_size_t n);
 rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_size_t count);
 rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_size_t count);
+
 char *rt_strdup(const char *s);
 char *rt_strdup(const char *s);
 rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen);
 rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen);
 char *rt_strstr(const char *str1, const char *str2);
 char *rt_strstr(const char *str1, const char *str2);

+ 5 - 1
src/SConscript

@@ -2,7 +2,6 @@ from building import *
 import os
 import os
 
 
 src = Glob('*.c')
 src = Glob('*.c')
-src += Glob('klibc/*.c')
 cwd = GetCurrentDir()
 cwd = GetCurrentDir()
 inc = [os.path.join(cwd, '..', 'include')]
 inc = [os.path.join(cwd, '..', 'include')]
 
 
@@ -49,4 +48,9 @@ group = DefineGroup('Kernel', src, depend=[''], CPPPATH=inc,
                     LINKFLAGS=LINKFLAGS, LOCAL_CFLAGS=LOCAL_CFLAGS,
                     LINKFLAGS=LINKFLAGS, LOCAL_CFLAGS=LOCAL_CFLAGS,
                     CPPDEFINES=['__RTTHREAD__'], LOCAL_CPPDEFINES=['__RT_KERNEL_SOURCE__'])
                     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')
 Return('group')

+ 14 - 0
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')

+ 22 - 0
src/klibc/kstdio.c

@@ -72,3 +72,25 @@ int rt_sprintf(char *buf, const char *format, ...)
     return n;
     return n;
 }
 }
 RTM_EXPORT(rt_sprintf);
 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);

+ 1 - 1
src/klibc/rt_vsnprintf_std.c

@@ -6,7 +6,7 @@
  * Change Logs:
  * Change Logs:
  * Date           Author       Notes
  * Date           Author       Notes
  * 2021-11-27     Meco Man     porting for rt_vsnprintf as the fully functional version
  * 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
  */
  */
 
 
 /**
 /**

+ 502 - 0
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;
+}