diff --git a/FL/Fl_System_Driver.H b/FL/Fl_System_Driver.H index 12e0f5f1d..03364e2f4 100644 --- a/FL/Fl_System_Driver.H +++ b/FL/Fl_System_Driver.H @@ -98,10 +98,14 @@ public: virtual int get_key(int k) {return 0;} // implement scandir-like function virtual int filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) ) {return -1;} - // the default implementation of filename_expand may be enough + // the default implementation of filename_expand() may be enough virtual int filename_expand(char *to, int tolen, const char *from); // to implement virtual const char *getpwnam(const char *login) {return NULL;} + // the default implementation of filename_relative() is in src/filename_absolute.cxx and may be enough + virtual int filename_relative(char *to, int tolen, const char *from, const char *base); + // the default implementation of filename_absolute() is in src/filename_absolute.cxx and may be enough + virtual int filename_absolute(char *to, int tolen, const char *from); }; #endif // FL_SYSTEM_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H index 75fdbc860..cd7e03c50 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.H @@ -70,6 +70,8 @@ public: virtual int get_key(int k); virtual int filename_list(const char *d, dirent ***list, int (*sort)(struct dirent **, struct dirent **) ); virtual int filename_expand(char *to,int tolen, const char *from); + virtual int filename_relative(char *to, int tolen, const char *from, const char *base); + virtual int filename_absolute(char *to, int tolen, const char *from); }; #endif // FL_WINAPI_SYSTEM_DRIVER_H diff --git a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx index cbd5f9081..6d32b4f6b 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_System_Driver.cxx @@ -486,6 +486,134 @@ int Fl_WinAPI_System_Driver::filename_expand(char *to,int tolen, const char *fro return ret; } +int // O - 0 if no change, 1 if changed +Fl_WinAPI_System_Driver::filename_relative(char *to, // O - Relative filename + int tolen, // I - Size of "to" buffer + const char *from, // I - Absolute filename + const char *base) // I - Find path relative to this path +{ + char *newslash; // Directory separator + const char *slash; // Directory separator + char *cwd = 0L, *cwd_buf = 0L; + if (base) cwd = cwd_buf = strdup(base); + + // return if "from" is not an absolute path + if (from[0] == '\0' || + (!isdirsep(*from) && !isalpha(*from) && from[1] != ':' && + !isdirsep(from[2]))) { + strlcpy(to, from, tolen); + if (cwd_buf) free(cwd_buf); + return 0; + } + + // return if "cwd" is not an absolute path + if (!cwd || cwd[0] == '\0' || + (!isdirsep(*cwd) && !isalpha(*cwd) && cwd[1] != ':' && + !isdirsep(cwd[2]))) { + strlcpy(to, from, tolen); + if (cwd_buf) free(cwd_buf); + return 0; + } + + // convert all backslashes into forward slashes + for (newslash = strchr(cwd, '\\'); newslash; newslash = strchr(newslash + 1, '\\')) + *newslash = '/'; + + // test for the exact same string and return "." if so + if (!strcasecmp(from, cwd)) { + strlcpy(to, ".", tolen); + free(cwd_buf); + return (1); + } + + // test for the same drive. Return the absolute path if not + if (tolower(*from & 255) != tolower(*cwd & 255)) { + // Not the same drive... + strlcpy(to, from, tolen); + free(cwd_buf); + return 0; + } + + // compare the path name without the drive prefix + from += 2; cwd += 2; + + // compare both path names until we find a difference + for (slash = from, newslash = cwd; + *slash != '\0' && *newslash != '\0'; + slash ++, newslash ++) + if (isdirsep(*slash) && isdirsep(*newslash)) continue; + else if (tolower(*slash & 255) != tolower(*newslash & 255)) break; + + // skip over trailing slashes + if ( *newslash == '\0' && *slash != '\0' && !isdirsep(*slash) + &&(newslash==cwd || !isdirsep(newslash[-1])) ) + newslash--; + + // now go back to the first character of the first differing paths segment + while (!isdirsep(*slash) && slash > from) slash --; + if (isdirsep(*slash)) slash ++; + + // do the same for the current dir + if (isdirsep(*newslash)) newslash --; + if (*newslash != '\0') + while (!isdirsep(*newslash) && newslash > cwd) newslash --; + + // prepare the destination buffer + to[0] = '\0'; + to[tolen - 1] = '\0'; + + // now add a "previous dir" sequence for every following slash in the cwd + while (*newslash != '\0') { + if (isdirsep(*newslash)) strlcat(to, "../", tolen); + newslash ++; + } + + // finally add the differing path from "from" + strlcat(to, slash, tolen); + + free(cwd_buf); + return 1; +} + +int Fl_WinAPI_System_Driver::filename_absolute(char *to, int tolen, const char *from) { + if (isdirsep(*from) || *from == '|' || from[1]==':') { + strlcpy(to, from, tolen); + return 0; + } + char *a; + char *temp = new char[tolen]; + const char *start = from; + a = getcwd(temp, tolen); + if (!a) { + strlcpy(to, from, tolen); + delete[] temp; + return 0; + } + for (a = temp; *a; a++) if (*a=='\\') *a = '/'; // ha ha + if (isdirsep(*(a-1))) a--; + /* remove intermediate . and .. names: */ + while (*start == '.') { + if (start[1]=='.' && isdirsep(start[2])) { + char *b; + for (b = a-1; b >= temp && !isdirsep(*b); b--) {/*empty*/} + if (b < temp) break; + a = b; + start += 3; + } else if (isdirsep(start[1])) { + start += 2; + } else if (!start[1]) { + start ++; // Skip lone "." + break; + } else + break; + } + *a++ = '/'; + strlcpy(a,start,tolen - (a - temp)); + strlcpy(to, temp, tolen); + delete[] temp; + return 1; +} + // // End of "$Id$". // diff --git a/src/filename_absolute.cxx b/src/filename_absolute.cxx index be1bb0888..7d96c6cbc 100644 --- a/src/filename_absolute.cxx +++ b/src/filename_absolute.cxx @@ -23,21 +23,12 @@ */ #include -#include +#include +#include #include #include "flstring.h" -#include -#if defined(WIN32) && !defined(__CYGWIN__) -# include -#else -# include -#endif -#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) -inline int isdirsep(char c) {return c=='/' || c=='\\';} -#else -#define isdirsep(c) ((c)=='/') -#endif +inline int isdirsep(char c) {return c == '/';} /** Makes a filename absolute from a relative filename. \code @@ -54,30 +45,25 @@ inline int isdirsep(char c) {return c=='/' || c=='\\';} \return 0 if no change, non zero otherwise */ int fl_filename_absolute(char *to, int tolen, const char *from) { - if (isdirsep(*from) || *from == '|' -#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) - || from[1]==':' -#endif - ) { + return Fl::system_driver()->filename_absolute(to, tolen, from); +} + + +int Fl_System_Driver::filename_absolute(char *to, int tolen, const char *from) { + if (isdirsep(*from) || *from == '|') { strlcpy(to, from, tolen); return 0; } - char *a; char *temp = new char[tolen]; const char *start = from; - a = fl_getcwd(temp, tolen); if (!a) { strlcpy(to, from, tolen); delete[] temp; return 0; } -#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) - for (a = temp; *a; a++) if (*a=='\\') *a = '/'; // ha ha -#else a = temp+strlen(temp); -#endif if (isdirsep(*(a-1))) a--; /* remove intermediate . and .. names: */ while (*start == '.') { @@ -95,14 +81,10 @@ int fl_filename_absolute(char *to, int tolen, const char *from) { } else break; } - *a++ = '/'; strlcpy(a,start,tolen - (a - temp)); - strlcpy(to, temp, tolen); - delete[] temp; - return 1; } @@ -151,113 +133,80 @@ fl_filename_relative(char *to, // O - Relative filename int tolen, // I - Size of "to" buffer const char *from, // I - Absolute filename const char *base) { // I - Find path relative to this path - + return Fl::system_driver()->filename_relative(to, tolen, from, base); +} + +int // O - 0 if no change, 1 if changed +Fl_System_Driver::filename_relative(char *to, // O - Relative filename + int tolen, // I - Size of "to" buffer + const char *from, // I - Absolute filename + const char *base) // I - Find path relative to this path +{ char *newslash; // Directory separator const char *slash; // Directory separator char *cwd = 0L, *cwd_buf = 0L; if (base) cwd = cwd_buf = strdup(base); // return if "from" is not an absolute path -#if defined(WIN32) || defined(__EMX__) - if (from[0] == '\0' || - (!isdirsep(*from) && !isalpha(*from) && from[1] != ':' && - !isdirsep(from[2]))) { -#else if (from[0] == '\0' || !isdirsep(*from)) { -#endif // WIN32 || __EMX__ strlcpy(to, from, tolen); if (cwd_buf) free(cwd_buf); return 0; } - + // return if "cwd" is not an absolute path -#if defined(WIN32) || defined(__EMX__) - if (!cwd || cwd[0] == '\0' || - (!isdirsep(*cwd) && !isalpha(*cwd) && cwd[1] != ':' && - !isdirsep(cwd[2]))) { -#else if (!cwd || cwd[0] == '\0' || !isdirsep(*cwd)) { -#endif // WIN32 || __EMX__ strlcpy(to, from, tolen); if (cwd_buf) free(cwd_buf); return 0; } - -#if defined(WIN32) || defined(__EMX__) - // convert all backslashes into forward slashes - for (newslash = strchr(cwd, '\\'); newslash; newslash = strchr(newslash + 1, '\\')) - *newslash = '/'; - - // test for the exact same string and return "." if so - if (!strcasecmp(from, cwd)) { - strlcpy(to, ".", tolen); - free(cwd_buf); - return (1); - } - - // test for the same drive. Return the absolute path if not - if (tolower(*from & 255) != tolower(*cwd & 255)) { - // Not the same drive... - strlcpy(to, from, tolen); - free(cwd_buf); - return 0; - } - - // compare the path name without the drive prefix - from += 2; cwd += 2; -#else + // test for the exact same string and return "." if so if (!strcmp(from, cwd)) { strlcpy(to, ".", tolen); free(cwd_buf); return (1); } -#endif // WIN32 || __EMX__ - + // compare both path names until we find a difference for (slash = from, newslash = cwd; - *slash != '\0' && *newslash != '\0'; + *slash != '\0' && *newslash != '\0'; slash ++, newslash ++) if (isdirsep(*slash) && isdirsep(*newslash)) continue; -#if defined(WIN32) || defined(__EMX__) || defined(__APPLE__) // PORTME: Fl_System_Driver - filename stuff - else if (tolower(*slash & 255) != tolower(*newslash & 255)) break; -#else else if (*slash != *newslash) break; -#endif // WIN32 || __EMX__ || __APPLE__ // PORTME: Fl_System_Driver - filename stuff - + // skip over trailing slashes if ( *newslash == '\0' && *slash != '\0' && !isdirsep(*slash) - &&(newslash==cwd || !isdirsep(newslash[-1])) ) + &&(newslash==cwd || !isdirsep(newslash[-1])) ) newslash--; - + // now go back to the first character of the first differing paths segment while (!isdirsep(*slash) && slash > from) slash --; if (isdirsep(*slash)) slash ++; - + // do the same for the current dir if (isdirsep(*newslash)) newslash --; if (*newslash != '\0') while (!isdirsep(*newslash) && newslash > cwd) newslash --; - + // prepare the destination buffer to[0] = '\0'; to[tolen - 1] = '\0'; - + // now add a "previous dir" sequence for every following slash in the cwd while (*newslash != '\0') { if (isdirsep(*newslash)) strlcat(to, "../", tolen); - + newslash ++; } - + // finally add the differing path from "from" strlcat(to, slash, tolen); - + free(cwd_buf); return 1; } - // // End of "$Id$". //