From 8f18c4049cccd4a01353e5a5c09ea05061c8d0a3 Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Sat, 1 Apr 2017 17:32:58 +0530 Subject: [PATCH] An optimized dirname() --- README.md | 10 ++++-- nnn.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8be8d230..20a9f113 100644 --- a/README.md +++ b/README.md @@ -72,9 +72,15 @@ I chose to fork because: - Associate PDF files with [zathura](https://pwmt.org/projects/zathura/) - Use environment variable `NNN_FALLBACK_OPENER` to open other non-associated files - Removed `less` as default file opener (there is no universal standalone opener utility) -- Compilation - - Use `-O3` for compilation, fixed warnings +- Optimizations + - Efficient memory usage, 0 malloc() + - Complete redundant buffer removal + - All frequently used local chunks now static + - Removed some redundant string allocation and manipulation + - Simplified some roundabout procedures + - `-O3` level optimization, warning fixes - Added compilation flag `-march=native` + - Massive binary size optimization - Remove generated config.h on `make clean` - strip the final binary diff --git a/nnn.c b/nnn.c index a6a37776..81652a76 100644 --- a/nnn.c +++ b/nnn.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -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)