xref: /freebsd/crypto/openssh/mdoc2man.awk (revision 2574974648c68c738aec3ff96644d888d7913a37)
1#!/usr/bin/awk
2#
3# Version history:
4#  v4+ Adapted for OpenSSH Portable (see cvs Id and history)
5#  v3, I put the program under a proper license
6#      Dan Nelson <dnelson@allantgroup.com> added .An, .Aq and fixed a typo
7#  v2, fixed to work on GNU awk --posix and MacOS X
8#  v1, first attempt, didn't work on MacOS X
9#
10# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org>
11#
12# Permission to use, copy, modify, and distribute this software for any
13# purpose with or without fee is hereby granted, provided that the above
14# copyright notice and this permission notice appear in all copies.
15#
16# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
24
25BEGIN {
26  optlist=0
27  oldoptlist=0
28  nospace=0
29  synopsis=0
30  reference=0
31  block=0
32  ext=0
33  extopt=0
34  literal=0
35  prenl=0
36  breakw=0
37  line=""
38}
39
40function wtail() {
41  retval=""
42  while(w<nwords) {
43    if(length(retval))
44      retval=retval OFS
45    retval=retval words[++w]
46  }
47  return retval
48}
49
50function add(str) {
51  for(;prenl;prenl--)
52    line=line "\n"
53  line=line str
54}
55
56! /^\./ {
57  for(;prenl;prenl--)
58    print ""
59  print
60  if(literal)
61    print ".br"
62  next
63}
64
65/^\.\\"/ { next }
66
67{
68  option=0
69  parens=0
70  angles=0
71  sub("^\\.","")
72  nwords=split($0,words)
73  for(w=1;w<=nwords;w++) {
74    skip=0
75    if(match(words[w],"^Li|Pf$")) {
76      skip=1
77    } else if(match(words[w],"^Xo$")) {
78      skip=1
79      ext=1
80      if(length(line)&&!(match(line," $")||prenl))
81	add(OFS)
82    } else if(match(words[w],"^Xc$")) {
83      skip=1
84      ext=0
85      if(!extopt)
86	prenl++
87      w=nwords
88    } else if(match(words[w],"^Bd$")) {
89      skip=1
90      if(match(words[w+1],"-literal")) {
91	literal=1
92	prenl++
93	w=nwords
94      }
95    } else if(match(words[w],"^Ed$")) {
96      skip=1
97      literal=0
98    } else if(match(words[w],"^Dl$")) {
99      skip=1
100    } else if(match(words[w],"^Ns$")) {
101      skip=1
102      if(!nospace)
103	nospace=1
104      sub(" $","",line)
105    } else if(match(words[w],"^No$")) {
106      skip=1
107      sub(" $","",line)
108      add(words[++w])
109    } else if(match(words[w],"^Dq$")) {
110      skip=1
111      add("``")
112      add(words[++w])
113      while(w<nwords&&!match(words[w+1],"^[\\.,]"))
114	add(OFS words[++w])
115      add("''")
116      if(!nospace&&match(words[w+1],"^[\\.,]"))
117	nospace=1
118    } else if(match(words[w],"^Sq|Ql$")) {
119      skip=1
120      add("`" words[++w] "'")
121      if(!nospace&&match(words[w+1],"^[\\.,]"))
122	nospace=1
123    } else if(match(words[w],"^Oo$")) {
124      skip=1
125      extopt=1
126      if(!nospace)
127	nospace=1
128      add("[")
129    } else if(match(words[w],"^Oc$")) {
130      skip=1
131      extopt=0
132      add("]")
133    }
134    if(!skip) {
135      if(!nospace&&length(line)&&!(match(line," $")||prenl))
136	add(OFS)
137      if(nospace==1)
138	nospace=0
139    }
140    if(match(words[w],"^Dd$")) {
141      if(match(words[w+1],"^\\$Mdocdate:")) {
142        w++;
143        if(match(words[w+4],"^\\$$")) {
144          words[w+4] = ""
145        }
146      }
147      date=wtail()
148      next
149    } else if(match(words[w],"^Dt$")) {
150      id=wtail()
151      next
152    } else if(match(words[w],"^Ux$")) {
153      add("UNIX")
154      skip=1
155    } else if(match(words[w],"^Ox$")) {
156      add("OpenBSD")
157      skip=1
158    } else if(match(words[w],"^Os$")) {
159      add(".TH " id " \"" date "\" \"" wtail() "\"")
160    } else if(match(words[w],"^Sh$")) {
161      add(".SH")
162      synopsis=match(words[w+1],"SYNOPSIS")
163    } else if(match(words[w],"^Xr$")) {
164      add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w])
165    } else if(match(words[w],"^Rs$")) {
166      split("",refauthors)
167      nrefauthors=0
168      reftitle=""
169      refissue=""
170      refdate=""
171      refopt=""
172      refreport=""
173      reference=1
174      next
175    } else if(match(words[w],"^Re$")) {
176      prenl++
177      for(i=nrefauthors-1;i>0;i--) {
178	add(refauthors[i])
179	if(i>1)
180	  add(", ")
181      }
182      if(nrefauthors>1)
183	add(" and ")
184      if(nrefauthors>0)
185        add(refauthors[0] ", ")
186      add("\\fI" reftitle "\\fP")
187      if(length(refissue))
188	add(", " refissue)
189      if(length(refreport)) {
190	add(", " refreport)
191      }
192      if(length(refdate))
193	add(", " refdate)
194      if(length(refopt))
195	add(", " refopt)
196      add(".")
197      reference=0
198    } else if(reference) {
199      if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() }
200      if(match(words[w],"^%T$")) {
201	reftitle=wtail()
202	sub("^\"","",reftitle)
203	sub("\"$","",reftitle)
204      }
205      if(match(words[w],"^%N$")) { refissue=wtail() }
206      if(match(words[w],"^%D$")) { refdate=wtail() }
207      if(match(words[w],"^%O$")) { refopt=wtail() }
208      if(match(words[w],"^%R$")) { refreport=wtail() }
209    } else if(match(words[w],"^Nm$")) {
210      if(synopsis) {
211	add(".br")
212	prenl++
213      }
214      n=words[++w]
215      if(!length(name))
216	name=n
217      if(!length(n))
218	n=name
219      add("\\fB" n "\\fP")
220      if(!nospace&&match(words[w+1],"^[\\.,]"))
221	nospace=1
222    } else if(match(words[w],"^Nd$")) {
223      add("\\- " wtail())
224    } else if(match(words[w],"^Fl$")) {
225      add("\\fB\\-" words[++w] "\\fP")
226      if(!nospace&&match(words[w+1],"^[\\.,]"))
227	nospace=1
228    } else if(match(words[w],"^Ar$")) {
229      add("\\fI")
230      if(w==nwords)
231	add("file ...\\fP")
232      else {
233	add(words[++w] "\\fP")
234	while(match(words[w+1],"^\\|$"))
235	  add(OFS words[++w] " \\fI" words[++w] "\\fP")
236      }
237      if(!nospace&&match(words[w+1],"^[\\.,]"))
238	nospace=1
239    } else if(match(words[w],"^Cm$")) {
240      add("\\fB" words[++w] "\\fP")
241      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
242	add(words[++w])
243    } else if(match(words[w],"^Op$")) {
244      option++
245      if(!nospace)
246	nospace=1
247      add("[")
248    } else if(match(words[w],"^Pp$")) {
249      prenl++
250    } else if(match(words[w],"^An$")) {
251      prenl++
252    } else if(match(words[w],"^Ss$")) {
253      add(".SS")
254    } else if(match(words[w],"^Pa$")&&!option) {
255      add("\\fI")
256      w++
257      if(match(words[w],"^\\."))
258	add("\\&")
259      add(words[w] "\\fP")
260      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
261	add(words[++w])
262    } else if(match(words[w],"^Dv$")) {
263      add(".BR")
264    } else if(match(words[w],"^Em|Ev$")) {
265      add(".IR")
266    } else if(match(words[w],"^Pq$")) {
267      add("(")
268      nospace=1
269      parens=1
270    } else if(match(words[w],"^Aq$")) {
271      add("<")
272      nospace=1
273      angles=1
274    } else if(match(words[w],"^S[xy]$")) {
275      add(".B " wtail())
276    } else if(match(words[w],"^Ic$")) {
277      plain=1
278      add("\\fB")
279      while(w<nwords) {
280	w++
281	if(match(words[w],"^Op$")) {
282	  w++
283	  add("[")
284	  words[nwords]=words[nwords] "]"
285	}
286	if(match(words[w],"^Ns$")) {
287	  w++
288	  if(!nospace)
289	    nospace=1
290	  sub(" $","",line)
291	}
292	if(match(words[w],"^Ar$")) {
293	  add("\\fI" words[++w] "\\fP")
294	} else if(match(words[w],"^[\\.,]")) {
295	  sub(" $","",line)
296	  if(plain) {
297	    add("\\fP")
298	    plain=0
299	  }
300	  add(words[w])
301	} else {
302	  if(!plain) {
303	    add("\\fB")
304	    plain=1
305	  }
306	  add(words[w])
307	}
308	if(!nospace)
309	  add(OFS)
310      }
311      sub(" $","",line)
312      if(plain)
313	add("\\fP")
314    } else if(match(words[w],"^Bl$")) {
315      oldoptlist=optlist
316      if(match(words[w+1],"-bullet"))
317	optlist=1
318      else if(match(words[w+1],"-enum")) {
319	optlist=2
320	enum=0
321      } else if(match(words[w+1],"-tag"))
322	optlist=3
323      else if(match(words[w+1],"-item"))
324	optlist=4
325      else if(match(words[w+1],"-bullet"))
326	optlist=1
327      w=nwords
328    } else if(match(words[w],"^El$")) {
329      optlist=oldoptlist
330      if(!optlist)
331        add(".PP")
332    } else if(match(words[w],"^Bk$")) {
333      if(match(words[w+1],"-words")) {
334	w++
335	breakw=1
336      }
337    } else if(match(words[w],"^Ek$")) {
338      breakw=0
339    } else if(match(words[w],"^It$")&&optlist) {
340      if(optlist==1)
341	add(".IP \\(bu")
342      else if(optlist==2)
343	add(".IP " ++enum ".")
344      else if(optlist==3) {
345	add(".TP")
346	prenl++
347	if(match(words[w+1],"^Pa$|^Ev$")) {
348	  add(".B")
349	  w++
350	}
351      } else if(optlist==4)
352	add(".IP")
353    } else if(match(words[w],"^Sm$")) {
354      if(match(words[w+1],"off"))
355	nospace=2
356      else if(match(words[w+1],"on"))
357	nospace=0
358      w++
359    } else if(!skip) {
360      add(words[w])
361    }
362  }
363  if(match(line,"^\\.[^a-zA-Z]"))
364    sub("^\\.","",line)
365  if(parens)
366    add(")")
367  if(angles)
368    add(">")
369  for(;option;option--)
370    add("]")
371  if(ext&&!extopt&&!match(line," $"))
372    add(OFS)
373  if(!ext&&!extopt&&length(line)) {
374    print line
375    prenl=0
376    line=""
377  }
378}
379