From 9fc1a0e56ee9008f2f407208c4ed6a1e6d259c5c Mon Sep 17 00:00:00 2001 From: Daniel Serpell Date: Sat, 9 May 2020 00:49:52 -0400 Subject: Adds a function to transform unix paths to absolute DOS paths. This allows to correctly set the current-working-directory and the executable name at program start. --- src/dos.c | 18 +++++++++++++- src/dosnames.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dosnames.h | 3 +++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/dos.c b/src/dos.c index a6745ee..4ac59ec 100644 --- a/src/dos.c +++ b/src/dos.c @@ -1969,6 +1969,18 @@ void init_dos(int argc, char **argv) strncpy(path, getenv(ENV_CWD), 63); dos_change_cwd(path); } + else + { + // No CWD given, translate from base path of default drive + char *cwd = dos_real_path(dos_get_default_drive(), "."); + if(cwd) + { + dos_change_cwd(cwd); + free(cwd); + } + else + debug(debug_dos, "\tWARNING: working directory outside default drive\n"); + } // Concat rest of arguments int i; @@ -2002,7 +2014,11 @@ void init_dos(int argc, char **argv) const char *progname = getenv(ENV_PROGNAME); if(!progname) - progname = argv[0]; + { + progname = dos_real_path(dos_get_default_drive(), argv[0]); + if(!progname) + progname = argv[0]; + } // Create main PSP int psp_mcb = create_PSP(args, environ, p - environ + 1, progname); diff --git a/src/dosnames.c b/src/dosnames.c index b98b8d3..f1e060f 100644 --- a/src/dosnames.c +++ b/src/dosnames.c @@ -74,6 +74,17 @@ static int dos_search_name(const struct dos_file_list *dl, const uint8_t *name) return 0; } +static const struct dos_file_list *dos_search_unix_name(const struct dos_file_list *dl, + const char *name) +{ + for(; dl && dl->unixname; dl++) + { + if(!strcmp(dl->unixname, name)) + return dl; + } + return 0; +} + // Sort unix entries so that '~' and '.' comes before other chars static int dos_unix_sort(const struct dirent **s1, const struct dirent **s2) { @@ -608,3 +619,67 @@ struct dos_file_list *dos_find_first_file_fcb(int addr) { return find_first_file(dos_unix_path_fcb(addr, 1)); } + +char *dos_real_path(char drive, const char *unix_path) +{ + char *ret = 0; + // Start by normalizing both base and given paths + char *base = realpath(get_base_path(drive), 0); + if(!base) + return 0; + char *path = realpath(unix_path, 0); + if(!path) + { + free(base); + return 0; + } + debug(debug_dos, "dos_real_path: base='%s' path='%s'\n", base, path); + // Now, see if the path is actually a descendent of base + size_t l = strlen(base), k = strlen(path); + if(strncmp(base, path, l) || (path[l] != '/' && path[l])) + { + debug(debug_dos, "dos_real_path: no common base\n"); + } + else if(k - l > 62) + { + debug(debug_dos, "dos_real_path: path too long for DOS\n"); + } + else + { + // Convert remaining components + ret = calloc(1, 64); + strncat(ret, "C:", 64); + + path[l] = 0; + while(++l < k) + { + // Extract one component + char *sep = strchr(path + l, '/'); + // Cut string there + if(!sep) + sep = path + k; + else + *sep = 0; + // And search the DOS path name + struct dos_file_list *fl = dos_read_dir(path, "*.*"); + path[l - 1] = '/'; + const struct dos_file_list *sl = dos_search_unix_name(fl, path); + if(!sl) + { + dos_free_file_list(fl); + debug(debug_dos, "dos_real_path: path not found: '%s' in '%s'\n", + path + l, path); + free(base); + free(path); + return 0; + } + strncat(ret, "\\", 64); + strncat(ret, (const char *)sl->dosname, 64); + dos_free_file_list(fl); + l = sep - path; + } + } + free(base); + free(path); + return ret; +} diff --git a/src/dosnames.h b/src/dosnames.h index 63a5771..c75b786 100644 --- a/src/dosnames.h +++ b/src/dosnames.h @@ -22,6 +22,9 @@ char *dos_unix_path_fcb(int addr, int force); int dos_change_cwd(char *path); int dos_change_dir(int addr); +// Returns a DOS path representing given Unix path in drive +char *dos_real_path(char drive, const char *unix_path); + // Gets current working directory const uint8_t *dos_get_cwd(int drive); -- cgit v1.2.3