ESPHome 2026.3.0
Loading...
Searching...
No Matches
printf_stubs.cpp
Go to the documentation of this file.
1/*
2 * Linker wrap stubs for FILE*-based printf functions.
3 *
4 * The ESP8266 Arduino framework and libraries may reference printf(),
5 * vprintf(), and fprintf() which pull in newlib's _vfprintf_r (~900 bytes).
6 * ESPHome never uses these — all logging writes directly to the UART via
7 * Arduino's Serial, so the libc FILE*-based printf path is dead code.
8 *
9 * These stubs redirect through vsnprintf() (which is already in the binary
10 * for ESPHome's logging) and fwrite(), allowing the linker to dead-code
11 * eliminate _vfprintf_r.
12 *
13 * Saves ~1.6 KB of flash.
14 */
15
16#if defined(USE_ESP8266) && !defined(USE_FULL_PRINTF)
17#include <cstdarg>
18#include <cstdio>
19#include <cstdlib>
20
21namespace esphome::esp8266 {}
22
23static constexpr size_t PRINTF_BUFFER_SIZE = 512;
24
25// These stubs are essentially dead code at runtime — ESPHome writes directly
26// to the UART via Arduino's Serial, and Serial.printf() has its own implementation.
27// The buffer overflow check is purely defensive and should never trigger.
28static int write_printf_buffer(FILE *stream, char *buf, int len) {
29 if (len < 0) {
30 return len;
31 }
32 size_t write_len = len;
33 if (write_len >= PRINTF_BUFFER_SIZE) {
34 fwrite(buf, 1, PRINTF_BUFFER_SIZE - 1, stream);
35 abort();
36 }
37 if (fwrite(buf, 1, write_len, stream) < write_len || ferror(stream)) {
38 return -1;
39 }
40 return len;
41}
42
43// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
44extern "C" {
45
46int __wrap_vprintf(const char *fmt, va_list ap) {
47 char buf[PRINTF_BUFFER_SIZE];
48 return write_printf_buffer(stdout, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
49}
50
51int __wrap_printf(const char *fmt, ...) {
52 va_list ap;
53 va_start(ap, fmt);
54 int len = __wrap_vprintf(fmt, ap);
55 va_end(ap);
56 return len;
57}
58
59int __wrap_fprintf(FILE *stream, const char *fmt, ...) {
60 va_list ap;
61 va_start(ap, fmt);
62 char buf[PRINTF_BUFFER_SIZE];
63 int len = write_printf_buffer(stream, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
64 va_end(ap);
65 return len;
66}
67
68} // extern "C"
69// NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
70
71#endif // USE_ESP8266 && !USE_FULL_PRINTF
int __wrap_fprintf(FILE *stream, const char *fmt,...)
int __wrap_printf(const char *fmt,...)
int __wrap_vprintf(const char *fmt, va_list ap)
uint32_t len