diff options
author | Colin Watson <cjwatson@debian.org> | 2012-02-22 03:06:44 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2012-02-22 03:06:44 +0000 |
commit | 2e102cf5a64a00dc259947a6974cdc2de80c9443 (patch) | |
tree | e0a32d33580481f6eec307f7ece57a665a818968 /src/whatis.c | |
parent | 8aa6c5aa791a4783799d9e546e3f18b40079a687 (diff) |
Optimise apropos when given many arguments (Ubuntu bug #927028).
* src/whatis.c (use_grep, do_whatis, parse_name, parse_whatis,
do_apropos, search): Operate on multiple pages.
(use_grep, do_whatis, do_apropos): Update an output array rather
than returning an int.
(parse_name, parse_whatis): Update an output array as well as
returning an int.
(display, do_whatis_section): Constify page argument.
(match): Constify lowpage and whatis arguments.
(main): Process all arguments using a single call to search.
* NEWS: Document this.
Diffstat (limited to 'src/whatis.c')
-rw-r--r-- | src/whatis.c | 251 |
1 files changed, 163 insertions, 88 deletions
diff --git a/src/whatis.c b/src/whatis.c index 73162d58..98371417 100644 --- a/src/whatis.c +++ b/src/whatis.c @@ -2,8 +2,8 @@ * whatis.c: search the index or whatis database(s) for words. * * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) - * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 - * Colin Watson. + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, + * 2012 Colin Watson. * * This file is part of man-db. * @@ -91,7 +91,7 @@ int quiet = 1; iconv_t conv_to_locale; #endif /* HAVE_ICONV */ -static regex_t preg; +static regex_t *preg; static int regex_opt; static int exact; @@ -272,17 +272,20 @@ static char *simple_convert (iconv_t conv, char *string) # define simple_convert(conv, string) xstrdup (string) #endif /* HAVE_ICONV */ -/* do the old thing, if we cannot find the relevant database */ -static inline int use_grep (char *page, char *manpath) +/* Do the old thing, if we cannot find the relevant database. + * This invokes grep once per argument; we can't do much about this because + * we need to know which arguments failed. The only way to speed this up + * would be to implement grep internally, but it hardly seems worth it for a + * legacy mechanism. + */ +static void use_grep (const char * const *pages, int num_pages, char *manpath, + int *found) { char *whatis_file = appendstr (NULL, manpath, "/whatis", NULL); - int status; if (access (whatis_file, R_OK) == 0) { - pipeline *grep_pl = pipeline_new (); - pipecmd *grep_cmd; const char *flags; - char *anchored_page = NULL; + int i; if (am_apropos) { if (regex_opt) @@ -292,29 +295,38 @@ static inline int use_grep (char *page, char *manpath) else flags = get_def_user ("apropos_grep_flags", APROPOS_GREP_FLAGS); - anchored_page = xstrdup (page); - } else { + } else flags = get_def_user ("whatis_grep_flags", WHATIS_GREP_FLAGS); - anchored_page = appendstr (NULL, "^", page, NULL); - } - grep_cmd = pipecmd_new_argstr (get_def_user ("grep", GREP)); - pipecmd_argstr (grep_cmd, flags); - pipecmd_args (grep_cmd, anchored_page, whatis_file, NULL); - pipeline_command (grep_pl, grep_cmd); + for (i = 0; i < num_pages; ++i) { + pipeline *grep_pl; + pipecmd *grep_cmd; + char *anchored_page; - status = (pipeline_run (grep_pl) == 0); + if (am_apropos) + anchored_page = xstrdup (pages[i]); + else + anchored_page = appendstr (NULL, "^", pages[i], + NULL); - free (anchored_page); - } else { + grep_cmd = pipecmd_new_argstr (get_def_user ("grep", + GREP)); + pipecmd_argstr (grep_cmd, flags); + pipecmd_args (grep_cmd, anchored_page, whatis_file, + NULL); + grep_pl = pipeline_new_commands (grep_cmd, NULL); + + if (pipeline_run (grep_pl) == 0) + found[i] = 1; + + free (anchored_page); + } + } else debug ("warning: can't read the fallback whatis text database " "%s/whatis\n", manpath); - status = 0; - } free (whatis_file); - return status; } static struct mandata *resolve_pointers (struct mandata *info, @@ -375,7 +387,7 @@ static char *get_whatis (struct mandata *info, const char *page) } /* print out any matches found */ -static void display (struct mandata *info, char *page) +static void display (struct mandata *info, const char *page) { struct mandata *newinfo; char *string, *whatis, *string_conv; @@ -441,7 +453,7 @@ out: } /* lookup the page and display the results */ -static inline int do_whatis_section (char *page, const char *section) +static inline int do_whatis_section (const char *page, const char *section) { struct mandata *info; int count = 0; @@ -460,39 +472,61 @@ static inline int do_whatis_section (char *page, const char *section) return count; } -static inline int do_whatis (char *page) +static void do_whatis (const char * const *pages, int num_pages, int *found) { - int count = 0; - - if (sections) { - char * const *section; + int i; - for (section = sections; *section; ++section) - count += do_whatis_section (page, *section); - } else - count += do_whatis_section (page, NULL); + for (i = 0; i < num_pages; ++i) { + if (sections) { + char * const *section; - return count; + for (section = sections; *section; ++section) { + if (do_whatis_section (pages[i], *section)) + found[i] = 1; + } + } else { + if (do_whatis_section (pages[i], NULL)) + found[i] = 1; + } + } } -/* return 1 if page matches name, else 0 */ -static int parse_name (char *page, char *dbname) +/* return 1 if any of pages matches name, else 0 */ +static int parse_name (const char * const *pages, int num_pages, + const char *dbname, int *found) { - if (regex_opt) - return (regexec (&preg, dbname, 0, (regmatch_t *) 0, 0) == 0); + int i; + int ret = 0; + + if (regex_opt) { + for (i = 0; i < num_pages; ++i) { + if (regexec (&preg[i], dbname, 0, + (regmatch_t *) 0, 0) == 0) + found[i] = ret = 1; + } + return ret; + } if (am_apropos && !wildcard) { char *lowdbname = lower (dbname); - int ret = STREQ (lowdbname, page); + + for (i = 0; i < num_pages; ++i) { + if (STREQ (lowdbname, pages[i])) + found[i] = ret = 1; + } free (lowdbname); return ret; } - return (fnmatch (page, dbname, 0) == 0); + for (i = 0; i < num_pages; ++i) { + if (fnmatch (pages[i], dbname, 0) == 0) + found[i] = ret = 1; + } + return ret; } /* return 1 on word match */ -static int match (char *lowpage, char *whatis) +static int match (const char *lowpage, const char *whatis) { char *lowwhatis = lower (whatis); size_t len = strlen (lowpage); @@ -517,20 +551,40 @@ static int match (char *lowpage, char *whatis) return 0; } -/* return 1 if page matches whatis, else 0 */ -static int parse_whatis (char *page, char *lowpage, char *whatis) +/* return 1 if any of pages matches whatis, else 0 */ +static int parse_whatis (const char * const *pages, char * const *lowpages, + int num_pages, const char *whatis, int *found) { - if (regex_opt) - return (regexec (&preg, whatis, 0, (regmatch_t *) 0, 0) == 0); + int i; + int ret = 0; + + if (regex_opt) { + for (i = 0; i < num_pages; ++i) { + if (regexec (&preg[i], whatis, 0, + (regmatch_t *) 0, 0) == 0) + found[i] = ret = 1; + } + return ret; + } if (wildcard) { - if (exact) - return (fnmatch (page, whatis, 0) == 0); - else - return word_fnmatch (page, whatis); + for (i = 0; i < num_pages; ++i) { + if (exact) { + if (fnmatch (pages[i], whatis, 0) == 0) + found[i] = ret = 1; + } else { + if (word_fnmatch (pages[i], whatis)) + found[i] = ret = 1; + } + } + return ret; } - return match (lowpage, whatis); + for (i = 0; i < num_pages; ++i) { + if (match (lowpages[i], whatis)) + found[i] = ret = 1; + } + return ret; } /* cjwatson: Optimized functions don't seem to be correct in some @@ -539,20 +593,28 @@ static int parse_whatis (char *page, char *lowpage, char *whatis) #undef BTREE /* scan for the page, print any matches */ -static int do_apropos (char *page, char *lowpage) +static void do_apropos (const char * const *pages, int num_pages, int *found) { datum key, cont; - int found = 0; - + char **lowpages; + int i; #ifndef BTREE datum nextkey; +#else /* BTREE */ + int end; +#endif /* !BTREE */ + lowpages = XNMALLOC (num_pages, char *); + for (i = 0; i < num_pages; ++i) { + lowpages[i] = lower (pages[i]); + debug ("lower(%s) = \"%s\"\n", pages[i], lowpages[i]); + } + +#ifndef BTREE key = MYDBM_FIRSTKEY (dbf); while (MYDBM_DPTR (key)) { cont = MYDBM_FETCH (dbf, key); #else /* BTREE */ - int end; - end = btree_nextkeydata (dbf, &key, &cont); while (!end) { #endif /* !BTREE */ @@ -624,11 +686,14 @@ static int do_apropos (char *page, char *lowpage) strlen (seen_key)); if (seen_count && !require_all) goto nextpage_tab; - got_match = parse_name (lowpage, MYDBM_DPTR (key)); + got_match = parse_name ((const char **) lowpages, + num_pages, MYDBM_DPTR (key), + found); whatis = info.whatis ? xstrdup (info.whatis) : NULL; if (!got_match && whatis) - got_match = parse_whatis (page, lowpage, - whatis); + got_match = parse_whatis (pages, lowpages, + num_pages, whatis, + found); free (whatis); if (got_match) { if (!seen_count) { @@ -646,15 +711,13 @@ static int do_apropos (char *page, char *lowpage) display (&info, MYDBM_DPTR (key)); } free (seen_key); - found++; } else { - got_match = parse_name (page, MYDBM_DPTR (key)); + got_match = parse_name (pages, num_pages, + MYDBM_DPTR (key), found); if (got_match) display (&info, MYDBM_DPTR (key)); } - found += got_match; - nextpage_tab: if (tab) *tab = '\t'; @@ -673,17 +736,17 @@ nextpage: free_mandata_elements (&info); } - return found; + for (i = 0; i < num_pages; ++i) + free (lowpages[i]); + free (lowpages); } /* loop through the man paths, searching for a match */ -static int search (char *page) +static int search (const char * const *pages, int num_pages) { - int found = 0; - char *lowpage = lower (page); + int *found = XCALLOC (num_pages, int); char *catpath, **mp; - - debug ("lower(%s) = \"%s\"\n", page, lowpage); + int any_found, i; for (mp = manpathlist; *mp; mp++) { catpath = get_catpath (*mp, SYSTEM_CAT | USER_CAT); @@ -702,17 +765,17 @@ static int search (char *page) dbf = NULL; } if (!dbf) { - found += use_grep (page, *mp); + use_grep (pages, num_pages, *mp, found); continue; } if (am_apropos) - found += do_apropos (page, lowpage); + do_apropos (pages, num_pages, found); else { - if (regex_opt || wildcard) { - found += do_apropos (page, lowpage); - } else - found += do_whatis (page); + if (regex_opt || wildcard) + do_apropos (pages, num_pages, found); + else + do_whatis (pages, num_pages, found); } free (database); database = NULL; @@ -721,12 +784,17 @@ static int search (char *page) chkr_garbage_detector (); - if (!found) - fprintf (stderr, _("%s: nothing appropriate.\n"), page); - - free (lowpage); + any_found = 0; + for (i = 0; i < num_pages; ++i) { + if (found[i]) + any_found = 1; + else + fprintf (stderr, _("%s: nothing appropriate.\n"), + pages[i]); + } - return found; + free (found); + return any_found; } int main (int argc, char *argv[]) @@ -735,7 +803,6 @@ int main (int argc, char *argv[]) #ifdef HAVE_ICONV char *locale_charset; #endif - int i; int status = OK; program_name = base_name (argv[0]); @@ -829,14 +896,22 @@ int main (int argc, char *argv[]) free (locale_charset); #endif /* HAVE_ICONV */ - for (i = 0; i < num_keywords; ++i) { - if (regex_opt) - xregcomp (&preg, keywords[i], + if (regex_opt) { + int i; + preg = XNMALLOC (num_keywords, regex_t); + for (i = 0; i < num_keywords; ++i) + xregcomp (&preg[i], keywords[i], REG_EXTENDED | REG_NOSUB | REG_ICASE); - if (!search (keywords[i])) - status = NOT_FOUND; - if (regex_opt) - regfree (&preg); + } + + if (!search ((const char **) keywords, num_keywords)) + status = NOT_FOUND; + + if (regex_opt) { + int i; + for (i = 0; i < num_keywords; ++i) + regfree (&preg[i]); + free (preg); } #ifdef HAVE_ICONV |