Return to man_html.c CVS log | Up to [cvsweb.bsd.lv] / mandoc |
version 1.139, 2017/05/05 02:06:19 | version 1.171, 2019/02/28 16:36:13 | ||
---|---|---|---|
|
|
||
/* $Id$ */ | /* $Id$ */ | ||
/* | /* | ||
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> | * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> | ||
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> | * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org> | ||
* | * | ||
* Permission to use, copy, modify, and distribute this software for any | * Permission to use, copy, modify, and distribute this software for any | ||
* purpose with or without fee is hereby granted, provided that the above | * purpose with or without fee is hereby granted, provided that the above | ||
|
|
||
#include <string.h> | #include <string.h> | ||
#include "mandoc_aux.h" | #include "mandoc_aux.h" | ||
#include "mandoc.h" | |||
#include "roff.h" | #include "roff.h" | ||
#include "man.h" | #include "man.h" | ||
#include "out.h" | #include "out.h" | ||
#include "html.h" | #include "html.h" | ||
#include "main.h" | #include "main.h" | ||
/* FIXME: have PD set the default vspace width. */ | |||
#define INDENT 5 | |||
#define MAN_ARGS const struct roff_meta *man, \ | #define MAN_ARGS const struct roff_meta *man, \ | ||
const struct roff_node *n, \ | const struct roff_node *n, \ | ||
struct html *h | struct html *h | ||
struct htmlman { | struct man_html_act { | ||
int (*pre)(MAN_ARGS); | int (*pre)(MAN_ARGS); | ||
int (*post)(MAN_ARGS); | int (*post)(MAN_ARGS); | ||
}; | }; | ||
static void print_bvspace(struct html *, | static void print_man_head(const struct roff_meta *, | ||
const struct roff_node *); | struct html *); | ||
static void print_man_head(MAN_ARGS); | |||
static void print_man_nodelist(MAN_ARGS); | static void print_man_nodelist(MAN_ARGS); | ||
static void print_man_node(MAN_ARGS); | static void print_man_node(MAN_ARGS); | ||
static int fillmode(struct html *, int); | |||
static int a2width(const struct roff_node *, | |||
struct roffsu *); | |||
static int man_B_pre(MAN_ARGS); | static int man_B_pre(MAN_ARGS); | ||
static int man_HP_pre(MAN_ARGS); | |||
static int man_IP_pre(MAN_ARGS); | static int man_IP_pre(MAN_ARGS); | ||
static int man_I_pre(MAN_ARGS); | static int man_I_pre(MAN_ARGS); | ||
static int man_OP_pre(MAN_ARGS); | static int man_OP_pre(MAN_ARGS); | ||
|
|
||
static int man_RS_pre(MAN_ARGS); | static int man_RS_pre(MAN_ARGS); | ||
static int man_SH_pre(MAN_ARGS); | static int man_SH_pre(MAN_ARGS); | ||
static int man_SM_pre(MAN_ARGS); | static int man_SM_pre(MAN_ARGS); | ||
static int man_SS_pre(MAN_ARGS); | static int man_SY_pre(MAN_ARGS); | ||
static int man_UR_pre(MAN_ARGS); | static int man_UR_pre(MAN_ARGS); | ||
static int man_abort_pre(MAN_ARGS); | |||
static int man_alt_pre(MAN_ARGS); | static int man_alt_pre(MAN_ARGS); | ||
static int man_ign_pre(MAN_ARGS); | static int man_ign_pre(MAN_ARGS); | ||
static int man_in_pre(MAN_ARGS); | static int man_in_pre(MAN_ARGS); | ||
static void man_root_post(MAN_ARGS); | static void man_root_post(const struct roff_meta *, | ||
static void man_root_pre(MAN_ARGS); | struct html *); | ||
static int man_sp_pre(MAN_ARGS); | static void man_root_pre(const struct roff_meta *, | ||
struct html *); | |||
static const struct htmlman __mans[MAN_MAX - MAN_TH] = { | static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = { | ||
{ NULL, NULL }, /* TH */ | { NULL, NULL }, /* TH */ | ||
{ man_SH_pre, NULL }, /* SH */ | { man_SH_pre, NULL }, /* SH */ | ||
{ man_SS_pre, NULL }, /* SS */ | { man_SH_pre, NULL }, /* SS */ | ||
{ man_IP_pre, NULL }, /* TP */ | { man_IP_pre, NULL }, /* TP */ | ||
{ man_PP_pre, NULL }, /* LP */ | { man_IP_pre, NULL }, /* TQ */ | ||
{ man_abort_pre, NULL }, /* LP */ | |||
{ man_PP_pre, NULL }, /* PP */ | { man_PP_pre, NULL }, /* PP */ | ||
{ man_PP_pre, NULL }, /* P */ | { man_abort_pre, NULL }, /* P */ | ||
{ man_IP_pre, NULL }, /* IP */ | { man_IP_pre, NULL }, /* IP */ | ||
{ man_HP_pre, NULL }, /* HP */ | { man_PP_pre, NULL }, /* HP */ | ||
{ man_SM_pre, NULL }, /* SM */ | { man_SM_pre, NULL }, /* SM */ | ||
{ man_SM_pre, NULL }, /* SB */ | { man_SM_pre, NULL }, /* SB */ | ||
{ man_alt_pre, NULL }, /* BI */ | { man_alt_pre, NULL }, /* BI */ | ||
|
|
||
{ man_I_pre, NULL }, /* I */ | { man_I_pre, NULL }, /* I */ | ||
{ man_alt_pre, NULL }, /* IR */ | { man_alt_pre, NULL }, /* IR */ | ||
{ man_alt_pre, NULL }, /* RI */ | { man_alt_pre, NULL }, /* RI */ | ||
{ man_sp_pre, NULL }, /* sp */ | |||
{ NULL, NULL }, /* nf */ | |||
{ NULL, NULL }, /* fi */ | |||
{ NULL, NULL }, /* RE */ | { NULL, NULL }, /* RE */ | ||
{ man_RS_pre, NULL }, /* RS */ | { man_RS_pre, NULL }, /* RS */ | ||
{ man_ign_pre, NULL }, /* DT */ | { man_ign_pre, NULL }, /* DT */ | ||
|
|
||
{ man_ign_pre, NULL }, /* PD */ | { man_ign_pre, NULL }, /* PD */ | ||
{ man_ign_pre, NULL }, /* AT */ | { man_ign_pre, NULL }, /* AT */ | ||
{ man_in_pre, NULL }, /* in */ | { man_in_pre, NULL }, /* in */ | ||
{ man_SY_pre, NULL }, /* SY */ | |||
{ NULL, NULL }, /* YS */ | |||
{ man_OP_pre, NULL }, /* OP */ | { man_OP_pre, NULL }, /* OP */ | ||
{ NULL, NULL }, /* EX */ | { NULL, NULL }, /* EX */ | ||
{ NULL, NULL }, /* EE */ | { NULL, NULL }, /* EE */ | ||
{ man_UR_pre, NULL }, /* UR */ | { man_UR_pre, NULL }, /* UR */ | ||
{ NULL, NULL }, /* UE */ | { NULL, NULL }, /* UE */ | ||
{ man_ign_pre, NULL }, /* ll */ | { man_UR_pre, NULL }, /* MT */ | ||
{ NULL, NULL }, /* ME */ | |||
}; | }; | ||
static const struct htmlman *const mans = __mans - MAN_TH; | |||
/* | |||
* Printing leading vertical space before a block. | |||
* This is used for the paragraph macros. | |||
* The rules are pretty simple, since there's very little nesting going | |||
* on here. Basically, if we're the first within another block (SS/SH), | |||
* then don't emit vertical space. If we are (RS), then do. If not the | |||
* first, print it. | |||
*/ | |||
static void | |||
print_bvspace(struct html *h, const struct roff_node *n) | |||
{ | |||
if (n->body && n->body->child) | |||
if (n->body->child->type == ROFFT_TBL) | |||
return; | |||
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) | |||
if (NULL == n->prev) | |||
return; | |||
print_paragraph(h); | |||
} | |||
void | void | ||
html_man(void *arg, const struct roff_man *man) | html_man(void *arg, const struct roff_meta *man) | ||
{ | { | ||
struct html *h; | struct html *h; | ||
struct tag *t; | struct roff_node *n; | ||
struct tag *t; | |||
h = (struct html *)arg; | h = (struct html *)arg; | ||
n = man->first->child; | |||
if ((h->oflags & HTML_FRAGMENT) == 0) { | if ((h->oflags & HTML_FRAGMENT) == 0) { | ||
print_gen_decls(h); | print_gen_decls(h); | ||
print_otag(h, TAG_HTML, ""); | print_otag(h, TAG_HTML, ""); | ||
if (n != NULL && n->type == ROFFT_COMMENT) | |||
print_gen_comment(h, n); | |||
t = print_otag(h, TAG_HEAD, ""); | t = print_otag(h, TAG_HEAD, ""); | ||
print_man_head(&man->meta, man->first, h); | print_man_head(man, h); | ||
print_tagq(h, t); | print_tagq(h, t); | ||
print_otag(h, TAG_BODY, ""); | print_otag(h, TAG_BODY, ""); | ||
} | } | ||
man_root_pre(&man->meta, man->first, h); | man_root_pre(man, h); | ||
t = print_otag(h, TAG_DIV, "c", "manual-text"); | t = print_otag(h, TAG_DIV, "c", "manual-text"); | ||
print_man_nodelist(&man->meta, man->first->child, h); | print_man_nodelist(man, n, h); | ||
print_tagq(h, t); | print_tagq(h, t); | ||
man_root_post(&man->meta, man->first, h); | man_root_post(man, h); | ||
print_tagq(h, NULL); | print_tagq(h, NULL); | ||
} | } | ||
static void | static void | ||
print_man_head(MAN_ARGS) | print_man_head(const struct roff_meta *man, struct html *h) | ||
{ | { | ||
char *cp; | char *cp; | ||
|
|
||
static void | static void | ||
print_man_nodelist(MAN_ARGS) | print_man_nodelist(MAN_ARGS) | ||
{ | { | ||
while (n != NULL) { | while (n != NULL) { | ||
print_man_node(man, n, h); | print_man_node(man, n, h); | ||
n = n->next; | n = n->next; | ||
|
|
||
static void | static void | ||
print_man_node(MAN_ARGS) | print_man_node(MAN_ARGS) | ||
{ | { | ||
static int want_fillmode = MAN_fi; | |||
static int save_fillmode; | |||
struct tag *t; | struct tag *t; | ||
int child; | int child; | ||
/* | if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) | ||
* Handle fill mode switch requests up front, | |||
* they would just cause trouble in the subsequent code. | |||
*/ | |||
switch (n->tok) { | |||
case MAN_nf: | |||
case MAN_EX: | |||
want_fillmode = MAN_nf; | |||
return; | return; | ||
case MAN_fi: | |||
case MAN_EE: | |||
want_fillmode = MAN_fi; | |||
if (fillmode(h, 0) == MAN_fi) | |||
print_otag(h, TAG_BR, ""); | |||
return; | |||
default: | |||
break; | |||
} | |||
/* Set up fill mode for the upcoming node. */ | html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi); | ||
switch (n->type) { | |||
case ROFFT_BLOCK: | |||
save_fillmode = 0; | |||
/* Some block macros suspend or cancel .nf. */ | |||
switch (n->tok) { | |||
case MAN_TP: /* Tagged paragraphs */ | |||
case MAN_IP: /* temporarily disable .nf */ | |||
case MAN_HP: /* for the head. */ | |||
save_fillmode = want_fillmode; | |||
/* FALLTHROUGH */ | |||
case MAN_SH: /* Section headers */ | |||
case MAN_SS: /* permanently cancel .nf. */ | |||
want_fillmode = MAN_fi; | |||
/* FALLTHROUGH */ | |||
case MAN_PP: /* These have no head. */ | |||
case MAN_LP: /* They will simply */ | |||
case MAN_P: /* reopen .nf in the body. */ | |||
case MAN_RS: | |||
case MAN_UR: | |||
fillmode(h, MAN_fi); | |||
break; | |||
default: | |||
break; | |||
} | |||
break; | |||
case ROFFT_TBL: | |||
fillmode(h, MAN_fi); | |||
break; | |||
case ROFFT_ELEM: | |||
/* | |||
* Some in-line macros produce tags and/or text | |||
* in the handler, so they require fill mode to be | |||
* configured up front just like for text nodes. | |||
* For the others, keep the traditional approach | |||
* of doing the same, for now. | |||
*/ | |||
fillmode(h, want_fillmode); | |||
break; | |||
case ROFFT_TEXT: | |||
if (fillmode(h, want_fillmode) == MAN_fi && | |||
want_fillmode == MAN_fi && | |||
n->flags & NODE_LINE && *n->string == ' ') | |||
print_otag(h, TAG_BR, ""); | |||
if (*n->string != '\0') | |||
break; | |||
print_paragraph(h); | |||
return; | |||
default: | |||
break; | |||
} | |||
/* Produce output for this node. */ | |||
child = 1; | child = 1; | ||
switch (n->type) { | switch (n->type) { | ||
case ROFFT_TEXT: | case ROFFT_TEXT: | ||
if (*n->string == '\0') { | |||
print_endline(h); | |||
return; | |||
} | |||
if (*n->string == ' ' && n->flags & NODE_LINE && | |||
(h->flags & HTML_NONEWLINE) == 0) | |||
print_endline(h); | |||
else if (n->flags & NODE_DELIMC) | |||
h->flags |= HTML_NOSPACE; | |||
t = h->tag; | t = h->tag; | ||
t->refcnt++; | |||
print_text(h, n->string); | print_text(h, n->string); | ||
break; | break; | ||
case ROFFT_EQN: | case ROFFT_EQN: | ||
t = h->tag; | t = h->tag; | ||
t->refcnt++; | |||
print_eqn(h, n->eqn); | print_eqn(h, n->eqn); | ||
break; | break; | ||
case ROFFT_TBL: | case ROFFT_TBL: | ||
|
|
||
* the "meta" table state. This will be reopened on the | * the "meta" table state. This will be reopened on the | ||
* next table element. | * next table element. | ||
*/ | */ | ||
if (h->tblt) | if (h->tblt != NULL) | ||
print_tblclose(h); | print_tblclose(h); | ||
t = h->tag; | t = h->tag; | ||
t->refcnt++; | |||
if (n->tok < ROFF_MAX) { | if (n->tok < ROFF_MAX) { | ||
roff_html_pre(h, n); | roff_html_pre(h, n); | ||
break; | t->refcnt--; | ||
print_stagq(h, t); | |||
return; | |||
} | } | ||
assert(n->tok >= MAN_TH && n->tok < MAN_MAX); | assert(n->tok >= MAN_TH && n->tok < MAN_MAX); | ||
if (mans[n->tok].pre) | if (man_html_acts[n->tok - MAN_TH].pre != NULL) | ||
child = (*mans[n->tok].pre)(man, n, h); | child = (*man_html_acts[n->tok - MAN_TH].pre)(man, | ||
n, h); | |||
/* Some block macros resume .nf in the body. */ | |||
if (save_fillmode && n->type == ROFFT_BODY) | |||
want_fillmode = save_fillmode; | |||
break; | break; | ||
} | } | ||
if (child && n->child) | if (child && n->child != NULL) | ||
print_man_nodelist(man, n->child, h); | print_man_nodelist(man, n->child, h); | ||
/* This will automatically close out any font scope. */ | /* This will automatically close out any font scope. */ | ||
print_stagq(h, t); | t->refcnt--; | ||
if (n->type == ROFFT_BLOCK && | |||
(n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) { | |||
t = h->tag; | |||
while (t->tag != TAG_DL) | |||
t = t->next; | |||
/* | |||
* Close the list if no further item of the same type | |||
* follows; otherwise, close the item only. | |||
*/ | |||
if (n->next == NULL || | |||
(n->tok == MAN_IP && n->next->tok != MAN_IP) || | |||
(n->tok != MAN_IP && | |||
n->next->tok != MAN_TP && n->next->tok != MAN_TQ)) { | |||
print_tagq(h, t); | |||
t = NULL; | |||
} | |||
} | |||
if (t != NULL) | |||
print_stagq(h, t); | |||
if (fillmode(h, 0) == MAN_nf && | if (n->flags & NODE_NOFILL && n->tok != MAN_YS && | ||
n->next != NULL && n->next->flags & NODE_LINE) | (n->next != NULL && n->next->flags & NODE_LINE)) { | ||
/* In .nf = <pre>, print even empty lines. */ | |||
h->col++; | |||
print_endline(h); | print_endline(h); | ||
} | |||
/* | |||
* MAN_nf switches to no-fill mode, MAN_fi to fill mode. | |||
* Other arguments do not switch. | |||
* The old mode is returned. | |||
*/ | |||
static int | |||
fillmode(struct html *h, int want) | |||
{ | |||
struct tag *pre; | |||
int had; | |||
for (pre = h->tag; pre != NULL; pre = pre->next) | |||
if (pre->tag == TAG_PRE) | |||
break; | |||
had = pre == NULL ? MAN_fi : MAN_nf; | |||
if (want && want != had) { | |||
if (want == MAN_nf) | |||
print_otag(h, TAG_PRE, ""); | |||
else | |||
print_tagq(h, pre); | |||
} | } | ||
return had; | |||
} | } | ||
static int | |||
a2width(const struct roff_node *n, struct roffsu *su) | |||
{ | |||
if (n->type != ROFFT_TEXT) | |||
return 0; | |||
if (a2roffsu(n->string, su, SCALE_EN)) | |||
return 1; | |||
return 0; | |||
} | |||
static void | static void | ||
man_root_pre(MAN_ARGS) | man_root_pre(const struct roff_meta *man, struct html *h) | ||
{ | { | ||
struct tag *t, *tt; | struct tag *t, *tt; | ||
char *title; | char *title; | ||
|
|
||
print_stagq(h, tt); | print_stagq(h, tt); | ||
print_otag(h, TAG_TD, "c", "head-vol"); | print_otag(h, TAG_TD, "c", "head-vol"); | ||
if (NULL != man->vol) | if (man->vol != NULL) | ||
print_text(h, man->vol); | print_text(h, man->vol); | ||
print_stagq(h, tt); | print_stagq(h, tt); | ||
|
|
||
} | } | ||
static void | static void | ||
man_root_post(MAN_ARGS) | man_root_post(const struct roff_meta *man, struct html *h) | ||
{ | { | ||
struct tag *t, *tt; | struct tag *t, *tt; | ||
|
|
||
print_stagq(h, tt); | print_stagq(h, tt); | ||
print_otag(h, TAG_TD, "c", "foot-os"); | print_otag(h, TAG_TD, "c", "foot-os"); | ||
if (man->os) | if (man->os != NULL) | ||
print_text(h, man->os); | print_text(h, man->os); | ||
print_tagq(h, t); | print_tagq(h, t); | ||
} | } | ||
static int | static int | ||
man_sp_pre(MAN_ARGS) | |||
{ | |||
struct roffsu su; | |||
SCALE_VS_INIT(&su, 1); | |||
if (NULL != (n = n->child)) | |||
if ( ! a2roffsu(n->string, &su, SCALE_VS)) | |||
su.scale = 1.0; | |||
print_otag(h, TAG_DIV, "suh", &su); | |||
/* So the div isn't empty: */ | |||
print_text(h, "\\~"); | |||
return 0; | |||
} | |||
static int | |||
man_SH_pre(MAN_ARGS) | man_SH_pre(MAN_ARGS) | ||
{ | { | ||
char *id; | char *id; | ||
if (n->type == ROFFT_HEAD) { | switch (n->type) { | ||
id = html_make_id(n); | case ROFFT_BLOCK: | ||
print_otag(h, TAG_H1, "cTi", "Sh", id); | html_close_paragraph(h); | ||
break; | |||
case ROFFT_HEAD: | |||
id = html_make_id(n, 1); | |||
if (n->tok == MAN_SH) | |||
print_otag(h, TAG_H1, "ci", "Sh", id); | |||
else | |||
print_otag(h, TAG_H2, "ci", "Ss", id); | |||
if (id != NULL) | if (id != NULL) | ||
print_otag(h, TAG_A, "chR", "selflink", id); | print_otag(h, TAG_A, "chR", "permalink", id); | ||
free(id); | break; | ||
case ROFFT_BODY: | |||
break; | |||
default: | |||
abort(); | |||
} | } | ||
return 1; | return 1; | ||
} | } | ||
|
|
||
man_alt_pre(MAN_ARGS) | man_alt_pre(MAN_ARGS) | ||
{ | { | ||
const struct roff_node *nn; | const struct roff_node *nn; | ||
struct tag *t; | |||
int i; | int i; | ||
enum htmltag fp; | enum htmltag fp; | ||
struct tag *t; | |||
for (i = 0, nn = n->child; nn; nn = nn->next, i++) { | for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) { | ||
switch (n->tok) { | switch (n->tok) { | ||
case MAN_BI: | case MAN_BI: | ||
fp = i % 2 ? TAG_I : TAG_B; | fp = i % 2 ? TAG_I : TAG_B; | ||
|
|
||
man_SM_pre(MAN_ARGS) | man_SM_pre(MAN_ARGS) | ||
{ | { | ||
print_otag(h, TAG_SMALL, ""); | print_otag(h, TAG_SMALL, ""); | ||
if (MAN_SB == n->tok) | if (n->tok == MAN_SB) | ||
print_otag(h, TAG_B, ""); | print_otag(h, TAG_B, ""); | ||
return 1; | return 1; | ||
} | } | ||
static int | static int | ||
man_SS_pre(MAN_ARGS) | |||
{ | |||
char *id; | |||
if (n->type == ROFFT_HEAD) { | |||
id = html_make_id(n); | |||
print_otag(h, TAG_H2, "cTi", "Ss", id); | |||
if (id != NULL) | |||
print_otag(h, TAG_A, "chR", "selflink", id); | |||
free(id); | |||
} | |||
return 1; | |||
} | |||
static int | |||
man_PP_pre(MAN_ARGS) | man_PP_pre(MAN_ARGS) | ||
{ | { | ||
switch (n->type) { | |||
if (n->type == ROFFT_HEAD) | case ROFFT_BLOCK: | ||
html_close_paragraph(h); | |||
break; | |||
case ROFFT_HEAD: | |||
return 0; | return 0; | ||
else if (n->type == ROFFT_BLOCK) | case ROFFT_BODY: | ||
print_bvspace(h, n); | if (n->child != NULL && | ||
(n->child->flags & NODE_NOFILL) == 0) | |||
print_otag(h, TAG_P, "c", | |||
n->tok == MAN_PP ? "Pp" : "Pp HP"); | |||
break; | |||
default: | |||
abort(); | |||
} | |||
return 1; | return 1; | ||
} | } | ||
|
|
||
{ | { | ||
const struct roff_node *nn; | const struct roff_node *nn; | ||
if (n->type == ROFFT_BODY) { | switch (n->type) { | ||
print_otag(h, TAG_DD, "c", "It-tag"); | case ROFFT_BLOCK: | ||
html_close_paragraph(h); | |||
/* | |||
* Open a new list unless there is an immediately | |||
* preceding item of the same type. | |||
*/ | |||
if (n->prev == NULL || | |||
(n->tok == MAN_IP && n->prev->tok != MAN_IP) || | |||
(n->tok != MAN_IP && | |||
n->prev->tok != MAN_TP && n->prev->tok != MAN_TQ)) | |||
print_otag(h, TAG_DL, "c", "Bl-tag"); | |||
return 1; | return 1; | ||
} else if (n->type != ROFFT_HEAD) { | case ROFFT_HEAD: | ||
print_otag(h, TAG_DL, "c", "Bl-tag"); | print_otag(h, TAG_DT, ""); | ||
break; | |||
case ROFFT_BODY: | |||
print_otag(h, TAG_DD, ""); | |||
return 1; | return 1; | ||
default: | |||
abort(); | |||
} | } | ||
/* FIXME: width specification. */ | switch(n->tok) { | ||
case MAN_IP: /* Only print the first header element. */ | |||
print_otag(h, TAG_DT, "c", "It-tag"); | if (n->child != NULL) | ||
print_man_node(man, n->child, h); | |||
/* For IP, only print the first header element. */ | break; | ||
case MAN_TP: /* Only print next-line header elements. */ | |||
if (MAN_IP == n->tok && n->child) | case MAN_TQ: | ||
print_man_node(man, n->child, h); | |||
/* For TP, only print next-line header elements. */ | |||
if (MAN_TP == n->tok) { | |||
nn = n->child; | nn = n->child; | ||
while (NULL != nn && 0 == (NODE_LINE & nn->flags)) | while (nn != NULL && (NODE_LINE & nn->flags) == 0) | ||
nn = nn->next; | nn = nn->next; | ||
while (NULL != nn) { | while (nn != NULL) { | ||
print_man_node(man, nn, h); | print_man_node(man, nn, h); | ||
nn = nn->next; | nn = nn->next; | ||
} | } | ||
break; | |||
default: | |||
abort(); | |||
} | } | ||
return 0; | return 0; | ||
} | } | ||
static int | static int | ||
man_HP_pre(MAN_ARGS) | |||
{ | |||
struct roffsu sum, sui; | |||
const struct roff_node *np; | |||
if (n->type == ROFFT_HEAD) | |||
return 0; | |||
else if (n->type != ROFFT_BLOCK) | |||
return 1; | |||
np = n->head->child; | |||
if (np == NULL || !a2width(np, &sum)) | |||
SCALE_HS_INIT(&sum, INDENT); | |||
sui.unit = sum.unit; | |||
sui.scale = -sum.scale; | |||
print_bvspace(h, n); | |||
print_otag(h, TAG_DIV, "csului", "Pp", &sum, &sui); | |||
return 1; | |||
} | |||
static int | |||
man_OP_pre(MAN_ARGS) | man_OP_pre(MAN_ARGS) | ||
{ | { | ||
struct tag *tt; | struct tag *tt; | ||
|
|
||
h->flags |= HTML_NOSPACE; | h->flags |= HTML_NOSPACE; | ||
tt = print_otag(h, TAG_SPAN, "c", "Op"); | tt = print_otag(h, TAG_SPAN, "c", "Op"); | ||
if (NULL != (n = n->child)) { | if ((n = n->child) != NULL) { | ||
print_otag(h, TAG_B, ""); | print_otag(h, TAG_B, ""); | ||
print_text(h, n->string); | print_text(h, n->string); | ||
} | } | ||
print_stagq(h, tt); | print_stagq(h, tt); | ||
if (NULL != n && NULL != n->next) { | if (n != NULL && n->next != NULL) { | ||
print_otag(h, TAG_I, ""); | print_otag(h, TAG_I, ""); | ||
print_text(h, n->next->string); | print_text(h, n->next->string); | ||
} | } | ||
|
|
||
static int | static int | ||
man_ign_pre(MAN_ARGS) | man_ign_pre(MAN_ARGS) | ||
{ | { | ||
return 0; | return 0; | ||
} | } | ||
static int | static int | ||
man_RS_pre(MAN_ARGS) | man_RS_pre(MAN_ARGS) | ||
{ | { | ||
struct roffsu su; | switch (n->type) { | ||
case ROFFT_BLOCK: | |||
if (n->type == ROFFT_HEAD) | html_close_paragraph(h); | ||
break; | |||
case ROFFT_HEAD: | |||
return 0; | return 0; | ||
else if (n->type == ROFFT_BODY) | case ROFFT_BODY: | ||
return 1; | print_otag(h, TAG_DIV, "c", "Bd-indent"); | ||
break; | |||
default: | |||
abort(); | |||
} | |||
return 1; | |||
} | |||
SCALE_HS_INIT(&su, INDENT); | static int | ||
if (n->head->child) | man_SY_pre(MAN_ARGS) | ||
a2width(n->head->child, &su); | { | ||
switch (n->type) { | |||
print_otag(h, TAG_DIV, "sul", &su); | case ROFFT_BLOCK: | ||
html_close_paragraph(h); | |||
print_otag(h, TAG_TABLE, "c", "Nm"); | |||
print_otag(h, TAG_TR, ""); | |||
break; | |||
case ROFFT_HEAD: | |||
print_otag(h, TAG_TD, ""); | |||
print_otag(h, TAG_CODE, "c", "Nm"); | |||
break; | |||
case ROFFT_BODY: | |||
print_otag(h, TAG_TD, ""); | |||
break; | |||
default: | |||
abort(); | |||
} | |||
return 1; | return 1; | ||
} | } | ||
static int | static int | ||
man_UR_pre(MAN_ARGS) | man_UR_pre(MAN_ARGS) | ||
{ | { | ||
char *cp; | |||
n = n->child; | n = n->child; | ||
assert(n->type == ROFFT_HEAD); | assert(n->type == ROFFT_HEAD); | ||
if (n->child != NULL) { | if (n->child != NULL) { | ||
assert(n->child->type == ROFFT_TEXT); | assert(n->child->type == ROFFT_TEXT); | ||
print_otag(h, TAG_A, "cTh", "Lk", n->child->string); | if (n->tok == MAN_MT) { | ||
mandoc_asprintf(&cp, "mailto:%s", n->child->string); | |||
print_otag(h, TAG_A, "ch", "Mt", cp); | |||
free(cp); | |||
} else | |||
print_otag(h, TAG_A, "ch", "Lk", n->child->string); | |||
} | } | ||
assert(n->next->type == ROFFT_BODY); | assert(n->next->type == ROFFT_BODY); | ||
|
|
||
n = n->next; | n = n->next; | ||
print_man_nodelist(man, n->child, h); | print_man_nodelist(man, n->child, h); | ||
return 0; | return 0; | ||
} | |||
static int | |||
man_abort_pre(MAN_ARGS) | |||
{ | |||
abort(); | |||
} | } |