Index: src/include/port.h =================================================================== RCS file: /cvsroot/pgsql-server/src/include/port.h,v retrieving revision 1.27 diff -c -c -r1.27 port.h *** src/include/port.h 30 Apr 2004 17:52:07 -0000 1.27 --- src/include/port.h 4 May 2004 17:07:30 -0000 *************** *** 26,31 **** --- 26,32 ---- extern char *last_path_separator(const char *filename); extern void canonicalize_path(char *path); extern char *get_progname(char *argv0); + extern char *relative_path(const char *src, const char *dst, const char *target); /* Portable delay handling */ extern void pg_usleep(long microsec); Index: src/port/path.c =================================================================== RCS file: /cvsroot/pgsql-server/src/port/path.c,v retrieving revision 1.5 diff -c -c -r1.5 path.c *** src/port/path.c 9 Mar 2004 04:49:02 -0000 1.5 --- src/port/path.c 4 May 2004 17:07:31 -0000 *************** *** 13,21 **** --- 13,31 ---- *------------------------------------------------------------------------- */ + #ifndef FRONTEND + #include "postgres.h" + #else #include "c.h" + #endif #include + #ifndef WIN32 + #define ISSEP(c) ((c) == '/') + #else + #define ISSEP(c) ((c) == '/' || (c) == '\\') + #endif + /* * is_absolute_path */ *************** *** 33,39 **** } - /* * first_path_separator */ --- 43,48 ---- *************** *** 120,123 **** --- 129,241 ---- return argv0; else return last_path_separator(argv0) + 1; + } + + + /* + * relative_path + * + * Determine the relative path for getting from 'src' to 'dst' and + * map that change from 'target' to a new directory. + */ + char * + relative_path(const char *src, const char *dst, const char *target) + { + const char *dst_slash = NULL; + char *ret; + int dirs_up; + + #ifdef WIN32 + if (isalpha(*src) && src[1] == ':' && + isalpha(*dst) && dst[1] == ':') + { + if (toupper(*src) != toupper(*src)) + return NULL; /* no relative path, can't cross drive letters */ + } + + /* Move past drive letters */ + if (isalpha(*src) && src[1] == ':') + src += 2; + if (isalpha(*dst) && dst[1] == ':') + src += 2; + #endif + + /* If we don't have two absolute paths, give up */ + if (!is_absolute_path(src) || + !is_absolute_path(dst)) + return NULL; + + dst_slash = dst; + + while (1) + { + /* Move past adjacent slashes like //, and trailing ones */ + while (ISSEP(*src) && (ISSEP(src[1]) || !src[1])) + src++; + while (ISSEP(*dst) && (ISSEP(dst[1]) || !dst[1])) + dst++; + + /* Paths are done or not equal? */ + if (!*src || !*dst) + break; + #ifndef WIN32 + if (*src != *dst) + break; + #else + /* Win32 filesystem is case insensitive */ + if (toupper(*src) != toupper(*dst) && + (!ISSEP(*src) || !ISSEP(*dst))) /* '/' == '\\' */ + break; + #endif + if (ISSEP(*dst)) + dst_slash = dst; + + src++; + dst++; + } + + /* Did the last part of the path match? */ + dirs_up = ((*src == '\0' || ISSEP(*src)) && + (*dst == '\0' || ISSEP(*dst))) ? 0 : 1; + + /* How many directories do we have to move up? */ + while (*src) + { + if (ISSEP(*src)) + { + while (ISSEP(*src)) + src++; + if (*src != '\0') /* skip trailing slash */ + dirs_up++; + } + else + src++; + } + + #ifndef FRONTEND + ret = palloc(strlen(target) + strlen(dst) + 1); + #else + ret = malloc(strlen(target) + strlen(dst) + 1); + #endif + + strcpy(ret, target); + + /* Trim off trailing slash from target */ + if (strlen(ret) > 0 && ISSEP(ret[strlen(ret)-1])) + dirs_up++; + + while (dirs_up--) + if (last_path_separator(ret) != NULL) + *last_path_separator(ret) = '\0'; /* trim off directory */ + else + return NULL; + + /* Add dst to trimmed target */ + strcat(ret, dst_slash); + + /* Trim off trailing slash from result */ + if (strlen(ret) > 0 && ISSEP(ret[strlen(ret)-1])) + *last_path_separator(ret) = '\0'; /* trim off slash */ + + return ret; }