[BACK]Return to apropos.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

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