summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--Makefile.depend5
-rw-r--r--main.c69
-rw-r--r--man.17
-rw-r--r--mdoc_term.c22
-rw-r--r--tag.c183
-rw-r--r--tag.h27
-rw-r--r--term.h1
-rw-r--r--term_ascii.c4
9 files changed, 292 insertions, 29 deletions
diff --git a/Makefile b/Makefile
index 5007315a..8f466d02 100644
--- a/Makefile
+++ b/Makefile
@@ -93,6 +93,7 @@ SRCS = att.c \
roff.c \
soelim.c \
st.c \
+ tag.c \
tbl.c \
tbl_data.c \
tbl_html.c \
@@ -160,6 +161,7 @@ DISTFILES = INSTALL \
soelim.1 \
st.in \
style.css \
+ tag.h \
tbl.3 \
tbl.7 \
term.h \
@@ -234,6 +236,7 @@ BASE_OBJS = $(MANDOC_HTML_OBJS) \
main.o \
manpath.o \
out.o \
+ tag.o \
tree.o
MAIN_OBJS = $(BASE_OBJS)
diff --git a/Makefile.depend b/Makefile.depend
index 52e95807..1481d1cd 100644
--- a/Makefile.depend
+++ b/Makefile.depend
@@ -22,7 +22,7 @@ eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h
eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h
html.o: html.c config.h mandoc.h mandoc_aux.h out.h html.h manconf.h main.h
lib.o: lib.c config.h roff.h mdoc.h libmdoc.h lib.in
-main.o: main.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h
+main.o: main.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h
man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
man_hash.o: man_hash.c config.h roff.h man.h libman.h
man_html.o: man_html.c config.h mandoc_aux.h roff.h man.h out.h html.h main.h
@@ -42,7 +42,7 @@ mdoc_hash.o: mdoc_hash.c config.h roff.h mdoc.h libmdoc.h
mdoc_html.o: mdoc_html.c config.h mandoc_aux.h roff.h mdoc.h out.h html.h main.h
mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h
-mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h main.h
+mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h tag.h main.h
mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
msec.o: msec.c config.h mandoc.h libmandoc.h msec.in
out.o: out.c config.h mandoc_aux.h mandoc.h out.h
@@ -51,6 +51,7 @@ read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h ro
roff.o: roff.c config.h mandoc.h mandoc_aux.h roff.h libmandoc.h roff_int.h libroff.h predefs.in
soelim.o: soelim.c config.h compat_stringlist.h
st.o: st.c config.h roff.h mdoc.h libmdoc.h st.in
+tag.o: tag.c compat_ohash.h mandoc_aux.h tag.h
tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h
diff --git a/main.c b/main.c
index 61aba7ae..75f6e4e0 100644
--- a/main.c
+++ b/main.c
@@ -39,6 +39,7 @@
#include "roff.h"
#include "mdoc.h"
#include "man.h"
+#include "tag.h"
#include "main.h"
#include "manconf.h"
#include "mansearch.h"
@@ -497,7 +498,9 @@ out:
if (pager_pid != 0 && pager_pid != 1) {
fclose(stdout);
+ tag_write();
waitpid(pager_pid, NULL, 0);
+ tag_unlink();
}
return((int)rc);
@@ -959,10 +962,50 @@ spawn_pager(void)
char *argv[MAX_PAGER_ARGS];
const char *pager;
char *cp;
+ size_t cmdlen;
int fildes[2];
int argc;
pid_t pager_pid;
+ pager = getenv("MANPAGER");
+ if (pager == NULL || *pager == '\0')
+ pager = getenv("PAGER");
+ if (pager == NULL || *pager == '\0')
+ pager = "more -s";
+ cp = mandoc_strdup(pager);
+
+ /*
+ * Parse the pager command into words.
+ * Intentionally do not do anything fancy here.
+ */
+
+ argc = 0;
+ while (argc + 4 < MAX_PAGER_ARGS) {
+ argv[argc++] = cp;
+ cp = strchr(cp, ' ');
+ if (cp == NULL)
+ break;
+ *cp++ = '\0';
+ while (*cp == ' ')
+ cp++;
+ if (*cp == '\0')
+ break;
+ }
+
+ /* Read all text right away and use the tag file. */
+
+ if ((cmdlen = strlen(argv[0])) >= 4) {
+ cp = argv[0] + cmdlen - 4;
+ if (strcmp(cp, "less") == 0 ||
+ strcmp(cp, "more") == 0) {
+ tag_init();
+ argv[argc++] = mandoc_strdup("+G1G");
+ argv[argc++] = mandoc_strdup("-T");
+ argv[argc++] = tag_filename();
+ }
+ }
+ argv[argc] = NULL;
+
if (pipe(fildes) == -1) {
fprintf(stderr, "%s: pipe: %s\n",
progname, strerror(errno));
@@ -998,32 +1041,6 @@ spawn_pager(void)
}
close(fildes[0]);
- pager = getenv("MANPAGER");
- if (pager == NULL || *pager == '\0')
- pager = getenv("PAGER");
- if (pager == NULL || *pager == '\0')
- pager = "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);
diff --git a/man.1 b/man.1
index db4c86e9..0f756c4e 100644
--- a/man.1
+++ b/man.1
@@ -360,6 +360,13 @@ Any non-empty value of the environment variable
.Ev MANPAGER
will be used instead of the standard pagination program,
.Xr more 1 .
+If
+.Xr less 1
+is used, the interactive
+.Ic :t
+command can be used to go to the definitions of various terms, for
+example command line options, command modifiers, internal commands,
+and environment variables.
.It Ev MANPATH
The standard search path used by
.Nm
diff --git a/mdoc_term.c b/mdoc_term.c
index a2ce71fc..95790806 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -34,6 +34,7 @@
#include "mdoc.h"
#include "out.h"
#include "term.h"
+#include "tag.h"
#include "main.h"
struct termpair {
@@ -117,6 +118,7 @@ static int termp_skip_pre(DECL_ARGS);
static int termp_sm_pre(DECL_ARGS);
static int termp_sp_pre(DECL_ARGS);
static int termp_ss_pre(DECL_ARGS);
+static int termp_tag_pre(DECL_ARGS);
static int termp_under_pre(DECL_ARGS);
static int termp_ud_pre(DECL_ARGS);
static int termp_vt_pre(DECL_ARGS);
@@ -145,7 +147,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_bold_pre, NULL }, /* Cm */
{ NULL, NULL }, /* Dv */
{ NULL, NULL }, /* Er */
- { NULL, NULL }, /* Ev */
+ { termp_tag_pre, NULL }, /* Ev */
{ termp_ex_pre, NULL }, /* Ex */
{ termp_fa_pre, NULL }, /* Fa */
{ termp_fd_pre, termp_fd_post }, /* Fd */
@@ -1049,6 +1051,7 @@ static int
termp_fl_pre(DECL_ARGS)
{
+ termp_tag_pre(p, pair, meta, n);
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\-");
@@ -1330,6 +1333,7 @@ static int
termp_bold_pre(DECL_ARGS)
{
+ termp_tag_pre(p, pair, meta, n);
term_fontpush(p, TERMFONT_BOLD);
return(1);
}
@@ -2252,3 +2256,19 @@ termp_under_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_UNDER);
return(1);
}
+
+static int
+termp_tag_pre(DECL_ARGS)
+{
+
+ if (n->child != NULL &&
+ n->child->type == ROFFT_TEXT &&
+ n->prev == NULL &&
+ (n->parent->tok == MDOC_It ||
+ (n->parent->tok == MDOC_Xo &&
+ n->parent->parent->prev == NULL &&
+ n->parent->parent->parent->tok == MDOC_It)) &&
+ ! tag_get(n->child->string, 0))
+ tag_put(n->child->string, 0, p->line);
+ return(1);
+}
diff --git a/tag.c b/tag.c
new file mode 100644
index 00000000..a3610a47
--- /dev/null
+++ b/tag.c
@@ -0,0 +1,183 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_OHASH
+#include <ohash.h>
+#else
+#include "compat_ohash.h"
+#endif
+
+#include "mandoc_aux.h"
+#include "tag.h"
+
+struct tag_entry {
+ size_t line;
+ char s[];
+};
+
+static void *tag_alloc(size_t, void *);
+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;
+
+
+/*
+ * 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.
+ */
+void
+tag_init(void)
+{
+ struct ohash_info tag_info;
+
+ tag_fn = mandoc_strdup("/tmp/man.XXXXXXXXXX");
+ if ((tag_fd = mkstemp(tag_fn)) == -1) {
+ free(tag_fn);
+ tag_fn = NULL;
+ return;
+ }
+
+ tag_info.alloc = tag_alloc;
+ tag_info.calloc = tag_calloc;
+ tag_info.free = tag_free;
+ tag_info.key_offset = offsetof(struct tag_entry, s);
+ tag_info.data = NULL;
+ ohash_init(&tag_data, 4, &tag_info);
+}
+
+char *
+tag_filename(void)
+{
+
+ return(tag_fn);
+}
+
+/*
+ * Return the line number where a term is defined,
+ * or 0 if the term is unknown.
+ */
+size_t
+tag_get(const char *s, size_t len)
+{
+ struct tag_entry *entry;
+ const char *end;
+ unsigned int slot;
+
+ if (tag_fd == -1)
+ return(0);
+ if (len == 0)
+ len = strlen(s);
+ end = s + len;
+ slot = ohash_qlookupi(&tag_data, s, &end);
+ entry = ohash_find(&tag_data, slot);
+ return(entry == NULL ? 0 : entry->line);
+}
+
+/*
+ * Set the line number where a term is defined.
+ */
+void
+tag_put(const char *s, size_t len, size_t line)
+{
+ struct tag_entry *entry;
+ const char *end;
+ unsigned int slot;
+
+ if (tag_fd == -1)
+ return;
+ if (len == 0)
+ len = strlen(s);
+ end = s + len;
+ slot = ohash_qlookupi(&tag_data, s, &end);
+ entry = ohash_find(&tag_data, slot);
+ if (entry == NULL) {
+ entry = mandoc_malloc(sizeof(*entry) + len + 1);
+ memcpy(entry->s, s, len);
+ entry->s[len] = '\0';
+ ohash_insert(&tag_data, slot, entry);
+ }
+ entry->line = line;
+}
+
+/*
+ * Write out the tags file using the previously collected
+ * information and clear the ohash table while going along.
+ */
+void
+tag_write(void)
+{
+ FILE *stream;
+ struct tag_entry *entry;
+ unsigned int slot;
+
+ if (tag_fd == -1)
+ return;
+ stream = fdopen(tag_fd, "w");
+ entry = ohash_first(&tag_data, &slot);
+ while (entry != NULL) {
+ if (stream != NULL)
+ fprintf(stream, "%s - %zu\n", entry->s, entry->line);
+ free(entry);
+ entry = ohash_next(&tag_data, &slot);
+ }
+ ohash_delete(&tag_data);
+ if (stream != NULL)
+ fclose(stream);
+}
+
+void
+tag_unlink(void)
+{
+
+ if (tag_fn != NULL)
+ unlink(tag_fn);
+}
+
+/*
+ * Memory management callback functions for ohash.
+ */
+static void *
+tag_alloc(size_t sz, void *arg)
+{
+
+ return(mandoc_malloc(sz));
+}
+
+static void *
+tag_calloc(size_t nmemb, size_t sz, void *arg)
+{
+
+ return(mandoc_calloc(nmemb, sz));
+}
+
+static void
+tag_free(void *p, void *arg)
+{
+
+ free(p);
+}
diff --git a/tag.h b/tag.h
new file mode 100644
index 00000000..18f7b804
--- /dev/null
+++ b/tag.h
@@ -0,0 +1,27 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+__BEGIN_DECLS
+
+void tag_init(void);
+char *tag_filename(void);
+size_t tag_get(const char *, size_t);
+void tag_put(const char *, size_t, size_t);
+void tag_write(void);
+void tag_unlink(void);
+
+__END_DECLS
diff --git a/term.h b/term.h
index fc4eda7d..debaab94 100644
--- a/term.h
+++ b/term.h
@@ -53,6 +53,7 @@ struct termp {
struct rofftbl tbl; /* table configuration */
int synopsisonly; /* print the synopsis only */
int mdocstyle; /* imitate mdoc(7) output */
+ size_t line; /* Current output line number. */
size_t defindent; /* Default indent for text. */
size_t defrmargin; /* Right margin of the device. */
size_t lastrmargin; /* Right margin before the last ll. */
diff --git a/term_ascii.c b/term_ascii.c
index d210c812..596c1142 100644
--- a/term_ascii.c
+++ b/term_ascii.c
@@ -70,6 +70,7 @@ ascii_init(enum termenc enc, const struct mchars *mchars,
p = mandoc_calloc(1, sizeof(struct termp));
p->symtab = mchars;
+ p->line = 1;
p->tabwidth = 5;
p->defrmargin = p->lastrmargin = 78;
p->fontq = mandoc_reallocarray(NULL,
@@ -163,6 +164,7 @@ ascii_sepline(void *arg)
size_t i;
p = (struct termp *)arg;
+ p->line += 3;
putchar('\n');
for (i = 0; i < p->defrmargin; i++)
putchar('-');
@@ -209,6 +211,7 @@ static void
ascii_endline(struct termp *p)
{
+ p->line++;
putchar('\n');
}
@@ -365,6 +368,7 @@ static void
locale_endline(struct termp *p)
{
+ p->line++;
putwchar(L'\n');
}