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
This commit is contained in:
Ingo Weinhold 2004-02-10 01:29:19 +00:00
parent bf3a9e7597
commit 74c89bd7f8
2 changed files with 93 additions and 0 deletions

View File

@ -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);

View File

@ -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 */