Enabled basic file searching

This commit is contained in:
d0k3 2016-07-21 00:29:48 +02:00
parent b51af7ceb4
commit dfd0a4e306
8 changed files with 121 additions and 19 deletions

View File

@ -34,7 +34,7 @@
/ 2: Enable with LF-CRLF conversion. */ / 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 1 #define _USE_FIND 0
/* This option switches filtered directory read functions, f_findfirst() and /* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */

44
source/fatfs/store.c Normal file
View File

@ -0,0 +1,44 @@
#include "store.h"
#include "ff.h"
#define STORE_BUFFER ((DirStruct*)0x21300000)
static bool is_stored = false;
bool IsStoredDrive(const char* path) {
return is_stored && (strncmp(path, "Z:", 3) == 0);
}
void StoreDirContents(DirStruct* contents) {
memcpy(STORE_BUFFER, contents, sizeof(DirStruct));
is_stored = true;
}
void GetStoredDirContents(DirStruct* contents) {
// warning: this assumes the store buffer is filled with data that makes sense
DirStruct* stored = STORE_BUFFER;
u32 skip = 0;
// basic sanity checking
if (!is_stored || (stored->n_entries > MAX_ENTRIES)) return;
// copy available entries, remove missing from storage
for (u32 i = 0; i < stored->n_entries; i++) {
DirEntry* entry = &(stored->entry[i]);
if (strncmp(entry->name, "..", 3) == 0) continue; // disregard dotdot entry
if (f_stat(entry->path, NULL) != FR_OK) {
skip++; // remember this has to be removed from the stored struct
} else { // entry is valid
if (skip) { // move remaining entries to the left
stored->n_entries -= skip;
memmove(entry - skip, entry, (stored->n_entries - i) * sizeof(DirEntry));
entry -= skip;
skip = 0;
}
if (contents->n_entries < MAX_ENTRIES)
memcpy(&(contents->entry[contents->n_entries++]), entry, sizeof(DirEntry));
else break;
}
}
stored->n_entries -= skip;
}

7
source/fatfs/store.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "fs.h"
bool IsStoredDrive(const char* path);
void StoreDirContents(DirStruct* contents);
void GetStoredDirContents(DirStruct* contents);

View File

