diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-30 22:31:30 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-30 22:31:30 +0100 |
commit | a92a74961d838209f3468d10426bc945ba26070c (patch) | |
tree | b3284e65f5bdef8c373eecab3dd910f0268dd318 | |
parent | d4f3db9427c443b2709fc9a00bc46d8a71be806b (diff) | |
download | busybox-w32-a92a74961d838209f3468d10426bc945ba26070c.tar.gz busybox-w32-a92a74961d838209f3468d10426bc945ba26070c.tar.bz2 busybox-w32-a92a74961d838209f3468d10426bc945ba26070c.zip |
man: allow nroff and tbl commands be overridden; unmangle writing to files
Parse this in config files:
DEFINE col ...
DEFINE tbl ...
DEFINE nroff ...
Add width options to nroff command line.
Use "tbl", not "gtbl", as default tbl command.
Export GROFF_NO_SGR=1 and use "col -b -p -x" instead of pager when writing to file.
function old new delta
man_main 735 863 +128
if_redefined - 64 +64
show_manpage 199 169 -30
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 192/-30) Total: 162 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/man.c | 104 |
1 files changed, 79 insertions, 25 deletions
diff --git a/miscutils/man.c b/miscutils/man.c index f705dd31e..01382c4d7 100644 --- a/miscutils/man.c +++ b/miscutils/man.c | |||
@@ -11,6 +11,7 @@ | |||
11 | //usage: "\n -w Show page locations" | 11 | //usage: "\n -w Show page locations" |
12 | 12 | ||
13 | #include "libbb.h" | 13 | #include "libbb.h" |
14 | #include "common_bufsiz.h" | ||
14 | 15 | ||
15 | enum { | 16 | enum { |
16 | OPT_a = 1, /* all */ | 17 | OPT_a = 1, /* all */ |
@@ -18,7 +19,6 @@ enum { | |||
18 | }; | 19 | }; |
19 | 20 | ||
20 | /* This is what I see on my desktop system being executed: | 21 | /* This is what I see on my desktop system being executed: |
21 | |||
22 | ( | 22 | ( |
23 | echo ".ll 12.4i" | 23 | echo ".ll 12.4i" |
24 | echo ".nr LL 12.4i" | 24 | echo ".nr LL 12.4i" |
@@ -28,11 +28,39 @@ echo ".\\\"" | |||
28 | echo ".pl \n(nlu+10" | 28 | echo ".pl \n(nlu+10" |
29 | ) | gtbl | nroff -Tlatin1 -mandoc | less | 29 | ) | gtbl | nroff -Tlatin1 -mandoc | less |
30 | 30 | ||
31 | */ | 31 | On another system I see this: |
32 | 32 | ||
33 | static int show_manpage(const char *pager, char *man_filename, int man, int level); | 33 | ... | tbl | nroff -mandoc -rLL=<NNN>n -rLT=<NNN>n -Tutf8 | less |
34 | 34 | ||
35 | static int run_pipe(const char *pager, char *man_filename, int man, int level) | 35 | where <NNN> is screen width minus 5. |
36 | Replacing "DEFINE nroff nroff -mandoc" in /etc/man_db.conf | ||
37 | changes "nroff -mandoc" part; -rLL=<NNN>n, -rLT=<NNN>n and -Tutf8 parts are | ||
38 | appended to the user-specified command. | ||
39 | |||
40 | Redirecting to a pipe or file sets GROFF_NO_SGR=1 to prevent color escapes, | ||
41 | and uses "col -b -p -x" instead of pager, this filters out backspace | ||
42 | and underscore tricks. | ||
43 | */ | ||
44 | |||
45 | struct globals { | ||
46 | const char *col; | ||
47 | const char *tbl; | ||
48 | const char *nroff; | ||
49 | const char *pager; | ||
50 | } FIX_ALIASING; | ||
51 | #define G (*(struct globals*)bb_common_bufsiz1) | ||
52 | #define INIT_G() do { \ | ||
53 | setup_common_bufsiz(); \ | ||
54 | G.col = "col"; \ | ||
55 | G.tbl = "tbl"; \ | ||
56 | /* replaced -Tlatin1 with -Tascii for non-UTF8 displays */; \ | ||
57 | G.nroff = "nroff -mandoc -Tascii"; \ | ||
58 | G.pager = ENABLE_LESS ? "less" : "more"; \ | ||
59 | } while (0) | ||
60 | |||
61 | static int show_manpage(char *man_filename, int man, int level); | ||
62 | |||
63 | static int run_pipe(char *man_filename, int man, int level) | ||
36 | { | 64 | { |
37 | char *cmd; | 65 | char *cmd; |
38 | 66 | ||
@@ -95,7 +123,7 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) | |||
95 | man_filename = xasprintf("%s/%s", man_filename, linkname); | 123 | man_filename = xasprintf("%s/%s", man_filename, linkname); |
96 | free(line); | 124 | free(line); |
97 | /* Note: we leak "new" man_filename string as well... */ | 125 | /* Note: we leak "new" man_filename string as well... */ |
98 | if (show_manpage(pager, man_filename, man, level + 1)) | 126 | if (show_manpage(man_filename, man, level + 1)) |
99 | return 1; | 127 | return 1; |
100 | /* else: show the link, it's better than nothing */ | 128 | /* else: show the link, it's better than nothing */ |
101 | } | 129 | } |
@@ -103,20 +131,29 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) | |||
103 | ordinary_manpage: | 131 | ordinary_manpage: |
104 | close(STDIN_FILENO); | 132 | close(STDIN_FILENO); |
105 | open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ | 133 | open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ |
106 | /* "2>&1" is added so that nroff errors are shown in pager too. | 134 | if (man) { |
107 | * Otherwise it may show just empty screen */ | 135 | /* "man man" formats to screen width. |
108 | cmd = xasprintf( | 136 | * "man man >file" formats to default 80 columns. |
109 | /* replaced -Tlatin1 with -Tascii for non-UTF8 displays */ | 137 | * "man man | cat" formats to default 80 columns. |
110 | man ? "gtbl | nroff -Tascii -mandoc 2>&1 | %s" | 138 | */ |
111 | : "%s", | 139 | int w = get_terminal_width(STDOUT_FILENO); |
112 | pager); | 140 | if (w > 10) |
141 | w -= 2; | ||
142 | /* "2>&1" is added so that nroff errors are shown in pager too. | ||
143 | * Otherwise it may show just empty screen */ | ||
144 | cmd = xasprintf("%s | %s -rLL=%un -rLT=%un 2>&1 | %s", | ||
145 | G.tbl, G.nroff, w, w, | ||
146 | G.pager); | ||
147 | } else { | ||
148 | cmd = xstrdup(G.pager); | ||
149 | } | ||
113 | system(cmd); | 150 | system(cmd); |
114 | free(cmd); | 151 | free(cmd); |
115 | return 1; | 152 | return 1; |
116 | } | 153 | } |
117 | 154 | ||
118 | /* man_filename is of the form "/dir/dir/dir/name.s" */ | 155 | /* man_filename is of the form "/dir/dir/dir/name.s" */ |
119 | static int show_manpage(const char *pager, char *man_filename, int man, int level) | 156 | static int show_manpage(char *man_filename, int man, int level) |
120 | { | 157 | { |
121 | #if SEAMLESS_COMPRESSION | 158 | #if SEAMLESS_COMPRESSION |
122 | /* We leak this allocation... */ | 159 | /* We leak this allocation... */ |
@@ -125,26 +162,26 @@ static int show_manpage(const char *pager, char *man_filename, int man, int leve | |||
125 | #endif | 162 | #endif |
126 | 163 | ||
127 | #if ENABLE_FEATURE_SEAMLESS_LZMA | 164 | #if ENABLE_FEATURE_SEAMLESS_LZMA |
128 | if (run_pipe(pager, filename_with_zext, man, level)) | 165 | if (run_pipe(filename_with_zext, man, level)) |
129 | return 1; | 166 | return 1; |
130 | #endif | 167 | #endif |
131 | #if ENABLE_FEATURE_SEAMLESS_XZ | 168 | #if ENABLE_FEATURE_SEAMLESS_XZ |
132 | strcpy(ext, "xz"); | 169 | strcpy(ext, "xz"); |
133 | if (run_pipe(pager, filename_with_zext, man, level)) | 170 | if (run_pipe(filename_with_zext, man, level)) |
134 | return 1; | 171 | return 1; |
135 | #endif | 172 | #endif |
136 | #if ENABLE_FEATURE_SEAMLESS_BZ2 | 173 | #if ENABLE_FEATURE_SEAMLESS_BZ2 |
137 | strcpy(ext, "bz2"); | 174 | strcpy(ext, "bz2"); |
138 | if (run_pipe(pager, filename_with_zext, man, level)) | 175 | if (run_pipe(filename_with_zext, man, level)) |
139 | return 1; | 176 | return 1; |
140 | #endif | 177 | #endif |
141 | #if ENABLE_FEATURE_SEAMLESS_GZ | 178 | #if ENABLE_FEATURE_SEAMLESS_GZ |
142 | strcpy(ext, "gz"); | 179 | strcpy(ext, "gz"); |
143 | if (run_pipe(pager, filename_with_zext, man, level)) | 180 | if (run_pipe(filename_with_zext, man, level)) |
144 | return 1; | 181 | return 1; |
145 | #endif | 182 | #endif |
146 | 183 | ||
147 | return run_pipe(pager, man_filename, man, level); | 184 | return run_pipe(man_filename, man, level); |
148 | } | 185 | } |
149 | 186 | ||
150 | static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) | 187 | static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) |
@@ -182,11 +219,20 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) | |||
182 | return man_path_list; | 219 | return man_path_list; |
183 | } | 220 | } |
184 | 221 | ||
222 | static const char *if_redefined(const char *var, const char *key, const char *line) | ||
223 | { | ||
224 | if (!is_prefixed_with(line, key)) | ||
225 | return var; | ||
226 | line += strlen(key); | ||
227 | if (!isspace(line[0])) | ||
228 | return var; | ||
229 | return xstrdup(skip_whitespace(line)); | ||
230 | } | ||
231 | |||
185 | int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 232 | int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
186 | int man_main(int argc UNUSED_PARAM, char **argv) | 233 | int man_main(int argc UNUSED_PARAM, char **argv) |
187 | { | 234 | { |
188 | parser_t *parser; | 235 | parser_t *parser; |
189 | const char *pager = ENABLE_LESS ? "less" : "more"; | ||
190 | char *sec_list; | 236 | char *sec_list; |
191 | char *cur_path, *cur_sect; | 237 | char *cur_path, *cur_sect; |
192 | char **man_path_list; | 238 | char **man_path_list; |
@@ -195,6 +241,8 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
195 | int opt, not_found; | 241 | int opt, not_found; |
196 | char *token[2]; | 242 | char *token[2]; |
197 | 243 | ||
244 | INIT_G(); | ||
245 | |||
198 | opt_complementary = "-1"; /* at least one argument */ | 246 | opt_complementary = "-1"; /* at least one argument */ |
199 | opt = getopt32(argv, "+aw"); | 247 | opt = getopt32(argv, "+aw"); |
200 | argv += optind; | 248 | argv += optind; |
@@ -228,9 +276,10 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
228 | if (!token[1]) | 276 | if (!token[1]) |
229 | continue; | 277 | continue; |
230 | if (strcmp("DEFINE", token[0]) == 0) { | 278 | if (strcmp("DEFINE", token[0]) == 0) { |
231 | if (is_prefixed_with(token[1], "pager")) { | 279 | G.col = if_redefined(G.tbl , "col", token[1]); |
232 | pager = xstrdup(skip_whitespace(token[1] + 5)); | 280 | G.tbl = if_redefined(G.tbl , "tbl", token[1]); |
233 | } | 281 | G.nroff = if_redefined(G.nroff, "nroff", token[1]); |
282 | G.pager = if_redefined(G.pager, "pager", token[1]); | ||
234 | } else | 283 | } else |
235 | if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ | 284 | if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ |
236 | || strcmp("MANDATORY_MANPATH", token[0]) == 0 | 285 | || strcmp("MANDATORY_MANPATH", token[0]) == 0 |
@@ -250,7 +299,12 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
250 | if (!env_pager) | 299 | if (!env_pager) |
251 | env_pager = getenv("PAGER"); | 300 | env_pager = getenv("PAGER"); |
252 | if (env_pager) | 301 | if (env_pager) |
253 | pager = env_pager; | 302 | G.pager = env_pager; |
303 | } | ||
304 | |||
305 | if (!isatty(STDOUT_FILENO)) { | ||
306 | putenv((char*)"GROFF_NO_SGR=1"); | ||
307 | G.pager = xasprintf("%s -b -p -x", G.col); | ||
254 | } | 308 | } |
255 | 309 | ||
256 | not_found = 0; | 310 | not_found = 0; |
@@ -259,7 +313,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
259 | cur_mp = 0; | 313 | cur_mp = 0; |
260 | 314 | ||
261 | if (strchr(*argv, '/')) { | 315 | if (strchr(*argv, '/')) { |
262 | found = show_manpage(pager, *argv, /*man:*/ 1, 0); | 316 | found = show_manpage(*argv, /*man:*/ 1, 0); |
263 | goto check_found; | 317 | goto check_found; |
264 | } | 318 | } |
265 | while ((cur_path = man_path_list[cur_mp++]) != NULL) { | 319 | while ((cur_path = man_path_list[cur_mp++]) != NULL) { |
@@ -280,7 +334,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
280 | sect_len, cur_sect, | 334 | sect_len, cur_sect, |
281 | *argv, | 335 | *argv, |
282 | sect_len, cur_sect); | 336 | sect_len, cur_sect); |
283 | found_here = show_manpage(pager, man_filename, cat0man1, 0); | 337 | found_here = show_manpage(man_filename, cat0man1, 0); |
284 | found |= found_here; | 338 | found |= found_here; |
285 | cat0man1 += found_here + 1; | 339 | cat0man1 += found_here + 1; |
286 | free(man_filename); | 340 | free(man_filename); |