mirror of
https://github.com/esphome/esphome.git
synced 2026-10-15 10:42:52 +00:00
[esp32] Trim the sscanf wrap comments and docstrings
This commit is contained in:
@@ -199,11 +199,8 @@ PSRAM_XIP_VARIANTS = {
|
||||
# neither, so the engine is already in the image and the wrap saves nothing.
|
||||
ROM_VSNPRINTF_WITHOUT_VASPRINTF_VARIANTS = {VARIANT_ESP32C6}
|
||||
|
||||
# Variants whose ROM exports sscanf under the newlib format ESPHome links
|
||||
# against: the ESP32-C6 normal-format ROM (esp32c6.rom.newlib-normal.ld) and
|
||||
# the ESP32-C2 nano-format ROM, nano being the IDF default on the C2. There
|
||||
# the sscanf wrap saves nothing; see sscanf_stubs.cpp. The classic ESP32 ROM
|
||||
# only exports it under nano format, which ESPHome does not use.
|
||||
# Variants whose ROM exports sscanf with the newlib format in use (C6 normal
|
||||
# format, C2 nano format by IDF default), so the sscanf wrap saves nothing.
|
||||
ROM_SSCANF_VARIANTS = {VARIANT_ESP32C2, VARIANT_ESP32C6}
|
||||
|
||||
# NVS encryption (HMAC peripheral scheme) is only available on variants that
|
||||
@@ -2327,12 +2324,10 @@ async def _set_libc_picolibc_newlib_compat() -> None:
|
||||
|
||||
|
||||
def _newlib_wraps_apply() -> bool:
|
||||
"""Whether the printf, vasprintf and sscanf linker wraps belong in this build.
|
||||
"""Whether the printf, vasprintf and sscanf wraps belong in this build.
|
||||
|
||||
They need an ESP-IDF framework build (their stubs compile out on Arduino)
|
||||
on newlib: IDF 5.x defaults to newlib on every variant, IDF 6.0+ switches
|
||||
to picolibc on every variant, and the wraps are only measured against
|
||||
newlib.
|
||||
ESP-IDF framework (the stubs compile out on Arduino) on newlib, which
|
||||
IDF 6.0+ replaces with picolibc.
|
||||
"""
|
||||
return not CORE.using_arduino and idf_version() < cv.Version(6, 0, 0)
|
||||
|
||||
@@ -2340,9 +2335,8 @@ def _newlib_wraps_apply() -> bool:
|
||||
def _add_wrap_stub(symbol: str, define: str) -> None:
|
||||
"""Emit a linker wrap for ``symbol`` served by a stub compiled under ``define``.
|
||||
|
||||
The --undefined flag is needed because libsrc.a is scanned before the IDF
|
||||
libraries that reference the symbol, so the stub would otherwise never be
|
||||
pulled from the archive.
|
||||
--undefined is needed because libsrc.a is scanned before the IDF library
|
||||
that references the symbol.
|
||||
"""
|
||||
cg.add_define(define)
|
||||
cg.add_build_flag(f"-Wl,--wrap={symbol}")
|
||||
@@ -2353,11 +2347,8 @@ def _add_wrap_stub(symbol: str, define: str) -> None:
|
||||
async def _add_sscanf_stub(enable_full_scanf: bool | None) -> None:
|
||||
"""Wrap sscanf when bluedroid is the only reason newlib's scanf engine links.
|
||||
|
||||
Runs at FINAL priority so every request_bluetooth() call has happened;
|
||||
see sscanf_stubs.cpp for what the stub covers. A lambda that scans a float
|
||||
keeps the libc sscanf unless enable_full_scanf is set explicitly, since the
|
||||
stub has no floating-point conversions and the wrap applies to the whole
|
||||
image.
|
||||
FINAL priority so every request_bluetooth() call has happened. A lambda
|
||||
that scans a float keeps the libc sscanf unless enable_full_scanf is set.
|
||||
"""
|
||||
if (
|
||||
enable_full_scanf
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
/*
|
||||
* Linker wrap stub for sscanf on ESP-IDF, newlib only.
|
||||
* Linker wrap for sscanf on ESP-IDF with newlib.
|
||||
*
|
||||
* Nothing in ESPHome calls sscanf, but bluedroid does in two places:
|
||||
* btc_config_get_bin decodes stored bonding keys with "%02x" and
|
||||
* string_to_bdaddr parses "%02x:%02x:%02x:%02x:%02x:%02x". Those two
|
||||
* calls are the only reference to newlib's scanf engine (__ssvfscanf_r,
|
||||
* _strtod_l and their helpers, ~13 KB) in a Bluetooth build on variants
|
||||
* whose ROM does not export sscanf.
|
||||
*
|
||||
* This stub routes sscanf through the scanner in core/sscanf_no_float.h,
|
||||
* so any other caller in the image (user lambdas included) keeps working.
|
||||
* Floating-point conversions are the one gap: supporting them would pull
|
||||
* _strtod_l straight back, so a format using %f and friends aborts with a
|
||||
* message pointing at enable_full_scanf: true. Codegen already keeps the
|
||||
* libc sscanf when a lambda scans a float.
|
||||
*
|
||||
* Only compiled in when codegen defines USE_ESP32_SSCANF_STUB, which is
|
||||
* gated on a Bluetooth component being present, on the variant's ROM and
|
||||
* on the same newlib condition as printf_stubs.cpp.
|
||||
* bluedroid's two "%02x" parses (btc_config_get_bin, string_to_bdaddr) are
|
||||
* the only sscanf callers in an ESPHome image and link newlib's whole scanf
|
||||
* engine (~13 KB with _strtod_l). Routing them through core/sscanf_no_float.h
|
||||
* drops it; floats would pull _strtod_l back, so those abort with a message
|
||||
* naming enable_full_scanf. Codegen skips the wrap when a lambda scans a float
|
||||
* and only defines USE_ESP32_SSCANF_STUB for Bluetooth builds on variants
|
||||
* whose ROM lacks sscanf.
|
||||
*/
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* A small sscanf without floating-point conversions.
|
||||
*
|
||||
* Backs the ESP-IDF linker wrap in components/esp32/sscanf_stubs.cpp, where
|
||||
* bluedroid's "%02x" parses would otherwise link newlib's whole scanf engine
|
||||
* (~13 KB with _strtod_l). Integer, character, string and scanset conversions
|
||||
* behave like libc; a conversion this scanner does not implement (floats,
|
||||
* %p, wide characters) returns SSCANF_UNSUPPORTED so the caller can fail
|
||||
* loudly instead of misparsing.
|
||||
*
|
||||
* Header only so the host unit tests can exercise it without compiling a
|
||||
* target platform's sources.
|
||||
*/
|
||||
// sscanf without floating-point conversions, backing the linker wrap in
|
||||
// components/esp32/sscanf_stubs.cpp. Integer, character, string and scanset
|
||||
// conversions behave like libc; anything else returns SSCANF_UNSUPPORTED.
|
||||
// Header only so the host unit tests can cover it.
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
@@ -40,9 +31,7 @@ enum class SscanfLength : uint8_t {
|
||||
|
||||
inline bool is_space(char c) { return c == ' ' || (c >= '\t' && c <= '\r'); }
|
||||
|
||||
// The bit pattern is what the signed conversions want as well. All object
|
||||
// pointers share one representation, so the caller fetches the argument
|
||||
// once as void * rather than once per pointee type.
|
||||
// The unsigned bit pattern is what the signed conversions want as well
|
||||
inline void store_int(void *dest, SscanfLength length, uint64_t value) {
|
||||
switch (length) {
|
||||
case SscanfLength::SSCANF_LENGTH_HH:
|
||||
@@ -80,8 +69,7 @@ struct Scanset {
|
||||
}
|
||||
};
|
||||
|
||||
// Parses a "[set]" directive starting just after the '[' and returns the
|
||||
// position after the closing ']'.
|
||||
// Parses "[set]" from just after the '[' and returns the position after ']'
|
||||
inline const char *parse_scanset(const char *f, Scanset &set) {
|
||||
if (*f == '^') {
|
||||
set.negate = true;
|
||||
@@ -103,8 +91,7 @@ inline const char *parse_scanset(const char *f, Scanset &set) {
|
||||
return *f == ']' ? f + 1 : f;
|
||||
}
|
||||
|
||||
// Radix of an integer conversion: 0 means "detect from the prefix" (%i),
|
||||
// 0xFF marks a conversion this scanner does not implement.
|
||||
// Radix of an integer conversion: 0 detects from the prefix (%i), 0xFF is unsupported
|
||||
inline unsigned int_base(char conv) {
|
||||
switch (conv) {
|
||||
case 'd':
|
||||
@@ -261,8 +248,7 @@ inline int vsscanf_no_float(const char *str, const char *fmt, va_list ap) { //
|
||||
Scanset set;
|
||||
if (conv == '[')
|
||||
f = parse_scanset(f + 1, set) - 1; // the loop's f++ steps past the ']'
|
||||
// %c reads exactly width characters (default 1); like newlib, a short
|
||||
// read still assigns whatever was available.
|
||||
// %c reads width characters (default 1); a short read still assigns, like newlib
|
||||
const size_t limit = conv == 'c' && width == SIZE_MAX ? 1 : width;
|
||||
size_t n = 0;
|
||||
while (n < limit && in[n] != '\0' && (conv == 'c' || (conv == '[' ? set.contains(in[n]) : !is_space(in[n])))) {
|
||||
|
||||
Reference in New Issue
Block a user