dmenu_path.c (shell is a bottleneck) bf7b8e37
Connor Lane Smith · 2010-10-08 23:24 3 file(s) · +108 −34
Makefile +7 −8
3 3
4 4
include config.mk
5 5
6 -
all: options dmenu
6 +
all: options dmenu dmenu_path
7 7
8 8
options:
9 9
	@echo dmenu build options:
11 11
	@echo "LDFLAGS  = ${LDFLAGS}"
12 12
	@echo "CC       = ${CC}"
13 13
14 -
dmenu.o: dmenu.c config.mk
15 -
	@echo CC $<
16 -
	@${CC} -c ${CFLAGS} $<
14 +
dmenu: dmenu.c config.mk
15 +
dmenu_path: dmenu_path.c
17 16
18 -
dmenu: dmenu.o
17 +
dmenu dmenu_path:
19 18
	@echo CC -o $@
20 -
	@${CC} -o $@ $+ ${LDFLAGS}
19 +
	@${CC} -o $@ $< ${CFLAGS} ${LDFLAGS}
21 20
22 21
clean:
23 22
	@echo cleaning
24 -
	@rm -f dmenu dmenu.o dmenu-${VERSION}.tar.gz
23 +
	@rm -f dmenu dmenu_path dmenu-${VERSION}.tar.gz
25 24
26 25
dist: clean
27 26
	@echo creating dist tarball
28 27
	@mkdir -p dmenu-${VERSION}
29 -
	@cp LICENSE Makefile README config.mk dmenu.1 dmenu.c dmenu_path dmenu_run dmenu-${VERSION}
28 +
	@cp LICENSE Makefile README config.mk dmenu.1 dmenu.c dmenu_path.c dmenu_run dmenu-${VERSION}
30 29
	@tar -cf dmenu-${VERSION}.tar dmenu-${VERSION}
31 30
	@gzip dmenu-${VERSION}.tar
32 31
	@rm -rf dmenu-${VERSION}
dmenu_path (deleted) +0 −26
1 -
#!/bin/sh
2 -
CACHE=$HOME/.dmenu_cache
3 -
IFS=:
4 -
5 -
uptodate() {
6 -
	test -f "$CACHE" &&
7 -
	for dir in $PATH
8 -
	do
9 -
		test ! $dir -nt "$CACHE" || return 1
10 -
	done
11 -
}
12 -
13 -
if ! uptodate
14 -
then
15 -
	for dir in $PATH
16 -
	do
17 -
		cd "$dir" &&
18 -
		for file in *
19 -
		do
20 -
			test -x "$file" && echo "$file"
21 -
		done
22 -
	done | sort -u > "$CACHE".$$ &&
23 -
	mv "$CACHE".$$ "$CACHE"
24 -
fi
25 -
26 -
cat "$CACHE"
dmenu_path.c (added) +101 −0
1 +
/* See LICENSE file for copyright and license details. */
2 +
#include <dirent.h>
3 +
#include <stdio.h>
4 +
#include <stdlib.h>
5 +
#include <string.h>
6 +
#include <unistd.h>
7 +
#include <sys/stat.h>
8 +
9 +
#define CACHE ".dmenu_cache"
10 +
11 +
static int qstrcmp(const void *a, const void *b);
12 +
static void die(const char *s);
13 +
static void scan(void);
14 +
static int uptodate(void);
15 +
16 +
static char **items = NULL;
17 +
static const char *Home, *Path;
18 +
static size_t count = 0;
19 +
20 +
int
21 +
main(void) {
22 +
	if(!(Home = getenv("HOME")))
23 +
		die("no $HOME");
24 +
	if(!(Path = getenv("PATH")))
25 +
		die("no $PATH");
26 +
	if(chdir(Home) < 0)
27 +
		die("chdir failed");
28 +
	if(uptodate()) {
29 +
		execlp("cat", "cat", CACHE, NULL);
30 +
		die("exec failed");
31 +
	}
32 +
	scan();
33 +
	return EXIT_SUCCESS;
34 +
}
35 +
36 +
void
37 +
die(const char *s) {
38 +
	fprintf(stderr, "dmenu_path: %s\n", s);
39 +
	exit(EXIT_FAILURE);
40 +
}
41 +
42 +
int
43 +
qstrcmp(const void *a, const void *b) {
44 +
	return strcmp(*(const char **)a, *(const char **)b);
45 +
}
46 +
47 +
void
48 +
scan(void) {
49 +
	char buf[PATH_MAX];
50 +
	char *dir, *path;
51 +
	size_t i;
52 +
	struct dirent *ent;
53 +
	DIR *dp;
54 +
	FILE *cache;
55 +
56 +
	if(!(path = strdup(Path)))
57 +
		die("strdup failed");
58 +
	for(dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) {
59 +
		if(!(dp = opendir(dir)))
60 +
			continue;
61 +
		while((ent = readdir(dp))) {
62 +
			snprintf(buf, sizeof buf, "%s/%s", dir, ent->d_name);
63 +
			if(ent->d_name[0] == '.' || access(buf, X_OK) < 0)
64 +
				continue;
65 +
			if(!(items = realloc(items, ++count * sizeof *items)))
66 +
				die("malloc failed");
67 +
			if(!(items[count-1] = strdup(ent->d_name)))
68 +
				die("strdup failed");
69 +
		}
70 +
		closedir(dp);
71 +
	}
72 +
	qsort(items, count, sizeof *items, qstrcmp);
73 +
	if(!(cache = fopen(CACHE, "w")))
74 +
		die("open failed");
75 +
	for(i = 0; i < count; i++) {
76 +
		if(i > 0 && !strcmp(items[i], items[i-1]))
77 +
			continue;
78 +
		fprintf(cache,  "%s\n", items[i]);
79 +
		fprintf(stdout, "%s\n", items[i]);
80 +
	}
81 +
	fclose(cache);
82 +
	free(path);
83 +
}
84 +
85 +
int
86 +
uptodate(void) {
87 +
	char *dir, *path;
88 +
	time_t mtime;
89 +
	struct stat st;
90 +
91 +
	if(stat(CACHE, &st) < 0)
92 +
		return 0;
93 +
	mtime = st.st_mtime;
94 +
	if(!(path = strdup(Path)))
95 +
		die("strdup failed");
96 +
	for(dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
97 +
		if(!stat(dir, &st) && st.st_mtime > mtime)
98 +
			return 0;
99 +
	free(path);
100 +
	return 1;
101 +
}