1124208Sdes#!/usr/bin/awk 2124208Sdes# 3204861Sdes# $Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp $ 4180744Sdes# 5124208Sdes# Version history: 6180744Sdes# v4+ Adapted for OpenSSH Portable (see cvs Id and history) 7124208Sdes# v3, I put the program under a proper license 8124208Sdes# Dan Nelson <dnelson@allantgroup.com> added .An, .Aq and fixed a typo 9124208Sdes# v2, fixed to work on GNU awk --posix and MacOS X 10124208Sdes# v1, first attempt, didn't work on MacOS X 11124208Sdes# 12124208Sdes# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org> 13124208Sdes# 14124208Sdes# Permission to use, copy, modify, and distribute this software for any 15124208Sdes# purpose with or without fee is hereby granted, provided that the above 16124208Sdes# copyright notice and this permission notice appear in all copies. 17124208Sdes# 18124208Sdes# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 19124208Sdes# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 20124208Sdes# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 21124208Sdes# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22124208Sdes# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 23124208Sdes# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 24124208Sdes# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25124208Sdes 26124208Sdes 27124208SdesBEGIN { 28124208Sdes optlist=0 29124208Sdes oldoptlist=0 30124208Sdes nospace=0 31124208Sdes synopsis=0 32124208Sdes reference=0 33124208Sdes block=0 34124208Sdes ext=0 35124208Sdes extopt=0 36124208Sdes literal=0 37124208Sdes prenl=0 38137015Sdes breakw=0 39124208Sdes line="" 40124208Sdes} 41124208Sdes 42124208Sdesfunction wtail() { 43124208Sdes retval="" 44124208Sdes while(w<nwords) { 45124208Sdes if(length(retval)) 46124208Sdes retval=retval OFS 47124208Sdes retval=retval words[++w] 48124208Sdes } 49124208Sdes return retval 50124208Sdes} 51124208Sdes 52124208Sdesfunction add(str) { 53124208Sdes for(;prenl;prenl--) 54124208Sdes line=line "\n" 55124208Sdes line=line str 56124208Sdes} 57124208Sdes 58124208Sdes! /^\./ { 59124208Sdes for(;prenl;prenl--) 60124208Sdes print "" 61124208Sdes print 62124208Sdes if(literal) 63124208Sdes print ".br" 64124208Sdes next 65124208Sdes} 66124208Sdes 67124208Sdes/^\.\\"/ { next } 68124208Sdes 69124208Sdes{ 70124208Sdes option=0 71124208Sdes parens=0 72124208Sdes angles=0 73124208Sdes sub("^\\.","") 74124208Sdes nwords=split($0,words) 75124208Sdes for(w=1;w<=nwords;w++) { 76124208Sdes skip=0 77124208Sdes if(match(words[w],"^Li|Pf$")) { 78124208Sdes skip=1 79124208Sdes } else if(match(words[w],"^Xo$")) { 80124208Sdes skip=1 81124208Sdes ext=1 82124208Sdes if(length(line)&&!(match(line," $")||prenl)) 83126274Sdes add(OFS) 84124208Sdes } else if(match(words[w],"^Xc$")) { 85124208Sdes skip=1 86124208Sdes ext=0 87124208Sdes if(!extopt) 88126274Sdes prenl++ 89124208Sdes w=nwords 90124208Sdes } else if(match(words[w],"^Bd$")) { 91124208Sdes skip=1 92124208Sdes if(match(words[w+1],"-literal")) { 93126274Sdes literal=1 94126274Sdes prenl++ 95126274Sdes w=nwords 96124208Sdes } 97124208Sdes } else if(match(words[w],"^Ed$")) { 98124208Sdes skip=1 99124208Sdes literal=0 100124208Sdes } else if(match(words[w],"^Ns$")) { 101124208Sdes skip=1 102124208Sdes if(!nospace) 103126274Sdes nospace=1 104124208Sdes sub(" $","",line) 105124208Sdes } else if(match(words[w],"^No$")) { 106124208Sdes skip=1 107124208Sdes sub(" $","",line) 108124208Sdes add(words[++w]) 109124208Sdes } else if(match(words[w],"^Dq$")) { 110124208Sdes skip=1 111124208Sdes add("``") 112124208Sdes add(words[++w]) 113124208Sdes while(w<nwords&&!match(words[w+1],"^[\\.,]")) 114126274Sdes add(OFS words[++w]) 115124208Sdes add("''") 116124208Sdes if(!nospace&&match(words[w+1],"^[\\.,]")) 117126274Sdes nospace=1 118124208Sdes } else if(match(words[w],"^Sq|Ql$")) { 119124208Sdes skip=1 120124208Sdes add("`" words[++w] "'") 121124208Sdes if(!nospace&&match(words[w+1],"^[\\.,]")) 122126274Sdes nospace=1 123124208Sdes } else if(match(words[w],"^Oo$")) { 124124208Sdes skip=1 125124208Sdes extopt=1 126124208Sdes if(!nospace) 127126274Sdes nospace=1 128124208Sdes add("[") 129124208Sdes } else if(match(words[w],"^Oc$")) { 130124208Sdes skip=1 131124208Sdes extopt=0 132124208Sdes add("]") 133124208Sdes } 134124208Sdes if(!skip) { 135124208Sdes if(!nospace&&length(line)&&!(match(line," $")||prenl)) 136126274Sdes add(OFS) 137124208Sdes if(nospace==1) 138126274Sdes nospace=0 139124208Sdes } 140124208Sdes if(match(words[w],"^Dd$")) { 141180744Sdes if(match(words[w+1],"^\\$Mdocdate:")) { 142180744Sdes w++; 143180744Sdes if(match(words[w+4],"^\\$$")) { 144180744Sdes words[w+4] = "" 145180744Sdes } 146180744Sdes } 147124208Sdes date=wtail() 148124208Sdes next 149124208Sdes } else if(match(words[w],"^Dt$")) { 150124208Sdes id=wtail() 151124208Sdes next 152204861Sdes } else if(match(words[w],"^Ux$")) { 153204861Sdes add("UNIX") 154204861Sdes skip=1 155149749Sdes } else if(match(words[w],"^Ox$")) { 156149749Sdes add("OpenBSD") 157149749Sdes skip=1 158124208Sdes } else if(match(words[w],"^Os$")) { 159124208Sdes add(".TH " id " \"" date "\" \"" wtail() "\"") 160124208Sdes } else if(match(words[w],"^Sh$")) { 161124208Sdes add(".SH") 162124208Sdes synopsis=match(words[w+1],"SYNOPSIS") 163124208Sdes } else if(match(words[w],"^Xr$")) { 164124208Sdes add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w]) 165124208Sdes } else if(match(words[w],"^Rs$")) { 166124208Sdes split("",refauthors) 167124208Sdes nrefauthors=0 168124208Sdes reftitle="" 169124208Sdes refissue="" 170124208Sdes refdate="" 171124208Sdes refopt="" 172180744Sdes refreport="" 173124208Sdes reference=1 174124208Sdes next 175124208Sdes } else if(match(words[w],"^Re$")) { 176124208Sdes prenl++ 177124208Sdes for(i=nrefauthors-1;i>0;i--) { 178126274Sdes add(refauthors[i]) 179126274Sdes if(i>1) 180126274Sdes add(", ") 181124208Sdes } 182124208Sdes if(nrefauthors>1) 183126274Sdes add(" and ") 184180744Sdes if(nrefauthors>0) 185180744Sdes add(refauthors[0] ", ") 186180744Sdes add("\\fI" reftitle "\\fP") 187124208Sdes if(length(refissue)) 188126274Sdes add(", " refissue) 189180744Sdes if(length(refreport)) { 190180744Sdes add(", " refreport) 191180744Sdes } 192124208Sdes if(length(refdate)) 193126274Sdes add(", " refdate) 194124208Sdes if(length(refopt)) 195126274Sdes add(", " refopt) 196124208Sdes add(".") 197124208Sdes reference=0 198124208Sdes } else if(reference) { 199124208Sdes if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() } 200124208Sdes if(match(words[w],"^%T$")) { 201126274Sdes reftitle=wtail() 202126274Sdes sub("^\"","",reftitle) 203126274Sdes sub("\"$","",reftitle) 204124208Sdes } 205124208Sdes if(match(words[w],"^%N$")) { refissue=wtail() } 206124208Sdes if(match(words[w],"^%D$")) { refdate=wtail() } 207124208Sdes if(match(words[w],"^%O$")) { refopt=wtail() } 208180744Sdes if(match(words[w],"^%R$")) { refreport=wtail() } 209124208Sdes } else if(match(words[w],"^Nm$")) { 210124208Sdes if(synopsis) { 211126274Sdes add(".br") 212126274Sdes prenl++ 213124208Sdes } 214124208Sdes n=words[++w] 215124208Sdes if(!length(name)) 216126274Sdes name=n 217124208Sdes if(!length(n)) 218126274Sdes n=name 219124208Sdes add("\\fB" n "\\fP") 220124208Sdes if(!nospace&&match(words[w+1],"^[\\.,]")) 221126274Sdes nospace=1 222124208Sdes } else if(match(words[w],"^Nd$")) { 223124208Sdes add("\\- " wtail()) 224124208Sdes } else if(match(words[w],"^Fl$")) { 225124208Sdes add("\\fB\\-" words[++w] "\\fP") 226124208Sdes if(!nospace&&match(words[w+1],"^[\\.,]")) 227126274Sdes nospace=1 228124208Sdes } else if(match(words[w],"^Ar$")) { 229124208Sdes add("\\fI") 230124208Sdes if(w==nwords) 231126274Sdes add("file ...\\fP") 232124208Sdes else { 233126274Sdes add(words[++w] "\\fP") 234126274Sdes while(match(words[w+1],"^\\|$")) 235126274Sdes add(OFS words[++w] " \\fI" words[++w] "\\fP") 236124208Sdes } 237124208Sdes if(!nospace&&match(words[w+1],"^[\\.,]")) 238126274Sdes nospace=1 239124208Sdes } else if(match(words[w],"^Cm$")) { 240124208Sdes add("\\fB" words[++w] "\\fP") 241124208Sdes while(w<nwords&&match(words[w+1],"^[\\.,:;)]")) 242126274Sdes add(words[++w]) 243124208Sdes } else if(match(words[w],"^Op$")) { 244124208Sdes option=1 245124208Sdes if(!nospace) 246126274Sdes nospace=1 247124208Sdes add("[") 248124208Sdes } else if(match(words[w],"^Pp$")) { 249124208Sdes prenl++ 250124208Sdes } else if(match(words[w],"^An$")) { 251124208Sdes prenl++ 252124208Sdes } else if(match(words[w],"^Ss$")) { 253124208Sdes add(".SS") 254124208Sdes } else if(match(words[w],"^Pa$")&&!option) { 255124208Sdes add("\\fI") 256124208Sdes w++ 257124208Sdes if(match(words[w],"^\\.")) 258126274Sdes add("\\&") 259124208Sdes add(words[w] "\\fP") 260124208Sdes while(w<nwords&&match(words[w+1],"^[\\.,:;)]")) 261126274Sdes add(words[++w]) 262124208Sdes } else if(match(words[w],"^Dv$")) { 263124208Sdes add(".BR") 264124208Sdes } else if(match(words[w],"^Em|Ev$")) { 265124208Sdes add(".IR") 266124208Sdes } else if(match(words[w],"^Pq$")) { 267124208Sdes add("(") 268124208Sdes nospace=1 269124208Sdes parens=1 270124208Sdes } else if(match(words[w],"^Aq$")) { 271124208Sdes add("<") 272124208Sdes nospace=1 273124208Sdes angles=1 274124208Sdes } else if(match(words[w],"^S[xy]$")) { 275124208Sdes add(".B " wtail()) 276124208Sdes } else if(match(words[w],"^Ic$")) { 277124208Sdes plain=1 278124208Sdes add("\\fB") 279124208Sdes while(w<nwords) { 280126274Sdes w++ 281126274Sdes if(match(words[w],"^Op$")) { 282126274Sdes w++ 283126274Sdes add("[") 284126274Sdes words[nwords]=words[nwords] "]" 285126274Sdes } 286126274Sdes if(match(words[w],"^Ar$")) { 287126274Sdes add("\\fI" words[++w] "\\fP") 288126274Sdes } else if(match(words[w],"^[\\.,]")) { 289126274Sdes sub(" $","",line) 290126274Sdes if(plain) { 291126274Sdes add("\\fP") 292126274Sdes plain=0 293126274Sdes } 294126274Sdes add(words[w]) 295126274Sdes } else { 296126274Sdes if(!plain) { 297126274Sdes add("\\fB") 298126274Sdes plain=1 299126274Sdes } 300126274Sdes add(words[w]) 301126274Sdes } 302126274Sdes if(!nospace) 303126274Sdes add(OFS) 304124208Sdes } 305124208Sdes sub(" $","",line) 306124208Sdes if(plain) 307126274Sdes add("\\fP") 308124208Sdes } else if(match(words[w],"^Bl$")) { 309124208Sdes oldoptlist=optlist 310124208Sdes if(match(words[w+1],"-bullet")) 311126274Sdes optlist=1 312124208Sdes else if(match(words[w+1],"-enum")) { 313126274Sdes optlist=2 314126274Sdes enum=0 315124208Sdes } else if(match(words[w+1],"-tag")) 316126274Sdes optlist=3 317124208Sdes else if(match(words[w+1],"-item")) 318126274Sdes optlist=4 319124208Sdes else if(match(words[w+1],"-bullet")) 320126274Sdes optlist=1 321124208Sdes w=nwords 322124208Sdes } else if(match(words[w],"^El$")) { 323124208Sdes optlist=oldoptlist 324137015Sdes } else if(match(words[w],"^Bk$")) { 325137015Sdes if(match(words[w+1],"-words")) { 326137015Sdes w++ 327137015Sdes breakw=1 328137015Sdes } 329137015Sdes } else if(match(words[w],"^Ek$")) { 330137015Sdes breakw=0 331124208Sdes } else if(match(words[w],"^It$")&&optlist) { 332124208Sdes if(optlist==1) 333126274Sdes add(".IP \\(bu") 334124208Sdes else if(optlist==2) 335126274Sdes add(".IP " ++enum ".") 336124208Sdes else if(optlist==3) { 337126274Sdes add(".TP") 338126274Sdes prenl++ 339137015Sdes if(match(words[w+1],"^Pa$|^Ev$")) { 340126274Sdes add(".B") 341126274Sdes w++ 342126274Sdes } 343124208Sdes } else if(optlist==4) 344126274Sdes add(".IP") 345124208Sdes } else if(match(words[w],"^Sm$")) { 346124208Sdes if(match(words[w+1],"off")) 347126274Sdes nospace=2 348124208Sdes else if(match(words[w+1],"on")) 349126274Sdes nospace=0 350124208Sdes w++ 351124208Sdes } else if(!skip) { 352124208Sdes add(words[w]) 353124208Sdes } 354124208Sdes } 355124208Sdes if(match(line,"^\\.[^a-zA-Z]")) 356124208Sdes sub("^\\.","",line) 357124208Sdes if(parens) 358124208Sdes add(")") 359124208Sdes if(angles) 360124208Sdes add(">") 361124208Sdes if(option) 362124208Sdes add("]") 363124208Sdes if(ext&&!extopt&&!match(line," $")) 364124208Sdes add(OFS) 365124208Sdes if(!ext&&!extopt&&length(line)) { 366124208Sdes print line 367124208Sdes prenl=0 368124208Sdes line="" 369124208Sdes } 370124208Sdes} 371