#!/usr/bin/mawk -f
# md2man based on txt2man-1.5
# Copyright (C) 2001, 2002, 2003 Marc Vertes
# Licensed under GPL v2
#
# md2man version: very raw alpha
#
# fixes:
# v mawk compatible
# v setex-styled headers
# v asciidoc-alike subheaders (starting with ".")

function reset_section() {
    ls = 0          # line start index
    pls = 0         # previous line start index
    pnzls = 0       # previous non zero line start index

    ni = 0          # indent level
    ind[0] = 0      # indent offset table

    prevblankline = 0

    text=""
}

function process_section( header ) {
    if ((in_bd + 0) == 1) {
        in_bd = 0
        print ".fam T\n.fi"
    }
    if (section == "SYNOPSIS") {
        print ".fam T\n.fi"
        type["SYNOPSIS"] = ""
    }
    if (header ~/^[^ ]/)
        print ".SH " header
    else
        print ".SS" header
    sub(/^ +/, "")
    section = header
    if (section == "SYNOPSIS")
        print ".nf\n.fam C"

    reset_section()
}

BEGIN {
    print ".\\\" Text automatically generated by md2man "

    "uname -s" | getline source
    manual = source " Reference Manual"
    title = title ? title : ARGV[1]; sub(".*/","",title); sub("\\.md$","",title)
    section = title; sub(".*\\.","",section); sub("\\..*","",title)
    "LC_ALL=C.UTF-8 date -u +'%B %d, %Y'" | getline date
    print ".TH " title " " section " \"" date "\" \"" source "\" \"" manual "\""

    word="[0-9a-zA-Z_]+"
    reset_section()
}

# comment
/^#/ { next }

{
    # to avoid some side effects in regexp
    sub(/\.\.\./, "\\.\\.\\.")
    # remove spaces in empty lines
    sub(/^ +$/,"")
}

# setex-style header
text && /^=+$/ { process_section( toupper(text) ); next }
text && /^-+$/ { process_section( toupper(text) ); next }

# Section header
/^[A-Z][A-Z ]+$/ { process_section( $0 ); next }
# asciidoc-alike subheader
/^\.[a-zA-Z]/ { process_section( " " substr($0,2) ); next }

{
    # Compute line start index, handle start of example display block
    pls = ls
    if (ls != 0)
        pnzls = ls
    match($0, /[^ ]/)
    ls = RSTART
    # if (pls == 0 && pnzls > 0 && ls >= ( pnzls + 4 ) && $1 !~ /^[0-9\-\*\o]/) {
    if (pls == 0 && ls >= ( pls + 4 ) && $1 !~ /^[0-9\-\*\o]/) {
        # example display block
        if (prevblankline == 1) {
            print ".PP"
            prevblankline = 0
        }
        print ".nf\n.fam C"
        in_bd = 1
#        eoff = ls
    }
    if (ls > 0 && ind[0] == 0)
        ind[0] = ls
}
in_bd {
    # In example display block
    if (ls < 4) {
        # End of litteral display block
        in_bd = 0
        print ".fam T\n.fi"
    } else { print; next }
}

section == "NAME" && NF > 1 {
    $1 = "\\fB" $1
    sub(/ - /, " \\fP- ")
    print; next
}

