changeset: 658:61b9d6aca10f
tag: tip
user: Connor Lane Smith <cls_AT_lubutu.com>
date: Sat Dec 11 03:20:12 2010 +0000
files: tools.suckless.org/dmenu/index.md tools.suckless.org/dmenu/patches/allow-kp_decimal-in-dmenu.patch tools.suckless.org/dmenu/patches/dmenu-4.0-paste.diff tools.suckless.org/dmenu/patches/dmenu_path-cls.c tools.suckless.org/dmenu/patches/dmenu_path.c tools.suckless.org/dmenu/patches/dmenu_path.md tools.suckless.org/dmenu/patches/kp_decimal.md tools.suckless.org/dmenu/patches/legacy/allow-kp_decimal-in-dmenu.patch tools.suckless.org/dmenu/patches/legacy/dmenu-4.0-paste.diff tools.suckless.org/dmenu/patches/legacy/dmenu_path-cls.c tools.suckless.org/dmenu/patches/legacy/dmenu_path.c tools.suckless.org/dmenu/patches/legacy/dmenu_path.md tools.suckless.org/dmenu/patches/legacy/index.md tools.suckless.org/dmenu/patches/legacy/kp_decimal.md tools.suckless.org/dmenu/patches/legacy/paste.md tools.suckless.org/dmenu/patches/paste.md
description:
moved patches to legacy
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/index.md
--- a/tools.suckless.org/dmenu/index.md Fri Dec 10 12:15:30 2010 +0100
+++ b/tools.suckless.org/dmenu/index.md Sat Dec 11 03:20:12 2010 +0000
_AT_@ -23,4 +23,3 @@
-----
* [Man page](
http://man.suckless.org/tools/1/dmenu)
-* Rewrite of dmenu_path in C is under [Patches](
http://tools.suckless.org/dmenu/patches). It is supposedly around 2-4 times faster on cache hits and around 10-20 times faster on cache misses.
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/allow-kp_decimal-in-dmenu.patch
--- a/tools.suckless.org/dmenu/patches/allow-kp_decimal-in-dmenu.patch Fri Dec 10 12:15:30 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
_AT_@ -1,12 +0,0 @@
-diff -r 4684b2cf4eab dmenu.c
---- a/dmenu.c Sat Dec 05 16:52:53 2009 +0000
-+++ b/dmenu.c Sun Dec 13 20:50:57 2009 +0000
-_AT_@ -395,6 +395,8 @@
- ksym = XK_Return;
- else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
- ksym = (ksym - XK_KP_0) + XK_0;
-+ else if(ksym == XK_KP_Decimal)
-+ ksym = XK_period;
- }
- if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
- || IsMiscFunctionKey(ksym) || IsPFKey(ksym)
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/dmenu-4.0-paste.diff
--- a/tools.suckless.org/dmenu/patches/dmenu-4.0-paste.diff Fri Dec 10 12:15:30 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
_AT_@ -1,27 +0,0 @@
-diff -r f48e2b63129e dmenu.c
---- a/dmenu.c Tue Oct 27 14:38:03 2009 -0700
-+++ b/dmenu.c Thu Oct 29 13:14:21 2009 -0700
-_AT_@ -389,6 +389,23 @@
- case XK_G:
- ksym = XK_End;
- break;
-+ case XK_p:
-+ {
-+ FILE *fp;
-+ char *c;
-+ if(!(fp = (FILE*)popen("sselp", "r")))
-+ fprintf(stderr, "dmenu: Could not popen sselp\n");
-+ c = fgets(text + len, sizeof(text) - len, fp);
-+ pclose(fp);
-+ if(c == NULL)
-+ return;
-+ }
-+ len = strlen(text);
-+ if(len && text[len-1] == '\n')
-+ text[--len] = '\0';
-+ match(text);
-+ drawmenu();
-+ return;
- }
- }
- switch(ksym) {
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/dmenu_path-cls.c
--- a/tools.suckless.org/dmenu/patches/dmenu_path-cls.c Fri Dec 10 12:15:30 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
_AT_@ -1,100 +0,0 @@
-#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;
-}
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/dmenu_path.c
--- a/tools.suckless.org/dmenu/patches/dmenu_path.c Fri Dec 10 12:15:30 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
_AT_@ -1,376 +0,0 @@
-/*
- * dmenu_path
- * This program dumps all executables in $PATH to stdout.
- * It uses the file $HOME/.dmenu_cache as a cache.
- *
- * This program is released under the X11 license (sometimes known as the MIT
- * license), which basically means that you can do whatever you want with it.
- *
- * Sorry for the hairy code. I didn't know how to make it simpler and still
- * as generic. Valgrind claims it's correct and doesn't leak, but I'm sure you
- * can find a couple of ways to make it crash.
- *
- * I'd appreciate, but I don't require, that you mail me any improvements or
- * comments on the code.
- *
- * Elmo Todurov todurov+dmenu_AT_gmail.com
- * 2010-05-19 09:55
- */
-
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <malloc.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <assert.h>
-
-static uid_t uid;
-static gid_t gid;
-static char* cache_path;
-
-static int uptodate(char** paths)
-{
- struct stat dirstat;
- time_t cache_time;
- char** dirs;
-
- if (stat(cache_path, &dirstat))
- {
- if (errno != ENOENT)
- {
- perror("stat");
- }
- return 0;
- }
- cache_time = dirstat.st_mtime;
-
- dirs = paths;
- while (*dirs != NULL)
- {
- if (stat(*dirs, &dirstat))
- {
- if (errno != ENOENT)
- perror("stat");
- return 0;
- }
-
- if (cache_time < dirstat.st_mtime)
- return 0;
-
- dirs++;
- }
-
- return 1;
-}
-
-static void die(const char* msg)
-{
- perror(msg);
- exit(EXIT_FAILURE);
-}
-
-static char* get_cache_path()
-{
- const char* home;
- char* path;
- home = getenv("HOME");
- if (home == NULL)
- die("getenv");
- path = (char*)malloc(strlen(home) + strlen("/.dmenu_cache") + 1);
- if (path == NULL)
- die("malloc");
- strcpy(path, home);
- strcat(path, "/.dmenu_cache");
- return path;
-}
-
-static char* get_PATH()
-{
- const char* path = getenv("PATH");
- char* copy_path;
- if (path == NULL)
- die("getenv");
-
- copy_path = strdup(path);
- return copy_path;
-}
-
-static void split_PATH(char* PATH, char*** dirs_in)
-{
- char** dirs;
- const char* dir = strtok(PATH, ":");
- size_t i = 0;
- size_t allocated = 10;
- dirs = (char**)malloc(sizeof(char*) * allocated);
- if (dirs == NULL)
- die("malloc");
-
- while (dir != NULL)
- {
- dirs[i] = (char*)malloc(strlen(dir) + 1);
- if (dirs[i] == NULL)
- die("malloc");
- strcpy(dirs[i], dir);
- dir = strtok(NULL, ":");
- i++;
- if (i == allocated)
- {
- allocated *= 2;
- dirs = (char**)realloc(dirs, allocated * sizeof(char**));
- if (dirs == NULL)
- die("realloc");
- }
- }
- dirs[i] = NULL;
-
- *dirs_in = dirs;
-}
-
-static void free_charpp(char** in)
-{
- char** ptr = in;
- while (*ptr != NULL)
- {
- free(*ptr);
- ptr++;
- }
- free(in);
-}
-
-static void fprint_charpp(char** in, FILE* out)
-{
- char** ptr = in;
- while (*ptr != NULL)
- {
- fputs(*ptr, out);
- fputc('\n', out);
- ptr++;
- }
-}
-
-static size_t count_charpp(char** in)
-{
- char** ptr = in;
- size_t count = 0;
- while (*ptr != NULL)
- {
- count++;
- ptr++;
- }
- return count;
-}
-
-static int isexecutable(const char* fname)
-{
- struct stat st;
- int ret;
- int success;
- gid_t* grouplist;
-
- ret = stat(fname, &st);
- if (ret != 0)
- return 0;
- if (!S_ISREG(st.st_mode)) /* this catches regular files and symlinks as well */
- return 0;
- if ((st.st_uid == uid && (st.st_mode & S_IXUSR) != 0)
- || (st.st_uid != uid && st.st_gid != gid && (st.st_mode & S_IXOTH) != 0))
- {
- return 1;
- }
-
- /* check secondary groups */
- if (st.st_mode & S_IXGRP)
- {
- success = 0;
- ret = getgroups(0, 0);
- grouplist = (gid_t*)malloc(sizeof(gid_t) * ret);
- if (grouplist == NULL)
- die("malloc");
- ret = getgroups(ret, grouplist);
- while (ret != 0)
- {
- ret--;
- if (st.st_uid != uid /* for group to match, user must not match. */
- && st.st_gid == grouplist[ret])
- {
- success = 1;
- break;
- }
- }
- free(grouplist);
- return success;
- }
-
- return 0;
-}
-
-static void add(const char* prog, char*** progs)
-{
- static unsigned progs_allocated = 0;
- static unsigned progs_used = 0;
-
- if (progs_used == progs_allocated)
- {
- progs_allocated = progs_allocated == 0 ? 256 : progs_allocated * 2;
- *progs = (char**)realloc(*progs, sizeof(char*) * progs_allocated);
- if (*progs == NULL)
- die("realloc");
- }
-
- if (prog != NULL)
- {
- (*progs)[progs_used] = (char*)malloc(strlen(prog) + 1);
- if ((*progs)[progs_used] == NULL)
- die("malloc");
- strcpy((*progs)[progs_used], prog);
- progs_used++;
- }
- else
- {
- (*progs)[progs_used] = NULL;
- }
-}
-
-static void refresh_path(const char* path, char*** progs)
-{
- DIR* dirp = opendir(path);
- struct dirent* dp;
- char fullpath[PATH_MAX];
- char* end;
- strcpy(fullpath, path);
- end = fullpath + strlen(fullpath);
-
- if (dirp == NULL)
- {
- if (errno != ENOENT)
- perror("opendir");
- return;
- }
-
- dp = readdir(dirp);
- while (dp != NULL)
- {
- strcat(end, "/");
- strcpy(end + 1, dp->d_name);
- if (isexecutable(fullpath))
- add(dp->d_name, progs);
- dp = readdir(dirp);
- }
- closedir(dirp);
-}
-
-static int compare(const void* a, const void* b)
-{
- return strcmp(*(const char**)a, *(const char**)b);
-}
-
-static void sort(char*** progs)
-{
- qsort(*progs, count_charpp(*progs), sizeof(*progs), compare);
-}
-
-static void uniq(char*** progs)
-{
- char** progs_new;
- char** ptr_1 = *progs;
- char** ptr_2 = ptr_1 + 1;
- unsigned long i = 0;;
-
- progs_new = (char**)malloc(sizeof(char*) * (count_charpp(*progs) + 1));
- if (progs_new == NULL)
- die("malloc");
-
- while (*ptr_1 != NULL)
- {
- while (*ptr_2 != NULL && strcmp(*ptr_1, *ptr_2) == 0)
- {
- free(*ptr_2);
- ptr_2++;
- }
- progs_new[i] = *ptr_1;
- i++;
- ptr_1 = ptr_2;
- ptr_2++;
- }
- progs_new[i] = NULL;
-
- free(*progs);
-
- *progs = progs_new;
-}
-
-static void refresh(char** paths)
-{
- char** progs = NULL;
- FILE* out;
- while (*paths != NULL)
- {
- refresh_path(*paths, &progs);
- paths++;
- }
- add(NULL, &progs);
-
- out = fopen(cache_path, "w");
- if (out == NULL)
- die("fopen");
-
- sort(&progs);
- uniq(&progs);
- fprint_charpp(progs, out);
- fprint_charpp(progs, stdout);
-
- free_charpp(progs);
- fclose(out);
-}
-
-static void cat()
-{
- FILE* cache = fopen(cache_path, "r");
- char buf[4096];
- struct stat cachestat;
- size_t still_unread;
- size_t chunk;
- if (cache == NULL)
- die("fopen");
-
- if (stat(cache_path, &cachestat))
- die("stat");
- still_unread = cachestat.st_size;
-
- while (still_unread > 0)
- {
- chunk = fread(buf, 1, sizeof(buf), cache);
- still_unread -= chunk;
- fwrite(buf, 1, chunk, stdout);
- }
- fclose(cache);
-}
-
-int main(int argc, char *argv[])
-{
- char* PATH;
- char** paths = NULL;
- PATH = get_PATH();
- uid = getuid();
- gid = getgid();
-
- cache_path = get_cache_path();
- split_PATH(PATH, &paths);
- free(PATH);
- sort(&paths);
- uniq(&paths);
-
- if ((argc == 2 && strcmp(argv[1], "-f") == 0)
- || !uptodate(paths))
- refresh(paths);
- else
- cat();
-
- free_charpp(paths);
- free(cache_path);
-
- return 0;
-}
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/dmenu_path.md
--- a/tools.suckless.org/dmenu/patches/dmenu_path.md Fri Dec 10 12:15:30 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
_AT_@ -1,11 +0,0 @@
-DMENU_PATH.C
-============
-
-The mainline dmenu_path is a shell script, which means it can be slow. Faster
-implementations have been written in C.
-
-Download
---------
-
-* [376 LOC](dmenu_path.c) by Elmo Todurov - <todurov_AT_gmail.com>
-* [100 LOC](dmenu_path-cls.c) by Connor Lane Smith - <cls_AT_lubutu.com>
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/kp_decimal.md
--- a/tools.suckless.org/dmenu/patches/kp_decimal.md Fri Dec 10 12:15:30 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
_AT_@ -1,14 +0,0 @@
-KEYPAD DECIMAL KEY
-==================
-
-This patch allows the decimal key on keypads to input a decimal in dmenu.
-
-Download
---------
-
-* [allow-kp_decimal-in-dmenu.patch](allow-kp_decimal-in-dmenu.patch)
-
-Author
-------
-
-* Thomas Adam (thomas_adam) <[thomas.adam22_AT_gmail.com](mailto:thomas.adam22_AT_gmail.com)>
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/allow-kp_decimal-in-dmenu.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools.suckless.org/dmenu/patches/legacy/allow-kp_decimal-in-dmenu.patch Sat Dec 11 03:20:12 2010 +0000
_AT_@ -0,0 +1,12 @@
+diff -r 4684b2cf4eab dmenu.c
+--- a/dmenu.c Sat Dec 05 16:52:53 2009 +0000
++++ b/dmenu.c Sun Dec 13 20:50:57 2009 +0000
+_AT_@ -395,6 +395,8 @@
+ ksym = XK_Return;
+ else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
+ ksym = (ksym - XK_KP_0) + XK_0;
++ else if(ksym == XK_KP_Decimal)
++ ksym = XK_period;
+ }
+ if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
+ || IsMiscFunctionKey(ksym) || IsPFKey(ksym)
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/dmenu-4.0-paste.diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools.suckless.org/dmenu/patches/legacy/dmenu-4.0-paste.diff Sat Dec 11 03:20:12 2010 +0000
_AT_@ -0,0 +1,27 @@
+diff -r f48e2b63129e dmenu.c
+--- a/dmenu.c Tue Oct 27 14:38:03 2009 -0700
++++ b/dmenu.c Thu Oct 29 13:14:21 2009 -0700
+_AT_@ -389,6 +389,23 @@
+ case XK_G:
+ ksym = XK_End;
+ break;
++ case XK_p:
++ {
++ FILE *fp;
++ char *c;
++ if(!(fp = (FILE*)popen("sselp", "r")))
++ fprintf(stderr, "dmenu: Could not popen sselp\n");
++ c = fgets(text + len, sizeof(text) - len, fp);
++ pclose(fp);
++ if(c == NULL)
++ return;
++ }
++ len = strlen(text);
++ if(len && text[len-1] == '\n')
++ text[--len] = '\0';
++ match(text);
++ drawmenu();
++ return;
+ }
+ }
+ switch(ksym) {
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/dmenu_path-cls.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools.suckless.org/dmenu/patches/legacy/dmenu_path-cls.c Sat Dec 11 03:20:12 2010 +0000
_AT_@ -0,0 +1,100 @@
+#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;
+}
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/dmenu_path.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools.suckless.org/dmenu/patches/legacy/dmenu_path.c Sat Dec 11 03:20:12 2010 +0000
_AT_@ -0,0 +1,376 @@
+/*
+ * dmenu_path
+ * This program dumps all executables in $PATH to stdout.
+ * It uses the file $HOME/.dmenu_cache as a cache.
+ *
+ * This program is released under the X11 license (sometimes known as the MIT
+ * license), which basically means that you can do whatever you want with it.
+ *
+ * Sorry for the hairy code. I didn't know how to make it simpler and still
+ * as generic. Valgrind claims it's correct and doesn't leak, but I'm sure you
+ * can find a couple of ways to make it crash.
+ *
+ * I'd appreciate, but I don't require, that you mail me any improvements or
+ * comments on the code.
+ *
+ * Elmo Todurov todurov+dmenu_AT_gmail.com
+ * 2010-05-19 09:55
+ */
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <assert.h>
+
+static uid_t uid;
+static gid_t gid;
+static char* cache_path;
+
+static int uptodate(char** paths)
+{
+ struct stat dirstat;
+ time_t cache_time;
+ char** dirs;
+
+ if (stat(cache_path, &dirstat))
+ {
+ if (errno != ENOENT)
+ {
+ perror("stat");
+ }
+ return 0;
+ }
+ cache_time = dirstat.st_mtime;
+
+ dirs = paths;
+ while (*dirs != NULL)
+ {
+ if (stat(*dirs, &dirstat))
+ {
+ if (errno != ENOENT)
+ perror("stat");
+ return 0;
+ }
+
+ if (cache_time < dirstat.st_mtime)
+ return 0;
+
+ dirs++;
+ }
+
+ return 1;
+}
+
+static void die(const char* msg)
+{
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+static char* get_cache_path()
+{
+ const char* home;
+ char* path;
+ home = getenv("HOME");
+ if (home == NULL)
+ die("getenv");
+ path = (char*)malloc(strlen(home) + strlen("/.dmenu_cache") + 1);
+ if (path == NULL)
+ die("malloc");
+ strcpy(path, home);
+ strcat(path, "/.dmenu_cache");
+ return path;
+}
+
+static char* get_PATH()
+{
+ const char* path = getenv("PATH");
+ char* copy_path;
+ if (path == NULL)
+ die("getenv");
+
+ copy_path = strdup(path);
+ return copy_path;
+}
+
+static void split_PATH(char* PATH, char*** dirs_in)
+{
+ char** dirs;
+ const char* dir = strtok(PATH, ":");
+ size_t i = 0;
+ size_t allocated = 10;
+ dirs = (char**)malloc(sizeof(char*) * allocated);
+ if (dirs == NULL)
+ die("malloc");
+
+ while (dir != NULL)
+ {
+ dirs[i] = (char*)malloc(strlen(dir) + 1);
+ if (dirs[i] == NULL)
+ die("malloc");
+ strcpy(dirs[i], dir);
+ dir = strtok(NULL, ":");
+ i++;
+ if (i == allocated)
+ {
+ allocated *= 2;
+ dirs = (char**)realloc(dirs, allocated * sizeof(char**));
+ if (dirs == NULL)
+ die("realloc");
+ }
+ }
+ dirs[i] = NULL;
+
+ *dirs_in = dirs;
+}
+
+static void free_charpp(char** in)
+{
+ char** ptr = in;
+ while (*ptr != NULL)
+ {
+ free(*ptr);
+ ptr++;
+ }
+ free(in);
+}
+
+static void fprint_charpp(char** in, FILE* out)
+{
+ char** ptr = in;
+ while (*ptr != NULL)
+ {
+ fputs(*ptr, out);
+ fputc('\n', out);
+ ptr++;
+ }
+}
+
+static size_t count_charpp(char** in)
+{
+ char** ptr = in;
+ size_t count = 0;
+ while (*ptr != NULL)
+ {
+ count++;
+ ptr++;
+ }
+ return count;
+}
+
+static int isexecutable(const char* fname)
+{
+ struct stat st;
+ int ret;
+ int success;
+ gid_t* grouplist;
+
+ ret = stat(fname, &st);
+ if (ret != 0)
+ return 0;
+ if (!S_ISREG(st.st_mode)) /* this catches regular files and symlinks as well */
+ return 0;
+ if ((st.st_uid == uid && (st.st_mode & S_IXUSR) != 0)
+ || (st.st_uid != uid && st.st_gid != gid && (st.st_mode & S_IXOTH) != 0))
+ {
+ return 1;
+ }
+
+ /* check secondary groups */
+ if (st.st_mode & S_IXGRP)
+ {
+ success = 0;
+ ret = getgroups(0, 0);
+ grouplist = (gid_t*)malloc(sizeof(gid_t) * ret);
+ if (grouplist == NULL)
+ die("malloc");
+ ret = getgroups(ret, grouplist);
+ while (ret != 0)
+ {
+ ret--;
+ if (st.st_uid != uid /* for group to match, user must not match. */
+ && st.st_gid == grouplist[ret])
+ {
+ success = 1;
+ break;
+ }
+ }
+ free(grouplist);
+ return success;
+ }
+
+ return 0;
+}
+
+static void add(const char* prog, char*** progs)
+{
+ static unsigned progs_allocated = 0;
+ static unsigned progs_used = 0;
+
+ if (progs_used == progs_allocated)
+ {
+ progs_allocated = progs_allocated == 0 ? 256 : progs_allocated * 2;
+ *progs = (char**)realloc(*progs, sizeof(char*) * progs_allocated);
+ if (*progs == NULL)
+ die("realloc");
+ }
+
+ if (prog != NULL)
+ {
+ (*progs)[progs_used] = (char*)malloc(strlen(prog) + 1);
+ if ((*progs)[progs_used] == NULL)
+ die("malloc");
+ strcpy((*progs)[progs_used], prog);
+ progs_used++;
+ }
+ else
+ {
+ (*progs)[progs_used] = NULL;
+ }
+}
+
+static void refresh_path(const char* path, char*** progs)
+{
+ DIR* dirp = opendir(path);
+ struct dirent* dp;
+ char fullpath[PATH_MAX];
+ char* end;
+ strcpy(fullpath, path);
+ end = fullpath + strlen(fullpath);
+
+ if (dirp == NULL)
+ {
+ if (errno != ENOENT)
+ perror("opendir");
+ return;
+ }
+
+ dp = readdir(dirp);
+ while (dp != NULL)
+ {
+ strcat(end, "/");
+ strcpy(end + 1, dp->d_name);
+ if (isexecutable(fullpath))
+ add(dp->d_name, progs);
+ dp = readdir(dirp);
+ }
+ closedir(dirp);
+}
+
+static int compare(const void* a, const void* b)
+{
+ return strcmp(*(const char**)a, *(const char**)b);
+}
+
+static void sort(char*** progs)
+{
+ qsort(*progs, count_charpp(*progs), sizeof(*progs), compare);
+}
+
+static void uniq(char*** progs)
+{
+ char** progs_new;
+ char** ptr_1 = *progs;
+ char** ptr_2 = ptr_1 + 1;
+ unsigned long i = 0;;
+
+ progs_new = (char**)malloc(sizeof(char*) * (count_charpp(*progs) + 1));
+ if (progs_new == NULL)
+ die("malloc");
+
+ while (*ptr_1 != NULL)
+ {
+ while (*ptr_2 != NULL && strcmp(*ptr_1, *ptr_2) == 0)
+ {
+ free(*ptr_2);
+ ptr_2++;
+ }
+ progs_new[i] = *ptr_1;
+ i++;
+ ptr_1 = ptr_2;
+ ptr_2++;
+ }
+ progs_new[i] = NULL;
+
+ free(*progs);
+
+ *progs = progs_new;
+}
+
+static void refresh(char** paths)
+{
+ char** progs = NULL;
+ FILE* out;
+ while (*paths != NULL)
+ {
+ refresh_path(*paths, &progs);
+ paths++;
+ }
+ add(NULL, &progs);
+
+ out = fopen(cache_path, "w");
+ if (out == NULL)
+ die("fopen");
+
+ sort(&progs);
+ uniq(&progs);
+ fprint_charpp(progs, out);
+ fprint_charpp(progs, stdout);
+
+ free_charpp(progs);
+ fclose(out);
+}
+
+static void cat()
+{
+ FILE* cache = fopen(cache_path, "r");
+ char buf[4096];
+ struct stat cachestat;
+ size_t still_unread;
+ size_t chunk;
+ if (cache == NULL)
+ die("fopen");
+
+ if (stat(cache_path, &cachestat))
+ die("stat");
+ still_unread = cachestat.st_size;
+
+ while (still_unread > 0)
+ {
+ chunk = fread(buf, 1, sizeof(buf), cache);
+ still_unread -= chunk;
+ fwrite(buf, 1, chunk, stdout);
+ }
+ fclose(cache);
+}
+
+int main(int argc, char *argv[])
+{
+ char* PATH;
+ char** paths = NULL;
+ PATH = get_PATH();
+ uid = getuid();
+ gid = getgid();
+
+ cache_path = get_cache_path();
+ split_PATH(PATH, &paths);
+ free(PATH);
+ sort(&paths);
+ uniq(&paths);
+
+ if ((argc == 2 && strcmp(argv[1], "-f") == 0)
+ || !uptodate(paths))
+ refresh(paths);
+ else
+ cat();
+
+ free_charpp(paths);
+ free(cache_path);
+
+ return 0;
+}
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/dmenu_path.md
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools.suckless.org/dmenu/patches/legacy/dmenu_path.md Sat Dec 11 03:20:12 2010 +0000
_AT_@ -0,0 +1,11 @@
+DMENU_PATH.C
+============
+
+The mainline dmenu_path is a shell script, which means it can be slow. Faster
+implementations have been written in C.
+
+Download
+--------
+
+* [376 LOC](dmenu_path.c) by Elmo Todurov - <todurov_AT_gmail.com>
+* [100 LOC](dmenu_path-cls.c) by Connor Lane Smith - <cls_AT_lubutu.com>
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/index.md
--- a/tools.suckless.org/dmenu/patches/legacy/index.md Fri Dec 10 12:15:30 2010 +0100
+++ b/tools.suckless.org/dmenu/patches/legacy/index.md Sat Dec 11 03:20:12 2010 +0000
_AT_@ -1,4 +1,4 @@
LEGACY PATCHES
==============
-Patches that have been integrated to dmenu and that do not apply anymore
+Patches that have since been merged into dmenu trunk in the latest release.
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/kp_decimal.md
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools.suckless.org/dmenu/patches/legacy/kp_decimal.md Sat Dec 11 03:20:12 2010 +0000
_AT_@ -0,0 +1,14 @@
+KEYPAD DECIMAL KEY
+==================
+
+This patch allows the decimal key on keypads to input a decimal in dmenu.
+
+Download
+--------
+
+* [allow-kp_decimal-in-dmenu.patch](allow-kp_decimal-in-dmenu.patch)
+
+Author
+------
+
+* Thomas Adam (thomas_adam) <[thomas.adam22_AT_gmail.com](mailto:thomas.adam22_AT_gmail.com)>
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/legacy/paste.md
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools.suckless.org/dmenu/patches/legacy/paste.md Sat Dec 11 03:20:12 2010 +0000
_AT_@ -0,0 +1,23 @@
+PASTE
+=====
+
+Description
+-----------
+
+This patch allows you to paste the contents of the X selection into dmenu. The
+default keybinding for this is mod1+p.
+
+The patch depends on [sselp](/sselp).
+
+Download
+--------
+
+* [dmenu-4.0-paste.diff](dmenu-4.0-paste.diff) (597) (20091029)
+
+Author
+------
+
+* Evan Gates (emg) <[evan.gates_AT_gmail.com](mailto:evan.gates_AT_gmail.com)>
+
+
+***Note, this patch is present in dmenu-4.1.1.***
diff -r 3214ae7e3478 -r 61b9d6aca10f tools.suckless.org/dmenu/patches/paste.md
--- a/tools.suckless.org/dmenu/patches/paste.md Fri Dec 10 12:15:30 2010 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
_AT_@ -1,23 +0,0 @@
-PASTE
-=====
-
-Description
------------
-
-This patch allows you to paste the contents of the X selection into dmenu. The
-default keybinding for this is mod1+p.
-
-The patch depends on [sselp](/sselp).
-
-Download
---------
-
-* [dmenu-4.0-paste.diff](dmenu-4.0-paste.diff) (597) (20091029)
-
-Author
-------
-
-* Evan Gates (emg) <[evan.gates_AT_gmail.com](mailto:evan.gates_AT_gmail.com)>
-
-
-***Note, this patch is present in dmenu-4.1.1.***
Received on Sat Dec 11 2010 - 04:20:34 CET