git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@16241 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
parent
298b40a1a6
commit
831d2840df
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -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
|
||||
};
|
||||
|
||||
/** @} */
|
Loading…
Reference in New Issue