-/* $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>
#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 *);
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)
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,
}
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);
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);
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);
(*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);
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);
}
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 */;