diff options
author | Connor Lane Smith <cls@lubutu.com> | 2010-10-08 23:24:22 +0100 |
---|---|---|
committer | Connor Lane Smith <cls@lubutu.com> | 2010-10-08 23:24:22 +0100 |
commit | bf7b8e37ee2a53f0f1bed75dd84e5214269cfac8 (patch) | |
tree | e1e6e3ef7c82e062fe86b088a9741d63aa9325c1 /dmenu_path.c | |
parent | 610a0a8d126b5caa7fec60632c999ca326ca2eff (diff) | |
download | dmenu-bf7b8e37ee2a53f0f1bed75dd84e5214269cfac8.tar.gz dmenu-bf7b8e37ee2a53f0f1bed75dd84e5214269cfac8.tar.bz2 dmenu-bf7b8e37ee2a53f0f1bed75dd84e5214269cfac8.zip |
dmenu_path.c (shell is a bottleneck)
Diffstat (limited to 'dmenu_path.c')
-rw-r--r-- | dmenu_path.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/dmenu_path.c b/dmenu_path.c new file mode 100644 index 0000000..1575f1d --- /dev/null +++ b/dmenu_path.c @@ -0,0 +1,101 @@ +/* See LICENSE file for copyright and license details. */ +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +#define CACHE ".dmenu_cache" + +static int qstrcmp(const void *a, const void *b); +static void die(const char *s); +static void scan(void); +static int uptodate(void); + +static char **items = NULL; +static const char *Home, *Path; +static size_t count = 0; + +int +main(void) { + if(!(Home = getenv("HOME"))) + die("no $HOME"); + if(!(Path = getenv("PATH"))) + die("no $PATH"); + if(chdir(Home) < 0) + die("chdir failed"); + if(uptodate()) { + execlp("cat", "cat", CACHE, NULL); + die("exec failed"); + } + scan(); + return EXIT_SUCCESS; +} + +void +die(const char *s) { + fprintf(stderr, "dmenu_path: %s\n", s); + exit(EXIT_FAILURE); +} + +int +qstrcmp(const void *a, const void *b) { + return strcmp(*(const char **)a, *(const char **)b); +} + +void +scan(void) { + char buf[PATH_MAX]; + char *dir, *path; + size_t i; + struct dirent *ent; + DIR *dp; + FILE *cache; + + if(!(path = strdup(Path))) + die("strdup failed"); + for(dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) { + if(!(dp = opendir(dir))) + continue; + while((ent = readdir(dp))) { + snprintf(buf, sizeof buf, "%s/%s", dir, ent->d_name); + if(ent->d_name[0] == '.' || access(buf, X_OK) < 0) + continue; + if(!(items = realloc(items, ++count * sizeof *items))) + die("malloc failed"); + if(!(items[count-1] = strdup(ent->d_name))) + die("strdup failed"); + } + closedir(dp); + } + qsort(items, count, sizeof *items, qstrcmp); + if(!(cache = fopen(CACHE, "w"))) + die("open failed"); + for(i = 0; i < count; i++) { + if(i > 0 && !strcmp(items[i], items[i-1])) + continue; + fprintf(cache, "%s\n", items[i]); + fprintf(stdout, "%s\n", items[i]); + } + fclose(cache); + free(path); +} + +int +uptodate(void) { + char *dir, *path; + time_t mtime; + struct stat st; + + if(stat(CACHE, &st) < 0) + return 0; + mtime = st.st_mtime; + if(!(path = strdup(Path))) + die("strdup failed"); + for(dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) + if(!stat(dir, &st) && st.st_mtime > mtime) + return 0; + free(path); + return 1; +} |