X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=miscutils%2Fman.c;h=ba6bb4c01f6df7a2570a37fbab53594cd3e63921;hb=4c9455f967e21d30db0de2e13b6e1115ab8f36ce;hp=51baceb165a25b5a2e79a35e68efdfdc6f4aeae5;hpb=ff6506131152ee383685047c19bc420ed4de030e;p=oweals%2Fbusybox.git diff --git a/miscutils/man.c b/miscutils/man.c index 51baceb16..ba6bb4c01 100644 --- a/miscutils/man.c +++ b/miscutils/man.c @@ -2,6 +2,15 @@ * Copyright (C) 2008 Denys Vlasenko * Licensed under GPLv2, see file LICENSE in this source tree. */ +//config:config MAN +//config: bool "man (27 kb)" +//config: default y +//config: help +//config: Format and display manual pages. + +//applet:IF_MAN(APPLET(man, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_MAN) += man.o //usage:#define man_trivial_usage //usage: "[-aw] [MANPAGE]..." @@ -9,8 +18,11 @@ //usage: "Format and display manual page\n" //usage: "\n -a Display all pages" //usage: "\n -w Show page locations" +//usage: "\n" +//usage: "\n$COLUMNS overrides output width" #include "libbb.h" +#include "common_bufsiz.h" enum { OPT_a = 1, /* all */ @@ -18,7 +30,6 @@ enum { }; /* This is what I see on my desktop system being executed: - ( echo ".ll 12.4i" echo ".nr LL 12.4i" @@ -28,11 +39,41 @@ echo ".\\\"" echo ".pl \n(nlu+10" ) | gtbl | nroff -Tlatin1 -mandoc | less -*/ +Some systems use -Tascii. + +On another system I see this: -static int show_manpage(const char *pager, char *man_filename, int man, int level); +... | tbl | nroff -mandoc -rLL=n -rLT=n -Tutf8 | less -static int run_pipe(const char *pager, char *man_filename, int man, int level) +where is screen width minus 5. +Replacing "DEFINE nroff nroff -mandoc" in /etc/man_db.conf +changes "nroff -mandoc" part; -rLL=n, -rLT=n and -Tutf8 parts are +appended to the user-specified command. + +Redirecting to a pipe or file sets GROFF_NO_SGR=1 to prevent color escapes, +and uses "col -b -p -x" instead of pager, this filters out backspace +and underscore tricks. +*/ + +struct globals { + const char *col; + const char *tbl; + const char *nroff; + const char *pager; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + G.col = "col"; \ + G.tbl = "tbl"; \ + /* Removed -Tlatin1. Assuming system nroff has suitable default */ \ + G.nroff = "nroff -mandoc"; \ + G.pager = ENABLE_LESS ? "less" : "more"; \ +} while (0) + +static int show_manpage(char *man_filename, int man, int level); + +static int run_pipe(char *man_filename, int man, int level) { char *cmd; @@ -66,7 +107,7 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) goto ordinary_manpage; line = xmalloc_open_zipped_read_close(man_filename, NULL); - if (!line || strncmp(line, ".so ", 4) != 0) { + if (!line || !is_prefixed_with(line, ".so ")) { free(line); goto ordinary_manpage; } @@ -95,27 +136,34 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) man_filename = xasprintf("%s/%s", man_filename, linkname); free(line); /* Note: we leak "new" man_filename string as well... */ - if (show_manpage(pager, man_filename, man, level + 1)) + if (show_manpage(man_filename, man, level + 1)) return 1; /* else: show the link, it's better than nothing */ } ordinary_manpage: close(STDIN_FILENO); - open_zipped(man_filename); /* guaranteed to use fd 0 (STDIN_FILENO) */ - /* "2>&1" is added so that nroff errors are shown in pager too. - * Otherwise it may show just empty screen */ - cmd = xasprintf( - man ? "gtbl | nroff -Tlatin1 -mandoc 2>&1 | %s" - : "%s", - pager); + open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ + if (man) { + int w = get_terminal_width(-1); + if (w > 10) + w -= 2; + /* "2>&1" is added so that nroff errors are shown in pager too. + * Otherwise it may show just empty screen. + */ + cmd = xasprintf("%s | %s -rLL=%un -rLT=%un 2>&1 | %s", + G.tbl, G.nroff, w, w, + G.pager); + } else { + cmd = xstrdup(G.pager); + } system(cmd); free(cmd); return 1; } /* man_filename is of the form "/dir/dir/dir/name.s" */ -static int show_manpage(const char *pager, char *man_filename, int man, int level) +static int show_manpage(char *man_filename, int man, int level) { #if SEAMLESS_COMPRESSION /* We leak this allocation... */ @@ -124,53 +172,105 @@ static int show_manpage(const char *pager, char *man_filename, int man, int leve #endif #if ENABLE_FEATURE_SEAMLESS_LZMA - if (run_pipe(pager, filename_with_zext, man, level)) + if (run_pipe(filename_with_zext, man, level)) return 1; #endif #if ENABLE_FEATURE_SEAMLESS_XZ strcpy(ext, "xz"); - if (run_pipe(pager, filename_with_zext, man, level)) + if (run_pipe(filename_with_zext, man, level)) return 1; #endif #if ENABLE_FEATURE_SEAMLESS_BZ2 strcpy(ext, "bz2"); - if (run_pipe(pager, filename_with_zext, man, level)) + if (run_pipe(filename_with_zext, man, level)) return 1; #endif #if ENABLE_FEATURE_SEAMLESS_GZ strcpy(ext, "gz"); - if (run_pipe(pager, filename_with_zext, man, level)) + if (run_pipe(filename_with_zext, man, level)) return 1; #endif - return run_pipe(pager, man_filename, man, level); + return run_pipe(man_filename, man, level); +} + +static char **add_MANPATH(char **man_path_list, int *count_mp, char *path) +{ + if (path) while (*path) { + char *next_path; + char **path_element; + + next_path = strchr(path, ':'); + if (next_path) { + if (next_path == path) /* "::"? */ + goto next; + *next_path = '\0'; + } + /* Do we already have path? */ + path_element = man_path_list; + if (path_element) while (*path_element) { + if (strcmp(*path_element, path) == 0) + goto skip; + path_element++; + } + man_path_list = xrealloc_vector(man_path_list, 4, *count_mp); + man_path_list[*count_mp] = xstrdup(path); + (*count_mp)++; + /* man_path_list is NULL terminated */ + /* man_path_list[*count_mp] = NULL; - xrealloc_vector did it */ + skip: + if (!next_path) + break; + /* "path" may be a result of getenv(), be nice and don't mangle it */ + *next_path = ':'; + next: + path = next_path + 1; + } + return man_path_list; +} + +static const char *if_redefined(const char *var, const char *key, const char *line) +{ + if (!is_prefixed_with(line, key)) + return var; + line += strlen(key); + if (!isspace(line[0])) + return var; + return xstrdup(skip_whitespace(line)); } int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int man_main(int argc UNUSED_PARAM, char **argv) { parser_t *parser; - const char *pager = ENABLE_LESS ? "less" : "more"; - char **man_path_list; char *sec_list; char *cur_path, *cur_sect; - int count_mp, cur_mp; + char **man_path_list; + int count_mp; + int cur_mp; int opt, not_found; char *token[2]; - opt_complementary = "-1"; /* at least one argument */ - opt = getopt32(argv, "+aw"); + INIT_G(); + + opt = getopt32(argv, "^+" "aw" "\0" "-1"/*at least one arg*/); argv += optind; sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); - /* Last valid man_path_list[] is [0x10] */ + count_mp = 0; - man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); - man_path_list[0] = getenv("MANPATH"); - if (!man_path_list[0]) /* default, may be overridden by /etc/man.conf */ + man_path_list = add_MANPATH(NULL, &count_mp, + getenv("MANDATORY_MANPATH"+10) /* "MANPATH" */ + ); + if (!man_path_list) { + /* default, may be overridden by /etc/man.conf */ + man_path_list = xzalloc(2 * sizeof(man_path_list[0])); man_path_list[0] = (char*)"/usr/man"; - else - count_mp++; + /* count_mp stays 0. + * Thus, man.conf will overwrite man_path_list[0] + * if a path is defined there. + */ + } /* Parse man.conf[ig] or man_db.conf */ /* man version 1.6f uses man.config */ @@ -185,42 +285,15 @@ int man_main(int argc UNUSED_PARAM, char **argv) if (!token[1]) continue; if (strcmp("DEFINE", token[0]) == 0) { - if (strncmp("pager", token[1], 5) == 0) { - pager = xstrdup(skip_whitespace(token[1]) + 5); - } + G.col = if_redefined(G.tbl , "col", token[1]); + G.tbl = if_redefined(G.tbl , "tbl", token[1]); + G.nroff = if_redefined(G.nroff, "nroff", token[1]); + G.pager = if_redefined(G.pager, "pager", token[1]); } else if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ || strcmp("MANDATORY_MANPATH", token[0]) == 0 ) { - char *path = token[1]; - while (*path) { - char *next_path; - char **path_element; - - next_path = strchr(path, ':'); - if (next_path) { - *next_path = '\0'; - if (next_path++ == path) /* "::"? */ - goto next; - } - /* Do we already have path? */ - path_element = man_path_list; - while (*path_element) { - if (strcmp(*path_element, path) == 0) - goto skip; - path_element++; - } - man_path_list = xrealloc_vector(man_path_list, 4, count_mp); - man_path_list[count_mp] = xstrdup(path); - count_mp++; - /* man_path_list is NULL terminated */ - /*man_path_list[count_mp] = NULL; - xrealloc_vector did it */ - skip: - if (!next_path) - break; - next: - path = next_path; - } + man_path_list = add_MANPATH(man_path_list, &count_mp, token[1]); } if (strcmp("MANSECT", token[0]) == 0) { free(sec_list); @@ -235,7 +308,12 @@ int man_main(int argc UNUSED_PARAM, char **argv) if (!env_pager) env_pager = getenv("PAGER"); if (env_pager) - pager = env_pager; + G.pager = env_pager; + } + + if (!isatty(STDOUT_FILENO)) { + putenv((char*)"GROFF_NO_SGR=1"); + G.pager = xasprintf("%s -b -p -x", G.col); } not_found = 0; @@ -244,7 +322,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) cur_mp = 0; if (strchr(*argv, '/')) { - found = show_manpage(pager, *argv, /*man:*/ 1, 0); + found = show_manpage(*argv, /*man:*/ 1, 0); goto check_found; } while ((cur_path = man_path_list[cur_mp++]) != NULL) { @@ -265,7 +343,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) sect_len, cur_sect, *argv, sect_len, cur_sect); - found_here = show_manpage(pager, man_filename, cat0man1, 0); + found_here = show_manpage(man_filename, cat0man1, 0); found |= found_here; cat0man1 += found_here + 1; free(man_filename);