diff options
author | Arun Prakash Jana <engineerarun@gmail.com> | 2017-04-01 17:32:58 +0530 |
---|---|---|
committer | Arun Prakash Jana <engineerarun@gmail.com> | 2017-04-01 17:32:58 +0530 |
commit | 8f18c4049cccd4a01353e5a5c09ea05061c8d0a3 (patch) | |
tree | 3354d6043933670c198ae411e9cc0e1ccca02d83 /nnn.c | |
parent | 7be7a6d215e861ebec0cae2334b4b4b86d3742da (diff) | |
download | nnn-8f18c4049cccd4a01353e5a5c09ea05061c8d0a3.tar.gz |
An optimized dirname()
Diffstat (limited to 'nnn.c')
-rw-r--r-- | nnn.c | 95 |
1 files changed, 91 insertions, 4 deletions
@@ -7,7 +7,6 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> -#include <libgen.h> #include <limits.h> #include <locale.h> #include <regex.h> @@ -93,9 +92,9 @@ typedef struct entry { static struct entry *dents; static int ndents, cur; static int idle; -static char *opener = NULL; -static char *fallback_opener = NULL; -static char *copier = NULL; +static char *opener; +static char *fallback_opener; +static char *copier; static const char* size_units[] = {"B", "K", "M", "G", "T", "P", "E", "Z", "Y"}; /* @@ -144,6 +143,29 @@ xrealloc(void *p, size_t size) return p; } +/* + * The poor man's implementation of memrchr(). + * We are only looking for '/' in this program. + */ +static void * +xmemrchr(const void *s, int c, size_t n) +{ + unsigned char *p; + unsigned char ch = (unsigned char)c; + + if (!s || !n) + return NULL; + + p = (unsigned char *)s + n - 1; + + while(n--) + if ((*p--) == ch) + return ++p; + + return NULL; +} + +#if 0 /* Some implementations of dirname(3) may modify `path' and some * return a pointer inside `path'. */ static char * @@ -159,6 +181,71 @@ xdirname(const char *path) strlcpy(out, p, sizeof(out)); return out; } +#endif + +/* + * The following dirname() implementation does not + * change the input. We use a copy of the original. + * + * Modified from the glibc (GNU LGPL) version. + */ +static char * +xdirname(const char *path) +{ + static char name[PATH_MAX]; + char *last_slash; + + strlcpy(name, path, PATH_MAX); + + /* Find last '/'. */ + last_slash = name != NULL ? strrchr(name, '/') : NULL; + + if (last_slash != NULL && last_slash != name && last_slash[1] == '\0') { + /* Determine whether all remaining characters are slashes. */ + char *runp; + + for (runp = last_slash; runp != name; --runp) + if (runp[-1] != '/') + break; + + /* The '/' is the last character, we have to look further. */ + if (runp != name) + last_slash = xmemrchr(name, '/', runp - name); + } + + if (last_slash != NULL) { + /* Determine whether all remaining characters are slashes. */ + char *runp; + + for (runp = last_slash; runp != name; --runp) + if (runp[-1] != '/') + break; + + /* Terminate the name. */ + if (runp == name) { + /* The last slash is the first character in the string. + We have to return "/". As a special case we have to + return "//" if there are exactly two slashes at the + beginning of the string. See XBD 4.10 Path Name + Resolution for more information. */ + if (last_slash == name + 1) + ++last_slash; + else + last_slash = name + 1; + } else + last_slash = runp; + + last_slash[0] = '\0'; + } else { + /* This assignment is ill-designed but the XPG specs require to + return a string containing "." in any case no directory part + is found and so a static and constant string is required. */ + name[0] = '.'; + name[1] = '\0'; + } + + return name; +} static void spawn(char *file, char *arg, char *dir) |