Import Mbed OS hard-float snapshot
This commit is contained in:
163
platform/source/minimal-printf/README.md
Normal file
163
platform/source/minimal-printf/README.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Minimal printf and snprintf
|
||||
|
||||
|
||||
Library supports both printf and snprintf in around 1300 bytes of flash.
|
||||
|
||||
Prints directly to stdio/UART without using malloc. All flags and precision modifiers are ignored.
|
||||
There is no error handling if a writing error occurs.
|
||||
|
||||
Supports:
|
||||
* %d: signed integer [h, hh, (none), l, ll, z, j, t].
|
||||
* %i: signed integer [h, hh, (none), l, ll, z, j, t].
|
||||
* %u: unsigned integer [h, hh, (none), l, ll, z, j, t].
|
||||
* %x: unsigned integer [h, hh, (none), l, ll, z, j, t], printed as hexadecimal number (e.g., ff).
|
||||
* %X: unsigned integer [h, hh, (none), l, ll, z, j, t], printed as hexadecimal number (e.g., FF).
|
||||
* %f: floating point (disabled by default).
|
||||
* %F: floating point (disabled by default, treated as %f).
|
||||
* %g: floating point (disabled by default, treated as %f).
|
||||
* %G: floating point (disabled by default, treated as %f).
|
||||
* %c: character.
|
||||
* %s: string.
|
||||
* %p: pointer (e.g. 0x00123456).
|
||||
|
||||
Note that support for:
|
||||
* 64b modifiers is only present when `minimal-printf-enable-64-bit` config is set to `true` (default).
|
||||
* Floating point parameters is only present when `minimal-printf-enable-floating-point` config is set to `true` (disabled by default).
|
||||
|
||||
Unrecognized format specifiers are treated as ordinary characters.
|
||||
|
||||
Floating point limitations:
|
||||
* All floating points are treated as %f.
|
||||
* No support for inf, infinity or nan
|
||||
|
||||
## Usage
|
||||
|
||||
As of Mbed OS 6.0 this is enabled by default. To replace the standard implementation of the printf functions with the ones in this library for older versions of Mbed:
|
||||
|
||||
Modify your application configuration file to override the parameter `target.printf_lib` with the value `minimal-printf` as shown below:
|
||||
|
||||
```json
|
||||
{
|
||||
"target_overrides": {
|
||||
"*": {
|
||||
"target.printf_lib": "minimal-printf"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If your application requires more advanced functionality, you'll need to revert to using standard version of printf/snprintf. Please note that it will result in significant ROM usage increase. In case you are using minimal version of standard C library advanced functionality may not be present.
|
||||
|
||||
Modify your application configuration in `mbed_app.json` file to override the parameter `target.printf_lib` with the value `std` as shown below:
|
||||
|
||||
```json
|
||||
"target_overrides": {
|
||||
"*": {
|
||||
"target.printf_lib": "std"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
Minimal printf is configured by the following parameters defined in `platform/mbed_lib.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "platform",
|
||||
"config": {
|
||||
"minimal-printf-enable-64-bit": {
|
||||
"help": "Enable printing 64 bit integers when using minimal printf library",
|
||||
"value": true
|
||||
},
|
||||
"minimal-printf-enable-floating-point": {
|
||||
"help": "Enable floating point printing when using minimal printf library",
|
||||
"value": false
|
||||
},
|
||||
"minimal-printf-set-floating-point-max-decimals": {
|
||||
"help": "Maximum number of decimals to be printed when using minimal printf library",
|
||||
"value": 6
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By default, 64 bit integers support is enabled, but floating point support is disabled to increase memory savings.
|
||||
|
||||
If your application needs to override the default configuration add following section to your `mbed_app.json`:
|
||||
```json
|
||||
"target_overrides": {
|
||||
"*": {
|
||||
"target.printf_lib": "minimal-printf",
|
||||
"platform.minimal-printf-enable-floating-point": false,
|
||||
"platform.minimal-printf-set-floating-point-max-decimals": 6,
|
||||
"platform.minimal-printf-enable-64-bit": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Size comparison
|
||||
|
||||
|
||||
### Blinky application
|
||||
|
||||
https://github.com/ARMmbed/mbed-os-example-blinky application compiled with the different toolchains.
|
||||
|
||||
Blinky application size on K64F/GCC_ARM
|
||||
|
||||
| | Floating point | 64 bit integers | Flash | RAM |
|
||||
| - | - | - | - | - |
|
||||
| mbed-printf | | | 32,972 | 11,608 |
|
||||
| mbed-printf | | X | 33,116 | 11,608 |
|
||||
| mbed-printf | X | X | 35,856 | 11,608 |
|
||||
| std printf | X | X | 55,766 | 12,104 |
|
||||
|
||||
Blinky application size on K64F/ARMC6
|
||||
|
||||
| | Floating point | 64 bit integers | Flash | RAM |
|
||||
| - | - | - | - | - |
|
||||
| mbed-printf | | | 33,585 | xxxxx |
|
||||
| mbed-printf | | X | 33,679 | xxxxx |
|
||||
| mbed-printf | X | X | 36,525 | xxxxx |
|
||||
| std printf | X | X | 39,128 | xxxxx |
|
||||
|
||||
Blinky application size on K64F/IAR
|
||||
|
||||
| | Floating point | 64 bit integers | Flash | RAM |
|
||||
| - | - | - | - | - |
|
||||
| mbed-printf | | | 31,439 | 8,493 |
|
||||
| mbed-printf | | X | 31,579 | 8,493 |
|
||||
| mbed-printf | X | X | 33,387 | 8,493 |
|
||||
| std printf | X | X | 36,643 | 8,553 |
|
||||
|
||||
### Blinky bare metal application
|
||||
|
||||
https://github.com/ARMmbed/mbed-os-example-blinky-baremetal application compiled with the different toolchains.
|
||||
|
||||
Blinky application size on K64F/GCC_ARM
|
||||
|
||||
| | Floating point | 64 bit integers | Flash | RAM |
|
||||
| - | - | - | - | - |
|
||||
| mbed-printf | | | 19,660 | 5,368 |
|
||||
| mbed-printf | | X | 19,804 | 5,368 |
|
||||
| mbed-printf | X | X | 22,548 | 5,368 |
|
||||
| std printf | X | X | 35,292 | 5,864 |
|
||||
|
||||
Blinky application size on K64F/ARMC6
|
||||
|
||||
| | Floating point | 64 bit integers | Flash | RAM |
|
||||
| - | - | - | - | - |
|
||||
| mbed-printf | | | 18,764 | xxxxx |
|
||||
| mbed-printf | | X | 18,764 | xxxxx |
|
||||
| mbed-printf | X | X | 18,764 | xxxxx |
|
||||
| std printf | X | X | 25,403 | xxxxx |
|
||||
|
||||
Blinky application size on K64F/IAR
|
||||
|
||||
| | Floating point | 64 bit integers | Flash | RAM |
|
||||
| - | - | - | - | - |
|
||||
| mbed-printf | | | 19,623 | 1,737 |
|
||||
| mbed-printf | | X | 19,763 | 1,737 |
|
||||
| mbed-printf | X | X | 21,571 | 1,737 |
|
||||
| std printf | X | X | 18,059 | 1,281 |
|
||||
391
platform/source/minimal-printf/mbed_printf_armlink_overrides.c
Normal file
391
platform/source/minimal-printf/mbed_printf_armlink_overrides.c
Normal file
@@ -0,0 +1,391 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Arm Compiler uses dedicated functions for each format specifier used by
|
||||
* [sn/v/vsn]printf. When minimal-printf overwrites [sn/v/vsn]printf the
|
||||
* linker is unable to remove unused functions related to printf.
|
||||
*
|
||||
* The following stubs replace the built-in functions and helps the linker
|
||||
* to resolve dependencies and correctly remove unused functions.
|
||||
*/
|
||||
|
||||
#ifdef MBED_MINIMAL_PRINTF
|
||||
|
||||
#if defined(TOOLCHAIN_ARM)
|
||||
|
||||
#include "mbed_printf_implementation.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Arm Compiler uses __2[s/sn/vsn]printf internally.
|
||||
*/
|
||||
int $Sub$$__2printf(const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stdout);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int $Sub$$__2sprintf(char *buffer, const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(buffer, LONG_MAX, format, arguments, NULL);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int $Sub$$__2snprintf(char *buffer, size_t length, const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(buffer, length, format, arguments, NULL);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int $Sub$$__2vprintf(const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stdout);
|
||||
}
|
||||
|
||||
int $Sub$$__2vsprintf(char *buffer, const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(buffer, LONG_MAX, format, arguments, NULL);
|
||||
}
|
||||
|
||||
int $Sub$$__2vsnprintf(char *buffer, size_t length, const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(buffer, length, format, arguments, NULL);
|
||||
}
|
||||
|
||||
int $Sub$$__2fprintf(FILE *stream, const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stream);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int $Sub$$__2vfprintf(FILE *stream, const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the built-in functions which the linker is unable to prune with dummy stubs
|
||||
* that take up less space.
|
||||
*/
|
||||
int $Sub$$_printf_a(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_c(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_char(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_char_common(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_char_file_locked(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_charcount(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_cs_common(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_d(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_dec(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_e(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_f(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_fp_dec(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_fp_dec_real(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_fp_hex(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_fp_hex_real(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_fp_infnan(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_g(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_hex_int_ll_ptr(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_hex_ptr(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_i(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_int_common(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_int_dec(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_int_hex(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_int_oct(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_l(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_lc(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_lcs_common(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_ll(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_ll_hex(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_ll_oct(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_lld(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_lli(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_llo(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_llu(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_llx(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_longlong_dec(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_longlong_hex(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_longlong_oct(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_ls(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_n(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_o(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_oct_int_ll(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_p(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_pad(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_percent(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_percent_end(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_s(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_str(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_string(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_truncate(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_truncate_signed(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_truncate_unsigned(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_u(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_wchar(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_wctomb(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_wstring(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int $Sub$$_printf_x(const char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // MBED_MINIMAL_PRINTF
|
||||
646
platform/source/minimal-printf/mbed_printf_implementation.c
Normal file
646
platform/source/minimal-printf/mbed_printf_implementation.c
Normal file
@@ -0,0 +1,646 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2020 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "mbed_printf_implementation.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if !TARGET_LIKE_MBED
|
||||
/* Linux implementation is for debug only */
|
||||
#define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 1
|
||||
#define MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS 6
|
||||
#define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 1
|
||||
#endif
|
||||
|
||||
#ifndef MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT
|
||||
#define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT 0
|
||||
#endif
|
||||
|
||||
#ifndef MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS
|
||||
#define MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS 6
|
||||
#endif
|
||||
|
||||
#ifndef MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT
|
||||
#define MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check architecture and choose storage data type.
|
||||
* On 32 bit machines, the default storage type is 32 bit wide
|
||||
* unless 64 bit integers are enabled in the configuration.
|
||||
*/
|
||||
#if INTPTR_MAX == INT32_MAX
|
||||
#define MBED_SIGNED_NATIVE_TYPE int32_t
|
||||
#define MBED_UNSIGNED_NATIVE_TYPE uint32_t
|
||||
#if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT
|
||||
#define MBED_SIGNED_STORAGE int64_t
|
||||
#define MBED_UNSIGNED_STORAGE uint64_t
|
||||
#else
|
||||
#define MBED_SIGNED_STORAGE int32_t
|
||||
#define MBED_UNSIGNED_STORAGE uint32_t
|
||||
#endif
|
||||
|
||||
#elif INTPTR_MAX == INT64_MAX
|
||||
#define MBED_SIGNED_NATIVE_TYPE int64_t
|
||||
#define MBED_UNSIGNED_NATIVE_TYPE uint64_t
|
||||
#define MBED_SIGNED_STORAGE int64_t
|
||||
#define MBED_UNSIGNED_STORAGE uint64_t
|
||||
#else
|
||||
#error unsupported architecture
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Precision defines
|
||||
*/
|
||||
#define PRECISION_DEFAULT (INT_MAX)
|
||||
|
||||
/**
|
||||
* Enum for storing width modifier.
|
||||
*/
|
||||
typedef enum {
|
||||
LENGTH_NONE = 0x00,
|
||||
LENGTH_H = 0x11,
|
||||
LENGTH_L = 0x21,
|
||||
LENGTH_J = 0x31,
|
||||
LENGTH_Z = 0x41,
|
||||
LENGTH_T = 0x51,
|
||||
LENGTH_CAPITAL_L = 0x61,
|
||||
LENGTH_HH = 0x72,
|
||||
LENGTH_LL = 0x82
|
||||
} length_t;
|
||||
|
||||
/**
|
||||
* Prototypes
|
||||
*/
|
||||
static void mbed_minimal_formatted_string_signed(char *buffer, size_t length, int *result, MBED_SIGNED_STORAGE value, FILE *stream);
|
||||
static void mbed_minimal_formatted_string_unsigned(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream);
|
||||
static void mbed_minimal_formatted_string_hexadecimal(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream, bool upper);
|
||||
static void mbed_minimal_formatted_string_void_pointer(char *buffer, size_t length, int *result, const void *value, FILE *stream);
|
||||
static void mbed_minimal_formatted_string_string(char *buffer, size_t length, int *result, const char *string, size_t precision, FILE *stream);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Print a single character, checking for buffer and size overflows.
|
||||
*
|
||||
* @param buffer The buffer to store output (NULL for stdout).
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param result The current output location.
|
||||
* @param[in] data The char to be printed.
|
||||
*/
|
||||
static void mbed_minimal_putchar(char *buffer, size_t length, int *result, char data, FILE *stream)
|
||||
{
|
||||
/* only continue if 'result' doesn't overflow */
|
||||
if ((*result >= 0) && (*result <= INT_MAX - 1)) {
|
||||
if (stream) {
|
||||
if (fputc(data, stream) == EOF) {
|
||||
*result = EOF;
|
||||
} else {
|
||||
*result += 1;
|
||||
}
|
||||
} else {
|
||||
if (buffer) {
|
||||
/* write data only if there's enough space */
|
||||
if ((size_t)*result < length) {
|
||||
buffer[*result] = data;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment 'result' even if data was not written. This ensures that
|
||||
'mbed_minimal_formatted_string' returns the correct value. */
|
||||
*result += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print signed integer.
|
||||
*
|
||||
* @param buffer The buffer to store output (NULL for stdout).
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param result The current output location.
|
||||
* @param[in] value The value to be printed.
|
||||
*/
|
||||
static void mbed_minimal_formatted_string_signed(char *buffer, size_t length, int *result, MBED_SIGNED_STORAGE value, FILE *stream)
|
||||
{
|
||||
MBED_UNSIGNED_STORAGE new_value = 0;
|
||||
|
||||
/* if value is negative print sign and treat as positive number */
|
||||
if (value < 0) {
|
||||
/* write sign */
|
||||
mbed_minimal_putchar(buffer, length, result, '-', stream);
|
||||
|
||||
/* get absolute value using two's complement */
|
||||
new_value = ~((MBED_UNSIGNED_STORAGE) value) + 1;
|
||||
} else {
|
||||
new_value = value;
|
||||
}
|
||||
|
||||
/* use unsigned long int function */
|
||||
mbed_minimal_formatted_string_unsigned(buffer, length, result, new_value, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print unsigned integer.
|
||||
*
|
||||
* @param buffer The buffer to store output (NULL for stdout).
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param result The current output location.
|
||||
* @param[in] value The value to be printed.
|
||||
*/
|
||||
static void mbed_minimal_formatted_string_unsigned(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream)
|
||||
{
|
||||
/* treat 0 as a corner case */
|
||||
if (value == 0) {
|
||||
mbed_minimal_putchar(buffer, length, result, '0', stream);
|
||||
} else {
|
||||
/* allocate 3 digits per byte */
|
||||
char scratch[sizeof(MBED_UNSIGNED_STORAGE) * 3] = { 0 };
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
/* write numbers in reverse order to scratch pad */
|
||||
for (; value > 0; index++) {
|
||||
/* use '0' as base and add digit */
|
||||
scratch[index] = '0' + (value % 10);
|
||||
|
||||
/* shift value one decimal position */
|
||||
value = value / 10;
|
||||
}
|
||||
|
||||
/* write scratch pad to buffer or output */
|
||||
for (; index > 0; index--) {
|
||||
mbed_minimal_putchar(buffer, length, result, scratch[index - 1], stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print hexadecimal.
|
||||
*
|
||||
* @param buffer The buffer to store output (NULL for stdout).
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param result The current output location.
|
||||
* @param[in] value The value to be printed.
|
||||
* @param upper Flag to print the hexadecimal in upper or lower case.
|
||||
*/
|
||||
static void mbed_minimal_formatted_string_hexadecimal(char *buffer, size_t length, int *result, MBED_UNSIGNED_STORAGE value, FILE *stream, bool upper)
|
||||
{
|
||||
bool print_leading_zero = false;
|
||||
|
||||
for (int index = 7; index >= 0; index--) {
|
||||
/* get most significant byte */
|
||||
uint8_t output = value >> (8 * index);
|
||||
|
||||
/* only print leading zeros when set */
|
||||
if (print_leading_zero || (output != 0) || (index == 0)) {
|
||||
unsigned int nibble_one = (output >> 4);
|
||||
unsigned int nibble_two = (output & 0x0F);
|
||||
|
||||
static const char int2hex_lower[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
static const char int2hex_upper[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
const char *int2hex = upper ? int2hex_upper : int2hex_lower;
|
||||
|
||||
if (print_leading_zero || nibble_one != 0) {
|
||||
mbed_minimal_putchar(buffer, length, result, int2hex[nibble_one], stream);
|
||||
}
|
||||
mbed_minimal_putchar(buffer, length, result, int2hex[nibble_two], stream);
|
||||
|
||||
/* print zeroes after the first non-zero byte */
|
||||
print_leading_zero = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print pointer.
|
||||
*
|
||||
* @param buffer The buffer to store output (NULL for stdout).
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param result The current output location.
|
||||
* @param[in] value The pointer to be printed.
|
||||
*/
|
||||
static void mbed_minimal_formatted_string_void_pointer(char *buffer, size_t length, int *result, const void *value, FILE *stream)
|
||||
{
|
||||
/* write leading 0x */
|
||||
mbed_minimal_putchar(buffer, length, result, '0', stream);
|
||||
mbed_minimal_putchar(buffer, length, result, 'x', stream);
|
||||
|
||||
/* write rest as a regular hexadecimal number */
|
||||
mbed_minimal_formatted_string_hexadecimal(buffer, length, result, (ptrdiff_t) value, stream, true);
|
||||
}
|
||||
|
||||
#if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT
|
||||
/**
|
||||
* @brief Write double.
|
||||
*
|
||||
* @param buffer The buffer to store output (NULL for stdout).
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param result The current output location.
|
||||
* @param[in] value The value to be printed.
|
||||
*/
|
||||
static void mbed_minimal_formatted_string_double(char *buffer, size_t length, int *result, double value, FILE *stream)
|
||||
{
|
||||
/* get integer part */
|
||||
MBED_SIGNED_STORAGE integer = value;
|
||||
|
||||
/* write integer part */
|
||||
mbed_minimal_formatted_string_signed(buffer, length, result, integer, stream);
|
||||
|
||||
/* write decimal point */
|
||||
mbed_minimal_putchar(buffer, length, result, '.', stream);
|
||||
|
||||
/* get decimal part */
|
||||
double precision = 1.0;
|
||||
|
||||
for (size_t index = 0; index < MBED_CONF_PLATFORM_MINIMAL_PRINTF_SET_FLOATING_POINT_MAX_DECIMALS; index++) {
|
||||
precision *= 10;
|
||||
}
|
||||
|
||||
value = (value - integer) * precision;
|
||||
|
||||
/* convert to unsigned integer */
|
||||
MBED_UNSIGNED_STORAGE decimal = 0;
|
||||
|
||||
if (value < 0) {
|
||||
MBED_SIGNED_STORAGE temp = value;
|
||||
decimal = ~((MBED_UNSIGNED_STORAGE) temp) + 1;
|
||||
} else {
|
||||
decimal = value;
|
||||
}
|
||||
|
||||
/* round up or down */
|
||||
value -= decimal;
|
||||
|
||||
if (!((value > -0.5) && (value < 0.5))) {
|
||||
decimal++;
|
||||
}
|
||||
|
||||
/* convert precision to unsigned integer */
|
||||
MBED_UNSIGNED_STORAGE precision_in_uint = precision;
|
||||
precision_in_uint /= 10;
|
||||
|
||||
/* ensure that leading zeros are printed if decimal equals 0 */
|
||||
MBED_UNSIGNED_STORAGE val = decimal ? decimal : decimal + 1;
|
||||
while (precision_in_uint > val) {
|
||||
/* print leading zeros */
|
||||
mbed_minimal_putchar(buffer, length, result, '0', stream);
|
||||
precision_in_uint /= 10;
|
||||
}
|
||||
|
||||
/* write decimal part */
|
||||
mbed_minimal_formatted_string_unsigned(buffer, length, result, decimal, stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Print string with precision.
|
||||
*
|
||||
* @param buffer The buffer to store output (NULL for stdout).
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param result The current output location.
|
||||
* @param[in] value The string to be printed.
|
||||
* @param[in] precision The maximum number of characters to be printed.
|
||||
*/
|
||||
static void mbed_minimal_formatted_string_string(char *buffer, size_t length, int *result, const char *string, size_t precision, FILE *stream)
|
||||
{
|
||||
while ((*string != '\0') && (precision)) {
|
||||
mbed_minimal_putchar(buffer, length, result, *string, stream);
|
||||
string++;
|
||||
precision--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse formatted string and invoke write handlers based on type.
|
||||
*
|
||||
* @param buffer The buffer to write to, write to stdout if NULL.
|
||||
* @param[in] length The length of the buffer.
|
||||
* @param[in] format The formatted string.
|
||||
* @param[in] arguments The va_list arguments.
|
||||
*
|
||||
* @return Number of characters written.
|
||||
*/
|
||||
int mbed_minimal_formatted_string(char *buffer, size_t length, const char *format, va_list arguments, FILE *stream)
|
||||
{
|
||||
int result = 0;
|
||||
bool empty_buffer = false;
|
||||
|
||||
/* ensure that function wasn't called with an empty buffer, or with or with
|
||||
a buffer size that is larger than the maximum 'int' value, or with
|
||||
a NULL format specifier */
|
||||
if (format && length <= INT_MAX) {
|
||||
/* Make sure that there's always space for the NULL terminator */
|
||||
if (length > 0) {
|
||||
length --;
|
||||
} else {
|
||||
/* the buffer is empty, there's no place to write the terminator */
|
||||
empty_buffer = true;
|
||||
}
|
||||
/* parse string */
|
||||
for (size_t index = 0; format[index] != '\0'; index++) {
|
||||
/* format specifier begin */
|
||||
if (format[index] == '%') {
|
||||
size_t next_index = index + 1;
|
||||
|
||||
/**************************************************************
|
||||
* skip and ignore flags [-+(space)#0]
|
||||
*************************************************************/
|
||||
if ((format[next_index] == '-') ||
|
||||
(format[next_index] == '+') ||
|
||||
(format[next_index] == ' ') ||
|
||||
(format[next_index] == '#') ||
|
||||
(format[next_index] == '0')) {
|
||||
/* skip to next character */
|
||||
next_index++;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* skip and ignore width [(number)*]
|
||||
*************************************************************/
|
||||
if (format[next_index] == '*') {
|
||||
/* skip to next character */
|
||||
next_index++;
|
||||
|
||||
/* discard argument */
|
||||
va_arg(arguments, MBED_SIGNED_NATIVE_TYPE);
|
||||
} else {
|
||||
while ((format[next_index] >= '0') &&
|
||||
(format[next_index] <= '9')) {
|
||||
/* skip to next character */
|
||||
next_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* look for precision modifier
|
||||
*************************************************************/
|
||||
int precision = PRECISION_DEFAULT;
|
||||
|
||||
if ((format[next_index] == '.') &&
|
||||
(format[next_index + 1] == '*')) {
|
||||
next_index += 2;
|
||||
|
||||
/* read precision from argument list */
|
||||
precision = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE);
|
||||
} else if (format[next_index] == '.') {
|
||||
/* precision modifier found, reset default to 0 and increment index */
|
||||
next_index++;
|
||||
precision = 0;
|
||||
|
||||
/* parse precision until not a decimal */
|
||||
size_t inner_index = 0;
|
||||
|
||||
while ((format[next_index + inner_index] >= '0') &&
|
||||
(format[next_index + inner_index] <= '9')) {
|
||||
precision = precision * 10 + (format[next_index + inner_index] - '0');
|
||||
|
||||
inner_index++;
|
||||
}
|
||||
|
||||
/* move index forward to point at next character */
|
||||
next_index += inner_index;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* look for length modifier, default to NONE
|
||||
*************************************************************/
|
||||
length_t length_modifier = LENGTH_NONE;
|
||||
|
||||
/* look for two character length modifier */
|
||||
if ((format[next_index] == 'h') && (format[next_index + 1] == 'h')) {
|
||||
length_modifier = LENGTH_HH;
|
||||
} else if ((format[next_index] == 'l') && (format[next_index + 1] == 'l')) {
|
||||
length_modifier = LENGTH_LL;
|
||||
}
|
||||
/* look for one character length modifier if two character search failed */
|
||||
else if (format[next_index] == 'h') {
|
||||
length_modifier = LENGTH_H;
|
||||
} else if (format[next_index] == 'l') {
|
||||
length_modifier = LENGTH_L;
|
||||
} else if (format[next_index] == 'j') {
|
||||
length_modifier = LENGTH_J;
|
||||
} else if (format[next_index] == 'z') {
|
||||
length_modifier = LENGTH_Z;
|
||||
} else if (format[next_index] == 't') {
|
||||
length_modifier = LENGTH_T;
|
||||
} else if (format[next_index] == 'L') {
|
||||
length_modifier = LENGTH_CAPITAL_L;
|
||||
}
|
||||
|
||||
/* increment index, length is encoded in modifier enum */
|
||||
next_index += (length_modifier & 0x0F);
|
||||
|
||||
/**************************************************************
|
||||
* read out character - this is a supported format character,
|
||||
* '\0', or a not suported character
|
||||
*************************************************************/
|
||||
char next = format[next_index];
|
||||
|
||||
/* signed integer */
|
||||
if ((next == 'd') || (next == 'i')) {
|
||||
MBED_SIGNED_STORAGE value = 0;
|
||||
|
||||
#if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT
|
||||
/* if 64 bit is enabled and the integer types are larger than the native type */
|
||||
if (((length_modifier == LENGTH_LL) && (sizeof(long long int) > sizeof(MBED_SIGNED_NATIVE_TYPE))) ||
|
||||
((length_modifier == LENGTH_L) && (sizeof(long int) > sizeof(MBED_SIGNED_NATIVE_TYPE))) ||
|
||||
((length_modifier == LENGTH_NONE) && (sizeof(int) > sizeof(MBED_SIGNED_NATIVE_TYPE)))) {
|
||||
/* use 64 bit storage type for readout */
|
||||
value = va_arg(arguments, MBED_SIGNED_STORAGE);
|
||||
} else
|
||||
#else
|
||||
/* If 64 bit is not enabled, print %ll[di] rather than truncated value */
|
||||
if (length_modifier == LENGTH_LL) {
|
||||
mbed_minimal_putchar(buffer, length, &result, '%', stream);
|
||||
if (next == '%') {
|
||||
// Continue printing loop after `%`
|
||||
index = next_index;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
/* use native storage type (which can be 32 or 64 bit) */
|
||||
value = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE);
|
||||
}
|
||||
|
||||
/* constrict value based on length modifier */
|
||||
switch (length_modifier) {
|
||||
case LENGTH_NONE:
|
||||
value = (int) value;
|
||||
break;
|
||||
case LENGTH_HH:
|
||||
value = (signed char) value;
|
||||
break;
|
||||
case LENGTH_H:
|
||||
value = (short int) value;
|
||||
break;
|
||||
case LENGTH_L:
|
||||
value = (long int) value;
|
||||
break;
|
||||
case LENGTH_LL:
|
||||
value = (long long int) value;
|
||||
break;
|
||||
case LENGTH_J:
|
||||
value = (intmax_t) value;
|
||||
break;
|
||||
case LENGTH_T:
|
||||
value = (ptrdiff_t) value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
index = next_index;
|
||||
|
||||
mbed_minimal_formatted_string_signed(buffer, length, &result, value, stream);
|
||||
}
|
||||
/* unsigned integer */
|
||||
else if ((next == 'u') || (next == 'x') || (next == 'X')) {
|
||||
MBED_UNSIGNED_STORAGE value = 0;
|
||||
|
||||
#if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_64_BIT
|
||||
/* if 64 bit is enabled and the integer types are larger than the native type */
|
||||
if (((length_modifier == LENGTH_LL) && (sizeof(unsigned long long int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE))) ||
|
||||
((length_modifier == LENGTH_L) && (sizeof(unsigned long int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE))) ||
|
||||
((length_modifier == LENGTH_NONE) && (sizeof(unsigned int) > sizeof(MBED_UNSIGNED_NATIVE_TYPE)))) {
|
||||
/* use 64 bit storage type for readout */
|
||||
value = va_arg(arguments, MBED_UNSIGNED_STORAGE);
|
||||
} else
|
||||
#else
|
||||
/* If 64 bit is not enabled, print %ll[uxX] rather than truncated value */
|
||||
if (length_modifier == LENGTH_LL) {
|
||||
mbed_minimal_putchar(buffer, length, &result, '%', stream);
|
||||
if (next == '%') {
|
||||
// Continue printing loop after `%`
|
||||
index = next_index;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
/* use native storage type (which can be 32 or 64 bit) */
|
||||
value = va_arg(arguments, MBED_UNSIGNED_NATIVE_TYPE);
|
||||
}
|
||||
|
||||
/* constrict value based on length modifier */
|
||||
switch (length_modifier) {
|
||||
case LENGTH_NONE:
|
||||
value = (unsigned int) value;
|
||||
break;
|
||||
case LENGTH_HH:
|
||||
value = (unsigned char) value;
|
||||
break;
|
||||
case LENGTH_H:
|
||||
value = (unsigned short int) value;
|
||||
break;
|
||||
case LENGTH_L:
|
||||
value = (unsigned long int) value;
|
||||
break;
|
||||
case LENGTH_LL:
|
||||
value = (unsigned long long int) value;
|
||||
break;
|
||||
case LENGTH_J:
|
||||
value = (uintmax_t) value;
|
||||
break;
|
||||
case LENGTH_Z:
|
||||
value = (size_t) value;
|
||||
break;
|
||||
case LENGTH_T:
|
||||
value = (ptrdiff_t) value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
index = next_index;
|
||||
|
||||
/* write unsigned or hexadecimal */
|
||||
if (next == 'u') {
|
||||
mbed_minimal_formatted_string_unsigned(buffer, length, &result, value, stream);
|
||||
} else {
|
||||
mbed_minimal_formatted_string_hexadecimal(buffer, length, &result, value, stream, next == 'X');
|
||||
}
|
||||
}
|
||||
#if MBED_CONF_PLATFORM_MINIMAL_PRINTF_ENABLE_FLOATING_POINT
|
||||
/* treat all floating points the same */
|
||||
else if ((next == 'f') || (next == 'F') || (next == 'g') || (next == 'G')) {
|
||||
double value = va_arg(arguments, double);
|
||||
index = next_index;
|
||||
|
||||
mbed_minimal_formatted_string_double(buffer, length, &result, value, stream);
|
||||
}
|
||||
#endif
|
||||
/* character */
|
||||
else if (next == 'c') {
|
||||
char value = va_arg(arguments, MBED_SIGNED_NATIVE_TYPE);
|
||||
index = next_index;
|
||||
|
||||
mbed_minimal_putchar(buffer, length, &result, value, stream);
|
||||
}
|
||||
/* string */
|
||||
else if (next == 's') {
|
||||
char *value = va_arg(arguments, char *);
|
||||
index = next_index;
|
||||
|
||||
mbed_minimal_formatted_string_string(buffer, length, &result, value, precision, stream);
|
||||
}
|
||||
/* pointer */
|
||||
else if (next == 'p') {
|
||||
void *value = va_arg(arguments, void *);
|
||||
index = next_index;
|
||||
|
||||
mbed_minimal_formatted_string_void_pointer(buffer, length, &result, value, stream);
|
||||
} else {
|
||||
// Unrecognised, or `%%`. Print the `%` that led us in.
|
||||
mbed_minimal_putchar(buffer, length, &result, '%', stream);
|
||||
if (next == '%') {
|
||||
// Continue printing loop after `%%`
|
||||
index = next_index;
|
||||
}
|
||||
// Otherwise we continue the printing loop after the leading `%`, so an
|
||||
// unrecognised thing like "Blah = %a" will just come out as "Blah = %a"
|
||||
}
|
||||
} else
|
||||
/* not a format specifier */
|
||||
{
|
||||
/* write normal character */
|
||||
mbed_minimal_putchar(buffer, length, &result, format[index], stream);
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer && !empty_buffer) {
|
||||
/* NULL-terminate the buffer no matter what. We use '<=' to compare instead of '<'
|
||||
because we know that we initially reserved space for '\0' by decrementing length */
|
||||
if ((size_t)result <= length) {
|
||||
buffer[result] = '\0';
|
||||
} else {
|
||||
buffer[length] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
25
platform/source/minimal-printf/mbed_printf_implementation.h
Normal file
25
platform/source/minimal-printf/mbed_printf_implementation.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MBED_PRINTF_IMPLEMENTATION_H
|
||||
#define MBED_PRINTF_IMPLEMENTATION_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
int mbed_minimal_formatted_string(char *buffer, size_t length, const char *format, va_list arguments, FILE *stream);
|
||||
#endif
|
||||
93
platform/source/minimal-printf/mbed_printf_wrapper.c
Normal file
93
platform/source/minimal-printf/mbed_printf_wrapper.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef MBED_MINIMAL_PRINTF
|
||||
|
||||
#include "mbed_printf_implementation.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#if defined(__ARMCC_VERSION) || defined(__ICCARM__)
|
||||
# define PREFIX(x) $Sub$$##x
|
||||
#elif defined(__GNUC__)
|
||||
# define PREFIX(x) __wrap_##x
|
||||
#else
|
||||
#warning "This compiler is not yet supported."
|
||||
#endif
|
||||
|
||||
int PREFIX(printf)(const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stdout);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int PREFIX(sprintf)(char *buffer, const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(buffer, LONG_MAX, format, arguments, NULL);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int PREFIX(snprintf)(char *buffer, size_t length, const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(buffer, length, format, arguments, NULL);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int PREFIX(vprintf)(const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stdout);
|
||||
}
|
||||
|
||||
int PREFIX(vsprintf)(char *buffer, const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(buffer, LONG_MAX, format, arguments, NULL);
|
||||
}
|
||||
|
||||
int PREFIX(vsnprintf)(char *buffer, size_t length, const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(buffer, length, format, arguments, NULL);
|
||||
}
|
||||
|
||||
int PREFIX(fprintf)(FILE *stream, const char *format, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stream);
|
||||
va_end(arguments);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int PREFIX(vfprintf)(FILE *stream, const char *format, va_list arguments)
|
||||
{
|
||||
return mbed_minimal_formatted_string(NULL, LONG_MAX, format, arguments, stream);
|
||||
}
|
||||
|
||||
#endif // MBED_MINIMAL_PRINTF
|
||||
Reference in New Issue
Block a user