mdoc2man revision 285612
1144518Sdavidxu#! /usr/local/bin/perl
2144518Sdavidxu
3144518Sdavidxu## mdoc2man.pl -- Convert mdoc tags to man tags
4144518Sdavidxu##
5144518Sdavidxu## Author:	Harlan Stenn <stenn@ntp.org>
6144518Sdavidxu##		
7144518Sdavidxu##
8144518Sdavidxu##  This file is part of AutoOpts, a companion to AutoGen.
9144518Sdavidxu##  AutoOpts is free software.
10144518Sdavidxu##  AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
11144518Sdavidxu##
12144518Sdavidxu##  AutoOpts is available under any one of two licenses.  The license
13144518Sdavidxu##  in use must be one of these two and the choice is under the control
14144518Sdavidxu##  of the user of the license.
15144518Sdavidxu##
16144518Sdavidxu##   The GNU Lesser General Public License, version 3 or later
17144518Sdavidxu##      See the files "COPYING.lgplv3" and "COPYING.gplv3"
18144518Sdavidxu##
19144518Sdavidxu##   The Modified Berkeley Software Distribution License
20144518Sdavidxu##      See the file "COPYING.mbsd"
21144518Sdavidxu##
22144518Sdavidxu##  These files have the following sha256 sums:
23144518Sdavidxu##
24144518Sdavidxu##  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
25144518Sdavidxu##  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
26144518Sdavidxu##  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
27144518Sdavidxu
28144518Sdavidxu### ToDo
29144518Sdavidxu# Properly implement -columns in the "my %lists" definition...
30144518Sdavidxu#
31144518Sdavidxu# .Xr requires at least 1 arg, the code here expects at least 2
32144518Sdavidxu#
33144518Sdavidxu###
34144518Sdavidxu
35144518Sdavidxupackage mdoc2man;
36144518Sdavidxuuse strict;
37144518Sdavidxuuse warnings;
38144518Sdavidxuuse File::Basename;
39144518Sdavidxuuse lib dirname(__FILE__);
40144518Sdavidxuuse Mdoc qw(hs ns pp mapwords son soff stoggle gen_encloser);
41144518Sdavidxu
42165967Simp########
43144518Sdavidxu## Basic
44144518Sdavidxu########
45144518Sdavidxu
46144518SdavidxuMdoc::def_macro( '.Sh', sub { '.SH', hs, @_ }, raw => 1);
47144518SdavidxuMdoc::def_macro( '.Ss', sub { '.SS', hs, @_ }, raw => 1);
48144518SdavidxuMdoc::def_macro( '.Pp', sub { ".sp \\n(Ppu\n.ne 2\n" } );
49144518SdavidxuMdoc::def_macro( '.Nd', sub { "\\- @_" } );
50144518Sdavidxu
51144518Sdavidxu# Macros that enclose things
52144518SdavidxuMdoc::def_macro( '.Brq', gen_encloser(qw({ }))          , greedy => 1 );
53144518SdavidxuMdoc::def_macro( '.Op' , gen_encloser(qw([ ]))          , greedy => 1 );
54144518SdavidxuMdoc::def_macro( '.Qq' , gen_encloser(qw(" "))          , greedy => 1 );
55144518SdavidxuMdoc::def_macro( '.Dq' , gen_encloser(qw(\*[Lq] \*[Rq])), greedy => 1 );
56144518SdavidxuMdoc::def_macro( '.Ql' , gen_encloser(qw(\[oq] \[cq]))  , greedy => 1 );
57144518SdavidxuMdoc::def_macro( '.Sq' , gen_encloser(qw(\[oq] \[cq]))  , greedy => 1 );
58144518SdavidxuMdoc::def_macro( '.Pq' , gen_encloser(qw/( )/)          , greedy => 1 );
59144518SdavidxuMdoc::def_macro( '.D1' , sub { ".in +4\n", ns, @_ , ns , "\n.in -4" } , greedy => 1);
60267200Skib
61157457SdavidxuMdoc::def_macro( 'Oo',  sub { '[', @_ } );
62144518SdavidxuMdoc::def_macro( 'Oc',  sub { ']', @_ } );
63211706Skib
64144518SdavidxuMdoc::def_macro( 'Po',  sub { '(', @_} );
65144518SdavidxuMdoc::def_macro( 'Pc',  sub { ')', @_ } );
66144518Sdavidxu
67144518SdavidxuMdoc::def_macro( 'Bro', sub { '{', ns, @_ } );
68144518SdavidxuMdoc::def_macro( 'Brc', sub { '}', @_ } );
69157457Sdavidxu
70144518SdavidxuMdoc::def_macro( '.Oo',  gen_encloser(qw([ ])), concat_until => '.Oc' );
71144518SdavidxuMdoc::def_macro( '.Bro', gen_encloser(qw({ })), concat_until => '.Brc' );
72185369SkibMdoc::def_macro( '.Po',  gen_encloser(qw/( )/), concat_until => '.Pc' );
73144518Sdavidxu
74144518SdavidxuMdoc::def_macro( '.Ev', sub { @_ } );
75144518SdavidxuMdoc::def_macro( '.An', sub { ".NOP ", @_, "\n.br" }, raw => 1 );
76144518SdavidxuMdoc::def_macro( '.Li', sub { mapwords {"\\f[C]$_\\f[]"} @_ } );
77144518SdavidxuMdoc::def_macro( '.Cm', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } );
78144518SdavidxuMdoc::def_macro( '.Ic', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } );
79144518SdavidxuMdoc::def_macro( '.Fl', sub { mapwords {"\\f\\*[B-Font]\\-$_\\f[]"} @_ } );
80144518SdavidxuMdoc::def_macro( '.Ar', sub { mapwords {"\\f\\*[I-Font]$_\\f[]"} @_ } );
81144518SdavidxuMdoc::def_macro( '.Em', sub { mapwords {"\\fI$_\\f[]"} @_ } );
82144518SdavidxuMdoc::def_macro( '.Va', sub { mapwords {"\\fI$_\\f[]"} @_ } );
83144518SdavidxuMdoc::def_macro( '.Sx', sub { mapwords {"\\fI$_\\f[]"} @_ } );
84144518SdavidxuMdoc::def_macro( '.Xr', sub { "\\fC".(shift)."\\f[]\\fR(".(shift).")\\f[]", @_ } );
85144518SdavidxuMdoc::def_macro( '.Fn', sub { "\\f\\*[B-Font]".(shift)."\\f[]\\fR()\\f[]" } );
86144518SdavidxuMdoc::def_macro( '.Fn', sub { "\\fB".(shift)."\\f[]\\fR()\\f[]" } );
87144518SdavidxuMdoc::def_macro( '.Fx', sub { "FreeBSD", @_ } );
88144518SdavidxuMdoc::def_macro( '.Ux', sub { "UNIX", @_ } );
89144518Sdavidxu
90144518SdavidxuMdoc::def_macro( '.No', sub { ".NOP", map { ($_, ns) } @_ } );
91144518SdavidxuMdoc::def_macro( '.Pa', sub { mapwords {"\\fI$_\\f[]"} @_; } );
92144518Sdavidxu{
93212078Sdavidxu    my $name;
94212078Sdavidxu    Mdoc::def_macro('.Nm', sub {
95144518Sdavidxu        $name = shift if (!$name);
96212077Sdavidxu        "\\f\\*[B-Font]$name\\fP", @_
97212078Sdavidxu    } );
98144518Sdavidxu}
99144518Sdavidxu
100144518Sdavidxu########
101211706Skib## lists
102211706Skib########
103211706Skib
104212083Sdavidxumy %lists = (
105211706Skib    bullet => sub {
106211706Skib        Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' });
107211706Skib    },
108211706Skib
109211706Skib    column => sub {
110211706Skib        Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' });
111212083Sdavidxu    },
112212077Sdavidxu
113211706Skib    tag    => sub {
114211706Skib        my (%opts) = @_;
115211706Skib
116211706Skib        my $width = '';
117211706Skib
118212083Sdavidxu        if (exists $opts{width}) {
119211706Skib            $width = ' '.((length $opts{width})+1);
120211706Skib        }
121212077Sdavidxu
122212083Sdavidxu        if (exists $opts{compact}) {
123212083Sdavidxu            my $dobrns = 0;
124212083Sdavidxu            Mdoc::def_macro('.It', sub {
125212083Sdavidxu                    my @ret = (".TP$width\n.NOP", hs);
126212083Sdavidxu                    if ($dobrns) {
127211860Sdavidxu                        ".br\n.ns\n", ns, @ret, @_;
128212076Sdavidxu                    }
129211706Skib                    else {
130211706Skib                        $dobrns = 1;
131277317Skib                        @ret, @_;
132144518Sdavidxu                    }
133144518Sdavidxu                }, raw => 1);
134277317Skib        }
135144518Sdavidxu        else {
136144518Sdavidxu            Mdoc::def_macro('.It', sub {
137144518Sdavidxu                    ".TP$width\n.NOP", hs, @_
138144518Sdavidxu                }, raw => 1);
139212841Sdavidxu        }
140191993Sgreen    },
141185558Skib);
142144518Sdavidxu
143144518SdavidxuMdoc::set_Bl_callback(do { my $nested = 0; sub {
144144518Sdavidxu    my $type = shift;
145144518Sdavidxu    my %opts = Mdoc::parse_opts(@_);
146144518Sdavidxu    if (defined $type && $type =~ /-(\w+)/ && exists $lists{$1}) {
147212841Sdavidxu
148212841Sdavidxu        # Wrap nested lists with .RS and .RE
149212077Sdavidxu        Mdoc::set_El_callback(sub { 
150144518Sdavidxu                return '.RE' if $nested-- > 1;
151144518Sdavidxu                return '.PP';
152144518Sdavidxu            });
153144518Sdavidxu
154144518Sdavidxu        $lists{$1}->(%opts);
155144518Sdavidxu
156144518Sdavidxu        if ($nested++) {
157144518Sdavidxu            return ".RS";
158212077Sdavidxu        }
159212077Sdavidxu        else {
160212077Sdavidxu            return ();
161212077Sdavidxu        }
162212077Sdavidxu    }
163212077Sdavidxu    else {
164191993Sgreen        die "Invalid list type <$type>";
165191993Sgreen    }
166191993Sgreen}}, raw => 1);
167144518Sdavidxu
168154248Sjasone# don't bother with arguments for now and do what mdoc2man'.sh' did
169191993Sgreen
170154248SjasoneMdoc::def_macro('.Bd', sub { ".br\n.in +4\n.nf" } );
171185369SkibMdoc::def_macro('.Ed', sub { ".in -4\n.fi" } );
172144518Sdavidxu
173191993SgreenMdoc::set_Re_callback(sub { 
174144518Sdavidxu        my ($reference) = @_;
175144518Sdavidxu        <<"REF";
176267200Skib$reference->{authors},
177267200Skib\\fI$reference->{title}\\fR,
178267200Skib$reference->{optional}\n.PP
179267200SkibREF
180267200Skib});
181267200Skib
182267200Skib# Define all macros which have the same sub for inline and standalone macro
183267200Skibfor (qw(Xr Em Ar Fl Ic Cm Qq Op Nm Pa Sq Li Va Brq Pq Fx Ux)) {
184267200Skib    my $m = Mdoc::get_macro(".$_");
185144518Sdavidxu    Mdoc::def_macro($_, delete $m->{run}, %$m);
186144518Sdavidxu}
187164583Sdavidxu
188212536Sdavidxusub print_line {
189163346Sdavidxu    print shift;
190144518Sdavidxu    print "\n";
191144518Sdavidxu}
192144518Sdavidxu
193144518Sdavidxusub run {
194212536Sdavidxu    print <<'DEFS';
195144518Sdavidxu.de1 NOP
196144518Sdavidxu.  it 1 an-trap
197144518Sdavidxu.  if \\n[.$] \,\\$*\/
198144518Sdavidxu..
199144518Sdavidxu.ie t \
200162061Sdavidxu.ds B-Font [CB]
201212077Sdavidxu.ds I-Font [CI]
202185531Skan.ds R-Font [CR]
203212076Sdavidxu.el \
204212076Sdavidxu.ds B-Font B
205191993Sgreen.ds I-Font I
206185531Skan.ds R-Font R
207144518SdavidxuDEFS
208144518Sdavidxu
209144518Sdavidxu    while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line)) {
210144518Sdavidxu        my @ret = Mdoc::call_macro($macro, @args);
211144518Sdavidxu        print_line(Mdoc::to_string(@ret)) if @ret;
212212077Sdavidxu    }
213212077Sdavidxu    return 0;
214144518Sdavidxu}
215191993Sgreen
216190025Skibexit run(@ARGV) unless caller;
217185456Skib
218190025Skib1;
219190025Skib__END__
220185369Skib