]> git.cameronkatri.com Git - mandoc.git/blobdiff - main.c
Complete the whatis.1 -> apropos.1 merge,
[mandoc.git] / main.c
diff --git a/main.c b/main.c
index 32ed232c741b0c3ca36d89751d0ec2b96bbcc6a9..b36bc899705bb39c41ca9825b8caf640a884486c 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/*     $Id: main.c,v 1.178 2014/08/10 23:54:41 schwarze Exp $ */
+/*     $Id: main.c,v 1.182 2014/08/21 00:32:15 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -32,6 +32,8 @@
 #include "main.h"
 #include "mdoc.h"
 #include "man.h"
+#include "manpath.h"
+#include "mansearch.h"
 
 #if !defined(__GNUC__) || (__GNUC__ < 2)
 # if !defined(lint)
 # endif
 #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
 
+enum   outmode {
+       OUTMODE_DEF = 0,
+       OUTMODE_FLN,
+       OUTMODE_LST,
+       OUTMODE_ALL,
+       OUTMODE_INT,
+       OUTMODE_ONE
+};
+
 typedef        void            (*out_mdoc)(void *, const struct mdoc *);
 typedef        void            (*out_man)(void *, const struct man *);
 typedef        void            (*out_free)(void *);
@@ -74,21 +85,34 @@ static      void              mmsg(enum mandocerr, enum mandoclevel,
 static void              parse(struct curparse *, int,
                                const char *, enum mandoclevel *);
 static int               toptions(struct curparse *, char *);
-static void              usage(void) __attribute__((noreturn));
+static void              usage(enum argmode) __attribute__((noreturn));
 static void              version(void) __attribute__((noreturn));
 static int               woptions(struct curparse *, char *);
 
+static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
 static const char       *progname;
 
 
 int
 main(int argc, char *argv[])
 {
-       int              c;
        struct curparse  curp;
-       int              options;
-       enum mandoclevel rc;
+       struct mansearch search;
+       struct manpaths  paths;
+       char            *conf_file, *defpaths, *auxpaths;
        char            *defos;
+#if HAVE_SQLITE3
+       struct manpage  *res;
+       char            **auxargv;
+       size_t           isec, i, sz;
+       int              prio, best_prio;
+       char             sec;
+#endif
+       enum mandoclevel rc;
+       enum outmode     outmode;
+       int              show_usage;
+       int              options;
+       int              c;
 
        progname = strrchr(argv[0], '/');
        if (progname == NULL)
@@ -96,15 +120,44 @@ main(int argc, char *argv[])
        else
                ++progname;
 
-       memset(&curp, 0, sizeof(struct curparse));
+       /* Search options. */
 
-       options = MPARSE_SO;
+       memset(&paths, 0, sizeof(struct manpaths));
+       conf_file = defpaths = auxpaths = NULL;
+
+       memset(&search, 0, sizeof(struct mansearch));
+       search.outkey = "Nd";
+
+       if (strcmp(progname, "man") == 0)
+               search.argmode = ARG_NAME;
+       else if (strncmp(progname, "apropos", 7) == 0)
+               search.argmode = ARG_EXPR;
+       else if (strncmp(progname, "whatis", 6) == 0)
+               search.argmode = ARG_WORD;
+       else
+               search.argmode = ARG_FILE;
+
+       /* Parser and formatter options. */
+
+       memset(&curp, 0, sizeof(struct curparse));
        curp.outtype = OUTT_ASCII;
        curp.wlevel  = MANDOCLEVEL_FATAL;
+       options = MPARSE_SO;
        defos = NULL;
 
