FastLED 3.9.15
Loading...
Searching...
No Matches
file_io.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/int.h"
4#include "platforms/is_platform.h"
5#include "fl/stl/cerrno.h" // For fl::get_errno()
6#include "fl/stl/cstring.h" // For fl::strerror()
7
8#ifdef FASTLED_TESTING
9// IWYU pragma: begin_keep
10#include <cstdio>
11// IWYU pragma: end_keep // For ::FILE*, ::fopen, ::fclose, etc.
12#endif
13
14// Platform-agnostic file I/O abstraction
15// Provides fl::FILE* and fl::fopen/fclose/etc. functions that platforms can implement
16//
17// Supported platforms:
18// - POSIX/Testing (FASTLED_TESTING): Maps to standard FILE* and libc functions
19// - Embedded (future): Can map to LittleFS, SPIFFS, SD card APIs, etc.
20
21namespace fl {
22
23// ============================================================================
24// Opaque File Handle Type
25// ============================================================================
26
27// Forward declare the platform-specific file handle structure
28// Each platform defines this in their implementation
29struct FILE_impl;
30
31// Opaque file handle pointer (like standard FILE*)
33
34// ============================================================================
35// File I/O Constants
36// ============================================================================
37
38namespace io {
39 // Seek origin constants (match SEEK_SET, SEEK_CUR, SEEK_END)
40 constexpr int seek_set = 0;
41 constexpr int seek_cur = 1;
42 constexpr int seek_end = 2;
43
44 // Error code for "bad file descriptor" (matches EBADF = 9 on POSIX)
45 constexpr int err_bad_file = 9;
46}
47
48// ============================================================================
49// Platform-Agnostic File I/O Functions
50// ============================================================================
51// These functions provide a consistent interface across all platforms.
52// Each platform implements these in their own way.
53
58FILE* fopen(const char* path, const char* mode);
59
63int fclose(FILE* file);
64
71fl::size_t fread(void* buffer, fl::size_t size, fl::size_t count, FILE* file);
72
79fl::size_t fwrite(const void* data, fl::size_t size, fl::size_t count, FILE* file);
80
84long ftell(FILE* file);
85
91int fseek(FILE* file, long offset, int origin);
92
96int fflush(FILE* file);
97
98// On some platforms (e.g., AVR), feof, ferror, and clearerr are macros
99// Save them only if they exist, undefine temporarily to declare our functions
100// Only needed on platforms where they are actually macros (AVR)
101#ifdef FL_IS_AVR
102#ifdef feof
103#define FL_MACRO_NEEDS_RESTORE_feof
104#pragma push_macro("feof")
105#undef feof
106#endif
107#ifdef ferror
108#define FL_MACRO_NEEDS_RESTORE_ferror
109#pragma push_macro("ferror")
110#undef ferror
111#endif
112#ifdef clearerr
113#define FL_MACRO_NEEDS_RESTORE_clearerr
114#pragma push_macro("clearerr")
115#undef clearerr
116#endif
117#endif // FL_IS_AVR
118
122#ifdef FL_IS_AVR
123int (feof)(FILE* file);
124#else
125int feof(FILE* file);
126#endif
127
131#ifdef FL_IS_AVR
132int (ferror)(FILE* file);
133#else
134int ferror(FILE* file);
135#endif
136
139#ifdef FL_IS_AVR
140void (clearerr)(FILE* file);
141#else
142void clearerr(FILE* file);
143#endif
144
145// Note: On AVR, we use parentheses around function names to prevent macro expansion
146// and we do NOT restore the macros (see comment at end of file for rationale)
147
148// Note: fl::get_errno() and fl::strerror() are already defined in fl/stl/cerrno.h and fl/stl/cstring.h
149// We don't redeclare them here to avoid conflicts
150
151} // namespace fl
152
153// ============================================================================
154// Platform-Specific Implementations
155// ============================================================================
156
157#ifdef FASTLED_TESTING
158// POSIX/Testing platform: Use standard C FILE* and libc functions
159
160namespace fl {
161
162// On POSIX platforms, fl::FILE is just the standard FILE
163struct FILE_impl : public ::FILE {};
164
165// Map fl:: functions to standard libc functions
166// Note: static_cast is safe here because FILE_impl inherits from ::FILE
167// This is a platform abstraction layer that wraps the POSIX FILE* API
168inline FILE* fopen(const char* path, const char* mode) {
169 return static_cast<FILE*>(::fopen(path, mode));
170}
171
172inline int fclose(FILE* file) {
173 return ::fclose(static_cast<::FILE*>(file));
174}
175
176inline fl::size_t fread(void* buffer, fl::size_t size, fl::size_t count, FILE* file) {
177 return ::fread(buffer, size, count, static_cast<::FILE*>(file));
178}
179
180inline fl::size_t fwrite(const void* data, fl::size_t size, fl::size_t count, FILE* file) {
181 return ::fwrite(data, size, count, static_cast<::FILE*>(file));
182}
183
184inline long ftell(FILE* file) {
185 return ::ftell(static_cast<::FILE*>(file));
186}
187
188inline int fseek(FILE* file, long offset, int origin) {
189 return ::fseek(static_cast<::FILE*>(file), offset, origin);
190}
191
192inline int fflush(FILE* file) {
193 return ::fflush(static_cast<::FILE*>(file));
194}
195
196#ifdef FL_IS_AVR
197inline int (feof)(FILE* file) {
198 return ::feof(static_cast<::FILE*>(file));
199}
200#else
201inline int feof(FILE* file) {
202 return ::feof(static_cast<::FILE*>(file));
203}
204#endif
205
206#ifdef FL_IS_AVR
207inline int (ferror)(FILE* file) {
208 return ::ferror(static_cast<::FILE*>(file));
209}
210#else
211inline int ferror(FILE* file) {
212 return ::ferror(static_cast<::FILE*>(file));
213}
214#endif
215
216#ifdef FL_IS_AVR
217inline void (clearerr)(FILE* file) {
218 ::clearerr(static_cast<::FILE*>(file));
219}
220#else
221inline void clearerr(FILE* file) {
222 ::clearerr(static_cast<::FILE*>(file));
223}
224#endif
225
226// Note: fl::get_errno() and fl::strerror() are defined in fl/stl/cerrno.h and fl/stl/cstring.h
227// No implementation needed here - those files provide them
228
229} // namespace fl
230
231#else // !FASTLED_TESTING
232
233// ============================================================================
234// Embedded Platform (No File System)
235// ============================================================================
236// Provides no-op implementations that fail gracefully
237
238namespace fl {
239
240// Minimal stub structure for embedded platforms
241struct FILE_impl {
242 int dummy; // Placeholder to make it a valid type
243};
244
245// No-op implementations
246inline FILE* fopen(const char* /*path*/, const char* /*mode*/) {
247 return nullptr;
248}
249
250inline int fclose(FILE* /*file*/) {
251 return -1;
252}
253
254inline fl::size_t fread(void* /*buffer*/, fl::size_t /*size*/, fl::size_t /*count*/, FILE* /*file*/) {
255 return 0;
256}
257
258inline fl::size_t fwrite(const void* /*data*/, fl::size_t /*size*/, fl::size_t /*count*/, FILE* /*file*/) {
259 return 0;
260}
261
262inline long ftell(FILE* /*file*/) {
263 return -1;
264}
265
266inline int fseek(FILE* /*file*/, long /*offset*/, int /*origin*/) {
267 return -1;
268}
269
270inline int fflush(FILE* /*file*/) {
271 return -1;
272}
273
274#ifdef FL_IS_AVR
275inline int (feof)(FILE* /*file*/) {
276 return 0;
277}
278#else
279inline int feof(FILE* /*file*/) {
280 return 0;
281}
282#endif
283
284#ifdef FL_IS_AVR
285inline int (ferror)(FILE* /*file*/) {
286 return 1;
287}
288#else
289inline int ferror(FILE* /*file*/) {
290 return 1;
291}
292#endif
293
294#ifdef FL_IS_AVR
295inline void (clearerr)(FILE* /*file*/) {
296}
297#else
298inline void clearerr(FILE* /*file*/) {
299}
300#endif
301
302// Note: fl::get_errno() and fl::strerror() are defined in fl/stl/cerrno.h and fl/stl/cstring.h
303// We use those implementations instead of defining our own here
304
305} // namespace fl
306
307#endif // FASTLED_TESTING
308
309// DO NOT restore the feof/ferror/clearerr macros on AVR
310// Rationale: Even with parentheses in function declarations, restoring these macros causes
311// them to expand at call sites like `fl::feof(file)`, which breaks compilation.
312// Macro expansion happens before namespace resolution, so `fl::feof(x)` becomes
313// `fl::((x)->flags & _FEOF)` on AVR, which is invalid syntax.
314//
315// Solution: We only undefine these macros on AVR (where they exist as macros), and we
316// use parentheses around function names `(feof)`, `(ferror)`, `(clearerr)` in declarations
317// and definitions to prevent macro expansion. We do NOT restore the macros.
318//
319// On non-AVR platforms where these are regular functions (not macros), we use normal
320// function syntax without parentheses.
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
__SIZE_TYPE__ size_t
Definition s16x16x4.h:16
constexpr int seek_cur
Definition file_io.h:41
constexpr int err_bad_file
Definition file_io.h:45
constexpr int seek_set
Definition file_io.h:40
constexpr int seek_end
Definition file_io.h:42
int fseek(FILE *file, long offset, int origin)
Set file position.
Definition file_io.h:266
int ferror(FILE *file)
Check for file error.
Definition file_io.h:289
int fflush(FILE *file)
Flush file buffers.
Definition file_io.h:270
FILE_impl FILE
Definition file_io.h:32
void clearerr(FILE *file)
Clear file error indicators.
Definition file_io.h:298
FILE * fopen(const char *path, const char *mode)
Open a file.
Definition file_io.h:246
fl::size_t fread(void *buffer, fl::size_t size, fl::size_t count, FILE *file)
Read from file.
Definition file_io.h:254
int fclose(FILE *file)
Close a file.
Definition file_io.h:250
long ftell(FILE *file)
Get current file position.
Definition file_io.h:262
fl::size_t fwrite(const void *data, fl::size_t size, fl::size_t count, FILE *file)
Write to file.
Definition file_io.h:258
int feof(FILE *file)
Check for end-of-file.
Definition file_io.h:279
Base definition for an LED controller.
Definition crgb.hpp:179