|
@@ -261,7 +261,14 @@ void CardReader::selectByName(SdFile dir, const char * const match) {
|
261
|
261
|
}
|
262
|
262
|
|
263
|
263
|
//
|
264
|
|
-// Recursive method to list all files within a folder
|
|
264
|
+// Recursive method to print all files within a folder in flat
|
|
265
|
+// DOS 8.3 format. This style of listing is the most compatible
|
|
266
|
+// with legacy hosts.
|
|
267
|
+//
|
|
268
|
+// This method recurses to unlimited depth and lists every
|
|
269
|
+// G-code file within the given parent. If the hierarchy is
|
|
270
|
+// very deep this can blow up the stack, so a 'depth' parameter
|
|
271
|
+// (as with printListingJSON) would be a good addition.
|
265
|
272
|
//
|
266
|
273
|
void CardReader::printListing(SdFile parent, const char * const prepend/*=nullptr*/) {
|
267
|
274
|
dir_t p;
|
|
@@ -288,17 +295,17 @@ void CardReader::printListing(SdFile parent, const char * const prepend/*=nullpt
|
288
|
295
|
|
289
|
296
|
// Get a new directory object using the full path
|
290
|
297
|
// and dive recursively into it.
|
291
|
|
- SdFile child;
|
292
|
|
- if (!child.open(&parent, dosFilename, O_READ))
|
|
298
|
+ SdFile child; // child.close() in destructor
|
|
299
|
+ if (child.open(&parent, dosFilename, O_READ))
|
|
300
|
+ printListing(child, path);
|
|
301
|
+ else {
|
293
|
302
|
SERIAL_ECHO_MSG(STR_SD_CANT_OPEN_SUBDIR, dosFilename);
|
294
|
|
-
|
295
|
|
- printListing(child, path);
|
296
|
|
- // close() is done automatically by destructor of SdFile
|
|
303
|
+ return;
|
|
304
|
+ }
|
297
|
305
|
}
|
298
|
306
|
else if (is_dir_or_gcode(p)) {
|
299
|
|
- createFilename(filename, p);
|
300
|
307
|
if (prepend) SERIAL_ECHO(prepend);
|
301
|
|
- SERIAL_ECHO(filename);
|
|
308
|
+ SERIAL_ECHO(createFilename(filename, p));
|
302
|
309
|
SERIAL_CHAR(' ');
|
303
|
310
|
SERIAL_ECHOLN(p.fileSize);
|
304
|
311
|
}
|
|
@@ -342,7 +349,7 @@ void CardReader::ls() {
|
342
|
349
|
// Go to the next segment
|
343
|
350
|
while (path[++i]) { }
|
344
|
351
|
|
345
|
|
- // SERIAL_ECHOPGM("Looking for segment: "); SERIAL_ECHOLN(segment);
|
|
352
|
+ //SERIAL_ECHOLNPAIR("Looking for segment: ", segment);
|
346
|
353
|
|
347
|
354
|
// Find the item, setting the long filename
|
348
|
355
|
diveDir.rewind();
|
|
@@ -720,14 +727,14 @@ void CardReader::removeFile(const char * const name) {
|
720
|
727
|
|
721
|
728
|
//abortFilePrintNow();
|
722
|
729
|
|
723
|
|
- SdFile *curDir;
|
724
|
|
- const char * const fname = diveToFile(false, curDir, name);
|
|
730
|
+ SdFile *itsDirPtr;
|
|
731
|
+ const char * const fname = diveToFile(false, itsDirPtr, name);
|
725
|
732
|
if (!fname) return;
|
726
|
733
|
|
727
|
734
|
#if ENABLED(SDCARD_READONLY)
|
728
|
735
|
SERIAL_ECHOLNPAIR("Deletion failed (read-only), File: ", fname, ".");
|
729
|
736
|
#else
|
730
|
|
- if (file.remove(curDir, fname)) {
|
|
737
|
+ if (file.remove(itsDirPtr, fname)) {
|
731
|
738
|
SERIAL_ECHOLNPAIR("File deleted:", fname);
|
732
|
739
|
sdpos = 0;
|
733
|
740
|
TERN_(SDCARD_SORT_ALPHA, presort());
|
|
@@ -870,98 +877,101 @@ uint16_t CardReader::countFilesInWorkDir() {
|
870
|
877
|
* - If update_cwd was 'true' the workDir now points to the file's directory.
|
871
|
878
|
*
|
872
|
879
|
* Returns a pointer to the last segment (filename) of the given DOS 8.3 path.
|
|
880
|
+ * On exit, inDirPtr contains an SdFile reference to the file's directory.
|
873
|
881
|
*
|
874
|
882
|
* A nullptr result indicates an unrecoverable error.
|
|
883
|
+ *
|
|
884
|
+ * NOTE: End the path with a slash to dive to a folder. In this case the
|
|
885
|
+ * returned filename will be blank (points to the end of the path).
|
875
|
886
|
*/
|
876
|
|
-const char* CardReader::diveToFile(const bool update_cwd, SdFile* &diveDir, const char * const path, const bool echo/*=false*/) {
|
|
887
|
+const char* CardReader::diveToFile(const bool update_cwd, SdFile* &inDirPtr, const char * const path, const bool echo/*=false*/) {
|
877
|
888
|
DEBUG_SECTION(est, "diveToFile", true);
|
878
|
889
|
|
879
|
890
|
// Track both parent and subfolder
|
880
|
891
|
static SdFile newDir1, newDir2;
|
881
|
|
- SdFile *sub = &newDir1, *startDir;
|
|
892
|
+ SdFile *sub = &newDir1, *startDirPtr;
|
882
|
893
|
|
883
|
894
|
// Parsing the path string
|
884
|
|
- const char *item_name_adr = path;
|
|
895
|
+ const char *atom_ptr = path;
|
885
|
896
|
|
886
|
897
|
DEBUG_ECHOLNPAIR(" path = '", path, "'");
|
887
|
898
|
|
888
|
899
|
if (path[0] == '/') { // Starting at the root directory?
|
889
|
|
- diveDir = &root;
|
890
|
|
- item_name_adr++;
|
891
|
|
- DEBUG_ECHOLNPAIR(" CWD to root: ", hex_address((void*)diveDir));
|
|
900
|
+ inDirPtr = &root;
|
|
901
|
+ atom_ptr++;
|
|
902
|
+ DEBUG_ECHOLNPAIR(" CWD to root: ", hex_address((void*)inDirPtr));
|
892
|
903
|
if (update_cwd) workDirDepth = 0; // The cwd can be updated for the benefit of sub-programs
|
893
|
904
|
}
|
894
|
905
|
else
|
895
|
|
- diveDir = &workDir; // Dive from workDir (as set by the UI)
|
|
906
|
+ inDirPtr = &workDir; // Dive from workDir (as set by the UI)
|
896
|
907
|
|
897
|
|
- startDir = diveDir;
|
|
908
|
+ startDirPtr = inDirPtr;
|
898
|
909
|
|
899
|
|
- DEBUG_ECHOLNPAIR(" startDir = ", hex_address((void*)startDir));
|
|
910
|
+ DEBUG_ECHOLNPAIR(" startDirPtr = ", hex_address((void*)startDirPtr));
|
900
|
911
|
|
901
|
|
- while (item_name_adr) {
|
|
912
|
+ while (atom_ptr) {
|
902
|
913
|
// Find next subdirectory delimiter
|
903
|
|
- char * const name_end = strchr(item_name_adr, '/');
|
|
914
|
+ char * const name_end = strchr(atom_ptr, '/');
|
904
|
915
|
|
905
|
916
|
// Last atom in the path? Item found.
|
906
|
|
- if (name_end <= item_name_adr) break;
|
|
917
|
+ if (name_end <= atom_ptr) break;
|
907
|
918
|
|
908
|
|
- // Set subDirName
|
909
|
|
- const uint8_t len = name_end - item_name_adr;
|
|
919
|
+ // Isolate the next subitem name
|
|
920
|
+ const uint8_t len = name_end - atom_ptr;
|
910
|
921
|
char dosSubdirname[len + 1];
|
911
|
|
- strncpy(dosSubdirname, item_name_adr, len);
|
|
922
|
+ strncpy(dosSubdirname, atom_ptr, len);
|
912
|
923
|
dosSubdirname[len] = 0;
|
913
|
924
|
|
914
|
925
|
if (echo) SERIAL_ECHOLN(dosSubdirname);
|
915
|
926
|
|
916
|
927
|
DEBUG_ECHOLNPAIR(" sub = ", hex_address((void*)sub));
|
917
|
928
|
|
918
|
|
- // Open diveDir (closing first)
|
|
929
|
+ // Open inDirPtr (closing first)
|
919
|
930
|
sub->close();
|
920
|
|
- if (!sub->open(diveDir, dosSubdirname, O_READ)) {
|
|
931
|
+ if (!sub->open(inDirPtr, dosSubdirname, O_READ)) {
|
921
|
932
|
openFailed(dosSubdirname);
|
922
|
|
- item_name_adr = nullptr;
|
|
933
|
+ atom_ptr = nullptr;
|
923
|
934
|
break;
|
924
|
935
|
}
|
925
|
936
|
|
926
|
|
- // Close diveDir if not at starting-point
|
927
|
|
- if (diveDir != startDir) {
|
928
|
|
- DEBUG_ECHOLNPAIR(" closing diveDir: ", hex_address((void*)diveDir));
|
929
|
|
- diveDir->close();
|
|
937
|
+ // Close inDirPtr if not at starting-point
|
|
938
|
+ if (inDirPtr != startDirPtr) {
|
|
939
|
+ DEBUG_ECHOLNPAIR(" closing inDirPtr: ", hex_address((void*)inDirPtr));
|
|
940
|
+ inDirPtr->close();
|
930
|
941
|
}
|
931
|
942
|
|
932
|
|
- // diveDir now subDir
|
933
|
|
- diveDir = sub;
|
934
|
|
- DEBUG_ECHOLNPAIR(" diveDir = sub: ", hex_address((void*)diveDir));
|
|
943
|
+ // inDirPtr now subDir
|
|
944
|
+ inDirPtr = sub;
|
|
945
|
+ DEBUG_ECHOLNPAIR(" inDirPtr = sub: ", hex_address((void*)inDirPtr));
|
935
|
946
|
|
936
|
947
|
// Update workDirParents and workDirDepth
|
937
|
948
|
if (update_cwd) {
|
938
|
949
|
DEBUG_ECHOLNPAIR(" update_cwd");
|
939
|
950
|
if (workDirDepth < MAX_DIR_DEPTH)
|
940
|
|
- workDirParents[workDirDepth++] = *diveDir;
|
|
951
|
+ workDirParents[workDirDepth++] = *inDirPtr;
|
941
|
952
|
}
|
942
|
953
|
|
943
|
954
|
// Point sub at the other scratch object
|
944
|
|
- sub = (diveDir != &newDir1) ? &newDir1 : &newDir2;
|
|
955
|
+ sub = (inDirPtr != &newDir1) ? &newDir1 : &newDir2;
|
945
|
956
|
DEBUG_ECHOLNPAIR(" swapping sub = ", hex_address((void*)sub));
|
946
|
957
|
|
947
|
958
|
// Next path atom address
|
948
|
|
- item_name_adr = name_end + 1;
|
|
959
|
+ atom_ptr = name_end + 1;
|
949
|
960
|
}
|
950
|
961
|
|
951
|
962
|
if (update_cwd) {
|
952
|
|
- workDir = *diveDir;
|
953
|
|
- DEBUG_ECHOLNPAIR(" final workDir = ", hex_address((void*)diveDir));
|
|
963
|
+ workDir = *inDirPtr;
|
|
964
|
+ DEBUG_ECHOLNPAIR(" final workDir = ", hex_address((void*)inDirPtr));
|
954
|
965
|
flag.workDirIsRoot = (workDirDepth == 0);
|
955
|
966
|
TERN_(SDCARD_SORT_ALPHA, presort());
|
956
|
967
|
}
|
957
|
968
|
|
958
|
|
- DEBUG_ECHOLNPAIR(" returning string ", item_name_adr ?: "nullptr");
|
959
|
|
- return item_name_adr;
|
|
969
|
+ DEBUG_ECHOLNPAIR(" returning string ", atom_ptr ?: "nullptr");
|
|
970
|
+ return atom_ptr;
|
960
|
971
|
}
|
961
|
972
|
|
962
|
973
|
void CardReader::cd(const char * relpath) {
|
963
|
|
- SdFile newDir;
|
964
|
|
- SdFile *parent = workDir.isOpen() ? &workDir : &root;
|
|
974
|
+ SdFile newDir, *parent = &getWorkDir();
|
965
|
975
|
|
966
|
976
|
if (newDir.open(parent, relpath, O_READ)) {
|
967
|
977
|
workDir = newDir;
|