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 | |
| 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')
| -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); |
