From 5a1a668ce924a9a94c4c4fec5df734070325eeb2 Mon Sep 17 00:00:00 2001 From: "makepost@firemail.cc" Date: Fri, 19 Apr 2019 15:49:14 -0400 Subject: Implement man. To look up docs on my netbook and server. Practically deroff.1, with heuristic for where to put spaces and newlines. How would you simplify file resolution and bzcat? What have I got wrong when escaping slashes, because while \-\^\- is -- ok, \-\- becomes -\-, e.g. in git-pull.1? --- tests/man.test | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++ toys/pending/man.c | 112 ++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 tests/man.test create mode 100644 toys/pending/man.c diff --git a/tests/man.test b/tests/man.test new file mode 100644 index 00000000..51c492a2 --- /dev/null +++ b/tests/man.test @@ -0,0 +1,196 @@ +#!/bin/bash +# Copyright 2019 makepost + +[ -f testing.sh ] && . testing.sh + +#testing "name" "command" "result" "infile" "stdin" + +x=$((RANDOM)) +echo $x | bzip2 >/usr/share/man/man1/toybox.1.bz2 +testing "curl_strequal" "man toybox" " $x\n\n" "" "" + +x=$((RANDOM)) +echo $x | bzip2 >/usr/share/man/man1/toybox.1.bz2 +testing "curl_strequal.3" "man toybox.1" " $x\n\n" "" "" + +rm /usr/share/man/man1/toybox.1.bz2 + +x=$((RANDOM)) +echo $x >/usr/share/man/man1/toybox.1 +testing "curl_strnequal" "man toybox" " $x\n\n" "" "" + +x=$((RANDOM)) +echo $x >/usr/share/man/man1/toybox.1 +testing "curl_strnequal.3" "man toybox.1" " $x\n\n" "" "" + +cat >/usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 +testing "gawk quote" "man toybox" " \"--\"\n\n" "" "" + +cat >/usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 <= 1 +EOF +testing "bash escape" "man toybox" " \"\C-x\C-r\": re-read must be >= 1\n\n" "" "" + +echo "\\*(AK language. The \\*(PX standard" >/usr/share/man/man1/toybox.1 +testing "gawk var" "man toybox" " #AK language. The #PX standard\n\n" "" "" + +cat >/usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 +testing "lastb" "man toybox" "See last.1\n\n" "" "" + +cat >/usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 </usr/share/man/man1/toybox.1 < + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/man.html + +USE_MAN(NEWTOY(man, "<1>1", TOYFLAG_USR|TOYFLAG_BIN)) + +config MAN + bool "man" + default n + help + usage: man COMMAND + + Read manual for system command. +*/ + +#define FOR_man +#include +#include + +GLOBALS( + char any, cell, *f, *line; +) + +static void newln() +{ + if (TT.any) putchar('\n'); + if (TT.any && TT.cell != 2) putchar('\n'); // gawk alias + TT.any = TT.cell = 0; +} +static void put(char *x) { while (*x && *x != '\n') TT.any = putchar(*x++); } + +static void s(char *x, char *y) { // Substitute with same length or shorter. + int i = strlen(x), j = strlen(y), k, l; + 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]; + } +} + +static char start(char *x) { return !strncmp(x, TT.line, strlen(x)); } +static void trim(char *x) { if (start(x)) while (*x++) TT.line++; } + +static void do_man(FILE *fp) +{ + size_t len = 0; + char *line = 0; + while (getline(&line, &len, fp) > 0) { + TT.line = line; + 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 + s("\\(bu", "*"), s("\\(bv", "|"); // bash symbol + s("\\&", ""), s("\\f(CW", ""); // gawk,rsync fancy + s("\\-", "-"), s("\\(", ""), s("\\^", ""), s("\\e", "\\"); // bash escape + s("\\*(", "#"); // gawk var + if (start(".BR")) trim(".BR "), s(" ", ""); // bash boldpunct + if (start(".IP")) newln(), trim(".IP "); // bash list + if (start(".IR")) trim(".IR "), s(" ", ""); // bash itapunct + trim(".B "); // bash bold + trim(".BI "); // gawk boldita + trim(".FN "); // bash filename + trim(".I "); // bash ita + trim(".if n "); // bash nroff + 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 + else if (start(".TH")) s("\"", " "), put(TT.line + 4); // gawk,git head + else if (start(".TP")) newln(), TT.cell = 1; // bash table + else if (start(".") || start("\'")); // bash,git garbage + else if (!*TT.line); // emerge + else ((TT.cell != 0) && TT.cell++), put(" "), put(TT.line); + } + newln(); + free(line); + fclose(fp); +} + +static FILE *bzcat() +{ + char cmd[FILENAME_MAX]; + snprintf(cmd, sizeof(cmd), "bzcat %s", TT.f); + return popen(cmd, "r"); +} + +static char *find(char *path, int suf) +{ + glob_t g; + int i; + size_t len = strlen(*toys.optargs); + char *name; + glob(path, 0, 0, &g); + for (i = 0; !TT.f && i < g.gl_pathc; i++) { + name = basename(g.gl_pathv[i]); + if (strlen(name) == len + suf && !strncmp(name, *toys.optargs, len)) + TT.f = strdup(g.gl_pathv[i]); + } + globfree(&g); + return TT.f; +} + +void man_main(void) +{ + chdir("/usr/share/man"); + if (find("man?/*.?.bz2", 6)) do_man(bzcat()); // curl_strequal + else if (find("man?/*.bz2", 4)) do_man(bzcat()); // curl_strequal.3 + else if (find("man?/*.?", 2)) do_man(fopen(TT.f, "r")); // curl_strnequal + else if (find("man?/*", 0)) do_man(fopen(TT.f, "r")); // curl_strnequal.3 + if (TT.f) free(TT.f); +} -- cgit v1.2.3