diff options
| author | Ed Schouten <ed@FreeBSD.org> | 2016-09-18 20:47:55 +0000 |
|---|---|---|
| committer | Ed Schouten <ed@FreeBSD.org> | 2016-09-18 20:47:55 +0000 |
| commit | fd85bff53ed2f054b26750f44defd9203967b136 (patch) | |
| tree | 8f45d4ca4818a69d96a39117bbfe0895de71f162 /lib/libc | |
| parent | 06403dbce51fdac71de7c2f0adf3c7c6e5a09e48 (diff) | |
Notes
Diffstat (limited to 'lib/libc')
| -rw-r--r-- | lib/libc/gen/dirname.3 | 7 | ||||
| -rw-r--r-- | lib/libc/gen/dirname.c | 65 |
2 files changed, 25 insertions, 47 deletions
diff --git a/lib/libc/gen/dirname.3 b/lib/libc/gen/dirname.3 index 18405f9af6ef7..60f44e2986148 100644 --- a/lib/libc/gen/dirname.3 +++ b/lib/libc/gen/dirname.3 @@ -16,7 +16,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 12, 2016 +.Dd September 5, 2016 .Dt DIRNAME 3 .Os .Sh NAME @@ -60,11 +60,6 @@ space instead. The advantage of the former approach is that it ensures thread-safety, while also placing no upper limit on the supported length of the pathname. -.Pp -The algorithm used by this implementation also discards redundant -slashes and -.Qq \&. -pathname components from the pathname string. .Sh SEE ALSO .Xr basename 1 , .Xr dirname 1 , diff --git a/lib/libc/gen/dirname.c b/lib/libc/gen/dirname.c index 621122b90c403..ae7b928d54eb8 100644 --- a/lib/libc/gen/dirname.c +++ b/lib/libc/gen/dirname.c @@ -27,64 +27,47 @@ __FBSDID("$FreeBSD$"); #include <libgen.h> -#include <stdbool.h> #include <string.h> char * (dirname)(char *path) { - const char *in, *prev, *begin, *end; - char *out; - size_t prevlen; - bool skipslash; + char *end; /* * If path is a null pointer or points to an empty string, * dirname() shall return a pointer to the string ".". */ if (path == NULL || *path == '\0') - return ((char *)"."); + return (__DECONST(char *, ".")); - /* Retain at least one leading slash character. */ - in = out = *path == '/' ? path + 1 : path; + /* Find end of last pathname component. */ + end = path + strlen(path); + while (end > path + 1 && *(end - 1) == '/') + --end; - skipslash = true; - prev = "."; - prevlen = 1; - for (;;) { - /* Extract the next pathname component. */ - while (*in == '/') - ++in; - begin = in; - while (*in != '/' && *in != '\0') - ++in; - end = in; - if (begin == end) - break; - - /* - * Copy over the previous pathname component, except if - * it's dot. There is no point in retaining those. - */ - if (prevlen != 1 || *prev != '.') { - if (!skipslash) - *out++ = '/'; - skipslash = false; - memmove(out, prev, prevlen); - out += prevlen; - } - - /* Preserve the pathname component for the next iteration. */ - prev = begin; - prevlen = end - begin; - } + /* Strip off the last pathname component. */ + while (end > path && *(end - 1) != '/') + --end; /* * If path does not contain a '/', then dirname() shall return a * pointer to the string ".". */ - if (out == path) - *out++ = '.'; - *out = '\0'; + if (end == path) { + path[0] = '.'; + path[1] = '\0'; + return (path); + } + + /* + * Remove trailing slashes from the resulting directory name. Ensure + * that at least one character remains. + */ + while (end > path + 1 && *(end - 1) == '/') + --end; + + /* Null terminate directory name and return it. */ + *end = '\0'; return (path); } |
