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