section == "SYNOPSIS" && ! /^ *$/ {
    # Identify arguments of fcts and cmds
    if (type["SYNOPSIS"] == "") {
        if (index($0, "(") == 0 && index($0, ")") == 0 &&
            index($0, "#include") == 0)

            type["SYNOPSIS"] = "cmd"
        else
            type["SYNOPSIS"] = "fct"
    }
    if (type["SYNOPSIS"] == "cmd") {
        # Line is a command line
        if ($1 !~ /^\[/) {
            b = $1
            sub(/^\*/, "", b)
            subwords[b] = "\\fB" b "\\fP"
        }
        for (i = 2; i <= NF; i++) {
            a = $i
            gsub(/[\[\]\|]/, "", a)
            if (a ~ /^[^\-]/)
                subwords[a] = "\\fI" a "\\fP"
        }
    } else {
        # Line is a C function definition
        if ($1 == "typedef")
            subwords["\\<" $2 "\\>"] = "\\fI" $2 "\\fP"
        else if ($1 == "#define")
            subwords["\\<" $2 "\\>"] = "\\fI" $2 "\\fP"
        for (i = 1; i <= NF; i++) {
            if ($i ~ /[\,\)]/) {
                a = $i
                sub(/.*\(/, "", a)
                gsub(/\W/, "", a)
                if (a !~ /^void$/)
                    subwords["\\<" a "\\>"] = "\\fI" a "\\fP"
            }
        }
    }
}
{
    # protect dots inside words
    while ($0  ~ word "\\." word )
        sub(/\./, "~dOt~")
    
    # identify func calls and cross refs
    for (i = 1; i <= NF; i++) {
        b = $i
        sub(/^\*/, "", b)
        if ((a = index(b, ")(")) > 3) {
            w = substr(b, 3, a - 3)
            subwords[w] = "\\fI" w "\\fP"
        }
        if ((a = index(b, "(")) > 1) {
            w = substr(b, 1, a - 1)
            subwords[w "\\("] = "\\fB" w "\\fP("
        }
    }

    # terrible workaround for lack of mawk \B regexp
    # spaces are not preserved literally
    gsub(/  +/, " ~sp4ce~ ")
    for (i=1; i<=NF; i++) {
        # shell options
        if ($i ~ /^[^a-zA-Z0-9][-a-zA-Z0-9]/ )
            sub("-+[a-zA-Z][-a-zA-Z0-9_]*", "\\fB&\\fP", $i)
        # word attributes
        for (k in subwords)
            sub("[^-a-zA-Z0-9_]" k "|^" k, subwords[k], $i)
        # italic
        if ($i ~ "^_.*_$") $i = "\\fI" substr($i,2,length($i)-2) "\\fP"
        # bold
        if ($i ~ "^\\*.*\\*$") $i = "\\fB" substr($i,2,length($i)-2) "\\fP"
    }
    gsub(/~sp4ce~/, "  ")

    # unprotect dots inside words
    gsub(/~dOt~/, ".")

    # tag list item
    if (match($0, /[^ ]  +/) > 0) {
        if (text) { print text; text = "" }
        tag = substr($0, 1, RSTART)
        sub(/^ */, "", tag)
        if (RSTART+RLENGTH < length($0))
            $0 = substr($0, RSTART + RLENGTH)
        else
            $0 = ""
        print ".TP\n.B"
        print tag
        prevblankline = 0
        if (NF == 0)
            next

    # bullet list item
    } else if ($1 == "-"||$1 == "o"||$1 == "*") {
        if (text) { print text; text = "" }
        print ".IP \\(bu 3"
        prevblankline = 0
        $1 = ""

    # enum list item
    } else if ($1 ~ /^[0-9]+[\).]$/) {
        if (text) { print text; text = "" }
        print ".IP " $1 " 4"
        prevblankline = 0
        $1 = ""

    # new paragraph
    } else if (pls == 0) {
        if (section != "SYNOPSIS" || $0 ~ /^  ? ? ?/) sub(/ */,"")

        text = (text ? text " " : "") $0
        if (prevblankline == 1) {
            print ".PP"
            prevblankline = 0
        }
        next

    # blank line
    } else if (NF == 0) {
        if (text) { print text; text = "" }
        #if (prevblankline == 0) {
        #    print ".PP"
        #}
        prevblankline = 1
        next

    } else
        prevblankline = 0

    # flush vertical space
    if (prevblankline == 1) {
        print ".PP"
        prevblankline = 0
    }
    if (text) { print text; text = "" }
    if (section != "SYNOPSIS" || $0 ~ /^  ? ? ?/) sub(/ */,"")
    print
}

