1290001Sglebius#! /usr/bin/perl
2290001Sglebius
3290001Sglebius### To Do:
4290001Sglebius
5290001Sglebius# the Bl -column command needs work:
6290001Sglebius# - support for "-offset" 
7290001Sglebius# - support for the header widths
8290001Sglebius
9290001Sglebius# 
10290001Sglebius
11290001Sglebius###
12290001Sglebius
13290001Sglebiuspackage mdoc2texi;
14290001Sglebiususe strict;
15290001Sglebiususe warnings;
16290001Sglebiususe File::Basename qw(dirname);
17290001Sglebiususe lib dirname(__FILE__);
18290001Sglebiususe Mdoc qw(ns pp hs mapwords gen_encloser nl);
19290001Sglebius
20290001Sglebius# Ignore commments
21290001SglebiusMdoc::def_macro( '.\"',  sub { () } );
22290001Sglebius
23290001Sglebius# Enclosers
24290001SglebiusMdoc::def_macro( '.An',  sub { @_, ns, '@*' } );
25290001SglebiusMdoc::def_macro( '.Aq',  gen_encloser(qw(< >)),   greedy => 1);
26290001SglebiusMdoc::def_macro( '.Bq',  gen_encloser(qw([ ])),   greedy => 1);
27290001SglebiusMdoc::def_macro( '.Brq', gen_encloser(qw(@{ @})), greedy => 1);
28290001SglebiusMdoc::def_macro( '.Pq',  gen_encloser(qw/( )/),   greedy => 1);
29290001SglebiusMdoc::def_macro( '.Qq',  gen_encloser(qw(" ")),   greedy => 1);
30290001SglebiusMdoc::def_macro( '.Op',  gen_encloser(qw(@code{[ ]})), greedy => 1);
31290001SglebiusMdoc::def_macro( '.Ql',  gen_encloser(qw(@quoteleft{} @quoteright{})),
32290001Sglebius    greedy => 1);
33290001SglebiusMdoc::def_macro( '.Sq',  gen_encloser(qw(@quoteleft{} @quoteright{})),
34290001Sglebius    greedy => 1);
35290001SglebiusMdoc::def_macro( '.Dq',  gen_encloser(qw(@quotedblleft{} @quotedblright{})), 
36290001Sglebius    greedy => 1);
37290001SglebiusMdoc::def_macro( '.Eq', sub { 
38290001Sglebius        my ($o, $c) = (shift, pop); 
39290001Sglebius        gen_encloser($o, $c)->(@_) 
40290001Sglebius},  greedy => 1);
41290001SglebiusMdoc::def_macro( '.D1', sub { "\@example\n", ns, @_, ns, "\n\@end example" },
42290001Sglebius    greedy => 1);
43290001SglebiusMdoc::def_macro( '.Dl', sub { "\@example\n", ns, @_, ns, "\n\@end example" },
44290001Sglebius    greedy => 1);
45290001Sglebius
46290001SglebiusMdoc::def_macro( '.Oo',  gen_encloser(qw(@code{[ ]})), concat_until => '.Oc');
47290001SglebiusMdoc::def_macro( 'Oo',   sub { '@code{[', ns, @_ } );
48290001SglebiusMdoc::def_macro( 'Oc',   sub { @_, ns, pp(']}') } );
49290001Sglebius
50290001SglebiusMdoc::def_macro( '.Bro', gen_encloser(qw(@code{@{ @}})), concat_until => '.Brc');
51290001SglebiusMdoc::def_macro( 'Bro',  sub { '@code{@{', ns, @_ } );
52290001SglebiusMdoc::def_macro( 'Brc',  sub { @_, ns, pp('@}}') } );
53290001Sglebius
54290001SglebiusMdoc::def_macro( '.Po',  gen_encloser(qw/( )/), concat_until => '.Pc');
55290001SglebiusMdoc::def_macro( 'Po',   sub { '(', @_     } );
56290001SglebiusMdoc::def_macro( 'Pc',   sub { @_, ')' } );
57290001Sglebius
58290001SglebiusMdoc::def_macro( '.Ar', sub { mapwords {"\@kbd{$_}"} @_ } );
59290001SglebiusMdoc::def_macro( '.Fl', sub { mapwords {"\@code{-$_}"} @_ } );
60290001SglebiusMdoc::def_macro( '.Cm', sub { mapwords {"\@code{-$_}"} @_ } );
61290001SglebiusMdoc::def_macro( '.Ic', sub { mapwords {"\@code{$_}"} @_ } );
62290001SglebiusMdoc::def_macro( '.Cm', sub { mapwords {"\@code{$_}"} @_ } );
63290001SglebiusMdoc::def_macro( '.Li', sub { mapwords {"\@code{$_}"} @_ } );
64290001SglebiusMdoc::def_macro( '.Va', sub { mapwords {"\@code{$_}"} @_ } );
65290001SglebiusMdoc::def_macro( '.Em', sub { mapwords {"\@emph{$_}"} @_ } );
66290001SglebiusMdoc::def_macro( '.Fn', sub { '@code{'.(shift).'()}' } );
67290001SglebiusMdoc::def_macro( '.Ss', sub { "\@subsubsection", hs, @_ });
68290001SglebiusMdoc::def_macro( '.Sh', sub { 
69290001Sglebius        my $name = "@_"; 
70290001Sglebius        "\@node", hs, "$name\n", ns, "\@subsection", hs, $name
71290001Sglebius    });
72290001SglebiusMdoc::def_macro( '.Ss', sub { "\@subsubsection", hs, @_ });
73290001SglebiusMdoc::def_macro( '.Xr', sub { '@code{'.(shift).'('.(shift).')}', @_ } );
74290001SglebiusMdoc::def_macro( '.Sx', gen_encloser(qw(@ref{ })) );
75290001SglebiusMdoc::def_macro( '.Ux', sub { '@sc{unix}', @_ } );
76290001SglebiusMdoc::def_macro( '.Fx', sub { '@sc{freebsd}', @_ } );
77290001Sglebius{
78290001Sglebius    my $name;
79290001Sglebius    Mdoc::def_macro('.Nm', sub {
80290001Sglebius        $name = shift || $ENV{AG_DEF_PROG_NAME} || 'XXX' if (!$name);
81290001Sglebius        "\@code{$name}"
82290001Sglebius    } );
83290001Sglebius}
84290001SglebiusMdoc::def_macro( '.Pa', sub { mapwords {"\@file{$_}"} @_ } );
85290001SglebiusMdoc::def_macro( '.Pp', sub { '' } );
86290001Sglebius
87290001Sglebius# Setup references
88290001Sglebius
89290001SglebiusMdoc::def_macro( '.Rs', sub { "\@*\n", @_ } );
90290001SglebiusMdoc::set_Re_callback(sub {
91290001Sglebius        my ($reference) = @_;
92290001Sglebius        "@*\n", ns, $reference->{authors}, ',', "\@emph{$reference->{title}}",
93290001Sglebius        ',', $reference->{optional}
94290001Sglebius    });
95290001Sglebius
96290001Sglebius# Set up Bd/Ed
97290001Sglebius
98290001Sglebiusmy %displays = (
99290001Sglebius    literal => [ '@verbatim', '@end verbatim' ],
100290001Sglebius);
101290001Sglebius
102290001SglebiusMdoc::def_macro( '.Bd', sub {
103290001Sglebius        (my $type = shift) =~ s/^-//;
104290001Sglebius        die "Not supported display type <$type>" 
105290001Sglebius            if not exists $displays{ $type };
106290001Sglebius
107290001Sglebius        my $orig_ed = Mdoc::get_macro('.Ed');
108290001Sglebius        Mdoc::def_macro('.Ed', sub {
109290001Sglebius                Mdoc::def_macro('.Ed', delete $orig_ed->{run}, %$orig_ed);
110290001Sglebius                $displays{ $type }[1];
111290001Sglebius            });
112290001Sglebius        $displays{ $type }[0]
113290001Sglebius    });
114290001SglebiusMdoc::def_macro('.Ed', sub { die '.Ed used but .Bd was not seen' });
115290001Sglebius
116290001Sglebius# Set up Bl/El
117290001Sglebius
118290001Sglebiusmy %lists = (
119290001Sglebius    bullet => [ '@itemize @bullet', '@end itemize' ],
120290001Sglebius    tag    => [ '@table @asis', '@end table' ],
121290001Sglebius    column => [ '@table @asis', '@end table' ],
122290001Sglebius);
123290001Sglebius
124290001SglebiusMdoc::set_Bl_callback(sub {
125290001Sglebius        my $type = shift;
126290001Sglebius        die "Specify a list type"             if not defined $type;
127290001Sglebius        $type =~ s/^-//;
128290001Sglebius        die "Not supported list type <$type>" if not exists $lists{ $type };
129290001Sglebius        Mdoc::set_El_callback(sub { $lists{ $type }[1] });
130290001Sglebius        $lists{ $type }[0]
131290001Sglebius    });
132290001SglebiusMdoc::def_macro('.It', sub { '@item', hs, @_ });
133290001Sglebius
134290001Sglebiusfor (qw(Aq Bq Brq Pq Qq Ql Sq Dq Eq Ar Fl Ic Pa Op Cm Li Fx Ux Va)) {
135290001Sglebius    my $m = Mdoc::get_macro(".$_");
136290001Sglebius    Mdoc::def_macro($_, delete $m->{run}, %$m);
137290001Sglebius}
138290001Sglebius
139290001Sglebiussub print_line {
140290001Sglebius    my $s = shift;
141290001Sglebius    $s =~ s/\\&//g;
142290001Sglebius    print "$s\n";
143290001Sglebius}
144290001Sglebius
145290001Sglebiussub preprocess_args {
146290001Sglebius    $_ =~ s/([{}])/\@$1/g for @_;
147290001Sglebius}
148290001Sglebius
149290001Sglebiussub run {
150290001Sglebius    while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line, 
151290001Sglebius            \&preprocess_args)
152290001Sglebius    ) {
153290001Sglebius        my @ret = Mdoc::call_macro($macro, @args);
154290001Sglebius        if (@ret) {
155290001Sglebius            my $s = Mdoc::to_string(@ret);
156290001Sglebius            print_line($s);
157290001Sglebius        }
158290001Sglebius    }
159290001Sglebius    return 0;
160290001Sglebius}
161290001Sglebius
162290001Sglebiusexit run(@ARGV) unless caller;
163