NetBSD/usr.bin/apropos/apropos.c
chuck d09fe2c467 modified man(1):
- avoid double slashes when displaying man pages (got tired
   of '/usr/share/man//cat1/man.0').
 - got rid of __P() while working on it.
 - incorporate some of my old notes explaining how manpath works into the
   comments of the code itself.
 - renamed some of the vars so that the code is consistent throughout
   (and hopefully clearer and easier to understand)
 - fixed relative man paths for multiple man pages (man did a chdir()
   on the first man page it had to format --- this broke any remaining
   relative path man pages left to process).   save old directory and
   fchdir() back to it after formatting.
 - improved doc on "man -h" which does more than just whatis(1) [e.g.
   "man -h fopen" prints the required include files and the prototypes
   rather than just the one-liner you get with whatis(1)]
 - manconf.c now fills in the "len" length field in the TAG/ENTRY
   structures (man now uses len).

revise man.conf file reading stuff to return error on failure in
addentry/gettag (fka getlist) rather than just err()ing out.   this
allows man(1) to call cleanup and delete its tmp files rather than
just leave them floating.  revise other apps using this code
(makewhatis, apropos, catman, whatis) to expect this.  also remove
__P on updated files.
2006-04-10 14:39:06 +00:00

239 lines
5.4 KiB
C

/* $NetBSD: apropos.c,v 1.27 2006/04/10 14:39:06 chuck Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: apropos.c,v 1.27 2006/04/10 14:39:06 chuck Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <glob.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "manconf.h" /* from ../man/ */
#include "pathnames.h" /* from ../man/ */
static int *found, foundman;
#define MAXLINELEN 8192 /* max line handled */
void apropos(char **, char *, int);
void lowstr(char *, char *);
int match(char *, char *);
void usage(void);
int
main(int argc, char *argv[])
{
ENTRY *ep;
TAG *tp;
int ch, rv;
char *conffile, **p, *p_augment, *p_path;
glob_t pg;
conffile = NULL;
p_augment = p_path = NULL;
while ((ch = getopt(argc, argv, "C:M:m:P:")) != -1)
switch (ch) {
case 'C':
conffile = optarg;
break;
case 'M':
case 'P': /* backward compatible */
p_path = optarg;
break;
case 'm':
p_augment = optarg;
break;
case '?':
default:
usage();
}
argv += optind;
argc -= optind;
if (argc < 1)
usage();
if ((found = malloc((u_int)argc * sizeof(int))) == NULL)
err(1, "malloc");
memset(found, 0, argc * sizeof(int));
for (p = argv; *p; ++p) /* convert to lower-case */
lowstr(*p, *p);
if (p_augment)
apropos(argv, p_augment, 1);
if (p_path || (p_path = getenv("MANPATH")))
apropos(argv, p_path, 1);
else {
config(conffile);
tp = gettag("_whatdb", 1);
if (!tp)
errx(EXIT_FAILURE, "malloc");
TAILQ_FOREACH(ep, &tp->entrylist, q) {
if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL,
&pg)) != 0) {
if (rv == GLOB_NOMATCH)
continue;
else
err(EXIT_FAILURE, "glob");
}
if (pg.gl_pathc)
for (p = pg.gl_pathv; *p; p++)
apropos(argv, *p, 0);
globfree(&pg);
}
}
if (!foundman)
errx(1, "no %s file found", _PATH_WHATIS);
rv = 1;
for (p = argv; *p; ++p)
if (found[p - argv])
rv = 0;
else
(void)printf("%s: nothing appropriate\n", *p);
exit(rv);
}
void
apropos(char **argv, char *path, int buildpath)
{
char *end, *name, **p;
char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1];
char hold[MAXPATHLEN + 1];
for (name = path; name; name = end) { /* through name list */
if ((end = strchr(name, ':')))
*end++ = '\0';
if (buildpath) {
(void)snprintf(hold, sizeof(hold), "%s/%s", name,
_PATH_WHATIS);
name = hold;
}
if (!freopen(name, "r", stdin))
continue;
foundman = 1;
/* for each file found */
while (fgets(buf, sizeof(buf), stdin)) {
if (!strchr(buf, '\n')) {
warnx("%s: line too long", name);
continue;
}
lowstr(buf, wbuf);
for (p = argv; *p; ++p)
if (match(wbuf, *p)) {
(void)printf("%s", buf);
found[p - argv] = 1;
/* only print line once */
while (*++p)
if (match(wbuf, *p))
found[p - argv] = 1;
break;
}
}
}
}
/*
* match --
* match anywhere the string appears
*/
int
match(char *bp, char *str)
{
int len;
char test;
if (!*bp)
return (0);
/* backward compatible: everything matches empty string */
if (!*str)
return (1);
for (test = *str++, len = strlen(str); *bp;)
if (test == *bp++ && !strncmp(bp, str, len))
return (1);
return (0);
}
/*
* lowstr --
* convert a string to lower case
*/
void
lowstr(char *from, char *to)
{
char ch;
while ((ch = *from++) && ch != '\n')
*to++ = tolower((unsigned char)ch);
*to = '\0';
}
/*
* usage --
* print usage message and die
*/
void
usage(void)
{
(void)fprintf(stderr,
"usage: %s [-C file] [-M path] [-m path] keyword ...\n",
getprogname());
exit(1);
}