aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/man.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/pending/man.c')
-rw-r--r--toys/pending/man.c125
1 files changed, 79 insertions, 46 deletions
diff --git a/toys/pending/man.c b/toys/pending/man.c
index 9abf92bc..0e54e93c 100644
--- a/toys/pending/man.c
+++ b/toys/pending/man.c
@@ -4,7 +4,7 @@
*
* See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/man.html
-USE_MAN(NEWTOY(man, "<1>2k:M:", TOYFLAG_USR|TOYFLAG_BIN))
+USE_MAN(NEWTOY(man, "k:M:", TOYFLAG_USR|TOYFLAG_BIN))
config MAN
bool "man"
@@ -28,16 +28,17 @@ config MAN
#define FOR_man
#include <toys.h>
-#include <glob.h>
GLOBALS(
char *M, *k;
- char any, cell, *f, *line;
+ char any, cell, ex, *f, k_done, *line, **sufs;
+ regex_t reg;
)
static void newln()
{
+ if (FLAG(k)) return;
if (TT.any) putchar('\n');
if (TT.any && TT.cell != 2) putchar('\n'); // gawk alias
TT.any = TT.cell = 0;
@@ -45,7 +46,7 @@ static void newln()
static void put(char *x)
{
- while (*x && *x != '\n') TT.any = putchar(*x++);
+ while (*x && (TT.ex || *x != '\n')) TT.any = putchar(*x++);
}
// Substitute with same length or shorter.
@@ -56,6 +57,7 @@ static void s(char *x, char *y)
for (k = 0; TT.line[k]; k++) if (!strncmp(x, &TT.line[k], i)) {
memmove(&TT.line[k], y, j);
for (l = k += j; TT.line[l]; l++) TT.line[l] = TT.line[l + i - j];
+ k--;
}
}
@@ -69,17 +71,23 @@ static void trim(char *x)
if (start(x)) while (*x++) TT.line++;
}
+static char k(char *s) {
+ TT.k_done = 2;
+ if (s) TT.line = s;
+ return !regexec(&TT.reg, TT.k, 0, 0, 0)||!regexec(&TT.reg, TT.line, 0, 0, 0);
+}
+
static void do_man(char **pline, long len)
{
- char *line;
-
- if (!pline) {
- newln();
- return;
- }
- line = *pline;
-
- TT.line = line;
+ if (!pline) return newln();
+ TT.line = *pline;
+
+ if (FLAG(k)) {
+ if (!TT.k_done && !start(".") && !start("'") && k(strstr(*pline, "- ")))
+ printf("%s %s%s", TT.k, "- "+2*(TT.line!=*pline), TT.line);
+ else if (!TT.k_done && start(".so") && k(basename(*pline + 4)))
+ printf("%s - See %s", TT.k, TT.line);
+ } else {
s("\\fB", ""), s("\\fI", ""), s("\\fP", ""), s("\\fR", ""); // bash bold,ita
s("\\(aq", "'"), s("\\(cq", "'"), s("\\(dq", "\""); // bash,rsync quote
s("\\*(lq", "\""), s("\\*(rq", "\""); // gawk quote
@@ -97,7 +105,8 @@ static void do_man(char **pline, long len)
trim(".FN "); // bash filename
trim(".I "); // bash ita
trim(".if n "); // bash nroff
- if (start(".PP")) newln(); // bash paragraph
+ if (start(".E")) TT.ex = TT.line[2] == 'X'; // stat example
+ else if (start(".PP")) newln(); // bash paragraph
else if (start(".SM")); // bash small
else if (start(".S")) newln(), put(TT.line + 4), newln(); // bash section
else if (start(".so")) put("See "), put(basename(TT.line + 4)); // lastb
@@ -107,56 +116,80 @@ static void do_man(char **pline, long len)
else if (!*TT.line); // emerge
else {
if (TT.cell) TT.cell++;
- put(" ");
+ if (!TT.ex) put(" ");
put(TT.line);
}
+ }
+}
+
+// Open file, decompressing if suffix known.
+static int zopen(char *s)
+{
+ int fds[] = {-1, -1};
+ char **known = TT.sufs, *suf = strrchr(s, '.');
+
+ if ((*fds = open(s, O_RDONLY)) == -1) return -1;
+ while (suf && *known && strcmp(suf, *known++));
+ if (!suf || !*known) return *fds;
+ sprintf(toybuf, "%czcat"+2*(suf[1]=='g'), suf[1]);
+ xpopen_both((char *[]){toybuf, s, 0}, fds);
+ close(fds[0]);
+ return fds[1];
}
// Try opening all the possible file extensions.
int tryfile(char *section, char *name)
{
- char *suf[] = {".gz", ".bz2", ".xz", ""}, *end,
- *s = xmprintf("%s/man%s/%s.%s.bz2", TT.M, section, name, section);
- int fd, i, and = 1;
-
- end = s+strlen(s);
- do {
- for (i = 0; i<ARRAY_LEN(suf); i++) {
- strcpy(end-4, suf[i]);
- if ((fd = open(s, O_RDONLY))!= -1) {
- if (*suf[i]) {
- int fds[] = {fd, -1};
-
- sprintf(toybuf, "%czcat"+(2*!i), suf[i][1]);
- xpopen_both((char *[]){toybuf, s, 0}, fds);
- fd = fds[1];
- }
- goto done;
- }
- }
- end -= strlen(section)+1;
- } while (and--);
-
-done:
+ char *s = xmprintf("%s/man%s/%s.%s.bz2", TT.M, section, name, section), **suf;
+ int dotnum, fd = -1;
+ size_t len = strlen(s) - 4;
+
+ for (dotnum = 0; dotnum <= 2; dotnum += 2) {
+ suf = TT.sufs;
+ while ((fd == -1) && *suf) strcpy(s + len - dotnum, *suf++), fd = zopen(s);
+ // Recheck suf in zopen, because for x.1.gz name here it is "".
+ }
free(s);
return fd;
}
void man_main(void)
{
- char *order = "18325467";
- int fd;
+ int fd = -1;
+ char **order = (char *[]) {"1", "8", "3", "2", "5", "4", "6", "7", 0};
+ TT.sufs = (char *[]) {".bz2", ".gz", ".xz", "", 0};
if (!TT.M) TT.M = "/usr/share/man";
- if (!toys.optc || FLAG(k)) error_exit("not yet");
+ if (FLAG(k)) {
+ char *d, *f;
+ DIR *dp;
+ struct dirent *entry;
+ if (regcomp(&TT.reg, TT.k, REG_ICASE|REG_NOSUB)) error_exit("bad regex");
+ while (*order) {
+ d = xmprintf("%s/man%s", TT.M, *order++);
+ if (!(dp = opendir(d))) continue;
+ while ((entry = readdir(dp))) {
+ if (entry->d_name[0] == '.') continue;
+ f = xmprintf("%s/%s", d, TT.k = entry->d_name);
+ if (-1 != (fd = zopen(f))) {
+ TT.k_done = 0;
+ do_lines(fd, '\n', do_man);
+ close(fd);
+ }
+ free(f);
+ }
+ closedir(dp);
+ free(d);
+ }
+ return regfree(&TT.reg);
+ }
+
+ if (!toys.optc) error_exit("not yet");
if (toys.optc == 1) {
- if (strchr(*toys.optargs, '/')) fd = xopen(*toys.optargs, O_RDONLY);
- else for (order = "18325467"; *order; order++) {
- *toybuf = *order;
- if (-1 != (fd = tryfile(toybuf, *toys.optargs))) break;
- }
+ if (strchr(*toys.optargs, '/')) fd = zopen(*toys.optargs);
+ else while ((fd == -1) && *order) fd = tryfile(*order++, *toys.optargs);
if (!*order) error_exit("no %s", *toys.optargs);
// If they specified a section, look for file in that section