diff --git a/arm9/source/filesys/fsdrive.c b/arm9/source/filesys/fsdrive.c index 7fe3881..b4c7486 100644 --- a/arm9/source/filesys/fsdrive.c +++ b/arm9/source/filesys/fsdrive.c @@ -117,7 +117,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const ch if (fvx_opendir(&pdir, fpath) != FR_OK) return false; - (fname++)[0] = '/'; + if (*(fname-1) != '/') *(fname++) = '/'; while (fvx_readdir(&pdir, &fno) == FR_OK) { if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0)) diff --git a/arm9/source/filesys/fsutil.c b/arm9/source/filesys/fsutil.c index e6c868c..e9a1f8b 100644 --- a/arm9/source/filesys/fsutil.c +++ b/arm9/source/filesys/fsutil.c @@ -719,11 +719,16 @@ bool PathAttr(const char* path, u8 attr, u8 mask) { return (f_chmod(path, attr, mask) == FR_OK); } -bool FileSelector(char* result, const char* text, const char* path, const char* pattern, bool hide_ext, bool no_dirs) { +bool FileSelector(char* result, const char* text, const char* path, const char* pattern, u32 flags) { DirStruct* contents = (DirStruct*) (void*) TEMP_BUFFER; char path_local[256]; strncpy(path_local, path, 256); + bool no_dirs = flags & NO_DIRS; + bool no_files = flags & NO_FILES; + bool hide_ext = flags & HIDE_EXT; + bool select_dirs = flags & SELECT_DIRS; + // main loop while (true) { u32 n_found = 0; @@ -737,7 +742,7 @@ bool FileSelector(char* result, const char* text, const char* path, const char* for (; pos < contents->n_entries; pos++) { DirEntry* entry = &(contents->entry[pos]); if (((entry->type == T_DIR) && no_dirs) || - ((entry->type == T_FILE) && (fvx_match_name(entry->name, pattern) != FR_OK)) || + ((entry->type == T_FILE) && (no_files || (fvx_match_name(entry->name, pattern) != FR_OK))) || (entry->type == T_DOTDOT) || (strncmp(entry->name, "._", 2) == 0)) continue; if (n_opt == _MAX_FS_OPT) { @@ -765,8 +770,12 @@ bool FileSelector(char* result, const char* text, const char* path, const char* if (!user_select) return false; DirEntry* res_local = res_entry[user_select-1]; if (res_local && (res_local->type == T_DIR)) { // selected dir - if (FileSelector(result, text, res_local->path, pattern, hide_ext, no_dirs)) + if (select_dirs) { + strncpy(result, res_local->path, 256); return true; + } else if (FileSelector(result, text, res_local->path, pattern, flags)) { + return true; + } break; } else if (res_local && (res_local->type == T_FILE)) { // selected file strncpy(result, res_local->path, 256); diff --git a/arm9/source/filesys/fsutil.h b/arm9/source/filesys/fsutil.h index f1d536b..34a48ae 100644 --- a/arm9/source/filesys/fsutil.h +++ b/arm9/source/filesys/fsutil.h @@ -13,6 +13,13 @@ #define SKIP_ALL (1UL<<7) #define OVERWRITE_ALL (1UL<<8) +// file selector flags +#define NO_DIRS (1UL<<0) +#define NO_FILES (1UL<<1) +#define HIDE_EXT (1UL<<2) +#define SELECT_DIRS (1UL<<3) + + /** Return total size of SD card **/ uint64_t GetSDCardSize(); @@ -77,7 +84,7 @@ bool PathRename(const char* path, const char* newname); bool PathAttr(const char* path, u8 attr, u8 mask); /** Select a file **/ -bool FileSelector(char* result, const char* text, const char* path, const char* pattern, bool hide_ext, bool no_dirs); +bool FileSelector(char* result, const char* text, const char* path, const char* pattern, u32 flags); /** Create a screenshot of the current framebuffer **/ void CreateScreenshot(); diff --git a/arm9/source/filesys/support.c b/arm9/source/filesys/support.c index 7e7a544..348c0da 100644 --- a/arm9/source/filesys/support.c +++ b/arm9/source/filesys/support.c @@ -67,9 +67,9 @@ bool CheckSupportDir(const char* dname) return GetSupportDir(path, dname); } -bool FileSelectorSupport(char* result, const char* text, const char* dname, const char* pattern, bool hide_ext, bool no_dirs) +bool FileSelectorSupport(char* result, const char* text, const char* dname, const char* pattern) { char path[256]; if (!GetSupportDir(path, dname)) return false; - return FileSelector(result, text, path, pattern, hide_ext, no_dirs); + return FileSelector(result, text, path, pattern, HIDE_EXT); } diff --git a/arm9/source/filesys/support.h b/arm9/source/filesys/support.h index 4ef5d26..5f074e8 100644 --- a/arm9/source/filesys/support.h +++ b/arm9/source/filesys/support.h @@ -10,4 +10,4 @@ bool CheckSupportFile(const char* fname); size_t LoadSupportFile(const char* fname, void* buffer, size_t max_len); bool CheckSupportDir(const char* fpath); -bool FileSelectorSupport(char* result, const char* text, const char* dname, const char* pattern, bool hide_ext, bool no_dirs); +bool FileSelectorSupport(char* result, const char* text, const char* dname, const char* pattern); diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 30db727..3ac628b 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -1853,9 +1853,9 @@ u32 GodMode(int entrypoint) { godmode9 = true; } else if (user_select == 2) { bootloader = true; - } else if ((user_select == 3) && (FileSelectorSupport(loadpath, "Bootloader payloads menu.\nSelect payload:", PAYLOADS_DIR, "*.firm", true, false))) { + } else if ((user_select == 3) && (FileSelectorSupport(loadpath, "Bootloader payloads menu.\nSelect payload:", PAYLOADS_DIR, "*.firm"))) { BootFirmHandler(loadpath, false, false); - } else if ((user_select == 4) && (FileSelectorSupport(loadpath, "Bootloader scripts menu.\nSelect script:", SCRIPTS_DIR, "*.gm9", true, false))) { + } else if ((user_select == 4) && (FileSelectorSupport(loadpath, "Bootloader scripts menu.\nSelect script:", SCRIPTS_DIR, "*.gm9"))) { ExecuteGM9Script(loadpath); } else if (user_select == 5) { exit_mode = GODMODE_EXIT_POWEROFF; @@ -2252,12 +2252,12 @@ u32 GodMode(int entrypoint) { (user_select != poweroff) && (user_select != reboot)) { char loadpath[256]; if ((user_select == more) && (HomeMoreMenu(current_path) == 0)) break; // more... menu - else if ((user_select == scripts) && (FileSelectorSupport(loadpath, "HOME scripts... menu.\nSelect script:", SCRIPTS_DIR, "*.gm9", true, false))) { + else if ((user_select == scripts) && (FileSelectorSupport(loadpath, "HOME scripts... menu.\nSelect script:", SCRIPTS_DIR, "*.gm9"))) { ExecuteGM9Script(loadpath); GetDirContents(current_dir, current_path); ClearScreenF(true, true, COLOR_STD_BG); break; - } else if ((user_select == payloads) && (FileSelectorSupport(loadpath, "HOME payloads... menu.\nSelect payload:", PAYLOADS_DIR, "*.firm", true, false))) { + } else if ((user_select == payloads) && (FileSelectorSupport(loadpath, "HOME payloads... menu.\nSelect payload:", PAYLOADS_DIR, "*.firm"))) { BootFirmHandler(loadpath, false, false); } } @@ -2326,7 +2326,7 @@ u32 ScriptRunner(int entrypoint) { ExecuteGM9Script(NULL); } else if (PathExist("V:/" VRAM0_SCRIPTS)) { char loadpath[256]; - if (FileSelector(loadpath, FLAVOR " scripts menu.\nSelect script:", "V:/" VRAM0_SCRIPTS, "*.gm9", true, false)) + if (FileSelector(loadpath, FLAVOR " scripts menu.\nSelect script:", "V:/" VRAM0_SCRIPTS, "*.gm9", HIDE_EXT)) ExecuteGM9Script(loadpath); } else ShowPrompt(false, "Compiled as script autorunner\nbut no script provided.\n \nDerp!"); diff --git a/arm9/source/utils/scripting.c b/arm9/source/utils/scripting.c index ddd9d5e..e9618fd 100644 --- a/arm9/source/utils/scripting.c +++ b/arm9/source/utils/scripting.c @@ -70,6 +70,7 @@ typedef enum { CMD_ID_ASK, CMD_ID_INPUT, CMD_ID_FILESEL, + CMD_ID_DIRSEL, CMD_ID_SET, CMD_ID_STRSPLIT, CMD_ID_STRREP, @@ -127,6 +128,7 @@ Gm9ScriptCmd cmd_list[] = { { CMD_ID_ASK , "ask" , 1, 0 }, { CMD_ID_INPUT , "input" , 2, 0 }, { CMD_ID_FILESEL , "filesel" , 3, _FLG('d') }, + { CMD_ID_DIRSEL , "dirsel" , 3, 0 }, { CMD_ID_SET , "set" , 2, 0 }, { CMD_ID_STRSPLIT, "strsplit", 3, _FLG('b') | _FLG('f')}, { CMD_ID_STRREP , "strrep" , 3, 0 }, @@ -815,7 +817,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "var fail"); } } - else if (id == CMD_ID_FILESEL) { + else if ((id == CMD_ID_FILESEL) || (id == CMD_ID_DIRSEL)) { char choice[_VAR_CNT_LEN] = { 0 }; char* var = get_var(argv[2], NULL); strncpy(choice, var, _VAR_CNT_LEN); @@ -829,10 +831,14 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { } else if (!npattern) { ret = false; if (err_str) snprintf(err_str, _ERR_STR_LEN, "invalid path"); - } else { + } else if (id == CMD_ID_FILESEL) { + u32 flags_ext = (flags & _FLG('d')) ? 0 : NO_DIRS; *(npattern++) = '\0'; - ret = FileSelector(choice, argv[0], path, npattern, false, !(flags & _FLG('d'))); + ret = FileSelector(choice, argv[0], path, npattern, flags_ext); if (err_str) snprintf(err_str, _ERR_STR_LEN, "fileselect abort"); + } else { + ret = FileSelector(choice, argv[0], path, npattern, NO_FILES | SELECT_DIRS); + if (err_str) snprintf(err_str, _ERR_STR_LEN, "dirselect abort"); } if (ret) { diff --git a/resources/sample/HelloScript.gm9 b/resources/sample/HelloScript.gm9 index 091c996..bef6fee 100644 --- a/resources/sample/HelloScript.gm9 +++ b/resources/sample/HelloScript.gm9 @@ -107,7 +107,12 @@ echo $[TESTREP] # The path is stored inside a variable, and the selection can be limited via wildcards # -d / --include_dirs allows to browse folders and select files inside filesel "Please select a file" 0:/*.* SELFILE -echo "You selected $[SELFILE]\nWe'll do nothing with that :)." + +# 'dirsel' COMMAND +# The 'dirsel' command works identically to the 'filesel' command, but allows selecting a dir +# Note that a final slash ('/') and no wildcard pattern is expected here. +dirsel "Now, select a dir" 0:/ SELDIR +echo "You selected $[SELFILE]\nand $[SELDIR]\nWe'll do nothing with either :)." # 'allow' COMMAND # typically used at the beginning of a script, prompts to allow writes to the location given in the argument