man """ & manword & """
""", keyword = keyword)
proc doLocal(man, path: string) =
# Note: we intentionally do not use -l, because it is not supported on
# various systems (at the very least FreeBSD, NetBSD).
let cmd = "MANCOLOR=1 GROFF_NO_SGR=1 MAN_KEEP_FORMATTING=1 " &
man & ' ' & quoteShellPosix(path)
let (ofile, efile) = myOpen(cmd)
if ofile == nil:
stdout.write("Cha-Control: ConnectionError 1 failed to run " & cmd)
quit(1)
ofile.processManpage(efile, header = """Content-Type: text/html
man -l """ & path & """
""", keyword = path.afterLast('/').until('.'))
proc doKeyword(man, keyword, section: string) =
let sectionOpt = if section == "": "" else: " -s " & quoteShellPosix(section)
let cmd = man & sectionOpt & " -k " & quoteShellPosix(keyword)
let (ofile, efile) = myOpen(cmd)
if ofile == nil:
stdout.write("Cha-Control: ConnectionError 1 failed to run " & cmd)
quit(1)
var line: string
if not ofile.readLine(line) or ofile.endOfFile():
stdout.write("Cha-Control: ConnectionError 4 " & efile.readErrorMsg(line))
ofile.close()
efile.close()
quit(1)
stdout.write("Content-Type: text/html\n\n")
stdout.write("man" & sectionOpt & " -k " & keyword & "\n")
stdout.write("man" & sectionOpt & " -k " & keyword & "
\n")
stdout.write("
")
template die =
stdout.write("Error parsing line! " & line)
quit(1)
while true:
if line.len == 0:
stdout.write("\n")
if not ofile.readLine(line):
break
continue
# collect titles
var titles: seq[string] = @[]
var i = 0
while true:
let title = line.until({'(', ','}, i)
i += title.len
titles.add(title)
if i >= line.len or line[i] == '(':
break
i = line.skipBlanks(i + 1)
# collect section
if line[i] != '(': die
let sectionText = line.substr(i, line.find(')', i))
i += sectionText.len
# create line
var section = sectionText.until(',') # for multiple sections, take first
if section[^1] != ')':
section &= ')'
var s = "- "
for i, title in titles:
let title = title.htmlEscape()
s &= "" & title & ""
if i < titles.high:
s &= ", "
s &= sectionText
s &= line.substr(i)
s &= "\n"
stdout.write(s)
if not ofile.readLine(line):
break
ofile.close()
efile.close()
proc main() =
var man = getEnv("MANCHA_MAN")
if man == "":
block notfound:
for s in ["/usr/bin/man", "/bin/man", "/usr/local/bin/man"]:
if fileExists(s) or symlinkExists(s):
man = s
break notfound
man = "/usr/bin/env man"
var apropos = getEnv("MANCHA_APROPOS")
if apropos == "":
# on most systems, man is compatible with apropos (using -s syntax for
# specifying sections).
# ...not on FreeBSD :( here we have -S and MANSECT for specifying man
# sections, and both are silently ignored when searching with -k. hooray.
when not defined(freebsd):
apropos = man
else:
apropos = "/usr/bin/apropos" # this is where it should be.
let path = getEnv("MAPPED_URI_PATH")
let scheme = getEnv("MAPPED_URI_SCHEME")
if scheme == "man":
let (keyword, section) = parseSection(path)
doMan(man, keyword, section)
elif scheme == "man-k":
let (keyword, section) = parseSection(path)
doKeyword(apropos, keyword, section)
elif scheme == "man-l":
doLocal(man, path)
else:
stdout.write("Cha-Control: ConnectionError 1 invalid scheme")
main()