Experimental feature to let apropos(1) show different keys than .Nd.
authorschwarze <schwarze@openbsd.org>
Tue, 31 Dec 2013 03:41:09 +0000 (03:41 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 31 Dec 2013 03:41:09 +0000 (03:41 +0000)
This really takes us beyond what grep -R /usr/*/man/ can do
because now you can search for pages by *one* criterion and then
display the contents of *another* macro from those pages, like in
$ apropos -O Ox Fa~wchar
to get an impression how long wide character handling is available.

usr.bin/mandoc/apropos.c
usr.bin/mandoc/mansearch.c
usr.bin/mandoc/mansearch.h

index d9cf3d1..ecce6dc 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: apropos.c,v 1.18 2013/12/31 00:40:19 schwarze Exp $ */
+/*     $Id: apropos.c,v 1.19 2013/12/31 03:41:09 schwarze Exp $ */
 /*
  * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -38,6 +39,7 @@ apropos(int argc, char *argv[])
        char            *defpaths, *auxpaths;
        char            *conf_file;
        char            *progname;
+       char            *outkey;
        extern char     *optarg;
        extern int       optind;
 
@@ -54,8 +56,9 @@ apropos(int argc, char *argv[])
 
        auxpaths = defpaths = NULL;
        conf_file = NULL;
+       outkey = NULL;
 
-       while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
+       while (-1 != (ch = getopt(argc, argv, "C:M:m:O:S:s:")))
                switch (ch) {
                case ('C'):
                        conf_file = optarg;
@@ -66,6 +69,9 @@ apropos(int argc, char *argv[])
                case ('m'):
                        auxpaths = optarg;
                        break;
+               case ('O'):
+                       outkey = optarg;
+                       break;
                case ('S'):
                        search.arch = optarg;
                        break;
@@ -86,23 +92,27 @@ apropos(int argc, char *argv[])
        search.flags = whatis ? MANSEARCH_WHATIS : 0;
 
        manpath_parse(&paths, conf_file, defpaths, auxpaths);
-       ch = mansearch(&search, &paths, argc, argv, &res, &sz);
+       ch = mansearch(&search, &paths, argc, argv, outkey, &res, &sz);
        manpath_free(&paths);
 
        if (0 == ch)
                goto usage;
 
        for (i = 0; i < sz; i++) {
-               printf("%s - %s\n", res[i].names, res[i].desc);
+               printf("%s - %s\n", res[i].names,
+                   NULL == outkey ? res[i].desc :
+                   NULL == res[i].output ? "" : res[i].output);
                free(res[i].file);
                free(res[i].names);
                free(res[i].desc);
+               free(res[i].output);
        }
 
        free(res);
        return(sz ? EXIT_SUCCESS : EXIT_FAILURE);
 usage:
        fprintf(stderr, "usage: %s [-C file] [-M path] [-m path] "
+                       "[-O outkey] "
                        "[-S arch] [-s section]%s ...\n", progname,
                        whatis ? " name" : "\n               expression");
        return(EXIT_FAILURE);
index 8154552..2c0795b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mansearch.c,v 1.2 2013/12/31 02:42:20 schwarze Exp $ */
+/*     $Id: mansearch.c,v 1.3 2013/12/31 03:41:09 schwarze Exp $ */
 /*
  * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -114,6 +114,8 @@ static      const struct type types[] = {
 };
 
 static char            *buildnames(sqlite3 *, sqlite3_stmt *, uint64_t);
+static char            *buildoutput(sqlite3 *, sqlite3_stmt *,
+                                uint64_t, uint64_t);
 static void            *hash_alloc(size_t, void *);
 static void             hash_free(void *, size_t, void *);
 static void            *hash_halloc(size_t, void *);
@@ -130,18 +132,20 @@ static    char            *sql_statement(const struct expr *,
 
 int
 mansearch(const struct mansearch *search,
-               const struct manpaths *paths, 
-               int argc, char *argv[], 
+               const struct manpaths *paths,
+               int argc, char *argv[],
+               const char *outkey,
                struct manpage **res, size_t *sz)
 {
-       int              fd, rc, c;
+       int              fd, rc, c, ibit;
        int64_t          id;
+       uint64_t         outbit;
        char             buf[PATH_MAX];
        char            *sql;
        struct manpage  *mpage;
        struct expr     *e, *ep;
        sqlite3         *db;
-       sqlite3_stmt    *s;
+       sqlite3_stmt    *s, *s2;
        struct match    *mp;
        struct ohash_info info;
        struct ohash     htab;
@@ -167,6 +171,16 @@ mansearch(const struct mansearch *search,
        if (NULL == (e = exprcomp(search, argc, argv)))
                goto out;
 
+       outbit = 0;
+       if (NULL != outkey) {
+               for (ibit = 0; types[ibit].bits; ibit++) {
+                       if (0 == strcasecmp(types[ibit].name, outkey)) {
+                               outbit = types[ibit].bits;
+                               break;
+                       }
+               }
+       }
+
        /*
         * Save a descriptor to the current working directory.
         * Since pathnames in the "paths" variable might be relative,
@@ -283,6 +297,12 @@ mansearch(const struct mansearch *search,
                if (SQLITE_OK != c)
                        fprintf(stderr, "%s\n", sqlite3_errmsg(db));
 
+               c = sqlite3_prepare_v2(db,
+                   "SELECT * FROM keys WHERE pageid=? AND bits & ?",
+                   -1, &s2, NULL);
+               if (SQLITE_OK != c)
+                       fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+
                for (mp = ohash_first(&htab, &idx);
                                NULL != mp;
                                mp = ohash_next(&htab, &idx)) {
@@ -300,6 +320,8 @@ mansearch(const struct mansearch *search,
                        mpage->desc = mp->desc;
                        mpage->form = mp->form;
                        mpage->names = buildnames(db, s, mp->id);
+                       mpage->output = outbit ?
+                           buildoutput(db, s2, mp->id, outbit) : NULL;
 
                        free(mp->file);
                        free(mp);
@@ -307,6 +329,7 @@ mansearch(const struct mansearch *search,
                }
 
                sqlite3_finalize(s);
+               sqlite3_finalize(s2);
                sqlite3_close(db);
                ohash_delete(&htab);
        }
@@ -357,6 +380,41 @@ buildnames(sqlite3 *db, sqlite3_stmt *s, uint64_t id)
        return(names);
 }
 
+static char *
+buildoutput(sqlite3 *db, sqlite3_stmt *s, uint64_t id, uint64_t outbit)
+{
+       char            *output, *newoutput;
+       const char      *oldoutput, *sep1, *data;
+       size_t           i;
+       int              c;
+
+       output = NULL;
+       i = 1;
+       SQL_BIND_INT64(db, s, i, id);
+       SQL_BIND_INT64(db, s, i, outbit);
+       while (SQLITE_ROW == (c = sqlite3_step(s))) {
+               if (NULL == output) {
+                       oldoutput = "";
+                       sep1 = "";
+               } else {
+                       oldoutput = output;
+                       sep1 = " # ";
+               }
+               data = sqlite3_column_text(s, 1);
+               if (-1 == asprintf(&newoutput, "%s%s%s",
+                   oldoutput, sep1, data)) {
+                       perror(0);
+                       exit((int)MANDOCLEVEL_SYSERR);
+               }
+               free(output);
+               output = newoutput;
+       }
+       if (SQLITE_DONE != c)
+               fprintf(stderr, "%s\n", sqlite3_errmsg(db));
+       sqlite3_reset(s);
+       return(output);
+}
+
 /*
  * Implement substring match as an application-defined SQL function.
  * Using the SQL LIKE or GLOB operators instead would be a bad idea
index bcb0696..9f7568f 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: mansearch.h,v 1.1 2013/12/31 00:40:19 schwarze Exp $ */
+/*     $Id: mansearch.h,v 1.2 2013/12/31 03:41:09 schwarze Exp $ */
 /*
  * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -64,6 +65,7 @@ struct        manpage {
        char            *file; /* to be prefixed by manpath */
        char            *names; /* a list of names with sections */
        char            *desc; /* description of manpage */
+       char            *output; /* user-defined additional output */
        int              form; /* 0 == catpage */
 };
 
@@ -79,6 +81,7 @@ int   mansearch(const struct mansearch *cfg, /* options */
                const struct manpaths *paths, /* manpaths */
                int argc, /* size of argv */
                char *argv[],  /* search terms */
+               const char *outkey, /* name of additional output key */
                struct manpage **res, /* results */
                size_t *ressz); /* results returned */