1*2b15cb3dSCy Schubert#! /usr/bin/perl 2*2b15cb3dSCy Schubert 3*2b15cb3dSCy Schubert### To Do: 4*2b15cb3dSCy Schubert 5*2b15cb3dSCy Schubert# the Bl -column command needs work: 6*2b15cb3dSCy Schubert# - support for "-offset" 7*2b15cb3dSCy Schubert# - support for the header widths 8*2b15cb3dSCy Schubert 9*2b15cb3dSCy Schubert# 10*2b15cb3dSCy Schubert 11*2b15cb3dSCy Schubert### 12*2b15cb3dSCy Schubert 13*2b15cb3dSCy Schubertpackage mdoc2texi; 14*2b15cb3dSCy Schubertuse strict; 15*2b15cb3dSCy Schubertuse warnings; 16*2b15cb3dSCy Schubertuse File::Basename qw(dirname); 17*2b15cb3dSCy Schubertuse lib dirname(__FILE__); 18*2b15cb3dSCy Schubertuse Mdoc qw(ns pp hs mapwords gen_encloser nl); 19*2b15cb3dSCy Schubert 20*2b15cb3dSCy Schubert# Ignore commments 21*2b15cb3dSCy SchubertMdoc::def_macro( '.\"', sub { () } ); 22*2b15cb3dSCy Schubert 23*2b15cb3dSCy Schubert# Enclosers 24*2b15cb3dSCy SchubertMdoc::def_macro( '.An', sub { @_, ns, '@*' } ); 25*2b15cb3dSCy SchubertMdoc::def_macro( '.Aq', gen_encloser(qw(< >)), greedy => 1); 26*2b15cb3dSCy SchubertMdoc::def_macro( '.Bq', gen_encloser(qw([ ])), greedy => 1); 27*2b15cb3dSCy SchubertMdoc::def_macro( '.Brq', gen_encloser(qw(@{ @})), greedy => 1); 28*2b15cb3dSCy SchubertMdoc::def_macro( '.Pq', gen_encloser(qw/( )/), greedy => 1); 29*2b15cb3dSCy SchubertMdoc::def_macro( '.Qq', gen_encloser(qw(" ")), greedy => 1); 30*2b15cb3dSCy SchubertMdoc::def_macro( '.Op', gen_encloser(qw(@code{[ ]})), greedy => 1); 31*2b15cb3dSCy SchubertMdoc::def_macro( '.Ql', gen_encloser(qw(@quoteleft{} @quoteright{})), 32*2b15cb3dSCy Schubert greedy => 1); 33*2b15cb3dSCy SchubertMdoc::def_macro( '.Sq', gen_encloser(qw(@quoteleft{} @quoteright{})), 34*2b15cb3dSCy Schubert greedy => 1); 35*2b15cb3dSCy SchubertMdoc::def_macro( '.Dq', gen_encloser(qw(@quotedblleft{} @quotedblright{})), 36*2b15cb3dSCy Schubert greedy => 1); 37*2b15cb3dSCy SchubertMdoc::def_macro( '.Eq', sub { 38*2b15cb3dSCy Schubert my ($o, $c) = (shift, pop); 39*2b15cb3dSCy Schubert gen_encloser($o, $c)->(@_) 40*2b15cb3dSCy Schubert}, greedy => 1); 41*2b15cb3dSCy SchubertMdoc::def_macro( '.D1', sub { "\@example\n", ns, @_, ns, "\n\@end example" }, 42*2b15cb3dSCy Schubert greedy => 1); 43*2b15cb3dSCy SchubertMdoc::def_macro( '.Dl', sub { "\@example\n", ns, @_, ns, "\n\@end example" }, 44*2b15cb3dSCy Schubert greedy => 1); 45*2b15cb3dSCy Schubert 46*2b15cb3dSCy SchubertMdoc::def_macro( '.Oo', gen_encloser(qw(@code{[ ]})), concat_until => '.Oc'); 47*2b15cb3dSCy SchubertMdoc::def_macro( 'Oo', sub { '@code{[', ns, @_ } ); 48*2b15cb3dSCy SchubertMdoc::def_macro( 'Oc', sub { @_, ns, pp(']}') } ); 49*2b15cb3dSCy Schubert 50*2b15cb3dSCy SchubertMdoc::def_macro( '.Bro', gen_encloser(qw(@code{@{ @}})), concat_until => '.Brc'); 51*2b15cb3dSCy SchubertMdoc::def_macro( 'Bro', sub { '@code{@{', ns, @_ } ); 52*2b15cb3dSCy SchubertMdoc::def_macro( 'Brc', sub { @_, ns, pp('@}}') } ); 53*2b15cb3dSCy Schubert 54*2b15cb3dSCy SchubertMdoc::def_macro( '.Po', gen_encloser(qw/( )/), concat_until => '.Pc'); 55*2b15cb3dSCy SchubertMdoc::def_macro( 'Po', sub { '(', @_ } ); 56*2b15cb3dSCy SchubertMdoc::def_macro( 'Pc', sub { @_, ')' } ); 57*2b15cb3dSCy Schubert 58*2b15cb3dSCy SchubertMdoc::def_macro( '.Ar', sub { mapwords {"\@kbd{$_}"} @_ } ); 59*2b15cb3dSCy SchubertMdoc::def_macro( '.Fl', sub { mapwords {"\@code{-$_}"} @_ } ); 60*2b15cb3dSCy SchubertMdoc::def_macro( '.Cm', sub { mapwords {"\@code{-$_}"} @_ } ); 61*2b15cb3dSCy SchubertMdoc::def_macro( '.Ic', sub { mapwords {"\@code{$_}"} @_ } ); 62*2b15cb3dSCy SchubertMdoc::def_macro( '.Cm', sub { mapwords {"\@code{$_}"} @_ } ); 63*2b15cb3dSCy SchubertMdoc::def_macro( '.Li', sub { mapwords {"\@code{$_}"} @_ } ); 64*2b15cb3dSCy SchubertMdoc::def_macro( '.Va', sub { mapwords {"\@code{$_}"} @_ } ); 65*2b15cb3dSCy SchubertMdoc::def_macro( '.Em', sub { mapwords {"\@emph{$_}"} @_ } ); 66*2b15cb3dSCy SchubertMdoc::def_macro( '.Fn', sub { '@code{'.(shift).'()}' } ); 67*2b15cb3dSCy SchubertMdoc::def_macro( '.Ss', sub { "\@subsubsection", hs, @_ }); 68*2b15cb3dSCy SchubertMdoc::def_macro( '.Sh', sub { 69*2b15cb3dSCy Schubert my $name = "@_"; 70*2b15cb3dSCy Schubert "\@node", hs, "$name\n", ns, "\@subsection", hs, $name 71*2b15cb3dSCy Schubert }); 72*2b15cb3dSCy SchubertMdoc::def_macro( '.Ss', sub { "\@subsubsection", hs, @_ }); 73*2b15cb3dSCy SchubertMdoc::def_macro( '.Xr', sub { '@code{'.(shift).'('.(shift).')}', @_ } ); 74*2b15cb3dSCy SchubertMdoc::def_macro( '.Sx', gen_encloser(qw(@ref{ })) ); 75*2b15cb3dSCy SchubertMdoc::def_macro( '.Ux', sub { '@sc{unix}', @_ } ); 76*2b15cb3dSCy SchubertMdoc::def_macro( '.Fx', sub { '@sc{freebsd}', @_ } ); 77*2b15cb3dSCy Schubert{ 78*2b15cb3dSCy Schubert my $name; 79*2b15cb3dSCy Schubert Mdoc::def_macro('.Nm', sub { 80*2b15cb3dSCy Schubert $name = shift || $ENV{AG_DEF_PROG_NAME} || 'XXX' if (!$name); 81*2b15cb3dSCy Schubert "\@code{$name}" 82*2b15cb3dSCy Schubert } ); 83*2b15cb3dSCy Schubert} 84*2b15cb3dSCy SchubertMdoc::def_macro( '.Pa', sub { mapwords {"\@file{$_}"} @_ } ); 85*2b15cb3dSCy SchubertMdoc::def_macro( '.Pp', sub { '' } ); 86*2b15cb3dSCy Schubert 87*2b15cb3dSCy Schubert# Setup references 88*2b15cb3dSCy Schubert 89*2b15cb3dSCy SchubertMdoc::def_macro( '.Rs', sub { "\@*\n", @_ } ); 90*2b15cb3dSCy SchubertMdoc::set_Re_callback(sub { 91*2b15cb3dSCy Schubert my ($reference) = @_; 92*2b15cb3dSCy Schubert "@*\n", ns, $reference->{authors}, ',', "\@emph{$reference->{title}}", 93*2b15cb3dSCy Schubert ',', $reference->{optional} 94*2b15cb3dSCy Schubert }); 95*2b15cb3dSCy Schubert 96*2b15cb3dSCy Schubert# Set up Bd/Ed 97*2b15cb3dSCy Schubert 98*2b15cb3dSCy Schubertmy %displays = ( 99*2b15cb3dSCy Schubert literal => [ '@verbatim', '@end verbatim' ], 100*2b15cb3dSCy Schubert); 101*2b15cb3dSCy Schubert 102*2b15cb3dSCy SchubertMdoc::def_macro( '.Bd', sub { 103*2b15cb3dSCy Schubert (my $type = shift) =~ s/^-//; 104*2b15cb3dSCy Schubert die "Not supported display type <$type>" 105*2b15cb3dSCy Schubert if not exists $displays{ $type }; 106*2b15cb3dSCy Schubert 107*2b15cb3dSCy Schubert my $orig_ed = Mdoc::get_macro('.Ed'); 108*2b15cb3dSCy Schubert Mdoc::def_macro('.Ed', sub { 109*2b15cb3dSCy Schubert Mdoc::def_macro('.Ed', delete $orig_ed->{run}, %$orig_ed); 110*2b15cb3dSCy Schubert $displays{ $type }[1]; 111*2b15cb3dSCy Schubert }); 112*2b15cb3dSCy Schubert $displays{ $type }[0] 113*2b15cb3dSCy Schubert }); 114*2b15cb3dSCy SchubertMdoc::def_macro('.Ed', sub { die '.Ed used but .Bd was not seen' }); 115*2b15cb3dSCy Schubert 116*2b15cb3dSCy Schubert# Set up Bl/El 117*2b15cb3dSCy Schubert 118*2b15cb3dSCy Schubertmy %lists = ( 119*2b15cb3dSCy Schubert bullet => [ '@itemize @bullet', '@end itemize' ], 120*2b15cb3dSCy Schubert tag => [ '@table @asis', '@end table' ], 121*2b15cb3dSCy Schubert column => [ '@table @asis', '@end table' ], 122*2b15cb3dSCy Schubert); 123*2b15cb3dSCy Schubert 124*2b15cb3dSCy SchubertMdoc::set_Bl_callback(sub { 125*2b15cb3dSCy Schubert my $type = shift; 126*2b15cb3dSCy Schubert die "Specify a list type" if not defined $type; 127*2b15cb3dSCy Schubert $type =~ s/^-//; 128*2b15cb3dSCy Schubert die "Not supported list type <$type>" if not exists $lists{ $type }; 129*2b15cb3dSCy Schubert Mdoc::set_El_callback(sub { $lists{ $type }[1] }); 130*2b15cb3dSCy Schubert $lists{ $type }[0] 131*2b15cb3dSCy Schubert }); 132*2b15cb3dSCy SchubertMdoc::def_macro('.It', sub { '@item', hs, @_ }); 133*2b15cb3dSCy Schubert 134*2b15cb3dSCy Schubertfor (qw(Aq Bq Brq Pq Qq Ql Sq Dq Eq Ar Fl Ic Pa Op Cm Li Fx Ux Va)) { 135*2b15cb3dSCy Schubert my $m = Mdoc::get_macro(".$_"); 136*2b15cb3dSCy Schubert Mdoc::def_macro($_, delete $m->{run}, %$m); 137*2b15cb3dSCy Schubert} 138*2b15cb3dSCy Schubert 139*2b15cb3dSCy Schubertsub print_line { 140*2b15cb3dSCy Schubert my $s = shift; 141*2b15cb3dSCy Schubert $s =~ s/\\&//g; 142*2b15cb3dSCy Schubert print "$s\n"; 143*2b15cb3dSCy Schubert} 144*2b15cb3dSCy Schubert 145*2b15cb3dSCy Schubertsub preprocess_args { 146*2b15cb3dSCy Schubert $_ =~ s/([{}])/\@$1/g for @_; 147*2b15cb3dSCy Schubert} 148*2b15cb3dSCy Schubert 149*2b15cb3dSCy Schubertsub run { 150*2b15cb3dSCy Schubert while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line, 151*2b15cb3dSCy Schubert \&preprocess_args) 152*2b15cb3dSCy Schubert ) { 153*2b15cb3dSCy Schubert my @ret = Mdoc::call_macro($macro, @args); 154*2b15cb3dSCy Schubert if (@ret) { 155*2b15cb3dSCy Schubert my $s = Mdoc::to_string(@ret); 156*2b15cb3dSCy Schubert print_line($s); 157*2b15cb3dSCy Schubert } 158*2b15cb3dSCy Schubert } 159*2b15cb3dSCy Schubert return 0; 160*2b15cb3dSCy Schubert} 161*2b15cb3dSCy Schubert 162*2b15cb3dSCy Schubertexit run(@ARGV) unless caller; 163