#!/usr/bin/tcc -run #include #include #include #include #include #include #include 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; }