File: [cvsweb.bsd.lv] / mandoc / Attic / mdoc_action.c (download)
Revision 1.73, Thu Jul 1 22:35:54 2010 UTC (13 years, 9 months ago) by schwarze
Branch: MAIN
Changes since 1.72: +12 -1 lines
In the mdoc(7) parser, inspect roff registers early such that all parts
of the parser can use the resulting cues. In particular, this allows
to use .nr nS to force SYNOPSIS-style .Nm indentation outside the
SYNOPSIS as needed by ifconfig(8).
To actually make this useable, .Pp must rewind .Nm, or the rest of the
section would end up indented. Implement a quick hack for now,
a generic solution can be designed later.
ok kristaps@ and tested by sobrado@
|
/* $Id: mdoc_action.c,v 1.73 2010/07/01 22:35:54 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef OSNAME
#include <sys/utsname.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mandoc.h"
#include "libmdoc.h"
#include "libmandoc.h"
/*
* FIXME: this file is deprecated. All future "actions" should be
* pushed into mdoc_validate.c.
*/
#define POST_ARGS struct mdoc *m, struct mdoc_node *n
#define PRE_ARGS struct mdoc *m, struct mdoc_node *n
#define NUMSIZ 32
#define DATESIZ 32
struct actions {
int (*pre)(PRE_ARGS);
int (*post)(POST_ARGS);
};
static int concat(struct mdoc *, char *,
const struct mdoc_node *, size_t);
static inline int order_rs(enum mdoct);
static int post_ar(POST_ARGS);
static int post_at(POST_ARGS);
static int post_bl(POST_ARGS);
static int post_bl_head(POST_ARGS);
static int post_bl_tagwidth(POST_ARGS);
static int post_bl_width(POST_ARGS);
static int post_dd(POST_ARGS);
static int post_display(POST_ARGS);
static int post_dt(POST_ARGS);
static int post_lb(POST_ARGS);
static int post_li(POST_ARGS);
static int post_nm(POST_ARGS);
static int post_os(POST_ARGS);
static int post_pa(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 pre_bd(PRE_ARGS);
static int pre_dl(PRE_ARGS);
static const struct actions mdoc_actions[MDOC_MAX] = {
{ NULL, NULL }, /* Ap */
{ NULL, post_dd }, /* Dd */
{ NULL, post_dt }, /* Dt */
{ NULL, post_os }, /* Os */
{ NULL, post_sh }, /* Sh */
{ NULL, NULL }, /* Ss */
{ NULL, NULL }, /* Pp */
{ NULL, NULL }, /* D1 */
{ pre_dl, post_display }, /* Dl */
{ pre_bd, post_display }, /* Bd */
{ NULL, NULL }, /* Ed */
{ NULL, post_bl }, /* Bl */
{ NULL, NULL }, /* El */
{ NULL, NULL }, /* It */
{ NULL, NULL }, /* Ad */
{ NULL, NULL }, /* An */
{ NULL, post_ar }, /* Ar */
{ NULL, NULL }, /* Cd */
{ NULL, NULL }, /* Cm */
{ NULL, NULL }, /* Dv */
{ NULL, NULL }, /* Er */
{ NULL, NULL }, /* Ev */
{ NULL, post_std }, /* Ex */
{ NULL, NULL }, /* Fa */
{ NULL, NULL }, /* Fd */
{ NULL, NULL }, /* Fl */
{ NULL, NULL }, /* Fn */
{ NULL, NULL }, /* Ft */
{ NULL, NULL }, /* Ic */
{ NULL, NULL }, /* In */
{ NULL, post_li }, /* Li */
{ NULL, NULL }, /* Nd */
{ NULL, post_nm }, /* Nm */
{ NULL, NULL }, /* Op */
{ NULL, NULL }, /* Ot */
{ NULL, post_pa }, /* Pa */
{ NULL, post_std }, /* Rv */
{ NULL, post_st }, /* St */
{ NULL, NULL }, /* Va */
{ NULL, NULL }, /* Vt */
{ NULL, NULL }, /* Xr */
{ NULL, NULL }, /* %A */
{ NULL, NULL }, /* %B */
{ NULL, NULL }, /* %D */
{ NULL, NULL }, /* %I */
{ NULL, NULL }, /* %J */
{ NULL, NULL }, /* %N */
{ NULL, NULL }, /* %O */
{ NULL, NULL }, /* %P */
{ NULL, NULL }, /* %R */
{ NULL, NULL }, /* %T */
{ NULL, NULL }, /* %V */
{ NULL, NULL }, /* Ac */
{ NULL, NULL }, /* Ao */
{ NULL, NULL }, /* Aq */
{ NULL, post_at }, /* At */
{ NULL, NULL }, /* Bc */
{ NULL, NULL }, /* Bf */
{ NULL, NULL }, /* Bo */
{ NULL, NULL }, /* Bq */
{ NULL, NULL }, /* Bsx */
{ NULL, NULL }, /* Bx */
{ NULL, NULL }, /* Db */
{ NULL, NULL }, /* Dc */
{ NULL, NULL }, /* Do */
{ NULL, NULL }, /* Dq */
{ NULL, NULL }, /* Ec */
{ NULL, NULL }, /* Ef */
{ NULL, NULL }, /* Em */
{ NULL, NULL }, /* Eo */
{ NULL, NULL }, /* Fx */
{ NULL, NULL }, /* Ms */
{ NULL, NULL }, /* No */
{ NULL, NULL }, /* Ns */
{ NULL, NULL }, /* Nx */
{ NULL, NULL }, /* Ox */
{ NULL, NULL }, /* Pc */
{ NULL, NULL }, /* Pf */
{ NULL, NULL }, /* Po */
{ NULL, NULL }, /* Pq */
{ NULL, NULL }, /* Qc */
{ NULL, NULL }, /* Ql */
{ NULL, NULL }, /* Qo */
{ NULL, NULL }, /* Qq */
{ NULL, NULL }, /* Re */
{ NULL, post_rs }, /* Rs */
{ NULL, NULL }, /* Sc */
{ NULL, NULL }, /* So */
{ NULL, NULL }, /* Sq */
{ NULL, NULL }, /* Sm */
{ NULL, NULL }, /* Sx */
{ NULL, NULL }, /* Sy */
{ NULL, NULL }, /* Tn */
{ NULL, NULL }, /* Ux */
{ NULL, NULL }, /* Xc */
{ NULL, NULL }, /* Xo */
{ NULL, NULL }, /* Fo */
{ NULL, NULL }, /* Fc */
{ NULL, NULL }, /* Oo */
{ NULL, NULL }, /* Oc */
{ NULL, NULL }, /* Bk */
{ NULL, NULL }, /* Ek */
{ NULL, NULL }, /* Bt */
{ NULL, NULL }, /* Hf */
{ NULL, NULL }, /* Fr */
{ NULL, NULL }, /* Ud */
{ NULL, post_lb }, /* Lb */
{ NULL, NULL }, /* Lp */
{ NULL, NULL }, /* Lk */
{ NULL, NULL }, /* Mt */
{ NULL, NULL }, /* Brq */
{ NULL, NULL }, /* Bro */
{ NULL, NULL }, /* Brc */
{ NULL, NULL }, /* %C */
{ NULL, NULL }, /* Es */
{ NULL, NULL }, /* En */
{ NULL, NULL }, /* Dx */
{ NULL, NULL }, /* %Q */
{ NULL, NULL }, /* br */
{ NULL, NULL }, /* sp */
{ NULL, NULL }, /* %U */
{ NULL, NULL }, /* Ta */
};
#define RSORD_MAX 14
static const enum mdoct 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,
MDOC__U
};
int
mdoc_action_pre(struct mdoc *m, struct mdoc_node *n)
{
switch (n->type) {
case (MDOC_ROOT):
/* FALLTHROUGH */
case (MDOC_TEXT):
return(1);
default:
break;
}
if (NULL == mdoc_actions[n->tok].pre)
return(1);
return((*mdoc_actions[n->tok].pre)(m, n));
}
int
mdoc_action_post(struct mdoc *m)
{
if (MDOC_ACTED & m->last->flags)
return(1);
m->last->flags |= MDOC_ACTED;
switch (m->last->type) {
case (MDOC_TEXT):
/* FALLTHROUGH */
case (MDOC_ROOT):
return(1);
default:
break;
}
if (NULL == mdoc_actions[m->last->tok].post)
return(1);
return((*mdoc_actions[m->last->tok].post)(m, m->last));
}
/*
* Concatenate sibling nodes together. All siblings must be of type
* MDOC_TEXT or an assertion is raised. Concatenation is separated by a
* single whitespace.
*/
static int
concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz)
{
assert(sz);
p[0] = '\0';
for ( ; n; n = n->next) {
assert(MDOC_TEXT == n->type);
/*
* XXX: yes, these can technically be resized, but it's
* highly unlikely that we're going to get here, so let
* it slip for now.
*/
if (strlcat(p, n->string, sz) >= sz) {
mdoc_nmsg(m, n, MANDOCERR_MEM);
return(0);
}
if (NULL == n->next)
continue;
if (strlcat(p, " ", sz) >= sz) {
mdoc_nmsg(m, n, MANDOCERR_MEM);
return(0);
}
}
return(1);
}
/*
* Macros accepting `-std' as an argument have the name of the current
* document (`Nm') filled in as the argument if it's not provided.
*/
static int
post_std(POST_ARGS)
{
struct mdoc_node *nn;
if (n->child)
return(1);
if (NULL == m->meta.name)
return(1);
nn = n;
m->next = MDOC_NEXT_CHILD;
if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
return(0);
m->last = nn;
return(1);
}
/*
* The `Nm' macro's first use sets the name of the document. See also
* post_std(), etc.
*/
static int
post_nm(POST_ARGS)
{
char buf[BUFSIZ];
if (m->meta.name)
return(1);
if ( ! concat(m, buf, n->child, BUFSIZ))
return(0);
m->meta.name = mandoc_strdup(buf);
return(1);
}
/*
* Look up the value of `Lb' for matching predefined strings. If it has
* one, then substitute the current value for the formatted value. Note
* that the lookup may fail (we can provide arbitrary strings).
*/
/* ARGSUSED */
static int
post_lb(POST_ARGS)
{
const char *p;
char *buf;
size_t sz;
assert(MDOC_TEXT == n->child->type);
p = mdoc_a2lib(n->child->string);
if (p) {
free(n->child->string);
n->child->string = mandoc_strdup(p);
return(1);
}
sz = strlen(n->child->string) +
2 + strlen("\\(lqlibrary\\(rq");
buf = mandoc_malloc(sz);
snprintf(buf, sz, "library \\(lq%s\\(rq", n->child->string);
free(n->child->string);
n->child->string = buf;
return(1);
}
/*
* Substitute the value of `St' for the corresponding formatted string.
* We're guaranteed that this exists (it's been verified during the
* validation phase).
*/
/* ARGSUSED */
static int
post_st(POST_ARGS)
{
const char *p;
assert(MDOC_TEXT == n->child->type);
p = mdoc_a2st(n->child->string);
if (p != NULL) {
free(n->child->string);
n->child->string = mandoc_strdup(p);
}
return(1);
}
/*
* Look up the standard string in a table. We know that it exists from
* the validation phase, so assert on failure. If a standard key wasn't
* supplied, supply the default ``AT&T UNIX''.
*/
static int
post_at(POST_ARGS)
{
struct mdoc_node *nn;
const char *p, *q;
char *buf;
size_t sz;
if (n->child) {
assert(MDOC_TEXT == n->child->type);
p = mdoc_a2att(n->child->string);
if (p) {
free(n->child->string);
n->child->string = mandoc_strdup(p);
} else {
p = "AT&T UNIX ";
q = n->child->string;
sz = strlen(p) + strlen(q) + 1;
buf = mandoc_malloc(sz);
strlcpy(buf, p, sz);
strlcat(buf, q, sz);
free(n->child->string);
n->child->string = buf;
}
return(1);
}
nn = n;
m->next = MDOC_NEXT_CHILD;
if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
return(0);
m->last = nn;
return(1);
}
/*
* Mark the current section. The ``named'' section (lastnamed) is set
* whenever the current section isn't a custom section--we use this to
* keep track of section ordering. Also check that the section is
* allowed within the document's manual section.
*/
static int
post_sh(POST_ARGS)
{
enum mdoc_sec sec;
char buf[BUFSIZ];
if (MDOC_HEAD != n->type)
return(1);
if ( ! concat(m, buf, n->child, BUFSIZ))
return(0);
sec = mdoc_str2sec(buf);
/*
* The first section should always make us move into a non-new
* state.
*/
if (SEC_NONE == m->lastnamed || SEC_CUSTOM != sec)
m->lastnamed = sec;
/*
* Switch the parser's SYNOPSIS mode, to be copied
* into individual nodes when creating them.
* Note that this mode can also be set and unset
* using the roff nS register.
*/
if (SEC_SYNOPSIS == sec)
m->flags |= MDOC_SYNOPSIS;
else
m->flags &= ~MDOC_SYNOPSIS;
/* Some sections only live in certain manual sections. */
switch ((m->lastsec = sec)) {
case (SEC_RETURN_VALUES):
/* FALLTHROUGH */
case (SEC_ERRORS):
assert(m->meta.msec);
if (*m->meta.msec == '2')
break;
if (*m->meta.msec == '3')
break;
if (*m->meta.msec == '9')
break;
return(mdoc_nmsg(m, n, MANDOCERR_SECMSEC));
default:
break;
}
return(1);
}
/*
* Parse out the contents of `Dt'. See in-line documentation for how we
* handle the various fields of this macro.
*/
static int
post_dt(POST_ARGS)
{
struct mdoc_node *nn;
const char *cp;
if (m->meta.title)
free(m->meta.title);
if (m->meta.vol)
free(m->meta.vol);
if (m->meta.arch)
free(m->meta.arch);
m->meta.title = m->meta.vol = m->meta.arch = NULL;
/* Handles: `.Dt'
* --> title = unknown, volume = local, msec = 0, arch = NULL
*/
if (NULL == (nn = n->child)) {
/* XXX: make these macro values. */
/* FIXME: warn about missing values. */
m->meta.title = mandoc_strdup("UNKNOWN");
m->meta.vol = mandoc_strdup("LOCAL");
m->meta.msec = mandoc_strdup("1");
return(post_prol(m, n));
}
/* Handles: `.Dt TITLE'
* --> title = TITLE, volume = local, msec = 0, arch = NULL
*/
m->meta.title = mandoc_strdup
('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
if (NULL == (nn = nn->next)) {
/* FIXME: warn about missing msec. */
/* XXX: make this a macro value. */
m->meta.vol = mandoc_strdup("LOCAL");
m->meta.msec = mandoc_strdup("1");
return(post_prol(m, n));
}
/* Handles: `.Dt TITLE SEC'
* --> title = TITLE, volume = SEC is msec ?
* format(msec) : SEC,
* msec = SEC is msec ? atoi(msec) : 0,
* arch = NULL
*/
cp = mdoc_a2msec(nn->string);
if (cp) {
m->meta.vol = mandoc_strdup(cp);
m->meta.msec = mandoc_strdup(nn->string);
} else if (mdoc_nmsg(m, n, MANDOCERR_BADMSEC)) {
m->meta.vol = mandoc_strdup(nn->string);
m->meta.msec = mandoc_strdup(nn->string);
} else
return(0);
if (NULL == (nn = nn->next))
return(post_prol(m, n));
/* Handles: `.Dt TITLE SEC VOL'
* --> title = TITLE, volume = VOL is vol ?
* format(VOL) :
* VOL is arch ? format(arch) :
* VOL
*/
cp = mdoc_a2vol(nn->string);
if (cp) {
free(m->meta.vol);
m->meta.vol = mandoc_strdup(cp);
} else {
/* FIXME: warn about bad arch. */
cp = mdoc_a2arch(nn->string);
if (NULL == cp) {
free(m->meta.vol);
m->meta.vol = mandoc_strdup(nn->string);
} else
m->meta.arch = mandoc_strdup(cp);
}
/* Ignore any subsequent parameters... */
/* FIXME: warn about subsequent parameters. */
return(post_prol(m, n));
}
/*
* Set the operating system by way of the `Os' macro. Note that if an
* argument isn't provided and -DOSNAME="\"foo\"" is provided during
* compilation, this value will be used instead of filling in "sysname
* release" from uname().
*/
static int
post_os(POST_ARGS)
{
char buf[BUFSIZ];
#ifndef OSNAME
struct utsname utsname;
#endif
if (m->meta.os)
free(m->meta.os);
if ( ! concat(m, buf, n->child, BUFSIZ))
return(0);
/* XXX: yes, these can all be dynamically-adjusted buffers, but
* it's really not worth the extra hackery.
*/
if ('\0' == buf[0]) {
#ifdef OSNAME
if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
mdoc_nmsg(m, n, MANDOCERR_MEM);
return(0);
}
#else /*!OSNAME */
if (-1 == uname(&utsname))
return(mdoc_nmsg(m, n, MANDOCERR_UTSNAME));
if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
mdoc_nmsg(m, n, MANDOCERR_MEM);
return(0);
}
if (strlcat(buf, " ", 64) >= BUFSIZ) {
mdoc_nmsg(m, n, MANDOCERR_MEM);
return(0);
}
if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
mdoc_nmsg(m, n, MANDOCERR_MEM);
return(0);
}
#endif /*!OSNAME*/
}
m->meta.os = mandoc_strdup(buf);
return(post_prol(m, n));
}
/*
* Calculate the -width for a `Bl -tag' list if it hasn't been provided.
* Uses the first head macro. NOTE AGAIN: this is ONLY if the -width
* argument has NOT been provided. See post_bl_width() for converting
* the -width string.
*/
static int
post_bl_tagwidth(POST_ARGS)
{
struct mdoc_node *nn;
size_t sz, ssz;
int i;
char buf[NUMSIZ];
sz = 10;
for (nn = n->body->child; nn; nn = nn->next) {
if (MDOC_It != nn->tok)
continue;
assert(MDOC_BLOCK == nn->type);
nn = nn->head->child;
if (MDOC_TEXT == nn->type) {
sz = strlen(nn->string) + 1;
break;
}
if (0 != (ssz = mdoc_macro2len(nn->tok)))
sz = ssz;
else if ( ! mdoc_nmsg(m, n, MANDOCERR_NOWIDTHARG))
return(0);
break;
}
/* Defaults to ten ens. */
snprintf(buf, NUMSIZ, "%zun", sz);
/*
* We have to dynamically add this to the macro's argument list.
* We're guaranteed that a MDOC_Width doesn't already exist.
*/
assert(n->args);
i = (int)(n->args->argc)++;
n->args->argv = mandoc_realloc(n->args->argv,
n->args->argc * sizeof(struct mdoc_argv));
n->args->argv[i].arg = MDOC_Width;
n->args->argv[i].line = n->line;
n->args->argv[i].pos = n->pos;
n->args->argv[i].sz = 1;
n->args->argv[i].value = mandoc_malloc(sizeof(char *));
n->args->argv[i].value[0] = mandoc_strdup(buf);
/* Set our width! */
n->data.Bl.width = n->args->argv[i].value[0];
return(1);
}
/*
* Calculate the real width of a list from the -width string, which may
* contain a macro (with a known default width), a literal string, or a
* scaling width.
*/
static int
post_bl_width(POST_ARGS)
{
size_t width;
int i;
enum mdoct tok;
char buf[NUMSIZ];
/*
* If the value to -width is a macro, then we re-write it to be
* the macro's width as set in share/tmac/mdoc/doc-common.
*/
if (0 == strcmp(n->data.Bl.width, "Ds"))
width = 6;
else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl.width)))
return(1);
else if (0 == (width = mdoc_macro2len(tok)))
return(mdoc_nmsg(m, n, MANDOCERR_BADWIDTH));
/* The value already exists: free and reallocate it. */
assert(n->args);
for (i = 0; i < (int)n->args->argc; i++)
if (MDOC_Width == n->args->argv[i].arg)
break;
assert(i < (int)n->args->argc);
snprintf(buf, NUMSIZ, "%zun", width);
free(n->args->argv[i].value[0]);
n->args->argv[i].value[0] = mandoc_strdup(buf);
/* Set our width! */
n->data.Bl.width = n->args->argv[i].value[0];
return(1);
}
/*
* Do processing for -column lists, which can have two distinct styles
* of invocation. Merge this two styles into a consistent form.
*/
/* ARGSUSED */
static int
post_bl_head(POST_ARGS)
{
int i, c;
struct mdoc_node *np, *nn, *nnp;
if (LIST_column != n->data.Bl.type)
return(1);
else if (NULL == n->child)
return(1);
np = n->parent;
assert(np->args);
for (c = 0; c < (int)np->args->argc; c++)
if (MDOC_Column == np->args->argv[c].arg)
break;
assert(c < (int)np->args->argc);
assert(0 == np->args->argv[c].sz);
/*
* Accomodate for new-style groff column syntax. Shuffle the
* child nodes, all of which must be TEXT, as arguments for the
* column field. Then, delete the head children.
*/
np->args->argv[c].sz = (size_t)n->nchild;
np->args->argv[c].value = mandoc_malloc
((size_t)n->nchild * sizeof(char *));
for (i = 0, nn = n->child; nn; i++) {
np->args->argv[c].value[i] = nn->string;
nn->string = NULL;
nnp = nn;
nn = nn->next;
mdoc_node_delete(NULL, nnp);
}
n->nchild = 0;
n->child = NULL;
return(1);
}
static int
post_bl(POST_ARGS)
{
struct mdoc_node *nn;
const char *ww;
if (MDOC_HEAD == n->type)
return(post_bl_head(m, n));
if (MDOC_BLOCK != n->type)
return(1);
/*
* These are fairly complicated, so we've broken them into two
* functions. post_bl_tagwidth() is called when a -tag is
* specified, but no -width (it must be guessed). The second
* when a -width is specified (macro indicators must be
* rewritten into real lengths).
*/
ww = n->data.Bl.width;
if (LIST_tag == n->data.Bl.type && NULL == n->data.Bl.width) {
if ( ! post_bl_tagwidth(m, n))
return(0);
} else if (NULL != n->data.Bl.width) {
if ( ! post_bl_width(m, n))
return(0);
} else
return(1);
assert(n->data.Bl.width);
/* If it has changed, propogate new width to children. */
if (ww == n->data.Bl.width)
return(1);
for (nn = n->child; nn; nn = nn->next)
if (MDOC_Bl == nn->tok)
nn->data.Bl.width = n->data.Bl.width;
return(1);
}
/*
* The `Pa' macro defaults to a tilde if no value is provided as an
* argument.
*/
static int
post_pa(POST_ARGS)
{
struct mdoc_node *np;
if (n->child)
return(1);
np = n;
m->next = MDOC_NEXT_CHILD;
if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
return(0);
m->last = np;
return(1);
}
/*
* Empty `Li' macros get an empty string to make front-ends add an extra
* space.
*/
static int
post_li(POST_ARGS)
{
struct mdoc_node *np;
if (n->child)
return(1);
np = n;
m->next = MDOC_NEXT_CHILD;
if ( ! mdoc_word_alloc(m, n->line, n->pos, ""))
return(0);
m->last = np;
return(1);
}
/*
* The `Ar' macro defaults to two strings "file ..." if no value is
* provided as an argument.
*/
static int
post_ar(POST_ARGS)
{
struct mdoc_node *np;
if (n->child)
return(1);
np = n;
m->next = MDOC_NEXT_CHILD;
/* XXX: make into macro values. */
if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
return(0);
if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
return(0);
m->last = np;
return(1);
}
/*
* Parse the date field in `Dd'.
*/
static int
post_dd(POST_ARGS)
{
char buf[DATESIZ];
if ( ! concat(m, buf, n->child, DATESIZ))
return(0);
m->meta.date = mandoc_a2time
(MTIME_MDOCDATE | MTIME_CANONICAL, buf);
if (0 == m->meta.date) {
if ( ! mdoc_nmsg(m, n, MANDOCERR_BADDATE))
return(0);
m->meta.date = time(NULL);
}
return(post_prol(m, n));
}
/*
* Remove prologue macros from the document after they're processed.
* The final document uses mdoc_meta for these values and discards the
* originals.
*/
static int
post_prol(POST_ARGS)
{
mdoc_node_delete(m, n);
if (m->meta.title && m->meta.date && m->meta.os)
m->flags |= MDOC_PBODY;
return(1);
}
/*
* Trigger a literal context.
*/
static int
pre_dl(PRE_ARGS)
{
if (MDOC_BODY == n->type)
m->flags |= MDOC_LITERAL;
return(1);
}
static int
pre_bd(PRE_ARGS)
{
if (MDOC_BODY != n->type)
return(1);
if (DISP_literal == n->data.Bd.type)
m->flags |= MDOC_LITERAL;
if (DISP_unfilled == n->data.Bd.type)
m->flags |= MDOC_LITERAL;
return(1);
}
static int
post_display(POST_ARGS)
{
if (MDOC_BODY == n->type)
m->flags &= ~MDOC_LITERAL;
return(1);
}
static inline int
order_rs(enum mdoct t)
{
int i;
for (i = 0; i < (int)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);
}