diff options
-rw-r--r-- | apropos.1 | 116 | ||||
-rw-r--r-- | apropos.c | 197 | ||||
-rw-r--r-- | manpage.c | 178 |
3 files changed, 233 insertions, 258 deletions
@@ -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 @@ -1,7 +1,6 @@ /* $Id$ */ /* - * 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..93f3d264 --- /dev/null +++ b/manpage.c @@ -0,0 +1,178 @@ +/* $Id$ */ +/* + * 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); +} |