aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2015-07-28 18:38:55 +0000
committerIngo Schwarze <schwarze@openbsd.org>2015-07-28 18:38:55 +0000
commit12f4fdd4872dac294b89bcf984492bc88dca0b5e (patch)
tree73028812770ae85474acade6b6690624f79313f8
parentd7a1c33838e142532c49cdda9ea67e18aad92683 (diff)
downloadmandoc-12f4fdd4872dac294b89bcf984492bc88dca0b5e.tar.gz
mandoc-12f4fdd4872dac294b89bcf984492bc88dca0b5e.tar.zst
mandoc-12f4fdd4872dac294b89bcf984492bc88dca0b5e.zip
Remove the hack of scrolling forward and backward with +G1G that
many (jmc@, millert@, espie@, deraadt@) considered revolting. Instead, when using a pager, since we are using a temporary file for tags anyway, use another temporary file for the formatted page(s), as suggested by millert@ and similar to what the traditional BSD man(1) did, except that we use only one single temporary output file rather than one for each formatted manual page, such that searching (both with / and :t) works across all the displayed files.
-rw-r--r--main.c95
-rw-r--r--tag.c77
-rw-r--r--tag.h11
3 files changed, 99 insertions, 84 deletions
diff --git a/main.c b/main.c
index 66bbfea8..92730522 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.243 2015/07/21 03:26:21 schwarze Exp $ */
+/* $Id: main.c,v 1.244 2015/07/28 18:38:55 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -95,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**);
@@ -105,7 +104,7 @@ 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 *);
@@ -123,6 +122,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;
@@ -136,8 +136,8 @@ 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 (argc < 1)
progname = "mandoc";
@@ -180,7 +180,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;
@@ -194,14 +195,14 @@ 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':
@@ -277,7 +278,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;
@@ -419,8 +420,8 @@ main(int argc, char *argv[])
if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths))
return((int)MANDOCLEVEL_BADARG);
- if (pager_pid == 1 && isatty(STDOUT_FILENO) == 0)
- pager_pid = 0;
+ if (use_pager && ! isatty(STDOUT_FILENO))
+ use_pager = 0;
curp.mchars = mchars_alloc();
curp.mp = mparse_alloc(options, curp.wlevel, mmsg,
@@ -433,8 +434,8 @@ main(int argc, char *argv[])
mparse_keep(curp.mp);
if (argc < 1) {
- if (pager_pid == 1)
- pager_pid = spawn_pager();
+ if (use_pager)
+ tag_files = tag_init();
parse(&curp, STDIN_FILENO, "<stdin>");
}
@@ -445,8 +446,10 @@ main(int argc, char *argv[])
rc = rctmp;
if (fd != -1) {
- if (pager_pid == 1)
- pager_pid = spawn_pager();
+ if (use_pager) {
+ tag_files = tag_init();
+ use_pager = 0;
+ }
if (resp == NULL)
parse(&curp, fd, *argv);
@@ -490,15 +493,14 @@ 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);
tag_write();
- waitpid(pager_pid, NULL, 0);
+ waitpid(spawn_pager(tag_files), NULL, 0);
tag_unlink();
}
@@ -947,22 +949,14 @@ 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;
size_t cmdlen;
- int fildes[2];
int argc;
pid_t pager_pid;
@@ -991,29 +985,18 @@ spawn_pager(void)
break;
}
- /* Read all text right away and use the tag file. */
+ /* For more(1) and less(1), use the tag file. */
- for (;;) {
- if ((cmdlen = strlen(argv[0])) < 4)
- break;
+ if ((cmdlen = strlen(argv[0])) >= 4) {
cp = argv[0] + cmdlen - 4;
- if (strcmp(cp, "less") && strcmp(cp, "more"))
- break;
- if ((cp = tag_init()) == NULL)
- break;
- argv[argc++] = mandoc_strdup("+G1G");
- argv[argc++] = mandoc_strdup("-T");
- argv[argc++] = cp;
- break;
+ 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;
- 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",
@@ -1022,29 +1005,17 @@ spawn_pager(void)
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));
+ if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) {
+ fprintf(stderr, "pager: stdout: %s\n", strerror(errno));
exit((int)MANDOCLEVEL_SYSERR);
}
- close(fildes[0]);
-
- /* Hand over to the pager. */
-
+ close(tag_files->ofd);
+ close(tag_files->tfd);
execvp(argv[0], argv);
fprintf(stderr, "%s: exec %s: %s\n",
progname, argv[0], strerror(errno));
diff --git a/tag.c b/tag.c
index 02020663..3b3de023 100644
--- a/tag.c
+++ b/tag.c
@@ -1,4 +1,4 @@
-/* $Id: tag.c,v 1.5 2015/07/25 14:28:59 schwarze Exp $ */
+/* $Id: tag.c,v 1.6 2015/07/28 18:38:55 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -44,29 +44,49 @@ static void tag_free(void *, void *);
static void *tag_calloc(size_t, size_t, void *);
static struct ohash tag_data;
-static char *tag_fn = NULL;
-static int tag_fd = -1;
+static struct tag_files tag_files;
/*
- * Set up the ohash table to collect output line numbers
- * where various marked-up terms are documented and create
- * the temporary tags file, saving the name for the pager.
+ * Prepare for using a pager.
+ * Not all pagers are capable of using a tag file,
+ * but for simplicity, create it anyway.
*/
-char *
+struct tag_files *
tag_init(void)
{
struct ohash_info tag_info;
+ int ofd;
- tag_fn = mandoc_strdup("/tmp/man.XXXXXXXXXX");
+ ofd = -1;
+ tag_files.tfd = -1;
+
+ /* Save the original standard output for use by the pager. */
+
+ if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
+ goto fail;
+
+ /* Create both temporary output files. */
+
+ (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
+ sizeof(tag_files.ofn));
+ (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
+ sizeof(tag_files.tfn));
signal(SIGHUP, tag_signal);
signal(SIGINT, tag_signal);
signal(SIGTERM, tag_signal);
- if ((tag_fd = mkstemp(tag_fn)) == -1) {
- free(tag_fn);
- tag_fn = NULL;
- return(NULL);
- }
+ if ((ofd = mkstemp(tag_files.ofn)) == -1)
+ goto fail;
+ if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
+ goto fail;
+ if (dup2(ofd, STDOUT_FILENO) == -1)
+ goto fail;
+ close(ofd);
+
+ /*
+ * Set up the ohash table to collect output line numbers
+ * where various marked-up terms are documented.
+ */
tag_info.alloc = tag_alloc;
tag_info.calloc = tag_calloc;
@@ -74,7 +94,21 @@ tag_init(void)
tag_info.key_offset = offsetof(struct tag_entry, s);
tag_info.data = NULL;
ohash_init(&tag_data, 4, &tag_info);
- return(tag_fn);
+ return(&tag_files);
+
+fail:
+ tag_unlink();
+ if (ofd != -1)
+ close(ofd);
+ if (tag_files.ofd != -1)
+ close(tag_files.ofd);
+ if (tag_files.tfd != -1)
+ close(tag_files.tfd);
+ *tag_files.ofn = '\0';
+ *tag_files.tfn = '\0';
+ tag_files.ofd = -1;
+ tag_files.tfd = -1;
+ return(NULL);
}
/*
@@ -88,7 +122,7 @@ tag_put(const char *s, int prio, size_t line)
size_t len;
unsigned int slot;
- if (tag_fd == -1)
+ if (tag_files.tfd <= 0)
return;
slot = ohash_qlookup(&tag_data, s);
entry = ohash_find(&tag_data, slot);
@@ -114,13 +148,14 @@ tag_write(void)
struct tag_entry *entry;
unsigned int slot;
- if (tag_fd == -1)
+ if (tag_files.tfd <= 0)
return;
- stream = fdopen(tag_fd, "w");
+ stream = fdopen(tag_files.tfd, "w");
entry = ohash_first(&tag_data, &slot);
while (entry != NULL) {
if (stream != NULL)
- fprintf(stream, "%s - %zu\n", entry->s, entry->line);
+ fprintf(stream, "%s %s %zu\n",
+ entry->s, tag_files.ofn, entry->line);
free(entry);
entry = ohash_next(&tag_data, &slot);
}
@@ -133,8 +168,10 @@ void
tag_unlink(void)
{
- if (tag_fn != NULL)
- unlink(tag_fn);
+ if (*tag_files.ofn != '\0')
+ unlink(tag_files.ofn);
+ if (*tag_files.tfn != '\0')
+ unlink(tag_files.tfn);
}
static void
diff --git a/tag.h b/tag.h
index 34a7eee2..0cf5c90b 100644
--- a/tag.h
+++ b/tag.h
@@ -1,4 +1,4 @@
-/* $Id: tag.h,v 1.4 2015/07/25 14:28:59 schwarze Exp $ */
+/* $Id: tag.h,v 1.5 2015/07/28 18:38:55 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -15,9 +15,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+struct tag_files {
+ char ofn[20];
+ char tfn[20];
+ int ofd;
+ int tfd;
+};
+
__BEGIN_DECLS
-char *tag_init(void);
+struct tag_files *tag_init(void);
void tag_put(const char *, int, size_t);
void tag_write(void);
void tag_unlink(void);