=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.230 retrieving revision 1.247 diff -u -p -r1.230 -r1.247 --- mandoc/main.c 2015/03/27 21:33:20 1.230 +++ mandoc/main.c 2015/10/11 21:12:54 1.247 @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.230 2015/03/27 21:33:20 schwarze Exp $ */ +/* $Id: main.c,v 1.247 2015/10/11 21:12:54 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include @@ -34,11 +34,13 @@ #include #include -#include "mandoc.h" #include "mandoc_aux.h" -#include "main.h" +#include "mandoc.h" +#include "roff.h" #include "mdoc.h" #include "man.h" +#include "tag.h" +#include "main.h" #include "manconf.h" #include "mansearch.h" @@ -57,8 +59,8 @@ enum outmode { OUTMODE_ONE }; -typedef void (*out_mdoc)(void *, const struct mdoc *); -typedef void (*out_man)(void *, const struct man *); +typedef void (*out_mdoc)(void *, const struct roff_man *); +typedef void (*out_man)(void *, const struct roff_man *); typedef void (*out_free)(void *); enum outt { @@ -93,7 +95,6 @@ static int fs_lookup(const struct manpaths *, static void fs_search(const struct mansearch *, const struct manpaths *, int, char**, struct manpage **, size_t *); -static void handle_sigpipe(int); static int koptions(int *, char *); #if HAVE_SQLITE3 int mandocdb(int, char**); @@ -103,15 +104,16 @@ static void mmsg(enum mandocerr, enum mandoclevel, const char *, int, int, const char *); static void parse(struct curparse *, int, const char *); static void passthrough(const char *, int, int); -static pid_t spawn_pager(void); +static pid_t spawn_pager(struct tag_files *); static int toptions(struct curparse *, char *); static void usage(enum argmode) __attribute__((noreturn)); static int woptions(struct curparse *, char *); +extern char *__progname; + 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 enum mandoclevel rc; @@ -121,6 +123,7 @@ main(int argc, char *argv[]) struct manconf conf; struct curparse curp; struct mansearch search; + struct tag_files *tag_files; char *auxpaths; char *defos; unsigned char *uc; @@ -134,19 +137,21 @@ main(int argc, char *argv[]) int fd; int show_usage; int options; + int use_pager; int c; - pid_t pager_pid; /* 0: don't use; 1: not yet spawned. */ +#if !HAVE_PROGNAME if (argc < 1) - progname = "mandoc"; - else if ((progname = strrchr(argv[0], '/')) == NULL) - progname = argv[0]; + __progname = mandoc_strdup("mandoc"); + else if ((__progname = strrchr(argv[0], '/')) == NULL) + __progname = argv[0]; else - ++progname; + ++__progname; +#endif #if HAVE_SQLITE3 - if (strcmp(progname, BINM_MAKEWHATIS) == 0) - return(mandocdb(argc, argv)); + if (strcmp(__progname, BINM_MAKEWHATIS) == 0) + return mandocdb(argc, argv); #endif /* Search options. */ @@ -158,13 +163,13 @@ main(int argc, char *argv[]) memset(&search, 0, sizeof(struct mansearch)); search.outkey = "Nd"; - if (strcmp(progname, BINM_MAN) == 0) + if (strcmp(__progname, BINM_MAN) == 0) search.argmode = ARG_NAME; - else if (strcmp(progname, BINM_APROPOS) == 0) + else if (strcmp(__progname, BINM_APROPOS) == 0) search.argmode = ARG_EXPR; - else if (strcmp(progname, BINM_WHATIS) == 0) + else if (strcmp(__progname, BINM_WHATIS) == 0) search.argmode = ARG_WORD; - else if (strncmp(progname, "help", 4) == 0) + else if (strncmp(__progname, "help", 4) == 0) search.argmode = ARG_NAME; else search.argmode = ARG_FILE; @@ -178,7 +183,8 @@ main(int argc, char *argv[]) options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1; defos = NULL; - pager_pid = 1; + use_pager = 1; + tag_files = NULL; show_usage = 0; outmode = OUTMODE_DEF; @@ -192,28 +198,24 @@ main(int argc, char *argv[]) conf_file = optarg; break; case 'c': - pager_pid = 0; + use_pager = 0; break; case 'f': search.argmode = ARG_WORD; break; case 'h': conf.output.synopsisonly = 1; - pager_pid = 0; + use_pager = 0; outmode = OUTMODE_ALL; break; case 'I': if (strncmp(optarg, "os=", 3)) { - fprintf(stderr, - "%s: -I %s: Bad argument\n", - progname, optarg); - return((int)MANDOCLEVEL_BADARG); + warnx("-I %s: Bad argument", optarg); + return (int)MANDOCLEVEL_BADARG; } if (defos) { - fprintf(stderr, - "%s: -I %s: Duplicate argument\n", - progname, optarg); - return((int)MANDOCLEVEL_BADARG); + warnx("-I %s: Duplicate argument", optarg); + return (int)MANDOCLEVEL_BADARG; } defos = mandoc_strdup(optarg + 3); break; @@ -222,7 +224,7 @@ main(int argc, char *argv[]) break; case 'K': if ( ! koptions(&options, optarg)) - return((int)MANDOCLEVEL_BADARG); + return (int)MANDOCLEVEL_BADARG; break; case 'k': search.argmode = ARG_EXPR; @@ -251,11 +253,11 @@ main(int argc, char *argv[]) break; case 'T': if ( ! toptions(&curp, optarg)) - return((int)MANDOCLEVEL_BADARG); + return (int)MANDOCLEVEL_BADARG; break; case 'W': if ( ! woptions(&curp, optarg)) - return((int)MANDOCLEVEL_BADARG); + return (int)MANDOCLEVEL_BADARG; break; case 'w': outmode = OUTMODE_FLN; @@ -275,7 +277,7 @@ main(int argc, char *argv[]) switch (search.argmode) { case ARG_FILE: outmode = OUTMODE_ALL; - pager_pid = 0; + use_pager = 0; break; case ARG_NAME: outmode = OUTMODE_ONE; @@ -286,6 +288,11 @@ main(int argc, char *argv[]) } } + if (outmode == OUTMODE_FLN || + outmode == OUTMODE_LST || + !isatty(STDOUT_FILENO)) + use_pager = 0; + /* Parse arguments. */ if (argc > 0) { @@ -300,7 +307,7 @@ main(int argc, char *argv[]) */ if (search.argmode == ARG_NAME) { - if (*progname == 'h') { + if (*__progname == 'h') { if (argc == 0) { argv = help_argv; argc = 1; @@ -346,14 +353,18 @@ main(int argc, char *argv[]) if (search.argmode != ARG_NAME) { fputs("mandoc: database support not compiled in\n", stderr); - return((int)MANDOCLEVEL_BADARG); + return (int)MANDOCLEVEL_BADARG; } sz = 0; #endif - if (sz == 0 && search.argmode == ARG_NAME) - fs_search(&search, &conf.manpath, - argc, argv, &res, &sz); + if (sz == 0) { + if (search.argmode == ARG_NAME) + fs_search(&search, &conf.manpath, + argc, argv, &res, &sz); + else + warnx("nothing appropriate"); + } if (sz == 0) { rc = MANDOCLEVEL_BADARG; @@ -409,7 +420,7 @@ main(int argc, char *argv[]) /* mandoc(1) */ if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths)) - return((int)MANDOCLEVEL_BADARG); + return (int)MANDOCLEVEL_BADARG; curp.mchars = mchars_alloc(); curp.mp = mparse_alloc(options, curp.wlevel, mmsg, @@ -422,8 +433,8 @@ main(int argc, char *argv[]) mparse_keep(curp.mp); if (argc < 1) { - if (pager_pid == 1 && isatty(STDOUT_FILENO)) - pager_pid = spawn_pager(); + if (use_pager) + tag_files = tag_init(); parse(&curp, STDIN_FILENO, ""); } @@ -434,8 +445,10 @@ main(int argc, char *argv[]) rc = rctmp; if (fd != -1) { - if (pager_pid == 1 && isatty(STDOUT_FILENO)) - pager_pid = spawn_pager(); + if (use_pager) { + tag_files = tag_init(); + use_pager = 0; + } if (resp == NULL) parse(&curp, fd, *argv); @@ -447,10 +460,6 @@ main(int argc, char *argv[]) passthrough(resp->file, fd, conf.output.synopsisonly); - rctmp = mparse_wait(curp.mp); - if (rc < rctmp) - rc = rctmp; - if (argc > 1 && curp.outtype <= OUTT_UTF8) ascii_sepline(curp.outdata); } @@ -483,17 +492,18 @@ out: free(defos); /* - * If a pager is attached, flush the pipe leading to it - * and signal end of file such that the user can browse - * to the end. Then wait for the user to close the pager. + * When using a pager, finish writing both temporary files, + * fork it, wait for the user to close it, and clean up. */ - if (pager_pid != 0 && pager_pid != 1) { + if (tag_files != NULL) { fclose(stdout); - waitpid(pager_pid, NULL, 0); + tag_write(); + waitpid(spawn_pager(tag_files), NULL, 0); + tag_unlink(); } - return((int)rc); + return (int)rc; } static void @@ -560,26 +570,23 @@ fs_lookup(const struct manpaths *paths, size_t ipath, free(file); } - mandoc_asprintf(&file, "%s/man%s/%s.*", + mandoc_asprintf(&file, "%s/man%s/%s.[01-9]*", paths->paths[ipath], sec, name); globres = glob(file, 0, NULL, &globinfo); if (globres != 0 && globres != GLOB_NOMATCH) - fprintf(stderr, "%s: %s: glob: %s\n", - progname, file, strerror(errno)); + warn("%s: glob", file); free(file); if (globres == 0) file = mandoc_strdup(*globinfo.gl_pathv); globfree(&globinfo); if (globres != 0) - return(0); + return 0; found: #if HAVE_SQLITE3 - fprintf(stderr, "%s: outdated mandoc.db lacks %s(%s) entry,\n" - " consider running # makewhatis %s\n", - progname, name, sec, paths->paths[ipath]); + warnx("outdated mandoc.db lacks %s(%s) entry, run makewhatis %s\n", + name, sec, paths->paths[ipath]); #endif - *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage)); page = *res + (*ressz - 1); page->file = file; @@ -589,7 +596,7 @@ found: page->bits = NAME_FILE & NAME_MASK; page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10; page->form = form; - return(1); + return 1; } static void @@ -620,9 +627,7 @@ fs_search(const struct mansearch *cfg, const struct ma return; } if (*ressz == lastsz) - fprintf(stderr, - "%s: No entry for %s in the manual.\n", - progname, *argv); + warnx("No entry for %s in the manual.", *argv); lastsz = *ressz; argv++; argc--; @@ -633,8 +638,7 @@ static void parse(struct curparse *curp, int fd, const char *file) { enum mandoclevel rctmp; - struct mdoc *mdoc; - struct man *man; + struct roff_man *man; /* Begin by parsing the file itself. */ @@ -721,14 +725,16 @@ parse(struct curparse *curp, int fd, const char *file) } } - mparse_result(curp->mp, &mdoc, &man, NULL); + mparse_result(curp->mp, &man, NULL); /* Execute the out device, if it exists. */ - if (man && curp->outman) + if (man == NULL) + return; + if (curp->outmdoc != NULL && man->macroset == MACROSET_MDOC) + (*curp->outmdoc)(curp->outdata, man); + if (curp->outman != NULL && man->macroset == MACROSET_MAN) (*curp->outman)(curp->outdata, man); - if (mdoc && curp->outmdoc) - (*curp->outmdoc)(curp->outdata, mdoc); } static void @@ -792,8 +798,7 @@ done: return; fail: - fprintf(stderr, "%s: %s: SYSERR: %s: %s", - progname, file, syscall, strerror(errno)); + warn("%s: SYSERR: %s", file, syscall); if (rc < MANDOCLEVEL_SYSERR) rc = MANDOCLEVEL_SYSERR; } @@ -811,11 +816,10 @@ koptions(int *options, char *arg) } else if ( ! strcmp(arg, "us-ascii")) { *options &= ~(MPARSE_UTF8 | MPARSE_LATIN1); } else { - fprintf(stderr, "%s: -K %s: Bad argument\n", - progname, arg); - return(0); + warnx("-K %s: Bad argument", arg); + return 0; } - return(1); + return 1; } static int @@ -831,12 +835,11 @@ moptions(int *options, char *arg) else if (0 == strcmp(arg, "an")) *options |= MPARSE_MAN; else { - fprintf(stderr, "%s: -m %s: Bad argument\n", - progname, arg); - return(0); + warnx("-m %s: Bad argument", arg); + return 0; } - return(1); + return 1; } static int @@ -865,12 +868,11 @@ toptions(struct curparse *curp, char *arg) else if (0 == strcmp(arg, "pdf")) curp->outtype = OUTT_PDF; else { - fprintf(stderr, "%s: -T %s: Bad argument\n", - progname, arg); - return(0); + warnx("-T %s: Bad argument", arg); + return 0; } - return(1); + return 1; } static int @@ -908,13 +910,12 @@ woptions(struct curparse *curp, char *arg) curp->wlevel = MANDOCLEVEL_BADARG; break; default: - fprintf(stderr, "%s: -W %s: Bad argument\n", - progname, o); - return(0); + warnx("-W %s: Bad argument", o); + return 0; } } - return(1); + return 1; } static void @@ -923,7 +924,7 @@ mmsg(enum mandocerr t, enum mandoclevel lvl, { const char *mparse_msg; - fprintf(stderr, "%s: %s:", progname, file); + fprintf(stderr, "%s: %s:", __progname, file); if (line) fprintf(stderr, "%d:%d:", line, col + 1); @@ -939,64 +940,22 @@ mmsg(enum mandocerr t, enum mandoclevel lvl, fputc('\n', stderr); } -static void -handle_sigpipe(int signum) -{ - - exit((int)rc); -} - static pid_t -spawn_pager(void) +spawn_pager(struct tag_files *tag_files) { #define MAX_PAGER_ARGS 16 char *argv[MAX_PAGER_ARGS]; const char *pager; char *cp; - int fildes[2]; + size_t cmdlen; int argc; pid_t pager_pid; - if (pipe(fildes) == -1) { - fprintf(stderr, "%s: pipe: %s\n", - progname, strerror(errno)); - return(0); - } - - switch (pager_pid = fork()) { - case -1: - fprintf(stderr, "%s: fork: %s\n", - progname, strerror(errno)); - exit((int)MANDOCLEVEL_SYSERR); - case 0: - break; - default: - close(fildes[0]); - if (dup2(fildes[1], STDOUT_FILENO) == -1) { - fprintf(stderr, "%s: dup output: %s\n", - progname, strerror(errno)); - exit((int)MANDOCLEVEL_SYSERR); - } - close(fildes[1]); - signal(SIGPIPE, handle_sigpipe); - return(pager_pid); - } - - /* The child 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); - } - close(fildes[0]); - pager = getenv("MANPAGER"); if (pager == NULL || *pager == '\0') pager = getenv("PAGER"); if (pager == NULL || *pager == '\0') - pager = "/usr/bin/more -s"; + pager = "more -s"; cp = mandoc_strdup(pager); /* @@ -1005,7 +964,7 @@ spawn_pager(void) */ argc = 0; - while (argc + 1 < MAX_PAGER_ARGS) { + while (argc + 4 < MAX_PAGER_ARGS) { argv[argc++] = cp; cp = strchr(cp, ' '); if (cp == NULL) @@ -1016,12 +975,34 @@ spawn_pager(void) if (*cp == '\0') break; } + + /* For more(1) and less(1), use the tag file. */ + + if ((cmdlen = strlen(argv[0])) >= 4) { + cp = argv[0] + cmdlen - 4; + if (strcmp(cp, "less") == 0 || strcmp(cp, "more") == 0) { + argv[argc++] = mandoc_strdup("-T"); + argv[argc++] = tag_files->tfn; + } + } + argv[argc++] = tag_files->ofn; argv[argc] = NULL; - /* Hand over to the pager. */ + switch (pager_pid = fork()) { + case -1: + err((int)MANDOCLEVEL_SYSERR, "fork"); + case 0: + break; + default: + return pager_pid; + } + /* The child process becomes the pager. */ + + if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) + err((int)MANDOCLEVEL_SYSERR, "pager stdout"); + close(tag_files->ofd); + close(tag_files->tfd); execvp(argv[0], argv); - fprintf(stderr, "%s: exec: %s\n", - progname, strerror(errno)); - exit((int)MANDOCLEVEL_SYSERR); + err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]); }