Annotation of mandoc/apropos.c, Revision 1.17
1.17 ! kristaps 1: /* $Id: apropos.c,v 1.16 2011/11/20 16:29:50 kristaps Exp $ */
1.1 kristaps 2: /*
1.8 kristaps 3: * Copyright (c) 2011 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
21:
1.1 kristaps 22: #include <assert.h>
1.17 ! kristaps 23: #include <ctype.h>
1.1 kristaps 24: #include <getopt.h>
25: #include <limits.h>
26: #include <stdio.h>
27: #include <stdlib.h>
28: #include <string.h>
29:
1.11 schwarze 30: #include "apropos_db.h"
1.1 kristaps 31: #include "mandoc.h"
32:
1.15 kristaps 33: /*
1.17 ! kristaps 34: * FIXME: add support for manpath(1), which everybody but OpenBSD and
! 35: * NetBSD seem to use.
! 36: */
! 37: #define MAN_CONF_FILE "/etc/man.conf"
! 38: #define MAN_CONF_KEY "_whatdb"
! 39:
! 40: /*
1.15 kristaps 41: * List of paths to be searched for manual databases.
42: */
43: struct manpaths {
44: int sz;
45: char **paths;
46: };
47:
1.8 kristaps 48: static int cmp(const void *, const void *);
1.14 kristaps 49: static void list(struct res *, size_t, void *);
1.16 kristaps 50: static void manpath_add(struct manpaths *, const char *);
51: static void manpath_parse(struct manpaths *, char *);
1.17 ! kristaps 52: static void manpath_parseconf(struct manpaths *);
1.1 kristaps 53: static void usage(void);
54:
1.2 kristaps 55: static char *progname;
1.1 kristaps 56:
57: int
58: main(int argc, char *argv[])
59: {
1.15 kristaps 60: int i, ch, rc;
61: struct manpaths paths;
1.14 kristaps 62: size_t terms;
1.1 kristaps 63: struct opts opts;
1.10 kristaps 64: struct expr *e;
1.17 ! kristaps 65: char *defpaths, *auxpaths;
1.1 kristaps 66: extern int optind;
67: extern char *optarg;
68:
69: progname = strrchr(argv[0], '/');
70: if (progname == NULL)
71: progname = argv[0];
72: else
73: ++progname;
74:
1.15 kristaps 75: memset(&paths, 0, sizeof(struct manpaths));
76: memset(&opts, 0, sizeof(struct opts));
77:
1.17 ! kristaps 78: auxpaths = defpaths = NULL;
1.15 kristaps 79: e = NULL;
80: rc = 0;
81:
1.17 ! kristaps 82: while (-1 != (ch = getopt(argc, argv, "M:m:S:s:")))
1.1 kristaps 83: switch (ch) {
1.17 ! kristaps 84: case ('M'):
! 85: defpaths = optarg;
! 86: break;
1.15 kristaps 87: case ('m'):
1.17 ! kristaps 88: auxpaths = optarg;
1.15 kristaps 89: break;
1.9 kristaps 90: case ('S'):
1.1 kristaps 91: opts.arch = optarg;
92: break;
1.9 kristaps 93: case ('s'):
1.1 kristaps 94: opts.cat = optarg;
95: break;
96: default:
97: usage();
1.15 kristaps 98: goto out;
1.1 kristaps 99: }
100:
101: argc -= optind;
102: argv += optind;
103:
1.15 kristaps 104: if (0 == argc) {
105: rc = 1;
106: goto out;
107: }
108:
1.17 ! kristaps 109: if (NULL != getenv("MANPATH"))
! 110: defpaths = getenv("MANPATH");
1.16 kristaps 111:
1.17 ! kristaps 112: if (NULL == defpaths)
! 113: manpath_parseconf(&paths);
1.16 kristaps 114: else
1.17 ! kristaps 115: manpath_parse(&paths, defpaths);
! 116:
! 117: manpath_parse(&paths, auxpaths);
1.1 kristaps 118:
1.14 kristaps 119: if (NULL == (e = exprcomp(argc, argv, &terms))) {
1.16 kristaps 120: fprintf(stderr, "%s: Bad expression\n", progname);
1.15 kristaps 121: goto out;
1.10 kristaps 122: }
1.13 kristaps 123:
1.15 kristaps 124: rc = apropos_search
125: (paths.sz, paths.paths,
126: &opts, e, terms, NULL, list);
127:
1.16 kristaps 128: if (0 == rc)
129: fprintf(stderr, "%s: Error reading "
130: "manual database\n", progname);
1.2 kristaps 131:
1.15 kristaps 132: out:
133: for (i = 0; i < paths.sz; i++)
134: free(paths.paths[i]);
135:
136: free(paths.paths);
1.10 kristaps 137: exprfree(e);
1.15 kristaps 138:
139: return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
1.1 kristaps 140: }
141:
1.8 kristaps 142: /* ARGSUSED */
1.1 kristaps 143: static void
1.14 kristaps 144: list(struct res *res, size_t sz, void *arg)
1.1 kristaps 145: {
1.8 kristaps 146: int i;
1.1 kristaps 147:
1.14 kristaps 148: qsort(res, sz, sizeof(struct res), cmp);
1.1 kristaps 149:
1.8 kristaps 150: for (i = 0; i < (int)sz; i++)
1.1 kristaps 151: printf("%s(%s%s%s) - %s\n", res[i].title,
152: res[i].cat,
153: *res[i].arch ? "/" : "",
154: *res[i].arch ? res[i].arch : "",
155: res[i].desc);
156: }
157:
1.8 kristaps 158: static int
159: cmp(const void *p1, const void *p2)
160: {
161:
1.14 kristaps 162: return(strcmp(((const struct res *)p1)->title,
163: ((const struct res *)p2)->title));
1.8 kristaps 164: }
165:
1.1 kristaps 166: static void
167: usage(void)
168: {
169:
1.15 kristaps 170: fprintf(stderr, "usage: %s "
1.17 ! kristaps 171: "[-M dirs] "
1.15 kristaps 172: "[-m dirs] "
173: "[-S arch] "
174: "[-s section] "
1.14 kristaps 175: "expression...\n", progname);
1.15 kristaps 176: }
177:
178: /*
179: * Parse a FULL pathname from a colon-separated list of arrays.
180: */
1.16 kristaps 181: static void
1.15 kristaps 182: manpath_parse(struct manpaths *dirs, char *path)
183: {
184: char *dir;
185:
1.17 ! kristaps 186: if (NULL == path)
! 187: return;
! 188:
1.15 kristaps 189: for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
1.16 kristaps 190: manpath_add(dirs, dir);
1.15 kristaps 191: }
192:
193: /*
1.16 kristaps 194: * Add a directory to the array, ignoring bad directories.
1.15 kristaps 195: * Grow the array one-by-one for simplicity's sake.
196: */
1.16 kristaps 197: static void
1.15 kristaps 198: manpath_add(struct manpaths *dirs, const char *dir)
199: {
200: char buf[PATH_MAX];
201: char *cp;
1.17 ! kristaps 202: int i;
1.15 kristaps 203:
1.16 kristaps 204: if (NULL == (cp = realpath(dir, buf)))
205: return;
1.15 kristaps 206:
1.17 ! kristaps 207: for (i = 0; i < dirs->sz; i++)
! 208: if (0 == strcmp(dirs->paths[i], dir))
! 209: return;
! 210:
1.15 kristaps 211: dirs->paths = mandoc_realloc
212: (dirs->paths,
213: ((size_t)dirs->sz + 1) * sizeof(char *));
214:
215: dirs->paths[dirs->sz++] = mandoc_strdup(cp);
1.17 ! kristaps 216: }
! 217:
! 218: static void
! 219: manpath_parseconf(struct manpaths *dirs)
! 220: {
! 221: FILE *stream;
! 222: #ifdef USE_MANPATH
! 223: char *buf;
! 224: size_t sz, bsz;
! 225:
! 226: stream = popen("manpath", "r");
! 227: if (NULL == stream)
! 228: return;
! 229:
! 230: buf = NULL;
! 231: bsz = 0;
! 232:
! 233: do {
! 234: buf = mandoc_realloc(buf, bsz + 1024);
! 235: sz = fread(buf + (int)bsz, 1, 1024, stream);
! 236: bsz += sz;
! 237: } while (sz > 0);
! 238:
! 239: assert(bsz && '\n' == buf[bsz - 1]);
! 240: buf[bsz - 1] = '\0';
! 241:
! 242: manpath_parse(dirs, buf);
! 243: free(buf);
! 244: pclose(stream);
! 245: #else
! 246: char *p, *q;
! 247: size_t len, keysz;
! 248:
! 249: keysz = strlen(MAN_CONF_KEY);
! 250: assert(keysz > 0);
! 251:
! 252: if (NULL == (stream = fopen(MAN_CONF_FILE, "r")))
! 253: return;
! 254:
! 255: while (NULL != (p = fgetln(stream, &len))) {
! 256: if (0 == len || '\n' == p[--len])
! 257: break;
! 258: p[len] = '\0';
! 259: while (isspace((unsigned char)*p))
! 260: p++;
! 261: if (strncmp(MAN_CONF_KEY, p, keysz))
! 262: continue;
! 263: p += keysz;
! 264: while (isspace(*p))
! 265: p++;
! 266: if ('\0' == *p)
! 267: continue;
! 268: if (NULL == (q = strrchr(p, '/')))
! 269: continue;
! 270: *q = '\0';
! 271: manpath_add(dirs, p);
! 272: }
! 273:
! 274: fclose(stream);
! 275: #endif
1.1 kristaps 276: }
CVSweb