From 74c89bd7f81dfb9d30f14400b65e4cffa6ebc5fc Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 10 Feb 2004 01:29:19 +0000 Subject: [PATCH] Added a normalize_path() function, that does a certain normalization of paths. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6546 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tools/jam/pathsys.h | 1 + src/tools/jam/pathunix.c | 92 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/tools/jam/pathsys.h b/src/tools/jam/pathsys.h index c8c94521a1..652a5f5378 100644 --- a/src/tools/jam/pathsys.h +++ b/src/tools/jam/pathsys.h @@ -49,3 +49,4 @@ void path_build( PATHNAME *f, char *file, int binding ); void path_parse( const char *file, PATHNAME *f ); void path_parent( PATHNAME *f ); +char *normalize_path(const char *path, char *buffer, size_t bufferSize); diff --git a/src/tools/jam/pathunix.c b/src/tools/jam/pathunix.c index 5fa09418d1..ef0ac612c9 100644 --- a/src/tools/jam/pathunix.c +++ b/src/tools/jam/pathunix.c @@ -232,4 +232,96 @@ path_parent( PATHNAME *f ) f->f_member.len = 0; } +/* + * normalize_path() - normalize a path + * + * It doesn't really generate a unique representation of a path to an entry, + * but at least reduces the number of categories that represent the same + * entry. On error, or if the supplied buffer is too small, NULL is returned. + */ + +char * +normalize_path(const char *path, char *buffer, size_t bufferSize) +{ + // init cwd + static char _cwd[PATH_MAX]; + static char *cwd = 0; + static size_t cwdLen = 0; + int pathLen = (path ? strlen(path) : 0); + int resultLen = 0; + int resolveDotDot = !0; + // init cwd + if (!cwd) { + cwd = getcwd(_cwd, PATH_MAX); + if (cwd) + cwdLen = strlen(cwd); + else + return 0; + } + // check length + if (cwdLen + pathLen + 2 > bufferSize) + return 0; + // construct result + if (pathLen > 0 && path[0] == PATH_DELIM) { + // absolute path: ignore cwd + buffer[0] = PATH_DELIM; + buffer[1] = '\0'; + resultLen = 1; + path++; + pathLen--; + } else { + // relative path: copy cwd into result + memcpy(buffer, cwd, cwdLen + 1); + resultLen = cwdLen; + } + // append path componentwise to the result, skipping "." and empty + // components, and chopping off a component per ".." + while (pathLen > 0) { + // find component + char *separator = strchr(path, PATH_DELIM); + const char *component = path; + int componentLen = 0; + if (separator) { + componentLen = separator - path; + pathLen -= componentLen + 1; + path = separator + 1; + } else { + componentLen = pathLen; + path += componentLen; + pathLen = 0; + } + // handle found component + if (componentLen > 0) { + if (componentLen == 1 && component[0] == '.') { + // component is ".": skip + } else if (resolveDotDot && componentLen == 2 && component[0] == '.' + && component[1] == '.') { + // component is "..": eat the last component of the result + char *lastSeparator = strrchr(buffer, PATH_DELIM); + if (lastSeparator) { + resultLen = lastSeparator - buffer; + if (resultLen == 0) { + // always leave at least the root + buffer[0] = PATH_DELIM; + resultLen = 1; + } + buffer[resultLen] = '\0'; + } // else: not good + } else { + // normal component: append + if (resultLen < 1 || buffer[resultLen - 1] != PATH_DELIM) + buffer[resultLen++] = PATH_DELIM; + memcpy(buffer + resultLen, component, componentLen); + resultLen += componentLen; + buffer[resultLen] = '\0'; + // After we found the first real path component, we don't + // resolve ".." anymore, as it could be a (sym)link, which + // could break the algorithm. + resolveDotDot = 0; + } + } + } + return buffer; +} + # endif /* unix, NT, OS/2, AmigaOS */