1275970Scy#! /usr/bin/perl
2275970Scy
3275970Scy### To Do:
4275970Scy
5275970Scy# the Bl -column command needs work:
6275970Scy# - support for "-offset" 
7275970Scy# - support for the header widths
8275970Scy
9275970Scy# 
10275970Scy
11275970Scy###
12275970Scy
13275970Scypackage mdoc2texi;
14275970Scyuse strict;
15275970Scyuse warnings;
16275970Scyuse File::Basename qw(dirname);
17275970Scyuse lib dirname(__FILE__);
18275970Scyuse Mdoc qw(ns pp hs mapwords gen_encloser nl);
19275970Scy
20275970Scy# Ignore commments
21275970ScyMdoc::def_macro( '.\"',  sub { () } );
22275970Scy
23275970Scy# Enclosers
24275970ScyMdoc::def_macro( '.An',  sub { @_, ns, '@*' } );
25275970ScyMdoc::def_macro( '.Aq',  gen_encloser(qw(< >)),   greedy => 1);
26275970ScyMdoc::def_macro( '.Bq',  gen_encloser(qw([ ])),   greedy => 1);
27275970ScyMdoc::def_macro( '.Brq', gen_encloser(qw(@{ @})), greedy => 1);
28275970ScyMdoc::def_macro( '.Pq',  gen_encloser(qw/( )/),   greedy => 1);
29275970ScyMdoc::def_macro( '.Qq',  gen_encloser(qw(" ")),   greedy => 1);
30275970ScyMdoc::def_macro( '.Op',  gen_encloser(qw(@code{[ ]})), greedy => 1);
31275970ScyMdoc::def_macro( '.Ql',  gen_encloser(qw(@quoteleft{} @quoteright{})),
32275970Scy    greedy => 1);
33275970ScyMdoc::def_macro( '.Sq',  gen_encloser(qw(@quoteleft{} @quoteright{})),
34275970Scy    greedy => 1);
35275970ScyMdoc::def_macro( '.Dq',  gen_encloser(qw(@quotedblleft{} @quotedblright{})), 
36275970Scy    greedy => 1);
37275970ScyMdoc::def_macro( '.Eq', sub { 
38275970Scy        my ($o, $c) = (shift, pop); 
39275970Scy        gen_encloser($o, $c)->(@_) 
40275970Scy},  greedy => 1);
41275970ScyMdoc::def_macro( '.D1', sub { "\@example\n", ns, @_, ns, "\n\@end example" },
42275970Scy    greedy => 1);
43275970ScyMdoc::def_macro( '.Dl', sub { "\@example\n", ns, @_, ns, "\n\@end example" },
44275970Scy    greedy => 1);
45275970Scy
46275970ScyMdoc::def_macro( '.Oo',  gen_encloser(qw(@code{[ ]})), concat_until => '.Oc');
47275970ScyMdoc::def_macro( 'Oo',   sub { '@code{[', ns, @_ } );
48275970ScyMdoc::def_macro( 'Oc',   sub { @_, ns, pp(']}') } );
49275970Scy
50275970ScyMdoc::def_macro( '.Bro', gen_encloser(qw(@code{@{ @}})), concat_until => '.Brc');
51275970ScyMdoc::def_macro( 'Bro',  sub { '@code{@{', ns, @_ } );
52275970ScyMdoc::def_macro( 'Brc',  sub { @_, ns, pp('@}}') } );
53275970Scy
54275970ScyMdoc::def_macro( '.Po',  gen_encloser(qw/( )/), concat_until => '.Pc');
55275970ScyMdoc::def_macro( 'Po',   sub { '(', @_     } );
56275970ScyMdoc::def_macro( 'Pc',   sub { @_, ')' } );
57275970Scy
58275970ScyMdoc::def_macro( '.Ar', sub { mapwords {"\@kbd{$_}"} @_ } );
59275970ScyMdoc::def_macro( '.Fl', sub { mapwords {"\@code{-$_}"} @_ } );
60275970ScyMdoc::def_macro( '.Cm', sub { mapwords {"\@code{-$_}"} @_ } );
61275970ScyMdoc::def_macro( '.Ic', sub { mapwords {"\@code{$_}"} @_ } );
62275970ScyMdoc::def_macro( '.Cm', sub { mapwords {"\@code{$_}"} @_ } );
63275970ScyMdoc::def_macro( '.Li', sub { mapwords {"\@code{$_}"} @_ } );
64275970ScyMdoc::def_macro( '.Va', sub { mapwords {"\@code{$_}"} @_ } );
65275970ScyMdoc::def_macro( '.Em', sub { mapwords {"\@emph{$_}"} @_ } );
66275970ScyMdoc::def_macro( '.Fn', sub { '@code{'.(shift).'()}' } );
67275970ScyMdoc::def_macro( '.Ss', sub { "\@subsubsection", hs, @_ });
68275970ScyMdoc::def_macro( '.Sh', sub { 
69275970Scy        my $name = "@_"; 
70275970Scy        "\@node", hs, "$name\n", ns, "\@subsection", hs, $name
71275970Scy    });
72275970ScyMdoc::def_macro( '.Ss', sub { "\@subsubsection", hs, @_ });
73275970ScyMdoc::def_macro( '.Xr', sub { '@code{'.(shift).'('.(shift).')}', @_ } );
74275970ScyMdoc::def_macro( '.Sx', gen_encloser(qw(@ref{ })) );
75275970ScyMdoc::def_macro( '.Ux', sub { '@sc{unix}', @_ } );
76275970ScyMdoc::def_macro( '.Fx', sub { '@sc{freebsd}', @_ } );
77275970Scy{
78275970Scy    my $name;
79275970Scy    Mdoc::def_macro('.Nm', sub {
80275970Scy        $name = shift || $ENV{AG_DEF_PROG_NAME} || 'XXX' if (!$name);
81275970Scy        "\@code{$name}"
82275970Scy    } );
83275970Scy}
84275970ScyMdoc::def_macro( '.Pa', sub { mapwords {"\@file{$_}"} @_ } );
85275970ScyMdoc::def_macro( '.Pp', sub { '' } );
86275970Scy
87275970Scy# Setup references
88275970Scy
89275970ScyMdoc::def_macro( '.Rs', sub { "\@*\n", @_ } );
90275970ScyMdoc::set_Re_callback(sub {
91275970Scy        my ($reference) = @_;
92275970Scy        "@*\n", ns, $reference->{authors}, ',', "\@emph{$reference->{title}}",
93275970Scy        ',', $reference->{optional}
94275970Scy    });
95275970Scy
96275970Scy# Set up Bd/Ed
97275970Scy
98275970Scymy %displays = (
99275970Scy    literal => [ '@verbatim', '@end verbatim' ],
100275970Scy);
101275970Scy
102275970ScyMdoc::def_macro( '.Bd', sub {
103275970Scy        (my $type = shift) =~ s/^-//;
104275970Scy        die "Not supported display type <$type>" 
105275970Scy            if not exists $displays{ $type };
106275970Scy
107275970Scy        my $orig_ed = Mdoc::get_macro('.Ed');
108275970Scy        Mdoc::def_macro('.Ed', sub {
109275970Scy                Mdoc::def_macro('.Ed', delete $orig_ed->{run}, %$orig_ed);
110275970Scy                $displays{ $type }[1];
111275970Scy            });
112275970Scy        $displays{ $type }[0]
113275970Scy    });
114275970ScyMdoc::def_macro('.Ed', sub { die '.Ed used but .Bd was not seen' });
115275970Scy
116275970Scy# Set up Bl/El
117275970Scy
118275970Scymy %lists = (
119275970Scy    bullet => [ '@itemize @bullet', '@end itemize' ],
120275970Scy    tag    => [ '@table @asis', '@end table' ],
121275970Scy    column => [ '@table @asis', '@end table' ],
122275970Scy);
123275970Scy
124275970ScyMdoc::set_Bl_callback(sub {
125275970Scy        my $type = shift;
126275970Scy        die "Specify a list type"             if not defined $type;
127275970Scy        $type =~ s/^-//;
128275970Scy        die "Not supported list type <$type>" if not exists $lists{ $type };
129275970Scy        Mdoc::set_El_callback(sub { $lists{ $type }[1] });
130275970Scy        $lists{ $type }[0]
131275970Scy    });
132275970ScyMdoc::def_macro('.It', sub { '@item', hs, @_ });
133275970Scy
134275970Scyfor (qw(Aq Bq Brq Pq Qq Ql Sq Dq Eq Ar Fl Ic Pa Op Cm Li Fx Ux Va)) {
135275970Scy    my $m = Mdoc::get_macro(".$_");
136275970Scy    Mdoc::def_macro($_, delete $m->{run}, %$m);
137275970Scy}
138275970Scy
139275970Scysub print_line {
140275970Scy    my $s = shift;
141275970Scy    $s =~ s/\\&//g;
142275970Scy    print "$s\n";
143275970Scy}
144275970Scy
145275970Scysub preprocess_args {
146275970Scy    $_ =~ s/([{}])/\@$1/g for @_;
147275970Scy}
148275970Scy
149275970Scysub run {
150275970Scy    while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line, 
151275970Scy            \&preprocess_args)
152275970Scy    ) {
153275970Scy        my @ret = Mdoc::call_macro($macro, @args);
154275970Scy        if (@ret) {
155275970Scy            my $s = Mdoc::to_string(@ret);
156275970Scy            print_line($s);
157275970Scy        }
158275970Scy    }
159275970Scy    return 0;
160275970Scy}
161275970Scy
162275970Scyexit run(@ARGV) unless caller;
163