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