mdoc2man revision 1.1.1.1.2.2 1 1.1.1.1.2.2 riz #!/usr/bin/perl
2 1.1.1.1.2.2 riz
3 1.1.1.1.2.2 riz ### ToDo
4 1.1.1.1.2.2 riz # Properly implement -columns in the "my %lists" definition...
5 1.1.1.1.2.2 riz #
6 1.1.1.1.2.2 riz # .Xr requires at least 1 arg, the code here expects at least 2
7 1.1.1.1.2.2 riz ###
8 1.1.1.1.2.2 riz
9 1.1.1.1.2.2 riz package mdoc2man;
10 1.1.1.1.2.2 riz use strict;
11 1.1.1.1.2.2 riz use warnings;
12 1.1.1.1.2.2 riz use File::Basename;
13 1.1.1.1.2.2 riz use lib dirname(__FILE__);
14 1.1.1.1.2.2 riz use Mdoc qw(hs ns pp mapwords son soff stoggle gen_encloser);
15 1.1.1.1.2.2 riz
16 1.1.1.1.2.2 riz ########
17 1.1.1.1.2.2 riz ## Basic
18 1.1.1.1.2.2 riz ########
19 1.1.1.1.2.2 riz
20 1.1.1.1.2.2 riz Mdoc::def_macro( '.Sh', sub { '.SH', hs, @_ }, raw => 1);
21 1.1.1.1.2.2 riz Mdoc::def_macro( '.Ss', sub { '.SS', hs, @_ }, raw => 1);
22 1.1.1.1.2.2 riz Mdoc::def_macro( '.Pp', sub { ".sp \\n(Ppu\n.ne 2\n" } );
23 1.1.1.1.2.2 riz Mdoc::def_macro( '.Nd', sub { "\\- @_" } );
24 1.1.1.1.2.2 riz
25 1.1.1.1.2.2 riz # Macros that enclose things
26 1.1.1.1.2.2 riz Mdoc::def_macro( '.Brq', gen_encloser(qw({ })) , greedy => 1 );
27 1.1.1.1.2.2 riz Mdoc::def_macro( '.Op' , gen_encloser(qw([ ])) , greedy => 1 );
28 1.1.1.1.2.2 riz Mdoc::def_macro( '.Qq' , gen_encloser(qw(" ")) , greedy => 1 );
29 1.1.1.1.2.2 riz Mdoc::def_macro( '.Dq' , gen_encloser(qw(\*[Lq] \*[Rq])), greedy => 1 );
30 1.1.1.1.2.2 riz Mdoc::def_macro( '.Ql' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 );
31 1.1.1.1.2.2 riz Mdoc::def_macro( '.Sq' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 );
32 1.1.1.1.2.2 riz Mdoc::def_macro( '.Pq' , gen_encloser(qw/( )/) , greedy => 1 );
33 1.1.1.1.2.2 riz Mdoc::def_macro( '.D1' , sub { ".in +4\n", ns, @_ , ns , "\n.in -4" } , greedy => 1);
34 1.1.1.1.2.2 riz
35 1.1.1.1.2.2 riz Mdoc::def_macro( 'Oo', sub { '[', @_ } );
36 1.1.1.1.2.2 riz Mdoc::def_macro( 'Oc', sub { ']', @_ } );
37 1.1.1.1.2.2 riz
38 1.1.1.1.2.2 riz Mdoc::def_macro( 'Po', sub { '(', @_} );
39 1.1.1.1.2.2 riz Mdoc::def_macro( 'Pc', sub { ')', @_ } );
40 1.1.1.1.2.2 riz
41 1.1.1.1.2.2 riz Mdoc::def_macro( 'Bro', sub { '{', ns, @_ } );
42 1.1.1.1.2.2 riz Mdoc::def_macro( 'Brc', sub { '}', @_ } );
43 1.1.1.1.2.2 riz
44 1.1.1.1.2.2 riz Mdoc::def_macro( '.Oo', gen_encloser(qw([ ])), concat_until => '.Oc' );
45 1.1.1.1.2.2 riz Mdoc::def_macro( '.Bro', gen_encloser(qw({ })), concat_until => '.Brc' );
46 1.1.1.1.2.2 riz Mdoc::def_macro( '.Po', gen_encloser(qw/( )/), concat_until => '.Pc' );
47 1.1.1.1.2.2 riz
48 1.1.1.1.2.2 riz Mdoc::def_macro( '.Ev', sub { @_ } );
49 1.1.1.1.2.2 riz Mdoc::def_macro( '.An', sub { ".NOP ", @_, "\n.br" }, raw => 1 );
50 1.1.1.1.2.2 riz Mdoc::def_macro( '.Li', sub { mapwords {"\\f[C]$_\\f[]"} @_ } );
51 1.1.1.1.2.2 riz Mdoc::def_macro( '.Cm', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } );
52 1.1.1.1.2.2 riz Mdoc::def_macro( '.Ic', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } );
53 1.1.1.1.2.2 riz Mdoc::def_macro( '.Fl', sub { mapwords {"\\f\\*[B-Font]\\-$_\\f[]"} @_ } );
54 1.1.1.1.2.2 riz Mdoc::def_macro( '.Ar', sub { mapwords {"\\f\\*[I-Font]$_\\f[]"} @_ } );
55 1.1.1.1.2.2 riz Mdoc::def_macro( '.Em', sub { mapwords {"\\fI$_\\f[]"} @_ } );
56 1.1.1.1.2.2 riz Mdoc::def_macro( '.Va', sub { mapwords {"\\fI$_\\f[]"} @_ } );
57 1.1.1.1.2.2 riz Mdoc::def_macro( '.Sx', sub { mapwords {"\\fI$_\\f[]"} @_ } );
58 1.1.1.1.2.2 riz Mdoc::def_macro( '.Xr', sub { "\\fC".(shift)."\\fR(".(shift).")\\f[]", @_ } );
59 1.1.1.1.2.2 riz Mdoc::def_macro( '.Fn', sub { "\\f\\*[B-Font]".(shift)."\\fR()\\f[]" } );
60 1.1.1.1.2.2 riz Mdoc::def_macro( '.Fn', sub { "\\fB".(shift)."\\fR()\\f[]" } );
61 1.1.1.1.2.2 riz Mdoc::def_macro( '.Fx', sub { "FreeBSD", @_ } );
62 1.1.1.1.2.2 riz Mdoc::def_macro( '.Ux', sub { "UNIX", @_ } );
63 1.1.1.1.2.2 riz
64 1.1.1.1.2.2 riz Mdoc::def_macro( '.No', sub { ".NOP", map { ($_, ns) } @_ } );
65 1.1.1.1.2.2 riz Mdoc::def_macro( '.Pa', sub { mapwords {"\\fI$_\\f[]"} @_; } );
66 1.1.1.1.2.2 riz {
67 1.1.1.1.2.2 riz my $name;
68 1.1.1.1.2.2 riz Mdoc::def_macro('.Nm', sub {
69 1.1.1.1.2.2 riz $name = shift if (!$name);
70 1.1.1.1.2.2 riz "\\f\\*[B-Font]$name\\fP", @_
71 1.1.1.1.2.2 riz } );
72 1.1.1.1.2.2 riz }
73 1.1.1.1.2.2 riz
74 1.1.1.1.2.2 riz ########
75 1.1.1.1.2.2 riz ## lists
76 1.1.1.1.2.2 riz ########
77 1.1.1.1.2.2 riz
78 1.1.1.1.2.2 riz my %lists = (
79 1.1.1.1.2.2 riz bullet => sub {
80 1.1.1.1.2.2 riz Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' });
81 1.1.1.1.2.2 riz },
82 1.1.1.1.2.2 riz
83 1.1.1.1.2.2 riz column => sub {
84 1.1.1.1.2.2 riz Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' });
85 1.1.1.1.2.2 riz },
86 1.1.1.1.2.2 riz
87 1.1.1.1.2.2 riz tag => sub {
88 1.1.1.1.2.2 riz my (%opts) = @_;
89 1.1.1.1.2.2 riz
90 1.1.1.1.2.2 riz my $width = '';
91 1.1.1.1.2.2 riz
92 1.1.1.1.2.2 riz if (exists $opts{width}) {
93 1.1.1.1.2.2 riz $width = ' '.((length $opts{width})+1);
94 1.1.1.1.2.2 riz }
95 1.1.1.1.2.2 riz
96 1.1.1.1.2.2 riz if (exists $opts{compact}) {
97 1.1.1.1.2.2 riz my $dobrns = 0;
98 1.1.1.1.2.2 riz Mdoc::def_macro('.It', sub {
99 1.1.1.1.2.2 riz my @ret = (".TP$width\n.NOP", hs);
100 1.1.1.1.2.2 riz if ($dobrns) {
101 1.1.1.1.2.2 riz ".br\n.ns\n", ns, @ret, @_;
102 1.1.1.1.2.2 riz }
103 1.1.1.1.2.2 riz else {
104 1.1.1.1.2.2 riz $dobrns = 1;
105 1.1.1.1.2.2 riz @ret, @_;
106 1.1.1.1.2.2 riz }
107 1.1.1.1.2.2 riz }, raw => 1);
108 1.1.1.1.2.2 riz }
109 1.1.1.1.2.2 riz else {
110 1.1.1.1.2.2 riz Mdoc::def_macro('.It', sub {
111 1.1.1.1.2.2 riz ".TP$width\n.NOP", hs, @_
112 1.1.1.1.2.2 riz }, raw => 1);
113 1.1.1.1.2.2 riz }
114 1.1.1.1.2.2 riz },
115 1.1.1.1.2.2 riz );
116 1.1.1.1.2.2 riz
117 1.1.1.1.2.2 riz Mdoc::set_Bl_callback(do { my $nested = 0; sub {
118 1.1.1.1.2.2 riz my $type = shift;
119 1.1.1.1.2.2 riz my %opts = Mdoc::parse_opts(@_);
120 1.1.1.1.2.2 riz if (defined $type && $type =~ /-(\w+)/ && exists $lists{$1}) {
121 1.1.1.1.2.2 riz
122 1.1.1.1.2.2 riz # Wrap nested lists with .RS and .RE
123 1.1.1.1.2.2 riz Mdoc::set_El_callback(sub {
124 1.1.1.1.2.2 riz return '.RE' if $nested-- > 1;
125 1.1.1.1.2.2 riz return '.PP';
126 1.1.1.1.2.2 riz });
127 1.1.1.1.2.2 riz
128 1.1.1.1.2.2 riz $lists{$1}->(%opts);
129 1.1.1.1.2.2 riz
130 1.1.1.1.2.2 riz if ($nested++) {
131 1.1.1.1.2.2 riz return ".RS";
132 1.1.1.1.2.2 riz }
133 1.1.1.1.2.2 riz else {
134 1.1.1.1.2.2 riz return ();
135 1.1.1.1.2.2 riz }
136 1.1.1.1.2.2 riz }
137 1.1.1.1.2.2 riz else {
138 1.1.1.1.2.2 riz die "Invalid list type <$type>";
139 1.1.1.1.2.2 riz }
140 1.1.1.1.2.2 riz }}, raw => 1);
141 1.1.1.1.2.2 riz
142 1.1.1.1.2.2 riz # don't bother with arguments for now and do what mdoc2man'.sh' did
143 1.1.1.1.2.2 riz
144 1.1.1.1.2.2 riz Mdoc::def_macro('.Bd', sub { ".br\n.in +4\n.nf" } );
145 1.1.1.1.2.2 riz Mdoc::def_macro('.Ed', sub { ".in -4\n.fi" } );
146 1.1.1.1.2.2 riz
147 1.1.1.1.2.2 riz Mdoc::set_Re_callback(sub {
148 1.1.1.1.2.2 riz my ($reference) = @_;
149 1.1.1.1.2.2 riz <<"REF";
150 1.1.1.1.2.2 riz $reference->{authors},
151 1.1.1.1.2.2 riz \\fI$reference->{title}\\fR,
152 1.1.1.1.2.2 riz $reference->{optional}\n.PP
153 1.1.1.1.2.2 riz REF
154 1.1.1.1.2.2 riz });
155 1.1.1.1.2.2 riz
156 1.1.1.1.2.2 riz # Define all macros which have the same sub for inline and standalone macro
157 1.1.1.1.2.2 riz for (qw(Xr Em Ar Fl Ic Cm Qq Op Nm Pa Sq Li Va Brq Pq Fx Ux)) {
158 1.1.1.1.2.2 riz my $m = Mdoc::get_macro(".$_");
159 1.1.1.1.2.2 riz Mdoc::def_macro($_, delete $m->{run}, %$m);
160 1.1.1.1.2.2 riz }
161 1.1.1.1.2.2 riz
162 1.1.1.1.2.2 riz sub print_line {
163 1.1.1.1.2.2 riz print shift;
164 1.1.1.1.2.2 riz print "\n";
165 1.1.1.1.2.2 riz }
166 1.1.1.1.2.2 riz
167 1.1.1.1.2.2 riz sub run {
168 1.1.1.1.2.2 riz print <<'DEFS';
169 1.1.1.1.2.2 riz .de1 NOP
170 1.1.1.1.2.2 riz . it 1 an-trap
171 1.1.1.1.2.2 riz . if \\n[.$] \,\\$*\/
172 1.1.1.1.2.2 riz ..
173 1.1.1.1.2.2 riz .ie t \
174 1.1.1.1.2.2 riz .ds B-Font [CB]
175 1.1.1.1.2.2 riz .ds I-Font [CI]
176 1.1.1.1.2.2 riz .ds R-Font [CR]
177 1.1.1.1.2.2 riz .el \
178 1.1.1.1.2.2 riz .ds B-Font B
179 1.1.1.1.2.2 riz .ds I-Font I
180 1.1.1.1.2.2 riz .ds R-Font R
181 1.1.1.1.2.2 riz DEFS
182 1.1.1.1.2.2 riz
183 1.1.1.1.2.2 riz while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line)) {
184 1.1.1.1.2.2 riz my @ret = Mdoc::call_macro($macro, @args);
185 1.1.1.1.2.2 riz print_line(Mdoc::to_string(@ret)) if @ret;
186 1.1.1.1.2.2 riz }
187 1.1.1.1.2.2 riz return 0;
188 1.1.1.1.2.2 riz }
189 1.1.1.1.2.2 riz
190 1.1.1.1.2.2 riz exit run(@ARGV) unless caller;
191 1.1.1.1.2.2 riz
192 1.1.1.1.2.2 riz 1;
193 1.1.1.1.2.2 riz __END__
194