git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@16241 27425a3e-05d8-49a3-a47f-9c15f0e5edd8

This commit is contained in:
Giovanni Di Sirio 2023-04-28 14:25:12 +00:00
parent 298b40a1a6
commit 831d2840df
8 changed files with 1316 additions and 7 deletions

View File

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE doc [
<!ENTITY memstreams SYSTEM "memstreams.xml">
<!ENTITY oop_base_interface SYSTEM "oop_base_interface.xml">
<!ENTITY oop_referenced_object SYSTEM "oop_referenced_object.xml">
<!ENTITY oop_synchronized_object SYSTEM "oop_synchronized_object.xml">
<!ENTITY oop_sequential_stream SYSTEM "oop_sequential_stream.xml">
<!ENTITY nullstreams SYSTEM "nullstreams.xml">
]>
<!-- Class/interfaces definitions -->
<instance
@ -15,5 +12,6 @@
</paths>
<modules>
&memstreams;
&nullstreams;
</modules>
</instance>

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.chibios.org/xml/schema/ccode/modules.xsd"
name="nullstreams" descr="Null Streams" editcode="false">
<brief>Null streams class.</brief>
<imports>
<import>oop_base_object.xml</import>
<import>oop_sequential_stream.xml</import>
</imports>
<public>
<includes>
<include style="angular">string.h</include>
<include style="regular">oop_base_object.h</include>
<include style="regular">oop_sequential_stream.h</include>
</includes>
<types>
<class type="regular" name="null_stream"
namespace="nullstm" ancestorname="base_object"
descr="null stream">
<brief>Null streams class.</brief>
<details><![CDATA[This class implements a null stream.]]></details>
<implements>
<if name="sequential_stream">
<method shortname="write">
<implementation><![CDATA[
(void)self;
(void)bp;
return n;]]></implementation>
</method>
<method shortname="read">
<implementation><![CDATA[
(void)self;
(void)bp;
return n;]]></implementation>
</method>
<method shortname="put">
<implementation><![CDATA[
(void)self;
(void)b;
return STM_OK;]]></implementation>
</method>
<method shortname="get">
<implementation><![CDATA[
(void)self;
return 4;]]></implementation>
</method>
<method shortname="unget">
<implementation><![CDATA[
(void)self;
(void)b;
return STM_RESET;]]></implementation>
</method>
</if>
</implements>
<fields>
</fields>
<methods>
<objinit callsuper="true">
<implementation><![CDATA[ ]]></implementation>
</objinit>
<dispose>
<implementation><![CDATA[ ]]></implementation>
</dispose>
</methods>
</class>
</types>
</public>
<private>
</private>
</module>

View File

@ -39,8 +39,8 @@
#ifdef __cplusplus
extern "C" {
#endif
int chvprintf(sequential_stream_i *chp, const char *fmt, va_list ap);
int chprintf(sequential_stream_i *chp, const char *fmt, ...);
int chvprintf(sequential_stream_i *stmp, const char *fmt, va_list ap);
int chprintf(sequential_stream_i *stmp, const char *fmt, ...);
int chsnprintf(char *str, size_t size, const char *fmt, ...);
int chvsnprintf(char *str, size_t size, const char *fmt, va_list ap);
#ifdef __cplusplus

View File

@ -0,0 +1,58 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file was contributed by Alex Lewontin.
*/
/**
* @file chscanf.h
* @brief Mini scanf-like functionality.
*
* @addtogroup HAL_CHSCANF
* @{
*/
#ifndef CHSCANF_H
#define CHSCANF_H
#include <stdarg.h>
/**
* @brief Float type support.
*/
#if !defined(CHSCANF_USE_FLOAT) || defined(__DOXYGEN__)
#define CHSCANF_USE_FLOAT FALSE
#endif
#if CHSCANF_USE_FLOAT
#include <math.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
int chvscanf(sequential_stream_i *stmp, const char *fmt, va_list ap);
int chscanf(sequential_stream_i *stmp, const char *fmt, ...);
int chsnscanf(char *str, size_t size, const char *fmt, ...);
int chvsnscanf(char *str, size_t size, const char *fmt, va_list ap);
#ifdef __cplusplus
}
#endif
#endif /* CHSCANF_H */
/** @} */

