/* scan for the page, print any matches */ static void do_apropos (MYDBM_FILE dbf, const char * const *pages, int num_pages, int *found) { datum key, cont; char **lowpages; int *found_here; int (*combine) (int, int *); 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]); } found_here = XNMALLOC (num_pages, int); combine = require_all ? all_set : any_set; #ifndef BTREE key = MYDBM_FIRSTKEY (dbf); while (MYDBM_DPTR (key)) { cont = MYDBM_FETCH (dbf, key); #else /* BTREE */ end = btree_nextkeydata (dbf, &key, &cont); while (!end) { #endif /* !BTREE */ char *tab; struct mandata info; memset (&info, 0, sizeof (info)); /* bug#4372, NULL pointer dereference in MYDBM_DPTR (cont), * fix by [email protected] (J.H.M.Dassen), thanx Ray. * cjwatson: In that case, complain and exit, otherwise we * might loop (bug #95052). */ if (!MYDBM_DPTR (cont)) { debug ("key was %s\n", MYDBM_DPTR (key)); error (FATAL, 0, _("Database %s corrupted; rebuild with " "mandb --create"), database); } if (*MYDBM_DPTR (key) == '$') goto nextpage; if (*MYDBM_DPTR (cont) == '\t') goto nextpage; /* a real page */ split_content (MYDBM_DPTR (cont), &info); /* If there are sections given, does any of them match * either the section or extension of this page? */ if (sections) { char * const *section; int matched = 0; for (section = sections; *section; ++section) { if (STREQ (*section, info.sec) || STREQ (*section, info.ext)) { matched = 1; break; } } if (!matched) goto nextpage; } tab = strrchr (MYDBM_DPTR (key), '\t'); if (tab) *tab = '\0'; memset (found_here, 0, num_pages * sizeof (*found_here)); if (am_apropos) { char *whatis; parse_name ((const char **) lowpages, num_pages, MYDBM_DPTR (key), found, found_here); whatis = info.whatis ? xstrdup (info.whatis) : NULL; if (!combine (num_pages, found_here) && whatis) parse_whatis (pages, lowpages, num_pages, whatis, found, found_here); free (whatis); } else parse_name (pages, num_pages, MYDBM_DPTR (key), found, found_here); if (combine (num_pages, found_here)) display (dbf, &info, MYDBM_DPTR (key)); if (tab) *tab = '\t'; nextpage: #ifndef BTREE nextkey = MYDBM_NEXTKEY (dbf, key); MYDBM_FREE_DPTR (cont); MYDBM_FREE_DPTR (key); key = nextkey; #else /* BTREE */ MYDBM_FREE_DPTR (cont); MYDBM_FREE_DPTR (key); end = btree_nextkeydata (dbf, &key, &cont); #endif /* !BTREE */ info.addr = NULL; /* == MYDBM_DPTR (cont), freed above */ free_mandata_elements (&info); } for (i = 0; i < num_pages; ++i) free (lowpages[i]); free (lowpages); } /* loop through the man paths, searching for a match */ static int search (const char * const *pages, int num_pages) { int *found = XCALLOC (num_pages, int); char *catpath, **mp; int any_found, i; for (mp = manpathlist; *mp; mp++) { MYDBM_FILE dbf; catpath = get_catpath (*mp, SYSTEM_CAT | USER_CAT); if (catpath) { database = mkdbname (catpath); free (catpath); } else database = mkdbname (*mp); debug ("path=%s\n", *mp); dbf = MYDBM_RDOPEN (database); if (dbf && dbver_rd (dbf)) { MYDBM_CLOSE (dbf); dbf = NULL; } if (!dbf) { use_grep (pages, num_pages, *mp, found); continue; } if (am_apropos) do_apropos (dbf, pages, num_pages, found); else { if (regex_opt || wildcard) do_apropos (dbf, pages, num_pages, found); else do_whatis (dbf, pages, num_pages, *mp, found); } free (database); database = NULL; MYDBM_CLOSE (dbf); } chkr_garbage_detector (); 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]); } free (found); return any_found; }
int main (int argc, char **argv) { int status = 0; char *nextarg; char *tmp; char *section = 0; #ifdef __CYGWIN__ extern int optind; #endif #if 0 { /* There are no known cases of buffer overflow caused by excessively long environment variables. In case you find one, the simplistic way to fix is to enable this stopgap. */ char *s; #define CHECK(p,l) s=getenv(p); if(s && strlen(s)>(l)) { fprintf(stderr, "ERROR: Environment variable %s too long!\n", p); exit(1); } CHECK("LANG", 32); CHECK("LANGUAGE", 128); CHECK("LC_MESSAGES", 128); CHECK("MANPAGER", 128); CHECK("MANPL", 128); CHECK("MANROFFSEQ", 128); CHECK("MANSECT", 128); CHECK("MAN_HP_DIREXT", 128); CHECK("PAGER", 128); CHECK("SYSTEM", 64); CHECK("BROWSER", 64); CHECK("HTMLPAGER", 64); /* COLUMNS, LC_ALL, LC_CTYPE, MANPATH, MANWIDTH, MAN_IRIX_CATNAMES, MAN_ICONV_PATH, MAN_ICONV_OPT, MAN_ICONV_INPUT_CHARSET, MAN_ICONV_OUTPUT_CHARSET, NLSPATH, PATH */ } #endif #ifndef __FreeBSD__ /* Slaven Rezif: FreeBSD-2.2-SNAP does not recognize LC_MESSAGES. */ setlocale(LC_CTYPE, ""); /* used anywhere? maybe only isdigit()? */ setlocale(LC_MESSAGES, ""); #endif /* No doubt we'll need some generic language code here later. For the moment only Japanese support. */ setlang(); /* Handle /usr/man/man1.Z/name.1 nonsense from HP */ dohp = getenv("MAN_HP_DIREXT"); /* .Z */ /* Handle ls.z (instead of ls.1.z) cat page naming from IRIX */ if (getenv("MAN_IRIX_CATNAMES")) do_irix = 1; /* Handle lack of ':' in NTFS file names */ #if defined(_WIN32) || defined(__CYGWIN__) do_win32 = 1; #endif progname = mkprogname (argv[0]); get_permissions (); get_line_length(); /* * read command line options and man.conf */ man_getopt (argc, argv); /* * manpath or man --path or man -w will only print the manpath */ if (!strcmp (progname, "manpath") || (optind == argc && print_where)) { init_manpath(); prmanpath(); exit(0); } if (optind == argc) gripe(NO_NAME_NO_SECTION); section_list = get_section_list (); while (optind < argc) { nextarg = argv[optind++]; /* is_section correctly accepts 3Xt as section, but also 9wm, so we should not believe is_section() for the last arg. */ tmp = is_section (nextarg); if (tmp && optind < argc) { section = tmp; if (debug) gripe (SECTION, section); continue; } if (global_apropos) status = !do_global_apropos (nextarg, section); else if (apropos) status = !do_apropos (nextarg); else if (whatis) status = !do_whatis (nextarg); else { status = man (nextarg, section); if (status == 0) { if (section) gripe (NO_SUCH_ENTRY_IN_SECTION, nextarg, section); else gripe (NO_SUCH_ENTRY, nextarg); } } } return status ? EXIT_SUCCESS : EXIT_FAILURE; }