PageRenderTime 51ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/doc/mdoc2mediawiki.awk

https://code.google.com/
AWK | 445 lines | 390 code | 16 blank | 39 comment | 0 complexity | 237d5f528dc8ea7c86a009cf0bc6f8b7 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. listdepth = 0
  22. trailer = ""
  23. out = ""
  24. sep = ""
  25. nextsep = " "
  26. spaces = " "
  27. }
  28. # Add a word with appropriate preceding whitespace
  29. # Maintain a short queue of the expected upcoming word separators.
  30. function add(str) {
  31. out=out sep str
  32. sep = nextsep
  33. nextsep = " "
  34. }
  35. # Add a word with no following whitespace
  36. # Use for opening punctuation such as '('
  37. function addopen(str) {
  38. add(str)
  39. sep = ""
  40. }
  41. # Add a word with no preceding whitespace
  42. # Use for closing punctuation such as ')' or '.'
  43. function addclose(str) {
  44. sep = ""
  45. add(str)
  46. }
  47. # Add a word with no space before or after
  48. # Use for separating punctuation such as '='
  49. function addpunct(str) {
  50. sep = ""
  51. add(str)
  52. sep = ""
  53. }
  54. # Emit the current line so far
  55. function endline() {
  56. addclose(trailer)
  57. trailer = ""
  58. if(length(out) > 0) {
  59. print out
  60. out=""
  61. }
  62. if(displaylines > 0) {
  63. displaylines = displaylines - 1
  64. if (displaylines == 0)
  65. dispend()
  66. }
  67. # First word on next line has no preceding whitespace
  68. sep = ""
  69. }
  70. function linecmd(cmd) {
  71. endline()
  72. add(cmd)
  73. endline()
  74. }
  75. function breakline() {
  76. linecmd("<br>")
  77. }
  78. # Start an indented display
  79. function dispstart() {
  80. linecmd("<pre>")
  81. }
  82. # End an indented display
  83. function dispend() {
  84. linecmd("</pre>")
  85. }
  86. # Collect rest of input line
  87. function wtail() {
  88. retval=""
  89. while(w<nwords) {
  90. if(length(retval))
  91. retval=retval " "
  92. retval=retval words[++w]
  93. }
  94. return retval
  95. }
  96. function splitwords(l, dest, n, o, w) {
  97. n = 1
  98. delete dest
  99. while (length(l) > 0) {
  100. sub("^[ \t]*", "", l)
  101. if (match(l, "^\"")) {
  102. l = substr(l, 2)
  103. o = index(l, "\"")
  104. if (o > 0) {
  105. w = substr(l, 1, o-1)
  106. l = substr(l, o+1)
  107. dest[n++] = w
  108. } else {
  109. dest[n++] = l
  110. l = ""
  111. }
  112. } else {
  113. o = match(l, "[ \t]")
  114. if (o > 0) {
  115. w = substr(l, 1, o-1)
  116. l = substr(l, o+1)
  117. dest[n++] = w
  118. } else {
  119. dest[n++] = l
  120. l = ""
  121. }
  122. }
  123. }
  124. return n-1
  125. }
  126. ! /^\./ {
  127. out = $0 " "
  128. endline()
  129. next
  130. }
  131. /^\.\\"/ { next }
  132. {
  133. sub("^\\.","")
  134. nwords=splitwords($0, words)
  135. # TODO: Instead of iterating 'w' over the array, have a separate
  136. # function that returns 'next word' and use that. This will allow
  137. # proper handling of double-quoted arguments as well.
  138. for(w=1;w<=nwords;w++) {
  139. if(match(words[w],"^Li$")) { # Literal; rest of line is unformatted
  140. dispstart()
  141. displaylines = 1
  142. } else if(match(words[w],"^Dl$")) { # Display literal
  143. dispstart()
  144. displaylines = 1
  145. } else if(match(words[w],"^Bd$")) { # Begin display
  146. if(match(words[w+1],"-literal")) {
  147. dispstart()
  148. displaylines=10000
  149. w=nwords
  150. }
  151. } else if(match(words[w],"^Ed$")) { # End display
  152. displaylines = 0
  153. dispend()
  154. } else if(match(words[w],"^Ns$")) { # Suppress space before next word
  155. sep=""
  156. } else if(match(words[w],"^No$")) { # Normal text
  157. add(words[++w])
  158. } else if(match(words[w],"^Dq$")) { # Quote
  159. addopen("\"")
  160. add(words[++w])
  161. while(w<nwords&&!match(words[w+1],"^[\\.,]"))
  162. add(words[++w])
  163. addclose("\"")
  164. } else if(match(words[w],"^Do$")) {
  165. addopen("\"")
  166. } else if(match(words[w],"^Dc$")) {
  167. addclose("\"")
  168. } else if(match(words[w],"^Oo$")) {
  169. addopen("<nowiki>[</nowiki>")
  170. } else if(match(words[w],"^Oc$")) {
  171. addclose("<nowiki>]</nowiki>")
  172. } else if(match(words[w],"^Ao$")) {
  173. addopen("&lt;")
  174. } else if(match(words[w],"^Ac$")) {
  175. addclose("&gt;")
  176. } else if(match(words[w],"^Dd$")) {
  177. date=wtail()
  178. next
  179. } else if(match(words[w],"^Dt$")) {
  180. id=words[++w] "(" words[++w] ")"
  181. next
  182. } else if(match(words[w],"^Ox$")) {
  183. add("OpenBSD")
  184. } else if(match(words[w],"^Fx$")) {
  185. add("FreeBSD")
  186. } else if(match(words[w],"^Bx$")) {
  187. add("BSD")
  188. } else if(match(words[w],"^Nx$")) {
  189. add("NetBSD")
  190. } else if(match(words[w],"^St$")) {
  191. if (match(words[w+1], "^-p1003.1$")) {
  192. w++
  193. add("<nowiki>IEEE Std 1003.1 (``POSIX.1'')</nowiki>")
  194. } else if(match(words[w+1], "^-p1003.1-96$")) {
  195. w++
  196. add("<nowiki>ISO/IEC 9945-1:1996 (``POSIX.1'')</nowiki>")
  197. } else if(match(words[w+1], "^-p1003.1-88$")) {
  198. w++
  199. add("<nowiki>IEEE Std 1003.1-1988 (``POSIX.1'')</nowiki>")
  200. } else if(match(words[w+1], "^-p1003.1-2001$")) {
  201. w++
  202. add("<nowiki>IEEE Std 1003.1-2001 (``POSIX.1'')</nowiki>")
  203. } else if(match(words[w+1], "^-susv2$")) {
  204. w++
  205. add("<nowiki>Version 2 of the Single UNIX Specification (``SUSv2'')</nowiki>")
  206. }
  207. } else if(match(words[w],"^Ex$")) {
  208. if (match(words[w+1], "^-std$")) {
  209. w++
  210. add("The '''" name "''' utility exits 0 on success, and &gt;0 if an error occurs.")
  211. }
  212. } else if(match(words[w],"^Os$")) {
  213. add(id " manual page")
  214. } else if(match(words[w],"^Sh$")) {
  215. section=wtail()
  216. linecmd("== " section " ==")
  217. } else if(match(words[w],"^Xr$")) {
  218. add("'''" words[++w] "'''(" words[++w] ")" words[++w] " ")
  219. } else if(match(words[w],"^Nm$")) {
  220. if(match(section,"SYNOPSIS"))
  221. breakline()
  222. if(w >= nwords)
  223. n=name
  224. else if (match(words[w+1], "^[A-Z][a-z]$"))
  225. n=name
  226. else if (match(words[w+1], "^[.,;:]$"))
  227. n=name
  228. else {
  229. n=words[++w]
  230. if(!length(name))
  231. name=n
  232. }
  233. if(!length(n))
  234. n=name
  235. if (displaylines == 0)
  236. add("'''" n "'''")
  237. else
  238. add(n)
  239. } else if(match(words[w],"^Nd$")) {
  240. add("- " wtail())
  241. } else if(match(words[w],"^Fl$")) {
  242. addopen("-")
  243. } else if(match(words[w],"^Ar$")) {
  244. if(w==nwords)
  245. add("''file ...''" " ")
  246. else {
  247. ++w
  248. gsub("<", "&lt;", words[w])
  249. add("''" words[w] "''" " ")
  250. }
  251. } else if(match(words[w],"^Cm$")) {
  252. ++w
  253. if (displaylines == 0) {
  254. add("'''" words[w] "'''" " ")
  255. } else
  256. add(words[w])
  257. l = wtail()
  258. add(l " ")
  259. } else if(match(words[w],"^Op$")) {
  260. addopen("<nowiki>[</nowiki>")
  261. option=1
  262. trailer="<nowiki>]</nowiki>" trailer
  263. } else if(match(words[w],"^Pp$")) {
  264. ++w
  265. endline()
  266. print ""
  267. } else if(match(words[w],"^An$")) {
  268. if (match(words[w+1],"-nosplit"))
  269. ++w
  270. endline()
  271. } else if(match(words[w],"^Ss$")) {
  272. add("===")
  273. trailer="==="
  274. } else if(match(words[w],"^Ft$")) {
  275. if (match(section, "SYNOPSIS")) {
  276. breakline()
  277. }
  278. l = wtail()
  279. add("'''" l "'''")
  280. if (match(section, "SYNOPSIS")) {
  281. breakline()
  282. }
  283. } else if(match(words[w],"^Fn$")) {
  284. ++w
  285. F = "'''" words[w] "'''("
  286. Fsep = ""
  287. while(w<nwords) {
  288. ++w
  289. if (match(words[w], "^[.,:]$")) {
  290. --w
  291. break
  292. }
  293. F = F Fsep "''" words[w] "''"
  294. Fsep = ", "
  295. }
  296. add(F ")")
  297. if (match(section, "SYNOPSIS")) {
  298. addclose(";")
  299. }
  300. } else if(match(words[w],"^Fo$")) {
  301. w++
  302. F = "'''" words[w] "'''("
  303. Fsep = ""
  304. } else if(match(words[w],"^Fa$")) {
  305. w++
  306. F = F Fsep "''" words[w] "''"
  307. Fsep = ", "
  308. } else if(match(words[w],"^Fc$")) {
  309. add(F ")")
  310. if (match(section, "SYNOPSIS")) {
  311. addclose(";")
  312. }
  313. } else if(match(words[w],"^Va$")) {
  314. w++
  315. add("''" words[w] "''")
  316. } else if(match(words[w],"^In$")) {
  317. w++
  318. add("'''<nowiki>#include <" words[w] "></nowiki>'''")
  319. } else if(match(words[w],"^Pa$")) {
  320. w++
  321. # if(match(words[w],"^\\."))
  322. # add("\\&")
  323. if (displaylines == 0)
  324. add("''" words[w] "''")
  325. else
  326. add(words[w])
  327. } else if(match(words[w],"^Dv$")) {
  328. linecmd()
  329. l = wtail()
  330. add(l " ")
  331. } else if(match(words[w],"^Em|Ev$")) {
  332. add(".IR")
  333. } else if(match(words[w],"^Pq$")) {
  334. addopen("(")
  335. trailer=")" trailer
  336. } else if(match(words[w],"^Aq$")) {
  337. addopen(" &lt;")
  338. trailer="&gt;" trailer
  339. } else if(match(words[w],"^Brq$")) {
  340. addopen("<nowiki>{</nowiki>")
  341. trailer="<nowiki>}</nowiki>" trailer
  342. } else if(match(words[w],"^S[xy]$")) {
  343. add(".B " wtail())
  344. } else if(match(words[w],"^Tn$")) {
  345. n=wtail()
  346. add("'''" n "'''")
  347. } else if(match(words[w],"^Ic$")) {
  348. add("''")
  349. trailer="''" trailer
  350. } else if(match(words[w],"^Bl$")) {
  351. ++listdepth
  352. listnext[listdepth]=""
  353. if(match(words[w+1],"-bullet")) {
  354. optlist[listdepth]=1
  355. addopen("<ul>")
  356. listclose[listdepth]="</ul>"
  357. } else if(match(words[w+1],"-enum")) {
  358. optlist[listdepth]=2
  359. enum=0
  360. addopen("<ol>")
  361. listclose[listdepth]="</ol>"
  362. } else if(match(words[w+1],"-tag")) {
  363. optlist[listdepth]=3
  364. addopen("<dl>")
  365. listclose[listdepth]="</dl>"
  366. } else if(match(words[w+1],"-item")) {
  367. optlist[listdepth]=4
  368. addopen("<ul>")
  369. listclose[listdepth]="</ul>"
  370. }
  371. w=nwords
  372. } else if(match(words[w],"^El$")) {
  373. addclose(listnext[listdepth])
  374. addclose(listclose[listdepth])
  375. listclose[listdepth]=""
  376. listdepth--
  377. } else if(match(words[w],"^It$")) {
  378. addclose(listnext[listdepth])
  379. if(optlist[listdepth]==1) {
  380. addpunct("<li>")
  381. listnext[listdepth] = "</li>"
  382. } else if(optlist[listdepth]==2) {
  383. addpunct("<li>")
  384. listnext[listdepth] = "</li>"
  385. } else if(optlist[listdepth]==3) {
  386. addpunct("<dt>")
  387. listnext[listdepth] = "</dt>"
  388. if(match(words[w+1],"^Xo$")) {
  389. # Suppress trailer
  390. w++
  391. } else if(match(words[w+1],"^Pa$|^Ev$")) {
  392. addopen("'''")
  393. w++
  394. add(words[++w] "'''")
  395. } else {
  396. trailer = listnext[listdepth] "<dd>" trailer
  397. listnext[listdepth] = "</dd>"
  398. }
  399. } else if(optlist[listdepth]==4) {
  400. addpunct("<li>")
  401. listnext[listdepth] = "</li>"
  402. }
  403. } else if(match(words[w], "^Vt$")) {
  404. w++
  405. add("''" words[w] "''")
  406. } else if(match(words[w],"^Xo$")) {
  407. # TODO: Figure out how to handle this
  408. } else if(match(words[w],"^Xc$")) {
  409. # TODO: Figure out how to handle this
  410. if (optlist[listdepth] == 3) {
  411. addclose(listnext[listdepth])
  412. addopen("<dd>")
  413. listnext[listdepth] = "</dd>"
  414. }
  415. } else if(match(words[w],"^[=]$")) {
  416. addpunct(words[w])
  417. } else if(match(words[w],"^[[{(]$")) {
  418. addopen(words[w])
  419. } else if(match(words[w],"^[\\])}.,;:]$")) {
  420. addclose(words[w])
  421. } else {
  422. sub("\\\\&", "", words[w])
  423. add(words[w])
  424. }
  425. }
  426. if(match(out,"^\\.[^a-zA-Z]"))
  427. sub("^\\.","",out)
  428. endline()
  429. }