summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libman.h6
-rw-r--r--man.c80
-rw-r--r--man.h6
-rw-r--r--man_action.c30
-rw-r--r--man_html.c8
-rw-r--r--man_macro.c112
-rw-r--r--man_term.c8
-rw-r--r--man_validate.c26
8 files changed, 233 insertions, 43 deletions
diff --git a/libman.h b/libman.h
index a4d5cbb5..747abfa9 100644
--- a/libman.h
+++ b/libman.h
@@ -60,6 +60,7 @@ enum merr {
WNOSCOPE,
WOLITERAL,
WNLITERAL,
+ WROFFNEST,
WERRMAX
};
@@ -73,6 +74,7 @@ struct man_macro {
#define MAN_EXPLICIT (1 << 1) /* See blk_imp(). */
#define MAN_FSCOPED (1 << 2) /* See blk_imp(). */
#define MAN_NSCOPED (1 << 3) /* See in_line_eoln(). */
+#define MAN_NOCLOSE (1 << 4) /* See blk_exp(). */
};
extern const struct man_macro *const man_macros;
@@ -93,9 +95,7 @@ int man_block_alloc(struct man *, int, int, enum mant);
int man_head_alloc(struct man *, int, int, enum mant);
int man_body_alloc(struct man *, int, int, enum mant);
int man_elem_alloc(struct man *, int, int, enum mant);
-void man_node_free(struct man_node *);
-void man_node_freelist(struct man_node *);
-void man_node_unlink(struct man *, struct man_node *);
+void man_node_delete(struct man *, struct man_node *);
void man_hash_init(void);
enum mant man_hash_find(const char *);
int man_macroend(struct man *);
diff --git a/man.c b/man.c
index 986efec6..bf3754a8 100644
--- a/man.c
+++ b/man.c
@@ -49,7 +49,8 @@ const char *const __man_merrnames[WERRMAX] = {
"scope open on exit", /* WEXITSCOPE */
"no scope context", /* WNOSCOPE */
"literal context already open", /* WOLITERAL */
- "no literal context open" /* WNLITERAL */
+ "no literal context open", /* WNLITERAL */
+ "invalid nesting of roff declarations", /* WROFFNEST */
};
const char *const __man_macronames[MAN_MAX] = {
@@ -61,7 +62,9 @@ const char *const __man_macronames[MAN_MAX] = {
"RI", "na", "i", "sp",
"nf", "fi", "r", "RE",
"RS", "DT", "UC", "PD",
- "Sp", "Vb", "Ve",
+ "Sp", "Vb", "Ve", "de",
+ "dei", "am", "ami", "ig",
+ ".",
};
const char * const *man_macronames = __man_macronames;
@@ -70,6 +73,9 @@ static struct man_node *man_node_alloc(int, int,
enum man_type, enum mant);
static int man_node_append(struct man *,
struct man_node *);
+static void man_node_free(struct man_node *);
+static void man_node_unlink(struct man *,
+ struct man_node *);
static int man_ptext(struct man *, int, char *);
static int man_pmacro(struct man *, int, char *);
static void man_free1(struct man *);
@@ -160,7 +166,7 @@ man_free1(struct man *man)
{
if (man->first)
- man_node_freelist(man->first);
+ man_node_delete(man, man->first);
if (man->meta.title)
free(man->meta.title);
if (man->meta.source)
@@ -179,6 +185,7 @@ man_alloc1(struct man *m)
m->last = mandoc_calloc(1, sizeof(struct man_node));
m->first = m->last;
m->last->type = MAN_ROOT;
+ m->last->tok = MAN_MAX;
m->next = MAN_NEXT_CHILD;
}
@@ -206,6 +213,7 @@ man_node_append(struct man *man, struct man_node *p)
/* NOTREACHED */
}
+ assert(p->parent);
p->parent->nchild++;
if ( ! man_valid_pre(man, p))
@@ -336,30 +344,29 @@ man_word_alloc(struct man *m, int line, int pos, const char *word)
}
-void
+/*
+ * Free all of the resources held by a node. This does NOT unlink a
+ * node from its context; for that, see man_node_unlink().
+ */
+static void
man_node_free(struct man_node *p)
{
if (p->string)
free(p->string);
- if (p->parent)
- p->parent->nchild--;
free(p);
}
void
-man_node_freelist(struct man_node *p)
+man_node_delete(struct man *m, struct man_node *p)
{
- struct man_node *n;
- if (p->child)
- man_node_freelist(p->child);
- assert(0 == p->nchild);
- n = p->next;
+ while (p->child)
+ man_node_delete(m, p->child);
+
+ man_node_unlink(m, p);
man_node_free(p);
- if (n)
- man_node_freelist(n);
}
@@ -568,8 +575,7 @@ man_pmacro(struct man *m, int ln, char *buf)
if ( ! man_nwarn(m, n, WLNSCOPE))
return(0);
- man_node_unlink(m, n);
- man_node_free(n);
+ man_node_delete(m, n);
m->flags &= ~MAN_ELINE;
}
@@ -584,6 +590,9 @@ out:
/*
* We weren't in a block-line scope when entering the
* above-parsed macro, so return.
+ *
+ * FIXME: this prohibits the nesting of blocks (e.g., `de' and
+ * family) within BLINE or ELINE systems. This is annoying.
*/
if ( ! (MAN_BLINE & fl)) {
@@ -672,26 +681,43 @@ man_err(struct man *m, int line, int pos, int iserr, enum merr type)
}
-void
+/*
+ * Unlink a node from its context. If "m" is provided, the last parse
+ * point will also be adjusted accordingly.
+ */
+static void
man_node_unlink(struct man *m, struct man_node *n)
{
- if (n->prev) {
+ /* Adjust siblings. */
+
+ if (n->prev)
n->prev->next = n->next;
- if (m->last == n) {
- assert(NULL == n->next);
+ if (n->next)
+ n->next->prev = n->prev;
+
+ /* Adjust parent. */
+
+ if (n->parent) {
+ n->parent->nchild--;
+ if (n->parent->child == n)
+ n->parent->child = n->prev ? n->prev : n->next;
+ }
+
+ /* Adjust parse point, if applicable. */
+
+ if (m && m->last == n) {
+ /*XXX: this can occur when bailing from validation. */
+ /*assert(NULL == n->next);*/
+ if (n->prev) {
m->last = n->prev;
m->next = MAN_NEXT_SIBLING;
- }
- } else {
- n->parent->child = n->next;
- if (m->last == n) {
- assert(NULL == n->next);
+ } else {
m->last = n->parent;
m->next = MAN_NEXT_CHILD;
}
}
- if (n->next)
- n->next->prev = n->prev;
+ if (m && m->first == n)
+ m->first = NULL;
}
diff --git a/man.h b/man.h
index 872fbf48..55662828 100644
--- a/man.h
+++ b/man.h
@@ -55,6 +55,12 @@ enum mant {
MAN_Sp,
MAN_Vb,
MAN_Ve,
+ MAN_de,
+ MAN_dei,
+ MAN_am,
+ MAN_ami,
+ MAN_ig,
+ MAN_dot,
MAN_MAX,
};
diff --git a/man_action.c b/man_action.c
index 7634b5fd..6cd24666 100644
--- a/man_action.c
+++ b/man_action.c
@@ -30,6 +30,7 @@ struct actions {
};
static int post_TH(struct man *);
+static int post_de(struct man *);
static int post_fi(struct man *);
static int post_nf(struct man *);
@@ -69,6 +70,12 @@ const struct actions man_actions[MAN_MAX] = {
{ NULL }, /* Sp */
{ post_nf }, /* Vb */
{ post_fi }, /* Ve */
+ { post_de }, /* de */
+ { post_de }, /* dei */
+ { post_de }, /* am */
+ { post_de }, /* ami */
+ { post_de }, /* ig */
+ { NULL }, /* . */
};
@@ -108,6 +115,21 @@ post_fi(struct man *m)
static int
+post_de(struct man *m)
+{
+
+ /*
+ * XXX: for the time being, we indiscriminately remove roff
+ * instructions from the parse stream.
+ */
+ if (MAN_BLOCK == m->last->type)
+ man_node_delete(m, m->last);
+
+ return(1);
+}
+
+
+static int
post_nf(struct man *m)
{
@@ -179,8 +201,10 @@ post_TH(struct man *m)
if (n && (n = n->next))
m->meta.vol = mandoc_strdup(n->string);
- n = m->last;
- man_node_unlink(m, n);
- man_node_freelist(n);
+ /*
+ * Remove the `TH' node after we've processed it for our
+ * meta-data.
+ */
+ man_node_delete(m, m->last);
return(1);
}
diff --git a/man_html.c b/man_html.c
index 37357cc8..ffd721db 100644
--- a/man_html.c
+++ b/man_html.c
@@ -105,7 +105,13 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_ign_pre, NULL }, /* PD */
{ man_br_pre, NULL }, /* Sp */
{ man_ign_pre, NULL }, /* Vb */
- { NULL, NULL }, /* Vi */
+ { NULL, NULL }, /* Ve */
+ { man_ign_pre, NULL }, /* de */
+ { man_ign_pre, NULL }, /* dei */
+ { man_ign_pre, NULL }, /* am */
+ { man_ign_pre, NULL }, /* ami */
+ { man_ign_pre, NULL }, /* ig */
+ { NULL, NULL }, /* . */
};
diff --git a/man_macro.c b/man_macro.c
index 372c65bc..d8b1122b 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -31,9 +31,11 @@ enum rew {
REW_HALT,
};
-static int in_line_eoln(MACRO_PROT_ARGS);
-static int blk_imp(MACRO_PROT_ARGS);
static int blk_close(MACRO_PROT_ARGS);
+static int blk_dotted(MACRO_PROT_ARGS);
+static int blk_exp(MACRO_PROT_ARGS);
+static int blk_imp(MACRO_PROT_ARGS);
+static int in_line_eoln(MACRO_PROT_ARGS);
static int rew_scope(enum man_type,
struct man *, enum mant);
@@ -71,13 +73,19 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, 0 }, /* fi */
{ in_line_eoln, 0 }, /* r */
{ blk_close, 0 }, /* RE */
- { blk_imp, MAN_EXPLICIT }, /* RS */
+ { blk_exp, MAN_EXPLICIT }, /* RS */
{ in_line_eoln, 0 }, /* DT */
{ in_line_eoln, 0 }, /* UC */
{ in_line_eoln, 0 }, /* PD */
{ in_line_eoln, MAN_NSCOPED }, /* Sp */
{ in_line_eoln, 0 }, /* Vb */
{ in_line_eoln, 0 }, /* Ve */
+ { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* de */
+ { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* dei */
+ { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* am */
+ { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* ami */
+ { blk_exp, MAN_EXPLICIT | MAN_NOCLOSE}, /* ig */
+ { blk_dotted, 0 }, /* . */
};
const struct man_macro * const man_macros = __man_macros;
@@ -88,7 +96,6 @@ man_unscope(struct man *m, const struct man_node *n)
{
assert(n);
- m->next = MAN_NEXT_SIBLING;
/* LINTED */
while (m->last != n) {
@@ -102,7 +109,13 @@ man_unscope(struct man *m, const struct man_node *n)
if ( ! man_valid_post(m))
return(0);
- return(man_action_post(m));
+ if ( ! man_action_post(m))
+ return(0);
+
+ m->next = MAN_ROOT == m->last->type ?
+ MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
+
+ return(1);
}
@@ -206,6 +219,37 @@ rew_scope(enum man_type type, struct man *m, enum mant tok)
/* ARGSUSED */
int
+blk_dotted(MACRO_PROT_ARGS)
+{
+ enum mant ntok;
+ struct man_node *nn;
+
+ for (nn = m->last->parent; nn; nn = nn->parent)
+ if (nn->tok == MAN_de || nn->tok == MAN_dei ||
+ nn->tok == MAN_am ||
+ nn->tok == MAN_ami ||
+ nn->tok == MAN_ig) {
+ ntok = nn->tok;
+ break;
+ }
+
+ if (NULL == nn) {
+ if ( ! man_pwarn(m, line, ppos, WNOSCOPE))
+ return(0);
+ return(1);
+ }
+
+ if ( ! rew_scope(MAN_BODY, m, ntok))
+ return(0);
+ if ( ! rew_scope(MAN_BLOCK, m, ntok))
+ return(0);
+
+ return(1);
+}
+
+
+/* ARGSUSED */
+int
blk_close(MACRO_PROT_ARGS)
{
enum mant ntok;
@@ -232,11 +276,61 @@ blk_close(MACRO_PROT_ARGS)
return(0);
if ( ! rew_scope(MAN_BLOCK, m, ntok))
return(0);
- m->next = MAN_NEXT_SIBLING;
+
return(1);
}
+int
+blk_exp(MACRO_PROT_ARGS)
+{
+ int w, la;
+ char *p;
+ struct man_node *n;
+
+ /*
+ * Close out prior scopes. "Regular" explicit macros cannot be
+ * nested, but we allow roff macros to be placed just about
+ * anywhere.
+ */
+
+ if ( ! (MAN_NOCLOSE & man_macros[tok].flags)) {
+ if ( ! rew_scope(MAN_BODY, m, tok))
+ return(0);
+ if ( ! rew_scope(MAN_BLOCK, m, tok))
+ return(0);
+ }
+
+ if ( ! man_block_alloc(m, line, ppos, tok))
+ return(0);
+ if ( ! man_head_alloc(m, line, ppos, tok))
+ return(0);
+
+ n = m->last;
+
+ for (;;) {
+ la = *pos;
+ w = man_args(m, line, pos, buf, &p);
+
+ if (-1 == w)
+ return(0);
+ if (0 == w)
+ break;
+
+ if ( ! man_word_alloc(m, line, la, p))
+ return(0);
+ }
+
+ assert(m);
+ assert(tok != MAN_MAX);
+
+ if ( ! rew_scope(MAN_HEAD, m, tok))
+ return(0);
+ return(man_body_alloc(m, line, ppos, tok));
+}
+
+
+
/*
* Parse an implicit-block macro. These contain a MAN_HEAD and a
* MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
@@ -296,7 +390,6 @@ blk_imp(MACRO_PROT_ARGS)
if ( ! rew_scope(MAN_HEAD, m, tok))
return(0);
-
return(man_body_alloc(m, line, ppos, tok));
}
@@ -371,8 +464,9 @@ in_line_eoln(MACRO_PROT_ARGS)
return(0);
if (m->last->type != MAN_ROOT && ! man_action_post(m))
return(0);
- if (m->last->type != MAN_ROOT)
- m->next = MAN_NEXT_SIBLING;
+
+ m->next = MAN_ROOT == m->last->type ?
+ MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
return(1);
}
diff --git a/man_term.c b/man_term.c
index 19489b71..1715ff26 100644
--- a/man_term.c
+++ b/man_term.c
@@ -142,6 +142,12 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_sp, NULL, MAN_NOTEXT }, /* Sp */
{ pre_nf, NULL, 0 }, /* Vb */
{ pre_fi, NULL, 0 }, /* Ve */
+ { pre_ign, NULL, MAN_NOTEXT }, /* de */
+ { pre_ign, NULL, MAN_NOTEXT }, /* dei */
+ { pre_ign, NULL, MAN_NOTEXT }, /* am */
+ { pre_ign, NULL, MAN_NOTEXT }, /* ami */
+ { pre_ign, NULL, MAN_NOTEXT }, /* ig */
+ { NULL, NULL, 0 }, /* . */
};
@@ -785,6 +791,8 @@ post_RS(DECL_ARGS)
case (MAN_BLOCK):
mt->offset = mt->lmargin = INDENT;
break;
+ case (MAN_HEAD):
+ break;
default:
term_newln(p);
p->offset = INDENT;
diff --git a/man_validate.c b/man_validate.c
index 6d0c5e4d..6787d911 100644
--- a/man_validate.c
+++ b/man_validate.c
@@ -46,6 +46,7 @@ static int check_ge2(CHKARGS);
static int check_le5(CHKARGS);
static int check_par(CHKARGS);
static int check_part(CHKARGS);
+static int check_roff(CHKARGS);
static int check_root(CHKARGS);
static int check_sec(CHKARGS);
static int check_text(CHKARGS);
@@ -57,6 +58,7 @@ static v_check posts_part[] = { check_part, NULL };
static v_check posts_sec[] = { check_sec, NULL };
static v_check posts_le1[] = { check_le1, NULL };
static v_check pres_bline[] = { check_bline, NULL };
+static v_check pres_roff[] = { check_bline, check_roff, NULL };
static const struct man_valid man_valids[MAN_MAX] = {
{ NULL, posts_eq0 }, /* br */
@@ -94,6 +96,12 @@ static const struct man_valid man_valids[MAN_MAX] = {
{ NULL, posts_eq0 }, /* Sp */
{ pres_bline, posts_le1 }, /* Vb */
{ pres_bline, posts_eq0 }, /* Ve */
+ { pres_roff, NULL }, /* de */
+ { pres_roff, NULL }, /* dei */
+ { pres_roff, NULL }, /* am */
+ { pres_roff, NULL }, /* ami */
+ { pres_roff, NULL }, /* ig */
+ { NULL, NULL }, /* . */
};
@@ -284,6 +292,24 @@ check_bline(CHKARGS)
assert( ! (MAN_ELINE & m->flags));
if (MAN_BLINE & m->flags)
return(man_nerr(m, n, WLNSCOPE));
+
return(1);
}
+
+static int
+check_roff(CHKARGS)
+{
+
+ if (MAN_BLOCK != n->type)
+ return(1);
+
+ for (n = n->parent; n; n = n->parent)
+ if (MAN_de == n->tok || MAN_dei == n->tok ||
+ MAN_am == n->tok ||
+ MAN_ami == n->tok ||
+ MAN_ig == n->tok)
+ return(man_nerr(m, n, WROFFNEST));
+
+ return(1);
+}