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