/* $Id: mdoc_man.c,v 1.96 2016/01/08 17:48:09 schwarze Exp $ */
/*
* Copyright (c) 2011-2016 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.
*/
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "man.h"
#include "out.h"
#include "main.h"
struct manact {
};
static void font_push(char);
static void font_pop(void);
static void mid_it(void);
static void post_percent(DECL_ARGS);
static void print_word(const char *);
static void print_line(const char *, int);
static void print_block(const char *, int);
static void print_offs(const char *, int);
static void print_width(const struct mdoc_bl *,
const struct roff_node *);
static void print_count(int *);
static void print_node(DECL_ARGS);
};
static int outflags;
static struct {
char *head;
char *tail;
} fontqueue;
static void
{
}
print_word("");
printf("\\f");
}
static void
font_pop(void)
{
print_word("");
printf("\\f");
}
static void
print_word(const char *s)
{
/*
* If we need a newline, print it now and start afresh.
*/
printf("\n.PD");
}
printf("\n.PD 0");
}
printf("\n.PP\n");
printf("\n.br\n");
putchar('\n');
if (1 == TPremain)
printf(".br\n");
TPremain = 0;
/*
* If we need a space, only print it if
* (1) it is forced by `No' or
* (2) what follows is not terminating punctuation or
* (3) what follows is longer than one character.
*/
! (MMAN_Bk_susp & outflags))
putchar('\\');
putchar(' ');
if (TPremain)
TPremain--;
}
}
/*
* Reassign needing space if we're not following opening
* punctuation.
*/
(('(' != s[0] && '[' != s[0]) || '\0' != s[1])))
else
for ( ; *s; s++) {
switch (*s) {
case ASCII_NBRSP:
printf("\\ ");
break;
case ASCII_HYPH:
putchar('-');
break;
case ASCII_BREAK:
printf("\\:");
break;
case ' ':
if (MMAN_nbrword & outflags) {
printf("\\ ");
break;
}
/* FALLTHROUGH */
default:
putchar((unsigned char)*s);
break;
}
if (TPremain)
TPremain--;
}
outflags &= ~MMAN_nbrword;
}
static void
{
print_word(s);
}
static void
{
print_line(".PD", 0);
}
print_word(s);
}
static void
{
int sz;
/* Convert v into a number (of characters). */
sz = 0;
sz = 6;
sz = 12;
else {
/*
* XXX
* If we are inside an enclosing list,
* there is no easy way to add the two
* indentations because they are provided
* in terms of different units.
*/
print_word(v);
return;
}
} else
/*
* We are inside an enclosing list.
* Add the two indentations.
*/
if (Bl_stack_len)
}
/*
* Set up the indentation for a list item; used from pre_it().
*/
static void
{
numeric = 1;
remain = 0;
/* Convert the width into a number (of characters). */
else {
sz = 0;
numeric = 0;
}
} else
/* XXX Rough estimation, might have multiple parts. */
else
chsz = 0;
/* Maybe we are inside an enclosing list? */
mid_it();
/*
* Save our own indentation,
* such that child lists can use it.
*/
/* Set up the current list. */
print_block(".HP", 0);
else {
print_block(".TP", 0);
}
if (numeric) {
} else
}
static void
{
}
void
{
/*
* Dump the keep buffer.
* We're guaranteed by now that this exists (is non-NULL).
* Flush stdout afterward, just in case.
*/
}
void
{
struct roff_node *n;
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
/* Disable hyphenation and if nroff, disable justification. */
printf(".nh\n.if n .ad l");
}
putchar('\n');
}
static void
{
/*
* Break the line if we were parsed subsequent the current node.
* This makes the page structure be more consistent.
*/
cond = 0;
do_sub = 1;
n->flags &= ~MDOC_ENDED;
if (n->type == ROFFT_TEXT) {
/*
* Make sure that we don't happen to start with a
* control character at the start of a line.
*/
print_word("");
printf("\\&");
}
print_word(n->string);
} else {
/*
* Conditionally run the pre-node action handler for a
* node.
*/
}
/*
* Conditionally run all child nodes.
* Note that this iterates over children instead of using
* recursion. This prevents unnecessary depth in the stack.
*/
if (do_sub)
/*
* Lastly, conditionally run the post-node handler.
*/
if (MDOC_ENDED & n->flags)
return;
if (ENDBODY_NOT != n->end)
if (ENDBODY_NOSPACE == n->end)
}
static int
{
return n->type == ROFFT_HEAD;
}
static int
{
return n->type == ROFFT_BODY;
}
static int
{
const char *prefix;
return 1;
return 1;
}
static void
{
const char *suffix;
return;
}
static int
{
print_word("The");
font_push('B');
font_pop();
continue;
print_word(",");
}
print_word("and");
}
print_word("utilities exit\\~0");
else
print_word("utility exits\\~0");
print_word("on success, and\\~>0 if an error occurs.");
return 0;
}
static void
{
font_pop();
}
static void
{
font_pop();
if (n->next) {
print_word(",");
print_word("and");
} else {
print_word(".");
}
}
static int
{
print_word("");
putchar('\"');
} else
font_push('I');
return 1;
}
static void
{
print_word("");
putchar('\"');
} else
font_pop();
post_percent(meta, n);
}
/*
* Print before a section header.
*/
static int
{
if (n->type == ROFFT_HEAD) {
print_word("");
putchar('\"');
}
return 1;
}
/*
* Print subsequent a section header.
*/
static void
{
if (n->type != ROFFT_HEAD)
return;
print_word("");
putchar('\"');
}
/* See mdoc_term.c, synopsis_pre() for comments. */
static void
{
return;
return;
}
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
case MDOC_In:
case MDOC_Vt:
break;
case MDOC_Ft:
break;
}
/* FALLTHROUGH */
default:
break;
}
}
static int
{
case AUTH_split:
outflags &= ~MMAN_An_nosplit;
return 0;
case AUTH_nosplit:
outflags &= ~MMAN_An_split;
return 0;
default:
if (MMAN_An_split & outflags)
else if (SEC_AUTHORS == n->sec &&
! (MMAN_An_nosplit & outflags))
return 1;
}
}
static int
{
print_word("'");
return 0;
}
static int
{
return 1;
}
static void
{
}
static int
{
print_line(".nf", 0);
return 1;
}
static void
{
/* Close out this display. */
/* Maybe we are inside an enclosing list? */
mid_it();
}
static int
{
switch (n->type) {
case ROFFT_BLOCK:
return 1;
case ROFFT_BODY:
break;
default:
return 0;
}
case FONT_Em:
font_push('I');
break;
case FONT_Sy:
font_push('B');
break;
default:
font_push('R');
break;
}
return 1;
}
static void
{
if (n->type == ROFFT_BODY)
font_pop();
}
static int
{
switch (n->type) {
case ROFFT_BLOCK:
return 1;
case ROFFT_BODY:
return 1;
default:
return 0;
}
}
static void
{
if (n->type == ROFFT_BODY)
}
static int
{
/*
* print_offs() will increase the -offset to account for
* a possible enclosing .It, but any enclosed .It blocks
* just nest and do not add up their indentation.
*/
Bl_stack[Bl_stack_len++] = 0;
}
case LIST_enum:
return 1;
case LIST_column:
break;
default:
return 1;
}
print_word("l");
print_word(".");
}
return 1;
}
static void
{
case LIST_column:
print_line(".TE", 0);
break;
case LIST_enum:
break;
default:
break;
}
Bl_stack_len--;
} else {
}
/* Maybe we are inside an enclosing list? */
mid_it();
}
static int
{
return 0;
}
static int
{
n = n->child;
if (n) {
print_word(n->string);
n = n->next;
}
print_word("BSD");
if (NULL == n)
return 0;
print_word("-");
print_word(n->string);
return 0;
}
static int
{
print_offs("6n", 0);
return 1;
}
static void
{
/* Maybe we are inside an enclosing list? */
mid_it();
}
static int
{
font_push('I');
return 1;
}
static int
{
return 1;
return 1;
}
static void
{
return;
return;
}
static int
{
if (n->end == ENDBODY_NOT &&
print_word("\\&");
return 1;
}
static void
{
if (n->end != ENDBODY_NOT) {
return;
}
print_word("\\&");
else if ( ! tail)
}
static int
{
int am_Fa;
if (am_Fa)
n = n->child;
while (NULL != n) {
font_push('I');
outflags |= MMAN_nbrword;
print_node(meta, n);
font_pop();
print_word(",");
}
return 0;
}
static void
{
print_word(",");
}
static int
{
pre_syn(n);
font_push('B');
return 1;
}
static void
{
font_pop();
}
static int
{
font_push('B');
print_word("\\-");
return 1;
}
static void
{
font_pop();
}
static int
{
pre_syn(n);
n = n->child;
if (NULL == n)
return 0;
if (MDOC_SYNPRETTY & n->flags)
font_push('B');
print_node(meta, n);
font_pop();
print_word("(");
n = n->next;
if (NULL != n)
return 0;
}
static void
{
print_word(")");
if (MDOC_SYNPRETTY & n->flags) {
print_word(";");
}
}
static int
{
switch (n->type) {
case ROFFT_BLOCK:
pre_syn(n);
break;
case ROFFT_HEAD:
return 0;
if (MDOC_SYNPRETTY & n->flags)
font_push('B');
break;
case ROFFT_BODY:
print_word("(");
break;
default:
break;
}
return 1;
}
static void
{
switch (n->type) {
case ROFFT_HEAD:
font_pop();
break;
case ROFFT_BODY:
break;
default:
break;
}
}
static int
{
pre_syn(n);
font_push('I');
return 1;
}
static int
{
if (MDOC_SYNPRETTY & n->flags) {
pre_syn(n);
font_push('B');
print_word("#include <");
} else {
print_word("<");
font_push('I');
}
return 1;
}
static void
{
if (MDOC_SYNPRETTY & n->flags) {
print_word(">");
font_pop();
} else {
font_pop();
print_word(">");
}
}
static int
{
switch (n->type) {
case ROFFT_HEAD:
case LIST_item:
return 0;
case LIST_inset:
case LIST_diag:
case LIST_ohang:
print_line(".B \"", 0);
else
print_line(".R \"", 0);
return 1;
case LIST_bullet:
case LIST_dash:
case LIST_hyphen:
TPremain = 0;
font_push('B');
print_word("\\(bu");
else
print_word("-");
font_pop();
return 0;
case LIST_enum:
TPremain = 0;
return 0;
case LIST_hang:
TPremain = 0;
return 1;
case LIST_tag:
putchar('\n');
return 1;
default:
return 1;
}
default:
break;
}
return 1;
}
/*
* This function is called after closing out an indented block.
* If we are inside an enclosing list, restore its indentation.
*/
static void
mid_it(void)
{
/* Nothing to do outside a list. */
return;
/* The indentation has already been set up. */
return;
/* Restore the indentation of the enclosing list. */
/* Remeber to close out this .RS block later. */
}
static void
{
switch (n->type) {
case ROFFT_HEAD:
case LIST_diag:
print_word("\\ ");
break;
case LIST_ohang:
break;
default:
break;
}
break;
case ROFFT_BODY:
case LIST_bullet:
case LIST_dash:
case LIST_hyphen:
case LIST_enum:
case LIST_hang:
case LIST_tag:
Bl_stack[--Bl_stack_len] = 0;
/*
* Our indentation had to be restored
* after a child display or child list.
* Close out that indentation block now.
*/
if (Bl_stack_post[Bl_stack_len]) {
Bl_stack_post[Bl_stack_len] = 0;
}
break;
case LIST_column:
putchar('\t');
}
break;
default:
break;
}
break;
default:
break;
}
}
static void
{
if (SEC_LIBRARY == n->sec)
}
static int
{
return 0;
font_push('I');
}
print_word(":");
font_pop();
}
font_push('B');
font_pop();
return 0;
}
static int
{
print_line(".ll", 0);
return 1;
}
static int
{
font_push('R');
return 1;
}
static int
{
char *name;
if (n->type == ROFFT_BLOCK) {
pre_syn(n);
}
return 1;
return 0;
if (n->type == ROFFT_HEAD) {
print_block(".HP", 0);
}
font_push('B');
return 1;
}
static void
{
switch (n->type) {
case ROFFT_BLOCK:
break;
case ROFFT_HEAD:
case ROFFT_ELEM:
font_pop();
break;
default:
break;
}
}
static int
{
return 1;
}
static int
{
return 0;
}
static void
{
}
static int
{
return 0;
}
static int
{
if (SEC_SEE_ALSO == n->sec) {
}
return 1;
}
static int
{
print_word("The");
font_push('B');
font_pop();
print_word("()");
continue;
print_word(",");
}
print_word("and");
}
print_word("functions return");
else
print_word("function returns");
print_word("the value\\~0 if successful;");
} else
print_word("Upon successful completion, "
"the value\\~0 is returned;");
print_word("otherwise the value\\~\\-1 is returned"
" and the global variable");
font_push('I');
print_word("errno");
font_pop();
print_word("is set to indicate the error.");
return 0;
}
static int
{
return 0;
}
static int
{
else
return 0;
}
static int
{
print_line(".PP", 0);
} else
print_line(".sp", 0);
return 1;
}
static void
{
}
static int
{
font_push('B');
return 1;
}
static int
{
if (MDOC_SYNPRETTY & n->flags) {
switch (n->type) {
case ROFFT_BLOCK:
pre_syn(n);
return 1;
case ROFFT_BODY:
break;
default:
return 0;
}
}
font_push('I');
return 1;
}
static void
{
return;
font_pop();
}
static int
{
n = n->child;
if (NULL == n)
return 0;
print_node(meta, n);
n = n->next;
if (NULL == n)
return 0;
print_word("(");
print_node(meta, n);
print_word(")");
return 0;
}
static int
{
return 0;
print_word("\\ ");
return 1;
}