Annotation of mandoc/apropos.c, Revision 1.28
1.28 ! kristaps 1: /* $Id: apropos.c,v 1.27 2012/03/24 00:31:55 kristaps Exp $ */
1.1 kristaps 2: /*
1.28 ! kristaps 3: * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
1.15 kristaps 4: * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
1.13 kristaps 18: #ifdef HAVE_CONFIG_H
19: #include "config.h"
20: #endif
1.27 kristaps 21: #include <sys/param.h>
1.13 kristaps 22:
1.1 kristaps 23: #include <assert.h>
24: #include <getopt.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28:
1.11 schwarze 29: #include "apropos_db.h"
1.1 kristaps 30: #include "mandoc.h"
1.18 kristaps 31: #include "manpath.h"
1.15 kristaps 32:
1.28 ! kristaps 33: #define SINGLETON(_res, _sz) \
! 34: ((_sz) && (_res)[0].matched && \
! 35: (1 == (_sz) || 0 == (_res)[1].matched))
! 36: #define EMPTYSET(_res, _sz) \
! 37: ((0 == (_sz)) || 0 == (_res)[0].matched)
! 38:
1.8 kristaps 39: static int cmp(const void *, const void *);
1.14 kristaps 40: static void list(struct res *, size_t, void *);
1.1 kristaps 41: static void usage(void);
42:
1.2 kristaps 43: static char *progname;
1.1 kristaps 44:
45: int
46: main(int argc, char *argv[])
47: {
1.28 ! kristaps 48: int ch, rc, whatis, usecat;
1.27 kristaps 49: struct res *res;
1.15 kristaps 50: struct manpaths paths;
1.28 ! kristaps 51: const char *prog;
! 52: pid_t pid;
! 53: char path[PATH_MAX];
! 54: int fds[2];
! 55: size_t terms, ressz, sz;
1.1 kristaps 56: struct opts opts;
1.10 kristaps 57: struct expr *e;
1.28 ! kristaps 58: char *defpaths, *auxpaths, *conf_file, *cp;
1.1 kristaps 59: extern int optind;
60: extern char *optarg;
61:
62: progname = strrchr(argv[0], '/');
63: if (progname == NULL)
64: progname = argv[0];
65: else
66: ++progname;
67:
1.21 schwarze 68: whatis = 0 == strncmp(progname, "whatis", 6);
1.20 kristaps 69:
1.15 kristaps 70: memset(&paths, 0, sizeof(struct manpaths));
71: memset(&opts, 0, sizeof(struct opts));
72:
1.28 ! kristaps 73: usecat = 0;
1.27 kristaps 74: ressz = 0;
75: res = NULL;
1.17 kristaps 76: auxpaths = defpaths = NULL;
1.24 schwarze 77: conf_file = NULL;
1.15 kristaps 78: e = NULL;
1.28 ! kristaps 79: path[0] = '\0';
1.15 kristaps 80:
1.24 schwarze 81: while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
1.1 kristaps 82: switch (ch) {
1.24 schwarze 83: case ('C'):
84: conf_file = optarg;
85: break;
1.17 kristaps 86: case ('M'):
87: defpaths = optarg;
88: break;
1.15 kristaps 89: case ('m'):
1.17 kristaps 90: auxpaths = optarg;
1.15 kristaps 91: break;
1.9 kristaps 92: case ('S'):
1.1 kristaps 93: opts.arch = optarg;
94: break;
1.9 kristaps 95: case ('s'):
1.1 kristaps 96: opts.cat = optarg;
97: break;
98: default:
99: usage();
1.20 kristaps 100: return(EXIT_FAILURE);
1.1 kristaps 101: }
102:
103: argc -= optind;
104: argv += optind;
105:
1.20 kristaps 106: if (0 == argc)
107: return(EXIT_SUCCESS);
108:
109: rc = 0;
1.15 kristaps 110:
1.24 schwarze 111: manpath_parse(&paths, conf_file, defpaths, auxpaths);
1.1 kristaps 112:
1.20 kristaps 113: e = whatis ? termcomp(argc, argv, &terms) :
114: exprcomp(argc, argv, &terms);
115:
116: if (NULL == e) {
1.16 kristaps 117: fprintf(stderr, "%s: Bad expression\n", progname);
1.15 kristaps 118: goto out;
1.10 kristaps 119: }
1.13 kristaps 120:
1.15 kristaps 121: rc = apropos_search
1.27 kristaps 122: (paths.sz, paths.paths, &opts,
123: e, terms, NULL, &ressz, &res, list);
1.2 kristaps 124:
1.28 ! kristaps 125: terms = 1;
! 126:
1.27 kristaps 127: if (0 == rc) {
128: fprintf(stderr, "%s: Bad database\n", progname);
129: goto out;
1.28 ! kristaps 130: } else if ( ! isatty(STDOUT_FILENO) || EMPTYSET(res, ressz))
! 131: goto out;
! 132:
! 133: if ( ! SINGLETON(res, ressz)) {
! 134: printf("Which manpage would you like [1]? ");
! 135: fflush(stdout);
! 136: if (NULL != (cp = fgetln(stdin, &sz)) &&
! 137: sz > 1 && '\n' == cp[--sz]) {
! 138: if ((ch = atoi(cp)) <= 0)
! 139: goto out;
! 140: terms = (size_t)ch;
! 141: }
! 142: }
! 143:
! 144: if (--terms < ressz && res[terms].matched) {
! 145: strlcpy(path, res[terms].file, PATH_MAX);
! 146: usecat = RESTYPE_CAT == res[terms].type;
1.27 kristaps 147: }
1.15 kristaps 148: out:
1.18 kristaps 149: manpath_free(&paths);
1.27 kristaps 150: resfree(res, ressz);
1.10 kristaps 151: exprfree(e);
1.28 ! kristaps 152:
! 153: if ('\0' == path[0])
! 154: return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
! 155:
! 156: if (-1 == pipe(fds)) {
! 157: perror(NULL);
! 158: exit(EXIT_FAILURE);
! 159: }
! 160:
! 161: if (-1 == (pid = fork())) {
! 162: perror(NULL);
! 163: exit(EXIT_FAILURE);
! 164: } else if (pid > 0) {
! 165: dup2(fds[0], STDIN_FILENO);
! 166: close(fds[1]);
! 167: prog = NULL != getenv("MANPAGER") ?
! 168: getenv("MANPAGER") :
! 169: (NULL != getenv("PAGER") ?
! 170: getenv("PAGER") : "more");
! 171: execlp(prog, prog, (char *)NULL);
! 172: perror(prog);
! 173: return(EXIT_FAILURE);
! 174: }
! 175:
! 176: dup2(fds[1], STDOUT_FILENO);
! 177: close(fds[0]);
! 178: prog = usecat ? "cat" : "mandoc";
! 179: execlp(prog, prog, path, (char *)NULL);
! 180: perror(prog);
! 181: return(EXIT_FAILURE);
1.1 kristaps 182: }
183:
1.8 kristaps 184: /* ARGSUSED */
1.1 kristaps 185: static void
1.14 kristaps 186: list(struct res *res, size_t sz, void *arg)
1.1 kristaps 187: {
1.26 kristaps 188: size_t i;
1.1 kristaps 189:
1.14 kristaps 190: qsort(res, sz, sizeof(struct res), cmp);
1.1 kristaps 191:
1.28 ! kristaps 192: if (EMPTYSET(res, sz) || SINGLETON(res, sz))
! 193: return;
! 194:
! 195: if ( ! isatty(STDOUT_FILENO))
! 196: for (i = 0; i < sz && res[i].matched; i++)
! 197: printf("%s(%s%s%s) - %.70s\n",
! 198: res[i].title, res[i].cat,
! 199: *res[i].arch ? "/" : "",
! 200: *res[i].arch ? res[i].arch : "",
! 201: res[i].desc);
! 202: else
! 203: for (i = 0; i < sz && res[i].matched; i++)
! 204: printf("[%zu] %s(%s%s%s) - %.70s\n", i + 1,
! 205: res[i].title, res[i].cat,
! 206: *res[i].arch ? "/" : "",
! 207: *res[i].arch ? res[i].arch : "",
! 208: res[i].desc);
1.1 kristaps 209: }
210:
1.8 kristaps 211: static int
212: cmp(const void *p1, const void *p2)
213: {
1.28 ! kristaps 214: const struct res *r1 = p1;
! 215: const struct res *r2 = p2;
! 216:
! 217: if (0 == r1->matched)
! 218: return(1);
! 219: else if (0 == r2->matched)
! 220: return(1);
1.8 kristaps 221:
1.28 ! kristaps 222: return(strcasecmp(r1->title, r2->title));
1.8 kristaps 223: }
224:
1.1 kristaps 225: static void
226: usage(void)
227: {
228:
1.15 kristaps 229: fprintf(stderr, "usage: %s "
1.24 schwarze 230: "[-C file] "
1.22 kristaps 231: "[-M manpath] "
232: "[-m manpath] "
1.15 kristaps 233: "[-S arch] "
234: "[-s section] "
1.24 schwarze 235: "expression ...\n",
1.19 schwarze 236: progname);
1.1 kristaps 237: }
CVSweb