Annotation of mandoc/apropos.c, Revision 1.29
1.29 ! kristaps 1: /* $Id: apropos.c,v 1.28 2012/03/24 01:46:25 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>
1.29 ! kristaps 28: #include <unistd.h>
1.1 kristaps 29:
1.11 schwarze 30: #include "apropos_db.h"
1.1 kristaps 31: #include "mandoc.h"
1.18 kristaps 32: #include "manpath.h"
1.15 kristaps 33:
1.28 kristaps 34: #define SINGLETON(_res, _sz) \
35: ((_sz) && (_res)[0].matched && \
36: (1 == (_sz) || 0 == (_res)[1].matched))
37: #define EMPTYSET(_res, _sz) \
38: ((0 == (_sz)) || 0 == (_res)[0].matched)
39:
1.8 kristaps 40: static int cmp(const void *, const void *);
1.14 kristaps 41: static void list(struct res *, size_t, void *);
1.1 kristaps 42: static void usage(void);
43:
1.2 kristaps 44: static char *progname;
1.1 kristaps 45:
46: int
47: main(int argc, char *argv[])
48: {
1.28 kristaps 49: int ch, rc, whatis, usecat;
1.27 kristaps 50: struct res *res;
1.15 kristaps 51: struct manpaths paths;
1.28 kristaps 52: const char *prog;
53: pid_t pid;
54: char path[PATH_MAX];
55: int fds[2];
56: size_t terms, ressz, sz;
1.1 kristaps 57: struct opts opts;
1.10 kristaps 58: struct expr *e;
1.28 kristaps 59: char *defpaths, *auxpaths, *conf_file, *cp;
1.1 kristaps 60: extern int optind;
61: extern char *optarg;
62:
63: progname = strrchr(argv[0], '/');
64: if (progname == NULL)
65: progname = argv[0];
66: else
67: ++progname;
68:
1.21 schwarze 69: whatis = 0 == strncmp(progname, "whatis", 6);
1.20 kristaps 70:
1.15 kristaps 71: memset(&paths, 0, sizeof(struct manpaths));
72: memset(&opts, 0, sizeof(struct opts));
73:
1.28 kristaps 74: usecat = 0;
1.27 kristaps 75: ressz = 0;
76: res = NULL;
1.17 kristaps 77: auxpaths = defpaths = NULL;
1.24 schwarze 78: conf_file = NULL;
1.15 kristaps 79: e = NULL;
1.28 kristaps 80: path[0] = '\0';
1.15 kristaps 81:
1.24 schwarze 82: while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
1.1 kristaps 83: switch (ch) {
1.24 schwarze 84: case ('C'):
85: conf_file = optarg;
86: break;
1.17 kristaps 87: case ('M'):
88: defpaths = optarg;
89: break;
1.15 kristaps 90: case ('m'):
1.17 kristaps 91: auxpaths = optarg;
1.15 kristaps 92: break;
1.9 kristaps 93: case ('S'):
1.1 kristaps 94: opts.arch = optarg;
95: break;
1.9 kristaps 96: case ('s'):
1.1 kristaps 97: opts.cat = optarg;
98: break;
99: default:
100: usage();
1.20 kristaps 101: return(EXIT_FAILURE);
1.1 kristaps 102: }
103:
104: argc -= optind;
105: argv += optind;
106:
1.20 kristaps 107: if (0 == argc)
108: return(EXIT_SUCCESS);
109:
110: rc = 0;
1.15 kristaps 111:
1.24 schwarze 112: manpath_parse(&paths, conf_file, defpaths, auxpaths);
1.1 kristaps 113:
1.20 kristaps 114: e = whatis ? termcomp(argc, argv, &terms) :
115: exprcomp(argc, argv, &terms);
116:
117: if (NULL == e) {
1.16 kristaps 118: fprintf(stderr, "%s: Bad expression\n", progname);
1.15 kristaps 119: goto out;
1.10 kristaps 120: }
1.13 kristaps 121:
1.15 kristaps 122: rc = apropos_search
1.27 kristaps 123: (paths.sz, paths.paths, &opts,
124: e, terms, NULL, &ressz, &res, list);
1.2 kristaps 125:
1.28 kristaps 126: terms = 1;
127:
1.27 kristaps 128: if (0 == rc) {
129: fprintf(stderr, "%s: Bad database\n", progname);
130: goto out;
1.28 kristaps 131: } else if ( ! isatty(STDOUT_FILENO) || EMPTYSET(res, ressz))
132: goto out;
133:
134: if ( ! SINGLETON(res, ressz)) {
135: printf("Which manpage would you like [1]? ");
136: fflush(stdout);
137: if (NULL != (cp = fgetln(stdin, &sz)) &&
138: sz > 1 && '\n' == cp[--sz]) {
139: if ((ch = atoi(cp)) <= 0)
140: goto out;
141: terms = (size_t)ch;
142: }
143: }
144:
145: if (--terms < ressz && res[terms].matched) {
146: strlcpy(path, res[terms].file, PATH_MAX);
147: usecat = RESTYPE_CAT == res[terms].type;
1.27 kristaps 148: }
1.15 kristaps 149: out:
1.18 kristaps 150: manpath_free(&paths);
1.27 kristaps 151: resfree(res, ressz);
1.10 kristaps 152: exprfree(e);
1.28 kristaps 153:
154: if ('\0' == path[0])
155: return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
156:
157: if (-1 == pipe(fds)) {
158: perror(NULL);
159: exit(EXIT_FAILURE);
160: }
161:
162: if (-1 == (pid = fork())) {
163: perror(NULL);
164: exit(EXIT_FAILURE);
165: } else if (pid > 0) {
166: dup2(fds[0], STDIN_FILENO);
167: close(fds[1]);
168: prog = NULL != getenv("MANPAGER") ?
169: getenv("MANPAGER") :
170: (NULL != getenv("PAGER") ?
171: getenv("PAGER") : "more");
172: execlp(prog, prog, (char *)NULL);
173: perror(prog);
174: return(EXIT_FAILURE);
175: }
176:
177: dup2(fds[1], STDOUT_FILENO);
178: close(fds[0]);
179: prog = usecat ? "cat" : "mandoc";
180: execlp(prog, prog, path, (char *)NULL);
181: perror(prog);
182: return(EXIT_FAILURE);
1.1 kristaps 183: }
184:
1.8 kristaps 185: /* ARGSUSED */
1.1 kristaps 186: static void
1.14 kristaps 187: list(struct res *res, size_t sz, void *arg)
1.1 kristaps 188: {
1.26 kristaps 189: size_t i;
1.1 kristaps 190:
1.14 kristaps 191: qsort(res, sz, sizeof(struct res), cmp);
1.1 kristaps 192:
1.28 kristaps 193: if (EMPTYSET(res, sz) || SINGLETON(res, sz))
194: return;
195:
196: if ( ! isatty(STDOUT_FILENO))
197: for (i = 0; i < sz && res[i].matched; i++)
198: printf("%s(%s%s%s) - %.70s\n",
199: res[i].title, res[i].cat,
200: *res[i].arch ? "/" : "",
201: *res[i].arch ? res[i].arch : "",
202: res[i].desc);
203: else
204: for (i = 0; i < sz && res[i].matched; i++)
205: printf("[%zu] %s(%s%s%s) - %.70s\n", i + 1,
206: res[i].title, res[i].cat,
207: *res[i].arch ? "/" : "",
208: *res[i].arch ? res[i].arch : "",
209: res[i].desc);
1.1 kristaps 210: }
211:
1.8 kristaps 212: static int
213: cmp(const void *p1, const void *p2)
214: {
1.28 kristaps 215: const struct res *r1 = p1;
216: const struct res *r2 = p2;
217:
218: if (0 == r1->matched)
219: return(1);
220: else if (0 == r2->matched)
221: return(1);
1.8 kristaps 222:
1.28 kristaps 223: return(strcasecmp(r1->title, r2->title));
1.8 kristaps 224: }
225:
1.1 kristaps 226: static void
227: usage(void)
228: {
229:
1.15 kristaps 230: fprintf(stderr, "usage: %s "
1.24 schwarze 231: "[-C file] "
1.22 kristaps 232: "[-M manpath] "
233: "[-m manpath] "
1.15 kristaps 234: "[-S arch] "
235: "[-s section] "
1.24 schwarze 236: "expression ...\n",
1.19 schwarze 237: progname);
1.1 kristaps 238: }
CVSweb