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
|
#include "path.h"
#include "application.h"
#include "tllist.h"
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#define LOG_MODULE "path"
#define LOG_ENABLE_DBG 0
#include "log.h"
#include "xdg.h"
#include "char32.h"
#include "xmalloc.h"
void
path_find_programs(struct application_list *applications)
{
const char *_path = getenv("PATH");
if (_path == NULL)
return ;
char *copy = xstrdup(_path);
char *ctx = NULL;
tll(struct application *) entries = tll_init();
for (const char *tok = strtok_r(copy, ":", &ctx);
tok != NULL;
tok = strtok_r(NULL, ":", &ctx))
{
DIR *d = opendir(tok);
if (d == NULL) {
LOG_WARN("failed to open %s from PATH: %s", tok, strerror(errno));
continue;
}
int fd = dirfd(d);
if (fd == -1) {
LOG_WARN("failed to open %s's fd from PATH: %s", tok, strerror(errno));
closedir(d);
continue;
}
for (const struct dirent *e = readdir(d); e != NULL; e = readdir(d)) {
if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
continue;
struct stat st;
if (fstatat(fd, e->d_name, &st, 0) == -1) {
LOG_WARN("%s: failed to stat: %s", e->d_name, strerror(errno));
continue;
}
if (S_ISREG(st.st_mode) && st.st_mode & S_IXUSR) {
char32_t *wtitle = ambstoc32(e->d_name);
if (wtitle == NULL)
continue;
bool already_exist = false;
tll_foreach(entries, it) {
if (c32cmp(wtitle, it->item->title) == 0) {
already_exist = true;
break;
}
};
if (already_exist) {
free(wtitle);
continue;
}
char32_t *lowercase = xc32dup(wtitle);
for (size_t i = 0; i < c32len(lowercase); i++)
lowercase[i] = toc32lower(lowercase[i]);
struct application *app = xmalloc(sizeof(*app));
*app = (struct application){
.index = 0, /* Not used in application mode */
.title = wtitle,
.title_lowercase = lowercase,
.title_len = c32len(lowercase),
.exec = xstrjoin3(tok, "/", e->d_name),
.visible = true,
};
tll_push_back(entries, app);
}
}
closedir(d);
}
free(copy);
applications->v = xreallocarray(
applications->v, applications->count + tll_length(entries), sizeof(applications->v[0]));
tll_foreach(entries, it) {
applications->v[applications->count++] = it->item;
applications->visible_count++;
tll_remove(entries, it);
}
}
|