371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* $Id: main.c,v 1.269 2016/07/12 05:18:38 kristaps Exp $ */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore/*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * Copyright (c) 2010-2012, 2014-2016 Ingo Schwarze <schwarze@openbsd.org>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * copyright notice and this permission notice appear in all copies.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore *
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "config.h"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <sys/types.h>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <sys/param.h> /* MACHINE */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <sys/wait.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <assert.h>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <ctype.h>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_ERR
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include <err.h>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <errno.h>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <fcntl.h>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include <glob.h>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_SANDBOX_INIT
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include <sandbox.h>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include <signal.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <stdio.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <stdint.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <stdlib.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <string.h>
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include <time.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include <unistd.h>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include "mandoc_aux.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "mandoc.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "roff.h"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "mdoc.h"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#include "man.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "tag.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "main.h"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#include "manconf.h"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#include "mansearch.h"
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#if !defined(__GNUC__) || (__GNUC__ < 2)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore# if !defined(lint)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore# define __attribute__(x)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore# endif
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovenum outmode {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov OUTMODE_DEF = 0,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov OUTMODE_FLN,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov OUTMODE_LST,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov OUTMODE_ALL,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov OUTMODE_INT,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov OUTMODE_ONE
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov};
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreenum outt {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_ASCII = 0, /* -Tascii */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_LOCALE, /* -Tlocale */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_UTF8, /* -Tutf8 */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_TREE, /* -Ttree */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_MAN, /* -Tman */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_HTML, /* -Thtml */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_LINT, /* -Tlint */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_PS, /* -Tps */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore OUTT_PDF /* -Tpdf */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestruct curparse {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct mparse *mp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore enum mandoclevel wlevel; /* ignore messages below this */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore int wstop; /* stop after a file with a warning */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov enum outt outtype; /* which output to use */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore void *outdata; /* data for output */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct manoutput *outopts; /* output options */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore};
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int fs_lookup(const struct manpaths *,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t ipath, const char *,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *, const char *,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct manpage **, size_t *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void fs_search(const struct mansearch *,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const struct manpaths *, int, char**,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct manpage **, size_t *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int koptions(int *, char *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#if HAVE_SQLITE3
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovint mandocdb(int, char**);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#endif
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int moptions(int *, char *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void mmsg(enum mandocerr, enum mandoclevel,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *, int, int, const char *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void parse(struct curparse *, int, const char *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void passthrough(const char *, int, int);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic pid_t spawn_pager(struct tag_files *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic int toptions(struct curparse *, char *);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void usage(enum argmode) __attribute__((noreturn));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic int woptions(struct curparse *, char *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic char help_arg[] = "help";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic char *help_argv[] = {help_arg, NULL};
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic enum mandoclevel rc;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreint
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoremain(int argc, char *argv[])
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct manconf conf;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore struct curparse curp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct mansearch search;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct tag_files *tag_files;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const char *progname;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *auxpaths;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore char *defos;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov unsigned char *uc;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct manpage *res, *resp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *conf_file, *defpaths;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const char *sec;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov size_t i, sz;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov int prio, best_prio;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov enum outmode outmode;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int fd;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int show_usage;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int options;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov int use_pager;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov int status, signum;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int c;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov pid_t pager_pid, tc_pgid, man_pgid, pid;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_PROGNAME
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov progname = getprogname();
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (argc < 1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov progname = mandoc_strdup("mandoc");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if ((progname = strrchr(argv[0], '/')) == NULL)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore progname = argv[0];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore ++progname;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov setprogname(progname);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#if HAVE_SQLITE3
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (strncmp(progname, "mandocdb", 8) == 0 ||
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov strcmp(progname, BINM_MAKEWHATIS) == 0)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return mandocdb(argc, argv);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_PLEDGE
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (pledge("stdio rpath tmppath tty proc exec flock", NULL) == -1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "pledge");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_SANDBOX_INIT
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov errx((int)MANDOCLEVEL_SYSERR, "sandbox_init");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#endif
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Search options. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov memset(&conf, 0, sizeof(conf));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov conf_file = defpaths = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov auxpaths = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov memset(&search, 0, sizeof(struct mansearch));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.outkey = "Nd";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (strcmp(progname, BINM_MAN) == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_NAME;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (strcmp(progname, BINM_APROPOS) == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_EXPR;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (strcmp(progname, BINM_WHATIS) == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_WORD;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (strncmp(progname, "help", 4) == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_NAME;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_FILE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Parser and formatter options. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov memset(&curp, 0, sizeof(struct curparse));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov curp.outtype = OUTT_LOCALE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov curp.wlevel = MANDOCLEVEL_BADARG;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp.outopts = &conf.output;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore defos = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov use_pager = 1;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_files = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov show_usage = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_DEF;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (-1 != (c = getopt(argc, argv,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "aC:cfhI:iK:klM:m:O:S:s:T:VW:w"))) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (c) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'a':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_ALL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'C':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov conf_file = optarg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'c':
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov use_pager = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'f':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_WORD;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'h':
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov conf.output.synopsisonly = 1;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov use_pager = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_ALL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'I':
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (strncmp(optarg, "os=", 3)) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("-I %s: Bad argument", optarg);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)MANDOCLEVEL_BADARG;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (defos) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("-I %s: Duplicate argument", optarg);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)MANDOCLEVEL_BADARG;
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore }
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore defos = mandoc_strdup(optarg + 3);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'i':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_INT;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'K':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! koptions(&options, optarg))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)MANDOCLEVEL_BADARG;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'k':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_EXPR;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'l':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.argmode = ARG_FILE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_ALL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'M':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov defpaths = optarg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'm':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov auxpaths = optarg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'O':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.outkey = optarg;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (optarg != NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov manconf_output(&conf.output,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov strsep(&optarg, ","));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'S':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.arch = optarg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 's':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.sec = optarg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'T':
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ( ! toptions(&curp, optarg))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)MANDOCLEVEL_BADARG;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'W':
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ( ! woptions(&curp, optarg))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)MANDOCLEVEL_BADARG;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 'w':
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_FLN;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov show_usage = 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (show_usage)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov usage(search.argmode);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Postprocess options. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (outmode == OUTMODE_DEF) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (search.argmode) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ARG_FILE:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_ALL;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov use_pager = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ARG_NAME:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_ONE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov default:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode = OUTMODE_LST;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (outmode == OUTMODE_FLN ||
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov outmode == OUTMODE_LST ||
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov !isatty(STDOUT_FILENO))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov use_pager = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_PLEDGE
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (!use_pager)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (pledge("stdio rpath flock", NULL) == -1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "pledge");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Parse arguments. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (argc > 0) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argc -= optind;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argv += optind;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov resp = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Quirks for help(1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and for a man(1) section argument without -s.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.argmode == ARG_NAME) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*progname == 'h') {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (argc == 0) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argv = help_argv;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argc = 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (argc > 1 &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ((uc = (unsigned char *)argv[0]) != NULL) &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ((isdigit(uc[0]) && (uc[1] == '\0' ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (isalpha(uc[1]) && uc[2] == '\0'))) ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (uc[0] == 'n' && uc[1] == '\0'))) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.sec = (char *)uc;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argv++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argc--;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.arch == NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.arch = getenv("MACHINE");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#ifdef MACHINE
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.arch == NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.arch = MACHINE;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#endif
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov rc = MANDOCLEVEL_OK;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* man(1), whatis(1), apropos(1) */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.argmode != ARG_FILE) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (argc == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov usage(search.argmode);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.argmode == ARG_NAME &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov outmode == OUTMODE_ONE)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov search.firstmatch = 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Access the mandoc database. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov manconf_parse(&conf, conf_file, defpaths, auxpaths);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#if HAVE_SQLITE3
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mansearch_setup(1);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ( ! mansearch(&search, &conf.manpath,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov argc, argv, &res, &sz))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov usage(search.argmode);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.argmode != ARG_NAME) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fputs("mandoc: database support not compiled in\n",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov stderr);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)MANDOCLEVEL_BADARG;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov sz = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#endif
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (sz == 0) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (search.argmode == ARG_NAME)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov fs_search(&search, &conf.manpath,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov argc, argv, &res, &sz);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("nothing appropriate");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (sz == 0) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov rc = MANDOCLEVEL_BADARG;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto out;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * For standard man(1) and -a output mode,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * prepare for copying filename pointers
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * into the program parameter array.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (outmode == OUTMODE_ONE) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argc = 1;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov best_prio = 20;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (outmode == OUTMODE_ALL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argc = (int)sz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Iterate all matching manuals. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov resp = res;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (i = 0; i < sz; i++) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (outmode == OUTMODE_FLN)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov puts(res[i].file);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (outmode == OUTMODE_LST)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov printf("%s - %s\n", res[i].names,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov res[i].output == NULL ? "" :
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov res[i].output);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (outmode == OUTMODE_ONE) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Search for the best section. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov sec = res[i].file;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov sec += strcspn(sec, "123456789");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (sec[0] == '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov prio = sec_prios[sec[0] - '1'];
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (sec[1] != '/')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov prio += 10;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (prio >= best_prio)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov best_prio = prio;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov resp = res + i;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * For man(1), -a and -i output mode, fall through
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * to the main mandoc(1) code iterating files
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * and running the parsers on each of them.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto out;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* mandoc(1) */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_PLEDGE
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (use_pager) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "pledge");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (pledge("stdio rpath", NULL) == -1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "pledge");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)MANDOCLEVEL_BADARG;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mchars_alloc();
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Conditionally start up the lookaside buffer before parsing.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (OUTT_MAN == curp.outtype)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore mparse_keep(curp.mp);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (argc < 1) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (use_pager)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_files = tag_init();
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov parse(&curp, STDIN_FILENO, "<stdin>");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (argc > 0) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (fd != -1) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (use_pager) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_files = tag_init();
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov use_pager = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (resp == NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov parse(&curp, fd, *argv);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (resp->form & FORM_SRC) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* For .so only; ignore failure. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov chdir(conf.manpath.paths[resp->ipath]);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov parse(&curp, fd, resp->file);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov passthrough(resp->file, fd,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov conf.output.synopsisonly);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (argc > 1 && curp.outtype <= OUTT_UTF8)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov terminal_sepline(curp.outdata);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else if (rc < MANDOCLEVEL_ERROR)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov rc = MANDOCLEVEL_ERROR;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MANDOCLEVEL_OK != rc && curp.wstop)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (resp != NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov resp++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argv++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (--argc)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mparse_reset(curp.mp);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (curp.outdata != NULL) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch (curp.outtype) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_HTML:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov html_free(curp.outdata);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_UTF8:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_LOCALE:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_ASCII:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov ascii_free(curp.outdata);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_PDF:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_PS:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov pspdf_free(curp.outdata);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mparse_free(curp.mp);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mchars_free();
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovout:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (search.argmode != ARG_FILE) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov manconf_free(&conf);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#if HAVE_SQLITE3
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mansearch_free(res, sz);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mansearch_setup(0);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#endif
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore free(defos);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * When using a pager, finish writing both temporary files,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * fork it, wait for the user to close it, and clean up.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (tag_files != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fclose(stdout);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_write();
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_pgid = getpgid(0);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_files->tcpgid = man_pgid == getpid() ?
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov getpgid(getppid()) : man_pgid;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov pager_pid = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov signum = SIGSTOP;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (;;) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Stop here until moved to the foreground. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tc_pgid = tcgetpgrp(STDIN_FILENO);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (tc_pgid != man_pgid) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (tc_pgid == pager_pid) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov (void)tcsetpgrp(STDIN_FILENO,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_pgid);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (signum == SIGTTIN)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov continue;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_files->tcpgid = tc_pgid;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov kill(0, signum);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov continue;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Once in the foreground, activate the pager. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (pager_pid) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov (void)tcsetpgrp(STDIN_FILENO, pager_pid);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov kill(pager_pid, SIGCONT);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov } else
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov pager_pid = spawn_pager(tag_files);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Wait for the pager to stop or exit. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while ((pid = waitpid(pager_pid, &status,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov WUNTRACED)) == -1 && errno == EINTR)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov continue;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (pid == -1) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warn("wait");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov rc = MANDOCLEVEL_SYSERR;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (!WIFSTOPPED(status))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov signum = WSTOPSIG(status);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_unlink();
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return (int)rc;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovusage(enum argmode argmode)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov switch (argmode) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ARG_FILE:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov fputs("usage: mandoc [-acfhkl] [-I os=name] "
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov "[-K encoding] [-mformat] [-O option]\n"
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov "\t [-T output] [-W level] [file ...]\n", stderr);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ARG_NAME:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fputs("usage: man [-acfhklw] [-C file] [-I os=name] "
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "[-K encoding] [-M path] [-m path]\n"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "\t [-O option=value] [-S subsection] [-s section] "
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "[-T output] [-W level]\n"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "\t [section] name ...\n", stderr);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ARG_WORD:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fputs("usage: whatis [-acfhklw] [-C file] "
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "[-M path] [-m path] [-O outkey] [-S arch]\n"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "\t [-s section] name ...\n", stderr);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case ARG_EXPR:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fputs("usage: apropos [-acfhklw] [-C file] "
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "[-M path] [-m path] [-O outkey] [-S arch]\n"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "\t [-s section] expression ...\n", stderr);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov exit((int)MANDOCLEVEL_BADARG);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovfs_lookup(const struct manpaths *paths, size_t ipath,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *sec, const char *arch, const char *name,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct manpage **res, size_t *ressz)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov glob_t globinfo;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov struct manpage *page;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *file;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int form, globres;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov form = FORM_SRC;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_asprintf(&file, "%s/man%s/%s.%s",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov paths->paths[ipath], sec, name, sec);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (access(file, R_OK) != -1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto found;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(file);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_asprintf(&file, "%s/cat%s/%s.0",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov paths->paths[ipath], sec, name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (access(file, R_OK) != -1) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov form = FORM_CAT;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto found;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(file);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (arch != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mandoc_asprintf(&file, "%s/man%s/%s/%s.%s",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov paths->paths[ipath], sec, arch, name, sec);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (access(file, R_OK) != -1)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto found;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(file);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mandoc_asprintf(&file, "%s/man%s/%s.[01-9]*",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov paths->paths[ipath], sec, name);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov globres = glob(file, 0, NULL, &globinfo);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (globres != 0 && globres != GLOB_NOMATCH)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warn("%s: glob", file);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov free(file);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (globres == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov file = mandoc_strdup(*globinfo.gl_pathv);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov globfree(&globinfo);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (globres != 0)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovfound:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#if HAVE_SQLITE3
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#endif
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page = *res + (*ressz - 1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page->file = file;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page->names = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page->output = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page->ipath = ipath;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page->bits = NAME_FILE & NAME_MASK;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov page->form = form;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic void
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovfs_search(const struct mansearch *cfg, const struct manpaths *paths,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int argc, char **argv, struct manpage **res, size_t *ressz)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *const sections[] =
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov {"1", "8", "6", "2", "3", "5", "7", "4", "9", "3p"};
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const size_t nsec = sizeof(sections)/sizeof(sections[0]);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov size_t ipath, isec, lastsz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov assert(cfg->argmode == ARG_NAME);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *res = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *ressz = lastsz = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (argc) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (ipath = 0; ipath < paths->sz; ipath++) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (cfg->sec != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (fs_lookup(paths, ipath, cfg->sec,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cfg->arch, *argv, res, ressz) &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cfg->firstmatch)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov return;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else for (isec = 0; isec < nsec; isec++)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (fs_lookup(paths, ipath, sections[isec],
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cfg->arch, *argv, res, ressz) &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cfg->firstmatch)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov return;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*ressz == lastsz)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("No entry for %s in the manual.", *argv);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov lastsz = *ressz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argv++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argc--;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovparse(struct curparse *curp, int fd, const char *file)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov enum mandoclevel rctmp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_man *man;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Begin by parsing the file itself. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore assert(file);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov assert(fd >= 0);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov rctmp = mparse_readfd(curp->mp, fd, file);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (fd != STDIN_FILENO)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov close(fd);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (rc < rctmp)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov rc = rctmp;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /*
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * With -Wstop and warnings or errors of at least the requested
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * level, do not produce output.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (rctmp != MANDOCLEVEL_OK && curp->wstop)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* If unset, allocate output dev now (if applicable). */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (curp->outdata == NULL) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (curp->outtype) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_HTML:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->outdata = html_alloc(curp->outopts);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_UTF8:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->outdata = utf8_alloc(curp->outopts);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_LOCALE:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->outdata = locale_alloc(curp->outopts);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_ASCII:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->outdata = ascii_alloc(curp->outopts);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_PDF:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->outdata = pdf_alloc(curp->outopts);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_PS:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov curp->outdata = ps_alloc(curp->outopts);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore default:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mparse_result(curp->mp, &man, NULL);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Execute the out device, if it exists. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man == NULL)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->macroset == MACROSET_MDOC) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov mdoc_validate(man);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (curp->outtype) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_HTML:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov html_mdoc(curp->outdata, man);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_TREE:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tree_mdoc(curp->outdata, man);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_MAN:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_mdoc(curp->outdata, man);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_PDF:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_ASCII:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_UTF8:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_LOCALE:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case OUTT_PS:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov terminal_mdoc(curp->outdata, man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (man->macroset == MACROSET_MAN) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_validate(man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch (curp->outtype) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_HTML:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov html_man(curp->outdata, man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_TREE:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tree_man(curp->outdata, man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_MAN:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov man_man(curp->outdata, man);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_PDF:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_ASCII:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_UTF8:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_LOCALE:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case OUTT_PS:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov terminal_man(curp->outdata, man);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore default:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovpassthrough(const char *file, int fd, int synopsis_only)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char synr[] = "SYNOPSIS";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov FILE *stream;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *syscall;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov char *line, *cp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov size_t linesz;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int print;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov line = NULL;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov linesz = 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ((stream = fdopen(fd, "r")) == NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov close(fd);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov syscall = "fdopen";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto fail;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov print = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (getline(&line, &linesz, stream) != -1) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov cp = line;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (synopsis_only) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (print) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ( ! isspace((unsigned char)*cp))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto done;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (isspace((unsigned char)*cp))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov cp++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (strcmp(cp, synb) == 0 ||
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov strcmp(cp, synr) == 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov print = 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov continue;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (fputs(cp, stdout)) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov fclose(stream);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov syscall = "fputs";
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov goto fail;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (ferror(stream)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fclose(stream);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov syscall = "getline";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov goto fail;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovdone:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(line);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fclose(stream);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovfail:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov free(line);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warn("%s: SYSERR: %s", file, syscall);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (rc < MANDOCLEVEL_SYSERR)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov rc = MANDOCLEVEL_SYSERR;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovkoptions(int *options, char *arg)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! strcmp(arg, "utf-8")) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *options |= MPARSE_UTF8;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *options &= ~MPARSE_LATIN1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if ( ! strcmp(arg, "iso-8859-1")) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *options |= MPARSE_LATIN1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *options &= ~MPARSE_UTF8;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if ( ! strcmp(arg, "us-ascii")) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("-K %s: Bad argument", arg);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic int
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovmoptions(int *options, char *arg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (arg == NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* nothing to do */;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (0 == strcmp(arg, "doc"))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *options |= MPARSE_MDOC;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "andoc"))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* nothing to do */;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "an"))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *options |= MPARSE_MAN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("-m %s: Bad argument", arg);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic int
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoretoptions(struct curparse *curp, char *arg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (0 == strcmp(arg, "ascii"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_ASCII;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "lint")) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_LINT;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->wlevel = MANDOCLEVEL_WARNING;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore } else if (0 == strcmp(arg, "tree"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_TREE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "man"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_MAN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "html"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_HTML;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "utf8"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_UTF8;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "locale"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_LOCALE;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "xhtml"))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov curp->outtype = OUTT_HTML;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "ps"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_PS;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else if (0 == strcmp(arg, "pdf"))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->outtype = OUTT_PDF;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore else {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("-T %s: Bad argument", arg);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic int
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorewoptions(struct curparse *curp, char *arg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore char *v, *o;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *toks[7];
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore toks[0] = "stop";
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore toks[1] = "all";
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore toks[2] = "warning";
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore toks[3] = "error";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov toks[4] = "unsupp";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov toks[5] = "fatal";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov toks[6] = NULL;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore while (*arg) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore o = arg;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (getsubopt(&arg, UNCONST(toks), &v)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 0:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->wstop = 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 1:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 2:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->wlevel = MANDOCLEVEL_WARNING;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 3:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore curp->wlevel = MANDOCLEVEL_ERROR;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 4:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov curp->wlevel = MANDOCLEVEL_UNSUPP;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov case 5:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov curp->wlevel = MANDOCLEVEL_BADARG;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore break;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov warnx("-W %s: Bad argument", o);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore }
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return 1;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovmmsg(enum mandocerr t, enum mandoclevel lvl,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const char *file, int line, int col, const char *msg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore{
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *mparse_msg;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov fprintf(stderr, "%s: %s:", getprogname(),
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov file == NULL ? "<stdin>" : file);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (line)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fprintf(stderr, "%d:%d:", line, col + 1);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fprintf(stderr, " %s", mparse_strlevel(lvl));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (NULL != (mparse_msg = mparse_strerror(t)))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov fprintf(stderr, ": %s", mparse_msg);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (msg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore fprintf(stderr, ": %s", msg);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore fputc('\n', stderr);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore}
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic pid_t
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovspawn_pager(struct tag_files *tag_files)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov{
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const struct timespec timeout = { 0, 100000000 }; /* 0.1s */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov#define MAX_PAGER_ARGS 16
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *argv[MAX_PAGER_ARGS];
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *pager;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov char *cp;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov size_t cmdlen;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int argc;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov pid_t pager_pid;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov pager = getenv("MANPAGER");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (pager == NULL || *pager == '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov pager = getenv("PAGER");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (pager == NULL || *pager == '\0')
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov pager = "more -s";
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = mandoc_strdup(pager);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /*
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Parse the pager command into words.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Intentionally do not do anything fancy here.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argc = 0;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (argc + 4 < MAX_PAGER_ARGS) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argv[argc++] = cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp = strchr(cp, ' ');
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (cp == NULL)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov *cp++ = '\0';
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (*cp == ' ')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov cp++;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*cp == '\0')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov break;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* For less(1), use the tag file. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if ((cmdlen = strlen(argv[0])) >= 4) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov cp = argv[0] + cmdlen - 4;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (strcmp(cp, "less") == 0) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov argv[argc++] = mandoc_strdup("-T");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov argv[argc++] = tag_files->tfn;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov argv[argc++] = tag_files->ofn;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov argv[argc] = NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch (pager_pid = fork()) {
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case -1:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "fork");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov case 0:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov break;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov default:
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov (void)setpgid(pager_pid, 0);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov (void)tcsetpgrp(STDIN_FILENO, pager_pid);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#if HAVE_PLEDGE
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (pledge("stdio rpath tmppath tty proc", NULL) == -1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "pledge");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov#endif
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov tag_files->pager_pid = pager_pid;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov return pager_pid;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov }
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* The child process becomes the pager. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "pager stdout");
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov close(tag_files->ofd);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov close(tag_files->tfd);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Do not start the pager before controlling the terminal. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov while (tcgetpgrp(STDIN_FILENO) != getpid())
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov nanosleep(&timeout, NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov execvp(argv[0], argv);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov}