summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--NEWS4
-rw-r--r--src/tests/Makefile.am1
-rw-r--r--src/tests/Makefile.in1
-rwxr-xr-xsrc/tests/whatis-158
-rw-r--r--src/whatis.c118
6 files changed, 169 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index 8935f0b4..c25e1eb0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+Mon Feb 27 13:26:47 GMT 2012 Colin Watson <cjwatson@debian.org>
+
+ * src/whatis.c (main): Move locale manpath expansion to ...
+ (locale_manpath): ... here (new function).
+ (suitable_manpath): New function.
+ (do_whatis): If a page contains a slash and is a path to an
+ executable on $PATH, then look up its base name only in
+ appropriate manual hierarchies.
+ (search): Pass current manpath entry to do_whatis.
+ * src/tests/whatis-1: New file.
+ * src/tests/Makefile.am (ALL_TESTS): Add whatis-1.
+ * NEWS: Document this.
+
Wed Feb 22 03:04:45 GMT 2012 Colin Watson <cjwatson@debian.org>
Optimise apropos when given many arguments (Ubuntu bug #927028).
diff --git a/NEWS b/NEWS
index 245be5ce..fd78f3ce 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,10 @@ Major changes since man-db 2.6.1:
o apropos is much faster when run with many arguments.
+ o whatis may be given the full path to an executable as an argument,
+ in which case it will look up the base name of that executable in
+ the appropriate parts of the manpath.
+
man-db 2.6.1 (14 February 2012)
===============================
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index b7560426..6090f631 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -26,6 +26,7 @@ ALL_TESTS = \
man-1 man-2 man-3 \
manconv-1 manconv-2 manconv-3 \
mandb-1 mandb-2 mandb-3 mandb-4 mandb-5 mandb-6 \
+ whatis-1 \
zsoelim-1
if !CROSS_COMPILING
TESTS = $(ALL_TESTS)
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 76fae660..448e1195 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -1145,6 +1145,7 @@ ALL_TESTS = \
man-1 man-2 man-3 \
manconv-1 manconv-2 manconv-3 \
mandb-1 mandb-2 mandb-3 mandb-4 mandb-5 mandb-6 \
+ whatis-1 \
zsoelim-1
@CROSS_COMPILING_FALSE@TESTS = $(ALL_TESTS)
diff --git a/src/tests/whatis-1 b/src/tests/whatis-1
new file mode 100755
index 00000000..22fe468a
--- /dev/null
+++ b/src/tests/whatis-1
@@ -0,0 +1,58 @@
+#! /bin/sh
+
+# Test that whatis behaves appropriately when given a path to an executable.
+
+: ${srcdir=.}
+. "$srcdir/testlib.sh"
+
+: ${MANDB=mandb}
+: ${WHATIS=whatis}
+
+init
+fake_config /usr/share/man /usr/local/man
+cat >>"$tmpdir/manpath.config" <<EOF
+MANPATH_MAP $tmpdir/usr/bin $tmpdir/usr/share/man
+MANPATH_MAP $tmpdir/usr/local/bin $tmpdir/usr/local/man
+EOF
+
+write_page test 1 "$tmpdir/usr/share/man/man1/test.1.gz" \
+ UTF-8 gz '' 'test \- /usr/bin/test'
+write_page test 8 "$tmpdir/usr/local/man/man8/test.8.gz" \
+ UTF-8 gz '' 'test \- /usr/local/bin/test'
+mkdir -p "$tmpdir/usr/bin" "$tmpdir/usr/local/bin"
+touch "$tmpdir/usr/bin/test" "$tmpdir/usr/local/bin/test"
+chmod +x "$tmpdir/usr/bin/test" "$tmpdir/usr/local/bin/test"
+MANPATH="$tmpdir/usr/share/man:$tmpdir/usr/local/man" run $MANDB \
+ -C "$tmpdir/manpath.config" -u -q \
+ "$tmpdir/usr/share/man:$tmpdir/usr/local/man"
+
+cat >"$tmpdir/1.exp" <<EOF
+test (1) - /usr/bin/test
+test (8) - /usr/local/bin/test
+EOF
+PATH="$PATH:$tmpdir/usr/bin:$tmpdir/usr/local/bin" \
+ MANPATH="$tmpdir/usr/share/man:$tmpdir/usr/local/man" run $WHATIS \
+ -C "$tmpdir/manpath.config" test >"$tmpdir/1.out"
+expect_pass 'simple name returns all matches' \
+ 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"'
+
+cat >"$tmpdir/2.exp" <<EOF
+test (1) - /usr/bin/test
+EOF
+PATH="$PATH:$tmpdir/usr/bin:$tmpdir/usr/local/bin" \
+ MANPATH="$tmpdir/usr/share/man:$tmpdir/usr/local/man" run $WHATIS \
+ -C "$tmpdir/manpath.config" "$tmpdir/usr/bin/test" >"$tmpdir/2.out"
+expect_pass '/usr/bin/test only returns appropriate match' \
+ 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"'
+
+cat >"$tmpdir/3.exp" <<EOF
+test (8) - /usr/local/bin/test
+EOF
+PATH="$PATH:$tmpdir/usr/bin:$tmpdir/usr/local/bin" \
+ MANPATH="$tmpdir/usr/share/man:$tmpdir/usr/local/man" run $WHATIS \
+ -C "$tmpdir/manpath.config" "$tmpdir/usr/local/bin/test" \
+ >"$tmpdir/3.out"
+expect_pass '/usr/local/bin/test only returns appropriate match' \
+ 'diff -u "$tmpdir/3.exp" "$tmpdir/3.out"'
+
+finish
diff --git a/src/whatis.c b/src/whatis.c
index 98371417..4c281e6d 100644
--- a/src/whatis.c
+++ b/src/whatis.c
@@ -51,6 +51,7 @@
#endif /* HAVE_ICONV */
#include <sys/types.h>
+#include <sys/stat.h>
#include "regex.h"
#include "argp.h"
@@ -63,6 +64,7 @@
#include "cleanup.h"
#include "error.h"
#include "pipeline.h"
+#include "pathsearch.h"
#include "linelength.h"
#include "hashtable.h"
#include "lower.h"
@@ -106,6 +108,7 @@ static char **sections;
static char *manp = NULL;
static const char *alt_systems = "";
static const char *locale = NULL;
+static char *multiple_locale = NULL, *internal_locale;
static struct hashtable *apropos_seen = NULL;
static struct hashtable *display_seen = NULL;
@@ -239,6 +242,30 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
static struct argp apropos_argp = { options, parse_opt, args_doc, apropos_doc };
static struct argp whatis_argp = { options, parse_opt, args_doc };
+static char *locale_manpath (char *manpath)
+{
+ char *all_locales;
+ char *new_manpath;
+
+ if (multiple_locale && *multiple_locale) {
+ if (internal_locale && *internal_locale)
+ all_locales = xasprintf ("%s:%s", multiple_locale,
+ internal_locale);
+ else
+ all_locales = xstrdup (multiple_locale);
+ } else {
+ if (internal_locale && *internal_locale)
+ all_locales = xstrdup (internal_locale);
+ else
+ all_locales = NULL;
+ }
+
+ new_manpath = add_nls_manpaths (manpath, all_locales);
+ free (all_locales);
+
+ return new_manpath;
+}
+
#ifdef HAVE_ICONV
static char *simple_convert (iconv_t conv, char *string)
{
@@ -472,22 +499,80 @@ static inline int do_whatis_section (const char *page, const char *section)
return count;
}
-static void do_whatis (const char * const *pages, int num_pages, int *found)
+static int suitable_manpath (const char *manpath, const char *page_dir)
+{
+ char *page_manp;
+ char *page_manpathlist[MAXDIRS], **mp;
+ int ret;
+
+ page_manp = get_manpath_from_path (page_dir, 0);
+ if (!page_manp || !*page_manp) {
+ free (page_manp);
+ return 0;
+ }
+ page_manp = locale_manpath (page_manp);
+ create_pathlist (page_manp, page_manpathlist);
+
+ ret = 0;
+ for (mp = page_manpathlist; *mp; ++mp) {
+ if (STREQ (*mp, manpath)) {
+ ret = 1;
+ break;
+ }
+ }
+
+ for (mp = page_manpathlist; *mp; ++mp)
+ free (*mp);
+ free (page_manp);
+ return ret;
+}
+
+static void do_whatis (const char * const *pages, int num_pages,
+ const char *manpath, int *found)
{
int i;
for (i = 0; i < num_pages; ++i) {
+ char *page = xstrdup (pages[i]);
+ struct stat st;
+
+ if (strchr (page, '/') && stat (page, &st) == 0 &&
+ !S_ISDIR (st.st_mode) &&
+ st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+ /* Perhaps an executable. If its directory is on
+ * $PATH, then we only want to process this page for
+ * matching manual hierarchies.
+ */
+ char *page_dir = dir_name (page);
+
+ if (directory_on_path (page_dir)) {
+ if (suitable_manpath (manpath, page_dir)) {
+ char *old_page = page;
+ page = base_name (old_page);
+ free (old_page);
+ } else {
+ debug ("%s not on manpath for %s\n",
+ manpath, page);
+ free (page_dir);
+ continue;
+ }
+ }
+ free (page_dir);
+ }
+
if (sections) {
char * const *section;
for (section = sections; *section; ++section) {
- if (do_whatis_section (pages[i], *section))
+ if (do_whatis_section (page, *section))
found[i] = 1;
}
} else {
- if (do_whatis_section (pages[i], NULL))
+ if (do_whatis_section (page, NULL))
found[i] = 1;
}
+
+ free (page);
}
}
@@ -775,7 +860,7 @@ static int search (const char * const *pages, int num_pages)
if (regex_opt || wildcard)
do_apropos (pages, num_pages, found);
else
- do_whatis (pages, num_pages, found);
+ do_whatis (pages, num_pages, *mp, found);
}
free (database);
database = NULL;
@@ -799,7 +884,6 @@ static int search (const char * const *pages, int num_pages)
int main (int argc, char *argv[])
{
- char *multiple_locale = NULL, *internal_locale;
#ifdef HAVE_ICONV
char *locale_charset;
#endif
@@ -861,27 +945,9 @@ int main (int argc, char *argv[])
}
/* sort out the internal manpath */
- if (manp == NULL) {
- char *all_locales;
-
- if (multiple_locale && *multiple_locale) {
- if (internal_locale && *internal_locale)
- all_locales = xasprintf ("%s:%s",
- multiple_locale,
- internal_locale);
- else
- all_locales = xstrdup (multiple_locale);
- } else {
- if (internal_locale && *internal_locale)
- all_locales = xstrdup (internal_locale);
- else
- all_locales = NULL;
- }
-
- manp = add_nls_manpaths (get_manpath (alt_systems),
- all_locales);
- free (all_locales);
- } else
+ if (manp == NULL)
+ manp = locale_manpath (get_manpath (alt_systems));
+ else
free (get_manpath (NULL));
create_pathlist (manp, manpathlist);