diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-08-05 13:16:18 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-08-05 13:16:18 +0000 |
commit | 540baf646a526a68aeb83a3c6da706a2f2a1aeb2 (patch) | |
tree | a00104b18b3d45e620df9d9d3ef215b0ed89c18d /miscutils/man.c | |
parent | e9ad84dfd4c7eb2936374f02989dacf7026a7276 (diff) | |
download | busybox-w32-540baf646a526a68aeb83a3c6da706a2f2a1aeb2.tar.gz busybox-w32-540baf646a526a68aeb83a3c6da706a2f2a1aeb2.tar.bz2 busybox-w32-540baf646a526a68aeb83a3c6da706a2f2a1aeb2.zip |
man: add handling of "man links", by Ivana Varekova <varekova AT redhat.com>
function old new delta
run_pipe 102 354 +252
show_manpage - 126 +126
man_main 705 615 -90
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 378/-90) Total: 288 bytes
Diffstat (limited to 'miscutils/man.c')
-rw-r--r-- | miscutils/man.c | 73 |
1 files changed, 62 insertions, 11 deletions
diff --git a/miscutils/man.c b/miscutils/man.c index f499fef62..91b995cf4 100644 --- a/miscutils/man.c +++ b/miscutils/man.c | |||
@@ -27,10 +27,19 @@ echo ".pl \n(nlu+10" | |||
27 | #define STR_catNULmanNUL "cat\0man" | 27 | #define STR_catNULmanNUL "cat\0man" |
28 | #define STR_cat "cat\0man" | 28 | #define STR_cat "cat\0man" |
29 | 29 | ||
30 | static int run_pipe(const char *unpacker, const char *pager, char *man_filename, int man) | 30 | //TODO: make gz/bz2 support conditional on FEATURE_SEAMLESS_GZ/BZ2, |
31 | // add SEAMLESS_LZMA support | ||
32 | |||
33 | static int show_manpage(const char *pager, char *man_filename, int man, int level); | ||
34 | |||
35 | static int run_pipe(const char *unpacker, const char *pager, char *man_filename, int man, int level) | ||
31 | { | 36 | { |
32 | char *cmd; | 37 | char *cmd; |
33 | 38 | ||
39 | /* Prevent man page link loops */ | ||
40 | if (level > 10) | ||
41 | return 0; | ||
42 | |||
34 | if (access(man_filename, R_OK) != 0) | 43 | if (access(man_filename, R_OK) != 0) |
35 | return 0; | 44 | return 0; |
36 | 45 | ||
@@ -39,6 +48,53 @@ static int run_pipe(const char *unpacker, const char *pager, char *man_filename, | |||
39 | return 1; | 48 | return 1; |
40 | } | 49 | } |
41 | 50 | ||
51 | if (man) { /* man page, not cat page */ | ||
52 | /* Test whether the man page is not a link to another one. */ | ||
53 | /* The link has the following on the first line: */ | ||
54 | /* ".so another_man_page" */ | ||
55 | struct stat sb; | ||
56 | char *line; | ||
57 | char *linkname, *p; | ||
58 | |||
59 | /* On my system: | ||
60 | * man1/genhostid.1.gz: 203 bytes - smallest real manpage | ||
61 | * man2/path_resolution.2.gz: 114 bytes - largest link | ||
62 | */ | ||
63 | xstat(man_filename, &sb); | ||
64 | if (sb.st_size > 300) /* err on the safe side */ | ||
65 | goto ordinary_manpage; | ||
66 | |||
67 | line = xmalloc_open_zipped_read_close(man_filename, NULL); | ||
68 | if (!line || strncmp(line, ".so ", 4) != 0) { | ||
69 | free(line); | ||
70 | goto ordinary_manpage; | ||
71 | } | ||
72 | /* Example: man2/path_resolution.2.gz contains | ||
73 | * ".so man7/path_resolution.7\n<junk>" | ||
74 | */ | ||
75 | *strchrnul(line, '\n') = '\0'; | ||
76 | linkname = p = skip_whitespace(&line[4]); | ||
77 | while (1) { | ||
78 | char *newname_slash, *oldname_slash; | ||
79 | |||
80 | oldname_slash = strrchr(man_filename, '/'); | ||
81 | if (!oldname_slash) | ||
82 | goto ordinary_manpage; | ||
83 | *oldname_slash = '\0'; | ||
84 | newname_slash = strchr(p, '/'); | ||
85 | if (!newname_slash) | ||
86 | break; | ||
87 | p = newname_slash + 1; | ||
88 | } | ||
89 | man_filename = xasprintf("%s/%s" ".bz2", man_filename, linkname); | ||
90 | free(line); | ||
91 | /* Note: we leak "new" man_filename string as well... */ | ||
92 | if (show_manpage(pager, man_filename, man, level + 1)) | ||
93 | return 1; | ||
94 | /* else: show the link, it's better than nothing */ | ||
95 | } | ||
96 | |||
97 | ordinary_manpage: | ||
42 | /* "2>&1" is added so that nroff errors are shown in pager too. | 98 | /* "2>&1" is added so that nroff errors are shown in pager too. |
43 | * Otherwise it may show just empty screen */ | 99 | * Otherwise it may show just empty screen */ |
44 | cmd = xasprintf( | 100 | cmd = xasprintf( |
@@ -51,22 +107,22 @@ static int run_pipe(const char *unpacker, const char *pager, char *man_filename, | |||
51 | } | 107 | } |
52 | 108 | ||
53 | /* man_filename is of the form "/dir/dir/dir/name.s.bz2" */ | 109 | /* man_filename is of the form "/dir/dir/dir/name.s.bz2" */ |
54 | static int show_manpage(const char *pager, char *man_filename, int man) | 110 | static int show_manpage(const char *pager, char *man_filename, int man, int level) |
55 | { | 111 | { |
56 | int len; | 112 | int len; |
57 | 113 | ||
58 | if (run_pipe("bunzip2 -c", pager, man_filename, man)) | 114 | if (run_pipe("bunzip2 -c", pager, man_filename, man, level)) |
59 | return 1; | 115 | return 1; |
60 | 116 | ||
61 | len = strlen(man_filename) - 1; | 117 | len = strlen(man_filename) - 1; |
62 | 118 | ||
63 | man_filename[len] = '\0'; /* ".bz2" -> ".gz" */ | 119 | man_filename[len] = '\0'; /* ".bz2" -> ".gz" */ |
64 | man_filename[len - 2] = 'g'; | 120 | man_filename[len - 2] = 'g'; |
65 | if (run_pipe("gunzip -c", pager, man_filename, man)) | 121 | if (run_pipe("gunzip -c", pager, man_filename, man, level)) |
66 | return 1; | 122 | return 1; |
67 | 123 | ||
68 | man_filename[len - 3] = '\0'; /* ".gz" -> "" */ | 124 | man_filename[len - 3] = '\0'; /* ".gz" -> "" */ |
69 | if (run_pipe(STR_cat, pager, man_filename, man)) | 125 | if (run_pipe(STR_cat, pager, man_filename, man, level)) |
70 | return 1; | 126 | return 1; |
71 | 127 | ||
72 | return 0; | 128 | return 0; |
@@ -121,11 +177,6 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
121 | } | 177 | } |
122 | config_close(parser); | 178 | config_close(parser); |
123 | 179 | ||
124 | // TODO: my man3/getpwuid.3.gz contains just one line: | ||
125 | // .so man3/getpwnam.3 | ||
126 | // (and I _dont_ have man3/getpwnam.3, I have man3/getpwnam.3.gz) | ||
127 | // need to support this... | ||
128 | |||
129 | not_found = 0; | 180 | not_found = 0; |
130 | do { /* for each argv[] */ | 181 | do { /* for each argv[] */ |
131 | int found = 0; | 182 | int found = 0; |
@@ -151,7 +202,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) | |||
151 | sect_len, cur_sect, | 202 | sect_len, cur_sect, |
152 | *argv, | 203 | *argv, |
153 | sect_len, cur_sect); | 204 | sect_len, cur_sect); |
154 | found_here = show_manpage(pager, man_filename, cat0man1); | 205 | found_here = show_manpage(pager, man_filename, cat0man1, 0); |
155 | found |= found_here; | 206 | found |= found_here; |
156 | cat0man1 += found_here + 1; | 207 | cat0man1 += found_here + 1; |
157 | free(man_filename); | 208 | free(man_filename); |