1*2b15cb3dSCy Schubert#!/usr/bin/perl 2*2b15cb3dSCy Schubert 3*2b15cb3dSCy Schubert### ToDo 4*2b15cb3dSCy Schubert# Properly implement -columns in the "my %lists" definition... 5*2b15cb3dSCy Schubert# 6*2b15cb3dSCy Schubert# .Xr requires at least 1 arg, the code here expects at least 2 7*2b15cb3dSCy Schubert### 8*2b15cb3dSCy Schubert 9*2b15cb3dSCy Schubertpackage mdoc2man; 10*2b15cb3dSCy Schubertuse strict; 11*2b15cb3dSCy Schubertuse warnings; 12*2b15cb3dSCy Schubertuse File::Basename; 13*2b15cb3dSCy Schubertuse lib dirname(__FILE__); 14*2b15cb3dSCy Schubertuse Mdoc qw(hs ns pp mapwords son soff stoggle gen_encloser); 15*2b15cb3dSCy Schubert 16*2b15cb3dSCy Schubert######## 17*2b15cb3dSCy Schubert## Basic 18*2b15cb3dSCy Schubert######## 19*2b15cb3dSCy Schubert 20*2b15cb3dSCy SchubertMdoc::def_macro( '.Sh', sub { '.SH', hs, @_ }, raw => 1); 21*2b15cb3dSCy SchubertMdoc::def_macro( '.Ss', sub { '.SS', hs, @_ }, raw => 1); 22*2b15cb3dSCy SchubertMdoc::def_macro( '.Pp', sub { ".sp \\n(Ppu\n.ne 2\n" } ); 23*2b15cb3dSCy SchubertMdoc::def_macro( '.Nd', sub { "\\- @_" } ); 24*2b15cb3dSCy Schubert 25*2b15cb3dSCy Schubert# Macros that enclose things 26*2b15cb3dSCy SchubertMdoc::def_macro( '.Brq', gen_encloser(qw({ })) , greedy => 1 ); 27*2b15cb3dSCy SchubertMdoc::def_macro( '.Op' , gen_encloser(qw([ ])) , greedy => 1 ); 28*2b15cb3dSCy SchubertMdoc::def_macro( '.Qq' , gen_encloser(qw(" ")) , greedy => 1 ); 29*2b15cb3dSCy SchubertMdoc::def_macro( '.Dq' , gen_encloser(qw(\*[Lq] \*[Rq])), greedy => 1 ); 30*2b15cb3dSCy SchubertMdoc::def_macro( '.Ql' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 31*2b15cb3dSCy SchubertMdoc::def_macro( '.Sq' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 32*2b15cb3dSCy SchubertMdoc::def_macro( '.Pq' , gen_encloser(qw/( )/) , greedy => 1 ); 33*2b15cb3dSCy SchubertMdoc::def_macro( '.D1' , sub { ".in +4\n", ns, @_ , ns , "\n.in -4" } , greedy => 1); 34*2b15cb3dSCy Schubert 35*2b15cb3dSCy SchubertMdoc::def_macro( 'Oo', sub { '[', @_ } ); 36*2b15cb3dSCy SchubertMdoc::def_macro( 'Oc', sub { ']', @_ } ); 37*2b15cb3dSCy Schubert 38*2b15cb3dSCy SchubertMdoc::def_macro( 'Po', sub { '(', @_} ); 39*2b15cb3dSCy SchubertMdoc::def_macro( 'Pc', sub { ')', @_ } ); 40*2b15cb3dSCy Schubert 41*2b15cb3dSCy SchubertMdoc::def_macro( 'Bro', sub { '{', ns, @_ } ); 42*2b15cb3dSCy SchubertMdoc::def_macro( 'Brc', sub { '}', @_ } ); 43*2b15cb3dSCy Schubert 44*2b15cb3dSCy SchubertMdoc::def_macro( '.Oo', gen_encloser(qw([ ])), concat_until => '.Oc' ); 45*2b15cb3dSCy SchubertMdoc::def_macro( '.Bro', gen_encloser(qw({ })), concat_until => '.Brc' ); 46*2b15cb3dSCy SchubertMdoc::def_macro( '.Po', gen_encloser(qw/( )/), concat_until => '.Pc' ); 47*2b15cb3dSCy Schubert 48*2b15cb3dSCy SchubertMdoc::def_macro( '.Ev', sub { @_ } ); 49*2b15cb3dSCy SchubertMdoc::def_macro( '.An', sub { ".NOP ", @_, "\n.br" }, raw => 1 ); 50*2b15cb3dSCy SchubertMdoc::def_macro( '.Li', sub { mapwords {"\\f[C]$_\\f[]"} @_ } ); 51*2b15cb3dSCy SchubertMdoc::def_macro( '.Cm', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 52*2b15cb3dSCy SchubertMdoc::def_macro( '.Ic', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 53*2b15cb3dSCy SchubertMdoc::def_macro( '.Fl', sub { mapwords {"\\f\\*[B-Font]\\-$_\\f[]"} @_ } ); 54*2b15cb3dSCy SchubertMdoc::def_macro( '.Ar', sub { mapwords {"\\f\\*[I-Font]$_\\f[]"} @_ } ); 55*2b15cb3dSCy SchubertMdoc::def_macro( '.Em', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 56*2b15cb3dSCy SchubertMdoc::def_macro( '.Va', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 57*2b15cb3dSCy SchubertMdoc::def_macro( '.Sx', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 58*2b15cb3dSCy SchubertMdoc::def_macro( '.Xr', sub { "\\fC".(shift)."\\fR(".(shift).")\\f[]", @_ } ); 59*2b15cb3dSCy SchubertMdoc::def_macro( '.Fn', sub { "\\f\\*[B-Font]".(shift)."\\fR()\\f[]" } ); 60*2b15cb3dSCy SchubertMdoc::def_macro( '.Fn', sub { "\\fB".(shift)."\\fR()\\f[]" } ); 61*2b15cb3dSCy SchubertMdoc::def_macro( '.Fx', sub { "FreeBSD", @_ } ); 62*2b15cb3dSCy SchubertMdoc::def_macro( '.Ux', sub { "UNIX", @_ } ); 63*2b15cb3dSCy Schubert 64*2b15cb3dSCy SchubertMdoc::def_macro( '.No', sub { ".NOP", map { ($_, ns) } @_ } ); 65*2b15cb3dSCy SchubertMdoc::def_macro( '.Pa', sub { mapwords {"\\fI$_\\f[]"} @_; } ); 66*2b15cb3dSCy Schubert{ 67*2b15cb3dSCy Schubert my $name; 68*2b15cb3dSCy Schubert Mdoc::def_macro('.Nm', sub { 69*2b15cb3dSCy Schubert $name = shift if (!$name); 70*2b15cb3dSCy Schubert "\\f\\*[B-Font]$name\\fP", @_ 71*2b15cb3dSCy Schubert } ); 72*2b15cb3dSCy Schubert} 73*2b15cb3dSCy Schubert 74*2b15cb3dSCy Schubert######## 75*2b15cb3dSCy Schubert## lists 76*2b15cb3dSCy Schubert######## 77*2b15cb3dSCy Schubert 78*2b15cb3dSCy Schubertmy %lists = ( 79*2b15cb3dSCy Schubert bullet => sub { 80*2b15cb3dSCy Schubert Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 81*2b15cb3dSCy Schubert }, 82*2b15cb3dSCy Schubert 83*2b15cb3dSCy Schubert column => sub { 84*2b15cb3dSCy Schubert Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 85*2b15cb3dSCy Schubert }, 86*2b15cb3dSCy Schubert 87*2b15cb3dSCy Schubert tag => sub { 88*2b15cb3dSCy Schubert my (%opts) = @_; 89*2b15cb3dSCy Schubert 90*2b15cb3dSCy Schubert my $width = ''; 91*2b15cb3dSCy Schubert 92*2b15cb3dSCy Schubert if (exists $opts{width}) { 93*2b15cb3dSCy Schubert $width = ' '.((length $opts{width})+1); 94*2b15cb3dSCy Schubert } 95*2b15cb3dSCy Schubert 96*2b15cb3dSCy Schubert if (exists $opts{compact}) { 97*2b15cb3dSCy Schubert my $dobrns = 0; 98*2b15cb3dSCy Schubert Mdoc::def_macro('.It', sub { 99*2b15cb3dSCy Schubert my @ret = (".TP$width\n.NOP", hs); 100*2b15cb3dSCy Schubert if ($dobrns) { 101*2b15cb3dSCy Schubert ".br\n.ns\n", ns, @ret, @_; 102*2b15cb3dSCy Schubert } 103*2b15cb3dSCy Schubert else { 104*2b15cb3dSCy Schubert $dobrns = 1; 105*2b15cb3dSCy Schubert @ret, @_; 106*2b15cb3dSCy Schubert } 107*2b15cb3dSCy Schubert }, raw => 1); 108*2b15cb3dSCy Schubert } 109*2b15cb3dSCy Schubert else { 110*2b15cb3dSCy Schubert Mdoc::def_macro('.It', sub { 111*2b15cb3dSCy Schubert ".TP$width\n.NOP", hs, @_ 112*2b15cb3dSCy Schubert }, raw => 1); 113*2b15cb3dSCy Schubert } 114*2b15cb3dSCy Schubert }, 115*2b15cb3dSCy Schubert); 116*2b15cb3dSCy Schubert 117*2b15cb3dSCy SchubertMdoc::set_Bl_callback(do { my $nested = 0; sub { 118*2b15cb3dSCy Schubert my $type = shift; 119*2b15cb3dSCy Schubert my %opts = Mdoc::parse_opts(@_); 120*2b15cb3dSCy Schubert if (defined $type && $type =~ /-(\w+)/ && exists $lists{$1}) { 121*2b15cb3dSCy Schubert 122*2b15cb3dSCy Schubert # Wrap nested lists with .RS and .RE 123*2b15cb3dSCy Schubert Mdoc::set_El_callback(sub { 124*2b15cb3dSCy Schubert return '.RE' if $nested-- > 1; 125*2b15cb3dSCy Schubert return '.PP'; 126*2b15cb3dSCy Schubert }); 127*2b15cb3dSCy Schubert 128*2b15cb3dSCy Schubert $lists{$1}->(%opts); 129*2b15cb3dSCy Schubert 130*2b15cb3dSCy Schubert if ($nested++) { 131*2b15cb3dSCy Schubert return ".RS"; 132*2b15cb3dSCy Schubert } 133*2b15cb3dSCy Schubert else { 134*2b15cb3dSCy Schubert return (); 135*2b15cb3dSCy Schubert } 136*2b15cb3dSCy Schubert } 137*2b15cb3dSCy Schubert else { 138*2b15cb3dSCy Schubert die "Invalid list type <$type>"; 139*2b15cb3dSCy Schubert } 140*2b15cb3dSCy Schubert}}, raw => 1); 141*2b15cb3dSCy Schubert 142*2b15cb3dSCy Schubert# don't bother with arguments for now and do what mdoc2man'.sh' did 143*2b15cb3dSCy Schubert 144*2b15cb3dSCy SchubertMdoc::def_macro('.Bd', sub { ".br\n.in +4\n.nf" } ); 145*2b15cb3dSCy SchubertMdoc::def_macro('.Ed', sub { ".in -4\n.fi" } ); 146*2b15cb3dSCy Schubert 147*2b15cb3dSCy SchubertMdoc::set_Re_callback(sub { 148*2b15cb3dSCy Schubert my ($reference) = @_; 149*2b15cb3dSCy Schubert <<"REF"; 150*2b15cb3dSCy Schubert$reference->{authors}, 151*2b15cb3dSCy Schubert\\fI$reference->{title}\\fR, 152*2b15cb3dSCy Schubert$reference->{optional}\n.PP 153*2b15cb3dSCy SchubertREF 154*2b15cb3dSCy Schubert}); 155*2b15cb3dSCy Schubert 156*2b15cb3dSCy Schubert# Define all macros which have the same sub for inline and standalone macro 157*2b15cb3dSCy Schubertfor (qw(Xr Em Ar Fl Ic Cm Qq Op Nm Pa Sq Li Va Brq Pq Fx Ux)) { 158*2b15cb3dSCy Schubert my $m = Mdoc::get_macro(".$_"); 159*2b15cb3dSCy Schubert Mdoc::def_macro($_, delete $m->{run}, %$m); 160*2b15cb3dSCy Schubert} 161*2b15cb3dSCy Schubert 162*2b15cb3dSCy Schubertsub print_line { 163*2b15cb3dSCy Schubert print shift; 164*2b15cb3dSCy Schubert print "\n"; 165*2b15cb3dSCy Schubert} 166*2b15cb3dSCy Schubert 167*2b15cb3dSCy Schubertsub run { 168*2b15cb3dSCy Schubert print <<'DEFS'; 169*2b15cb3dSCy Schubert.de1 NOP 170*2b15cb3dSCy Schubert. it 1 an-trap 171*2b15cb3dSCy Schubert. if \\n[.$] \,\\$*\/ 172*2b15cb3dSCy Schubert.. 173*2b15cb3dSCy Schubert.ie t \ 174*2b15cb3dSCy Schubert.ds B-Font [CB] 175*2b15cb3dSCy Schubert.ds I-Font [CI] 176*2b15cb3dSCy Schubert.ds R-Font [CR] 177*2b15cb3dSCy Schubert.el \ 178*2b15cb3dSCy Schubert.ds B-Font B 179*2b15cb3dSCy Schubert.ds I-Font I 180*2b15cb3dSCy Schubert.ds R-Font R 181*2b15cb3dSCy SchubertDEFS 182*2b15cb3dSCy Schubert 183*2b15cb3dSCy Schubert while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line)) { 184*2b15cb3dSCy Schubert my @ret = Mdoc::call_macro($macro, @args); 185*2b15cb3dSCy Schubert print_line(Mdoc::to_string(@ret)) if @ret; 186*2b15cb3dSCy Schubert } 187*2b15cb3dSCy Schubert return 0; 188*2b15cb3dSCy Schubert} 189*2b15cb3dSCy Schubert 190*2b15cb3dSCy Schubertexit run(@ARGV) unless caller; 191*2b15cb3dSCy Schubert 192*2b15cb3dSCy Schubert1; 193*2b15cb3dSCy Schubert__END__ 194