166 lines
4.0 KiB
C
Executable File
166 lines
4.0 KiB
C
Executable File
#!/usr/bin/tcc -run
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
void print_man_dir(FILE *menu, const char *dir) {
|
|
DIR *d = opendir(dir);
|
|
if (!d) {
|
|
return;
|
|
}
|
|
|
|
struct dirent *ent;
|
|
while ((ent = readdir(d))) {
|
|
if (ent->d_name[0] == '.') {
|
|
continue;
|
|
}
|
|
|
|
char file[512];
|
|
snprintf(file, sizeof(file), "%s", ent->d_name);
|
|
|
|
const char *suffixes[] = {".gz", ".bz2", ".xz", ".lzma", ".zst"};
|
|
for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); i++) {
|
|
size_t flen = strlen(file);
|
|
size_t slen = strlen(suffixes[i]);
|
|
if (flen > slen && strcmp(file + flen - slen, suffixes[i]) == 0) {
|
|
file[flen - slen] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
char *dot = strrchr(file, '.');
|
|
if (!dot || dot == file || !dot[1]) {
|
|
continue;
|
|
}
|
|
|
|
*dot++ = '\0';
|
|
fprintf(menu, "%s (%s)\tman\n", file, dot);
|
|
}
|
|
|
|
closedir(d);
|
|
}
|
|
|
|
void print_man_pages(FILE *menu, const char *root) {
|
|
DIR *d = opendir(root);
|
|
if (!d) {
|
|
return;
|
|
}
|
|
|
|
struct dirent *ent;
|
|
char path[4096];
|
|
while ((ent = readdir(d))) {
|
|
if (strncmp(ent->d_name, "man", 3) != 0) {
|
|
continue;
|
|
}
|
|
|
|
snprintf(path, sizeof(path), "%s/%s", root, ent->d_name);
|
|
print_man_dir(menu, path);
|
|
}
|
|
|
|
closedir(d);
|
|
}
|
|
|
|
int main(void) {
|
|
char path[] = "/tmp/docs-list.XXXXXX";
|
|
int fd = mkstemp(path);
|
|
if (fd < 0) {
|
|
perror("mkstemp");
|
|
return 1;
|
|
}
|
|
|
|
FILE *menu = fdopen(fd, "w");
|
|
if (!menu) {
|
|
perror("fdopen");
|
|
unlink(path);
|
|
return 1;
|
|
}
|
|
|
|
char line[8192];
|
|
FILE *manpath = popen("manpath 2>/dev/null", "r");
|
|
if (manpath && fgets(line, sizeof(line), manpath)) {
|
|
line[strcspn(line, "\n")] = '\0';
|
|
for (char *dir = strtok(line, ":"); dir; dir = strtok(NULL, ":")) {
|
|
print_man_pages(menu, dir);
|
|
}
|
|
}
|
|
if (manpath) {
|
|
pclose(manpath);
|
|
}
|
|
|
|
FILE *pydoc = popen("python -c 'import pkgutil; [print(m) for m in sorted({m.name for m in pkgutil.iter_modules()})]'", "r");
|
|
if (pydoc) {
|
|
while (fgets(line, sizeof(line), pydoc)) {
|
|
line[strcspn(line, "\n")] = '\0';
|
|
fprintf(menu, "%s\tpydoc\n", line);
|
|
}
|
|
pclose(pydoc);
|
|
}
|
|
|
|
fclose(menu);
|
|
|
|
char command[1024];
|
|
snprintf(command, sizeof(command), "wmenu -i -l 20 < '%s'", path);
|
|
|
|
FILE *wmenu = popen(command, "r");
|
|
if (!wmenu) {
|
|
perror("wmenu");
|
|
unlink(path);
|
|
return 1;
|
|
}
|
|
|
|
if (!fgets(line, sizeof(line), wmenu)) {
|
|
pclose(wmenu);
|
|
unlink(path);
|
|
return 0;
|
|
}
|
|
|
|
int status = pclose(wmenu);
|
|
unlink(path);
|
|
if (status != 0) {
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : 1;
|
|
}
|
|
|
|
line[strcspn(line, "\n")] = '\0';
|
|
char *kind = strrchr(line, '\t');
|
|
if (!kind) {
|
|
return 0;
|
|
}
|
|
*kind++ = '\0';
|
|
|
|
if (strcmp(kind, "man") == 0) {
|
|
char *s = line;
|
|
char name[256] = {0};
|
|
char section[64] = {0};
|
|
size_t i = 0;
|
|
|
|
while (*s && !isspace((unsigned char)*s) && *s != '(' && i < sizeof(name) - 1) {
|
|
name[i++] = *s++;
|
|
}
|
|
|
|
char *open = strchr(s, '(');
|
|
char *close = open ? strchr(open + 1, ')') : NULL;
|
|
if (open && close && close > open + 1) {
|
|
size_t len = close - open - 1;
|
|
if (len >= sizeof(section)) {
|
|
len = sizeof(section) - 1;
|
|
}
|
|
memcpy(section, open + 1, len);
|
|
}
|
|
|
|
if (name[0] && section[0]) {
|
|
execlp("foot", "foot", "-e", "man", section, name, NULL);
|
|
} else if (name[0]) {
|
|
execlp("foot", "foot", "-e", "man", name, NULL);
|
|
}
|
|
} else if (strcmp(kind, "pydoc") == 0 && line[0]) {
|
|
execlp("foot", "foot", "-e", "python", "-m", "pydoc", line, NULL);
|
|
}
|
|
|
|
perror("foot");
|
|
return 1;
|
|
}
|