diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | main.c | 6 | ||||
-rw-r--r-- | main.h | 2 | ||||
-rw-r--r-- | mandoc.1 | 16 | ||||
-rw-r--r-- | mdoc_man.c | 426 |
5 files changed, 456 insertions, 0 deletions
@@ -93,6 +93,7 @@ SRCS = Makefile \ mdoc_hash.c \ mdoc_html.c \ mdoc_macro.c \ + mdoc_man.c \ mdoc_term.c \ mdoc_validate.c \ msec.c \ @@ -220,6 +221,9 @@ MANDOC_HTML_LNS = eqn_html.ln \ mdoc_html.ln \ tbl_html.ln +MANDOC_MAN_OBJS = mdoc_man.o +MANDOC_MAN_LNS = mdoc_man.ln + MANDOC_TERM_OBJS = eqn_term.o \ man_term.o \ mdoc_term.o \ @@ -236,11 +240,13 @@ MANDOC_TERM_LNS = eqn_term.ln \ tbl_term.ln MANDOC_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_MAN_OBJS) \ $(MANDOC_TERM_OBJS) \ main.o \ out.o \ tree.o MANDOC_LNS = $(MANDOC_HTML_LNS) \ + $(MANDOC_MAN_LNS) \ $(MANDOC_TERM_LNS) \ main.ln \ out.ln \ @@ -46,6 +46,7 @@ enum outt { OUTT_LOCALE, /* -Tlocale */ OUTT_UTF8, /* -Tutf8 */ OUTT_TREE, /* -Ttree */ + OUTT_MAN, /* -Tman */ OUTT_HTML, /* -Thtml */ OUTT_XHTML, /* -Txhtml */ OUTT_LINT, /* -Tlint */ @@ -249,6 +250,9 @@ parse(struct curparse *curp, int fd, curp->outman = tree_man; curp->outmdoc = tree_mdoc; break; + case (OUTT_MAN): + curp->outmdoc = man_mdoc; + break; case (OUTT_PDF): /* FALLTHROUGH */ case (OUTT_ASCII): @@ -312,6 +316,8 @@ toptions(struct curparse *curp, char *arg) curp->wlevel = MANDOCLEVEL_WARNING; } else if (0 == strcmp(arg, "tree")) curp->outtype = OUTT_TREE; + else if (0 == strcmp(arg, "man")) + curp->outtype = OUTT_MAN; else if (0 == strcmp(arg, "html")) curp->outtype = OUTT_HTML; else if (0 == strcmp(arg, "utf8")) @@ -41,6 +41,8 @@ void html_free(void *); void tree_mdoc(void *, const struct mdoc *); void tree_man(void *, const struct man *); +void man_mdoc(void *, const struct mdoc *); + void *locale_alloc(char *); void *utf8_alloc(char *); void *ascii_alloc(char *); @@ -179,6 +179,12 @@ See Parse only: produce no output. Implies .Fl W Ns Cm warning . +.It Fl T Ns Cm man +Produce output in +.Xr man 7 +format; only useful when applied to +.Fl m Ns Cm doc +input. .It Fl T Ns Cm pdf Produce PDF output. See @@ -417,6 +423,16 @@ To check over a large set of manuals: To produce a series of PostScript manuals for A4 paper: .Pp .Dl $ mandoc \-Tps \-Opaper=a4 mdoc.7 man.7 \*(Gt manuals.ps +.Pp +Convert a modern +.Xr mdoc 7 +manual to the older +.Xr man 7 +format, for use on systems lacking an +.Xr mdoc 7 +parser: +.Pp +.Dl $ mandoc \-Tman foo.mdoc \*(Gt foo.man .Sh DIAGNOSTICS Standard error messages reporting parsing errors are prefixed by .Pp diff --git a/mdoc_man.c b/mdoc_man.c new file mode 100644 index 00000000..dbadb796 --- /dev/null +++ b/mdoc_man.c @@ -0,0 +1,426 @@ +/* $Id$ */ +/* + * 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); +} |