diff options
Diffstat (limited to 'mdoc_man.c')
-rw-r--r-- | mdoc_man.c | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/mdoc_man.c b/mdoc_man.c new file mode 100644 index 00000000..de62609f --- /dev/null +++ b/mdoc_man.c @@ -0,0 +1,426 @@ +/* $Id: mdoc_man.c,v 1.1 2011/09/17 15:00:51 schwarze Exp $ */ +/* + * Copyright (c) 2011 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 <stdio.h> +#include <string.h> + +#include "mandoc.h" +#include "mdoc.h" +#include "main.h" + +static int need_space = 0; +static int need_nl = 0; + +#define DECL_ARGS const struct mdoc_meta *m, \ + const struct mdoc_node *n + +struct manact { + int (*cond)(DECL_ARGS); + int (*pre)(DECL_ARGS); + void (*post)(DECL_ARGS); + char *prefix; + char *suffix; +}; + +static void print_word(const char *); +static void print_node(DECL_ARGS); + +static int cond_head(DECL_ARGS); +static int cond_body(DECL_ARGS); +static int pre_enc(DECL_ARGS); +static void post_enc(DECL_ARGS); +static void post_percent(DECL_ARGS); + +static int pre_dl(DECL_ARGS); +static void post_dl(DECL_ARGS); +static int pre_it(DECL_ARGS); +static int pre_nm(DECL_ARGS); +static void post_nm(DECL_ARGS); +static int pre_ns(DECL_ARGS); +static int pre_pp(DECL_ARGS); +static int pre_sh(DECL_ARGS); +static void post_sh(DECL_ARGS); +static int pre_xr(DECL_ARGS); + + +static const struct manact manacts[MDOC_MAX] = { + { NULL, NULL, NULL, NULL, NULL }, /* _Ap */ + { NULL, NULL, NULL, NULL, NULL }, /* _Dd */ + { NULL, NULL, NULL, NULL, NULL }, /* _Dt */ + { NULL, NULL, NULL, NULL, NULL }, /* _Os */ + { NULL, pre_sh, post_sh, NULL, NULL }, /* Sh */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ss */ + { NULL, pre_pp, NULL, NULL, NULL }, /* Pp */ + { NULL, NULL, NULL, NULL, NULL }, /* _D1 */ + { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bd */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ed */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bl */ + { NULL, NULL, NULL, NULL, NULL }, /* _El */ + { NULL, pre_it, NULL, NULL, NULL }, /* _It */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ad */ + { NULL, NULL, NULL, NULL, NULL }, /* _An */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */ + { NULL, NULL, NULL, NULL, NULL }, /* _Cd */ + { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */ + { NULL, NULL, NULL, NULL, NULL }, /* _Dv */ + { NULL, NULL, NULL, NULL, NULL }, /* _Er */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ev */ + { NULL, pre_enc, post_enc, "The \\fB", + "\\fP\nutility exits 0 on success, and >0 if an error occurs." + }, /* Ex */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fa */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fd */ + { NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fn */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ft */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ic */ + { NULL, NULL, NULL, NULL, NULL }, /* _In */ + { NULL, NULL, NULL, NULL, NULL }, /* _Li */ + { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */ + { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */ + { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ot */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Pa */ + { NULL, NULL, NULL, NULL, NULL }, /* _Rv */ + { NULL, NULL, NULL, NULL, NULL }, /* _St */ + { NULL, NULL, NULL, NULL, NULL }, /* _Va */ + { NULL, NULL, NULL, NULL, NULL }, /* _Vt */ + { NULL, pre_xr, NULL, NULL, NULL }, /* _Xr */ + { NULL, NULL, post_percent, NULL, NULL }, /* _%A */ + { NULL, NULL, NULL, NULL, NULL }, /* _%B */ + { NULL, NULL, post_percent, NULL, NULL }, /* _%D */ + { NULL, NULL, NULL, NULL, NULL }, /* _%I */ + { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */ + { NULL, NULL, NULL, NULL, NULL }, /* _%N */ + { NULL, NULL, NULL, NULL, NULL }, /* _%O */ + { NULL, NULL, NULL, NULL, NULL }, /* _%P */ + { NULL, NULL, NULL, NULL, NULL }, /* _%R */ + { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */ + { NULL, NULL, NULL, NULL, NULL }, /* _%V */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ac */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ao */ + { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */ + { NULL, NULL, NULL, NULL, NULL }, /* _At */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bf */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bsx */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bx */ + { NULL, NULL, NULL, NULL, NULL }, /* _Db */ + { NULL, NULL, NULL, NULL, NULL }, /* _Dc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Do */ + { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ec */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ef */ + { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* _Em */ + { NULL, NULL, NULL, NULL, NULL }, /* _Eo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fx */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ms */ + { NULL, NULL, NULL, NULL, NULL }, /* _No */ + { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */ + { NULL, NULL, NULL, NULL, NULL }, /* _Nx */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ox */ + { NULL, NULL, NULL, NULL, NULL }, /* _Pc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Pf */ + { NULL, NULL, NULL, NULL, NULL }, /* _Po */ + { cond_body, pre_enc, post_enc, "(", ")" }, /* _Pq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Qc */ + { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */ + { NULL, NULL, NULL, NULL, NULL }, /* _Qo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Qq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Re */ + { cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */ + { NULL, NULL, NULL, NULL, NULL }, /* _Sc */ + { NULL, NULL, NULL, NULL, NULL }, /* _So */ + { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Sm */ + { NULL, NULL, NULL, NULL, NULL }, /* _Sx */ + { NULL, NULL, NULL, NULL, NULL }, /* _Sy */ + { NULL, NULL, NULL, NULL, NULL }, /* _Tn */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ux */ + { NULL, NULL, NULL, NULL, NULL }, /* _Xc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Xo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Oo */ + { NULL, NULL, NULL, NULL, NULL }, /* _Oc */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bk */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ek */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bt */ + { NULL, NULL, NULL, NULL, NULL }, /* _Hf */ + { NULL, NULL, NULL, NULL, NULL }, /* _Fr */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ud */ + { NULL, NULL, NULL, NULL, NULL }, /* _Lb */ + { NULL, NULL, NULL, NULL, NULL }, /* _Lp */ + { NULL, NULL, NULL, NULL, NULL }, /* _Lk */ + { NULL, NULL, NULL, NULL, NULL }, /* _Mt */ + { NULL, NULL, NULL, NULL, NULL }, /* _Brq */ + { NULL, NULL, NULL, NULL, NULL }, /* _Bro */ + { NULL, NULL, NULL, NULL, NULL }, /* _Brc */ + { NULL, NULL, NULL, NULL, NULL }, /* _%C */ + { NULL, NULL, NULL, NULL, NULL }, /* _Es */ + { NULL, NULL, NULL, NULL, NULL }, /* _En */ + { NULL, NULL, NULL, NULL, NULL }, /* _Dx */ + { NULL, NULL, NULL, NULL, NULL }, /* _%Q */ + { NULL, NULL, NULL, NULL, NULL }, /* _br */ + { NULL, NULL, NULL, NULL, NULL }, /* _sp */ + { NULL, NULL, NULL, NULL, NULL }, /* _%U */ + { NULL, NULL, NULL, NULL, NULL }, /* _Ta */ +}; + + +static void +print_word(const char *s) +{ + if (need_nl) { + putchar('\n'); + need_space = 0; + need_nl = 0; + } else if (need_space && + (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1])) + putchar(' '); + need_space = ('(' != s[0] && '[' != s[0]) || '\0' != s[1]; + for ( ; *s; s++) { + switch (*s) { + case (ASCII_NBRSP): + printf("\\~"); + break; + case (ASCII_HYPH): + putchar('-'); + break; + default: + putchar(*s); + break; + } + } +} + +void +man_mdoc(void *arg, const struct mdoc *mdoc) +{ + const struct mdoc_meta *m; + const struct mdoc_node *n; + + m = mdoc_meta(mdoc); + n = mdoc_node(mdoc); + + printf(".TH \"%s\" \"%s\" \"%s\"", m->title, m->msec, m->date); + need_nl = 1; + need_space = 0; + + print_node(m, n); +} + +static void +print_node(DECL_ARGS) +{ + const struct mdoc_node *prev, *sub; + const struct manact *act = NULL; + int cond, do_sub; + + prev = n->prev ? n->prev : n->parent; + if (prev && prev->line < n->line) + need_nl = 1; + + cond = 0; + do_sub = 1; + if (MDOC_TEXT == n->type) { + print_word(n->string); + } else { + act = manacts + n->tok; + cond = NULL == act->cond || (*act->cond)(m, n); + if (cond && act->pre) + do_sub = (*act->pre)(m, n); + } + + if (do_sub) + for (sub = n->child; sub; sub = sub->next) + print_node(m, sub); + + if (cond && act->post) + (*act->post)(m, n); +} + +static int +cond_head(DECL_ARGS) +{ + return(MDOC_HEAD == n->type); +} + +static int +cond_body(DECL_ARGS) +{ + return(MDOC_BODY == n->type); +} + +static int +pre_enc(DECL_ARGS) +{ + const char *prefix; + + prefix = manacts[n->tok].prefix; + if (NULL == prefix) + return(1); + print_word(prefix); + need_space = 0; + return(1); +} + +static void +post_enc(DECL_ARGS) +{ + const char *suffix; + + suffix = manacts[n->tok].suffix; + if (NULL == suffix) + return; + need_space = 0; + print_word(suffix); +} + +static void +post_percent(DECL_ARGS) +{ + + post_enc(m, n); + if (n->next) + print_word(","); + else { + print_word("."); + need_nl = 1; + } +} + +static int +pre_dl(DECL_ARGS) +{ + + need_nl = 1; + print_word(".RS 6n"); + need_nl = 1; + return(1); +} + +static void +post_dl(DECL_ARGS) +{ + + need_nl = 1; + print_word(".RE"); + need_nl = 1; +} + +static int +pre_it(DECL_ARGS) +{ + const struct mdoc_node *bln; + + if (MDOC_HEAD == n->type) { + need_nl = 1; + print_word(".TP"); + bln = n->parent->parent->prev; + print_word(bln->norm->Bl.width); + need_nl = 1; + } + return(1); +} + +static int +pre_nm(DECL_ARGS) +{ + + if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) + return(1); + print_word("\\fB"); + need_space = 0; + if (NULL == n->child) + print_word(m->name); + return(1); +} + +static void +post_nm(DECL_ARGS) +{ + + if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) + return; + need_space = 0; + print_word("\\fP"); +} + +static int +pre_ns(DECL_ARGS) +{ + + need_space = 0; + return(0); +} + +static int +pre_pp(DECL_ARGS) +{ + + need_nl = 1; + if (MDOC_It == n->parent->tok) + print_word(".sp"); + else + print_word(".PP"); + need_nl = 1; + return(1); +} + +static int +pre_sh(DECL_ARGS) +{ + + if (MDOC_HEAD != n->type) + return(1); + need_nl = 1; + print_word(".SH \""); + need_space = 0; + return(1); +} + +static void +post_sh(DECL_ARGS) +{ + + if (MDOC_HEAD != n->type) + return; + need_space = 0; + print_word("\""); + need_nl = 1; +} + +static int +pre_xr(DECL_ARGS) +{ + + n = n->child; + if (NULL == n) + return(0); + print_node(m, n); + n = n->next; + if (NULL == n) + return(0); + need_space = 0; + print_word("("); + print_node(m, n); + print_word(")"); + return(0); +} |