1284990Scy#! /usr/local/bin/perl 2284990Scy 3284990Scy## mdoc2man.pl -- Convert mdoc tags to man tags 4284990Scy## 5284990Scy## Author: Harlan Stenn <stenn@ntp.org> 6284990Scy## 7284990Scy## 8284990Scy## This file is part of AutoOpts, a companion to AutoGen. 9284990Scy## AutoOpts is free software. 10284990Scy## AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 11284990Scy## 12284990Scy## AutoOpts is available under any one of two licenses. The license 13284990Scy## in use must be one of these two and the choice is under the control 14284990Scy## of the user of the license. 15284990Scy## 16284990Scy## The GNU Lesser General Public License, version 3 or later 17284990Scy## See the files "COPYING.lgplv3" and "COPYING.gplv3" 18284990Scy## 19284990Scy## The Modified Berkeley Software Distribution License 20284990Scy## See the file "COPYING.mbsd" 21284990Scy## 22284990Scy## These files have the following sha256 sums: 23284990Scy## 24284990Scy## 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 25284990Scy## 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 26284990Scy## 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 27284990Scy 28284990Scy### ToDo 29284990Scy# Properly implement -columns in the "my %lists" definition... 30284990Scy# 31284990Scy# .Xr requires at least 1 arg, the code here expects at least 2 32284990Scy# 33284990Scy### 34284990Scy 35284990Scypackage mdoc2man; 36284990Scyuse strict; 37284990Scyuse warnings; 38284990Scyuse File::Basename; 39284990Scyuse lib dirname(__FILE__); 40284990Scyuse Mdoc qw(hs ns pp mapwords son soff stoggle gen_encloser); 41284990Scy 42284990Scy######## 43284990Scy## Basic 44284990Scy######## 45284990Scy 46284990ScyMdoc::def_macro( '.Sh', sub { '.SH', hs, @_ }, raw => 1); 47284990ScyMdoc::def_macro( '.Ss', sub { '.SS', hs, @_ }, raw => 1); 48284990ScyMdoc::def_macro( '.Pp', sub { ".sp \\n(Ppu\n.ne 2\n" } ); 49284990ScyMdoc::def_macro( '.Nd', sub { "\\- @_" } ); 50284990Scy 51284990Scy# Macros that enclose things 52284990ScyMdoc::def_macro( '.Brq', gen_encloser(qw({ })) , greedy => 1 ); 53284990ScyMdoc::def_macro( '.Op' , gen_encloser(qw([ ])) , greedy => 1 ); 54284990ScyMdoc::def_macro( '.Qq' , gen_encloser(qw(" ")) , greedy => 1 ); 55284990ScyMdoc::def_macro( '.Dq' , gen_encloser(qw(\*[Lq] \*[Rq])), greedy => 1 ); 56284990ScyMdoc::def_macro( '.Ql' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 57284990ScyMdoc::def_macro( '.Sq' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 58284990ScyMdoc::def_macro( '.Pq' , gen_encloser(qw/( )/) , greedy => 1 ); 59284990ScyMdoc::def_macro( '.D1' , sub { ".in +4\n", ns, @_ , ns , "\n.in -4" } , greedy => 1); 60284990Scy 61284990ScyMdoc::def_macro( 'Oo', sub { '[', @_ } ); 62284990ScyMdoc::def_macro( 'Oc', sub { ']', @_ } ); 63284990Scy 64284990ScyMdoc::def_macro( 'Po', sub { '(', @_} ); 65284990ScyMdoc::def_macro( 'Pc', sub { ')', @_ } ); 66284990Scy 67284990ScyMdoc::def_macro( 'Bro', sub { '{', ns, @_ } ); 68284990ScyMdoc::def_macro( 'Brc', sub { '}', @_ } ); 69284990Scy 70284990ScyMdoc::def_macro( '.Oo', gen_encloser(qw([ ])), concat_until => '.Oc' ); 71284990ScyMdoc::def_macro( '.Bro', gen_encloser(qw({ })), concat_until => '.Brc' ); 72284990ScyMdoc::def_macro( '.Po', gen_encloser(qw/( )/), concat_until => '.Pc' ); 73284990Scy 74284990ScyMdoc::def_macro( '.Ev', sub { @_ } ); 75284990ScyMdoc::def_macro( '.An', sub { ".NOP ", @_, "\n.br" }, raw => 1 ); 76284990ScyMdoc::def_macro( '.Li', sub { mapwords {"\\f[C]$_\\f[]"} @_ } ); 77284990ScyMdoc::def_macro( '.Cm', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 78284990ScyMdoc::def_macro( '.Ic', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 79284990ScyMdoc::def_macro( '.Fl', sub { mapwords {"\\f\\*[B-Font]\\-$_\\f[]"} @_ } ); 80284990ScyMdoc::def_macro( '.Ar', sub { mapwords {"\\f\\*[I-Font]$_\\f[]"} @_ } ); 81284990ScyMdoc::def_macro( '.Em', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 82284990ScyMdoc::def_macro( '.Va', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 83284990ScyMdoc::def_macro( '.Sx', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 84284990ScyMdoc::def_macro( '.Xr', sub { "\\fC".(shift)."\\f[]\\fR(".(shift).")\\f[]", @_ } ); 85284990ScyMdoc::def_macro( '.Fn', sub { "\\f\\*[B-Font]".(shift)."\\f[]\\fR()\\f[]" } ); 86284990ScyMdoc::def_macro( '.Fn', sub { "\\fB".(shift)."\\f[]\\fR()\\f[]" } ); 87284990ScyMdoc::def_macro( '.Fx', sub { "FreeBSD", @_ } ); 88284990ScyMdoc::def_macro( '.Ux', sub { "UNIX", @_ } ); 89284990Scy 90284990ScyMdoc::def_macro( '.No', sub { ".NOP", map { ($_, ns) } @_ } ); 91284990ScyMdoc::def_macro( '.Pa', sub { mapwords {"\\fI$_\\f[]"} @_; } ); 92284990Scy{ 93284990Scy my $name; 94284990Scy Mdoc::def_macro('.Nm', sub { 95284990Scy $name = shift if (!$name); 96284990Scy "\\f\\*[B-Font]$name\\fP", @_ 97284990Scy } ); 98284990Scy} 99284990Scy 100284990Scy######## 101284990Scy## lists 102284990Scy######## 103284990Scy 104284990Scymy %lists = ( 105284990Scy bullet => sub { 106284990Scy Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 107284990Scy }, 108284990Scy 109284990Scy column => sub { 110284990Scy Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 111284990Scy }, 112284990Scy 113284990Scy tag => sub { 114284990Scy my (%opts) = @_; 115284990Scy 116284990Scy my $width = ''; 117284990Scy 118284990Scy if (exists $opts{width}) { 119284990Scy $width = ' '.((length $opts{width})+1); 120284990Scy } 121284990Scy 122284990Scy if (exists $opts{compact}) { 123284990Scy my $dobrns = 0; 124284990Scy Mdoc::def_macro('.It', sub { 125284990Scy my @ret = (".TP$width\n.NOP", hs); 126284990Scy if ($dobrns) { 127284990Scy ".br\n.ns\n", ns, @ret, @_; 128284990Scy } 129284990Scy else { 130284990Scy $dobrns = 1; 131284990Scy @ret, @_; 132284990Scy } 133284990Scy }, raw => 1); 134284990Scy } 135284990Scy else { 136284990Scy Mdoc::def_macro('.It', sub { 137284990Scy ".TP$width\n.NOP", hs, @_ 138284990Scy }, raw => 1); 139284990Scy } 140284990Scy }, 141284990Scy); 142284990Scy 143284990ScyMdoc::set_Bl_callback(do { my $nested = 0; sub { 144284990Scy my $type = shift; 145284990Scy my %opts = Mdoc::parse_opts(@_); 146284990Scy if (defined $type && $type =~ /-(\w+)/ && exists $lists{$1}) { 147284990Scy 148284990Scy # Wrap nested lists with .RS and .RE 149284990Scy Mdoc::set_El_callback(sub { 150284990Scy return '.RE' if $nested-- > 1; 151284990Scy return '.PP'; 152284990Scy }); 153284990Scy 154284990Scy $lists{$1}->(%opts); 155284990Scy 156284990Scy if ($nested++) { 157284990Scy return ".RS"; 158284990Scy } 159284990Scy else { 160284990Scy return (); 161284990Scy } 162284990Scy } 163284990Scy else { 164284990Scy die "Invalid list type <$type>"; 165284990Scy } 166284990Scy}}, raw => 1); 167284990Scy 168284990Scy# don't bother with arguments for now and do what mdoc2man'.sh' did 169284990Scy 170284990ScyMdoc::def_macro('.Bd', sub { ".br\n.in +4\n.nf" } ); 171284990ScyMdoc::def_macro('.Ed', sub { ".in -4\n.fi" } ); 172284990Scy 173284990ScyMdoc::set_Re_callback(sub { 174284990Scy my ($reference) = @_; 175284990Scy <<"REF"; 176284990Scy$reference->{authors}, 177284990Scy\\fI$reference->{title}\\fR, 178284990Scy$reference->{optional}\n.PP 179284990ScyREF 180284990Scy}); 181284990Scy 182284990Scy# Define all macros which have the same sub for inline and standalone macro 183284990Scyfor (qw(Xr Em Ar Fl Ic Cm Qq Op Nm Pa Sq Li Va Brq Pq Fx Ux)) { 184284990Scy my $m = Mdoc::get_macro(".$_"); 185284990Scy Mdoc::def_macro($_, delete $m->{run}, %$m); 186284990Scy} 187284990Scy 188284990Scysub print_line { 189284990Scy print shift; 190284990Scy print "\n"; 191284990Scy} 192284990Scy 193284990Scysub run { 194284990Scy print <<'DEFS'; 195284990Scy.de1 NOP 196284990Scy. it 1 an-trap 197284990Scy. if \\n[.$] \,\\$*\/ 198284990Scy.. 199284990Scy.ie t \ 200284990Scy.ds B-Font [CB] 201284990Scy.ds I-Font [CI] 202284990Scy.ds R-Font [CR] 203284990Scy.el \ 204284990Scy.ds B-Font B 205284990Scy.ds I-Font I 206284990Scy.ds R-Font R 207284990ScyDEFS 208284990Scy 209284990Scy while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line)) { 210284990Scy my @ret = Mdoc::call_macro($macro, @args); 211284990Scy print_line(Mdoc::to_string(@ret)) if @ret; 212284990Scy } 213284990Scy return 0; 214284990Scy} 215284990Scy 216284990Scyexit run(@ARGV) unless caller; 217284990Scy 218284990Scy1; 219284990Scy__END__ 220