diff options
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); |
