From 4bf5b5f58894ca3726608bc7eeebd221a5bef0dd Mon Sep 17 00:00:00 2001 From: knu Date: Mon, 20 Jan 2003 08:39:46 +0000 Subject: [PATCH] * mdoc2man.rb: New file. A mdoc to man converter ported from Perl. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3365 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 + mdoc2man.rb | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 393 insertions(+) create mode 100755 mdoc2man.rb diff --git a/ChangeLog b/ChangeLog index 05390a8240..4b1630944a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Jan 20 17:32:56 2003 Akinori MUSHA + + * mdoc2man.rb: New file. A mdoc to man converter ported from + Perl. + Mon Jan 20 15:40:15 2003 Akinori MUSHA * ruby.1: Properly close .Bl with .El. diff --git a/mdoc2man.rb b/mdoc2man.rb new file mode 100755 index 0000000000..b1356819ff --- /dev/null +++ b/mdoc2man.rb @@ -0,0 +1,388 @@ +#!/usr/bin/env ruby +### +### mdoc2man - mdoc to man converter +### +### Quick usage: mdoc2man.rb < mdoc_manpage.8 > man_manpage.8 +### +### Ported from Perl by Akinori MUSHA. +### +### Copyright (c) 2001 University of Illinois Board of Trustees +### Copyright (c) 2001 Mark D. Roth +### Copyright (c) 2002, 2003 Akinori MUSHA +### All rights reserved. +### +### Redistribution and use in source and binary forms, with or without +### modification, are permitted provided that the following conditions +### are met: +### 1. Redistributions of source code must retain the above copyright +### notice, this list of conditions and the following disclaimer. +### 2. Redistributions in binary form must reproduce the above copyright +### notice, this list of conditions and the following disclaimer in the +### documentation and/or other materials provided with the distribution. +### 3. All advertising materials mentioning features or use of this software +### must display the following acknowledgement: +### This product includes software developed by the University of +### Illinois at Urbana, and their contributors. +### 4. The University nor the names of their +### contributors may be used to endorse or promote products derived from +### this software without specific prior written permission. +### +### THIS SOFTWARE IS PROVIDED BY THE TRUSTEES AND CONTRIBUTORS ``AS IS'' AND +### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +### IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +### ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR CONTRIBUTORS BE LIABLE +### FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +### DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +### OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +### HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +### LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +### OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +### SUCH DAMAGE. +### +### $Id$ +### + +$name = $date = $id = nil +$refauthors = $reftitle = $refissue = $refdate = $refopt = nil + +$optlist = 0 ### 1 = bullet, 2 = enum, 3 = tag, 4 = item +$oldoptlist = 0 +$nospace = 0 ### 0, 1, 2 +$enum = 0 +$synopsis = true +$reference = false +$ext = false +$extopt = false +$literal = false + +def parse_macro(line) + words = line.split + retval = '' + + option = false + parens = false + + while word = words.shift + case word + when 'Li', 'Pf' + next + when 'Xo' + $ext = true + retval << ' ' unless retval.empty? || /[\n ]\z/ =~ retval + next + when 'Xc' + $ext = false + retval << "\n" unless $extopt + break + when 'Bd' + $literal = true if words[0] == '-literal' + retval << "\n" + break + when 'Ed' + $literal = false + break + when 'Ns' + $nospace = 1 if $nospace == 0 + retval.chomp!(' ') + next + when 'No' + retval.chomp!(' ') + retval << words.shift + next + when 'Dq' + retval << '``' + begin + retval << words.shift << ' ' + end until words.empty? || /^[\.,]/ =~ words[0] + retval.chomp!(' ') + retval << '\'\'' + $nospace = 1 if $nospace == 0 && /^[\.,]/ =~ words[0] + next + when 'Sq', 'Ql' + retval << '`' << words.shift << '\'' + $nospace = 1 if $nospace == 0 && /^[\.,]/ =~ words[0] + next + # when 'Ic' + # retval << '\\fB' << words.shift << '\\fP' + # next + when 'Oo' + #retval << "[\\c\n" + $extopt = true + $nospace = 1 if $nospace == 0 + retval << '[' + next + when 'Oc' + $extopt = false + retval << ']' + next + end + + retval << ' ' if $nospace == 0 && !(retval.empty? || /[\n ]\z/ =~ retval) + $nospace = 0 if $nospace == 1 + + case word + when 'Dd' + $date = words.join(' ') + return nil + when 'Dt' + $id = words.join(' ') + return nil + when 'Os' + retval << '.TH ' << $id << ' "' << $date << '" "' << + words.join(' ') << '"' + break + when 'Sh' + retval << '.SH' + $synopsis = (words[0] == 'SYNOPSIS') + next + when 'Xr' + retval << '\\fB' << words.shift << + '\\fP(' << words.shift << ')' << words.shift + break + when 'Rs' + $refauthors = [] + $reftitle = '' + $refissue = '' + $refdate = '' + $refopt = '' + $reference = true + break + when 'Re' + retval << "\n" + + # authors + while @refauthors.size > 1 + retval << @refauthors.shift << ', ' + end + retval << 'and ' unless retval.empty? + retval << @refauthors.shift + + # title + retval << ', \\fI' << $reftitle << '\\fP' + + # issue + retval << ', ' << $refissue unless $refissue.empty? + + # date + retval << ', ' << $refdate unless $refdate.empty? + + # optional info + retval << ', ' << $refopt unless $refopt.empty? + + retval << ".\n" + + $reference = false + break + end + + if $reference + case word + when '%A' + @refauthors.unshift(words.join(' ')) + break + when '%T' + $reftitle = words.join(' ') + $reftitle.sub!(/^"/, '') + $reftitle.sub!(/"$/, '') + break + when '%N' + $refissue = words.join(' ') + break + when '%D' + $refdate = words.join(' ') + break + when '%O' + $refopt = words.join(' ') + break + end + end + + case word + when 'Nm' + name = words.empty? ? $name : words.shift + $name ||= name + retval << ".br\n" if $synopsis + retval << "\\fB" << name << "\\fP" + $nospace = 1 if $nospace == 0 && /^[\.,]/ =~ words[0] + next + when 'Nd' + retval << '\\-' + next + when 'Fl' + retval << '\\fB\\-' << words.shift << '\\fP' + $nospace = 1 if $nospace == 0 && /^[\.,]/ =~ words[0] + next + when 'Ar' + retval << '\\fI' + if words.empty? + retval << 'file ...\\fP' + else + retval << words.shift << '\\fP' + while words[0] == '|' + retval << ' ' << words.shift << ' \\fI' << words.shift << '\\fP' + end + $nospace = 1 if $nospace == 0 && /^[\.,]/ =~ words[0] + next + end + when 'Cm' + retval << '\\fB' << words.shift << '\\fP' + while /^[\.,:)]$/ =~ words[0] + retval << words.shift + end + next + when 'Op' + option = true + $nospace = 1 if $nospace == 0 + retval << '[' + # words.push(words.pop + ']') + next + when 'Pp' + retval << "\n" + next + when 'Ss' + retval << '.SS' + next + end + + if word == 'Pa' && !option + retval << '\\fI' + retval << '\\&' if /^\./ =~ words[0] + retval << words.shift << '\\fP' + while /^[\.,:;)]$/ =~ words[0] + retval << words.shift + end + # $nospace = 1 if $nospace == 0 && /^[\.,]/ =~ words[0] + next + end + + case word + when 'Dv' + retval << '.BR' + next + when 'Em', 'Ev' + retval << '.IR' + next + when 'Pq' + retval << '(' + $nospace = 1 + parens = true + next + when 'Sx', 'Sy' + retval << '.B ' << words.join(' ') + break + when 'Ic' + retval << '\\fB' + until words.empty? || /^[\.,]/ =~ words[0] + case words[0] + when 'Op' + words.shift + retval << '[' + words.push(words.pop + ']') + next + when 'Ar' + words.shift + retval << '\\fI' << words.shift << '\\fP' + else + retval << words.shift + end + + retval << ' ' if $nospace == 0 + end + + retval.chomp!(' ') + retval << '\\fP' + retval << words.shift unless words.empty? + break + when 'Bl' + $oldoptlist = $optlist + + case words[0] + when '-bullet' + $optlist = 1 + when '-enum' + $optlist = 2 + $enum = 0 + when '-tag' + $optlist = 3 + when '-item' + $optlist = 4 + end + + break + when 'El' + $optlist = $oldoptlist + next + end + + if $optlist != 0 && word == 'It' + case $optlist + when 1 + # bullets + retval << '.IP \\(bu' + when 2 + # enum + $enum += 1 + retval << '.IP ' << $enum << '.' + when 3 + # tags + retval << ".TP\n" + case words[0] + when 'Pa', 'Ev' + words.shift + retval << '.B' + end + when 4 + # item + retval << ".IP\n" + end + + next + end + + case word + when 'Sm' + case words[0] + when 'off' + $nospace = 2 + when 'on' + # retval << "\n" + $nospace = 0 + end + words.shift + next + end + + retval << word + end + + return nil if retval == '.' + + retval.sub!(/\A\.([^a-zA-Z])/, "\\1") + # retval.chomp!(' ') + + retval << ')' if parens + + retval << ']' if option + + # retval << ' ' unless $nospace == 0 || retval.empty? || /\n\z/ =~ retval + + retval << ' ' unless !$ext || $extopt || / $/ =~ retval + + retval << "\n" unless $ext || $extopt || retval.empty? || /\n\z/ =~ retval + + return retval +end + +ARGF.each { |line| + if /^\./ !~ line + print line + print ".br\n" if $literal + next + end + + line.slice!(0, 1) + + next if /\\"/ =~ line + + line = parse_macro(line) and print line +}