Noodle
Loading...
Searching...
No Matches
noodle_fs.h
Go to the documentation of this file.
1
33#pragma once
34
35// -----------------------------
36// Path policy
37// -----------------------------
38#if defined(NOODLE_USE_SDFAT)
39 #define NOODLE_FS_NEEDS_LEADING_SLASH 0
40#else
41 #define NOODLE_FS_NEEDS_LEADING_SLASH 1
42#endif
43
44#ifndef NOODLE_MAX_FILENAME
45 #define NOODLE_MAX_FILENAME 20 // plenty for "w28.txt" etc.
46#endif
47
48
49// ------------------------------
50// 1) Enforce "exactly one"
51// ------------------------------
52#if (defined(NOODLE_USE_SDFAT) + defined(NOODLE_USE_SD_MMC) + defined(NOODLE_USE_FFAT) + defined(NOODLE_USE_LITTLEFS) + defined(NOODLE_USE_NONE)) != 1
53# error "Select exactly ONE backend: NOODLE_USE_SDFAT, NOODLE_USE_SD_MMC, NOODLE_USE_FFAT, NOODLE_USE_LITTLEFS, or NOODLE_USE_NONE"
54#endif
55
56// ------------------------------
57// 2) NONE backend
58// ------------------------------
59#if defined(NOODLE_USE_NONE)
60
61 // Minimal "file-like" stub so code compiles.
62 struct NDL_NullFile {
63 bool _open = false;
64
65 // Match common File/FsFile-ish methods used in embedded code.
66 operator bool() const { return _open; }
67 bool available() const { return false; }
68 int read() { return -1; }
69 int peek() { return -1; }
70 size_t readBytes(char*, size_t) { return 0; }
71 size_t write(uint8_t) { return 0; }
72 size_t write(const uint8_t*, size_t) { return 0; }
73 void flush() {}
74 void close() { _open = false; }
75 size_t size() const { return 0; }
76 size_t position() const { return 0; }
77 bool seek(uint32_t) { return false; }
78 size_t println(byte v) { (void)v; return 0; }
79 size_t println(float v) { (void)v; return 0; }
80 size_t println(float v, int base) { (void)v; return 0; }
81 };
82
83 using NDL_File = NDL_NullFile;
84
85 // No NOODLE_FS symbol in NONE mode.
86
87#else
88// ------------------------------
89// 3) Real backends
90// ------------------------------
91 #if defined(NOODLE_USE_SDFAT)
92 #include <SdFat.h>
93
94#if defined(ESP32) || defined(ARDUINO_ARCH_ESP32) || \
95 defined(ESP8266) || defined(ARDUINO_ARCH_ESP8266) || \
96 defined(ARDUINO_ARCH_RP2040)
97 using NDL_File = FsFile; // SdFat on ESP32 typically uses FsFile
98 #else
99 using NDL_File = File; // SdFat on AVR often uses File wrapper
100 #endif
101
102 extern SdFat NOODLE_FS; // defined in noodle.cpp
103
104 #elif defined(NOODLE_USE_FFAT)
105 #include <FFat.h>
106 #define NOODLE_FS FFat
107 using NDL_File = File;
108
109 #elif defined(NOODLE_USE_LITTLEFS)
110 #include <LittleFS.h>
111 #define NOODLE_FS LittleFS
112 using NDL_File = File;
113
114 #elif defined(NOODLE_USE_SD_MMC)
115 #include <SD_MMC.h>
116 #define NOODLE_FS SD_MMC
117 using NDL_File = File;
118
119 #endif
120#endif
121
122// ------------------------------
123// 4) Unified API
124// ------------------------------
125// Safe string copy with NUL-termination
126
127// Minimal bounded copy for short filenames
130inline void noodle_copy_name(char* dst, size_t cap, const char* src) {
131 if (!dst || cap == 0) return;
132 if (!src) { dst[0] = '\0'; return; }
133
134 size_t i = 0;
135 while (src[i] != '\0' && (i + 1) < cap) {
136 dst[i] = src[i];
137 i++;
138 }
139 dst[i] = '\0';
140}
141
142// Normalize path according to backend policy
143// Only safe for immediate use (open/remove); do not store returned pointer!
155inline const char* noodle_norm_filename(const char* name) {
156 if (!name) return "";
157
158#if NOODLE_FS_NEEDS_LEADING_SLASH
159 // One static buffer is enough for your simplified rules.
160 // Size = '/' + filename + '\0'
161 static char out[NOODLE_MAX_FILENAME + 2];
162
163 out[0] = '/';
164 noodle_copy_name(out + 1, NOODLE_MAX_FILENAME + 1, name);
165 return out;
166#else
167 // SdFat: return as-is, no extra RAM used.
168 return name;
169#endif
170}
171
172// Open a file for reading
175inline NDL_File noodle_fs_open_read(const char* path) {
176 path = noodle_norm_filename(path);
177#if defined(NOODLE_USE_NONE)
178 (void)path;
179 return NDL_File{}; // invalid handle
180#elif defined(NOODLE_USE_SDFAT)
181 return NOODLE_FS.open(path, O_RDONLY);
182#else
183 return NOODLE_FS.open(path, FILE_READ);
184#endif
185}
186
187// Open a file for writing (creates or truncates)
190inline NDL_File noodle_fs_open_write(const char* path) {
191 path = noodle_norm_filename(path);
192#if defined(NOODLE_USE_NONE)
193 (void)path;
194 return NDL_File{}; // invalid handle
195#elif defined(NOODLE_USE_SDFAT)
196 int flags = O_WRITE | O_CREAT | O_TRUNC;
197 return NOODLE_FS.open(path, flags);
198#else
199 return NOODLE_FS.open(path, FILE_WRITE);
200#endif
201}
202
206inline bool noodle_fs_remove(const char* path) {
207 path = noodle_norm_filename(path);
208#if defined(NOODLE_USE_NONE)
209 (void)path;
210 return false;
211#else
212 return NOODLE_FS.remove(path);
213#endif
214}
215
223inline void noodle_rewind_file(NDL_File &fi) {
224#if defined(NOODLE_USE_SDFAT)
225 fi.seekSet(0);
226#elif defined(NOODLE_USE_FFAT) || defined(NOODLE_USE_LITTLEFS) || defined(NOODLE_USE_SD_MMC) || defined(NOODLE_USE_SD)
227 fi.seek(0);
228#else
229 // NOODLE_USE_NONE (or unknown backend): nothing to seek. Close the handle.
230 fi.close();
231#endif
232}
NDL_File fi
Definition noodle.cpp:16
SdFat NOODLE_FS
Definition noodle.cpp:12
void noodle_rewind_file(NDL_File &fi)
Rewind a file handle to position 0.
Definition noodle_fs.h:223
void noodle_copy_name(char *dst, size_t cap, const char *src)
Copy a C string into a bounded buffer with NUL-termination.
Definition noodle_fs.h:130
bool noodle_fs_remove(const char *path)
Remove a file using the selected backend.
Definition noodle_fs.h:206
#define NOODLE_MAX_FILENAME
Definition noodle_fs.h:45
NDL_File noodle_fs_open_write(const char *path)
Open a file for writing (create or truncate) using the selected backend.
Definition noodle_fs.h:190
NDL_File noodle_fs_open_read(const char *path)
Open a file for reading using the selected backend.
Definition noodle_fs.h:175
const char * noodle_norm_filename(const char *name)
Normalize a filename/path for the selected filesystem backend.
Definition noodle_fs.h:155