From 416bc2159c66f39cbde0ebbcfa2a599e4ae6064c Mon Sep 17 00:00:00 2001 From: "Leo C." Date: Fri, 19 Jul 2024 09:24:15 +0200 Subject: [PATCH] wildcards for ls command (*, ?) --- avr/cmd_fat.c | 337 ++++++++++++++++++++----------------------- include/avr/ffconf.h | 2 +- 2 files changed, 160 insertions(+), 179 deletions(-) diff --git a/avr/cmd_fat.c b/avr/cmd_fat.c index 8477fc2..063ebfb 100644 --- a/avr/cmd_fat.c +++ b/avr/cmd_fat.c @@ -8,6 +8,7 @@ * FAT filesystem commands */ +#include "common.h" #include "cmd_fat.h" #include uint32_t fat_time(const struct tm * timeptr); @@ -22,13 +23,18 @@ uint32_t fat_time(const struct tm * timeptr); #include "env.h" #define DEBUG_FA 0 /* set to 1 to debug */ +#define DEBUG_LS 1 /* set to 1 to debug */ +#define DEBUG_RM 1 /* set to 1 to debug */ #define debug_fa(fmt, args...) \ debug_cond(DEBUG_FA, fmt, ##args) +#define debug_ls(fmt, args...) \ + debug_cond(DEBUG_LS, fmt, ##args) +#define debug_rm(fmt, args...) \ + debug_cond(DEBUG_RM, fmt, ##args) -/* TODO: use memory size test function (detect_ramsize() in cmd_loadihex.c) */ -/* TODO: detect_ramsize() should be moved to z80-if.c */ +/* TODO: use memory size test function (z80_memsize_detect() ) */ #define MAX_MEMORY CONFIG_SYS_RAMSIZE_MAX #define BUFFER_SIZE FF_MAX_SS #define PATH_MAX CONFIG_SYS_MAX_PATHLEN @@ -38,12 +44,8 @@ uint32_t fat_time(const struct tm * timeptr); * Multible (fat) partitions per physical drive are not supported, * but we have up to 2 sdcard slots. */ -FATFS FatFs0; -FATFS FatFs1; - -command_ret_t command_ret; -char *cmdname; - +static FATFS FatFs0; +static FATFS FatFs1; void setup_fatfs(void) { @@ -63,7 +65,8 @@ DWORD get_fattime (void) } -static bool check_abort(void) +static +bool check_abort(void) { bool ret = ctrlc(); @@ -98,13 +101,13 @@ static const FLASH char * const FLASH rc_strings[] = { }; - const FLASH char * fat_rctostr(FRESULT rc) { return rc < ARRAY_SIZE(rc_strings) ? rc_strings[rc] : PSTR(" Unknown Error"); } -static void swirl(void) +static +void swirl(void) { static const FLASH char swirlchar[] = { '-','\\','|','/' }; static uint_fast8_t cnt; @@ -118,83 +121,6 @@ static void swirl(void) } } -typedef struct { - char *p_end; /* pointer to NULL at end of path */ - char p_path[PATH_MAX + 1]; /* pointer to the start of a path */ -} PATH_T; - - -static char *path_skip_heading(char *p) -{ - if (isdigit(p[0]) && p[1] == ':') { - p += 2; - } else { - char *q = p; - if (*q++ == '.') { - if (*q == '.') - ++q; - if (*q == '\0' || *q == '/') - p = q; - } - return p; - } - if (*p == '/') - ++p; - - return p; -} - -static void strip_trailing_slash(PATH_T *p) -{ - char *beg = path_skip_heading(p->p_path); - char *end = p->p_end; - - while (end > beg && end[-1] == '/') - *--end = '\0'; - - p->p_end =end; -} - -/* - * Move specified string into path. Convert "" to "." to handle BSD - * semantics for a null path. Strip trailing slashes. - */ -static PATH_T *path_setup(char *string) -{ - if (strlen(string) > PATH_MAX) { - cmd_error(0, 0, PSTR("'%s': Name too long"), string); - return NULL; - } - - PATH_T *p = (PATH_T *) malloc(sizeof *p); - if (p == NULL) { - cmd_error(0, ENOMEM, NULL); - return NULL; - } - - strcpy(p->p_path, string); - size_t len = strlen(string); - if (len > 1 && p->p_path[1] == ':' && p->p_path[2] != '/') { - if (len < PATH_MAX) { - memmove(p->p_path+3, p->p_path+2, len-1); - p->p_path[2] = '/'; - len += 1; - } else { - cmd_error(0, ENOMEM, NULL); - return NULL; - } - } - - p->p_end = p->p_path + len; - if (p->p_path == p->p_end) { - *p->p_end++ = '.'; - *p->p_end = '\0'; - } - - strip_trailing_slash(p); - return p; -} - /* * pwd - Print current directory of the current drive. * @@ -202,23 +128,15 @@ static PATH_T *path_setup(char *string) command_ret_t do_pwd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED) { FRESULT res; - char *buf; + TCHAR buf[PATH_MAX]; - buf = (char *) malloc(PATH_MAX); - if (buf == NULL) - cmd_error(CMD_RET_FAILURE, ENOMEM, NULL); - *buf = '\0'; res = f_getcwd(buf, PATH_MAX); /* Get current directory path */ - debug_fa("### f_getcwd(): buf: '%s', res: %d\n", buf, res); - - if (res == FR_OK) { - puts(buf); - } - free(buf); if (res != FR_OK) cmd_error(CMD_RET_FAILURE, res, NULL); + puts(buf); + return CMD_RET_SUCCESS; } @@ -229,30 +147,23 @@ command_ret_t do_pwd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc */ command_ret_t do_cd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[]) { - char *arg; + TCHAR *path; FRESULT res = FR_OK; if (argc < 2) { - arg = getenv_str(PSTR(ENV_HOME)); - if (arg == NULL) { - cmd_error(CMD_RET_FAILURE, 0, PSTR("\"%S\" is not set"), PSTR(ENV_HOME)); + path = getenv_str(PSTR(ENV_HOME)); + if (path == NULL) { + cmd_error(CMD_RET_FAILURE, 0, PSTR("\"%S\" not set"), PSTR(ENV_HOME)); } } else - arg = argv[1]; + path = argv[1]; - PATH_T *path = path_setup(arg); - if (path == NULL) - return CMD_RET_FAILURE; + if (strlen(path) > 1 && path[1] == ':') + res = f_chdrive(path); + + if (res == FR_OK) + res = f_chdir(path); - if (strlen(path->p_path) > 1 && path->p_path[1] == ':') { - res = f_chdrive(path->p_path); - debug_fa("### f_chdrive(): p_path: '%s', res: %d\n", path->p_path, res); - } - if (res == FR_OK) { - res = f_chdir(path->p_path); - debug_fa("### f_chdir(): p_path: '%s', res: %d\n", path->p_path, res); - } - free(path); if (res != FR_OK) cmd_error(CMD_RET_FAILURE, res, NULL); @@ -260,6 +171,37 @@ command_ret_t do_cd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, } +static +void print_dirent(FILINFO *f) +{ + printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"), + (f->fattrib & AM_DIR) ? 'D' : '-', + (f->fattrib & AM_RDO) ? 'R' : '-', + (f->fattrib & AM_HID) ? 'H' : '-', + (f->fattrib & AM_SYS) ? 'S' : '-', + (f->fattrib & AM_ARC) ? 'A' : '-', + (f->fdate >> 9) + 1980, (f->fdate >> 5) & 15, f->fdate & 31, + (f->ftime >> 11), (f->ftime >> 5) & 63, + f->fsize, f->fname); +} + +char *path_split(char *p) +{ + if (isdigit(p[0]) && (p[1] == ':')) + p += 2; + + char *ps = strrchr(p, '/'); + if (ps) { + if (ps == p) { + ++ps; + memmove(ps+1, ps, strlen(ps)+1); + } + *ps++ = '\0'; + } + + return ps; +} + /* * ls path - Directory listing * @@ -267,100 +209,134 @@ command_ret_t do_cd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, command_ret_t do_ls(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[]) { FATFS *fs; - DIR Dir; /* Directory object */ - FILINFO Finfo; + DIR dir; /* Directory object */ + FILINFO finfo; unsigned long p1; unsigned int s1, s2; FRESULT res = FR_OK; - char *buf; + char buf[PATH_MAX]; + char *path = buf; + char *pattern; - buf = (char *) malloc(PATH_MAX); - if (buf == NULL) - cmd_error(CMD_RET_FAILURE, ENOMEM, NULL); + memset(buf, 0, PATH_MAX); + if (argc < 2) { + buf[0] = '.'; + } else { + strncpy(path, argv[1], PATH_MAX-1); + } + pattern = path_split(path); + debug_ls("### path, pattern: '%s', '%s'\n", path[0] ? path : "", pattern ? pattern : ""); - if (argc < 2) - res = f_getcwd(buf, PATH_MAX); /* Get current directory path */ - else - strncpy(buf, argv[1], PATH_MAX); + if (pattern == NULL) { + res = f_opendir(&dir, path); + if (res == FR_NO_PATH || res == FR_INVALID_NAME) { + pattern = path; + path = "."; + } else if (res != FR_OK) { + cmd_error(CMD_RET_FAILURE, res, PSTR("'%s'"), path); + } + } + debug_ls("### path, pattern: '%s', '%s'\n", path, pattern ? pattern : ""); - if (res == FR_OK) - res = f_opendir(&Dir, buf); - if (res != FR_OK) { - free(buf); - cmd_error(CMD_RET_FAILURE, res, NULL); - } + if (pattern == NULL || *pattern == '\0') + pattern = "*"; + + debug_ls("### path, pattern: '%s', '%s'\n", path, pattern ? pattern : ""); + + res = f_findfirst(&dir, &finfo, path, pattern); p1 = s1 = s2 = 0; for(;;) { - res = f_readdir(&Dir, &Finfo); - if ((res != FR_OK) || !Finfo.fname[0]) + if (res != FR_OK) + cmd_error(CMD_RET_FAILURE, res, NULL); + if (!finfo.fname[0]) break; - if (Finfo.fattrib & AM_DIR) { + if (finfo.fattrib & AM_DIR) { s2++; } else { - s1++; p1 += Finfo.fsize; + s1++; p1 += finfo.fsize; } - printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"), - (Finfo.fattrib & AM_DIR) ? 'D' : '-', - (Finfo.fattrib & AM_RDO) ? 'R' : '-', - (Finfo.fattrib & AM_HID) ? 'H' : '-', - (Finfo.fattrib & AM_SYS) ? 'S' : '-', - (Finfo.fattrib & AM_ARC) ? 'A' : '-', - (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15, Finfo.fdate & 31, - (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63, - Finfo.fsize, Finfo.fname); + print_dirent(&finfo); if (check_abort()) break; + res = f_findnext(&dir, &finfo); } if (res == FR_OK) { printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2); - if (f_getfree(buf, (DWORD*)&p1, &fs) == FR_OK) + if (f_getfree(path, (DWORD*)&p1, &fs) == FR_OK) printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2); } - free(buf); if (res) cmd_error(CMD_RET_FAILURE, res, NULL); return CMD_RET_SUCCESS; } -#if 0 -static -FRESULT mkpath(TCHAR *path) + +/* + * tst path - for debugging: test access with different functions + * + */ +command_ret_t do_tst(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[]) { - /* TODO: */ - (void) path; - FILINFO fd - TCHAR *p, *q; - FRESULT ret; - - res = f_stat (path, &fd) - - p = strchr(path, ':'); - if (p == NULL || *++p == '\0' || *p++ != '/') - return FR_OK; - - while ((q = strchr(p, '/')) != NULL) { - *q = '\0'; - ret = f_mkdir(path); - *q = '/'; - if (ret != FR_OK && ret != FR_EXIST) - return ret; - p = q + 1; + DIR Dir; /* Directory object */ + FILINFO finfo; + FRESULT res = FR_OK; + char *path = ""; + char *pattern = "*"; + + printf_P(PSTR("sizeof DIR: %u, sizeof FIL: %u\n"), sizeof (DIR), sizeof (FILINFO)); + + char * buf = (char *) malloc(BUFFER_SIZE); + if (buf == NULL) { + cmd_error(CMD_RET_FAILURE, ENOMEM, NULL); } + res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */ - return FR_OK; + if (!res) { + printf_P(PSTR("cwd: '%s'\n"), buf); + } + free(buf); + if (res) + cmd_error(CMD_RET_FAILURE, res, NULL); + + if (argc > 1) + path = argv[1]; + if (argc > 2) + pattern = argv[2]; + + printf_P(PSTR("arg: '%s' '%s'\n"), path, pattern); + printf_P(PSTR("==== f_stat: ")); + res = f_stat(path, &finfo); + cmd_error(0, res, NULL); + if (res == FR_OK) { + print_dirent(&finfo); + } + + printf_P(PSTR("==== f_findfirst: ")); + res = f_findfirst(&Dir, &finfo, path, pattern); /* Start to search for files */ + cmd_error(CMD_RET_FAILURE, res, NULL); + if (res == FR_OK) { + print_dirent(&finfo); + } + f_closedir(&Dir); + + printf_P(PSTR("==== f_opendir: ")); + res = f_opendir(&Dir, path); + cmd_error(CMD_RET_FAILURE, res, NULL); + f_closedir(&Dir); + + return CMD_RET_SUCCESS; } -#endif /* Work register for fs command */ struct stat_dat_s { DWORD AccSize; WORD AccFiles, AccDirs; - FILINFO Finfo; + FILINFO finfo; }; static @@ -378,12 +354,12 @@ FRESULT scan_files ( swirl(); if (res == FR_OK) { i = strlen(path); - while (((res = f_readdir(&dirs, &statp->Finfo)) == FR_OK) && - statp->Finfo.fname[0]) { - if (FF_FS_RPATH && statp->Finfo.fname[0] == '.') + while (((res = f_readdir(&dirs, &statp->finfo)) == FR_OK) && + statp->finfo.fname[0]) { + if (FF_FS_RPATH && statp->finfo.fname[0] == '.') continue; - fn = statp->Finfo.fname; - if (statp->Finfo.fattrib & AM_DIR) { + fn = statp->finfo.fname; + if (statp->finfo.fattrib & AM_DIR) { statp->AccDirs++; path[i] = '/'; strcpy(path+i+1, fn); @@ -394,7 +370,7 @@ FRESULT scan_files ( } else { //printf_P(PSTR("%s/%s\n"), path, fn); statp->AccFiles++; - statp->AccSize += statp->Finfo.fsize; + statp->AccSize += statp->finfo.fsize; } if (check_abort()) { res = 255; @@ -612,6 +588,11 @@ CMD_TBL_ITEM( "Directory listing", "path" ), +CMD_TBL_ITEM( + tst, 3, CTBL_DBG|CTBL_RPT, do_tst, + "FatFS test function", + "[path [pattern]]" +), CMD_TBL_ITEM( load, 5, 0, do_rw, "load binary file from a dos filesystem", diff --git a/include/avr/ffconf.h b/include/avr/ffconf.h index 4e89916..9e33e9f 100644 --- a/include/avr/ffconf.h +++ b/include/avr/ffconf.h @@ -25,7 +25,7 @@ / 3: f_lseek() function is removed in addition to 2. */ -#define FF_USE_FIND 0 +#define FF_USE_FIND 1 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ -- 2.39.2