diff --git a/scp.c b/scp.c index d2b313b1..6b4668b1 100644 --- a/scp.c +++ b/scp.c @@ -6184,156 +6184,6 @@ t_stat pwd_cmd (int32 flg, CONST char *cptr) return show_cmd (0, "DEFAULT"); } -#if defined (_WIN32) - -t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context) -{ -HANDLE hFind; -WIN32_FIND_DATAA File; -struct stat filestat; -char WildName[PATH_MAX + 1]; - -strlcpy (WildName, cptr, sizeof(WildName)); -cptr = WildName; -sim_trim_endspc (WildName); -if ((hFind = FindFirstFileA (cptr, &File)) != INVALID_HANDLE_VALUE) { - t_int64 FileSize; - char DirName[PATH_MAX + 1], FileName[PATH_MAX + 1]; - char *c; - const char *backslash = strchr (cptr, '\\'); - const char *slash = strchr (cptr, '/'); - const char *pathsep = (backslash && slash) ? MIN (backslash, slash) : (backslash ? backslash : slash); - - GetFullPathNameA(cptr, sizeof(DirName), DirName, (char **)&c); - c = strrchr (DirName, '\\'); - *c = '\0'; /* Truncate to just directory path */ - if (!pathsep || (!strcmp (slash, "/*"))) /* Separator wasn't mentioned? */ - pathsep = "\\"; /* Default to Windows backslash */ - if (*pathsep == '/') { /* If slash separator? */ - while ((c = strchr (DirName, '\\'))) - *c = '/'; /* Convert backslash to slash */ - } - sprintf (&DirName[strlen (DirName)], "%c", *pathsep); - do { - FileSize = (((t_int64)(File.nFileSizeHigh)) << 32) | File.nFileSizeLow; - sprintf (FileName, "%s%s", DirName, File.cFileName); - stat (FileName, &filestat); - entry (DirName, File.cFileName, FileSize, &filestat, context); - } while (FindNextFile (hFind, &File)); - FindClose (hFind); - } -else - return SCPE_ARG; -return SCPE_OK; -} - -#else /* !defined (_WIN32) */ - -#if defined (HAVE_GLOB) -#include -#else /* !defined (HAVE_GLOB) */ -#include -#if defined (HAVE_FNMATCH) -#include -#endif -#endif /* defined (HAVE_GLOB) */ - -t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context) -{ -#if defined (HAVE_GLOB) -glob_t paths; -#else -DIR *dir; -#endif -struct stat filestat; -char *c; -char DirName[PATH_MAX + 1], WholeName[PATH_MAX + 1], WildName[PATH_MAX + 1]; - -memset (DirName, 0, sizeof(DirName)); -memset (WholeName, 0, sizeof(WholeName)); -strlcpy (WildName, cptr, sizeof(WildName)); -cptr = WildName; -sim_trim_endspc (WildName); -if ((*cptr != '/') || (0 == memcmp (cptr, "./", 2)) || (0 == memcmp (cptr, "../", 3))) { - sim_getcwd (WholeName, sizeof (WholeName)-1); - strlcat (WholeName, "/", sizeof (WholeName)); - strlcat (WholeName, cptr, sizeof (WholeName)); - sim_trim_endspc (WholeName); - } -else - strlcpy (WholeName, cptr, sizeof (WholeName)); -while ((c = strstr (WholeName, "/./"))) - memmove (c + 1, c + 3, 1 + strlen (c + 3)); -while ((c = strstr (WholeName, "//"))) - memmove (c + 1, c + 2, 1 + strlen (c + 2)); -while ((c = strstr (WholeName, "/../"))) { - char *c1; - c1 = c - 1; - while ((c1 >= WholeName) && (*c1 != '/')) - c1 = c1 - 1; - memmove (c1, c + 3, 1 + strlen (c + 3)); - while (0 == memcmp (WholeName, "/../", 4)) - memmove (WholeName, WholeName+3, 1 + strlen (WholeName+3)); - } -c = strrchr (WholeName, '/'); -if (c) { - memmove (DirName, WholeName, 1+c-WholeName); - DirName[1+c-WholeName] = '\0'; - } -else { - sim_getcwd (WholeName, sizeof (WholeName)-1); - } -cptr = WholeName; -#if defined (HAVE_GLOB) -memset (&paths, 0, sizeof (paths)); -if (0 == glob (cptr, 0, NULL, &paths)) { -#else -dir = opendir(DirName[0] ? DirName : "/."); -if (dir) { - struct dirent *ent; -#endif - t_offset FileSize; - char FileName[PATH_MAX + 1]; - const char *MatchName = 1 + strrchr (cptr, '/'); - char *p_name; - struct tm *local; -#if defined (HAVE_GLOB) - size_t i; -#endif - -#if defined (HAVE_GLOB) - for (i=0; id_name, 0)) - continue; -#else - /* only match exact name without fnmatch support */ - if (strcmp(MatchName, ent->d_name) != 0) - continue; -#endif - sprintf (FileName, "%s%s", DirName, ent->d_name); -#endif - p_name = FileName + strlen (DirName); - memset (&filestat, 0, sizeof (filestat)); - (void)stat (FileName, &filestat); - FileSize = (t_offset)((filestat.st_mode & S_IFDIR) ? 0 : sim_fsize_name_ex (FileName)); - entry (DirName, p_name, FileSize, &filestat, context); - } -#if defined (HAVE_GLOB) - globfree (&paths); -#else - closedir (dir); -#endif - } -else - return SCPE_ARG; -return SCPE_OK; -} -#endif /* !defined(_WIN32) */ - typedef struct { char LastDir[PATH_MAX + 1]; t_offset TotalBytes; @@ -6404,24 +6254,31 @@ t_stat dir_cmd (int32 flg, CONST char *cptr) DIR_CTX dir_state; t_stat r; char WildName[PATH_MAX + 1]; - +struct stat filestat; memset (&dir_state, 0, sizeof (dir_state)); strlcpy (WildName, cptr, sizeof(WildName)); cptr = WildName; sim_trim_endspc (WildName); if (*cptr == '\0') - cptr = "./*"; + strlcpy (WildName, ".", sizeof (WildName)); else { - struct stat filestat; - - if ((!stat (WildName, &filestat)) && (filestat.st_mode & S_IFDIR)) - strlcat (WildName, "/*", sizeof (WildName)); + if ((WildName[strlen (WildName) - 1] == '/') || + (WildName[strlen (WildName) - 1] == '\\')) + WildName[strlen (WildName) - 1] = '\0'; } +if ((!stat (WildName, &filestat)) && (filestat.st_mode & S_IFDIR)) + strlcat (WildName, "/*", sizeof (WildName)); r = sim_dir_scan (cptr, sim_dir_entry, &dir_state); sim_dir_entry (NULL, NULL, 0, NULL, &dir_state); /* output summary */ -if (r != SCPE_OK) - return sim_messagef (SCPE_ARG, "File Not Found\n"); +if (r != SCPE_OK) { + char *cp = sim_filepath_parts (WildName, "p"); + + sim_printf ("\n Directory of %s\n\n", cp); + sim_printf ("File Not Found\n\n"); + free (cp); + return SCPE_OK; + } return r; } diff --git a/scp.h b/scp.h index b7b00bd7..84deee6f 100644 --- a/scp.h +++ b/scp.h @@ -230,12 +230,6 @@ size_t sim_strlcpy (char *dst, const char *src, size_t size); #ifndef strcasecmp #define strcasecmp(str1, str2) sim_strcasecmp ((str1), (str2)) #endif -typedef void (*DIR_ENTRY_CALLBACK)(const char *directory, - const char *filename, - t_offset FileSize, - const struct stat *filestat, - void *context); -t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context); CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st); CONST char *get_sim_sw (CONST char *cptr); const char *put_switches (char *buf, size_t bufsize, uint32 sw); diff --git a/sim_fio.c b/sim_fio.c index 389c0c27..ae03283f 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -71,6 +71,13 @@ t_bool sim_toffset_64; /* Large File (>2GB) file I/O Support availa #undef fputc #endif +#ifndef MAX +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#endif + /* OS-independent, endian independent binary I/O package For consistency, all binary data read and written by the simulator @@ -737,16 +744,16 @@ return getcwd (buf, buf_size); /* * Parsing and expansion of file names. * - * %~I% - expands the value of %I% removing any surrounding quotes (") - * %~fI% - expands the value of %I% to a fully qualified path name - * %~pI% - expands the value of %I% to a path only - * %~nI% - expands the value of %I% to a file name only - * %~xI% - expands the value of %I% to a file extension only + * %~I% - expands filepath value removing any surrounding quotes (" or ') + * %~fI% - expands filepath value to a fully qualified path name + * %~pI% - expands filepath value to a path only + * %~nI% - expands filepath value to a file name only + * %~xI% - expands filepath value to a file extension only * * The modifiers can be combined to get compound results: * - * %~pnI% - expands the value of %I% to a path and name only - * %~nxI% - expands the value of %I% to a file name and extension only + * %~pnI% - expands filepath value to a path and name only + * %~nxI% - expands filepath value to a file name and extension only * * In the above example above %I% can be replaced by other * environment variables or numeric parameters to a DO command @@ -804,25 +811,34 @@ else { } while ((c = strchr (fullpath, '\\'))) /* standardize on / directory separator */ *c = '/'; +if ((fullpath[1] == ':') && islower (fullpath[0])) + fullpath[0] = toupper (fullpath[0]); while ((c = strstr (fullpath + 1, "//"))) /* strip out redundant / characters (leaving the option for a leading //) */ memmove (c, c + 1, 1 + strlen (c + 1)); while ((c = strstr (fullpath, "/./"))) /* strip out irrelevant /./ sequences */ memmove (c, c + 2, 1 + strlen (c + 2)); while ((c = strstr (fullpath, "/../"))) { /* process up directory climbing */ - char *cl = c -1; + char *cl = c - 1; while ((*cl != '/') && (cl > fullpath)) --cl; - if (*cl == '/') - memmove (cl, c + 3, 1 + strlen (c + 3)); + if ((cl <= fullpath) || /* Digest Leading /../ sequences */ + ((fullpath[1] == ':') && (c == fullpath + 2))) + memmove (c, c + 3, 1 + strlen (c + 3)); /* and removing intervening elements */ else - break; + if (*cl == '/') + memmove (cl, c + 3, 1 + strlen (c + 3));/* and removing intervening elements */ + else + break; } name = 1 + strrchr (fullpath, '/'); ext = strrchr (name, '.'); if (ext == NULL) ext = name + strlen (name); -for (p = parts, tot_size = 0; *p; p++) { +tot_size = 0; +if (*parts == '\0') /* empty part specifier means strip only quotes */ + tot_size = strlen (tempfilepath); +for (p = parts; *p; p++) { switch (*p) { case 'f': tot_size += strlen (fullpath); @@ -840,6 +856,8 @@ for (p = parts, tot_size = 0; *p; p++) { } result = malloc (1 + tot_size); *result = '\0'; +if (*parts == '\0') /* empty part specifier means strip only quotes */ + strlcat (result, filepath, 1 + tot_size); for (p = parts; *p; p++) { switch (*p) { case 'f': @@ -866,3 +884,135 @@ free (fullpath); free (tempfilepath); return result; } + +#if defined (_WIN32) + +t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context) +{ +HANDLE hFind; +WIN32_FIND_DATAA File; +struct stat filestat; +char WildName[PATH_MAX + 1]; + +strlcpy (WildName, cptr, sizeof(WildName)); +cptr = WildName; +sim_trim_endspc (WildName); +if ((hFind = FindFirstFileA (cptr, &File)) != INVALID_HANDLE_VALUE) { + t_int64 FileSize; + char DirName[PATH_MAX + 1], FileName[PATH_MAX + 1]; + char *c; + const char *backslash = strchr (cptr, '\\'); + const char *slash = strchr (cptr, '/'); + const char *pathsep = (backslash && slash) ? MIN (backslash, slash) : (backslash ? backslash : slash); + + GetFullPathNameA(cptr, sizeof(DirName), DirName, (char **)&c); + c = strrchr (DirName, '\\'); + *c = '\0'; /* Truncate to just directory path */ + if (!pathsep || (!strcmp (slash, "/*"))) /* Separator wasn't mentioned? */ + pathsep = "\\"; /* Default to Windows backslash */ + if (*pathsep == '/') { /* If slash separator? */ + while ((c = strchr (DirName, '\\'))) + *c = '/'; /* Convert backslash to slash */ + } + sprintf (&DirName[strlen (DirName)], "%c", *pathsep); + do { + FileSize = (((t_int64)(File.nFileSizeHigh)) << 32) | File.nFileSizeLow; + sprintf (FileName, "%s%s", DirName, File.cFileName); + stat (FileName, &filestat); + entry (DirName, File.cFileName, FileSize, &filestat, context); + } while (FindNextFile (hFind, &File)); + FindClose (hFind); + } +else + return SCPE_ARG; +return SCPE_OK; +} + +#else /* !defined (_WIN32) */ + +#include +#if defined (HAVE_GLOB) +#include +#else /* !defined (HAVE_GLOB) */ +#include +#if defined (HAVE_FNMATCH) +#include +#endif +#endif /* defined (HAVE_GLOB) */ + +t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context) +{ +#if defined (HAVE_GLOB) +glob_t paths; +#else +DIR *dir; +#endif +struct stat filestat; +char *c; +char DirName[PATH_MAX + 1], WholeName[PATH_MAX + 1], WildName[PATH_MAX + 1]; + +memset (DirName, 0, sizeof(DirName)); +memset (WholeName, 0, sizeof(WholeName)); +strlcpy (WildName, cptr, sizeof(WildName)); +cptr = WildName; +sim_trim_endspc (WildName); +c = sim_filepath_parts (cptr, "f"); +strlcpy (WholeName, c, sizeof (WholeName)); +free (c); +c = strrchr (WholeName, '/'); +if (c) { + memmove (DirName, WholeName, 1+c-WholeName); + DirName[1+c-WholeName] = '\0'; + } +else + DirName[0] = '\0'; +cptr = WholeName; +#if defined (HAVE_GLOB) +memset (&paths, 0, sizeof (paths)); +if (0 == glob (cptr, 0, NULL, &paths)) { +#else +dir = opendir(DirName[0] ? DirName : "/."); +if (dir) { + struct dirent *ent; +#endif + t_offset FileSize; + char FileName[PATH_MAX + 1]; + const char *MatchName = 1 + strrchr (cptr, '/'); + char *p_name; + struct tm *local; +#if defined (HAVE_GLOB) + size_t i; +#endif + +#if defined (HAVE_GLOB) + for (i=0; id_name, 0)) + continue; +#else + /* only match exact name without fnmatch support */ + if (strcmp(MatchName, ent->d_name) != 0) + continue; +#endif + sprintf (FileName, "%s%s", DirName, ent->d_name); +#endif + p_name = FileName + strlen (DirName); + memset (&filestat, 0, sizeof (filestat)); + (void)stat (FileName, &filestat); + FileSize = (t_offset)((filestat.st_mode & S_IFDIR) ? 0 : sim_fsize_name_ex (FileName)); + entry (DirName, p_name, FileSize, &filestat, context); + } +#if defined (HAVE_GLOB) + globfree (&paths); +#else + closedir (dir); +#endif + } +else + return SCPE_ARG; +return SCPE_OK; +} +#endif /* !defined(_WIN32) */ diff --git a/sim_fio.h b/sim_fio.h index a959d137..aa96a8d6 100644 --- a/sim_fio.h +++ b/sim_fio.h @@ -72,6 +72,13 @@ t_offset sim_fsize_name_ex (const char *fname); t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing); char *sim_filepath_parts (const char *pathname, const char *parts); char *sim_getcwd (char *buf, size_t buf_size); +#include +typedef void (*DIR_ENTRY_CALLBACK)(const char *directory, + const char *filename, + t_offset FileSize, + const struct stat *filestat, + void *context); +t_stat sim_dir_scan (const char *cptr, DIR_ENTRY_CALLBACK entry, void *context); void sim_buf_swap_data (void *bptr, size_t size, size_t count); void sim_buf_copy_swapped (void *dptr, const void *bptr, size_t size, size_t count);