Blame doc/mdoc2man.awk

Packit 08bd4c
#!/usr/bin/awk
Packit 08bd4c
#
Packit 08bd4c
# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org>
Packit 08bd4c
#
Packit 08bd4c
# Permission to use, copy, modify, and distribute this software for any
Packit 08bd4c
# purpose with or without fee is hereby granted, provided that the above
Packit 08bd4c
# copyright notice and this permission notice appear in all copies.
Packit 08bd4c
#
Packit 08bd4c
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Packit 08bd4c
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Packit 08bd4c
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Packit 08bd4c
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit 08bd4c
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Packit 08bd4c
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Packit 08bd4c
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Packit 08bd4c
Packit 08bd4c
# Dramatically overhauled by Tim Kientzle.  This version almost
Packit 08bd4c
# handles library-style pages with Fn, Ft, etc commands.  Still
Packit 08bd4c
# a lot of problems...
Packit 08bd4c
Packit 08bd4c
BEGIN {
Packit 08bd4c
  displaylines = 0
Packit 08bd4c
  trailer = ""
Packit 08bd4c
  out = ""
Packit 08bd4c
  sep = ""
Packit 08bd4c
  nextsep = " "
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# Add a word with appropriate preceding whitespace
Packit 08bd4c
# Maintain a short queue of the expected upcoming word separators.
Packit 08bd4c
function add(str) {
Packit 08bd4c
  out=out sep str
Packit 08bd4c
  sep = nextsep
Packit 08bd4c
  nextsep = " "
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# Add a word with no following whitespace
Packit 08bd4c
# Use for opening punctuation such as '('
Packit 08bd4c
function addopen(str) {
Packit 08bd4c
  add(str)
Packit 08bd4c
  sep = ""
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# Add a word with no preceding whitespace
Packit 08bd4c
# Use for closing punctuation such as ')' or '.'
Packit 08bd4c
function addclose(str) {
Packit 08bd4c
  sep = ""
Packit 08bd4c
  add(str)
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# Add a word with no space before or after
Packit 08bd4c
# Use for separating punctuation such as '='
Packit 08bd4c
function addpunct(str) {
Packit 08bd4c
  sep = ""
Packit 08bd4c
  add(str)
Packit 08bd4c
  sep = ""
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# Emit the current line so far
Packit 08bd4c
function endline() {
Packit 08bd4c
  addclose(trailer)
Packit 08bd4c
  trailer = ""
Packit 08bd4c
  if(length(out) > 0) {
Packit 08bd4c
    print out
Packit 08bd4c
    out=""
Packit 08bd4c
  }
Packit 08bd4c
  if(displaylines > 0) {
Packit 08bd4c
    displaylines = displaylines - 1
Packit 08bd4c
    if (displaylines == 0)
Packit 08bd4c
      dispend()
Packit 08bd4c
  }
Packit 08bd4c
  # First word on next line has no preceding whitespace
Packit 08bd4c
  sep = ""
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
function linecmd(cmd) {
Packit 08bd4c
  endline()
Packit 08bd4c
  add(cmd)
Packit 08bd4c
  endline()
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
function breakline() {
Packit 08bd4c
  linecmd(".br")
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# Start an indented display
Packit 08bd4c
function dispstart() {
Packit 08bd4c
  linecmd(".RS 4")
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# End an indented display
Packit 08bd4c
function dispend() {
Packit 08bd4c
  linecmd(".RE")
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
# Collect rest of input line
Packit 08bd4c
function wtail() {
Packit 08bd4c
  retval=""
Packit 08bd4c
  while(w
Packit 08bd4c
    if(length(retval))
Packit 08bd4c
      retval=retval " "
Packit 08bd4c
    retval=retval words[++w]
Packit 08bd4c
  }
Packit 08bd4c
  return retval
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
function splitwords(l, dest, n, o, w) {
Packit 08bd4c
  n = 1
Packit 08bd4c
  delete dest
Packit 08bd4c
  while (length(l) > 0) {
Packit 08bd4c
    sub("^[ \t]*", "", l)
Packit 08bd4c
    if (match(l, "^\"")) {
Packit 08bd4c
      l = substr(l, 2)
Packit 08bd4c
      o = index(l, "\"")
Packit 08bd4c
      if (o > 0) {
Packit 08bd4c
	w = substr(l, 1, o-1)
Packit 08bd4c
	l = substr(l, o+1)
Packit 08bd4c
	dest[n++] = w
Packit 08bd4c
      } else {
Packit 08bd4c
	dest[n++] = l
Packit 08bd4c
	l = ""
Packit 08bd4c
      }
Packit 08bd4c
    } else {
Packit 08bd4c
      o = match(l, "[ \t]")
Packit 08bd4c
      if (o > 0) {
Packit 08bd4c
	w = substr(l, 1, o-1)
Packit 08bd4c
	l = substr(l, o+1)
Packit 08bd4c
	dest[n++] = w
Packit 08bd4c
      } else {
Packit 08bd4c
	dest[n++] = l
Packit 08bd4c
	l = ""
Packit 08bd4c
      }
Packit 08bd4c
    }
Packit 08bd4c
  }
Packit 08bd4c
  return n-1
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
! /^\./ {
Packit 08bd4c
  out = $0
Packit 08bd4c
  endline()
Packit 08bd4c
  next
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/^\.\\"/ { next }
Packit 08bd4c
Packit 08bd4c
{
Packit 08bd4c
  sub("^\\.","")
Packit 08bd4c
  nwords=splitwords($0, words)
Packit 08bd4c
  # TODO: Instead of iterating 'w' over the array, have a separate
Packit 08bd4c
  # function that returns 'next word' and use that.  This will allow
Packit 08bd4c
  # proper handling of double-quoted arguments as well.
Packit 08bd4c
  for(w=1;w<=nwords;w++) {
Packit 08bd4c
    if(match(words[w],"^Li$")) { # Literal; rest of line is unformatted
Packit 08bd4c
      dispstart()
Packit 08bd4c
      displaylines = 1
Packit 08bd4c
    } else if(match(words[w],"^Dl$")) { # Display literal
Packit 08bd4c
      dispstart()
Packit 08bd4c
      displaylines = 1
Packit 08bd4c
    } else if(match(words[w],"^Bd$")) { # Begin display
Packit 08bd4c
      if(match(words[w+1],"-literal")) {
Packit 08bd4c
        dispstart()
Packit 08bd4c
	linecmd(".nf")
Packit 08bd4c
	displaylines=10000
Packit 08bd4c
	w=nwords
Packit 08bd4c
      }
Packit 08bd4c
    } else if(match(words[w],"^Ed$")) { # End display
Packit 08bd4c
      displaylines = 0
Packit 08bd4c
      dispend()
Packit 08bd4c
    } else if(match(words[w],"^Ns$")) { # Suppress space after next word
Packit 08bd4c
      nextsep = ""
Packit 08bd4c
    } else if(match(words[w],"^No$")) { # Normal text
Packit 08bd4c
      add(words[++w])
Packit 08bd4c
    } else if(match(words[w],"^Dq$")) { # Quote
Packit 08bd4c
      addopen("``")
Packit 08bd4c
      add(words[++w])
Packit 08bd4c
      while(w
Packit 08bd4c
	add(words[++w])
Packit 08bd4c
      addclose("''")
Packit 08bd4c
    } else if(match(words[w],"^Do$")) {
Packit 08bd4c
      addopen("``")
Packit 08bd4c
    } else if(match(words[w],"^Dc$")) {
Packit 08bd4c
      addclose("''")
Packit 08bd4c
    } else if(match(words[w],"^Oo$")) {
Packit 08bd4c
      addopen("[")
Packit 08bd4c
    } else if(match(words[w],"^Oc$")) {
Packit 08bd4c
      addclose("]")
Packit 08bd4c
    } else if(match(words[w],"^Ao$")) {
Packit 08bd4c
      addopen("<")
Packit 08bd4c
    } else if(match(words[w],"^Ac$")) {
Packit 08bd4c
      addclose(">")
Packit 08bd4c
    } else if(match(words[w],"^Dd$")) {
Packit 08bd4c
      date=wtail()
Packit 08bd4c
      next
Packit 08bd4c
    } else if(match(words[w],"^Dt$")) {
Packit 08bd4c
      id=wtail()
Packit 08bd4c
      next
Packit 08bd4c
    } else if(match(words[w],"^Ox$")) {
Packit 08bd4c
      add("OpenBSD")
Packit 08bd4c
    } else if(match(words[w],"^Fx$")) {
Packit 08bd4c
      add("FreeBSD")
Packit 08bd4c
    } else if(match(words[w],"^Nx$")) {
Packit 08bd4c
      add("NetBSD")
Packit 08bd4c
    } else if(match(words[w],"^St$")) {
Packit 08bd4c
      if (match(words[w+1], "^-p1003.1$")) {
Packit 08bd4c
         w++
Packit 08bd4c
         add("IEEE Std 1003.1 (``POSIX.1'')")
Packit 08bd4c
      } else if(match(words[w+1], "^-p1003.1-96$")) {
Packit 08bd4c
         w++
Packit 08bd4c
         add("ISO/IEC 9945-1:1996 (``POSIX.1'')")
Packit 08bd4c
      } else if(match(words[w+1], "^-p1003.1-88$")) {
Packit 08bd4c
         w++
Packit 08bd4c
         add("IEEE Std 1003.1-1988 (``POSIX.1'')")
Packit 08bd4c
      } else if(match(words[w+1], "^-p1003.1-2001$")) {
Packit 08bd4c
         w++
Packit 08bd4c
         add("IEEE Std 1003.1-2001 (``POSIX.1'')")
Packit 08bd4c
      } else if(match(words[w+1], "^-susv2$")) {
Packit 08bd4c
         w++
Packit 08bd4c
         add("Version 2 of the Single UNIX Specification (``SUSv2'')")
Packit 08bd4c
      }
Packit 08bd4c
    } else if(match(words[w],"^Ex$")) {
Packit 08bd4c
      if (match(words[w+1], "^-std$")) {
Packit 08bd4c
         w++
Packit 08bd4c
         add("The \\fB" name "\\fP utility exits 0 on success, and >0 if an error occurs.")
Packit 08bd4c
      }
Packit 08bd4c
    } else if(match(words[w],"^Os$")) {
Packit 08bd4c
      add(".TH " id " \"" date "\" \"" wtail() "\"")
Packit 08bd4c
    } else if(match(words[w],"^Sh$")) {
Packit 08bd4c
      section=wtail()
Packit 08bd4c
      add(".SH " section)
Packit 08bd4c
      linecmd(".ad l")
Packit 08bd4c
    } else if(match(words[w],"^Xr$")) {
Packit 08bd4c
      add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w])
Packit 08bd4c
    } else if(match(words[w],"^Nm$")) {
Packit 08bd4c
      if(match(section,"SYNOPSIS"))
Packit 08bd4c
        breakline()
Packit 08bd4c
      if(w >= nwords)
Packit 08bd4c
	n=name
Packit 08bd4c
      else if (match(words[w+1], "^[A-Z][a-z]$"))
Packit 08bd4c
	n=name
Packit 08bd4c
      else if (match(words[w+1], "^[.,;:]$"))
Packit 08bd4c
	n=name
Packit 08bd4c
      else {
Packit 08bd4c
        n=words[++w]
Packit 08bd4c
        if(!length(name))
Packit 08bd4c
          name=n
Packit 08bd4c
      }
Packit 08bd4c
      if(!length(n))
Packit 08bd4c
        n=name
Packit 08bd4c
      add("\\fB\\%" n "\\fP")
Packit 08bd4c
    } else if(match(words[w],"^Nd$")) {
Packit 08bd4c
      add("\\- " wtail())
Packit 08bd4c
    } else if(match(words[w],"^Fl$")) {
Packit 08bd4c
      add("\\fB\\-" words[++w] "\\fP")
Packit 08bd4c
    } else if(match(words[w],"^Ar$")) {
Packit 08bd4c
      addopen("\\fI")
Packit 08bd4c
      if(w==nwords)
Packit 08bd4c
	add("file ...\\fP")
Packit 08bd4c
      else
Packit 08bd4c
	add(words[++w] "\\fP")
Packit 08bd4c
    } else if(match(words[w],"^Cm$")) {
Packit 08bd4c
      add("\\fB" words[++w] "\\fP")
Packit 08bd4c
    } else if(match(words[w],"^Op$")) {
Packit 08bd4c
      addopen("[")
Packit 08bd4c
      option=1
Packit 08bd4c
      trailer="]" trailer
Packit 08bd4c
    } else if(match(words[w],"^Pp$")) {
Packit 08bd4c
      linecmd(".PP")
Packit 08bd4c
    } else if(match(words[w],"^An$")) {
Packit 08bd4c
      endline()
Packit 08bd4c
    } else if(match(words[w],"^Ss$")) {
Packit 08bd4c
      add(".SS")
Packit 08bd4c
    } else if(match(words[w],"^Ft$")) {
Packit 08bd4c
      if (match(section, "SYNOPSIS")) {
Packit 08bd4c
	breakline()
Packit 08bd4c
      }
Packit 08bd4c
      add("\\fI" wtail() "\\fP")
Packit 08bd4c
      if (match(section, "SYNOPSIS")) {
Packit 08bd4c
	breakline()
Packit 08bd4c
      }
Packit 08bd4c
    } else if(match(words[w],"^Fn$")) {
Packit 08bd4c
      ++w
Packit 08bd4c
      F = "\\fB\\%" words[w] "\\fP("
Packit 08bd4c
      Fsep = ""
Packit 08bd4c
      while(w
Packit 08bd4c
	++w
Packit 08bd4c
	if (match(words[w], "^[.,:]$")) {
Packit 08bd4c
	  --w
Packit 08bd4c
	  break
Packit 08bd4c
	}
Packit 08bd4c
	gsub(" ", "\\ ", words[w])
Packit 08bd4c
	F = F Fsep "\\fI\\%"  words[w] "\\fP"
Packit 08bd4c
	Fsep = ", "
Packit 08bd4c
      }
Packit 08bd4c
      add(F ")")
Packit 08bd4c
      if (match(section, "SYNOPSIS")) {
Packit 08bd4c
	addclose(";")
Packit 08bd4c
      }
Packit 08bd4c
    } else if(match(words[w],"^Fo$")) {
Packit 08bd4c
      w++
Packit 08bd4c
      F = "\\fB\\%" words[w] "\\fP("
Packit 08bd4c
      Fsep = ""
Packit 08bd4c
    } else if(match(words[w],"^Fa$")) {
Packit 08bd4c
      w++
Packit 08bd4c
      gsub(" ", "\\ ", words[w])
Packit 08bd4c
      F = F Fsep "\\fI\\%"  words[w] "\\fP"
Packit 08bd4c
      Fsep = ", "
Packit 08bd4c
    } else if(match(words[w],"^Fc$")) {
Packit 08bd4c
      add(F ")")
Packit 08bd4c
      if (match(section, "SYNOPSIS")) {
Packit 08bd4c
	addclose(";")
Packit 08bd4c
      }
Packit 08bd4c
    } else if(match(words[w],"^Va$")) {
Packit 08bd4c
      w++
Packit 08bd4c
      add("\\fI" words[w] "\\fP")
Packit 08bd4c
    } else if(match(words[w],"^In$")) {
Packit 08bd4c
      w++
Packit 08bd4c
      add("\\fB#include <" words[w] ">\\fP")
Packit 08bd4c
    } else if(match(words[w],"^Pa$")) {
Packit 08bd4c
      addopen("\\fI")
Packit 08bd4c
      w++
Packit 08bd4c
      if(match(words[w],"^\\."))
Packit 08bd4c
	add("\\&")
Packit 08bd4c
      add(words[w] "\\fP")
Packit 08bd4c
    } else if(match(words[w],"^Dv$")) {
Packit 08bd4c
      add(".BR")
Packit 08bd4c
    } else if(match(words[w],"^Em|Ev$")) {
Packit 08bd4c
      add(".IR")
Packit 08bd4c
    } else if(match(words[w],"^Pq$")) {
Packit 08bd4c
      addopen("(")
Packit 08bd4c
      trailer=")" trailer
Packit 08bd4c
    } else if(match(words[w],"^Aq$")) {
Packit 08bd4c
      addopen("\\%<")
Packit 08bd4c
      trailer=">" trailer
Packit 08bd4c
    } else if(match(words[w],"^Brq$")) {
Packit 08bd4c
      addopen("{")
Packit 08bd4c
      trailer="}" trailer
Packit 08bd4c
    } else if(match(words[w],"^S[xy]$")) {
Packit 08bd4c
      add(".B " wtail())
Packit 08bd4c
    } else if(match(words[w],"^Ic$")) {
Packit 08bd4c
      add("\\fB")
Packit 08bd4c
      trailer="\\fP" trailer
Packit 08bd4c
    } else if(match(words[w],"^Bl$")) {
Packit 08bd4c
      oldoptlist=optlist
Packit 08bd4c
      linecmd(".RS 5")
Packit 08bd4c
      if(match(words[w+1],"-bullet"))
Packit 08bd4c
	optlist=1
Packit 08bd4c
      else if(match(words[w+1],"-enum")) {
Packit 08bd4c
	optlist=2
Packit 08bd4c
	enum=0
Packit 08bd4c
      } else if(match(words[w+1],"-tag"))
Packit 08bd4c
	optlist=3
Packit 08bd4c
      else if(match(words[w+1],"-item"))
Packit 08bd4c
	optlist=4
Packit 08bd4c
      else if(match(words[w+1],"-bullet"))
Packit 08bd4c
	optlist=1
Packit 08bd4c
      w=nwords
Packit 08bd4c
    } else if(match(words[w],"^El$")) {
Packit 08bd4c
      linecmd(".RE")
Packit 08bd4c
      optlist=oldoptlist
Packit 08bd4c
    } else if(match(words[w],"^It$")&&optlist) {
Packit 08bd4c
      if(optlist==1)
Packit 08bd4c
	add(".IP \\(bu")
Packit 08bd4c
      else if(optlist==2)
Packit 08bd4c
	add(".IP " ++enum ".")
Packit 08bd4c
      else if(optlist==3) {
Packit 08bd4c
	add(".TP")
Packit 08bd4c
        endline()
Packit 08bd4c
	if(match(words[w+1],"^Pa$|^Ev$")) {
Packit 08bd4c
	  add(".B")
Packit 08bd4c
	  w++
Packit 08bd4c
	}
Packit 08bd4c
      } else if(optlist==4)
Packit 08bd4c
	add(".IP")
Packit 08bd4c
    } else if(match(words[w],"^Xo$")) {
Packit 08bd4c
      # TODO: Figure out how to handle this
Packit 08bd4c
    } else if(match(words[w],"^Xc$")) {
Packit 08bd4c
      # TODO: Figure out how to handle this
Packit 08bd4c
    } else if(match(words[w],"^[=]$")) {
Packit 08bd4c
      addpunct(words[w])
Packit 08bd4c
    } else if(match(words[w],"^[[{(]$")) {
Packit 08bd4c
      addopen(words[w])
Packit 08bd4c
    } else if(match(words[w],"^[\\])}.,;:]$")) {
Packit 08bd4c
      addclose(words[w])
Packit 08bd4c
    } else {
Packit 08bd4c
      add(words[w])
Packit 08bd4c
    }
Packit 08bd4c
  }
Packit 08bd4c
  if(match(out,"^\\.[^a-zA-Z]"))
Packit 08bd4c
    sub("^\\.","",out)
Packit 08bd4c
  endline()
Packit 08bd4c
}