mdoc2man.awk revision 149749
1235267Sgabor#!/usr/bin/awk
2235267Sgabor#
3251245Sgabor# Version history:
4235267Sgabor#  v3, I put the program under a proper license
5235267Sgabor#      Dan Nelson <dnelson@allantgroup.com> added .An, .Aq and fixed a typo
6235267Sgabor#  v2, fixed to work on GNU awk --posix and MacOS X
7235267Sgabor#  v1, first attempt, didn't work on MacOS X
8235267Sgabor#
9235267Sgabor# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org>
10235267Sgabor#
11235267Sgabor# Permission to use, copy, modify, and distribute this software for any
12235267Sgabor# purpose with or without fee is hereby granted, provided that the above
13235267Sgabor# copyright notice and this permission notice appear in all copies.
14235267Sgabor#
15235267Sgabor# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16235267Sgabor# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17235267Sgabor# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18235267Sgabor# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19235267Sgabor# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20235267Sgabor# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21235267Sgabor# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22235267Sgabor
23235267Sgabor
24235267SgaborBEGIN {
25235267Sgabor  optlist=0
26235267Sgabor  oldoptlist=0
27235267Sgabor  nospace=0
28235267Sgabor  synopsis=0
29235267Sgabor  reference=0
30235267Sgabor  block=0
31235267Sgabor  ext=0
32235267Sgabor  extopt=0
33235267Sgabor  literal=0
34235267Sgabor  prenl=0
35235267Sgabor  breakw=0
36235267Sgabor  line=""
37235267Sgabor}
38235267Sgabor
39235267Sgaborfunction wtail() {
40235267Sgabor  retval=""
41235267Sgabor  while(w<nwords) {
42235267Sgabor    if(length(retval))
43235267Sgabor      retval=retval OFS
44235435Sgabor    retval=retval words[++w]
45235267Sgabor  }
46235435Sgabor  return retval
47235435Sgabor}
48235267Sgabor
49235267Sgaborfunction add(str) {
50235267Sgabor  for(;prenl;prenl--)
51235267Sgabor    line=line "\n"
52235267Sgabor  line=line str
53235267Sgabor}
54235267Sgabor
55235267Sgabor! /^\./ {
56235267Sgabor  for(;prenl;prenl--)
57235267Sgabor    print ""
58235267Sgabor  print
59235267Sgabor  if(literal)
60235267Sgabor    print ".br"
61235267Sgabor  next
62235267Sgabor}
63235267Sgabor
64235267Sgabor/^\.\\"/ { next }
65235267Sgabor
66235267Sgabor{
67235267Sgabor  option=0
68235267Sgabor  parens=0
69235267Sgabor  angles=0
70235267Sgabor  sub("^\\.","")
71235267Sgabor  nwords=split($0,words)
72242430Sgabor  for(w=1;w<=nwords;w++) {
73235267Sgabor    skip=0
74235267Sgabor    if(match(words[w],"^Li|Pf$")) {
75235267Sgabor      skip=1
76235267Sgabor    } else if(match(words[w],"^Xo$")) {
77235267Sgabor      skip=1
78235267Sgabor      ext=1
79235267Sgabor      if(length(line)&&!(match(line," $")||prenl))
80235267Sgabor	add(OFS)
81235267Sgabor    } else if(match(words[w],"^Xc$")) {
82235267Sgabor      skip=1
83235267Sgabor      ext=0
84235267Sgabor      if(!extopt)
85235267Sgabor	prenl++
86235267Sgabor      w=nwords
87235267Sgabor    } else if(match(words[w],"^Bd$")) {
88235267Sgabor      skip=1
89235267Sgabor      if(match(words[w+1],"-literal")) {
90235267Sgabor	literal=1
91235267Sgabor	prenl++
92235267Sgabor	w=nwords
93235267Sgabor      }
94235267Sgabor    } else if(match(words[w],"^Ed$")) {
95235267Sgabor      skip=1
96235267Sgabor      literal=0
97235267Sgabor    } else if(match(words[w],"^Ns$")) {
98242430Sgabor      skip=1
99235267Sgabor      if(!nospace)
100235267Sgabor	nospace=1
101235267Sgabor      sub(" $","",line)
102235267Sgabor    } else if(match(words[w],"^No$")) {
103235267Sgabor      skip=1
104242430Sgabor      sub(" $","",line)
105235267Sgabor      add(words[++w])
106235267Sgabor    } else if(match(words[w],"^Dq$")) {
107235267Sgabor      skip=1
108235267Sgabor      add("``")
109235267Sgabor      add(words[++w])
110235267Sgabor      while(w<nwords&&!match(words[w+1],"^[\\.,]"))
111235267Sgabor	add(OFS words[++w])
112235267Sgabor      add("''")
113235267Sgabor      if(!nospace&&match(words[w+1],"^[\\.,]"))
114235267Sgabor	nospace=1
115235267Sgabor    } else if(match(words[w],"^Sq|Ql$")) {
116235267Sgabor      skip=1
117235267Sgabor      add("`" words[++w] "'")
118235267Sgabor      if(!nospace&&match(words[w+1],"^[\\.,]"))
119235267Sgabor	nospace=1
120235267Sgabor    } else if(match(words[w],"^Oo$")) {
121235267Sgabor      skip=1
122235267Sgabor      extopt=1
123235267Sgabor      if(!nospace)
124235267Sgabor	nospace=1
125235267Sgabor      add("[")
126235267Sgabor    } else if(match(words[w],"^Oc$")) {
127235267Sgabor      skip=1
128235267Sgabor      extopt=0
129235267Sgabor      add("]")
130235267Sgabor    }
131235267Sgabor    if(!skip) {
132235267Sgabor      if(!nospace&&length(line)&&!(match(line," $")||prenl))
133235267Sgabor	add(OFS)
134235267Sgabor      if(nospace==1)
135235267Sgabor	nospace=0
136235267Sgabor    }
137235267Sgabor    if(match(words[w],"^Dd$")) {
138235267Sgabor      date=wtail()
139235267Sgabor      next
140235267Sgabor    } else if(match(words[w],"^Dt$")) {
141235267Sgabor      id=wtail()
142235267Sgabor      next
143235267Sgabor    } else if(match(words[w],"^Ox$")) {
144235267Sgabor      add("OpenBSD")
145235267Sgabor      skip=1
146235267Sgabor    } else if(match(words[w],"^Os$")) {
147235267Sgabor      add(".TH " id " \"" date "\" \"" wtail() "\"")
148235267Sgabor    } else if(match(words[w],"^Sh$")) {
149235267Sgabor      add(".SH")
150235267Sgabor      synopsis=match(words[w+1],"SYNOPSIS")
151235267Sgabor    } else if(match(words[w],"^Xr$")) {
152235267Sgabor      add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w])
153235267Sgabor    } else if(match(words[w],"^Rs$")) {
154235267Sgabor      split("",refauthors)
155235267Sgabor      nrefauthors=0
156235267Sgabor      reftitle=""
157235267Sgabor      refissue=""
158235267Sgabor      refdate=""
159235267Sgabor      refopt=""
160235267Sgabor      reference=1
161235267Sgabor      next
162235267Sgabor    } else if(match(words[w],"^Re$")) {
163235267Sgabor      prenl++
164235267Sgabor      for(i=nrefauthors-1;i>0;i--) {
165235267Sgabor	add(refauthors[i])
166235267Sgabor	if(i>1)
167235267Sgabor	  add(", ")
168235267Sgabor      }
169235267Sgabor      if(nrefauthors>1)
170235267Sgabor	add(" and ")
171235267Sgabor      add(refauthors[0] ", \\fI" reftitle "\\fP")
172235267Sgabor      if(length(refissue))
173235267Sgabor	add(", " refissue)
174235267Sgabor      if(length(refdate))
175235267Sgabor	add(", " refdate)
176235267Sgabor      if(length(refopt))
177235267Sgabor	add(", " refopt)
178235267Sgabor      add(".")
179235267Sgabor      reference=0
180235267Sgabor    } else if(reference) {
181235267Sgabor      if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() }
182235267Sgabor      if(match(words[w],"^%T$")) {
183235267Sgabor	reftitle=wtail()
184235267Sgabor	sub("^\"","",reftitle)
185235267Sgabor	sub("\"$","",reftitle)
186235267Sgabor      }
187235267Sgabor      if(match(words[w],"^%N$")) { refissue=wtail() }
188235267Sgabor      if(match(words[w],"^%D$")) { refdate=wtail() }
189235267Sgabor      if(match(words[w],"^%O$")) { refopt=wtail() }
190235267Sgabor    } else if(match(words[w],"^Nm$")) {
191235267Sgabor      if(synopsis) {
192235267Sgabor	add(".br")
193235267Sgabor	prenl++
194235267Sgabor      }
195235267Sgabor      n=words[++w]
196235267Sgabor      if(!length(name))
197235267Sgabor	name=n
198235267Sgabor      if(!length(n))
199235267Sgabor	n=name
200235267Sgabor      add("\\fB" n "\\fP")
201235267Sgabor      if(!nospace&&match(words[w+1],"^[\\.,]"))
202235267Sgabor	nospace=1
203235267Sgabor    } else if(match(words[w],"^Nd$")) {
204235267Sgabor      add("\\- " wtail())
205235267Sgabor    } else if(match(words[w],"^Fl$")) {
206235267Sgabor      add("\\fB\\-" words[++w] "\\fP")
207235267Sgabor      if(!nospace&&match(words[w+1],"^[\\.,]"))
208235267Sgabor	nospace=1
209235267Sgabor    } else if(match(words[w],"^Ar$")) {
210235267Sgabor      add("\\fI")
211235267Sgabor      if(w==nwords)
212235267Sgabor	add("file ...\\fP")
213235267Sgabor      else {
214235267Sgabor	add(words[++w] "\\fP")
215235267Sgabor	while(match(words[w+1],"^\\|$"))
216235267Sgabor	  add(OFS words[++w] " \\fI" words[++w] "\\fP")
217235267Sgabor      }
218235267Sgabor      if(!nospace&&match(words[w+1],"^[\\.,]"))
219235267Sgabor	nospace=1
220235267Sgabor    } else if(match(words[w],"^Cm$")) {
221235267Sgabor      add("\\fB" words[++w] "\\fP")
222235267Sgabor      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
223235267Sgabor	add(words[++w])
224235267Sgabor    } else if(match(words[w],"^Op$")) {
225235267Sgabor      option=1
226235267Sgabor      if(!nospace)
227235267Sgabor	nospace=1
228235267Sgabor      add("[")
229235267Sgabor    } else if(match(words[w],"^Pp$")) {
230235267Sgabor      prenl++
231235267Sgabor    } else if(match(words[w],"^An$")) {
232235267Sgabor      prenl++
233235267Sgabor    } else if(match(words[w],"^Ss$")) {
234235267Sgabor      add(".SS")
235235267Sgabor    } else if(match(words[w],"^Pa$")&&!option) {
236235267Sgabor      add("\\fI")
237235267Sgabor      w++
238235267Sgabor      if(match(words[w],"^\\."))
239235267Sgabor	add("\\&")
240235267Sgabor      add(words[w] "\\fP")
241235267Sgabor      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
242235267Sgabor	add(words[++w])
243235267Sgabor    } else if(match(words[w],"^Dv$")) {
244235267Sgabor      add(".BR")
245235267Sgabor    } else if(match(words[w],"^Em|Ev$")) {
246235267Sgabor      add(".IR")
247235267Sgabor    } else if(match(words[w],"^Pq$")) {
248235267Sgabor      add("(")
249235267Sgabor      nospace=1
250235267Sgabor      parens=1
251235267Sgabor    } else if(match(words[w],"^Aq$")) {
252235267Sgabor      add("<")
253235267Sgabor      nospace=1
254235267Sgabor      angles=1
255235267Sgabor    } else if(match(words[w],"^S[xy]$")) {
256235267Sgabor      add(".B " wtail())
257235267Sgabor    } else if(match(words[w],"^Ic$")) {
258235267Sgabor      plain=1
259235267Sgabor      add("\\fB")
260235267Sgabor      while(w<nwords) {
261235267Sgabor	w++
262235267Sgabor	if(match(words[w],"^Op$")) {
263235267Sgabor	  w++
264235267Sgabor	  add("[")
265235267Sgabor	  words[nwords]=words[nwords] "]"
266235267Sgabor	}
267235267Sgabor	if(match(words[w],"^Ar$")) {
268235267Sgabor	  add("\\fI" words[++w] "\\fP")
269235267Sgabor	} else if(match(words[w],"^[\\.,]")) {
270235267Sgabor	  sub(" $","",line)
271235267Sgabor	  if(plain) {
272235267Sgabor	    add("\\fP")
273235267Sgabor	    plain=0
274235267Sgabor	  }
275235267Sgabor	  add(words[w])
276235267Sgabor	} else {
277235267Sgabor	  if(!plain) {
278235267Sgabor	    add("\\fB")
279235267Sgabor	    plain=1
280235267Sgabor	  }
281235267Sgabor	  add(words[w])
282235267Sgabor	}
283235267Sgabor	if(!nospace)
284235267Sgabor	  add(OFS)
285235267Sgabor      }
286235267Sgabor      sub(" $","",line)
287235267Sgabor      if(plain)
288235267Sgabor	add("\\fP")
289235267Sgabor    } else if(match(words[w],"^Bl$")) {
290235267Sgabor      oldoptlist=optlist
291235267Sgabor      if(match(words[w+1],"-bullet"))
292235267Sgabor	optlist=1
293235267Sgabor      else if(match(words[w+1],"-enum")) {
294235267Sgabor	optlist=2
295235267Sgabor	enum=0
296235267Sgabor      } else if(match(words[w+1],"-tag"))
297235267Sgabor	optlist=3
298235267Sgabor      else if(match(words[w+1],"-item"))
299235267Sgabor	optlist=4
300235267Sgabor      else if(match(words[w+1],"-bullet"))
301235267Sgabor	optlist=1
302235267Sgabor      w=nwords
303235267Sgabor    } else if(match(words[w],"^El$")) {
304235267Sgabor      optlist=oldoptlist
305235267Sgabor    } else if(match(words[w],"^Bk$")) {
306235267Sgabor      if(match(words[w+1],"-words")) {
307235267Sgabor	w++
308235267Sgabor	breakw=1
309235267Sgabor      }
310235267Sgabor    } else if(match(words[w],"^Ek$")) {
311235267Sgabor      breakw=0
312235267Sgabor    } else if(match(words[w],"^It$")&&optlist) {
313235267Sgabor      if(optlist==1)
314235267Sgabor	add(".IP \\(bu")
315235267Sgabor      else if(optlist==2)
316235267Sgabor	add(".IP " ++enum ".")
317235267Sgabor      else if(optlist==3) {
318235267Sgabor	add(".TP")
319235267Sgabor	prenl++
320235267Sgabor	if(match(words[w+1],"^Pa$|^Ev$")) {
321235267Sgabor	  add(".B")
322235267Sgabor	  w++
323235267Sgabor	}
324235267Sgabor      } else if(optlist==4)
325235267Sgabor	add(".IP")
326235267Sgabor    } else if(match(words[w],"^Sm$")) {
327235267Sgabor      if(match(words[w+1],"off"))
328235267Sgabor	nospace=2
329235267Sgabor      else if(match(words[w+1],"on"))
330235267Sgabor	nospace=0
331235267Sgabor      w++
332235267Sgabor    } else if(!skip) {
333235267Sgabor      add(words[w])
334235267Sgabor    }
335235267Sgabor  }
336235267Sgabor  if(match(line,"^\\.[^a-zA-Z]"))
337235267Sgabor    sub("^\\.","",line)
338235267Sgabor  if(parens)
339235267Sgabor    add(")")
340235267Sgabor  if(angles)
341235267Sgabor    add(">")
342235267Sgabor  if(option)
343235267Sgabor    add("]")
344235267Sgabor  if(ext&&!extopt&&!match(line," $"))
345235267Sgabor    add(OFS)
346235267Sgabor  if(!ext&&!extopt&&length(line)) {
347235267Sgabor    print line
348235267Sgabor    prenl=0
349235267Sgabor    line=""
350235267Sgabor  }
351235267Sgabor}
352235267Sgabor