diff options
author | Ron Yorston <rmy@pobox.com> | 2016-11-02 10:19:18 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2016-11-02 10:19:18 +0000 |
commit | e45ff573dc9707b1ea71f490ef16cd9d08feaaf2 (patch) | |
tree | 09980b02b9c8efc8d772c7379abdcd4eef4ddad8 /miscutils | |
parent | 7bc3efa4f0c7608723d301bda5ee006a0f6141fe (diff) | |
parent | 2e6af549715f5d7b4c2ab204e46c8b8f6f057045 (diff) | |
download | busybox-w32-e45ff573dc9707b1ea71f490ef16cd9d08feaaf2.tar.gz busybox-w32-e45ff573dc9707b1ea71f490ef16cd9d08feaaf2.tar.bz2 busybox-w32-e45ff573dc9707b1ea71f490ef16cd9d08feaaf2.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'miscutils')
-rw-r--r-- | miscutils/man.c | 105 |
1 files changed, 80 insertions, 25 deletions
diff --git a/miscutils/man.c b/miscutils/man.c index 6d32890d1..a8c2d4047 100644 --- a/miscutils/man.c +++ b/miscutils/man.c | |||
@@ -9,8 +9,11 @@ | |||
9 | //usage: "Format and display manual page\n" | 9 | //usage: "Format and display manual page\n" |
10 | //usage: "\n -a Display all pages" | 10 | //usage: "\n -a Display all pages" |
11 | //usage: "\n -w Show page locations" | 11 | //usage: "\n -w Show page locations" |
12 | //usage: "\n" | ||
13 | //usage: "\n$COLUMNS overrides output width" | ||
12 | 14 | ||
13 | #include "libbb.h" | 15 | #include "libbb.h" |
16 | #include "common_bufsiz.h" | ||
14 | 17 | ||
15 | enum { | 18 | enum { |
16 | OPT_a = 1, /* all */ | 19 | OPT_a = 1, /* all */ |
@@ -18,7 +21,6 @@ enum { | |||
18 | }; | 21 | }; |
19 | 22 | ||
20 | /* This is what I see on my desktop system being executed: | 23 | /* This is what I see on my desktop system being executed: |
21 | |||
22 | ( | 24 | ( |
23 | echo ".ll 12.4i" | 25 | echo ".ll 12.4i" |
24 | echo ".nr LL 12.4i" | 26 | echo ".nr LL 12.4i" |
@@ -28,11 +30,41 @@ echo ".\\\"" | |||
28 | echo ".pl \n(nlu+10" | 30 | echo ".pl \n(nlu+10" |
29 | ) | gtbl | nroff -Tlatin1 -mandoc | less | 31 | ) | gtbl | nroff -Tlatin1 -mandoc | less |
30 | 32 | ||
31 | */ | 33 | Some systems use -Tascii. |
34 | |||
35 | On another system I see this: | ||
36 | |||
37 | ... | tbl | nroff -mandoc -rLL=<NNN>n -rLT=<NNN>n -Tutf8 | less | ||
32 | 38 | ||
33 | static int show_manpage(const char *pager, char *man_filename, int man, int level); | 39 | where <NNN> is screen width minus 5. |
40 | Replacing "DEFINE nroff nroff -mandoc" in /etc/man_db.conf | ||
41 | changes "nroff -mandoc" part; -rLL=<NNN>n, -rLT=<NNN>n and -Tutf8 parts are | ||
42 | appended to the user-specified command. | ||
34 | 43 | ||
35 | static int run_pipe(const char *pager, char *man_filename, int man, int level) | 44 | Redirecting to a pipe or file sets GROFF_NO_SGR=1 to prevent color escapes, |
45 | and uses "col -b -p -x" instead of pager, this filters out backspace | ||
46 | and underscore tricks. | ||
47 | */ | ||
48 | |||
49 | struct globals { | ||
50 | const char *col; | ||
51 | const char *tbl; | ||
52 | const char *nroff; | ||
53 | const char *pager; | ||
54 | } FIX_ALIASING; | ||
55 | #define G (*(struct globals*)bb_common_bufsiz1) | ||
56 | #define INIT_G() do { \ | ||
57 | setup_common_bufsiz(); \ | ||
58 | G.col = "col"; \ | ||
59 | G.tbl = "tbl"; \ | ||
60 | /* Removed -Tlatin1. Assuming system nroff has suitable default */ \ | ||
61 | G.nroff = "nroff -mandoc"; \ | ||
62 | G.pager = ENABLE_LESS ? "less" : "more"; \ | ||
63 | } while (0) | ||
64 | |||
65 | static int show_manpage(char *man_filename, int man, int level); | ||
66 | |||
67 | static int run_pipe(char *man_filename, int man, int level) | ||
36 | { | 68 | { |
37 | char *cmd; | 69 | char *cmd; |
38 | 70 | ||
@@ -95,7 +127,7 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) | |||
95 | man_filename = xasprintf("%s/%s", man_filename, linkname); | 127 | man_filename = xasprintf("%s/%s", man_filename, linkname); |
96 | free(line); | 128 | free(line); |
97 | /* Note: we leak "new" man_filename string as well... */ | 129 | /* Note: we leak "new" man_filename string as well... */ |
98 | if (show_manpage(pager, man_filename, man, level + 1)) | 130 | if (show_manpage(man_filename, man, level + 1)) |
99 | return 1; | 131 | return 1; |
100 | /* else: show the link, it's better than nothing */ | 132 | /* else: show the link, it's better than nothing */ |
101 | } | 133 | } |
@@ -103,20 +135,26 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) | |||
103 | ordinary_manpage: | 135 | ordinary_manpage: |
104 | close(STDIN_FILENO); | 136 | close(STDIN_FILENO); |
105 | open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ | 137 | 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. | 138 | if (man) { |
107 | * Otherwise it may show just empty screen */ | 139 | int w = get_terminal_width(-1); |
108 | cmd = xasprintf( | 140 | if (w > 10) |
109 | /* replaced -Tlatin1 with -Tascii for non-UTF8 displays */ | 141 | w -= 2; |
110 | man ? "gtbl | nroff -Tascii -mandoc 2>&1 | %s" | 142 | /* "2>&1" is added so that nroff errors are shown in pager too. |
111 | : "%s", | 143 | * Otherwise it may show just empty screen. |
112 | pager); | 144 | */ |
145 | cmd = xasprintf("%s | %s -rLL=%un -rLT=%un 2>&1 | %s", | ||
146 | G.tbl, G.nroff, w, w, | ||
147 | G.pager); | ||
148 | } else { | ||
149 | cmd = xstrdup(G.pager); | ||
150 | } | ||
113 | system(cmd); | 151 | system(cmd); |
114 | free(cmd); | 152 | free(cmd); |
115 | return 1; | 153 | return 1; |
116 | } | 154 | } |
117 | 155 | ||
118 | /* man_filename is of the form "/dir/dir/dir/name.s" */ | 156 | /* 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) | 157 | static int show_manpage(char *man_filename, int man, int level) |
120 | { | 158 | { |
121 | #if SEAMLESS_COMPRESSION | 159 | #if SEAMLESS_COMPRESSION |
122 | /* We leak this allocation... */ | 160 | /* We leak this allocation... */ |
@@ -125,26 +163,26 @@ static int show_manpage(const char *pager, char *man_filename, int man, int leve | |||
125 | #endif | 163 | #endif |
126 | 164 | ||
127 | #if ENABLE_FEATURE_SEAMLESS_LZMA | 165 | #if ENABLE_FEATURE_SEAMLESS_LZMA |
128 | if (run_pipe(pager, filename_with_zext, man, level)) | 166 | if (run_pipe(filename_with_zext, man, level)) |
129 | return 1; | 167 | return 1; |
130 | #endif | 168 | #endif |
131 | #if ENABLE_FEATURE_SEAMLESS_XZ | 169 | #if ENABLE_FEATURE_SEAMLESS_XZ |
132 | strcpy(ext, "xz"); | 170 | strcpy(ext, "xz"); |
133 | if (run_pipe(pager, filename_with_zext, man, level)) | 171 | if (run_pipe(filename_with_zext, man, level)) |
134 | return 1; | 172 | return 1; |
135 | #endif | 173 | #endif |
136 | #if ENABLE_FEATURE_SEAMLESS_BZ2 | 174 | #if ENABLE_FEATURE_SEAMLESS_BZ2 |
137 | strcpy(ext, "bz2"); | 175 | strcpy(ext, "bz2"); |
138 | if (run_pipe(pager, filename_with_zext, man, level)) | 176 | if (run_pipe(filename_with_zext, man, level)) |
139 | return 1; | 177 | return 1; |
140 | #endif | 178 | #endif |
141 | #if ENABLE_FEATURE_SEAMLESS_GZ | 179 | #if ENABLE_FEATURE_SEAMLESS_GZ |
142 | strcpy(ext, "gz"); | 180 | strcpy(ext, "gz"); |
143 | if (run_pipe(pager, filename_with_zext, man, level)) | 181 | if (run_pipe(filename_with_zext, man, level)) |
144 | return 1; | 182 | return 1; |
145 | #endif | 183 | #endif |
146 | 184 | ||
147 | return run_pipe(pager, man_filename, man, level); | 185 | return run_pipe(man_filename, man, level); |
148 | } | 186 | } |
149 | 187 | ||
150 | static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) | 188 | static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) |
@@ -186,11 +224,20 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) | |||
186 | return man_path_list; | 224 | return man_path_list; |
187 | } | 225 | } |
188 | 226 | ||
227 | static const char *if_redefined(const char *var, const char *key, const char *line) | ||
228 | { | ||
229 | if (!is_prefixed_with(line, key)) | ||
230 | return var; | ||
231 | line += strlen(key); | ||
232 | if (!isspace(line[0])) | ||
233 | return var; | ||
234 | return xstrdup(skip_whitespace(line)); | ||
235 | } | ||
236 | |||
189 | int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 237 | int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
190 | int man_main(int argc UNUSED_PARAM, char **argv) | 238 | int man_main(int argc UNUSED_PARAM, char **argv) |
191 | { | 239 | { |
192 | parser_t *parser; | 240 | parser_t *parser; |
193 | const char *pager = ENABLE_LESS ? "less" : "more"; | ||
194 | char *sec_list; | 241 | char *sec_list; |
195 | char *cur_path, *cur_sect; | 242 | char *cur_path, *cur_sect; |
196 | char **man_path_list; | 243 | char **man_path_list; |
@@ -199,6 +246,8 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
199 | int opt, not_found; | 246 | int opt, not_found; |
200 | char *token[2]; | 247 | char *token[2]; |
201 | 248 | ||
249 | INIT_G(); | ||
250 | |||
202 | opt_complementary = "-1"; /* at least one argument */ | 251 | opt_complementary = "-1"; /* at least one argument */ |
203 | opt = getopt32(argv, "+aw"); | 252 | opt = getopt32(argv, "+aw"); |
204 | argv += optind; | 253 | argv += optind; |
@@ -232,9 +281,10 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
232 | if (!token[1]) | 281 | if (!token[1]) |
233 | continue; | 282 | continue; |
234 | if (strcmp("DEFINE", token[0]) == 0) { | 283 | if (strcmp("DEFINE", token[0]) == 0) { |
235 | if (is_prefixed_with(token[1], "pager")) { | 284 | G.col = if_redefined(G.tbl , "col", token[1]); |
236 | pager = xstrdup(skip_whitespace(token[1] + 5)); | 285 | G.tbl = if_redefined(G.tbl , "tbl", token[1]); |
237 | } | 286 | G.nroff = if_redefined(G.nroff, "nroff", token[1]); |
287 | G.pager = if_redefined(G.pager, "pager", token[1]); | ||
238 | } else | 288 | } else |
239 | if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ | 289 | if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ |
240 | || strcmp("MANDATORY_MANPATH", token[0]) == 0 | 290 | || strcmp("MANDATORY_MANPATH", token[0]) == 0 |
@@ -254,7 +304,12 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
254 | if (!env_pager) | 304 | if (!env_pager) |
255 | env_pager = getenv("PAGER"); | 305 | env_pager = getenv("PAGER"); |
256 | if (env_pager) | 306 | if (env_pager) |
257 | pager = env_pager; | 307 | G.pager = env_pager; |
308 | } | ||
309 | |||
310 | if (!isatty(STDOUT_FILENO)) { | ||
311 | putenv((char*)"GROFF_NO_SGR=1"); | ||
312 | G.pager = xasprintf("%s -b -p -x", G.col); | ||
258 | } | 313 | } |
259 | 314 | ||
260 | not_found = 0; | 315 | not_found = 0; |
@@ -263,7 +318,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
263 | cur_mp = 0; | 318 | cur_mp = 0; |
264 | 319 | ||
265 | if (strchr(*argv, '/')) { | 320 | if (strchr(*argv, '/')) { |
266 | found = show_manpage(pager, *argv, /*man:*/ 1, 0); | 321 | found = show_manpage(*argv, /*man:*/ 1, 0); |
267 | goto check_found; | 322 | goto check_found; |
268 | } | 323 | } |
269 | while ((cur_path = man_path_list[cur_mp++]) != NULL) { | 324 | while ((cur_path = man_path_list[cur_mp++]) != NULL) { |
@@ -284,7 +339,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
284 | sect_len, cur_sect, | 339 | sect_len, cur_sect, |
285 | *argv, | 340 | *argv, |
286 | sect_len, cur_sect); | 341 | sect_len, cur_sect); |
287 | found_here = show_manpage(pager, man_filename, cat0man1, 0); | 342 | found_here = show_manpage(man_filename, cat0man1, 0); |
288 | found |= found_here; | 343 | found |= found_here; |
289 | cat0man1 += found_here + 1; | 344 | cat0man1 += found_here + 1; |
290 | free(man_filename); | 345 | free(man_filename); |