-/* $Id: mdoc_action.c,v 1.37 2009/09/16 20:49:06 kristaps Exp $ */
+/* $Id: mdoc_action.c,v 1.41 2009/09/25 13:03:25 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
*
int (*post)(POST_ARGS);
};
+static int concat(struct mdoc *,
+ const struct mdoc_node *,
+ char *, size_t);
+static inline int order_rs(int);
+
+#ifdef __linux__
+extern size_t strlcat(char *, const char *, size_t);
+#endif
+
static int post_ar(POST_ARGS);
static int post_at(POST_ARGS);
static int post_bl(POST_ARGS);
static int post_nm(POST_ARGS);
static int post_os(POST_ARGS);
static int post_prol(POST_ARGS);
+static int post_rs(POST_ARGS);
static int post_sh(POST_ARGS);
static int post_st(POST_ARGS);
static int post_std(POST_ARGS);
static int post_tilde(POST_ARGS);
static int pre_bd(PRE_ARGS);
+static int pre_bl(PRE_ARGS);
static int pre_dl(PRE_ARGS);
+static int pre_offset(PRE_ARGS);
static const struct actions mdoc_actions[MDOC_MAX] = {
{ NULL, NULL }, /* Ap */
{ pre_dl, post_display }, /* Dl */
{ pre_bd, post_display }, /* Bd */
{ NULL, NULL }, /* Ed */
- { NULL, post_bl }, /* Bl */
+ { pre_bl, post_bl }, /* Bl */
{ NULL, NULL }, /* El */
{ NULL, NULL }, /* It */
{ NULL, NULL }, /* Ad */
{ NULL, NULL }, /* Qo */
{ NULL, NULL }, /* Qq */
{ NULL, NULL }, /* Re */
- { NULL, NULL }, /* Rs */
+ { NULL, post_rs }, /* Rs */
{ NULL, NULL }, /* Sc */
{ NULL, NULL }, /* So */
{ NULL, NULL }, /* Sq */
{ NULL, NULL }, /* sp */
};
-static int concat(struct mdoc *, const struct mdoc_node *,
- char *, size_t);
-
-#ifdef __linux__
-extern size_t strlcat(char *, const char *, size_t);
-#endif
+#define RSORD_MAX 13
+
+static const int rsord[RSORD_MAX] = {
+ MDOC__A,
+ MDOC__T,
+ MDOC__B,
+ MDOC__I,
+ MDOC__J,
+ MDOC__R,
+ MDOC__N,
+ MDOC__V,
+ MDOC__P,
+ MDOC__Q,
+ MDOC__D,
+ MDOC__O,
+ MDOC__C
+};
int
}
+static int
+pre_offset(PRE_ARGS)
+{
+ int i;
+
+ /*
+ * Make sure that an empty offset produces an 8n length space as
+ * stipulated by mdoc.samples.
+ */
+
+ assert(n->args);
+ for (i = 0; i < (int)n->args->argc; i++) {
+ if (MDOC_Offset != n->args->argv[i].arg)
+ continue;
+ if (n->args->argv[i].sz)
+ break;
+ assert(1 == n->args->refcnt);
+ /* If no value set, length of <string>. */
+ n->args->argv[i].value =
+ calloc(1, sizeof(char *));
+ if (NULL == n->args->argv[i].value)
+ return(mdoc_nerr(m, n, EMALLOC));
+ n->args->argv[i].sz++;
+ n->args->argv[i].value[0] = strdup("8n");
+ if (NULL == n->args->argv[i].value[0])
+ return(mdoc_nerr(m, n, EMALLOC));
+ break;
+ }
+
+ return(1);
+}
+
+
+static int
+pre_bl(PRE_ARGS)
+{
+
+ return(MDOC_BLOCK == n->type ? pre_offset(m, n) : 1);
+}
+
+
static int
pre_bd(PRE_ARGS)
{
int i;
+ if (MDOC_BLOCK == n->type)
+ return(pre_offset(m, n));
if (MDOC_BODY != n->type)
return(1);
/* Enter literal context if `Bd -literal' or `-unfilled'. */
- /*
- * TODO: `-offset' without an argument should be the width of
- * the literal "<string>".
- */
-
for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
if (MDOC_Literal == n->args->argv[i].arg)
- break;
+ m->flags |= MDOC_LITERAL;
else if (MDOC_Unfilled == n->args->argv[i].arg)
- break;
-
- if (i < (int)n->args->argc)
- m->flags |= MDOC_LITERAL;
+ m->flags |= MDOC_LITERAL;
return(1);
}
}
+static inline int
+order_rs(int t)
+{
+ int i;
+
+ for (i = 0; i < RSORD_MAX; i++)
+ if (rsord[i] == t)
+ return(i);
+
+ abort();
+ /* NOTREACHED */
+}
+
+
+/* ARGSUSED */
+static int
+post_rs(POST_ARGS)
+{
+ struct mdoc_node *nn, *next, *prev;
+ int o;
+
+ if (MDOC_BLOCK != n->type)
+ return(1);
+
+ assert(n->body->child);
+ for (next = NULL, nn = n->body->child->next; nn; nn = next) {
+ o = order_rs(nn->tok);
+
+ /* Remove `nn' from the chain. */
+ next = nn->next;
+ if (next)
+ next->prev = nn->prev;
+
+ prev = nn->prev;
+ if (prev)
+ prev->next = nn->next;
+
+ nn->prev = nn->next = NULL;
+
+ /*
+ * Scan back until we reach a node that's ordered before
+ * us, then set ourselves as being the next.
+ */
+ for ( ; prev; prev = prev->prev)
+ if (order_rs(prev->tok) <= o)
+ break;
+
+ nn->prev = prev;
+ if (prev) {
+ if (prev->next)
+ prev->next->prev = nn;
+ nn->next = prev->next;
+ prev->next = nn;
+ continue;
+ }
+
+ n->body->child->prev = nn;
+ nn->next = n->body->child;
+ n->body->child = nn;
+ }
+ return(1);
+}