-       while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
+       show_usage = 0;
+       outmode = OUTMODE_DEF;
+       while (-1 != (c = getopt(argc, argv, "aC:fI:ikM:m:O:S:s:T:VW:w"))) {
                switch (c) {
+               case 'a':
+                       outmode = OUTMODE_ALL;
+                       break;
+               case 'C':
+                       conf_file = optarg;
+                       break;
+               case 'f':
+                       search.argmode = ARG_WORD;
+                       break;
                case 'I':
                        if (strncmp(optarg, "os=", 3)) {
                                fprintf(stderr,
@@ -120,14 +173,29 @@ main(int argc, char *argv[])
                        }
                        defos = mandoc_strdup(optarg + 3);
                        break;
+               case 'i':
+                       outmode = OUTMODE_INT;
+                       break;
+               case 'k':
+                       search.argmode = ARG_EXPR;
+                       break;
+               case 'M':
+                       defpaths = optarg;
+                       break;
                case 'm':
-                       if ( ! moptions(&options, optarg))
-                               return((int)MANDOCLEVEL_BADARG);
+                       auxpaths = optarg;
                        break;
                case 'O':
+                       search.outkey = optarg;
                        (void)strlcat(curp.outopts, optarg, BUFSIZ);
                        (void)strlcat(curp.outopts, ",", BUFSIZ);
                        break;
+               case 'S':
+                       search.arch = optarg;
+                       break;
+               case 's':
+                       search.sec = optarg;
+                       break;
                case 'T':
                        if ( ! toptions(&curp, optarg))
                                return((int)MANDOCLEVEL_BADARG);
@@ -136,13 +204,120 @@ main(int argc, char *argv[])
                        if ( ! woptions(&curp, optarg))
                                return((int)MANDOCLEVEL_BADARG);
                        break;
+               case 'w':
+                       outmode = OUTMODE_FLN;
+                       break;
                case 'V':
                        version();
                        /* NOTREACHED */
                default:
-                       usage();
-                       /* NOTREACHED */
+                       show_usage = 1;
+                       break;
                }
+       }
+
+       if (show_usage)
+               usage(search.argmode);
+
+       if (outmode == OUTMODE_DEF) {
+               switch (search.argmode) {
+               case ARG_FILE:
+                       outmode = OUTMODE_ALL;
+                       break;
+               case ARG_NAME:
+                       outmode = OUTMODE_ONE;
+                       break;
+               default:
+                       outmode = OUTMODE_LST;
+                       break;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+#if HAVE_SQLITE3
+       auxargv = NULL;
+#endif
+
+       rc = MANDOCLEVEL_OK;
+
+       /* man(1), whatis(1), apropos(1) */
+
+       if (search.argmode != ARG_FILE) {
+#if HAVE_SQLITE3
+               if (argc == 0)
+                       usage(search.argmode);
+
+               /* Access the mandoc database. */
+
+               manpath_parse(&paths, conf_file, defpaths, auxpaths);
+               mansearch_setup(1);
+               if( ! mansearch(&search, &paths, argc, argv, &res, &sz))
+                       usage(search.argmode);
+               manpath_free(&paths);
+
+               /*
+                * For standard man(1) and -a output mode,
+                * prepare for copying filename pointers
+                * into the program parameter array.
+                */
+
+               if (outmode == OUTMODE_ONE) {
+                       argc = 1;
+                       argv[0] = res[0].file;
+                       argv[1] = NULL;
+                       best_prio = 10;
+               } else if (outmode == OUTMODE_ALL) {
+                       argc = (int)sz;
+                       argv = auxargv = mandoc_reallocarray(
+                           NULL, sz + 1, sizeof(char *));
+                       argv[argc] = NULL;
+               }
+
+               /* Iterate all matching manuals. */
+
+               for (i = 0; i < sz; i++) {
+                       if (outmode == OUTMODE_FLN)
+                               puts(res[i].file);
+                       else if (outmode == OUTMODE_LST)
+                               printf("%s - %s\n", res[i].names,
+                                   res[i].output == NULL ? "" :
+                                   res[i].output);
+                       else if (outmode == OUTMODE_ALL)
+                               argv[i] = res[i].file;
+                       else {
+                               /* Search for the best section. */
+                               isec = strcspn(res[i].file, "123456789");
+                               sec = res[i].file[isec];
+                               if ('\0' == sec)
+                                       continue;
+                               prio = sec_prios[sec - '1'];
+                               if (prio >= best_prio)
+                                       continue;
+                               best_prio = prio;
+                               argv[0] = res[i].file;
+                       }
+               }
+
+               /*
+                * For man(1), -a and -i output mode, fall through
+                * to the main mandoc(1) code iterating files
+                * and running the parsers on each of them.
+                */
+
+               if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
+                       goto out;
+#else
+               fputs("mandoc: database support not compiled in\n",
+                   stderr);
+               return((int)MANDOCLEVEL_BADARG);
+#endif
+       }
+
+       /* mandoc(1) */
+
+       if ( ! moptions(&options, auxpaths))
+               return((int)MANDOCLEVEL_BADARG);
 
        curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
 
@@ -152,11 +327,6 @@ main(int argc, char *argv[])
        if (OUTT_MAN == curp.outtype)
                mparse_keep(curp.mp);
 
-       argc -= optind;
-       argv += optind;
-
-       rc = MANDOCLEVEL_OK;
-
        if (NULL == *argv)
                parse(&curp, STDIN_FILENO, "<stdin>", &rc);
 
@@ -171,6 +341,16 @@ main(int argc, char *argv[])
                (*curp.outfree)(curp.outdata);
        if (curp.mp)
                mparse_free(curp.mp);
+
+#if HAVE_SQLITE3
+out:
+       if (search.argmode != ARG_FILE) {
+               mansearch_free(res, sz);
+               mansearch_setup(0);
+               free(auxargv);
+       }
+#endif
+
        free(defos);
 
        return((int)rc);
@@ -180,24 +360,35 @@ static void
 version(void)
 {
 
-       printf("%s %s\n", progname, VERSION);
+       printf("mandoc %s\n", VERSION);
        exit((int)MANDOCLEVEL_OK);
 }
 
 static void
-usage(void)
+usage(enum argmode argmode)
 {
 
-       fprintf(stderr, "usage: %s "
-                       "[-V] "
-                       "[-Ios=name] "
-                       "[-mformat] "
-                       "[-Ooption] "
-                       "[-Toutput] "
-                       "[-Wlevel]\n"
-                       "\t      [file ...]\n",
-                       progname);
-
+       switch (argmode) {
+       case ARG_FILE:
+               fputs("usage: mandoc [-V] [-Ios=name] [-mformat]"
+                   " [-Ooption] [-Toutput] [-Wlevel]\n"
+                   "\t      [file ...]\n", stderr);
+               break;
+       case ARG_NAME:
+               fputs("usage: man [-acfhkVw] [-C file] "
+                   "[-M path] [-m path] [-S arch] [-s section]\n"
+                   "\t   [section] name ...\n", stderr);
+               break;
+       case ARG_WORD:
+               fputs("usage: whatis [-V] [-C file] [-M path] [-m path] "
+                   "[-S arch] [-s section] name ...\n", stderr);
+               break;
+       case ARG_EXPR:
+               fputs("usage: apropos [-V] [-C file] [-M path] [-m path] "
+                   "[-O outkey] [-S arch]\n"
+                   "\t       [-s section] expression ...\n", stderr);
+               break;
+       }
        exit((int)MANDOCLEVEL_BADARG);
 }
 
@@ -318,7 +509,9 @@ static int
 moptions(int *options, char *arg)
 {
 
-       if (0 == strcmp(arg, "doc"))
+       if (arg == NULL)
+               /* nothing to do */;
+       else if (0 == strcmp(arg, "doc"))
                *options |= MPARSE_MDOC;
        else if (0 == strcmp(arg, "andoc"))
                /* nothing to do */;