mdoc_term.c revision 95c635efb7c3b86efc493e0447eaec7aecca3f0f
/* $Id: mdoc_term.c,v 1.238 2011/11/13 13:15:14 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
#include "out.h"
#include "term.h"
#include "mdoc.h"
#include "main.h"
struct termpair {
int count;
};
const struct mdoc_meta *m, \
const struct mdoc_node *n
struct termact {
};
static void print_bvspace(struct termp *,
const struct mdoc_node *,
const struct mdoc_node *);
static void print_mdoc_node(DECL_ARGS);
static void print_mdoc_nodelist(DECL_ARGS);
static void print_mdoc_head(struct termp *, const void *);
static void print_mdoc_foot(struct termp *, const void *);
static void synopsis_pre(struct termp *,
const struct mdoc_node *);
static void termp____post(DECL_ARGS);
static void termp__t_post(DECL_ARGS);
static void termp_an_post(DECL_ARGS);
static void termp_bd_post(DECL_ARGS);
static void termp_bk_post(DECL_ARGS);
static void termp_bl_post(DECL_ARGS);
static void termp_d1_post(DECL_ARGS);
static void termp_fo_post(DECL_ARGS);
static void termp_in_post(DECL_ARGS);
static void termp_it_post(DECL_ARGS);
static void termp_lb_post(DECL_ARGS);
static void termp_nm_post(DECL_ARGS);
static void termp_pf_post(DECL_ARGS);
static void termp_quote_post(DECL_ARGS);
static void termp_sh_post(DECL_ARGS);
static void termp_ss_post(DECL_ARGS);
static int termp__a_pre(DECL_ARGS);
static int termp__t_pre(DECL_ARGS);
static int termp_an_pre(DECL_ARGS);
static int termp_ap_pre(DECL_ARGS);
static int termp_bd_pre(DECL_ARGS);
static int termp_bf_pre(DECL_ARGS);
static int termp_bk_pre(DECL_ARGS);
static int termp_bl_pre(DECL_ARGS);
static int termp_bold_pre(DECL_ARGS);
static int termp_bt_pre(DECL_ARGS);
static int termp_bx_pre(DECL_ARGS);
static int termp_cd_pre(DECL_ARGS);
static int termp_d1_pre(DECL_ARGS);
static int termp_ex_pre(DECL_ARGS);
static int termp_fa_pre(DECL_ARGS);
static int termp_fd_pre(DECL_ARGS);
static int termp_fl_pre(DECL_ARGS);
static int termp_fn_pre(DECL_ARGS);
static int termp_fo_pre(DECL_ARGS);
static int termp_ft_pre(DECL_ARGS);
static int termp_igndelim_pre(DECL_ARGS);
static int termp_in_pre(DECL_ARGS);
static int termp_it_pre(DECL_ARGS);
static int termp_li_pre(DECL_ARGS);
static int termp_lk_pre(DECL_ARGS);
static int termp_nd_pre(DECL_ARGS);
static int termp_nm_pre(DECL_ARGS);
static int termp_ns_pre(DECL_ARGS);
static int termp_quote_pre(DECL_ARGS);
static int termp_rs_pre(DECL_ARGS);
static int termp_rv_pre(DECL_ARGS);
static int termp_sh_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_under_pre(DECL_ARGS);
static int termp_ud_pre(DECL_ARGS);
static int termp_vt_pre(DECL_ARGS);
static int termp_xr_pre(DECL_ARGS);
static int termp_xx_pre(DECL_ARGS);
};
void
{
const struct mdoc_node *n;
const struct mdoc_meta *m;
struct termp *p;
if (0 == p->defindent)
p->defindent = 5;
p->overstep = 0;
p->maxrmargin = p->defrmargin;
p->symtab = mchars_alloc();
if (n->child)
term_end(p);
}
static void
{
print_mdoc_node(p, pair, m, n);
if (n->next)
}
/* ARGSUSED */
static void
{
int chld;
const void *font;
chld = 1;
font = term_fontq(p);
/*
* Keeps only work until the end of a line. If a keep was
* invoked in a prior line, revert it to PREKEEP.
*
* Also let SYNPRETTY sections behave as if they were wrapped
* in a `Bk' block.
*/
p->flags &= ~TERMP_KEEP;
p->flags |= TERMP_PREKEEP;
p->flags &= ~TERMP_KEEP;
p->flags |= TERMP_PREKEEP;
}
}
}
/*
* Since SYNPRETTY sections aren't "turned off" with `Ek',
* we have to intuit whether we should disable formatting.
*/
if ( ! (MDOC_SYNPRETTY & n->flags) &&
/*
* After the keep flags have been set up, we may now
* produce output. Note that some pre-handlers do so.
*/
switch (n->type) {
case (MDOC_TEXT):
term_newln(p);
if (MDOC_DELIMC & n->flags)
p->flags |= TERMP_NOSPACE;
if (MDOC_DELIMO & n->flags)
p->flags |= TERMP_NOSPACE;
break;
case (MDOC_EQN):
break;
case (MDOC_TBL):
break;
default:
(p, &npair, m, n);
break;
}
term_fontpopq(p, font);
switch (n->type) {
case (MDOC_TEXT):
break;
case (MDOC_TBL):
break;
case (MDOC_EQN):
break;
default:
break;
/*
* Explicit end tokens not only call the post
* handler, but also tell the respective block
* that it must not call the post handler again.
*/
if (ENDBODY_NOT != n->end)
/*
* End of line terminating an implicit block
* while an explicit block is still open.
* Continue the explicit block without spacing.
*/
if (ENDBODY_NOSPACE == n->end)
p->flags |= TERMP_NOSPACE;
break;
}
p->flags |= TERMP_SENTENCE;
}
static void
{
const struct mdoc_meta *m;
/*
* Output the footer in new-groff style, that is, three columns
* with the middle being the manual date and flanking columns
* being the operating system:
*
* SYSTEM DATE SYSTEM
*/
term_vspace(p);
p->offset = 0;
p->rmargin = (p->maxrmargin -
term_flushln(p);
p->flags |= TERMP_NOSPACE;
term_flushln(p);
p->rmargin = p->maxrmargin;
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
term_flushln(p);
p->offset = 0;
p->rmargin = p->maxrmargin;
p->flags = 0;
}
static void
{
const struct mdoc_meta *m;
/*
* 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.
*/
p->offset = 0;
p->rmargin = p->maxrmargin;
if (m->arch) {
}
p->offset = 0;
(p->maxrmargin -
p->maxrmargin - buflen;
term_flushln(p);
p->flags |= TERMP_NOSPACE;
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE;
p->rmargin = p->maxrmargin;
term_flushln(p);
}
p->flags &= ~TERMP_NOSPACE;
p->offset = 0;
p->rmargin = p->maxrmargin;
}
static size_t
{
assert(v);
return(term_vspan(p, &su));
}
static size_t
{
assert(v);
return(term_hspan(p, &su));
}
static size_t
{
if ('\0' == *v)
return(0);
else if (0 == strcmp(v, "left"))
return(0);
else if (0 == strcmp(v, "indent"))
else if (0 == strcmp(v, "indent-two"))
return(term_hspan(p, &su));
}
/*
* Determine how much space to print out before block elements of `It'
* (and thus `Bl') and `Bd'. And then go ahead and print that space,
* too.
*/
static void
print_bvspace(struct termp *p,
const struct mdoc_node *n)
{
assert(n);
term_newln(p);
return;
return;
continue;
return;
return;
continue;
break;
}
/* A `-column' does not assert vspace within the list. */
return;
/* A `-diag' without body does not vspace. */
return;
}
term_vspace(p);
}
/* ARGSUSED */
static int
{
char buf[7];
int i;
if (MDOC_BLOCK == n->type) {
return(1);
}
/*
* First calculate width and offset. This is pretty easy unless
* we're a -column list, in which case all prior columns must
* be accounted for.
*/
switch (type) {
case (LIST_column):
break;
/*
* Imitate groff's column handling:
* - For each earlier column, add its width.
* - For less than 5 columns, add four more blanks per
* column.
* - For exactly 5 columns, add three more blank per
* column.
* - For more than 5 columns, add only one column.
*/
/* LINTED */
/*
* Calculate the offset by applying all prior MDOC_BODY,
* so we stop at the MDOC_HEAD (NULL == nn->prev).
*/
/*
* When exceeding the declared number of columns, leave
* the remaining widths at 0. This will later be
* adjusted to the default width of 10, or, for the last
* column, stretched to the right margin.
*/
if (i >= (int)ncols)
break;
/*
* Use the declared column widths, extended as explained
* in the preceding paragraph.
*/
break;
default:
break;
/*
* Note: buffer the width by 2, which is groff's magic
* number for buffering single arguments. See the above
* handling for column for how this changes.
*/
break;
}
/*
* List-type can override the width in the case of fixed-head
* offset.
*/
switch (type) {
case (LIST_bullet):
/* FALLTHROUGH */
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_hyphen):
break;
case (LIST_enum):
break;
case (LIST_hang):
if (0 == width)
break;
case (LIST_column):
/* FALLTHROUGH */
case (LIST_tag):
if (0 == width)
break;
default:
break;
}
/*
* Whitespace control. Inset bodies need an initial space,
* while diagonal bodies need two.
*/
p->flags |= TERMP_NOSPACE;
switch (type) {
case (LIST_diag):
term_word(p, "\\ \\ ");
break;
case (LIST_inset):
term_word(p, "\\ ");
break;
default:
break;
}
p->flags |= TERMP_NOSPACE;
switch (type) {
case (LIST_diag):
break;
default:
break;
}
/*
* Pad and break control. This is the tricky part. These flags
* are documented in term_flushln() in term.c. Note that we're
* going to unset all of these flags in termp_it_post() when we
* exit.
*/
switch (type) {
case (LIST_bullet):
/* FALLTHROUGH */
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_enum):
/* FALLTHROUGH */
case (LIST_hyphen):
p->flags |= TERMP_NOBREAK;
break;
case (LIST_hang):
p->flags |= TERMP_NOBREAK;
else
break;
/*
* This is ugly. If `-hang' is specified and the body
* is a `Bl' or `Bd', then we want basically to nullify
* the "overstep" effect in term_flushln() and treat
* this as a `-ohang' list instead.
*/
p->flags &= ~TERMP_NOBREAK;
else
p->flags |= TERMP_HANG;
break;
case (LIST_tag):
break;
p->flags |= TERMP_DANGLE;
break;
case (LIST_column):
break;
p->flags &= ~TERMP_NOBREAK;
else
p->flags |= TERMP_NOBREAK;
break;
case (LIST_diag):
p->flags |= TERMP_NOBREAK;
break;
default:
break;
}
/*
* Margin control. Set-head-width lists have their right
* margins shortened. The body for these lists has the offset
* necessarily lengthened. Everybody gets the offset.
*/
switch (type) {
case (LIST_hang):
/*
* Same stipulation as above, regarding `-hang'. We
* don't want to recalculate rmargin and offsets when
* using `Bd' or `Bl' within `-hang' overstep lists.
*/
break;
/* FALLTHROUGH */
case (LIST_bullet):
/* FALLTHROUGH */
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_enum):
/* FALLTHROUGH */
case (LIST_hyphen):
/* FALLTHROUGH */
case (LIST_tag):
else
break;
case (LIST_column):
/*
* XXX - this behaviour is not documented: the
* right-most column is filled to the right margin.
*/
break;
p->rmargin = p->maxrmargin;
break;
default:
break;
}
/*
* The dash, hyphen, bullet and enum lists all have a special
* HEAD character (temporarily bold, in some cases).
*/
switch (type) {
case (LIST_bullet):
term_word(p, "\\[bu]");
term_fontpop(p);
break;
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_hyphen):
term_word(p, "\\(hy");
term_fontpop(p);
break;
case (LIST_enum):
break;
default:
break;
}
/*
* If we're not going to process our children, indicate so here.
*/
switch (type) {
case (LIST_bullet):
/* FALLTHROUGH */
case (LIST_item):
/* FALLTHROUGH */
case (LIST_dash):
/* FALLTHROUGH */
case (LIST_hyphen):
/* FALLTHROUGH */
case (LIST_enum):
return(0);
break;
case (LIST_column):
return(0);
break;
default:
break;
}
return(1);
}
/* ARGSUSED */
static void
{
if (MDOC_BLOCK == n->type)
return;
switch (type) {
case (LIST_item):
/* FALLTHROUGH */
case (LIST_diag):
/* FALLTHROUGH */
case (LIST_inset):
term_newln(p);
break;
case (LIST_column):
term_flushln(p);
break;
default:
term_newln(p);
break;
}
/*
* Now that our output is flushed, we can reset our tags. Since
* only `It' sets these flags, we're free to assume that nobody
* has munged them in the meanwhile.
*/
p->flags &= ~TERMP_DANGLE;
p->flags &= ~TERMP_NOBREAK;
p->flags &= ~TERMP_TWOSPACE;
p->flags &= ~TERMP_HANG;
}
/* ARGSUSED */
static int
{
if (MDOC_BLOCK == n->type)
return(1);
return(0);
p->flags |= TERMP_NOSPACE;
term_len(p, 5));
return(1);
}
return(0);
synopsis_pre(p, n->parent);
p->flags |= TERMP_HANG;
} else {
p->flags |= TERMP_HANG;
}
}
return(1);
}
/* ARGSUSED */
static void
{
term_flushln(p);
term_flushln(p);
}
/* ARGSUSED */
static int
{
term_word(p, "\\-");
if (n->child)
p->flags |= TERMP_NOSPACE;
p->flags |= TERMP_NOSPACE;
return(1);
}
/* ARGSUSED */
static int
{
term_word(p, "and");
return(1);
}
/* ARGSUSED */
static int
{
return(1);
/*
* If not in the AUTHORS section, `An -split' will cause
* newlines to occur before the author name. If in the AUTHORS
* section, by default, the first `An' invocation is nosplit,
* then all subsequent ones, regardless of whether interspersed
* will override the condition of the implied first -nosplit.
*/
if (n->sec == SEC_AUTHORS) {
if ( ! (TERMP_ANPREC & p->flags)) {
if (TERMP_SPLIT & p->flags)
term_newln(p);
return(1);
}
if (TERMP_NOSPLIT & p->flags)
return(1);
term_newln(p);
return(1);
}
if (TERMP_SPLIT & p->flags)
term_newln(p);
return(1);
}
/* ARGSUSED */
static void
{
if (n->child) {
if (SEC_AUTHORS == n->sec)
p->flags |= TERMP_ANPREC;
return;
}
p->flags &= ~TERMP_NOSPLIT;
p->flags |= TERMP_SPLIT;
p->flags &= ~TERMP_SPLIT;
p->flags |= TERMP_NOSPLIT;
}
}
/* ARGSUSED */
static int
{
p->flags |= TERMP_NOSPACE;
return(1);
}
/* ARGSUSED */
static int
{
if (SEC_SEE_ALSO != n->sec)
return(1);
term_vspace(p);
return(1);
}
/* ARGSUSED */
static int
{
int nchild;
term_newln(p);
term_word(p, "The");
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
term_word(p, "()");
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
term_word(p, "and");
}
if (nchild > 1)
term_word(p, "functions return");
else
term_word(p, "function returns");
term_word(p, "the value 0 if successful; otherwise the value "
"-1 is returned and the global variable");
term_word(p, "errno");
term_fontpop(p);
term_word(p, "is set to indicate the error.");
p->flags |= TERMP_SENTENCE;
return(0);
}
/* ARGSUSED */
static int
{
int nchild;
term_newln(p);
term_word(p, "The");
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
term_word(p, "and");
}
if (nchild > 1)
term_word(p, "utilities exit");
else
term_word(p, "utility exits");
term_word(p, "0 on success, and >0 if an error occurs.");
p->flags |= TERMP_SENTENCE;
return(0);
}
/* ARGSUSED */
static int
{
return(1);
#if defined(__OpenBSD__) || defined(__linux__)
term_word(p, "\\(en");
#else
term_word(p, "\\(em");
#endif
return(1);
}
/* ARGSUSED */
static int
{
}
/* ARGSUSED */
static void
{
if (MDOC_BLOCK == n->type)
term_newln(p);
}
/* ARGSUSED */
static int
{
return(0);
return(0);
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
p->flags |= TERMP_NOSPACE;
term_word(p, ")");
return(0);
}
/*
* This decides how to assert whitespace before any of the SYNOPSIS set
* macro combos).
*/
static void
{
/*
* Obviously, if we're not in a SYNOPSIS or no prior macros
* exist, do nothing.
*/
return;
/*
* If we're the second in a pair of like elements, emit our
* newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
* case we soldier on.
*/
term_newln(p);
return;
}
/*
* If we're one of the SYNOPSIS set and non-like pair-wise after
* vertical space, else only newline and move on.
*/
case (MDOC_Fd):
/* FALLTHROUGH */
case (MDOC_Fn):
/* FALLTHROUGH */
case (MDOC_Fo):
/* FALLTHROUGH */
case (MDOC_In):
/* FALLTHROUGH */
case (MDOC_Vt):
term_vspace(p);
break;
case (MDOC_Ft):
term_vspace(p);
break;
}
/* FALLTHROUGH */
default:
term_newln(p);
break;
}
}
static int
{
synopsis_pre(p, n);
return(termp_under_pre(p, pair, m, n));
} else if (MDOC_BLOCK == n->type) {
synopsis_pre(p, n);
return(1);
return(0);
return(termp_under_pre(p, pair, m, n));
}
/* ARGSUSED */
static int
{
return(1);
}
/* ARGSUSED */
static int
{
synopsis_pre(p, n);
return(termp_bold_pre(p, pair, m, n));
}
/* ARGSUSED */
static int
{
/* No vspace between consecutive `Sh' calls. */
switch (n->type) {
case (MDOC_BLOCK):
break;
term_vspace(p);
break;
case (MDOC_HEAD):
break;
case (MDOC_BODY):
break;
default:
break;
}
return(1);
}
/* ARGSUSED */
static void
{
switch (n->type) {
case (MDOC_HEAD):
term_newln(p);
break;
case (MDOC_BODY):
term_newln(p);
p->offset = 0;
break;
default:
break;
}
}
/* ARGSUSED */
static int
{
term_word(p, "is currently in beta test.");
p->flags |= TERMP_SENTENCE;
return(0);
}
/* ARGSUSED */
static void
{
term_newln(p);
}
/* ARGSUSED */
static int
{
term_word(p, "currently under development.");
p->flags |= TERMP_SENTENCE;
return(0);
}
/* ARGSUSED */
static int
{
if (MDOC_BLOCK != n->type)
return(1);
term_newln(p);
return(1);
}
/* ARGSUSED */
static void
{
if (MDOC_BLOCK != n->type)
return;
term_newln(p);
}
/* ARGSUSED */
static int
{
/* NB: MDOC_LINE does not effect this! */
synopsis_pre(p, n);
return(1);
}
/* ARGSUSED */
static int
{
int pretty;
synopsis_pre(p, n);
return(0);
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
term_fontpop(p);
if (n->next) {
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
}
p->flags |= TERMP_NOSPACE;
term_word(p, ")");
if (pretty) {
p->flags |= TERMP_NOSPACE;
term_word(p, ";");
}
return(0);
}
/* ARGSUSED */
static int
{
return(1);
}
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
}
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
return(0);
}
/* ARGSUSED */
static int
{
if (MDOC_BLOCK == n->type) {
print_bvspace(p, n, n);
return(1);
return(0);
/*
* If -ragged or -filled are specified, the block does nothing
* but change the indentation. If -unfilled or -literal are
* specified, text is printed exactly as entered in the display:
* for macro lines, a newline is appended to the line. Blank
* lines are allowed.
*/
return(1);
rmax = p->maxrmargin;
/*
* If the printed node flushes its own line, then we
* needn't do it here as well. This is hacky, but the
* notion of selective eoln whitespace is pretty dumb
* anyway, so don't sweat it.
*/
case (MDOC_Sm):
/* FALLTHROUGH */
case (MDOC_br):
/* FALLTHROUGH */
case (MDOC_sp):
/* FALLTHROUGH */
case (MDOC_Bl):
/* FALLTHROUGH */
case (MDOC_D1):
/* FALLTHROUGH */
case (MDOC_Dl):
/* FALLTHROUGH */
case (MDOC_Lp):
/* FALLTHROUGH */
case (MDOC_Pp):
continue;
default:
break;
}
continue;
term_flushln(p);
p->flags |= TERMP_NOSPACE;
}
p->maxrmargin = rmax;
return(0);
}
/* ARGSUSED */
static void
{
return;
rmax = p->maxrmargin;
p->flags |= TERMP_NOSPACE;
term_newln(p);
p->maxrmargin = rmax;
}
/* ARGSUSED */
static int
{
p->flags |= TERMP_NOSPACE;
term_word(p, "BSD");
} else {
term_word(p, "BSD");
return(0);
}
p->flags |= TERMP_NOSPACE;
term_word(p, "-");
p->flags |= TERMP_NOSPACE;
}
return(0);
}
/* ARGSUSED */
static int
{
const char *pp;
int flags;
switch (n->tok) {
case (MDOC_Bsx):
break;
case (MDOC_Dx):
pp = "DragonFly";
break;
case (MDOC_Fx):
pp = "FreeBSD";
break;
case (MDOC_Nx):
pp = "NetBSD";
break;
case (MDOC_Ox):
pp = "OpenBSD";
break;
case (MDOC_Ux):
pp = "UNIX";
break;
default:
break;
}
if (n->child) {
p->flags |= TERMP_KEEP;
}
return(0);
}
/* ARGSUSED */
static int
{
p->flags |= TERMP_IGNDELIM;
return(1);
}
/* ARGSUSED */
static void
{
p->flags |= TERMP_NOSPACE;
}
/* ARGSUSED */
static int
{
switch (n->type) {
case (MDOC_BLOCK):
term_newln(p);
if (n->prev)
term_vspace(p);
break;
case (MDOC_HEAD):
break;
default:
break;
}
return(1);
}
/* ARGSUSED */
static void
{
term_newln(p);
}
/* ARGSUSED */
static int
{
synopsis_pre(p, n);
return(1);
}
/* ARGSUSED */
static int
{
synopsis_pre(p, n);
term_word(p, "#include");
term_word(p, "<");
} else {
term_word(p, "<");
}
p->flags |= TERMP_NOSPACE;
return(1);
}
/* ARGSUSED */
static void
{
if (MDOC_SYNPRETTY & n->flags)
p->flags |= TERMP_NOSPACE;
term_word(p, ">");
if (MDOC_SYNPRETTY & n->flags)
term_fontpop(p);
}
/* ARGSUSED */
static int
{
switch (n->tok) {
case (MDOC_sp):
break;
case (MDOC_br):
len = 0;
break;
default:
len = 1;
break;
}
if (0 == len)
term_newln(p);
for (i = 0; i < len; i++)
term_vspace(p);
return(0);
}
/* ARGSUSED */
static int
{
return(1);
switch (n->tok) {
case (MDOC_Ao):
/* FALLTHROUGH */
case (MDOC_Aq):
term_word(p, "<");
break;
case (MDOC_Bro):
/* FALLTHROUGH */
case (MDOC_Brq):
term_word(p, "{");
break;
case (MDOC_Oo):
/* FALLTHROUGH */
case (MDOC_Op):
/* FALLTHROUGH */
case (MDOC_Bo):
/* FALLTHROUGH */
case (MDOC_Bq):
term_word(p, "[");
break;
case (MDOC_Do):
/* FALLTHROUGH */
case (MDOC_Dq):
term_word(p, "``");
break;
case (MDOC_Eo):
break;
case (MDOC_Po):
/* FALLTHROUGH */
case (MDOC_Pq):
term_word(p, "(");
break;
case (MDOC__T):
/* FALLTHROUGH */
case (MDOC_Qo):
/* FALLTHROUGH */
case (MDOC_Qq):
term_word(p, "\"");
break;
case (MDOC_Ql):
/* FALLTHROUGH */
case (MDOC_So):
/* FALLTHROUGH */
case (MDOC_Sq):
term_word(p, "`");
break;
default:
abort();
/* NOTREACHED */
}
p->flags |= TERMP_NOSPACE;
return(1);
}
/* ARGSUSED */
static void
{
return;
p->flags |= TERMP_NOSPACE;
switch (n->tok) {
case (MDOC_Ao):
/* FALLTHROUGH */
case (MDOC_Aq):
term_word(p, ">");
break;
case (MDOC_Bro):
/* FALLTHROUGH */
case (MDOC_Brq):
term_word(p, "}");
break;
case (MDOC_Oo):
/* FALLTHROUGH */
case (MDOC_Op):
/* FALLTHROUGH */
case (MDOC_Bo):
/* FALLTHROUGH */
case (MDOC_Bq):
term_word(p, "]");
break;
case (MDOC_Do):
/* FALLTHROUGH */
case (MDOC_Dq):
term_word(p, "''");
break;
case (MDOC_Eo):
break;
case (MDOC_Po):
/* FALLTHROUGH */
case (MDOC_Pq):
term_word(p, ")");
break;
case (MDOC__T):
/* FALLTHROUGH */
case (MDOC_Qo):
/* FALLTHROUGH */
case (MDOC_Qq):
term_word(p, "\"");
break;
case (MDOC_Ql):
/* FALLTHROUGH */
case (MDOC_So):
/* FALLTHROUGH */
case (MDOC_Sq):
term_word(p, "'");
break;
default:
abort();
/* NOTREACHED */
}
}
/* ARGSUSED */
static int
{
if (MDOC_BLOCK == n->type) {
synopsis_pre(p, n);
return(1);
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
return(1);
}
return(0);
/* XXX: we drop non-initial arguments as per groff. */
return(0);
}
/* ARGSUSED */
static void
{
return;
p->flags |= TERMP_NOSPACE;
term_word(p, ")");
if (MDOC_SYNPRETTY & n->flags) {
p->flags |= TERMP_NOSPACE;
term_word(p, ";");
}
}
/* ARGSUSED */
static int
{
return(0);
else if (MDOC_BLOCK != n->type)
return(1);
else
return(1);
}
/* ARGSUSED */
static int
{
if (p->col)
p->flags &= ~TERMP_NOSPACE;
p->flags &= ~TERMP_NONOSPACE;
} else
p->flags |= TERMP_NONOSPACE;
return(0);
}
/* ARGSUSED */
static int
{
p->flags |= TERMP_NOSPACE;
term_word(p, "'");
p->flags |= TERMP_NOSPACE;
return(1);
}
/* ARGSUSED */
static void
{
/*
* Handle lists of authors. In general, print each followed by
* a comma. Don't print the comma if there are only two
* authors.
*/
return;
/* TODO: %U. */
return;
p->flags |= TERMP_NOSPACE;
term_word(p, ".");
p->flags |= TERMP_SENTENCE;
} else
term_word(p, ",");
}
/* ARGSUSED */
static int
{
return(1);
}
/* ARGSUSED */
static int
{
return(1);
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
term_word(p, ":");
term_fontpop(p);
return(0);
}
/* ARGSUSED */
static int
{
switch (n->type) {
case (MDOC_BLOCK):
break;
case (MDOC_HEAD):
return(0);
case (MDOC_BODY):
p->flags |= TERMP_PREKEEP;
break;
default:
abort();
/* NOTREACHED */
}
return(1);
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
/*
* If we're in an `Rs' and there's a journal present, then quote
* us instead of underlining us (for disambiguation).
*/
termp_quote_post(p, pair, m, n);
termp____post(p, pair, m, n);
}
/* ARGSUSED */
static int
{
/*
* If we're in an `Rs' and there's a journal present, then quote
* us instead of underlining us (for disambiguation).
*/
return(termp_quote_pre(p, pair, m, n));
return(1);
}
/* ARGSUSED */
static int
{
return(1);
}