@ -2,6 +2,7 @@
#include "fs.h" #include "fs.h"
#include "virtual.h" #include "virtual.h"
#include "image.h" #include "image.h"
#include "store.h"
#include "sha.h" #include "sha.h"
#include "sdmmc.h" #include "sdmmc.h"
#include "ff.h" #include "ff.h"
@ -74,7 +75,7 @@ void DeinitSDCardFS() {
int PathToNumFS(const char* path) { int PathToNumFS(const char* path) {
int fsnum = *path - (int) '0'; int fsnum = *path - (int) '0';
if ((fsnum < 0) || (fsnum >= NORM_FS) || (path[1] != ':')) { if ((fsnum < 0) || (fsnum >= NORM_FS) || (path[1] != ':')) {
if (!GetVirtualSource(path)) ShowPrompt(false, "Invalid path (%s)", path); if (!GetVirtualSource(path) && !IsStoredDrive(path)) ShowPrompt(false, "Invalid path (%s)", path);
return -1; return -1;
} }
return fsnum; return fsnum;
@ -949,6 +950,34 @@ void SortDirStruct(DirStruct* contents) {
} }
} }
// inspired by http://www.geeksforgeeks.org/wildcard-character-matching/
bool MatchName(const char *pattern, const char *path) {
// handling non asterisk chars
for (; *pattern != '*'; pattern++, path++) {
if ((*pattern == '\0') && (*path == '\0')) {
return true; // end reached simultaneously, match found
} else if ((*pattern == '\0') || (*path == '\0')) {
return false; // end reached on only one, failure
} else if ((*pattern != '?') && (tolower(*pattern) != tolower(*path))) {
return false; // chars don't match, failure
}
}
// handling the asterisk (matches one or more chars in path)
if ((*(pattern+1) == '?') || (*(pattern+1) == '*')) {
return false; // stupid user shenanigans, failure
} else if (*path == '\0') {
return false; // asterisk, but end reached on path, failure
} else if (*(pattern+1) == '\0') {
return true; // nothing after the asterisk, match found
} else { // we couldn't really go without recursion here
for (path++; *path != '\0'; path++) {
if (MatchName(pattern + 1, path)) return true;
}
}
return false;
}
bool GetRootDirContentsWorker(DirStruct* contents) { bool GetRootDirContentsWorker(DirStruct* contents) {
static const char* drvname[] = { static const char* drvname[] = {
"SDCARD", "SDCARD",
@ -986,11 +1015,12 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
return contents->n_entries; return contents->n_entries;
} }
bool GetVirtualDirContentsWorker(DirStruct* contents, const char* path) { bool GetVirtualDirContentsWorker(DirStruct* contents, const char* path, const char* pattern) {
if (strchr(path, '/')) return false; // only top level paths if (strchr(path, '/')) return false; // only top level paths
for (u32 n = 0; (n < virtualFileList_size) && (contents->n_entries < MAX_ENTRIES); n++) { for (u32 n = 0; (n < virtualFileList_size) && (contents->n_entries < MAX_ENTRIES); n++) {
VirtualFile vfile; VirtualFile vfile;
DirEntry* entry = &(contents->entry[contents->n_entries]); DirEntry* entry = &(contents->entry[contents->n_entries]);
if (pattern && !MatchName(pattern, virtualFileList[n])) continue;
snprintf(entry->path, 256, "%s/%s", path, virtualFileList[n]); snprintf(entry->path, 256, "%s/%s", path, virtualFileList[n]);
if (!FindVirtualFile(&vfile, entry->path, 0)) continue; if (!FindVirtualFile(&vfile, entry->path, 0)) continue;
entry->name = entry->path + strnlen(path, 256) + 1; entry->name = entry->path + strnlen(path, 256) + 1;
@ -1003,7 +1033,7 @@ bool GetVirtualDirContentsWorker(DirStruct* contents, const char* path) {
return true; // not much we can check here return true; // not much we can check here
} }
bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, bool recursive) { bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const char* pattern, bool recursive) {
DIR pdir; DIR pdir;
FILINFO fno; FILINFO fno;
char* fname = fpath + strnlen(fpath, fnsize - 1); char* fname = fpath + strnlen(fpath, fnsize - 1);
@ -1020,7 +1050,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, bool rec
if (fno.fname[0] == 0) { if (fno.fname[0] == 0) {
ret = true; ret = true;
break; break;
} else { } else if (!pattern || MatchName(pattern, fname)) {
DirEntry* entry = &(contents->entry[contents->n_entries]); DirEntry* entry = &(contents->entry[contents->n_entries]);
strncpy(entry->path, fpath, 256); strncpy(entry->path, fpath, 256);
entry->name = entry->path + (fname - fpath); entry->name = entry->path + (fname - fpath);
@ -1037,7 +1067,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, bool rec
break; break;
} }
if (recursive && (fno.fattrib & AM_DIR)) { if (recursive && (fno.fattrib & AM_DIR)) {
if (!GetDirContentsWorker(contents, fpath, fnsize, recursive)) if (!GetDirContentsWorker(contents, fpath, fnsize, pattern, recursive))
break; break;
} }
} }
@ -1046,7 +1076,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, bool rec
return ret; return ret;
} }
void GetDirContents(DirStruct* contents, const char* path) { void SearchDirContents(DirStruct* contents, const char* path, const char* pattern, bool recursive) {
contents->n_entries = 0; contents->n_entries = 0;
if (!(*path)) { // root directory if (!(*path)) { // root directory
if (!GetRootDirContentsWorker(contents)) if (!GetRootDirContentsWorker(contents))
@ -1060,18 +1090,22 @@ void GetDirContents(DirStruct* contents, const char* path) {
contents->entry->size = 0; contents->entry->size = 0;
contents->n_entries = 1; contents->n_entries = 1;
if (GetVirtualSource(path)) { if (GetVirtualSource(path)) {
if (!GetVirtualDirContentsWorker(contents, path)) if (!GetVirtualDirContentsWorker(contents, path, pattern))
contents->n_entries = 0; contents->n_entries = 0;
} else { } else {
char fpath[256]; // 256 is the maximum length of a full path char fpath[256]; // 256 is the maximum length of a full path
strncpy(fpath, path, 256); strncpy(fpath, path, 256);
if (!GetDirContentsWorker(contents, fpath, 256, false)) if (!GetDirContentsWorker(contents, fpath, 256, pattern, recursive))
contents->n_entries = 0; contents->n_entries = 0;
} }
SortDirStruct(contents); SortDirStruct(contents);
} }
} }
void GetDirContents(DirStruct* contents, const char* path) {
SearchDirContents(contents, path, NULL, false);
}
uint64_t GetFreeSpace(const char* path) uint64_t GetFreeSpace(const char* path)
{ {
DWORD free_clusters; DWORD free_clusters;

View File

@ -90,6 +90,9 @@ bool DirCreate(const char* cpath, const char* dirname);
/** Create a screenshot of the current framebuffer **/ /** Create a screenshot of the current framebuffer **/
void CreateScreenshot(); void CreateScreenshot();
/** Search under a given path **/
void SearchDirContents(DirStruct* contents, const char* path, const char* pattern, bool recursive);
/** Get directory content under a given path **/ /** Get directory content under a given path **/
void GetDirContents(DirStruct* contents, const char* path); void GetDirContents(DirStruct* contents, const char* path);

View File

@ -6,8 +6,9 @@
#include "nand.h" #include "nand.h"
#include "virtual.h" #include "virtual.h"
#include "image.h" #include "image.h"
#include "store.h"
#define VERSION "0.6.2" #define VERSION "0.6.3"
#define N_PANES 2 #define N_PANES 2
#define IMG_DRV "789I" #define IMG_DRV "789I"
@ -544,13 +545,26 @@ u32 GodMode() {
} }
// basic navigation commands // basic navigation commands
if ((pad_state & BUTTON_A) && (curr_entry->type != T_FILE) && (curr_entry->type != T_DOTDOT)) { // one level up if ((pad_state & BUTTON_A) && (curr_entry->type != T_FILE) && (curr_entry->type != T_DOTDOT)) { // for dirs
if (switched) { // search directory
char searchstr[256];
char namestr[20+1];
snprintf(searchstr, 256, "*.*");
TruncateString(namestr, curr_entry->name, 20, 8);
if (ShowStringPrompt(searchstr, 256, "Search %s?\nEnter search below.", namestr)) {
ShowString("Searching path, please wait...");
snprintf(current_path, 256, "Z:");
SearchDirContents(current_dir, curr_entry->path, searchstr, true);
StoreDirContents(current_dir);
}
} else { // one level up
strncpy(current_path, curr_entry->path, 256); strncpy(current_path, curr_entry->path, 256);
GetDirContents(current_dir, current_path); GetDirContents(current_dir, current_path);
if (*current_path && (current_dir->n_entries > 1)) { if (*current_path && (current_dir->n_entries > 1)) {
cursor = 1; cursor = 1;
scroll = 0; scroll = 0;
} else cursor = 0; } else cursor = 0;
}
} else if ((pad_state & BUTTON_A) && (curr_entry->type == T_FILE)) { // process a file } else if ((pad_state & BUTTON_A) && (curr_entry->type == T_FILE)) { // process a file
u32 file_type = IdentifyImage(curr_entry->path); u32 file_type = IdentifyImage(curr_entry->path);
bool injectable = (clipboard->n_entries == 1) && bool injectable = (clipboard->n_entries == 1) &&

View File

@ -6,7 +6,7 @@
#include "nand.h" #include "nand.h"
#include "image.h" #include "image.h"
#define NAND_BUFFER ((u8*)0x21300000) #define NAND_BUFFER ((u8*)0x21400000)
#define NAND_BUFFER_SIZE (0x100000) // must be multiple of 0x200 #define NAND_BUFFER_SIZE (0x100000) // must be multiple of 0x200
#define NAND_MIN_SECTORS ((GetUnitPlatform() == PLATFORM_N3DS) ? 0x26C000 : 0x1D7800) #define NAND_MIN_SECTORS ((GetUnitPlatform() == PLATFORM_N3DS) ? 0x26C000 : 0x1D7800)

View File

@ -440,7 +440,7 @@ bool ShowInputPrompt(char* inputstr, u32 max_size, u32 resize, const char* alpha
} }
bool ShowStringPrompt(char* inputstr, u32 max_size, const char *format, ...) { bool ShowStringPrompt(char* inputstr, u32 max_size, const char *format, ...) {
const char* alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz(){}[]'`^,~!@#$%&0123456789=+-_."; const char* alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz(){}[]'`^,~*?!@#$%&0123456789=+-_.";
bool ret = false; bool ret = false;
va_list va; va_list va;