1275970Scy#!/usr/bin/perl 2275970Scy 3275970Scy### ToDo 4275970Scy# Properly implement -columns in the "my %lists" definition... 5275970Scy# 6275970Scy# .Xr requires at least 1 arg, the code here expects at least 2 7275970Scy### 8275970Scy 9275970Scypackage mdoc2man; 10275970Scyuse strict; 11275970Scyuse warnings; 12275970Scyuse File::Basename; 13275970Scyuse lib dirname(__FILE__); 14275970Scyuse Mdoc qw(hs ns pp mapwords son soff stoggle gen_encloser); 15275970Scy 16275970Scy######## 17275970Scy## Basic 18275970Scy######## 19275970Scy 20275970ScyMdoc::def_macro( '.Sh', sub { '.SH', hs, @_ }, raw => 1); 21275970ScyMdoc::def_macro( '.Ss', sub { '.SS', hs, @_ }, raw => 1); 22275970ScyMdoc::def_macro( '.Pp', sub { ".sp \\n(Ppu\n.ne 2\n" } ); 23275970ScyMdoc::def_macro( '.Nd', sub { "\\- @_" } ); 24275970Scy 25275970Scy# Macros that enclose things 26275970ScyMdoc::def_macro( '.Brq', gen_encloser(qw({ })) , greedy => 1 ); 27275970ScyMdoc::def_macro( '.Op' , gen_encloser(qw([ ])) , greedy => 1 ); 28275970ScyMdoc::def_macro( '.Qq' , gen_encloser(qw(" ")) , greedy => 1 ); 29275970ScyMdoc::def_macro( '.Dq' , gen_encloser(qw(\*[Lq] \*[Rq])), greedy => 1 ); 30275970ScyMdoc::def_macro( '.Ql' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 31275970ScyMdoc::def_macro( '.Sq' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 32275970ScyMdoc::def_macro( '.Pq' , gen_encloser(qw/( )/) , greedy => 1 ); 33275970ScyMdoc::def_macro( '.D1' , sub { ".in +4\n", ns, @_ , ns , "\n.in -4" } , greedy => 1); 34275970Scy 35275970ScyMdoc::def_macro( 'Oo', sub { '[', @_ } ); 36275970ScyMdoc::def_macro( 'Oc', sub { ']', @_ } ); 37275970Scy 38275970ScyMdoc::def_macro( 'Po', sub { '(', @_} ); 39275970ScyMdoc::def_macro( 'Pc', sub { ')', @_ } ); 40275970Scy 41275970ScyMdoc::def_macro( 'Bro', sub { '{', ns, @_ } ); 42275970ScyMdoc::def_macro( 'Brc', sub { '}', @_ } ); 43275970Scy 44275970ScyMdoc::def_macro( '.Oo', gen_encloser(qw([ ])), concat_until => '.Oc' ); 45275970ScyMdoc::def_macro( '.Bro', gen_encloser(qw({ })), concat_until => '.Brc' ); 46275970ScyMdoc::def_macro( '.Po', gen_encloser(qw/( )/), concat_until => '.Pc' ); 47275970Scy 48275970ScyMdoc::def_macro( '.Ev', sub { @_ } ); 49275970ScyMdoc::def_macro( '.An', sub { ".NOP ", @_, "\n.br" }, raw => 1 ); 50275970ScyMdoc::def_macro( '.Li', sub { mapwords {"\\f[C]$_\\f[]"} @_ } ); 51275970ScyMdoc::def_macro( '.Cm', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 52275970ScyMdoc::def_macro( '.Ic', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 53275970ScyMdoc::def_macro( '.Fl', sub { mapwords {"\\f\\*[B-Font]\\-$_\\f[]"} @_ } ); 54275970ScyMdoc::def_macro( '.Ar', sub { mapwords {"\\f\\*[I-Font]$_\\f[]"} @_ } ); 55275970ScyMdoc::def_macro( '.Em', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 56275970ScyMdoc::def_macro( '.Va', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 57275970ScyMdoc::def_macro( '.Sx', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 58275970ScyMdoc::def_macro( '.Xr', sub { "\\fC".(shift)."\\fR(".(shift).")\\f[]", @_ } ); 59275970ScyMdoc::def_macro( '.Fn', sub { "\\f\\*[B-Font]".(shift)."\\fR()\\f[]" } ); 60275970ScyMdoc::def_macro( '.Fn', sub { "\\fB".(shift)."\\fR()\\f[]" } ); 61275970ScyMdoc::def_macro( '.Fx', sub { "FreeBSD", @_ } ); 62275970ScyMdoc::def_macro( '.Ux', sub { "UNIX", @_ } ); 63275970Scy 64275970ScyMdoc::def_macro( '.No', sub { ".NOP", map { ($_, ns) } @_ } ); 65275970ScyMdoc::def_macro( '.Pa', sub { mapwords {"\\fI$_\\f[]"} @_; } ); 66275970Scy{ 67275970Scy my $name; 68275970Scy Mdoc::def_macro('.Nm', sub { 69275970Scy $name = shift if (!$name); 70275970Scy "\\f\\*[B-Font]$name\\fP", @_ 71275970Scy } ); 72275970Scy} 73275970Scy 74275970Scy######## 75275970Scy## lists 76275970Scy######## 77275970Scy 78275970Scymy %lists = ( 79275970Scy bullet => sub { 80275970Scy Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 81275970Scy }, 82275970Scy 83275970Scy column => sub { 84275970Scy Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 85275970Scy }, 86275970Scy 87275970Scy tag => sub { 88275970Scy my (%opts) = @_; 89275970Scy 90275970Scy my $width = ''; 91275970Scy 92275970Scy if (exists $opts{width}) { 93275970Scy $width = ' '.((length $opts{width})+1); 94275970Scy } 95275970Scy 96275970Scy if (exists $opts{compact}) { 97275970Scy my $dobrns = 0; 98275970Scy Mdoc::def_macro('.It', sub { 99275970Scy my @ret = (".TP$width\n.NOP", hs); 100275970Scy if ($dobrns) { 101275970Scy ".br\n.ns\n", ns, @ret, @_; 102275970Scy } 103275970Scy else { 104275970Scy $dobrns = 1; 105275970Scy @ret, @_; 106275970Scy } 107275970Scy }, raw => 1); 108275970Scy } 109275970Scy else { 110275970Scy Mdoc::def_macro('.It', sub { 111275970Scy ".TP$width\n.NOP", hs, @_ 112275970Scy }, raw => 1); 113275970Scy } 114275970Scy }, 115275970Scy); 116275970Scy 117275970ScyMdoc::set_Bl_callback(do { my $nested = 0; sub { 118275970Scy my $type = shift; 119275970Scy my %opts = Mdoc::parse_opts(@_); 120275970Scy if (defined $type && $type =~ /-(\w+)/ && exists $lists{$1}) { 121275970Scy 122275970Scy # Wrap nested lists with .RS and .RE 123275970Scy Mdoc::set_El_callback(sub { 124275970Scy return '.RE' if $nested-- > 1; 125275970Scy return '.PP'; 126275970Scy }); 127275970Scy 128275970Scy $lists{$1}->(%opts); 129275970Scy 130275970Scy if ($nested++) { 131275970Scy return ".RS"; 132275970Scy } 133275970Scy else { 134275970Scy return (); 135275970Scy } 136275970Scy } 137275970Scy else { 138275970Scy die "Invalid list type <$type>"; 139275970Scy } 140275970Scy}}, raw => 1); 141275970Scy 142275970Scy# don't bother with arguments for now and do what mdoc2man'.sh' did 143275970Scy 144275970ScyMdoc::def_macro('.Bd', sub { ".br\n.in +4\n.nf" } ); 145275970ScyMdoc::def_macro('.Ed', sub { ".in -4\n.fi" } ); 146275970Scy 147275970ScyMdoc::set_Re_callback(sub { 148275970Scy my ($reference) = @_; 149275970Scy <<"REF"; 150275970Scy$reference->{authors}, 151275970Scy\\fI$reference->{title}\\fR, 152275970Scy$reference->{optional}\n.PP 153275970ScyREF 154275970Scy}); 155275970Scy 156275970Scy# Define all macros which have the same sub for inline and standalone macro 157275970Scyfor (qw(Xr Em Ar Fl Ic Cm Qq Op Nm Pa Sq Li Va Brq Pq Fx Ux)) { 158275970Scy my $m = Mdoc::get_macro(".$_"); 159275970Scy Mdoc::def_macro($_, delete $m->{run}, %$m); 160275970Scy} 161275970Scy 162275970Scysub print_line { 163275970Scy print shift; 164275970Scy print "\n"; 165275970Scy} 166275970Scy 167275970Scysub run { 168275970Scy print <<'DEFS'; 169275970Scy.de1 NOP 170275970Scy. it 1 an-trap 171275970Scy. if \\n[.$] \,\\$*\/ 172275970Scy.. 173275970Scy.ie t \ 174275970Scy.ds B-Font [CB] 175275970Scy.ds I-Font [CI] 176275970Scy.ds R-Font [CR] 177275970Scy.el \ 178275970Scy.ds B-Font B 179275970Scy.ds I-Font I 180275970Scy.ds R-Font R 181275970ScyDEFS 182275970Scy 183275970Scy while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line)) { 184275970Scy my @ret = Mdoc::call_macro($macro, @args); 185275970Scy print_line(Mdoc::to_string(@ret)) if @ret; 186275970Scy } 187275970Scy return 0; 188275970Scy} 189275970Scy 190275970Scyexit run(@ARGV) unless caller; 191275970Scy 192275970Scy1; 193275970Scy__END__ 194