aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2012-06-08 10:44:52 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2012-06-08 10:44:52 +0000
commit5f164a6735403143d675639fe5dee257a943e09c (patch)
tree39a8d39df25f3b2b4b37e4acaf031640d632cbfc
parente65910f2c18c908bff6c793aeaa30f94bc89a8bc (diff)
downloadmandoc-5f164a6735403143d675639fe5dee257a943e09c.tar.gz
mandoc-5f164a6735403143d675639fe5dee257a943e09c.tar.zst
mandoc-5f164a6735403143d675639fe5dee257a943e09c.zip
Flip apropos to use mansearch instead of apropos_db.
This makes the utility much smaller and simpler. A lot of functionality has been omitted while the sqlite3 search routines improve (logical operations, etc.). It still needs work to make the output more conventional. Also add the manpage utility, which I use extensively as a mind-meld of apropos and man.
-rw-r--r--apropos.1120
-rw-r--r--apropos.c199
-rw-r--r--manpage.c178
3 files changed, 236 insertions, 261 deletions
diff --git a/apropos.1 b/apropos.1
index 7dea132a..4706d36a 100644
--- a/apropos.1
+++ b/apropos.1
@@ -1,4 +1,4 @@
-.\" $Id: apropos.1,v 1.17 2012/03/24 01:46:25 kristaps Exp $
+.\" $Id: apropos.1,v 1.18 2012/06/08 10:44:52 kristaps Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: March 24 2012 $
+.Dd $Mdocdate: June 8 2012 $
.Dt APROPOS 1
.Os
.Sh NAME
@@ -42,13 +42,11 @@ By default,
searches for
.Xr mandocdb 8
databases in the default paths stipulated by
-.Xr man 1 ,
-parses terms as case-sensitive regular expressions
+.Xr man 1
+and
+parses terms as case-sensitive words
over manual names and descriptions.
-Multiple terms imply pairwise
-.Fl o .
-If standard output is a TTY, a result may be selected from a list and
-its manual displayed with the pager.
+Multiple terms are OR'd.
.Pp
Its arguments are as follows:
.Bl -tag -width Ds
@@ -81,41 +79,8 @@ for a listing of manual sections.
.Pp
An
.Ar expression
-consists of search terms joined by logical operators
-.Fl a
-.Pq and
-and
-.Fl o
-.Pq or .
-The
-.Fl a
-operator has precedence over
-.Fl o
-and both are evaluated left-to-right.
-.Bl -tag -width Ds
-.It \&( Ar expr No \&)
-True if the subexpression
-.Ar expr
-is true.
-.It Ar expr1 Fl a Ar expr2
-True if both
-.Ar expr1
-and
-.Ar expr2
-are true (logical
-.Qq and ) .
-.It Ar expr1 Oo Fl o Oc Ar expr2
-True if
-.Ar expr1
-and/or
-.Ar expr2
-evaluate to true (logical
-.Qq or ) .
-.It Ar term
-True if
-.Ar term
-is satisfied.
-This has syntax
+consists of type and keyword pairs.
+This pair syntax
.Li [key[,key]*(=~)]?val ,
where operand
.Cm key
@@ -129,22 +94,15 @@ See
for a list of available keys.
Operator
.Li \&=
-evaluates a substring, while
+evaluates a full string, while
.Li \&~
-evaluates a regular expression.
-.It Fl i Ar term
-If
-.Ar term
-is a regular expression, it
-is evaluated case-insensitively.
-Has no effect on substring terms.
-.El
+evaluates a
+.Xr glob 7
+pattern.
.Pp
Results are sorted by manual title, with output formatted as
-.Pp
-.D1 title(sec) \- description
-.Pp
-Where
+.Qq title(sec) \- description
+where
.Qq title
is the manual's title (note multiple manual names may exist for one
title),
@@ -153,24 +111,7 @@ is the manual section, and
.Qq description
is the manual's short description.
If an architecture is specified for the manual, it is displayed as
-.Pp
-.D1 title(cat/arch) \- description
-.Pp
-If on a TTY, results are prefixed with a numeric identifier.
-.Pp
-.D1 [index] title(cat) \- description
-.Pp
-One may choose a manual be entering the index at the prompt.
-Valid choices are displayed using
-.Ev MANPAGER ,
-or failing that ,
-.Ev PAGER
-or just
-.Xr more 1 .
-Source pages are formatted with
-.Xr mandoc 1 ;
-preformatted pages with
-.Xr cat 1 .
+.Qq title(cat/arch) \- description .
.Ss Macro Keys
Queries evaluate over a subset of
.Xr mdoc 7
@@ -248,14 +189,6 @@ Text production:
.El
.Sh ENVIRONMENT
.Bl -tag -width Ds
-.It Ev MANPAGER
-Default pager for manuals.
-If this is unset, falls back to
-.Ev Pager .
-.It Ev PAGER
-The second choice for a manual pager.
-If this is unset, use
-.Xr more 1 .
.It Ev MANPATH
Colon-separated paths modifying the default list of paths searched for
manual databases.
@@ -294,31 +227,30 @@ configuration file
.Sh EXAMPLES
Search for
.Qq mdoc
-as a substring and regular expression
-within each manual name and description:
+as a word or
+.Xr glob 7
+expression:
.Pp
.Dl $ apropos mdoc
-.Dl $ apropos ~^mdoc$
+.Dl $ apropos any~mdoc*
.Pp
Include matches for
.Qq roff
and
.Qq man
-for the regular expression case:
+using
+.Xr glob 7
+expressions:
.Pp
-.Dl $ apropos ~^mdoc$ roff man
-.Dl $ apropos ~^mdoc$ \-o roff \-o man
+.Dl $ apropos ~*mdoc* ~*roff*
.Pp
Search for
-.Qq optind
-and
.Qq optarg
-as variable names in the library category:
+as a variable name in the library category:
.Pp
-.Dl $ apropos \-s 3 Va~^optind \-a Va~^optarg$
+.Dl $ apropos \-s 3 Va=optarg
.Sh SEE ALSO
-.Xr more 1
-.Xr re_format 7 ,
+.Xr glob 7 ,
.Xr mandocdb 8
.Sh AUTHORS
The
diff --git a/apropos.c b/apropos.c
index 9c3cae96..469bff5e 100644
--- a/apropos.c
+++ b/apropos.c
@@ -1,7 +1,6 @@
-/* $Id: apropos.c,v 1.30 2012/03/24 02:18:51 kristaps Exp $ */
+/* $Id: apropos.c,v 1.31 2012/06/08 10:44:52 kristaps Exp $ */
/*
- * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -27,38 +26,21 @@
#include <string.h>
#include <unistd.h>
-#include "apropos_db.h"
-#include "mandoc.h"
#include "manpath.h"
-
-#define SINGLETON(_res, _sz) \
- ((_sz) && (_res)[0].matched && \
- (1 == (_sz) || 0 == (_res)[1].matched))
-#define EMPTYSET(_res, _sz) \
- ((0 == (_sz)) || 0 == (_res)[0].matched)
-
-static int cmp(const void *, const void *);
-static void list(struct res *, size_t, void *);
-static void usage(void);
-
-static char *progname;
+#include "mansearch.h"
int
main(int argc, char *argv[])
{
- int ch, rc, whatis, usecat;
- struct res *res;
+ int ch;
+ size_t i, sz;
+ struct manpage *res;
+ char *conf_file, *defpaths, *auxpaths,
+ *arch, *sec;
struct manpaths paths;
- const char *prog;
- pid_t pid;
- char path[PATH_MAX];
- int fds[2];
- size_t terms, ressz, sz;
- struct opts opts;
- struct expr *e;
- char *defpaths, *auxpaths, *conf_file, *cp;
- extern int optind;
+ char *progname;
extern char *optarg;
+ extern int optind;
progname = strrchr(argv[0], '/');
if (progname == NULL)
@@ -66,18 +48,8 @@ main(int argc, char *argv[])
else
++progname;
- whatis = 0 == strncmp(progname, "whatis", 6);
-
+ auxpaths = defpaths = conf_file = arch = sec = NULL;
memset(&paths, 0, sizeof(struct manpaths));
- memset(&opts, 0, sizeof(struct opts));
-
- usecat = 0;
- ressz = 0;
- res = NULL;
- auxpaths = defpaths = NULL;
- conf_file = NULL;
- e = NULL;
- path[0] = '\0';
while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
switch (ch) {
@@ -91,149 +63,42 @@ main(int argc, char *argv[])
auxpaths = optarg;
break;
case ('S'):
- opts.arch = optarg;
+ arch = optarg;
break;
case ('s'):
- opts.cat = optarg;
+ sec = optarg;
break;
default:
- usage();
- return(EXIT_FAILURE);
+ goto usage;
}
argc -= optind;
argv += optind;
- if (0 == argc)
- return(EXIT_SUCCESS);
-
- rc = 0;
+ if (0 == argc)
+ goto usage;
manpath_parse(&paths, conf_file, defpaths, auxpaths);
-
- e = whatis ? termcomp(argc, argv, &terms) :
- exprcomp(argc, argv, &terms);
-
- if (NULL == e) {
- fprintf(stderr, "%s: Bad expression\n", progname);
- goto out;
- }
-
- rc = apropos_search
- (paths.sz, paths.paths, &opts,
- e, terms, NULL, &ressz, &res, list);
-
- terms = 1;
-
- if (0 == rc) {
- fprintf(stderr, "%s: Bad database\n", progname);
- goto out;
- } else if ( ! isatty(STDOUT_FILENO) || EMPTYSET(res, ressz))
- goto out;
-
- if ( ! SINGLETON(res, ressz)) {
- printf("Which manpage would you like [1]? ");
- fflush(stdout);
- if (NULL != (cp = fgetln(stdin, &sz)) &&
- sz > 1 && '\n' == cp[--sz]) {
- if ((ch = atoi(cp)) <= 0)
- goto out;
- terms = (size_t)ch;
- }
- }
-
- if (--terms < ressz && res[terms].matched) {
- chdir(paths.paths[res[terms].volume]);
- strlcpy(path, res[terms].file, PATH_MAX);
- usecat = RESTYPE_CAT == res[terms].type;
- }
-out:
+ ch = mansearch(&paths, arch, sec, argc, argv, &res, &sz);
manpath_free(&paths);
- resfree(res, ressz);
- exprfree(e);
- if ('\0' == path[0])
- return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
+ if (0 == ch)
+ goto usage;
- if (-1 == pipe(fds)) {
- perror(NULL);
- exit(EXIT_FAILURE);
+ for (i = 0; i < sz; i++) {
+ printf("%s - %s\n", res[i].file, res[i].desc);
+ free(res[i].desc);
}
- if (-1 == (pid = fork())) {
- perror(NULL);
- exit(EXIT_FAILURE);
- } else if (pid > 0) {
- dup2(fds[0], STDIN_FILENO);
- close(fds[1]);
- prog = NULL != getenv("MANPAGER") ?
- getenv("MANPAGER") :
- (NULL != getenv("PAGER") ?
- getenv("PAGER") : "more");
- execlp(prog, prog, (char *)NULL);
- perror(prog);
- return(EXIT_FAILURE);
- }
-
- dup2(fds[1], STDOUT_FILENO);
- close(fds[0]);
- prog = usecat ? "cat" : "mandoc";
- execlp(prog, prog, path, (char *)NULL);
- perror(prog);
+ free(res);
+ return(sz ? EXIT_SUCCESS : EXIT_FAILURE);
+usage:
+ fprintf(stderr, "usage: %s [-C conf] "
+ "[-M paths] "
+ "[-m paths] "
+ "[-S arch] "
+ "[-s section] "
+ "expr ...\n",
+ progname);
return(EXIT_FAILURE);
}
-
-/* ARGSUSED */
-static void
-list(struct res *res, size_t sz, void *arg)
-{
- size_t i;
-
- qsort(res, sz, sizeof(struct res), cmp);
-
- if (EMPTYSET(res, sz) || SINGLETON(res, sz))
- return;
-
- if ( ! isatty(STDOUT_FILENO))
- for (i = 0; i < sz && res[i].matched; i++)
- printf("%s(%s%s%s) - %.70s\n",
- res[i].title, res[i].cat,
- *res[i].arch ? "/" : "",
- *res[i].arch ? res[i].arch : "",
- res[i].desc);
- else
- for (i = 0; i < sz && res[i].matched; i++)
- printf("[%zu] %s(%s%s%s) - %.70s\n", i + 1,
- res[i].title, res[i].cat,
- *res[i].arch ? "/" : "",
- *res[i].arch ? res[i].arch : "",
- res[i].desc);
-}
-
-static int
-cmp(const void *p1, const void *p2)
-{
- const struct res *r1 = p1;
- const struct res *r2 = p2;
-
- if (0 == r1->matched)
- return(1);
- else if (0 == r2->matched)
- return(1);
-
- return(strcasecmp(r1->title, r2->title));
-}
-
-static void
-usage(void)
-{
-
- fprintf(stderr, "usage: %s "
- "[-C file] "
- "[-M manpath] "
- "[-m manpath] "
- "[-S arch] "
- "[-s section] "
- "expression ...\n",
- progname);
-}
diff --git a/manpage.c b/manpage.c
new file mode 100644
index 00000000..14f87665
--- /dev/null
+++ b/manpage.c
@@ -0,0 +1,178 @@
+/* $Id: manpage.c,v 1.1 2012/06/08 10:44:52 kristaps Exp $ */
+/*
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <sys/param.h>
+
+#include <assert.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "manpath.h"
+#include "mansearch.h"
+
+static void show(const char *, const char *);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, term;
+ size_t i, sz, len;
+ struct manpage *res;
+ char *conf_file, *defpaths, *auxpaths, *cp,
+ *arch, *sec;
+ char buf[MAXPATHLEN];
+ const char *cmd;
+ struct manpaths paths;
+ char *progname;
+ extern char *optarg;
+ extern int optind;
+
+ term = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
+
+ progname = strrchr(argv[0], '/');
+ if (progname == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ auxpaths = defpaths = conf_file = arch = sec = NULL;
+ memset(&paths, 0, sizeof(struct manpaths));
+
+ while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
+ switch (ch) {
+ case ('C'):
+ conf_file = optarg;
+ break;
+ case ('M'):
+ defpaths = optarg;
+ break;
+ case ('m'):
+ auxpaths = optarg;
+ break;
+ case ('S'):
+ arch = optarg;
+ break;
+ case ('s'):
+ sec = optarg;
+ break;
+ default:
+ goto usage;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (0 == argc)
+ goto usage;
+
+ manpath_parse(&paths, conf_file, defpaths, auxpaths);
+ ch = mansearch(&paths, arch, sec, argc, argv, &res, &sz);
+ manpath_free(&paths);
+
+ if (0 == ch)
+ goto usage;
+
+ if (0 == sz) {
+ free(res);
+ return(EXIT_FAILURE);
+ } else if (1 == sz && term) {
+ i = 1;
+ goto show;
+ } else if (NULL == res)
+ return(EXIT_FAILURE);
+
+ for (i = 0; i < sz; i++) {
+ printf("%6zu %s: %s\n",
+ i + 1, res[i].file, res[i].desc);
+ free(res[i].desc);
+ }
+
+ if (0 == term) {
+ free(res);
+ return(EXIT_SUCCESS);
+ }
+
+ i = 1;
+ printf("Enter a choice [1]: ");
+ fflush(stdout);
+
+ if (NULL != (cp = fgetln(stdin, &len)))
+ if ('\n' == cp[--len] && len > 0) {
+ cp[len] = '\0';
+ if ((i = atoi(cp)) < 1 || i > sz)
+ i = 0;
+ }
+
+ if (0 == i) {
+ free(res);
+ return(EXIT_SUCCESS);
+ }
+show:
+ cmd = res[i - 1].form ? "mandoc" : "cat";
+ strlcpy(buf, res[i - 1].file, MAXPATHLEN);
+ free(res);
+
+ show(cmd, buf);
+ /* NOTREACHED */
+usage:
+ fprintf(stderr, "usage: %s [-C conf] "
+ "[-M paths] "
+ "[-m paths] "
+ "[-S arch] "
+ "[-s section] "
+ "expr ...\n",
+ progname);
+ return(EXIT_FAILURE);
+}
+
+static void
+show(const char *cmd, const char *file)
+{
+ int fds[2];
+ pid_t pid;
+
+ if (-1 == pipe(fds)) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ if (-1 == (pid = fork())) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ } else if (pid > 0) {
+ dup2(fds[0], STDIN_FILENO);
+ close(fds[1]);
+ cmd = NULL != getenv("MANPAGER") ?
+ getenv("MANPAGER") :
+ (NULL != getenv("PAGER") ?
+ getenv("PAGER") : "more");
+ execlp(cmd, cmd, (char *)NULL);
+ perror(cmd);
+ exit(EXIT_FAILURE);
+ }
+
+ dup2(fds[1], STDOUT_FILENO);
+ close(fds[0]);
+ execlp(cmd, cmd, file, (char *)NULL);
+ perror(cmd);
+ exit(EXIT_FAILURE);
+}