forked from nyyManni/dmenu-wayland
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdmenu_path.c
More file actions
123 lines (95 loc) · 2.13 KB
/
dmenu_path.c
File metadata and controls
123 lines (95 loc) · 2.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#define CACHE ".dmenu_cache"
static void die(const char *s);
static int qstrcmp(const void *a, const void *b);
static void scan(void);
static int uptodate(void);
static char **items = NULL;
static const char *home, *path;
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, *p;
size_t i, count;
struct dirent *ent;
DIR *dp;
FILE *cache;
count = 0;
if(!(p = strdup(path))) {
die("strdup failed");
}
for(dir = strtok(p, ":"); 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(p);
}
int uptodate(void) {
char *dir, *p;
time_t mtime;
struct stat st;
if(stat(CACHE, &st) < 0) {
return 0;
}
mtime = st.st_mtime;
if(!(p = strdup(path))) {
die("strdup failed");
}
for(dir = strtok(p, ":"); dir; dir = strtok(NULL, ":")) {
if(!stat(dir, &st) && st.st_mtime > mtime) {
return 0;
}
}
free(p);
return 1;
}