3 ### mdoc2man - mdoc to man converter
5 ### Quick usage: mdoc2man.rb < mdoc_manpage.8 > man_manpage.8
7 ### Ported from Perl by Akinori MUSHA.
9 ### Copyright (c) 2001 University of Illinois Board of Trustees
10 ### Copyright (c) 2001 Mark D. Roth
11 ### Copyright (c) 2002, 2003 Akinori MUSHA
12 ### All rights reserved.
14 ### Redistribution and use in source and binary forms, with or without
15 ### modification, are permitted provided that the following conditions
17 ### 1. Redistributions of source code must retain the above copyright
18 ### notice, this list of conditions and the following disclaimer.
19 ### 2. Redistributions in binary form must reproduce the above copyright
20 ### notice, this list of conditions and the following disclaimer in the
21 ### documentation and/or other materials provided with the distribution.
22 ### 3. All advertising materials mentioning features or use of this software
23 ### must display the following acknowledgement:
24 ### This product includes software developed by the University of
25 ### Illinois at Urbana, and their contributors.
26 ### 4. The University nor the names of their
27 ### contributors may be used to endorse or promote products derived from
28 ### this software without specific prior written permission.
30 ### THIS SOFTWARE IS PROVIDED BY THE TRUSTEES AND CONTRIBUTORS ``AS IS'' AND
31 ### ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 ### IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 ### ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR CONTRIBUTORS BE LIABLE
34 ### FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 ### DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 ### OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 ### HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 ### LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 ### OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 RE_PUNCT = /^[!"'),\.\/:;>\?\]`]$/
53 @name = @date = @id = nil
54 @refauthors = @reftitle = @refissue = @refdate = @refopt = nil
56 @optlist = 0 ### 1 = bullet, 2 = enum, 3 = tag, 4 = item
58 @nospace = 0 ### 0, 1, 2
71 o.print ".br\n" if @literal
79 line = parse_macro(line) and o.print line
92 while word = words.shift
112 retval << ' ' unless retval.empty? || /[\n ]\z/ =~ retval
116 retval << "\n" unless @extopt
119 @literal = true if words[0] == '-literal'
126 @nospace = 1 if @nospace == 0
131 retval << words.shift
136 retval << words.shift << ' '
137 end until words.empty? || RE_PUNCT =~ words[0]
140 @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0]
143 retval << '`' << words.shift << '\''
144 @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0]
147 # retval << '\\fB' << words.shift << '\\fP'
152 @nospace = 1 if @nospace == 0
160 @nospace = 1 if @nospace == 0
168 retval << ' ' if @nospace == 0 && !(retval.empty? || /[\n ]\z/ =~ retval)
169 @nospace = 0 if @nospace == 1
173 @date = words.join(' ')
176 if words.size >= 2 && words[1] == '""' &&
177 /^(.*)\(([0-9])\)$/ =~ words[0]
181 @id = words.join(' ')
184 retval << '.TH ' << @id << ' "' << @date << '" "' <<
185 words.join(' ') << '"'
189 @synopsis = (words[0] == 'SYNOPSIS')
192 retval << '\\fB' << words.shift <<
193 '\\fP(' << words.shift << ')' << words.shift
207 while @refauthors.size > 1
208 retval << @refauthors.shift << ', '
210 retval << 'and ' unless retval.empty?
211 retval << @refauthors.shift
214 retval << ', \\fI' << @reftitle << '\\fP'
217 retval << ', ' << @refissue unless @refissue.empty?
220 retval << ', ' << @refdate unless @refdate.empty?
223 retval << ', ' << @refopt unless @refopt.empty?
232 retval << ".nf\n" << '\\& '
243 @refauthors.unshift(words.join(' '))
246 @reftitle = words.join(' ')
247 @reftitle.sub!(/^"/, '')
248 @reftitle.sub!(/"$/, '')
251 @refissue = words.join(' ')
254 @refdate = words.join(' ')
257 @refopt = words.join(' ')
264 name = words.empty? ? @name : words.shift
266 retval << ".br\n" if @synopsis
267 retval << "\\fB" << name << "\\fP"
268 @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0]
274 retval << '\\fB\\-' << words.shift << '\\fP'
275 @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0]
280 retval << 'file ...\\fP'
282 retval << words.shift << '\\fP'
283 while words[0] == '|'
284 retval << ' ' << words.shift << ' \\fI' << words.shift << '\\fP'
286 @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0]
290 retval << '\\fB' << words.shift << '\\fP'
291 while RE_PUNCT =~ words[0]
292 retval << words.shift
297 @nospace = 1 if @nospace == 0
299 # words.push(words.pop + ']')
303 @nospace = 1 if @nospace == 0
305 # words.push(words.pop + '>')
315 if word == 'Pa' && !quote.include?(OPTION)
317 retval << '\\&' if /^\./ =~ words[0]
318 retval << words.shift << '\\fP'
319 while RE_PUNCT =~ words[0]
320 retval << words.shift
322 # @nospace = 1 if @nospace == 0 && RE_PUNCT =~ words[0]
339 retval << '.B ' << words.join(' ')
343 until words.empty? || RE_PUNCT =~ words[0]
348 words.push(words.pop + ']')
353 words.push(words.pop + '>')
357 retval << '\\fI' << words.shift << '\\fP'
359 retval << words.shift
362 retval << ' ' if @nospace == 0
367 retval << words.shift unless words.empty?
370 @oldoptlist = @optlist
386 @optlist = @oldoptlist
390 if @optlist != 0 && word == 'It'
394 retval << '.IP \\(bu'
398 retval << '.IP ' << @enum << '.'
431 return nil if retval == '.'
433 retval.sub!(/\A\.([^a-zA-Z])/, "\\1")
447 # retval << ' ' unless @nospace == 0 || retval.empty? || /\n\z/ =~ retval
449 retval << ' ' unless !@ext || @extopt || / $/ =~ retval
451 retval << "\n" unless @ext || @extopt || retval.empty? || /\n\z/ =~ retval
453 retval << ".fi\n" if dl
458 def self.mdoc2man(i, o)
464 Mdoc2Man.mdoc2man(ARGF, STDOUT)