From 88f15230be7f66fcbb0009b5e966bad9b4f425c9 Mon Sep 17 00:00:00 2001 From: Kristaps Dzonsons Date: Sat, 24 Mar 2012 01:46:25 +0000 Subject: [PATCH] Be insane. Make apropos(1) subsume man(1). --- apropos.1 | 40 +++++++++++++------ apropos.c | 110 ++++++++++++++++++++++++++++++++++++++++++--------- apropos_db.c | 4 +- apropos_db.h | 4 +- cgi.c | 4 +- 5 files changed, 125 insertions(+), 37 deletions(-) diff --git a/apropos.1 b/apropos.1 index f2e0171a..7dea132a 100644 --- a/apropos.1 +++ b/apropos.1 @@ -1,6 +1,6 @@ -.\" $Id: apropos.1,v 1.16 2011/12/25 19:35:44 kristaps Exp $ +.\" $Id: apropos.1,v 1.17 2012/03/24 01:46:25 kristaps Exp $ .\" -.\" Copyright (c) 2011 Kristaps Dzonsons +.\" Copyright (c) 2011, 2012 Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -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: December 25 2011 $ +.Dd $Mdocdate: March 24 2012 $ .Dt APROPOS 1 .Os .Sh NAME @@ -44,11 +44,11 @@ searches for databases in the default paths stipulated by .Xr man 1 , parses terms as case-sensitive regular expressions -.Pq the Li \&~ operator -over manual names and descriptions -.Pq the Li \&Nm No and Li \&Nd No macro keys . +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. .Pp Its arguments are as follows: .Bl -tag -width Ds @@ -156,13 +156,21 @@ If an architecture is specified for the manual, it is displayed as .Pp .D1 title(cat/arch) \- description .Pp -Resulting manuals may be accessed as +If on a TTY, results are prefixed with a numeric identifier. .Pp -.Dl $ man \-s sec title +.D1 [index] title(cat) \- description .Pp -If an architecture is specified in the output, use -.Pp -.Dl $ man \-s sec \-S arch title +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 . .Ss Macro Keys Queries evaluate over a subset of .Xr mdoc 7 @@ -240,6 +248,14 @@ 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. @@ -301,7 +317,7 @@ as variable names in the library category: .Pp .Dl $ apropos \-s 3 Va~^optind \-a Va~^optarg$ .Sh SEE ALSO -.Xr man 1 , +.Xr more 1 .Xr re_format 7 , .Xr mandocdb 8 .Sh AUTHORS diff --git a/apropos.c b/apropos.c index 5278832e..4fcfba6f 100644 --- a/apropos.c +++ b/apropos.c @@ -1,6 +1,6 @@ -/* $Id: apropos.c,v 1.27 2012/03/24 00:31:55 kristaps Exp $ */ +/* $Id: apropos.c,v 1.28 2012/03/24 01:46:25 kristaps Exp $ */ /* - * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any @@ -30,6 +30,12 @@ #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); @@ -39,14 +45,17 @@ static char *progname; int main(int argc, char *argv[]) { - int ch, rc, whatis; + int ch, rc, whatis, usecat; struct res *res; struct manpaths paths; - size_t terms, ressz; + 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; - char *conf_file; + char *defpaths, *auxpaths, *conf_file, *cp; extern int optind; extern char *optarg; @@ -61,11 +70,13 @@ main(int argc, char *argv[]) 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) { @@ -111,15 +122,63 @@ main(int argc, char *argv[]) (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) { + strlcpy(path, res[terms].file, PATH_MAX); + usecat = RESTYPE_CAT == res[terms].type; } out: manpath_free(&paths); resfree(res, ressz); exprfree(e); - return(rc ? EXIT_SUCCESS : EXIT_FAILURE); + + if ('\0' == path[0]) + return(rc ? EXIT_SUCCESS : EXIT_FAILURE); + + 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]); + 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); + return(EXIT_FAILURE); } /* ARGSUSED */ @@ -130,24 +189,37 @@ list(struct res *res, size_t sz, void *arg) qsort(res, sz, sizeof(struct res), cmp); - for (i = 0; i < sz; i++) { - if ( ! res[i].matched) - continue; - 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); - } + 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(((const struct res *)p1)->title, - ((const struct res *)p2)->title)); + return(strcasecmp(r1->title, r2->title)); } static void diff --git a/apropos_db.c b/apropos_db.c index 50a84230..8aea771d 100644 --- a/apropos_db.c +++ b/apropos_db.c @@ -1,6 +1,6 @@ -/* $Id: apropos_db.c,v 1.30 2012/03/24 00:31:55 kristaps Exp $ */ +/* $Id: apropos_db.c,v 1.31 2012/03/24 01:46:25 kristaps Exp $ */ /* - * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any diff --git a/apropos_db.h b/apropos_db.h index bf0913e8..72d4c204 100644 --- a/apropos_db.h +++ b/apropos_db.h @@ -1,6 +1,6 @@ -/* $Id: apropos_db.h,v 1.12 2012/03/24 00:31:55 kristaps Exp $ */ +/* $Id: apropos_db.h,v 1.13 2012/03/24 01:46:25 kristaps Exp $ */ /* - * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011, 2012 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cgi.c b/cgi.c index 205235a2..2f5870ff 100644 --- a/cgi.c +++ b/cgi.c @@ -1,6 +1,6 @@ -/* $Id: cgi.c,v 1.41 2012/03/24 00:31:55 kristaps Exp $ */ +/* $Id: cgi.c,v 1.42 2012/03/24 01:46:25 kristaps Exp $ */ /* - * Copyright (c) 2011 Kristaps Dzonsons + * Copyright (c) 2011, 2012 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above -- 2.47.1