Annotation of mandoc/apropos.c, Revision 1.30
1.30 ! kristaps 1: /* $Id: apropos.c,v 1.29 2012/03/24 02:07:32 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) {
1.30 ! kristaps 146: chdir(paths.paths[res[terms].volume]);
1.28 kristaps 147: strlcpy(path, res[terms].file, PATH_MAX);
148: usecat = RESTYPE_CAT == res[terms].type;
1.27 kristaps 149: }
1.15 kristaps 150: out:
1.18 kristaps 151: manpath_free(&paths);
1.27 kristaps 152: resfree(res, ressz);
1.10 kristaps 153: exprfree(e);
1.28 kristaps 154:
155: if ('\0' == path[0])
156: return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
157:
158: if (-1 == pipe(fds)) {
159: perror(NULL);
160: exit(EXIT_FAILURE);
161: }
162:
163: if (-1 == (pid = fork())) {
164: perror(NULL);
165: exit(EXIT_FAILURE);
166: } else if (pid > 0) {
167: dup2(fds[0], STDIN_FILENO);
168: close(fds[1]);
169: prog = NULL != getenv("MANPAGER") ?
170: getenv("MANPAGER") :
171: (NULL != getenv("PAGER") ?
172: getenv("PAGER") : "more");
173: execlp(prog, prog, (char *)NULL);
174: perror(prog);
175: return(EXIT_FAILURE);
176: }
177:
178: dup2(fds[1], STDOUT_FILENO);
179: close(fds[0]);
180: prog = usecat ? "cat" : "mandoc";
181: execlp(prog, prog, path, (char *)NULL);
182: perror(prog);
183: return(EXIT_FAILURE);
1.1 kristaps 184: }
185:
1.8 kristaps 186: /* ARGSUSED */
1.1 kristaps 187: static void
1.14 kristaps 188: list(struct res *res, size_t sz, void *arg)
1.1 kristaps 189: {
1.26 kristaps 190: size_t i;
1.1 kristaps 191:
1.14 kristaps 192: qsort(res, sz, sizeof(struct res), cmp);
1.1 kristaps 193:
1.28 kristaps 194: if (EMPTYSET(res, sz) || SINGLETON(res, sz))
195: return;
196:
197: if ( ! isatty(STDOUT_FILENO))
198: for (i = 0; i < sz && res[i].matched; i++)
199: printf("%s(%s%s%s) - %.70s\n",
200: res[i].title, res[i].cat,
201: *res[i].arch ? "/" : "",
202: *res[i].arch ? res[i].arch : "",
203: res[i].desc);
204: else
205: for (i = 0; i < sz && res[i].matched; i++)
206: printf("[%zu] %s(%s%s%s) - %.70s\n", i + 1,
207: res[i].title, res[i].cat,
208: *res[i].arch ? "/" : "",
209: *res[i].arch ? res[i].arch : "",
210: res[i].desc);
1.1 kristaps 211: }
212:
1.8 kristaps 213: static int
214: cmp(const void *p1, const void *p2)
215: {
1.28 kristaps 216: const struct res *r1 = p1;
217: const struct res *r2 = p2;
218:
219: if (0 == r1->matched)
220: return(1);
221: else if (0 == r2->matched)
222: return(1);
1.8 kristaps 223:
1.28 kristaps 224: return(strcasecmp(r1->title, r2->title));
1.8 kristaps 225: }
226:
1.1 kristaps 227: static void
228: usage(void)
229: {
230:
1.15 kristaps 231: fprintf(stderr, "usage: %s "
1.24 schwarze 232: "[-C file] "
1.22 kristaps 233: "[-M manpath] "
234: "[-m manpath] "
1.15 kristaps 235: "[-S arch] "
236: "[-s section] "
1.24 schwarze 237: "expression ...\n",
1.19 schwarze 238: progname);
1.1 kristaps 239: }
CVSweb