![]() ![]() | ![]() |
version 1.177, 2014/06/21 22:24:01 | version 1.208, 2014/12/18 21:11:46 | ||
---|---|---|---|
|
|
||
/* $Id$ */ | /* $Id$ */ | ||
/* | /* | ||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> | * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> | ||
* Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org> | * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org> | ||
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> | * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> | ||
* | * | ||
|
|
||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | */ | ||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | #include "config.h" | ||
#endif | |||
#include <sys/types.h> | |||
#include <assert.h> | #include <assert.h> | ||
#include <ctype.h> | |||
#include <errno.h> | |||
#include <fcntl.h> | |||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdint.h> | #include <stdint.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
|
|
||
#include "main.h" | #include "main.h" | ||
#include "mdoc.h" | #include "mdoc.h" | ||
#include "man.h" | #include "man.h" | ||
#include "manpath.h" | |||
#include "mansearch.h" | |||
#if !defined(__GNUC__) || (__GNUC__ < 2) | #if !defined(__GNUC__) || (__GNUC__ < 2) | ||
# if !defined(lint) | # if !defined(lint) | ||
|
|
||
# endif | # endif | ||
#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ | #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_mdoc)(void *, const struct mdoc *); | ||
typedef void (*out_man)(void *, const struct man *); | typedef void (*out_man)(void *, const struct man *); | ||
typedef void (*out_free)(void *); | typedef void (*out_free)(void *); | ||
|
|
||
OUTT_TREE, /* -Ttree */ | OUTT_TREE, /* -Ttree */ | ||
OUTT_MAN, /* -Tman */ | OUTT_MAN, /* -Tman */ | ||
OUTT_HTML, /* -Thtml */ | OUTT_HTML, /* -Thtml */ | ||
OUTT_XHTML, /* -Txhtml */ | |||
OUTT_LINT, /* -Tlint */ | OUTT_LINT, /* -Tlint */ | ||
OUTT_PS, /* -Tps */ | OUTT_PS, /* -Tps */ | ||
OUTT_PDF /* -Tpdf */ | OUTT_PDF /* -Tpdf */ | ||
|
|
||
struct curparse { | struct curparse { | ||
struct mparse *mp; | struct mparse *mp; | ||
struct mchars *mchars; /* character table */ | |||
enum mandoclevel wlevel; /* ignore messages below this */ | enum mandoclevel wlevel; /* ignore messages below this */ | ||
int wstop; /* stop after a file with a warning */ | int wstop; /* stop after a file with a warning */ | ||
enum outt outtype; /* which output to use */ | enum outt outtype; /* which output to use */ | ||
|
|
||
char outopts[BUFSIZ]; /* buf of output opts */ | char outopts[BUFSIZ]; /* buf of output opts */ | ||
}; | }; | ||
static int koptions(int *, char *); | |||
#if HAVE_SQLITE3 | |||
int mandocdb(int, char**); | |||
#endif | |||
static int moptions(int *, char *); | static int moptions(int *, char *); | ||
static void mmsg(enum mandocerr, enum mandoclevel, | static void mmsg(enum mandocerr, enum mandoclevel, | ||
const char *, int, int, const char *); | const char *, int, int, const char *); | ||
static void parse(struct curparse *, int, | static void parse(struct curparse *, int, | ||
const char *, enum mandoclevel *); | const char *, enum mandoclevel *); | ||
#if HAVE_SQLITE3 | |||
static enum mandoclevel passthrough(const char *, int, int); | |||
#endif | |||
static void spawn_pager(void); | |||
static int toptions(struct curparse *, char *); | 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 void version(void) __attribute__((noreturn)); | ||
static int woptions(struct curparse *, char *); | static int woptions(struct curparse *, char *); | ||
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9}; | |||
static char help_arg[] = "help"; | |||
static char *help_argv[] = {help_arg, NULL}; | |||
static const char *progname; | static const char *progname; | ||
int | int | ||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||
{ | { | ||
int c; | |||
struct curparse curp; | struct curparse curp; | ||
int options; | struct mansearch search; | ||
enum mandoclevel rc; | struct manpaths paths; | ||
char *auxpaths; | |||
char *defos; | char *defos; | ||
unsigned char *uc; | |||
#if HAVE_SQLITE3 | |||
struct manpage *res, *resp; | |||
char *conf_file, *defpaths; | |||
size_t isec, i, sz; | |||
int prio, best_prio, synopsis_only; | |||
char sec; | |||
#endif | |||
enum mandoclevel rc; | |||
enum outmode outmode; | |||
int fd; | |||
int show_usage; | |||
int use_pager; | |||
int options; | |||
int c; | |||
progname = strrchr(argv[0], '/'); | progname = strrchr(argv[0], '/'); | ||
if (progname == NULL) | if (progname == NULL) | ||
|
|
||
else | else | ||
++progname; | ++progname; | ||
memset(&curp, 0, sizeof(struct curparse)); | #if HAVE_SQLITE3 | ||
if (strcmp(progname, BINM_MAKEWHATIS) == 0) | |||
return(mandocdb(argc, argv)); | |||
#endif | |||
options = MPARSE_SO; | /* Search options. */ | ||
curp.outtype = OUTT_ASCII; | |||
memset(&paths, 0, sizeof(struct manpaths)); | |||
#if HAVE_SQLITE3 | |||
conf_file = defpaths = NULL; | |||
#endif | |||
auxpaths = NULL; | |||
memset(&search, 0, sizeof(struct mansearch)); | |||
search.outkey = "Nd"; | |||
if (strcmp(progname, BINM_MAN) == 0) | |||
search.argmode = ARG_NAME; | |||
else if (strcmp(progname, BINM_APROPOS) == 0) | |||
search.argmode = ARG_EXPR; | |||
else if (strcmp(progname, BINM_WHATIS) == 0) | |||
search.argmode = ARG_WORD; | |||
else if (strncmp(progname, "help", 4) == 0) | |||
search.argmode = ARG_NAME; | |||
else | |||
search.argmode = ARG_FILE; | |||
/* Parser and formatter options. */ | |||
memset(&curp, 0, sizeof(struct curparse)); | |||
curp.outtype = OUTT_LOCALE; | |||
curp.wlevel = MANDOCLEVEL_FATAL; | curp.wlevel = MANDOCLEVEL_FATAL; | ||
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1; | |||
defos = NULL; | defos = NULL; | ||
while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:"))) | use_pager = 1; | ||
show_usage = 0; | |||
#if HAVE_SQLITE3 | |||
synopsis_only = 0; | |||
#endif | |||
outmode = OUTMODE_DEF; | |||
while (-1 != (c = getopt(argc, argv, | |||
"aC:cfhI:iK:klM:m:O:S:s:T:VW:w"))) { | |||
switch (c) { | switch (c) { | ||
case 'a': | |||
outmode = OUTMODE_ALL; | |||
break; | |||
case 'C': | |||
#if HAVE_SQLITE3 | |||
conf_file = optarg; | |||
#endif | |||
break; | |||
case 'c': | |||
use_pager = 0; | |||
break; | |||
case 'f': | |||
search.argmode = ARG_WORD; | |||
break; | |||
case 'h': | |||
(void)strlcat(curp.outopts, "synopsis,", BUFSIZ); | |||
#if HAVE_SQLITE3 | |||
synopsis_only = 1; | |||
#endif | |||
use_pager = 0; | |||
outmode = OUTMODE_ALL; | |||
break; | |||
case 'I': | case 'I': | ||
if (strncmp(optarg, "os=", 3)) { | if (strncmp(optarg, "os=", 3)) { | ||
fprintf(stderr, | fprintf(stderr, | ||
|
|
||
} | } | ||
defos = mandoc_strdup(optarg + 3); | defos = mandoc_strdup(optarg + 3); | ||
break; | break; | ||
case 'm': | case 'i': | ||
if ( ! moptions(&options, optarg)) | outmode = OUTMODE_INT; | ||
break; | |||
case 'K': | |||
if ( ! koptions(&options, optarg)) | |||
return((int)MANDOCLEVEL_BADARG); | return((int)MANDOCLEVEL_BADARG); | ||
break; | break; | ||
case 'k': | |||
search.argmode = ARG_EXPR; | |||
break; | |||
case 'l': | |||
search.argmode = ARG_FILE; | |||
outmode = OUTMODE_ALL; | |||
break; | |||
case 'M': | |||
#if HAVE_SQLITE3 | |||
defpaths = optarg; | |||
#endif | |||
break; | |||
case 'm': | |||
auxpaths = optarg; | |||
break; | |||
case 'O': | case 'O': | ||
search.outkey = optarg; | |||
(void)strlcat(curp.outopts, optarg, BUFSIZ); | (void)strlcat(curp.outopts, optarg, BUFSIZ); | ||
(void)strlcat(curp.outopts, ",", BUFSIZ); | (void)strlcat(curp.outopts, ",", BUFSIZ); | ||
break; | break; | ||
case 'S': | |||
search.arch = optarg; | |||
break; | |||
case 's': | |||
search.sec = optarg; | |||
break; | |||
case 'T': | case 'T': | ||
if ( ! toptions(&curp, optarg)) | if ( ! toptions(&curp, optarg)) | ||
return((int)MANDOCLEVEL_BADARG); | return((int)MANDOCLEVEL_BADARG); | ||
|
|
||
if ( ! woptions(&curp, optarg)) | if ( ! woptions(&curp, optarg)) | ||
return((int)MANDOCLEVEL_BADARG); | return((int)MANDOCLEVEL_BADARG); | ||
break; | break; | ||
case 'w': | |||
outmode = OUTMODE_FLN; | |||
break; | |||
case 'V': | case 'V': | ||
version(); | version(); | ||
/* NOTREACHED */ | /* NOTREACHED */ | ||
default: | default: | ||
usage(); | show_usage = 1; | ||
/* NOTREACHED */ | break; | ||
} | } | ||
} | |||
curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos); | if (show_usage) | ||
usage(search.argmode); | |||
/* Postprocess options. */ | |||
if (outmode == OUTMODE_DEF) { | |||
switch (search.argmode) { | |||
case ARG_FILE: | |||
outmode = OUTMODE_ALL; | |||
use_pager = 0; | |||
break; | |||
case ARG_NAME: | |||
outmode = OUTMODE_ONE; | |||
break; | |||
default: | |||
outmode = OUTMODE_LST; | |||
break; | |||
} | |||
} | |||
/* Parse arguments. */ | |||
argc -= optind; | |||
argv += optind; | |||
#if HAVE_SQLITE3 | |||
resp = NULL; | |||
#endif | |||
/* | /* | ||
* Quirks for help(1) | |||
* and for a man(1) section argument without -s. | |||
*/ | |||
if (search.argmode == ARG_NAME) { | |||
if (*progname == 'h') { | |||
if (argc == 0) { | |||
argv = help_argv; | |||
argc = 1; | |||
} | |||
} else if (((uc = argv[0]) != NULL) && | |||
((isdigit(uc[0]) && (uc[1] == '\0' || | |||
(isalpha(uc[1]) && uc[2] == '\0'))) || | |||
(uc[0] == 'n' && uc[1] == '\0'))) { | |||
search.sec = uc; | |||
argv++; | |||
argc--; | |||
} | |||
} | |||
rc = MANDOCLEVEL_OK; | |||
/* man(1), whatis(1), apropos(1) */ | |||
if (search.argmode != ARG_FILE) { | |||
#if HAVE_SQLITE3 | |||
if (argc == 0) | |||
usage(search.argmode); | |||
if (search.argmode == ARG_NAME && | |||
outmode == OUTMODE_ONE) | |||
search.firstmatch = 1; | |||
/* 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); | |||
resp = res; | |||
if (sz == 0) { | |||
if (search.argmode == ARG_NAME) | |||
fprintf(stderr, "%s: No entry for %s " | |||
"in the manual.\n", progname, argv[0]); | |||
rc = MANDOCLEVEL_BADARG; | |||
goto out; | |||
} | |||
/* | |||
* For standard man(1) and -a output mode, | |||
* prepare for copying filename pointers | |||
* into the program parameter array. | |||
*/ | |||
if (outmode == OUTMODE_ONE) { | |||
argc = 1; | |||
best_prio = 10; | |||
} else if (outmode == OUTMODE_ALL) | |||
argc = (int)sz; | |||
/* 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_ONE) { | |||
/* 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; | |||
resp = res + i; | |||
} | |||
} | |||
/* | |||
* 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); | |||
if (use_pager && isatty(STDOUT_FILENO)) | |||
spawn_pager(); | |||
curp.mchars = mchars_alloc(); | |||
curp.mp = mparse_alloc(options, curp.wlevel, mmsg, | |||
curp.mchars, defos); | |||
/* | |||
* Conditionally start up the lookaside buffer before parsing. | * Conditionally start up the lookaside buffer before parsing. | ||
*/ | */ | ||
if (OUTT_MAN == curp.outtype) | if (OUTT_MAN == curp.outtype) | ||
mparse_keep(curp.mp); | mparse_keep(curp.mp); | ||
argc -= optind; | if (argc == 0) | ||
argv += optind; | parse(&curp, STDIN_FILENO, "<stdin>", &rc); | ||
rc = MANDOCLEVEL_OK; | while (argc) { | ||
#if HAVE_SQLITE3 | |||
if (resp != NULL) { | |||
rc = mparse_open(curp.mp, &fd, resp->file); | |||
if (fd == -1) | |||
/* nothing */; | |||
else if (resp->form & FORM_SRC) { | |||
/* For .so only; ignore failure. */ | |||
chdir(paths.paths[resp->ipath]); | |||
parse(&curp, fd, resp->file, &rc); | |||
} else | |||
rc = passthrough(resp->file, fd, | |||
synopsis_only); | |||
resp++; | |||
} else | |||
#endif | |||
{ | |||
rc = mparse_open(curp.mp, &fd, *argv++); | |||
if (fd != -1) | |||
parse(&curp, fd, argv[-1], &rc); | |||
} | |||
if (NULL == *argv) | if (mparse_wait(curp.mp) != MANDOCLEVEL_OK) | ||
parse(&curp, STDIN_FILENO, "<stdin>", &rc); | rc = MANDOCLEVEL_SYSERR; | ||
while (*argv) { | |||
parse(&curp, -1, *argv, &rc); | |||
if (MANDOCLEVEL_OK != rc && curp.wstop) | if (MANDOCLEVEL_OK != rc && curp.wstop) | ||
break; | break; | ||
++argv; | argc--; | ||
} | } | ||
if (curp.outfree) | if (curp.outfree) | ||
(*curp.outfree)(curp.outdata); | (*curp.outfree)(curp.outdata); | ||
if (curp.mp) | mparse_free(curp.mp); | ||
mparse_free(curp.mp); | mchars_free(curp.mchars); | ||
#if HAVE_SQLITE3 | |||
out: | |||
if (search.argmode != ARG_FILE) { | |||
manpath_free(&paths); | |||
mansearch_free(res, sz); | |||
mansearch_setup(0); | |||
} | |||
#endif | |||
free(defos); | free(defos); | ||
return((int)rc); | return((int)rc); | ||
|
|
||
version(void) | version(void) | ||
{ | { | ||
printf("%s %s\n", progname, VERSION); | printf("mandoc %s\n", VERSION); | ||
exit((int)MANDOCLEVEL_OK); | exit((int)MANDOCLEVEL_OK); | ||
} | } | ||
static void | static void | ||
usage(void) | usage(enum argmode argmode) | ||
{ | { | ||
fprintf(stderr, "usage: %s " | switch (argmode) { | ||
"[-V] " | case ARG_FILE: | ||
"[-Ios=name] " | fputs("usage: mandoc [-acfhklV] [-Ios=name] " | ||
"[-mformat] " | "[-Kencoding] [-mformat] [-Ooption]\n" | ||
"[-Ooption] " | "\t [-Toutput] [-Wlevel] [file ...]\n", stderr); | ||
"[-Toutput] " | break; | ||
"[-Wlevel]\n" | case ARG_NAME: | ||
"\t [file ...]\n", | fputs("usage: man [-acfhklVw] [-C file] [-I os=name] " | ||
progname); | "[-K encoding] [-M path] [-m path]\n" | ||
"\t [-O option=value] [-S subsection] [-s section] " | |||
"[-T output] [-W level]\n" | |||
"\t [section] name ...\n", stderr); | |||
break; | |||
case ARG_WORD: | |||
fputs("usage: whatis [-acfhklVw] [-C file] " | |||
"[-M path] [-m path] [-O outkey] [-S arch]\n" | |||
"\t [-s section] name ...\n", stderr); | |||
break; | |||
case ARG_EXPR: | |||
fputs("usage: apropos [-acfhklVw] [-C file] " | |||
"[-M path] [-m path] [-O outkey] [-S arch]\n" | |||
"\t [-s section] expression ...\n", stderr); | |||
break; | |||
} | |||
exit((int)MANDOCLEVEL_BADARG); | exit((int)MANDOCLEVEL_BADARG); | ||
} | } | ||
|
|
||
if ( ! (curp->outman && curp->outmdoc)) { | if ( ! (curp->outman && curp->outmdoc)) { | ||
switch (curp->outtype) { | switch (curp->outtype) { | ||
case OUTT_XHTML: | |||
curp->outdata = xhtml_alloc(curp->outopts); | |||
curp->outfree = html_free; | |||
break; | |||
case OUTT_HTML: | case OUTT_HTML: | ||
curp->outdata = html_alloc(curp->outopts); | curp->outdata = html_alloc(curp->mchars, | ||
curp->outopts); | |||
curp->outfree = html_free; | curp->outfree = html_free; | ||
break; | break; | ||
case OUTT_UTF8: | case OUTT_UTF8: | ||
curp->outdata = utf8_alloc(curp->outopts); | curp->outdata = utf8_alloc(curp->mchars, | ||
curp->outopts); | |||
curp->outfree = ascii_free; | curp->outfree = ascii_free; | ||
break; | break; | ||
case OUTT_LOCALE: | case OUTT_LOCALE: | ||
curp->outdata = locale_alloc(curp->outopts); | curp->outdata = locale_alloc(curp->mchars, | ||
curp->outopts); | |||
curp->outfree = ascii_free; | curp->outfree = ascii_free; | ||
break; | break; | ||
case OUTT_ASCII: | case OUTT_ASCII: | ||
curp->outdata = ascii_alloc(curp->outopts); | curp->outdata = ascii_alloc(curp->mchars, | ||
curp->outopts); | |||
curp->outfree = ascii_free; | curp->outfree = ascii_free; | ||
break; | break; | ||
case OUTT_PDF: | case OUTT_PDF: | ||
curp->outdata = pdf_alloc(curp->outopts); | curp->outdata = pdf_alloc(curp->mchars, | ||
curp->outopts); | |||
curp->outfree = pspdf_free; | curp->outfree = pspdf_free; | ||
break; | break; | ||
case OUTT_PS: | case OUTT_PS: | ||
curp->outdata = ps_alloc(curp->outopts); | curp->outdata = ps_alloc(curp->mchars, | ||
curp->outopts); | |||
curp->outfree = pspdf_free; | curp->outfree = pspdf_free; | ||
break; | break; | ||
default: | default: | ||
|
|
||
switch (curp->outtype) { | switch (curp->outtype) { | ||
case OUTT_HTML: | case OUTT_HTML: | ||
/* FALLTHROUGH */ | |||
case OUTT_XHTML: | |||
curp->outman = html_man; | curp->outman = html_man; | ||
curp->outmdoc = html_mdoc; | curp->outmdoc = html_mdoc; | ||
break; | break; | ||
|
|
||
*level = rc; | *level = rc; | ||
} | } | ||
#if HAVE_SQLITE3 | |||
static enum mandoclevel | |||
passthrough(const char *file, int fd, int synopsis_only) | |||
{ | |||
const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"; | |||
const char synr[] = "SYNOPSIS"; | |||
FILE *stream; | |||
const char *syscall; | |||
char *line; | |||
size_t len, off; | |||
ssize_t nw; | |||
int print; | |||
if ((stream = fdopen(fd, "r")) == NULL) { | |||
close(fd); | |||
syscall = "fdopen"; | |||
goto fail; | |||
} | |||
print = 0; | |||
while ((line = fgetln(stream, &len)) != NULL) { | |||
if (synopsis_only) { | |||
if (print) { | |||
if ( ! isspace((unsigned char)*line)) | |||
goto done; | |||
while (len && | |||
isspace((unsigned char)*line)) { | |||
line++; | |||
len--; | |||
} | |||
} else { | |||
if ((len == sizeof(synb) && | |||
! strncmp(line, synb, len - 1)) || | |||
(len == sizeof(synr) && | |||
! strncmp(line, synr, len - 1))) | |||
print = 1; | |||
continue; | |||
} | |||
} | |||
for (off = 0; off < len; off += nw) | |||
if ((nw = write(STDOUT_FILENO, line + off, | |||
len - off)) == -1 || nw == 0) { | |||
fclose(stream); | |||
syscall = "write"; | |||
goto fail; | |||
} | |||
} | |||
if (ferror(stream)) { | |||
fclose(stream); | |||
syscall = "fgetln"; | |||
goto fail; | |||
} | |||
done: | |||
fclose(stream); | |||
return(MANDOCLEVEL_OK); | |||
fail: | |||
fprintf(stderr, "%s: %s: SYSERR: %s: %s", | |||
progname, file, syscall, strerror(errno)); | |||
return(MANDOCLEVEL_SYSERR); | |||
} | |||
#endif | |||
static int | static int | ||
koptions(int *options, char *arg) | |||
{ | |||
if ( ! strcmp(arg, "utf-8")) { | |||
*options |= MPARSE_UTF8; | |||
*options &= ~MPARSE_LATIN1; | |||
} else if ( ! strcmp(arg, "iso-8859-1")) { | |||
*options |= MPARSE_LATIN1; | |||
*options &= ~MPARSE_UTF8; | |||
} else if ( ! strcmp(arg, "us-ascii")) { | |||
*options &= ~(MPARSE_UTF8 | MPARSE_LATIN1); | |||
} else { | |||
fprintf(stderr, "%s: -K%s: Bad argument\n", | |||
progname, arg); | |||
return(0); | |||
} | |||
return(1); | |||
} | |||
static int | |||
moptions(int *options, char *arg) | 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; | *options |= MPARSE_MDOC; | ||
else if (0 == strcmp(arg, "andoc")) | else if (0 == strcmp(arg, "andoc")) | ||
/* nothing to do */; | /* nothing to do */; | ||
|
|
||
else if (0 == strcmp(arg, "locale")) | else if (0 == strcmp(arg, "locale")) | ||
curp->outtype = OUTT_LOCALE; | curp->outtype = OUTT_LOCALE; | ||
else if (0 == strcmp(arg, "xhtml")) | else if (0 == strcmp(arg, "xhtml")) | ||
curp->outtype = OUTT_XHTML; | curp->outtype = OUTT_HTML; | ||
else if (0 == strcmp(arg, "ps")) | else if (0 == strcmp(arg, "ps")) | ||
curp->outtype = OUTT_PS; | curp->outtype = OUTT_PS; | ||
else if (0 == strcmp(arg, "pdf")) | else if (0 == strcmp(arg, "pdf")) | ||
|
|
||
fprintf(stderr, ": %s", msg); | fprintf(stderr, ": %s", msg); | ||
fputc('\n', stderr); | fputc('\n', stderr); | ||
} | |||
static void | |||
spawn_pager(void) | |||
{ | |||
#define MAX_PAGER_ARGS 16 | |||
char *argv[MAX_PAGER_ARGS]; | |||
const char *pager; | |||
char *cp; | |||
int fildes[2]; | |||
int argc; | |||
if (pipe(fildes) == -1) { | |||
fprintf(stderr, "%s: pipe: %s\n", | |||
progname, strerror(errno)); | |||
return; | |||
} | |||
switch (fork()) { | |||
case -1: | |||
fprintf(stderr, "%s: fork: %s\n", | |||
progname, strerror(errno)); | |||
exit((int)MANDOCLEVEL_SYSERR); | |||
case 0: | |||
close(fildes[0]); | |||
if (dup2(fildes[1], STDOUT_FILENO) == -1) { | |||
fprintf(stderr, "%s: dup output: %s\n", | |||
progname, strerror(errno)); | |||
exit((int)MANDOCLEVEL_SYSERR); | |||
} | |||
return; | |||
default: | |||
break; | |||
} | |||
/* The original process becomes the pager. */ | |||
close(fildes[1]); | |||
if (dup2(fildes[0], STDIN_FILENO) == -1) { | |||
fprintf(stderr, "%s: dup input: %s\n", | |||
progname, strerror(errno)); | |||
exit((int)MANDOCLEVEL_SYSERR); | |||
} | |||
pager = getenv("MANPAGER"); | |||
if (pager == NULL || *pager == '\0') | |||
pager = getenv("PAGER"); | |||
if (pager == NULL || *pager == '\0') | |||
pager = "/usr/bin/more -s"; | |||
cp = mandoc_strdup(pager); | |||
/* | |||
* Parse the pager command into words. | |||
* Intentionally do not do anything fancy here. | |||
*/ | |||
argc = 0; | |||
while (argc + 1 < MAX_PAGER_ARGS) { | |||
argv[argc++] = cp; | |||
cp = strchr(cp, ' '); | |||
if (cp == NULL) | |||
break; | |||
*cp++ = '\0'; | |||
while (*cp == ' ') | |||
cp++; | |||
if (*cp == '\0') | |||
break; | |||
} | |||
argv[argc] = NULL; | |||
/* Hand over to the pager. */ | |||
execvp(argv[0], argv); | |||
fprintf(stderr, "%s: exec: %s\n", | |||
progname, strerror(errno)); | |||
exit((int)MANDOCLEVEL_SYSERR); | |||
} | } |