1*276da39aSCy Schubert#! /usr/local/bin/perl 2*276da39aSCy Schubert 3*276da39aSCy Schubert## mdoc2man.pl -- Convert mdoc tags to man tags 4*276da39aSCy Schubert## 5*276da39aSCy Schubert## Author: Harlan Stenn <stenn@ntp.org> 6*276da39aSCy Schubert## 7*276da39aSCy Schubert## 8*276da39aSCy Schubert## This file is part of AutoOpts, a companion to AutoGen. 9*276da39aSCy Schubert## AutoOpts is free software. 10*276da39aSCy Schubert## AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 11*276da39aSCy Schubert## 12*276da39aSCy Schubert## AutoOpts is available under any one of two licenses. The license 13*276da39aSCy Schubert## in use must be one of these two and the choice is under the control 14*276da39aSCy Schubert## of the user of the license. 15*276da39aSCy Schubert## 16*276da39aSCy Schubert## The GNU Lesser General Public License, version 3 or later 17*276da39aSCy Schubert## See the files "COPYING.lgplv3" and "COPYING.gplv3" 18*276da39aSCy Schubert## 19*276da39aSCy Schubert## The Modified Berkeley Software Distribution License 20*276da39aSCy Schubert## See the file "COPYING.mbsd" 21*276da39aSCy Schubert## 22*276da39aSCy Schubert## These files have the following sha256 sums: 23*276da39aSCy Schubert## 24*276da39aSCy Schubert## 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 25*276da39aSCy Schubert## 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 26*276da39aSCy Schubert## 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 27*276da39aSCy Schubert 28*276da39aSCy Schubert### ToDo 29*276da39aSCy Schubert# Properly implement -columns in the "my %lists" definition... 30*276da39aSCy Schubert# 31*276da39aSCy Schubert# .Xr requires at least 1 arg, the code here expects at least 2 32*276da39aSCy Schubert# 33*276da39aSCy Schubert### 34*276da39aSCy Schubert 35*276da39aSCy Schubertpackage mdoc2man; 36*276da39aSCy Schubertuse strict; 37*276da39aSCy Schubertuse warnings; 38*276da39aSCy Schubertuse File::Basename; 39*276da39aSCy Schubertuse lib dirname(__FILE__); 40*276da39aSCy Schubertuse Mdoc qw(hs ns pp mapwords son soff stoggle gen_encloser); 41*276da39aSCy Schubert 42*276da39aSCy Schubert######## 43*276da39aSCy Schubert## Basic 44*276da39aSCy Schubert######## 45*276da39aSCy Schubert 46*276da39aSCy SchubertMdoc::def_macro( '.Sh', sub { '.SH', hs, @_ }, raw => 1); 47*276da39aSCy SchubertMdoc::def_macro( '.Ss', sub { '.SS', hs, @_ }, raw => 1); 48*276da39aSCy SchubertMdoc::def_macro( '.Pp', sub { ".sp \\n(Ppu\n.ne 2\n" } ); 49*276da39aSCy SchubertMdoc::def_macro( '.Nd', sub { "\\- @_" } ); 50*276da39aSCy Schubert 51*276da39aSCy Schubert# Macros that enclose things 52*276da39aSCy SchubertMdoc::def_macro( '.Brq', gen_encloser(qw({ })) , greedy => 1 ); 53*276da39aSCy SchubertMdoc::def_macro( '.Op' , gen_encloser(qw([ ])) , greedy => 1 ); 54*276da39aSCy SchubertMdoc::def_macro( '.Qq' , gen_encloser(qw(" ")) , greedy => 1 ); 55*276da39aSCy SchubertMdoc::def_macro( '.Dq' , gen_encloser(qw(\*[Lq] \*[Rq])), greedy => 1 ); 56*276da39aSCy SchubertMdoc::def_macro( '.Ql' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 57*276da39aSCy SchubertMdoc::def_macro( '.Sq' , gen_encloser(qw(\[oq] \[cq])) , greedy => 1 ); 58*276da39aSCy SchubertMdoc::def_macro( '.Pq' , gen_encloser(qw/( )/) , greedy => 1 ); 59*276da39aSCy SchubertMdoc::def_macro( '.D1' , sub { ".in +4\n", ns, @_ , ns , "\n.in -4" } , greedy => 1); 60*276da39aSCy Schubert 61*276da39aSCy SchubertMdoc::def_macro( 'Oo', sub { '[', @_ } ); 62*276da39aSCy SchubertMdoc::def_macro( 'Oc', sub { ']', @_ } ); 63*276da39aSCy Schubert 64*276da39aSCy SchubertMdoc::def_macro( 'Po', sub { '(', @_} ); 65*276da39aSCy SchubertMdoc::def_macro( 'Pc', sub { ')', @_ } ); 66*276da39aSCy Schubert 67*276da39aSCy SchubertMdoc::def_macro( 'Bro', sub { '{', ns, @_ } ); 68*276da39aSCy SchubertMdoc::def_macro( 'Brc', sub { '}', @_ } ); 69*276da39aSCy Schubert 70*276da39aSCy SchubertMdoc::def_macro( '.Oo', gen_encloser(qw([ ])), concat_until => '.Oc' ); 71*276da39aSCy SchubertMdoc::def_macro( '.Bro', gen_encloser(qw({ })), concat_until => '.Brc' ); 72*276da39aSCy SchubertMdoc::def_macro( '.Po', gen_encloser(qw/( )/), concat_until => '.Pc' ); 73*276da39aSCy Schubert 74*276da39aSCy SchubertMdoc::def_macro( '.Ev', sub { @_ } ); 75*276da39aSCy SchubertMdoc::def_macro( '.An', sub { ".NOP ", @_, "\n.br" }, raw => 1 ); 76*276da39aSCy SchubertMdoc::def_macro( '.Li', sub { mapwords {"\\f[C]$_\\f[]"} @_ } ); 77*276da39aSCy SchubertMdoc::def_macro( '.Cm', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 78*276da39aSCy SchubertMdoc::def_macro( '.Ic', sub { mapwords {"\\f\\*[B-Font]$_\\f[]"} @_ } ); 79*276da39aSCy SchubertMdoc::def_macro( '.Fl', sub { mapwords {"\\f\\*[B-Font]\\-$_\\f[]"} @_ } ); 80*276da39aSCy SchubertMdoc::def_macro( '.Ar', sub { mapwords {"\\f\\*[I-Font]$_\\f[]"} @_ } ); 81*276da39aSCy SchubertMdoc::def_macro( '.Em', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 82*276da39aSCy SchubertMdoc::def_macro( '.Va', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 83*276da39aSCy SchubertMdoc::def_macro( '.Sx', sub { mapwords {"\\fI$_\\f[]"} @_ } ); 84*276da39aSCy SchubertMdoc::def_macro( '.Xr', sub { "\\fC".(shift)."\\f[]\\fR(".(shift).")\\f[]", @_ } ); 85*276da39aSCy SchubertMdoc::def_macro( '.Fn', sub { "\\f\\*[B-Font]".(shift)."\\f[]\\fR()\\f[]" } ); 86*276da39aSCy SchubertMdoc::def_macro( '.Fn', sub { "\\fB".(shift)."\\f[]\\fR()\\f[]" } ); 87*276da39aSCy SchubertMdoc::def_macro( '.Fx', sub { "FreeBSD", @_ } ); 88*276da39aSCy SchubertMdoc::def_macro( '.Ux', sub { "UNIX", @_ } ); 89*276da39aSCy Schubert 90*276da39aSCy SchubertMdoc::def_macro( '.No', sub { ".NOP", map { ($_, ns) } @_ } ); 91*276da39aSCy SchubertMdoc::def_macro( '.Pa', sub { mapwords {"\\fI$_\\f[]"} @_; } ); 92*276da39aSCy Schubert{ 93*276da39aSCy Schubert my $name; 94*276da39aSCy Schubert Mdoc::def_macro('.Nm', sub { 95*276da39aSCy Schubert $name = shift if (!$name); 96*276da39aSCy Schubert "\\f\\*[B-Font]$name\\fP", @_ 97*276da39aSCy Schubert } ); 98*276da39aSCy Schubert} 99*276da39aSCy Schubert 100*276da39aSCy Schubert######## 101*276da39aSCy Schubert## lists 102*276da39aSCy Schubert######## 103*276da39aSCy Schubert 104*276da39aSCy Schubertmy %lists = ( 105*276da39aSCy Schubert bullet => sub { 106*276da39aSCy Schubert Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 107*276da39aSCy Schubert }, 108*276da39aSCy Schubert 109*276da39aSCy Schubert column => sub { 110*276da39aSCy Schubert Mdoc::def_macro('.It', sub { '.IP \fB\(bu\fP 2' }); 111*276da39aSCy Schubert }, 112*276da39aSCy Schubert 113*276da39aSCy Schubert tag => sub { 114*276da39aSCy Schubert my (%opts) = @_; 115*276da39aSCy Schubert 116*276da39aSCy Schubert my $width = ''; 117*276da39aSCy Schubert 118*276da39aSCy Schubert if (exists $opts{width}) { 119*276da39aSCy Schubert $width = ' '.((length $opts{width})+1); 120*276da39aSCy Schubert } 121*276da39aSCy Schubert 122*276da39aSCy Schubert if (exists $opts{compact}) { 123*276da39aSCy Schubert my $dobrns = 0; 124*276da39aSCy Schubert Mdoc::def_macro('.It', sub { 125*276da39aSCy Schubert my @ret = (".TP$width\n.NOP", hs); 126*276da39aSCy Schubert if ($dobrns) { 127*276da39aSCy Schubert ".br\n.ns\n", ns, @ret, @_; 128*276da39aSCy Schubert } 129*276da39aSCy Schubert else { 130*276da39aSCy Schubert $dobrns = 1; 131*276da39aSCy Schubert @ret, @_; 132*276da39aSCy Schubert } 133*276da39aSCy Schubert }, raw => 1); 134*276da39aSCy Schubert } 135*276da39aSCy Schubert else { 136*276da39aSCy Schubert Mdoc::def_macro('.It', sub { 137*276da39aSCy Schubert ".TP$width\n.NOP", hs, @_ 138*276da39aSCy Schubert }, raw => 1); 139*276da39aSCy Schubert } 140*276da39aSCy Schubert }, 141*276da39aSCy Schubert); 142*276da39aSCy Schubert 143*276da39aSCy SchubertMdoc::set_Bl_callback(do { my $nested = 0; sub { 144*276da39aSCy Schubert my $type = shift; 145*276da39aSCy Schubert my %opts = Mdoc::parse_opts(@_); 146*276da39aSCy Schubert if (defined $type && $type =~ /-(\w+)/ && exists $lists{$1}) { 147*276da39aSCy Schubert 148*276da39aSCy Schubert # Wrap nested lists with .RS and .RE 149*276da39aSCy Schubert Mdoc::set_El_callback(sub { 150*276da39aSCy Schubert return '.RE' if $nested-- > 1; 151*276da39aSCy Schubert return '.PP'; 152*276da39aSCy Schubert }); 153*276da39aSCy Schubert 154*276da39aSCy Schubert $lists{$1}->(%opts); 155*276da39aSCy Schubert 156*276da39aSCy Schubert if ($nested++) { 157*276da39aSCy Schubert return ".RS"; 158*276da39aSCy Schubert } 159*276da39aSCy Schubert else { 160*276da39aSCy Schubert return (); 161*276da39aSCy Schubert } 162*276da39aSCy Schubert } 163*276da39aSCy Schubert else { 164*276da39aSCy Schubert die "Invalid list type <$type>"; 165*276da39aSCy Schubert } 166*276da39aSCy Schubert}}, raw => 1); 167*276da39aSCy Schubert 168*276da39aSCy Schubert# don't bother with arguments for now and do what mdoc2man'.sh' did 169*276da39aSCy Schubert 170*276da39aSCy SchubertMdoc::def_macro('.Bd', sub { ".br\n.in +4\n.nf" } ); 171*276da39aSCy SchubertMdoc::def_macro('.Ed', sub { ".in -4\n.fi" } ); 172*276da39aSCy Schubert 173*276da39aSCy SchubertMdoc::set_Re_callback(sub { 174*276da39aSCy Schubert my ($reference) = @_; 175*276da39aSCy Schubert <<"REF"; 176*276da39aSCy Schubert$reference->{authors}, 177*276da39aSCy Schubert\\fI$reference->{title}\\fR, 178*276da39aSCy Schubert$reference->{optional}\n.PP 179*276da39aSCy SchubertREF 180*276da39aSCy Schubert}); 181*276da39aSCy Schubert 182*276da39aSCy Schubert# Define all macros which have the same sub for inline and standalone macro 183*276da39aSCy Schubertfor (qw(Xr Em Ar Fl Ic Cm Qq Op Nm Pa Sq Li Va Brq Pq Fx Ux)) { 184*276da39aSCy Schubert my $m = Mdoc::get_macro(".$_"); 185*276da39aSCy Schubert Mdoc::def_macro($_, delete $m->{run}, %$m); 186*276da39aSCy Schubert} 187*276da39aSCy Schubert 188*276da39aSCy Schubertsub print_line { 189*276da39aSCy Schubert print shift; 190*276da39aSCy Schubert print "\n"; 191*276da39aSCy Schubert} 192*276da39aSCy Schubert 193*276da39aSCy Schubertsub run { 194*276da39aSCy Schubert print <<'DEFS'; 195*276da39aSCy Schubert.de1 NOP 196*276da39aSCy Schubert. it 1 an-trap 197*276da39aSCy Schubert. if \\n[.$] \,\\$*\/ 198*276da39aSCy Schubert.. 199*276da39aSCy Schubert.ie t \ 200*276da39aSCy Schubert.ds B-Font [CB] 201*276da39aSCy Schubert.ds I-Font [CI] 202*276da39aSCy Schubert.ds R-Font [CR] 203*276da39aSCy Schubert.el \ 204*276da39aSCy Schubert.ds B-Font B 205*276da39aSCy Schubert.ds I-Font I 206*276da39aSCy Schubert.ds R-Font R 207*276da39aSCy SchubertDEFS 208*276da39aSCy Schubert 209*276da39aSCy Schubert while (my ($macro, @args) = Mdoc::parse_line(\*STDIN, \&print_line)) { 210*276da39aSCy Schubert my @ret = Mdoc::call_macro($macro, @args); 211*276da39aSCy Schubert print_line(Mdoc::to_string(@ret)) if @ret; 212*276da39aSCy Schubert } 213*276da39aSCy Schubert return 0; 214*276da39aSCy Schubert} 215*276da39aSCy Schubert 216*276da39aSCy Schubertexit run(@ARGV) unless caller; 217*276da39aSCy Schubert 218*276da39aSCy Schubert1; 219*276da39aSCy Schubert__END__ 220