PageRenderTime 100ms CodeModel.GetById 14ms RepoModel.GetById 2ms app.codeStats 0ms

/doc/mdoc2man.awk

https://code.google.com/
AWK | 391 lines | 339 code | 16 blank | 36 comment | 0 complexity | b971e5a23acdb8899e37f4809450448a MD5 | raw file
Possible License(s): LGPL-2.0
  1. #!/usr/bin/awk
  2. #
  3. # Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org>
  4. #
  5. # Permission to use, copy, modify, and distribute this software for any
  6. # purpose with or without fee is hereby granted, provided that the above
  7. # copyright notice and this permission notice appear in all copies.
  8. #
  9. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. # Dramatically overhauled by Tim Kientzle. This version almost
  17. # handles library-style pages with Fn, Ft, etc commands. Still
  18. # a lot of problems...
  19. BEGIN {
  20. displaylines = 0
  21. trailer = ""
  22. out = ""
  23. sep = ""
  24. nextsep = " "
  25. }
  26. # Add a word with appropriate preceding whitespace
  27. # Maintain a short queue of the expected upcoming word separators.
  28. function add(str) {
  29. out=out sep str
  30. sep = nextsep
  31. nextsep = " "
  32. }
  33. # Add a word with no following whitespace
  34. # Use for opening punctuation such as '('
  35. function addopen(str) {
  36. add(str)
  37. sep = ""
  38. }
  39. # Add a word with no preceding whitespace
  40. # Use for closing punctuation such as ')' or '.'
  41. function addclose(str) {
  42. sep = ""
  43. add(str)
  44. }
  45. # Add a word with no space before or after
  46. # Use for separating punctuation such as '='
  47. function addpunct(str) {
  48. sep = ""
  49. add(str)
  50. sep = ""
  51. }
  52. # Emit the current line so far
  53. function endline() {
  54. addclose(trailer)
  55. trailer = ""
  56. if(length(out) > 0) {
  57. print out
  58. out=""
  59. }
  60. if(displaylines > 0) {
  61. displaylines = displaylines - 1
  62. if (displaylines == 0)
  63. dispend()
  64. }
  65. # First word on next line has no preceding whitespace
  66. sep = ""
  67. }
  68. function linecmd(cmd) {
  69. endline()
  70. add(cmd)
  71. endline()
  72. }
  73. function breakline() {
  74. linecmd(".br")
  75. }
  76. # Start an indented display
  77. function dispstart() {
  78. linecmd(".RS 4")
  79. }
  80. # End an indented display
  81. function dispend() {
  82. linecmd(".RE")
  83. }
  84. # Collect rest of input line
  85. function wtail() {
  86. retval=""
  87. while(w<nwords) {
  88. if(length(retval))
  89. retval=retval " "
  90. retval=retval words[++w]
  91. }
  92. return retval
  93. }
  94. function splitwords(l, dest, n, o, w) {
  95. n = 1
  96. delete dest
  97. while (length(l) > 0) {
  98. sub("^[ \t]*", "", l)
  99. if (match(l, "^\"")) {
  100. l = substr(l, 2)
  101. o = index(l, "\"")
  102. if (o > 0) {
  103. w = substr(l, 1, o-1)
  104. l = substr(l, o+1)
  105. dest[n++] = w
  106. } else {
  107. dest[n++] = l
  108. l = ""
  109. }
  110. } else {
  111. o = match(l, "[ \t]")
  112. if (o > 0) {
  113. w = substr(l, 1, o-1)
  114. l = substr(l, o+1)
  115. dest[n++] = w
  116. } else {
  117. dest[n++] = l
  118. l = ""
  119. }
  120. }
  121. }
  122. return n-1
  123. }
  124. ! /^\./ {
  125. out = $0
  126. endline()
  127. next
  128. }
  129. /^\.\\"/ { next }
  130. {
  131. sub("^\\.","")
  132. nwords=splitwords($0, words)
  133. # TODO: Instead of iterating 'w' over the array, have a separate
  134. # function that returns 'next word' and use that. This will allow
  135. # proper handling of double-quoted arguments as well.
  136. for(w=1;w<=nwords;w++) {
  137. if(match(words[w],"^Li$")) { # Literal; rest of line is unformatted
  138. dispstart()
  139. displaylines = 1
  140. } else if(match(words[w],"^Dl$")) { # Display literal
  141. dispstart()
  142. displaylines = 1
  143. } else if(match(words[w],"^Bd$")) { # Begin display
  144. if(match(words[w+1],"-literal")) {
  145. dispstart()
  146. linecmd(".nf")
  147. displaylines=10000
  148. w=nwords
  149. }
  150. } else if(match(words[w],"^Ed$")) { # End display
  151. displaylines = 0
  152. dispend()
  153. } else if(match(words[w],"^Ns$")) { # Suppress space after next word
  154. nextsep = ""
  155. } else if(match(words[w],"^No$")) { # Normal text
  156. add(words[++w])
  157. } else if(match(words[w],"^Dq$")) { # Quote
  158. addopen("``")
  159. add(words[++w])
  160. while(w<nwords&&!match(words[w+1],"^[\\.,]"))
  161. add(words[++w])
  162. addclose("''")
  163. } else if(match(words[w],"^Do$")) {
  164. addopen("``")
  165. } else if(match(words[w],"^Dc$")) {
  166. addclose("''")
  167. } else if(match(words[w],"^Oo$")) {
  168. addopen("[")
  169. } else if(match(words[w],"^Oc$")) {
  170. addclose("]")
  171. } else if(match(words[w],"^Ao$")) {
  172. addopen("<")
  173. } else if(match(words[w],"^Ac$")) {
  174. addclose(">")
  175. } else if(match(words[w],"^Dd$")) {
  176. date=wtail()
  177. next
  178. } else if(match(words[w],"^Dt$")) {
  179. id=wtail()
  180. next
  181. } else if(match(words[w],"^Ox$")) {
  182. add("OpenBSD")
  183. } else if(match(words[w],"^Fx$")) {
  184. add("FreeBSD")
  185. } else if(match(words[w],"^Nx$")) {
  186. add("NetBSD")
  187. } else if(match(words[w],"^St$")) {
  188. if (match(words[w+1], "^-p1003.1$")) {
  189. w++
  190. add("IEEE Std 1003.1 (``POSIX.1'')")
  191. } else if(match(words[w+1], "^-p1003.1-96$")) {
  192. w++
  193. add("ISO/IEC 9945-1:1996 (``POSIX.1'')")
  194. } else if(match(words[w+1], "^-p1003.1-88$")) {
  195. w++
  196. add("IEEE Std 1003.1-1988 (``POSIX.1'')")
  197. } else if(match(words[w+1], "^-p1003.1-2001$")) {
  198. w++
  199. add("IEEE Std 1003.1-2001 (``POSIX.1'')")
  200. } else if(match(words[w+1], "^-susv2$")) {
  201. w++
  202. add("Version 2 of the Single UNIX Specification (``SUSv2'')")
  203. }
  204. } else if(match(words[w],"^Ex$")) {
  205. if (match(words[w+1], "^-std$")) {
  206. w++
  207. add("The \\fB" name "\\fP utility exits 0 on success, and >0 if an error occurs.")
  208. }
  209. } else if(match(words[w],"^Os$")) {
  210. add(".TH " id " \"" date "\" \"" wtail() "\"")
  211. } else if(match(words[w],"^Sh$")) {
  212. section=wtail()
  213. add(".SH " section)
  214. linecmd(".ad l")
  215. } else if(match(words[w],"^Xr$")) {
  216. add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w])
  217. } else if(match(words[w],"^Nm$")) {
  218. if(match(section,"SYNOPSIS"))
  219. breakline()
  220. if(w >= nwords)
  221. n=name
  222. else if (match(words[w+1], "^[A-Z][a-z]$"))
  223. n=name
  224. else if (match(words[w+1], "^[.,;:]$"))
  225. n=name
  226. else {
  227. n=words[++w]
  228. if(!length(name))
  229. name=n
  230. }
  231. if(!length(n))
  232. n=name
  233. add("\\fB\\%" n "\\fP")
  234. } else if(match(words[w],"^Nd$")) {
  235. add("\\- " wtail())
  236. } else if(match(words[w],"^Fl$")) {
  237. add("\\fB\\-" words[++w] "\\fP")
  238. } else if(match(words[w],"^Ar$")) {
  239. addopen("\\fI")
  240. if(w==nwords)
  241. add("file ...\\fP")
  242. else
  243. add(words[++w] "\\fP")
  244. } else if(match(words[w],"^Cm$")) {
  245. add("\\fB" words[++w] "\\fP")
  246. } else if(match(words[w],"^Op$")) {
  247. addopen("[")
  248. option=1
  249. trailer="]" trailer
  250. } else if(match(words[w],"^Pp$")) {
  251. linecmd(".PP")
  252. } else if(match(words[w],"^An$")) {
  253. endline()
  254. } else if(match(words[w],"^Ss$")) {
  255. add(".SS")
  256. } else if(match(words[w],"^Ft$")) {
  257. if (match(section, "SYNOPSIS")) {
  258. breakline()
  259. }
  260. add("\\fI" wtail() "\\fP")
  261. if (match(section, "SYNOPSIS")) {
  262. breakline()
  263. }
  264. } else if(match(words[w],"^Fn$")) {
  265. ++w
  266. F = "\\fB\\%" words[w] "\\fP("
  267. Fsep = ""
  268. while(w<nwords) {
  269. ++w
  270. if (match(words[w], "^[.,:]$")) {
  271. --w
  272. break
  273. }
  274. gsub(" ", "\\ ", words[w])
  275. F = F Fsep "\\fI\\%" words[w] "\\fP"
  276. Fsep = ", "
  277. }
  278. add(F ")")
  279. if (match(section, "SYNOPSIS")) {
  280. addclose(";")
  281. }
  282. } else if(match(words[w],"^Fo$")) {
  283. w++
  284. F = "\\fB\\%" words[w] "\\fP("
  285. Fsep = ""
  286. } else if(match(words[w],"^Fa$")) {
  287. w++
  288. gsub(" ", "\\ ", words[w])
  289. F = F Fsep "\\fI\\%" words[w] "\\fP"
  290. Fsep = ", "
  291. } else if(match(words[w],"^Fc$")) {
  292. add(F ")")
  293. if (match(section, "SYNOPSIS")) {
  294. addclose(";")
  295. }
  296. } else if(match(words[w],"^Va$")) {
  297. w++
  298. add("\\fI" words[w] "\\fP")
  299. } else if(match(words[w],"^In$")) {
  300. w++
  301. add("\\fB#include <" words[w] ">\\fP")
  302. } else if(match(words[w],"^Pa$")) {
  303. addopen("\\fI")
  304. w++
  305. if(match(words[w],"^\\."))
  306. add("\\&")
  307. add(words[w] "\\fP")
  308. } else if(match(words[w],"^Dv$")) {
  309. add(".BR")
  310. } else if(match(words[w],"^Em|Ev$")) {
  311. add(".IR")
  312. } else if(match(words[w],"^Pq$")) {
  313. addopen("(")
  314. trailer=")" trailer
  315. } else if(match(words[w],"^Aq$")) {
  316. addopen("\\%<")
  317. trailer=">" trailer
  318. } else if(match(words[w],"^Brq$")) {
  319. addopen("{")
  320. trailer="}" trailer
  321. } else if(match(words[w],"^S[xy]$")) {
  322. add(".B " wtail())
  323. } else if(match(words[w],"^Ic$")) {
  324. add("\\fB")
  325. trailer="\\fP" trailer
  326. } else if(match(words[w],"^Bl$")) {
  327. oldoptlist=optlist
  328. linecmd(".RS 5")
  329. if(match(words[w+1],"-bullet"))
  330. optlist=1
  331. else if(match(words[w+1],"-enum")) {
  332. optlist=2
  333. enum=0
  334. } else if(match(words[w+1],"-tag"))
  335. optlist=3
  336. else if(match(words[w+1],"-item"))
  337. optlist=4
  338. else if(match(words[w+1],"-bullet"))
  339. optlist=1
  340. w=nwords
  341. } else if(match(words[w],"^El$")) {
  342. linecmd(".RE")
  343. optlist=oldoptlist
  344. } else if(match(words[w],"^It$")&&optlist) {
  345. if(optlist==1)
  346. add(".IP \\(bu")
  347. else if(optlist==2)
  348. add(".IP " ++enum ".")
  349. else if(optlist==3) {
  350. add(".TP")
  351. endline()
  352. if(match(words[w+1],"^Pa$|^Ev$")) {
  353. add(".B")
  354. w++
  355. }
  356. } else if(optlist==4)
  357. add(".IP")
  358. } else if(match(words[w],"^Xo$")) {
  359. # TODO: Figure out how to handle this
  360. } else if(match(words[w],"^Xc$")) {
  361. # TODO: Figure out how to handle this
  362. } else if(match(words[w],"^[=]$")) {
  363. addpunct(words[w])
  364. } else if(match(words[w],"^[[{(]$")) {
  365. addopen(words[w])
  366. } else if(match(words[w],"^[\\])}.,;:]$")) {
  367. addclose(words[w])
  368. } else {
  369. add(words[w])
  370. }
  371. }
  372. if(match(out,"^\\.[^a-zA-Z]"))
  373. sub("^\\.","",out)
  374. endline()
  375. }