View File

@ -0,0 +1,138 @@
/*
ChibiOS - Copyright (C) 2006..2023 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file nullstreams.h
* @brief Generated Null Streams header.
* @note This is a generated file, do not edit directly.
*
* @addtogroup NULLSTREAMS
* @brief Null streams class.
* @{
*/
#ifndef NULLSTREAMS_H
#define NULLSTREAMS_H
#include <string.h>
#include "oop_base_object.h"
#include "oop_sequential_stream.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/**
* @class null_stream_c
* @extends base_object_c.
* @implements sequential_stream_i
*
* @brief Null streams class.
* @details This class implements a null stream.
*
* @name Class @p null_stream_c structures
* @{
*/
/**
* @brief Type of a null stream class.
*/
typedef struct null_stream null_stream_c;
/**
* @brief Class @p null_stream_c virtual methods table.
*/
struct null_stream_vmt {
/* From base_object_c.*/
void (*dispose)(void *ip);
/* From null_stream_c.*/
};
/**
* @brief Structure representing a null stream class.
*/
struct null_stream {
/**
* @brief Virtual Methods Table.
*/
const struct null_stream_vmt *vmt;
/**
* @brief Implemented interface @p sequential_stream_i.
*/
sequential_stream_i stm;
};
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
/* Methods of null_stream_c.*/
void *__nullstm_objinit_impl(void *ip, const void *vmt);
void __nullstm_dispose_impl(void *ip);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @name Default constructor of null_stream_c
* @{
*/
/**
* @memberof null_stream_c
*
* @brief Default initialization function of @p null_stream_c.
*
* @param[out] self Pointer to a @p null_stream_c instance to be
* initialized.
* @return Pointer to the initialized object.
*
* @objinit
*/
CC_FORCE_INLINE
static inline null_stream_c *nullstmObjectInit(null_stream_c *self) {
extern const struct null_stream_vmt __null_stream_vmt;
return __nullstm_objinit_impl(self, &__null_stream_vmt);
}
/** @} */
#endif /* NULLSTREAMS_H */
/** @} */

View File

@ -1,6 +1,8 @@
# List of the ChibiOS common library modules.
CLIBSRC = ${CHIBIOS}/os/common/lib/src/memstreams.c \
${CHIBIOS}/os/common/lib/src/chprintf.c
${CHIBIOS}/os/common/lib/src/nullstreams.c \
${CHIBIOS}/os/common/lib/src/chprintf.c \
${CHIBIOS}/os/common/lib/src/chscanf.c
CLIBINC = ${CHIBIOS}/os/common/lib/include

795
os/common/lib/src/chscanf.c Normal file
View File

@ -0,0 +1,795 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
This file was contributed by Alex Lewontin.
*/
/**
* @file chscanf.c
* @brief Mini scanf-like functionality.
*
* @addtogroup HAL_CHSCANF
* @details Mini scanf-like functionality.
* @{
*/
#include <ctype.h>
#include "hal.h"
#include "chscanf.h"
#include "memstreams.h"
static long sym_to_val(char sym, int base)
{
sym = tolower(sym);
if (sym <= '7' && sym >= '0') {
return sym - '0';
}
switch (base) {
case 16:
if (sym <= 'f' && sym >= 'a') {
return (sym - 'a' + 0xa);
}
/* fallthrough */
case 10:
if (sym == '8') {
return 8;
}
if (sym == '9') {
return 9;
}
/* fallthrough */
default:
return -1;
}
}
#if CHSCANF_USE_FLOAT
/* Custom mixed-type power function. The internal promotion of the result to a double
allows for a greater dynamic range than integral types. This function is mostly for
simplicity, to allow us to do floating point math without either requiring any
libc linkages, or actually having to write floating point algorithms ourselves */
static inline double ch_mpow(double x, unsigned long y)
{
double res = 1;
do {
if (y & 1) {
res *= x;
}
x *= x;
} while (y >>= 1);
return res;
}
#endif
/**
* @brief System formatted input function.
* @details This function implements a minimal @p vscanf()-like functionality
* with input on a @p BaseSequentialStream.
* The general parameters format is: %[*][width][l|L]p
* The following parameter types (p) are supported:
* - <b>x</b> hexadecimal integer.
* - <b>X</b> hexadecimal long.
* - <b>o</b> octal integer.
* - <b>O</b> octal long.
* - <b>d</b> decimal signed integer.
* - <b>D</b> decimal signed long.
* - <b>u</b> decimal unsigned integer.
* - <b>U</b> decimal unsigned long.
* - <b>c</b> character.
* - <b>s</b> string.
* .
*
* @param[in] chp pointer to a @p BufferedStream implementing object
* @param[in] fmt formatting string
* @param[in] ap list of parameters
* @return The number parameters in ap that have been successfully
* filled. This does not conform to the standard in that if
* a failure (either matching or input) occurs before any
* parameters are assigned, the function will return 0.
*
* @api
*/
int chvscanf(sequential_stream_i *stmp, const char *fmt, va_list ap)
{
char f;
int c;
int width, base, i;
int n = 0;
void* buf;
bool is_long, is_signed, is_positive;
long vall, digit;
#if CHSCANF_USE_FLOAT
long exp;
double valf;
char exp_char;
int exp_base;
bool exp_is_positive, initial_digit;
char* match;
int fixed_point;
#endif
/* Peek the first character of the format string. If it is null,
we don't even need to take any input, just return 0 */
f = *fmt++;
if (f == 0) {
return n;
}
/* Otherwise, get the first character from the input stream before we loop for the first time
(no peek function for the stream means an extra character is taken out every iteration of the
loop, so each loop iteration uses the value of c from the last one. However, the first iteration
has no value to work with, so we initialize it here) */
c = stmGet(stmp);
while (c != STM_RESET && f != 0) {
/* There are 3 options for f:
- whitespace (take and discard as much contiguous whitespace as possible)
- a non-whitespace, non-control sequence character (must 1:1 match)
- a %, which indicates the beginning of a control sequence
*/
if (isspace(f)) {
while (isspace(c)) {
c = stmGet(stmp);
}
f = *fmt++;
continue;
}
if (f != '%') {
if (f != c) {
break;
} else {
c = stmGet(stmp);
f = *fmt++;
continue;
}
}
/* So we have a formatting token... probably */
f = *fmt++;
/* Special case: a %% is equivalent to a '%' literal */
if (f == '%') {
if (f != c) {
break;
} else {
c = stmGet(stmp);
f = *fmt++;
continue;
}
}
if (f == '*') {
buf = NULL;
f = *fmt++;
} else {
buf = va_arg(ap, void*);
}
/* Parse the optional width specifier */
width = 0;
while (isdigit(f)) {
width = (width * 10) + (f - '0');
f = *fmt++;
}
if (!width) {
width = -1;
}
/* Parse the optional length specifier */
if (f == 'l' || f == 'L') {
is_long = true;
f = *fmt++;
} else {
is_long = isupper(f);
}
is_positive = true;
is_signed = true;
base = 10;
switch (f) {
case 'c':
/* Not supporting wchar_t, is_long is just ignored */
if (width == 0) {
width = 1;
}
for (i = 0; i < width; ++i) {
if (buf) {
((char*)buf)[i] = c;
}
c = stmGet(stmp);
if (c == STM_RESET) {
return n;
}
}
++n;
f = *fmt++;
continue;
case 's':
/* S specifier discards leading whitespace */
while (isspace(c)) {
c = stmGet(stmp);
if (c == STM_RESET) {
return n;
}
}
/* Not supporting wchar_t, is_long is just ignored */
if (width == 0) {
width = -1;
}
for (i = 0; i < width; ++i) {
if (isspace(c)) {
if (buf) {
((char*)buf)[i] = 0;
}
break;
}
if (buf) {
((char*)buf)[i] = c;
}
c = stmGet(stmp);
if (c == STM_RESET) {
return n;
}
}
if (width != -1) {
if (buf) {
((char*)buf)[width] = 0;
}
}
++n;
f = *fmt++;
continue;
#if CHSCANF_USE_FLOAT
case 'f':
valf = -1;
exp_char = 'e';
exp_base = 10;
fixed_point = 0;
initial_digit = false;
while (isspace(c)) {
c = stmGet(stmp);
}
if (c == '+') {
if (--width == 0) {
return n;
}
c = stmGet(stmp);
} else if (c == '-') {
if (--width == 0) {
return n;
}
is_positive = false;
c = stmGet(stmp);
}
/* Special cases: a float can be INF(INITY) or NAN. As a note about this behavior:
this consumes "the longest sequence of input characters which does not exceed any
specified field width and which is, or is a prefix of, a matching input sequence" (from
the C99 standard). Therefore, if a '%f' format token gets the input 'INFINITxyx',
it will consume the 'INFINIT', leaving 'xyz' in the stream. Similarly, if it gets
'NAxyz', it will consume the 'NA', leaving 'xyz' in the stream.
Given that it seems a little odd to accept a short version and a long version, but not
a version in between that contains the short version but isn't long enough to be the
long version, This implementation is fairly permissive, and will accept anything from
'INF' to 'INFINITY', case insensative, (e.g. 'INF', 'INfiN', 'INFit', or 'infinity')
as a valid token meaning INF. It will not, however, accept less than 'INF' or 'NAN' as
a valid token (so the above example 'NAxyz' would consume the 'NA', but not recognize it
as signifying NaN)
*/
if (tolower(c) == 'n') {
c = stmGet(stmp);
match = "an";
while (*match != 0) {
if (*match != tolower(c)) {
stmUnget(chp, c);
return n;
}
if (--width == 0) {
stmUnget(chp, c);
return n;
}
++match;
c = stmGet(stmp);
}
valf = NAN;
goto float_common;
}
if (tolower(c) == 'i') {
c = stmGet(stmp);
match = "nf";
while (*match != 0) {
if (*match != tolower(c)) {
stmUnget(chp, c);
return n;
}
++match;
c = stmGet(stmp);
if (--width == 0) {
stmUnget(chp, c);
return n;
}
}
valf = INFINITY;
match = "inity";
while (*match != 0) {
if (*match != tolower(c)) {
break;
}
++match;
if (--width == 0) {
break;
}
c = stmGet(stmp);
}
goto float_common;
}
if (c == '0') {
c = stmGet(stmp);
if (--width == 0) {
valf = 0;
goto float_common;
}
if (c == 'x' || c == 'X') {
base = 16;
exp_char = 'p';
exp_base = 2;
c = stmGet(stmp);
if (--width == 0) {
stmUnget(chp, c);
return n;
}
} else {
valf = 0;
}
}
if (sym_to_val(c, base) != -1) {
valf = 0;
}
while (width--) {
digit = sym_to_val(c, base);
if (digit == -1) {
break;
}
valf = (valf * base) + (double)digit;
c = stmGet(stmp);
}
if (c == '.') {
c = stmGet(stmp);
while (width--) {
digit = sym_to_val(c, base);
if (digit == -1) {
break;
}
if (valf == -1) {
valf = 0;
}
valf = (valf * base) + (double)digit;
++fixed_point;
c = stmGet(stmp);
}
}
if (valf == -1.0) {
stmUnget(chp, c);
return n;
}
valf = valf / ch_mpow(base, fixed_point);
if (tolower(c) == exp_char) {
if (width-- == 0) {
return n;
}
c = stmGet(stmp);
exp_is_positive = true;
exp = 0;
if (c == '+') {
if (width-- == 0) {
return n;
}
c = stmGet(stmp);
} else if (c == '-') {
if (width-- == 0) {
return n;
}
exp_is_positive = false;
c = stmGet(stmp);
}
/*
"When parsing an incomplete floating-point value that ends in the exponent with no digits,
such as parsing "100er" with the conversion specifier %f, the sequence "100e" (the longest
prefix of a possibly valid floating-point number) is consumed, resulting in a matching
error (the consumed sequence cannot be converted to a floating-point number), with "r"
remaining." (https://en.cppreference.com/w/c/io/fscanf)
*/
digit = sym_to_val(c, 10);
if (digit == -1) {
stmUnget(chp, c);
return n;
}
while (width--) {
/* Even if the significand was hex, the exponent is decimal */
digit = sym_to_val(c, 10);
if (digit == -1) {
break;
}
exp = (exp * 10) + digit;
c = stmGet(stmp);
}
if (exp_is_positive) {
valf = valf * (double)ch_mpow(exp_base, exp);
} else {
valf = valf / (double)ch_mpow(exp_base, exp);
}
}
float_common:
if (!is_positive) {
valf = -1 * valf;
}
if (buf) {
if (is_long) {
*(double*)buf = valf;
} else {
*(float*)buf = valf;
}
}
++n;
f = *fmt++;
continue;
#endif
case 'i':
case 'I':
/* I specifier discards leading whitespace */
while (isspace(c)) {
c = stmGet(stmp);
}
/* The char might be +, might be -, might be 0, or might be something else */
if (c == '+') {
if (--width == 0) {
return n;
}
c = stmGet(stmp);
} else if (c == '-') {
if (--width == 0) {
return n;
}
is_positive = false;
c = stmGet(stmp);
}
if (c == '0') {
if (--width == 0) {
return ++n;
}
c = stmGet(stmp);
if (c == 'x' || c == 'X') {
base = 16;
if (--width == 0) {
return n;
}
c = stmGet(stmp);
} else {
base = 8;
}
}
break;
case 'd':
case 'D':
while (isspace(c)) {
c = stmGet(stmp);
}
if (c == '+') {
if (--width == 0) {
return n;
}
c = stmGet(stmp);
} else if (c == '-') {
if (--width == 0) {
return n;
}
is_positive = false;
c = stmGet(stmp);
}
break;
case 'X':
case 'x':
case 'P':
case 'p':
is_signed = false;
base = 16;
while (isspace(c)) {
c = stmGet(stmp);
}
if (c == '+') {
if (--width == 0) {
return n;
}
c = stmGet(stmp);
} else if (c == '-') {
if (--width == 0) {
return n;
}
is_positive = false;
c = stmGet(stmp);
}
if (c == '0') {
if (--width == 0) {
return ++n;
}
c = stmGet(stmp);
if (c == 'x' || c == 'X') {
if (--width == 0) {
return n;
}
c = stmGet(stmp);
}
}
break;
case 'U':
case 'u':
is_signed = false;
while (isspace(c)) {
c = stmGet(stmp);
}
if (c == '+') {
if (--width == 0) {
return n;
}
c = stmGet(stmp);
} else if (c == '-') {
if (--width == 0) {
return n;
}
is_positive = false;
c = stmGet(stmp);
}
break;
case 'O':
case 'o':
is_signed = false;
base = 8;
while (isspace(c)) {
c = stmGet(stmp);
}
if (c == '+') {
if (--width == 0) {
return n;
}
c = stmGet(stmp);
} else if (c == '-') {
if (--width == 0) {
return n;
}
is_positive = false;
c = stmGet(stmp);
}
break;
default:
stmUnget(stmp, c);
return n;
}
vall = 0UL;
/* If we don't have at least one additional eligible character, it's a matching failure */
if (sym_to_val(c, base) == -1) {
break;
}
while (width--) {
digit = sym_to_val(c, base);
if (digit == -1) {
break;
}
vall = (vall * base) + digit;
c = stmGet(stmp);
}
if (!is_positive) {
vall = -1 * vall;
}
if (buf) {
if (is_long && is_signed) {
*((signed long*)buf) = vall;
} else if (is_long && !is_signed) {
*((unsigned long*)buf) = vall;
} else if (!is_long && is_signed) {
*((signed int*)buf) = vall;
} else if (!is_long && !is_signed) {
*((unsigned int*)buf) = vall;
}
}
f = *fmt++;
++n;
}
stmUnget(stmp, c);
return n;
}
/**
* @brief System formatted input function.
* @details This function implements a minimal @p scanf() like functionality
* with input from a @p BufferedStream.
* The general parameters format is: %[*][width][l|L]p
* The following parameter types (p) are supported:
* - <b>x</b> hexadecimal integer.
* - <b>X</b> hexadecimal long.
* - <b>o</b> octal integer.
* - <b>O</b> octal long.
* - <b>d</b> decimal signed integer.
* - <b>D</b> decimal signed long.
* - <b>u</b> decimal unsigned integer.
* - <b>U</b> decimal unsigned long.
* - <b>c</b> character.
* - <b>s</b> string.
* .
*
* @param[in] chp pointer to a @p BufferedStream implementing object
* @param[in] fmt formatting string
* @return The number parameters in ap that have been successfully
* filled. This does not conform to the standard in that if
* a failure (either matching or input) occurs before any
* parameters are assigned, the function will return 0.
*
* @api
*/
int chscanf(sequential_stream_i *stmp, const char *fmt, ...)
{
va_list ap;
int retval;
va_start(ap, fmt);
retval = chvscanf(stmp, fmt, ap);
va_end(ap);
return retval;
}
/**
* @brief System formatted input function.
* @details This function implements a minimal @p snscanf()-like functionality.
* The general parameters format is: %[*][width][l|L]p
* The following parameter types (p) are supported:
* - <b>x</b> hexadecimal integer.
* - <b>X</b> hexadecimal long.
* - <b>o</b> octal integer.
* - <b>O</b> octal long.
* - <b>d</b> decimal signed integer.
* - <b>D</b> decimal signed long.
* - <b>u</b> decimal unsigned integer.
* - <b>U</b> decimal unsigned long.
* - <b>c</b> character.
* - <b>s</b> string.
* .
*
* @param[in] str pointer to a buffer
* @param[in] size size of the buffer
* @param[in] fmt formatting string
* @return The number parameters in ap that have been successfully
* filled. This does not conform to the standard in that if
* a failure (either matching or input) occurs before any
* parameters are assigned, the function will return 0.
*
* @api
*/
int chsnscanf(char *str, size_t size, const char *fmt, ...)
{
va_list ap;
int retval;
/* Performing the scan operation.*/
va_start(ap, fmt);
retval = chvsnscanf(str, size, fmt, ap);
va_end(ap);
/* Return number of receiving arguments successfully assigned.*/
return retval;
}
/**
* @brief System formatted input function.
* @details This function implements a minimal @p vsnscanf()-like functionality.
* The general parameters format is: %[*][width][l|L]p
* The following parameter types (p) are supported:
* - <b>x</b> hexadecimal integer.
* - <b>X</b> hexadecimal long.
* - <b>o</b> octal integer.
* - <b>O</b> octal long.
* - <b>d</b> decimal signed integer.
* - <b>D</b> decimal signed long.
* - <b>u</b> decimal unsigned integer.
* - <b>U</b> decimal unsigned long.
* - <b>c</b> character.
* - <b>s</b> string.
* .
*
* @param[in] str pointer to a buffer
* @param[in] size size of the buffer
* @param[in] fmt formatting string
* @param[in] ap list of parameters
* @return The number parameters in ap that have been successfully
* filled. This does not conform to the standard in that if
* a failure (either matching or input) occurs before any
* parameters are assigned, the function will return 0.
*
* @api
*/
int chvsnscanf(char *str, size_t size, const char *fmt, va_list ap)
{
memory_stream_c ms;
size_t size_wo_nul;
if (size > 0)
size_wo_nul = size - 1;
else
size_wo_nul = 0;
/* Memory stream object to be used as a string writer, reserving one
byte for the final zero.*/
memstmObjectInit(&ms, (uint8_t*)str, size_wo_nul, 0U);
/* Performing the scan operation using the common code and
return number of receiving arguments successfully assigned.*/
return chvscanf(oopGetIf(&ms, stm), fmt, ap);
}
/** @} */

View File

@ -0,0 +1,238 @@
/*
ChibiOS - Copyright (C) 2006..2023 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file nullstreams.c
* @brief Generated Null Streams source.
* @note This is a generated file, do not edit directly.
*
* @addtogroup NULLSTREAMS
* @{
*/
#include "nullstreams.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local macros. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module class "null_stream_c" methods. */
/*===========================================================================*/
/**
* @name Interfaces implementation of null_stream_c
* @{
*/
/**
* @memberof null_stream_c
* @private
*
* @brief Implementation of interface method @p stmWrite().
*
* @param[in,out] ip Pointer to the @p sequential_stream_i class
* interface.
* @param[in] bp Pointer to the data buffer.
* @param[in] n The maximum amount of data to be transferred.
* @return The number of bytes transferred. The returned
* value can be less than the specified number of
* bytes if an end-of-file condition has been met.
*/
static size_t __nullstm_stm_write_impl(void *ip, const uint8_t *bp, size_t n) {
null_stream_c *self = oopIfGetOwner(null_stream_c, ip);
(void)self;
(void)bp;
return n;
}
/**
* @memberof null_stream_c
* @private
*
* @brief Implementation of interface method @p stmRead().
*
* @param[in,out] ip Pointer to the @p sequential_stream_i class
* interface.
* @param[out] bp Pointer to the data buffer.
* @param[in] n The maximum amount of data to be transferred.
* @return The number of bytes transferred. The returned
* value can be less than the specified number of
* bytes if an end-of-file condition has been met.
*/
static size_t __nullstm_stm_read_impl(void *ip, uint8_t *bp, size_t n) {
null_stream_c *self = oopIfGetOwner(null_stream_c, ip);
(void)self;
(void)bp;
return n;
}
/**
* @memberof null_stream_c
* @private
*
* @brief Implementation of interface method @p stmPut().
*
* @param[in,out] ip Pointer to the @p sequential_stream_i class
* interface.
* @param[in] b The byte value to be written to the stream.
* @return The operation status.
*/
static int __nullstm_stm_put_impl(void *ip, uint8_t b) {
null_stream_c *self = oopIfGetOwner(null_stream_c, ip);
(void)self;
(void)b;
return STM_OK;
}
/**
* @memberof null_stream_c
* @private
*
* @brief Implementation of interface method @p stmGet().
*
* @param[in,out] ip Pointer to the @p sequential_stream_i class
* interface.
* @return A byte value from the stream.
*/
static int __nullstm_stm_get_impl(void *ip) {
null_stream_c *self = oopIfGetOwner(null_stream_c, ip);
(void)self;
return 4;
}
/**
* @memberof null_stream_c
* @private
*
* @brief Implementation of interface method @p stmUnget().
*
* @param[in,out] ip Pointer to the @p sequential_stream_i class
* interface.
* @param[in] b The byte value to be pushed back to the stream.
* @return The operation status.
*/
static int __nullstm_stm_unget_impl(void *ip, int b) {
null_stream_c *self = oopIfGetOwner(null_stream_c, ip);
(void)self;
(void)b;
return STM_RESET;
}
/** @} */
/**
* @name Methods implementations of null_stream_c
* @{
*/
/**
* @memberof null_stream_c
* @protected
*
* @brief Implementation of object creation.
* @note This function is meant to be used by derived classes.
*
* @param[out] ip Pointer to a @p null_stream_c instance to be
* initialized.
* @param[in] vmt VMT pointer for the new object.
* @return A new reference to the object.
*/
void *__nullstm_objinit_impl(void *ip, const void *vmt) {
null_stream_c *self = (null_stream_c *)ip;
/* Initialization of the ancestors-defined parts.*/
__bo_objinit_impl(self, vmt);
/* Initialization of interface sequential_stream_i.*/
{
static const struct sequential_stream_vmt nullstm_stm_vmt = {
.instance_offset = offsetof(null_stream_c, stm),
.write = __nullstm_stm_write_impl,
.read = __nullstm_stm_read_impl,
.put = __nullstm_stm_put_impl,
.get = __nullstm_stm_get_impl,
.unget = __nullstm_stm_unget_impl
};
oopIfObjectInit(&self->stm, &nullstm_stm_vmt);
}
/* No initialization code.*/
return self;
}
/**
* @memberof null_stream_c
* @protected
*
* @brief Implementation of object finalization.
* @note This function is meant to be used by derived classes.
*
* @param[in,out] ip Pointer to a @p null_stream_c instance to be
* disposed.
*/
void __nullstm_dispose_impl(void *ip) {
null_stream_c *self = (null_stream_c *)ip;
/* No finalization code.*/
(void)self;
/* Finalization of the ancestors-defined parts.*/
__bo_dispose_impl(self);
}
/** @} */
/**
* @brief VMT structure of null stream class.
* @note It is public because accessed by the inlined constructor.
*/
const struct null_stream_vmt __null_stream_vmt = {
.dispose = __nullstm_dispose_impl
};
/** @} */