#!/usr/bin/awk
#
# Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp
#
# Version history:
#  v4+ Adapted for OpenSSH Portable (see cvs Id and history)
#  v3, I put the program under a proper license
#      Dan Nelson <[email protected]> added .An, .Aq and fixed a typo
#  v2, fixed to work on GNU awk --posix and MacOS X
#  v1, first attempt, didn't work on MacOS X
#
# Copyright (c) 2003 Peter Stuge <[email protected]>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


BEGIN {
 optlist=0
 oldoptlist=0
 nospace=0
 synopsis=0
 reference=0
 block=0
 ext=0
 extopt=0
 literal=0
 prenl=0
 breakw=0
 line=""
}

function wtail() {
 retval=""
 while(w<nwords) {
   if(length(retval))
     retval=retval OFS
   retval=retval words[++w]
 }
 return retval
}

function add(str) {
 for(;prenl;prenl--)
   line=line "\n"
 line=line str
}

! /^\./ {
 for(;prenl;prenl--)
   print ""
 print
 if(literal)
   print ".br"
 next
}

/^\.\\"/ { next }

{
 option=0
 parens=0
 angles=0
 sub("^\\.","")
 nwords=split($0,words)
 for(w=1;w<=nwords;w++) {
   skip=0
   if(match(words[w],"^Li|Pf$")) {
     skip=1
   } else if(match(words[w],"^Xo$")) {
     skip=1
     ext=1
     if(length(line)&&!(match(line," $")||prenl))
       add(OFS)
   } else if(match(words[w],"^Xc$")) {
     skip=1
     ext=0
     if(!extopt)
       prenl++
     w=nwords
   } else if(match(words[w],"^Bd$")) {
     skip=1
     if(match(words[w+1],"-literal")) {
       literal=1
       prenl++
       w=nwords
     }
   } else if(match(words[w],"^Ed$")) {
     skip=1
     literal=0
   } else if(match(words[w],"^Ns$")) {
     skip=1
     if(!nospace)
       nospace=1
     sub(" $","",line)
   } else if(match(words[w],"^No$")) {
     skip=1
     sub(" $","",line)
     add(words[++w])
   } else if(match(words[w],"^Dq$")) {
     skip=1
     add("``")
     add(words[++w])
     while(w<nwords&&!match(words[w+1],"^[\\.,]"))
       add(OFS words[++w])
     add("''")
     if(!nospace&&match(words[w+1],"^[\\.,]"))
       nospace=1
   } else if(match(words[w],"^Sq|Ql$")) {
     skip=1
     add("`" words[++w] "'")
     if(!nospace&&match(words[w+1],"^[\\.,]"))
       nospace=1
   } else if(match(words[w],"^Oo$")) {
     skip=1
     extopt=1
     if(!nospace)
       nospace=1
     add("[")
   } else if(match(words[w],"^Oc$")) {
     skip=1
     extopt=0
     add("]")
   }
   if(!skip) {
     if(!nospace&&length(line)&&!(match(line," $")||prenl))
       add(OFS)
     if(nospace==1)
       nospace=0
   }
   if(match(words[w],"^Dd$")) {
     if(match(words[w+1],"^\\$Mdocdate:")) {
       w++;
       if(match(words[w+4],"^\\$$")) {
         words[w+4] = ""
       }
     }
     date=wtail()
     next
   } else if(match(words[w],"^Dt$")) {
     id=wtail()
     next
   } else if(match(words[w],"^Ux$")) {
     add("UNIX")
     skip=1
   } else if(match(words[w],"^Ox$")) {
     add("OpenBSD")
     skip=1
   } else if(match(words[w],"^Os$")) {
     add(".TH " id " \"" date "\" \"" wtail() "\"")
   } else if(match(words[w],"^Sh$")) {
     add(".SH")
     synopsis=match(words[w+1],"SYNOPSIS")
   } else if(match(words[w],"^Xr$")) {
     add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w])
   } else if(match(words[w],"^Rs$")) {
     split("",refauthors)
     nrefauthors=0
     reftitle=""
     refissue=""
     refdate=""
     refopt=""
     refreport=""
     reference=1
     next
   } else if(match(words[w],"^Re$")) {
     prenl++
     for(i=nrefauthors-1;i>0;i--) {
       add(refauthors[i])
       if(i>1)
         add(", ")
     }
     if(nrefauthors>1)
       add(" and ")
     if(nrefauthors>0)
       add(refauthors[0] ", ")
     add("\\fI" reftitle "\\fP")
     if(length(refissue))
       add(", " refissue)
     if(length(refreport)) {
       add(", " refreport)
     }
     if(length(refdate))
       add(", " refdate)
     if(length(refopt))
       add(", " refopt)
     add(".")
     reference=0
   } else if(reference) {
     if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() }
     if(match(words[w],"^%T$")) {
       reftitle=wtail()
       sub("^\"","",reftitle)
       sub("\"$","",reftitle)
     }
     if(match(words[w],"^%N$")) { refissue=wtail() }
     if(match(words[w],"^%D$")) { refdate=wtail() }
     if(match(words[w],"^%O$")) { refopt=wtail() }
     if(match(words[w],"^%R$")) { refreport=wtail() }
   } else if(match(words[w],"^Nm$")) {
     if(synopsis) {
       add(".br")
       prenl++
     }
     n=words[++w]
     if(!length(name))
       name=n
     if(!length(n))
       n=name
     add("\\fB" n "\\fP")
     if(!nospace&&match(words[w+1],"^[\\.,]"))
       nospace=1
   } else if(match(words[w],"^Nd$")) {
     add("\\- " wtail())
   } else if(match(words[w],"^Fl$")) {
     add("\\fB\\-" words[++w] "\\fP")
     if(!nospace&&match(words[w+1],"^[\\.,]"))
       nospace=1
   } else if(match(words[w],"^Ar$")) {
     add("\\fI")
     if(w==nwords)
       add("file ...\\fP")
     else {
       add(words[++w] "\\fP")
       while(match(words[w+1],"^\\|$"))
         add(OFS words[++w] " \\fI" words[++w] "\\fP")
     }
     if(!nospace&&match(words[w+1],"^[\\.,]"))
       nospace=1
   } else if(match(words[w],"^Cm$")) {
     add("\\fB" words[++w] "\\fP")
     while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
       add(words[++w])
   } else if(match(words[w],"^Op$")) {
     option=1
     if(!nospace)
       nospace=1
     add("[")
   } else if(match(words[w],"^Pp$")) {
     prenl++
   } else if(match(words[w],"^An$")) {
     prenl++
   } else if(match(words[w],"^Ss$")) {
     add(".SS")
   } else if(match(words[w],"^Pa$")&&!option) {
     add("\\fI")
     w++
     if(match(words[w],"^\\."))
       add("\\&")
     add(words[w] "\\fP")
     while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
       add(words[++w])
   } else if(match(words[w],"^Dv$")) {
     add(".BR")
   } else if(match(words[w],"^Em|Ev$")) {
     add(".IR")
   } else if(match(words[w],"^Pq$")) {
     add("(")
     nospace=1
     parens=1
   } else if(match(words[w],"^Aq$")) {
     add("<")
     nospace=1
     angles=1
   } else if(match(words[w],"^S[xy]$")) {
     add(".B " wtail())
   } else if(match(words[w],"^Ic$")) {
     plain=1
     add("\\fB")
     while(w<nwords) {
       w++
       if(match(words[w],"^Op$")) {
         w++
         add("[")
         words[nwords]=words[nwords] "]"
       }
       if(match(words[w],"^Ar$")) {
         add("\\fI" words[++w] "\\fP")
       } else if(match(words[w],"^[\\.,]")) {
         sub(" $","",line)
         if(plain) {
           add("\\fP")
           plain=0
         }
         add(words[w])
       } else {
         if(!plain) {
           add("\\fB")
           plain=1
         }
         add(words[w])
       }
       if(!nospace)
         add(OFS)
     }
     sub(" $","",line)
     if(plain)
       add("\\fP")
   } else if(match(words[w],"^Bl$")) {
     oldoptlist=optlist
     if(match(words[w+1],"-bullet"))
       optlist=1
     else if(match(words[w+1],"-enum")) {
       optlist=2
       enum=0
     } else if(match(words[w+1],"-tag"))
       optlist=3
     else if(match(words[w+1],"-item"))
       optlist=4
     else if(match(words[w+1],"-bullet"))
       optlist=1
     w=nwords
   } else if(match(words[w],"^El$")) {
     optlist=oldoptlist
   } else if(match(words[w],"^Bk$")) {
     if(match(words[w+1],"-words")) {
       w++
       breakw=1
     }
   } else if(match(words[w],"^Ek$")) {
     breakw=0
   } else if(match(words[w],"^It$")&&optlist) {
     if(optlist==1)
       add(".IP \\(bu")
     else if(optlist==2)
       add(".IP " ++enum ".")
     else if(optlist==3) {
       add(".TP")
       prenl++
       if(match(words[w+1],"^Pa$|^Ev$")) {
         add(".B")
         w++
       }
     } else if(optlist==4)
       add(".IP")
   } else if(match(words[w],"^Sm$")) {
     if(match(words[w+1],"off"))
       nospace=2
     else if(match(words[w+1],"on"))
       nospace=0
     w++
   } else if(!skip) {
     add(words[w])
   }
 }
 if(match(line,"^\\.[^a-zA-Z]"))
   sub("^\\.","",line)
 if(parens)
   add(")")
 if(angles)
   add(">")
 if(option)
   add("]")
 if(ext&&!extopt&&!match(line," $"))
   add(OFS)
 if(!ext&&!extopt&&length(line)) {
   print line
   prenl=0
   line=""
 }
}