summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile19
-rw-r--r--libman.h1
-rw-r--r--man.71
-rw-r--r--man.c60
-rw-r--r--man.h3
-rw-r--r--man_action.c14
-rw-r--r--man_macro.c42
-rw-r--r--man_term.c369
-rw-r--r--man_validate.c5
-rw-r--r--mdoc_term.c (renamed from term.c)387
-rw-r--r--term.h37
-rw-r--r--terminal.c319
12 files changed, 852 insertions, 405 deletions
diff --git a/Makefile b/Makefile
index d41c1431..d588637a 100644
--- a/Makefile
+++ b/Makefile
@@ -34,9 +34,12 @@ MANOBJS = man_macro.o man.o man_hash.o man_validate.o \
MANSRCS = man_macro.c man.c man_hash.c man_validate.c \
man_action.c
-MAINLNS = main.ln term.ln ascii.ln terminal.ln tree.ln compat.ln
-MAINOBJS = main.o term.o ascii.o terminal.o tree.o compat.o
-MAINSRCS = main.c term.c ascii.c terminal.c tree.c compat.c
+MAINLNS = main.ln mdoc_term.ln ascii.ln terminal.ln tree.ln \
+ compat.ln man_term.ln
+MAINOBJS = main.o mdoc_term.o ascii.o terminal.o tree.o compat.o \
+ man_term.o
+MAINSRCS = main.c mdoc_term.c ascii.c terminal.c tree.c compat.c \
+ man_term.c
LLNS = llib-llibmdoc.ln llib-llibman.ln llib-lmandoc.ln
LNS = $(MAINLNS) $(MDOCLNS) $(MANLNS)
@@ -129,8 +132,8 @@ st.o: st.c st.in libmdoc.h
mdoc_macro.ln: mdoc_macro.c libmdoc.h
mdoc_macro.o: mdoc_macro.c libmdoc.h
-term.ln: term.c term.h
-term.o: term.c term.h
+mdoc_term.ln: mdoc_term.c term.h mdoc.h
+mdoc_term.o: mdoc_term.c term.h mdoc.h
strings.ln: strings.c libmdoc.h
strings.o: strings.c libmdoc.h
@@ -150,8 +153,8 @@ man.o: man.c libman.h
main.ln: main.c mdoc.h
main.o: main.c mdoc.h
-terminal.ln: terminal.c term.h
-terminal.o: terminal.c term.h
+terminal.ln: terminal.c term.h man.h mdoc.h
+terminal.o: terminal.c term.h man.h mdoc.h
xstd.ln: xstd.c libmdoc.h
xstd.o: xstd.c libmdoc.h
@@ -170,8 +173,6 @@ mdoc_action.o: mdoc_action.c libmdoc.h
libmdoc.h: mdoc.h
-term.h: mdoc.h
-
mdocml-nport-$(VERSION).tar.gz: mdocml-$(VERSION).tar.gz Makefile.netbsd DESCR
mkdir -p .dist/mdocml/
sed -e "s!@VERSION@!$(VERSION)!" Makefile.netbsd > \
diff --git a/libman.h b/libman.h
index 5d32246e..171dca48 100644
--- a/libman.h
+++ b/libman.h
@@ -33,6 +33,7 @@ struct man {
int pflags;
int flags;
#define MAN_HALT (1 << 0)
+#define MAN_NLINE (1 << 1)
enum man_next next;
struct man_node *last;
struct man_node *first;
diff --git a/man.7 b/man.7
index ec1fecb0..4a02f87f 100644
--- a/man.7
+++ b/man.7
@@ -136,6 +136,7 @@ macros, arranged alphabetically, with the number of arguments.
.It \&.B Ta n
.It \&.I Ta n
.It \&.IR Ta n
+.It \&.RI Ta n
.El
.\" SECTION
.Sh SEE ALSO
diff --git a/man.c b/man.c
index 45fada80..18f03be3 100644
--- a/man.c
+++ b/man.c
@@ -31,7 +31,8 @@ const char *const __man_macronames[MAN_MAX] = {
"TP", "LP", "PP", "P",
"IP", "HP", "SM", "SB",
"BI", "IB", "BR", "RB",
- "R", "B", "I", "IR"
+ "R", "B", "I", "IR",
+ "RI"
};
const char * const *man_macronames = __man_macronames;
@@ -268,6 +269,25 @@ man_ptext(struct man *m, int line, char *buf)
if ( ! man_word_alloc(m, line, 0, buf))
return(0);
m->next = MAN_NEXT_SIBLING;
+
+ /*
+ * If this is one of the zany NLINE macros that consumes the
+ * next line of input as being influenced, then close out the
+ * existing macro "scope" and continue processing.
+ */
+
+ if ( ! (MAN_NLINE & m->flags))
+ return(1);
+
+ m->flags &= ~MAN_NLINE;
+ m->last = m->last->parent;
+
+ assert(MAN_ROOT != m->last->type);
+ if ( ! man_valid_post(m))
+ return(0);
+ if ( ! man_action_post(m))
+ return(0);
+
return(1);
}
@@ -275,13 +295,17 @@ man_ptext(struct man *m, int line, char *buf)
int
man_pmacro(struct man *m, int ln, char *buf)
{
- int i, j, c, ppos;
+ int i, j, c, ppos, fl;
char mac[5];
+ struct man_node *n;
/* Comments and empties are quickly ignored. */
+ n = m->last;
+ fl = MAN_NLINE & m->flags;
+
if (0 == buf[1])
- return(1);
+ goto out;
i = 1;
@@ -290,14 +314,14 @@ man_pmacro(struct man *m, int ln, char *buf)
while (buf[i] && ' ' == buf[i])
i++;
if (0 == buf[i])
- return(1);
+ goto out;
}
ppos = i;
if (buf[i] && '\\' == buf[i])
if (buf[i + 1] && '\"' == buf[i + 1])
- return(1);
+ goto out;
/* Copy the first word into a nil-terminated buffer. */
@@ -319,7 +343,7 @@ man_pmacro(struct man *m, int ln, char *buf)
if ( ! man_vwarn(m, ln, ppos,
"ill-formed macro: %s", mac))
goto err;
- return(1);
+ goto out;
}
if (MAN_MAX == (c = man_hash_find(m->htab, mac))) {
@@ -331,7 +355,7 @@ man_pmacro(struct man *m, int ln, char *buf)
if ( ! man_vwarn(m, ln, ppos,
"unknown macro: %s", mac))
goto err;
- return(1);
+ goto out;
}
/* The macro is sane. Jump to the next word. */
@@ -344,6 +368,28 @@ man_pmacro(struct man *m, int ln, char *buf)
if ( ! man_macro(m, c, ln, ppos, &i, buf))
goto err;
+out:
+ if (fl) {
+ /*
+ * A NLINE macro has been immediately followed with
+ * another. Close out the preceeding macro's scope, and
+ * continue.
+ */
+ assert(MAN_ROOT != m->last->type);
+ assert(m->last->parent);
+ assert(MAN_ROOT != m->last->parent->type);
+
+ if (n != m->last)
+ m->last = m->last->parent;
+
+ if ( ! man_valid_post(m))
+ return(0);
+ if ( ! man_action_post(m))
+ return(0);
+ m->next = MAN_NEXT_SIBLING;
+ m->flags &= ~MAN_NLINE;
+ }
+
return(1);
err: /* Error out. */
diff --git a/man.h b/man.h
index 3e232c18..993bd385 100644
--- a/man.h
+++ b/man.h
@@ -41,7 +41,8 @@
#define MAN_B 17
#define MAN_I 18
#define MAN_IR 19
-#define MAN_MAX 20
+#define MAN_RI 20
+#define MAN_MAX 21
enum man_type {
MAN_TEXT,
diff --git a/man_action.c b/man_action.c
index e159baa5..631a1d66 100644
--- a/man_action.c
+++ b/man_action.c
@@ -37,7 +37,7 @@ struct actions {
static int post_TH(struct man *);
-static time_t man_atotime(const char *);
+static time_t man_atotime(const char *);
const struct actions man_actions[MAN_MAX] = {
{ NULL }, /* __ */
@@ -60,6 +60,7 @@ const struct actions man_actions[MAN_MAX] = {
{ NULL }, /* B */
{ NULL }, /* I */
{ NULL }, /* IR */
+ { NULL }, /* RI */
};
@@ -125,12 +126,9 @@ post_TH(struct man *m)
/* TITLE MSEC ->DATE<- SOURCE VOL */
- if (NULL == (n = n->next)) {
+ if (NULL == (n = n->next))
m->meta.date = time(NULL);
- return(1);
- }
-
- if (0 == (m->meta.date = man_atotime(n->string))) {
+ else if (0 == (m->meta.date = man_atotime(n->string))) {
if ( ! man_vwarn(m, n->line, n->pos, "invalid date"))
return(0);
m->meta.date = time(NULL);
@@ -138,13 +136,13 @@ post_TH(struct man *m)
/* TITLE MSEC DATE ->SOURCE<- VOL */
- if ((n = n->next))
+ if (n && (n = n->next))
if (NULL == (m->meta.source = strdup(n->string)))
return(man_verr(m, n->line, n->pos, "malloc"));
/* TITLE MSEC DATE SOURCE ->VOL<- */
- if ((n = n->next))
+ if (n && (n = n->next))
if (NULL == (m->meta.vol = strdup(n->string)))
return(man_verr(m, n->line, n->pos, "malloc"));
diff --git a/man_macro.c b/man_macro.c
index 518b1e8e..2b389b14 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -24,9 +24,35 @@
#include "libman.h"
+#define FL_NLINE (1 << 0)
+#define FL_TLINE (1 << 1)
+
static int man_args(struct man *, int,
int *, char *, char **);
+static int man_flags[MAN_MAX] = {
+ 0, /* __ */
+ 0, /* TH */
+ 0, /* SH */
+ 0, /* SS */
+ FL_TLINE, /* TP */
+ 0, /* LP */
+ 0, /* PP */
+ 0, /* P */
+ 0, /* IP */
+ 0, /* HP */
+ FL_NLINE, /* SM */
+ FL_NLINE, /* SB */
+ FL_NLINE, /* BI */
+ FL_NLINE, /* IB */
+ FL_NLINE, /* BR */
+ FL_NLINE, /* RB */
+ FL_NLINE, /* R */
+ FL_NLINE, /* B */
+ FL_NLINE, /* I */
+ FL_NLINE, /* IR */
+ FL_NLINE, /* RI */
+};
int
man_macro(struct man *man, int tok, int line,
@@ -55,6 +81,22 @@ man_macro(struct man *man, int tok, int line,
man->next = MAN_NEXT_SIBLING;
}
+ if (n == man->last && (FL_NLINE & man_flags[tok])) {
+ if (MAN_NLINE & man->flags)
+ return(man_verr(man, line, ppos,
+ "next-line scope already open"));
+ man->flags |= MAN_NLINE;
+ return(1);
+ }
+
+ if (FL_TLINE & man_flags[tok]) {
+ if (MAN_NLINE & man->flags)
+ return(man_verr(man, line, ppos,
+ "next-line scope already open"));
+ man->flags |= MAN_NLINE;
+ return(1);
+ }
+
/*
* Note that when TH is pruned, we'll be back at the root, so
* make sure that we don't clobber as its sibling.
diff --git a/man_term.c b/man_term.c
new file mode 100644
index 00000000..0a8e5fce
--- /dev/null
+++ b/man_term.c
@@ -0,0 +1,369 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@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 <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "term.h"
+#include "man.h"
+
+#define DECL_ARGS struct termp *p, \
+ const struct man_node *n, \
+ const struct man_meta *m
+
+struct termact {
+ int (*pre)(DECL_ARGS);
+ void (*post)(DECL_ARGS);
+};
+
+static int pre_B(DECL_ARGS);
+static int pre_I(DECL_ARGS);
+static int pre_PP(DECL_ARGS);
+static int pre_SH(DECL_ARGS);
+static int pre_SS(DECL_ARGS);
+static int pre_TP(DECL_ARGS);
+
+static void post_B(DECL_ARGS);
+static void post_I(DECL_ARGS);
+static void post_SH(DECL_ARGS);
+static void post_SS(DECL_ARGS);
+
+static const struct termact termacts[MAN_MAX] = {
+ { NULL, NULL }, /* __ */
+ { NULL, NULL }, /* TH */
+ { pre_SH, post_SH }, /* SH */
+ { pre_SS, post_SS }, /* SS */
+ { pre_TP, NULL }, /* TP */
+ { pre_PP, NULL }, /* LP */
+ { pre_PP, NULL }, /* PP */
+ { pre_PP, NULL }, /* P */
+ { NULL, NULL }, /* IP */
+ { pre_PP, NULL }, /* HP */ /* XXX */
+ { NULL, NULL }, /* SM */
+ { pre_B, post_B }, /* SB */
+ { NULL, NULL }, /* BI */
+ { NULL, NULL }, /* IB */
+ { NULL, NULL }, /* BR */
+ { NULL, NULL }, /* RB */
+ { NULL, NULL }, /* R */
+ { pre_B, post_B }, /* B */
+ { pre_I, post_I }, /* I */
+ { NULL, NULL }, /* IR */
+ { NULL, NULL }, /* RI */
+};
+
+static void print_head(struct termp *,
+ const struct man_meta *);
+static void print_body(DECL_ARGS);
+static void print_node(DECL_ARGS);
+static void print_foot(struct termp *,
+ const struct man_meta *);
+
+
+int
+man_run(struct termp *p, const struct man *m)
+{
+
+ print_head(p, man_meta(m));
+ p->flags |= TERMP_NOSPACE;
+ print_body(p, man_node(m), man_meta(m));
+ print_foot(p, man_meta(m));
+
+ return(1);
+}
+
+
+static int
+pre_I(DECL_ARGS)
+{
+
+ p->flags |= TERMP_UNDER;
+ return(1);
+}
+
+
+static void
+post_I(DECL_ARGS)
+{
+
+ p->flags &= ~TERMP_UNDER;
+}
+
+
+static int
+pre_B(DECL_ARGS)
+{
+
+ p->flags |= TERMP_BOLD;
+ return(1);
+}
+
+
+static void
+post_B(DECL_ARGS)
+{
+
+ p->flags &= ~TERMP_BOLD;
+}
+
+
+static int
+pre_PP(DECL_ARGS)
+{
+
+ term_vspace(p);
+ p->offset = INDENT;
+ return(0);
+}
+
+
+static int
+pre_TP(DECL_ARGS)
+{
+ const struct man_node *nn;
+ size_t offs;
+
+ term_vspace(p);
+ p->offset = INDENT;
+
+ if (NULL == (nn = n->child))
+ return(1);
+
+ if (nn->line == n->line) {
+ if (MAN_TEXT != nn->type)
+ errx(1, "expected text line argument");
+ offs = atoi(nn->string);
+ nn = nn->next;
+ } else
+ offs = INDENT;
+
+ for ( ; nn; nn = nn->next)
+ print_node(p, nn, m);
+
+ term_flushln(p);
+ p->flags |= TERMP_NOSPACE;
+ p->offset += offs;
+ return(0);
+}
+
+
+static int
+pre_SS(DECL_ARGS)
+{
+
+ term_vspace(p);
+ p->flags |= TERMP_BOLD;
+ return(1);
+}
+
+
+static void
+post_SS(DECL_ARGS)
+{
+
+ term_flushln(p);
+ p->flags &= ~TERMP_BOLD;
+ p->flags |= TERMP_NOSPACE;
+}
+
+
+static int
+pre_SH(DECL_ARGS)
+{
+
+ term_vspace(p);
+ p->offset = 0;
+ p->flags |= TERMP_BOLD;
+ return(1);
+}
+
+
+static void
+post_SH(DECL_ARGS)
+{
+
+ term_flushln(p);
+ p->offset = INDENT;
+ p->flags &= ~TERMP_BOLD;
+ p->flags |= TERMP_NOSPACE;
+}
+
+
+static void
+print_node(DECL_ARGS)
+{
+ int c;
+
+ c = 1;
+
+ switch (n->type) {
+ case(MAN_ELEM):
+ if (termacts[n->tok].pre)
+ c = (*termacts[n->tok].pre)(p, n, m);
+ break;
+ case(MAN_TEXT):
+ if (*n->string) {
+ term_word(p, n->string);
+ break;
+ }
+ term_vspace(p);
+ break;
+ default:
+ break;
+ }
+
+ if (c && n->child)
+ print_body(p, n->child, m);
+
+ switch (n->type) {
+ case (MAN_ELEM):
+ if (termacts[n->tok].post)
+ (*termacts[n->tok].post)(p, n, m);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void
+print_body(DECL_ARGS)
+{
+ print_node(p, n, m);
+ if ( ! n->next)
+ return;
+ print_body(p, n->next, m);
+}
+
+
+static void
+print_foot(struct termp *p, const struct man_meta *meta)
+{
+ struct tm *tm;
+ char *buf;
+
+ if (NULL == (buf = malloc(p->rmargin)))
+ err(1, "malloc");
+
+ tm = localtime(&meta->date);
+
+#ifdef __OpenBSD__
+ if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
+#else
+ if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
+#endif
+ err(1, "strftime");
+
+ /*
+ * This is /slightly/ different from regular groff output
+ * because we don't have page numbers. Print the following:
+ *
+ * OS MDOCDATE
+ */
+
+ term_vspace(p);
+
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
+ p->rmargin = p->maxrmargin - strlen(buf);
+ p->offset = 0;
+
+ if (meta->source)
+ term_word(p, meta->source);
+ if (meta->source)
+ term_word(p, "");
+ term_flushln(p);
+
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+ p->offset = p->rmargin;
+ p->rmargin = p->maxrmargin;
+ p->flags &= ~TERMP_NOBREAK;
+
+ term_word(p, buf);
+ term_flushln(p);
+
+ free(buf);
+}
+
+
+static void
+print_head(struct termp *p, const struct man_meta *meta)
+{
+ char *buf, *title;
+
+ p->rmargin = p->maxrmargin;
+ p->offset = 0;
+
+ if (NULL == (buf = malloc(p->rmargin)))
+ err(1, "malloc");
+ if (NULL == (title = malloc(p->rmargin)))
+ err(1, "malloc");
+
+ /*
+ * The header is strange. It has three components, which are
+ * really two with the first duplicated. It goes like this:
+ *
+ * IDENTIFIER TITLE IDENTIFIER
+ *
+ * The IDENTIFIER is NAME(SECTION), which is the command-name
+ * (if given, or "unknown" if not) followed by the manual page
+ * section. These are given in `Dt'. The TITLE is a free-form
+ * string depending on the manual volume. If not specified, it
+ * switches on the manual section.
+ */
+
+ if (meta->vol)
+ (void)strlcpy(buf, meta->vol, p->rmargin);
+ else
+ *buf = 0;
+
+ (void)snprintf(title, p->rmargin, "%s(%d)",
+ meta->title, meta->msec);
+
+ p->offset = 0;
+ p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
+ p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
+
+ term_word(p, title);
+ term_flushln(p);
+
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+ p->offset = p->rmargin;
+ p->rmargin = p->maxrmargin - strlen(title);
+
+ term_word(p, buf);
+ term_flushln(p);
+
+ p->offset = p->rmargin;
+ p->rmargin = p->maxrmargin;
+ p->flags &= ~TERMP_NOBREAK;
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+
+ term_word(p, title);
+ term_flushln(p);
+
+ p->rmargin = p->maxrmargin;
+ p->offset = 0;
+ p->flags &= ~TERMP_NOSPACE;
+
+ free(title);
+ free(buf);
+}
+
diff --git a/man_validate.c b/man_validate.c
index 495e4329..fb7dd295 100644
--- a/man_validate.c
+++ b/man_validate.c
@@ -54,7 +54,7 @@ static const struct man_valid man_valids[MAN_MAX] = {
{ posts_ge2_le5 }, /* TH */
{ posts_ge1 }, /* SH */
{ posts_ge1 }, /* SS */
- { posts_le1 }, /* TP */
+ { NULL }, /* TP */
{ posts_eq0 }, /* LP */
{ posts_eq0 }, /* PP */
{ posts_eq0 }, /* P */
@@ -70,6 +70,7 @@ static const struct man_valid man_valids[MAN_MAX] = {
{ NULL }, /* B */
{ NULL }, /* I */
{ NULL }, /* IR */
+ { NULL }, /* RI */
};
@@ -119,7 +120,7 @@ check_##name(POSTARGS) \
int c; \
if ((c = count(n->child)) ineq (x)) \
return(1); \
- return(man_vwarn(m, n->line, n->pos, \
+ return(man_verr(m, n->line, n->pos, \
"expected line arguments %s %d, have %d", \
#ineq, (x), c)); \
}
diff --git a/term.c b/mdoc_term.c
index 73847282..71124804 100644
--- a/term.c
+++ b/mdoc_term.c
@@ -26,13 +26,10 @@
#include <string.h>
#include "term.h"
-
-/*
- * Performs actions on nodes of the abstract syntax tree. Both pre- and
- * post-fix operations are defined here.
- */
+#include "mdoc.h"
/* FIXME: macro arguments can be escaped. */
+/* FIXME: support more offset/width tokens. */
#define TTYPE_PROG 0
#define TTYPE_CMD_FLAG 1
@@ -59,14 +56,6 @@
#define TTYPE_LIST 22
#define TTYPE_NMAX 23
-/*
- * These define "styles" for element types, like command arguments or
- * executable names. This is useful when multiple macros must decorate
- * the same thing (like .Ex -std cmd and .Nm cmd).
- */
-
-/* TODO: abstract this into mdocterm.c. */
-
const int ttypes[TTYPE_NMAX] = {
TERMP_BOLD, /* TTYPE_PROG */
TERMP_BOLD, /* TTYPE_CMD_FLAG */
@@ -93,25 +82,28 @@ const int ttypes[TTYPE_NMAX] = {
TERMP_BOLD /* TTYPE_LIST */
};
-static int arg_hasattr(int, const struct mdoc_node *);
-static int arg_getattrs(const int *, int *, size_t,
- const struct mdoc_node *);
-static int arg_getattr(int, const struct mdoc_node *);
-static size_t arg_offset(const struct mdoc_argv *);
-static size_t arg_width(const struct mdoc_argv *, int);
-static int arg_listtype(const struct mdoc_node *);
-static int fmt_block_vspace(struct termp *,
- const struct mdoc_node *,
- const struct mdoc_node *);
+/* XXX - clean this up. */
-/*
- * What follows describes prefix and postfix operations for the abstract
- * syntax tree descent.
- */
+struct termpair {
+ struct termpair *ppair;
+ int type;
+#define TERMPAIR_FLAG (1 << 0)
+ int flag;
+ size_t offset;
+ size_t rmargin;
+ int count;
+};
+
+#define TERMPAIR_SETFLAG(termp, p, fl) \
+ do { \
+ assert(! (TERMPAIR_FLAG & (p)->type)); \
+ (termp)->flags |= (fl); \
+ (p)->flag = (fl); \
+ (p)->type |= TERMPAIR_FLAG; \
+ } while ( /* CONSTCOND */ 0)
#define DECL_ARGS \
- struct termp *p, \
- struct termpair *pair, \
+ struct termp *p, struct termpair *pair, \
const struct mdoc_meta *meta, \
const struct mdoc_node *node
@@ -187,7 +179,12 @@ DECL_POST(termp___);
DECL_POST(termp_bl);
DECL_POST(termp_bx);
-const struct termact __termacts[MDOC_MAX] = {
+struct termact {
+ int (*pre)(DECL_ARGS);
+ void (*post)(DECL_ARGS);
+};
+
+static const struct termact termacts[MDOC_MAX] = {
{ NULL, NULL }, /* \" */
{ NULL, NULL }, /* Dd */
{ NULL, NULL }, /* Dt */
@@ -309,7 +306,331 @@ const struct termact __termacts[MDOC_MAX] = {
{ NULL, NULL }, /* %Q */
};
-const struct termact *termacts = __termacts;
+static int arg_hasattr(int, const struct mdoc_node *);
+static int arg_getattrs(const int *, int *, size_t,
+ const struct mdoc_node *);
+static int arg_getattr(int, const struct mdoc_node *);
+static size_t arg_offset(const struct mdoc_argv *);
+static size_t arg_width(const struct mdoc_argv *, int);
+static int arg_listtype(const struct mdoc_node *);
+static int fmt_block_vspace(struct termp *,
+ const struct mdoc_node *,
+ const struct mdoc_node *);
+static int print_node(DECL_ARGS);
+static int print_head(struct termp *,
+ const struct mdoc_meta *);
+static int print_body(DECL_ARGS);
+static int print_foot(struct termp *,
+ const struct mdoc_meta *);
+static void sanity(const struct mdoc_node *);
+
+
+int
+mdoc_run(struct termp *p, const struct mdoc *m)
+{
+
+ if ( ! print_head(p, mdoc_meta(m)))
+ return(0);
+ if ( ! print_body(p, NULL, mdoc_meta(m), mdoc_node(m)))
+ return(0);
+ return(print_foot(p, mdoc_meta(m)));
+}
+
+
+static int
+print_body(DECL_ARGS)
+{
+
+ if ( ! print_node(p, pair, meta, node))
+ return(0);
+ if ( ! node->next)
+ return(1);
+ return(print_body(p, pair, meta, node->next));
+}
+
+
+static int
+print_node(DECL_ARGS)
+{
+ int dochild;
+ struct termpair npair;
+
+ /* Some quick sanity-checking. */
+
+ sanity(node);
+
+ /* Pre-processing. */
+
+ dochild = 1;
+ npair.ppair = pair;
+ npair.type = 0;
+ npair.offset = npair.rmargin = 0;
+ npair.flag = 0;
+ npair.count = 0;
+
+ if (MDOC_TEXT != node->type) {
+ if (termacts[node->tok].pre)
+ if ( ! (*termacts[node->tok].pre)(p, &npair, meta, node))
+ dochild = 0;
+ } else /* MDOC_TEXT == node->type */
+ term_word(p, node->string);
+
+ /* Children. */
+
+ if (TERMPAIR_FLAG & npair.type)
+ p->flags |= npair.flag;
+
+ if (dochild && node->child)
+ print_body(p, &npair, meta, node->child);
+
+ if (TERMPAIR_FLAG & npair.type)
+ p->flags &= ~npair.flag;
+
+ /* Post-processing. */
+
+ if (MDOC_TEXT != node->type)
+ if (termacts[node->tok].post)
+ (*termacts[node->tok].post)(p, &npair, meta, node);
+
+ return(1);
+}
+
+
+static int
+print_foot(struct termp *p, const struct mdoc_meta *meta)
+{
+ struct tm *tm;
+ char *buf, *os;
+
+ if (NULL == (buf = malloc(p->rmargin)))
+ err(1, "malloc");
+ if (NULL == (os = malloc(p->rmargin)))
+ err(1, "malloc");
+
+ tm = localtime(&meta->date);
+
+#ifdef __OpenBSD__
+ if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
+#else
+ if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
+#endif
+ err(1, "strftime");
+
+ (void)strlcpy(os, meta->os, p->rmargin);
+
+ /*
+ * This is /slightly/ different from regular groff output
+ * because we don't have page numbers. Print the following:
+ *
+ * OS MDOCDATE
+ */
+
+ term_vspace(p);
+
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
+ p->rmargin = p->maxrmargin - strlen(buf);
+ p->offset = 0;
+
+ term_word(p, os);
+ term_flushln(p);
+
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+ p->offset = p->rmargin;
+ p->rmargin = p->maxrmargin;
+ p->flags &= ~TERMP_NOBREAK;
+
+ term_word(p, buf);
+ term_flushln(p);
+
+ free(buf);
+ free(os);
+
+ return(1);
+}
+
+
+static int
+print_head(struct termp *p, const struct mdoc_meta *meta)
+{
+ char *buf, *title;
+
+ p->rmargin = p->maxrmargin;
+ p->offset = 0;
+
+ if (NULL == (buf = malloc(p->rmargin)))
+ err(1, "malloc");
+ if (NULL == (title = malloc(p->rmargin)))
+ err(1, "malloc");
+
+ /*
+ * The header is strange. It has three components, which are
+ * really two with the first duplicated. It goes like this:
+ *
+ * IDENTIFIER TITLE IDENTIFIER
+ *
+ * The IDENTIFIER is NAME(SECTION), which is the command-name
+ * (if given, or "unknown" if not) followed by the manual page
+ * section. These are given in `Dt'. The TITLE is a free-form
+ * string depending on the manual volume. If not specified, it
+ * switches on the manual section.
+ */
+
+ assert(meta->vol);
+ (void)strlcpy(buf, meta->vol, p->rmargin);
+
+ if (meta->arch) {
+ (void)strlcat(buf, " (", p->rmargin);
+ (void)strlcat(buf, meta->arch, p->rmargin);
+ (void)strlcat(buf, ")", p->rmargin);
+ }
+
+ (void)snprintf(title, p->rmargin, "%s(%d)",
+ meta->title, meta->msec);
+
+ p->offset = 0;
+ p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
+ p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
+
+ term_word(p, title);
+ term_flushln(p);
+
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+ p->offset = p->rmargin;
+ p->rmargin = p->maxrmargin - strlen(title);
+
+ term_word(p, buf);
+ term_flushln(p);
+
+ p->offset = p->rmargin;
+ p->rmargin = p->maxrmargin;
+ p->flags &= ~TERMP_NOBREAK;
+ p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+
+ term_word(p, title);
+ term_flushln(p);
+
+ p->rmargin = p->maxrmargin;
+ p->offset = 0;
+ p->flags &= ~TERMP_NOSPACE;
+
+ free(title);
+ free(buf);
+
+ return(1);
+}
+
+
+static void
+sanity(const struct mdoc_node *n)
+{
+ char *p;
+
+ p = "regular form violated";
+
+ switch (n->type) {
+ case (MDOC_TEXT):
+ if (n->child)
+ errx(1, p);
+ if (NULL == n->parent)
+ errx(1, p);
+ if (NULL == n->string)
+ errx(1, p);
+ switch (n->parent->type) {
+ case (MDOC_TEXT):
+ /* FALLTHROUGH */
+ case (MDOC_ROOT):
+ errx(1, p);
+ /* NOTREACHED */
+ default:
+ break;
+ }
+ break;
+ case (MDOC_ELEM):
+ if (NULL == n->parent)
+ errx(1, p);
+ switch (n->parent->type) {
+ case (MDOC_TAIL):
+ /* FALLTHROUGH */
+ case (MDOC_BODY):
+ /* FALLTHROUGH */
+ case (MDOC_HEAD):
+ break;
+ default:
+ errx(1, p);
+ /* NOTREACHED */
+ }
+ if (n->child) switch (n->child->type) {
+ case (MDOC_TEXT):
+ break;
+ default:
+ errx(1, p);
+ /* NOTREACHED */
+ }
+ break;
+ case (MDOC_HEAD):
+ /* FALLTHROUGH */
+ case (MDOC_BODY):
+ /* FALLTHROUGH */
+ case (MDOC_TAIL):
+ if (NULL == n->parent)
+ errx(1, p);
+ if (MDOC_BLOCK != n->parent->type)
+ errx(1, p);
+ if (n->child) switch (n->child->type) {
+ case (MDOC_BLOCK):
+ /* FALLTHROUGH */
+ case (MDOC_ELEM):
+ /* FALLTHROUGH */
+ case (MDOC_TEXT):
+ break;
+ default:
+ errx(1, p);
+ /* NOTREACHED */
+ }
+ break;
+ case (MDOC_BLOCK):
+ if (NULL == n->parent)
+ errx(1, p);
+ if (NULL == n->child)
+ errx(1, p);
+ switch (n->parent->type) {
+ case (MDOC_ROOT):
+ /* FALLTHROUGH */
+ case (MDOC_HEAD):
+ /* FALLTHROUGH */
+ case (MDOC_BODY):
+ /* FALLTHROUGH */
+ case (MDOC_TAIL):
+ break;
+ default:
+ errx(1, p);
+ /* NOTREACHED */
+ }
+ switch (n->child->type) {
+ case (MDOC_ROOT):
+ /* FALLTHROUGH */
+ case (MDOC_ELEM):
+ errx(1, p);
+ /* NOTREACHED */
+ default:
+ break;
+ }
+ break;
+ case (MDOC_ROOT):
+ if (n->parent)
+ errx(1, p);
+ if (NULL == n->child)
+ errx(1, p);
+ switch (n->child->type) {
+ case (MDOC_BLOCK):
+ break;
+ default:
+ errx(1, p);
+ /* NOTREACHED */
+ }
+ break;
+ }
+}
static size_t
@@ -387,7 +708,6 @@ static size_t
arg_offset(const struct mdoc_argv *arg)
{
- /* TODO */
assert(*arg->value);
if (0 == strcmp(*arg->value, "indent"))
return(INDENT);
@@ -1349,7 +1669,7 @@ termp_bd_pre(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
}
ln = node->line;
- term_node(p, pair, meta, node);
+ print_node(p, pair, meta, node);
}
return(0);
@@ -1924,3 +2244,4 @@ termp_mt_pre(DECL_ARGS)
return(1);
}
+
diff --git a/term.h b/term.h
index 47fde4ac..dca213a0 100644
--- a/term.h
+++ b/term.h
@@ -19,9 +19,6 @@
#ifndef TERM_H
#define TERM_H
-#include "mdoc.h"
-#include "man.h"
-
/* FIXME - clean up tabs. */
#define INDENT 6
@@ -56,35 +53,6 @@ struct termp {
void *symtab; /* Encoded-symbol table. */
};
-/* XXX - clean this up. */
-
-struct termpair {
- struct termpair *ppair;
- int type;
-#define TERMPAIR_FLAG (1 << 0)
- int flag;
- size_t offset;
- size_t rmargin;
- int count;
-};
-
-#define TERMPAIR_SETFLAG(termp, p, fl) \
- do { \
- assert(! (TERMPAIR_FLAG & (p)->type)); \
- (termp)->flags |= (fl); \
- (p)->flag = (fl); \
- (p)->type |= TERMPAIR_FLAG; \
- } while ( /* CONSTCOND */ 0)
-
-struct termact {
- int (*pre)(struct termp *, struct termpair *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
- void (*post)(struct termp *, struct termpair *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-};
-
void *term_ascii2htab(void);
const char *term_a2ascii(void *, const char *, size_t, size_t *);
void term_asciifree(void *);
@@ -93,11 +61,6 @@ void term_newln(struct termp *);
void term_vspace(struct termp *);
void term_word(struct termp *, const char *);
void term_flushln(struct termp *);
-void term_node(struct termp *, struct termpair *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-
-const struct termact *termacts;
__END_DECLS
diff --git a/terminal.c b/terminal.c
index accd0efa..f2048cd5 100644
--- a/terminal.c
+++ b/terminal.c
@@ -23,21 +23,21 @@
#include <string.h>
#include "term.h"
+#include "man.h"
+#include "mdoc.h"
#ifdef __linux__
extern size_t strlcpy(char *, const char *, size_t);
extern size_t strlcat(char *, const char *, size_t);
#endif
+extern int man_run(struct termp *,
+ const struct man *);
+extern int mdoc_run(struct termp *,
+ const struct mdoc *);
+
static struct termp *term_alloc(enum termenc);
static void term_free(struct termp *);
-static void term_body(struct termp *, struct termpair *,
- const struct mdoc_meta *,
- const struct mdoc_node *);
-static void term_head(struct termp *,
- const struct mdoc_meta *);
-static void term_foot(struct termp *,
- const struct mdoc_meta *);
static void term_pword(struct termp *, const char *, int);
static void term_pescape(struct termp *,
const char *, int *, int);
@@ -48,7 +48,6 @@ static void term_stringa(struct termp *,
const char *, size_t);
static int term_isopendelim(const char *, int);
static int term_isclosedelim(const char *, int);
-static void sanity(const struct mdoc_node *); /* XXX */
void *
@@ -65,17 +64,15 @@ terminal_run(void *arg, const struct man *man,
{
struct termp *p;
- if (NULL == mdoc)
- return(1);
-
p = (struct termp *)arg;
if (NULL == p->symtab)
p->symtab = term_ascii2htab();
- term_head(p, mdoc_meta(mdoc));
- term_body(p, NULL, mdoc_meta(mdoc), mdoc_node(mdoc));
- term_foot(p, mdoc_meta(mdoc));
+ if (man)
+ return(man_run(p, man));
+ if (mdoc)
+ return(mdoc_run(p, mdoc));
return(1);
}
@@ -403,191 +400,6 @@ term_word(struct termp *p, const char *word)
}
-static void
-term_body(struct termp *p, struct termpair *ppair,
- const struct mdoc_meta *meta,
- const struct mdoc_node *node)
-{
-
- term_node(p, ppair, meta, node);
- if (node->next)
- term_body(p, ppair, meta, node->next);
-}
-
-
-/*
- * This is the main function for printing out nodes. It's constituted
- * of PRE and POST functions, which correspond to prefix and infix
- * processing. The termpair structure allows data to persist between
- * prefix and postfix invocations.
- */
-void
-term_node(struct termp *p, struct termpair *ppair,
- const struct mdoc_meta *meta,
- const struct mdoc_node *node)
-{
- int dochild;
- struct termpair pair;
-
- /* Some quick sanity-checking. */
-
- sanity(node);
-
- /* Pre-processing. */
-
- dochild = 1;
- pair.ppair = ppair;
- pair.type = 0;
- pair.offset = pair.rmargin = 0;
- pair.flag = 0;
- pair.count = 0;
-
- if (MDOC_TEXT != node->type) {
- if (termacts[node->tok].pre)
- if ( ! (*termacts[node->tok].pre)(p, &pair, meta, node))
- dochild = 0;
- } else /* MDOC_TEXT == node->type */
- term_word(p, node->string);
-
- /* Children. */
-
- if (TERMPAIR_FLAG & pair.type)
- p->flags |= pair.flag;
-
- if (dochild && node->child)
- term_body(p, &pair, meta, node->child);
-
- if (TERMPAIR_FLAG & pair.type)
- p->flags &= ~pair.flag;
-
- /* Post-processing. */
-
- if (MDOC_TEXT != node->type)
- if (termacts[node->tok].post)
- (*termacts[node->tok].post)(p, &pair, meta, node);
-}
-
-
-static void
-term_foot(struct termp *p, const struct mdoc_meta *meta)
-{
- struct tm *tm;
- char *buf, *os;
-
- if (NULL == (buf = malloc(p->rmargin)))
- err(1, "malloc");
- if (NULL == (os = malloc(p->rmargin)))
- err(1, "malloc");
-
- tm = localtime(&meta->date);
-
-#ifdef __OpenBSD__
- if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
-#else
- if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
-#endif
- err(1, "strftime");
-
- (void)strlcpy(os, meta->os, p->rmargin);
-
- /*
- * This is /slightly/ different from regular groff output
- * because we don't have page numbers. Print the following:
- *
- * OS MDOCDATE
- */
-
- term_vspace(p);
-
- p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
- p->rmargin = p->maxrmargin - strlen(buf);
- p->offset = 0;
-
- term_word(p, os);
- term_flushln(p);
-
- p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
- p->offset = p->rmargin;
- p->rmargin = p->maxrmargin;
- p->flags &= ~TERMP_NOBREAK;
-
- term_word(p, buf);
- term_flushln(p);
-
- free(buf);
- free(os);
-}
-
-
-static void
-term_head(struct termp *p, const struct mdoc_meta *meta)
-{
- char *buf, *title;
-
- p->rmargin = p->maxrmargin;
- p->offset = 0;
-
- if (NULL == (buf = malloc(p->rmargin)))
- err(1, "malloc");
- if (NULL == (title = malloc(p->rmargin)))
- err(1, "malloc");
-
- /*
- * The header is strange. It has three components, which are
- * really two with the first duplicated. It goes like this:
- *
- * IDENTIFIER TITLE IDENTIFIER
- *
- * The IDENTIFIER is NAME(SECTION), which is the command-name
- * (if given, or "unknown" if not) followed by the manual page
- * section. These are given in `Dt'. The TITLE is a free-form
- * string depending on the manual volume. If not specified, it
- * switches on the manual section.
- */
-
- assert(meta->vol);
- (void)strlcpy(buf, meta->vol, p->rmargin);
-
- if (meta->arch) {
- (void)strlcat(buf, " (", p->rmargin);
- (void)strlcat(buf, meta->arch, p->rmargin);
- (void)strlcat(buf, ")", p->rmargin);
- }
-
- (void)snprintf(title, p->rmargin, "%s(%d)",
- meta->title, meta->msec);
-
- p->offset = 0;
- p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
- p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
-
- term_word(p, title);
- term_flushln(p);
-
- p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
- p->offset = p->rmargin;
- p->rmargin = p->maxrmargin - strlen(title);
-
- term_word(p, buf);
- term_flushln(p);
-
- p->offset = p->rmargin;
- p->rmargin = p->maxrmargin;
- p->flags &= ~TERMP_NOBREAK;
- p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
-
- term_word(p, title);
- term_flushln(p);
-
- p->rmargin = p->maxrmargin;
- p->offset = 0;
- p->flags &= ~TERMP_NOSPACE;
-
- free(title);
- free(buf);
-}
-
-
/*
* Determine the symbol indicated by an escape sequences, that is, one
* starting with a backslash. Once done, we pass this value into the
@@ -765,112 +577,3 @@ term_chara(struct termp *p, char c)
p->buf[(int)(p->col)++] = c;
}
-
-static void
-sanity(const struct mdoc_node *n)
-{
-
- switch (n->type) {
- case (MDOC_TEXT):
- if (n->child)
- errx(1, "regular form violated (1)");
- if (NULL == n->parent)
- errx(1, "regular form violated (2)");
- if (NULL == n->string)
- errx(1, "regular form violated (3)");
- switch (n->parent->type) {
- case (MDOC_TEXT):
- /* FALLTHROUGH */
- case (MDOC_ROOT):
- errx(1, "regular form violated (4)");
- /* NOTREACHED */
- default:
- break;
- }
- break;
- case (MDOC_ELEM):
- if (NULL == n->parent)
- errx(1, "regular form violated (5)");
- switch (n->parent->type) {
- case (MDOC_TAIL):
- /* FALLTHROUGH */
- case (MDOC_BODY):
- /* FALLTHROUGH */
- case (MDOC_HEAD):
- break;
- default:
- errx(1, "regular form violated (6)");
- /* NOTREACHED */
- }
- if (n->child) switch (n->child->type) {
- case (MDOC_TEXT):
- break;
- default:
- errx(1, "regular form violated (7(");
- /* NOTREACHED */
- }
- break;
- case (MDOC_HEAD):
- /* FALLTHROUGH */
- case (MDOC_BODY):
- /* FALLTHROUGH */
- case (MDOC_TAIL):
- if (NULL == n->parent)
- errx(1, "regular form violated (8)");
- if (MDOC_BLOCK != n->parent->type)
- errx(1, "regular form violated (9)");
- if (n->child) switch (n->child->type) {
- case (MDOC_BLOCK):
- /* FALLTHROUGH */
- case (MDOC_ELEM):
- /* FALLTHROUGH */
- case (MDOC_TEXT):
- break;
- default:
- errx(1, "regular form violated (a)");
- /* NOTREACHED */
- }
- break;
- case (MDOC_BLOCK):
- if (NULL == n->parent)
- errx(1, "regular form violated (b)");
- if (NULL == n->child)
- errx(1, "regular form violated (c)");
- switch (n->parent->type) {
- case (MDOC_ROOT):
- /* FALLTHROUGH */
- case (MDOC_HEAD):
- /* FALLTHROUGH */
- case (MDOC_BODY):
- /* FALLTHROUGH */
- case (MDOC_TAIL):
- break;
- default:
- errx(1, "regular form violated (d)");
- /* NOTREACHED */
- }
- switch (n->child->type) {
- case (MDOC_ROOT):
- /* FALLTHROUGH */
- case (MDOC_ELEM):
- errx(1, "regular form violated (e)");
- /* NOTREACHED */
- default:
- break;
- }
- break;
- case (MDOC_ROOT):
- if (n->parent)
- errx(1, "regular form violated (f)");
- if (NULL == n->child)
- errx(1, "regular form violated (10)");
- switch (n->child->type) {
- case (MDOC_BLOCK):
- break;
- default:
- errx(1, "regular form violated (11)");
- /* NOTREACHED */
- }
- break;
- }
-}