#!/usr/bin/env python3

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import sys
import re

# Converts a header file to restructured text documentation
#
# All text in /** */ comments becomes restructured text. Everything else is
# included as a code-block with C syntax highlighting.
#
# The beginning and end of the header are removed.
# - Find the first /** */ comment -> start of the documentation
# - Find the last line beginning with "#ifdef" -> end of the documentation

remove_keyword = [" UA_EXPORT", " UA_FUNC_ATTR_WARN_UNUSED_RESULT",
                  " UA_FUNC_ATTR_MALLOC", " UA_RESTRICT "]

def clean_comment(line):
    m = re.search(r"^\s*(\* |/\*\* )(.*?)( \*/)?$", line)
    if not m:
        return "\n"
    return m.group(2) + "\n"

def clean_line(line):
    for keyword in remove_keyword:
        line = line.replace(keyword, "")
    return line

def comment_start(line):
    m = re.search("^\\s*/\\*\\*[ \n]", line)
    if not m:
        return False
    return True

def comment_end(line):
    m = re.search(r" \*/$", line)
    if not m:
        return False
    return True

def first_line(c):
    "Searches for the first comment"
    for i in range(len(c)):
        if comment_start(c[i]):
            return i
    return -1

def last_line(c):
    "Searches for the latest ifdef (closing the include guard)"
    reg = re.compile("^#ifdef")
    for i in range(len(c)-1,1,-1):
        if "stop-doc-generation" in c[i]:
            return i
        if "_UA_END_DECLS" in c[i]:
            reg = re.compile("^_UA_END_DECLS")
    last = 1
    for i in range(len(c)-1,1,-1):
        m = reg.match(c[i])
        if m:
            last = i
            break
    # skip empty lines at the end
    for i in range(last-1,1,-1):
        if len(c[i].strip()) > 0:
            return i
    return len(c)-1

args = len(sys.argv)
if args < 3:
    print("Usage: python c2rst.py [input.c/h] output.rst")
    exit(0)

with open(sys.argv[args-1], 'w') as rst:
    for j in range(1,args-1):
        with open(sys.argv[j]) as f:
            c = f.readlines()
        in_doc = False
        last = last_line(c)
        for i in range(first_line(c), last+1):
            line = c[i]
            doc_start = False
            doc_end = False
            if in_doc:
                doc_end = comment_end(line)
                line = clean_comment(line)
            else:
                doc_start = comment_start(line)
                if doc_start:
                    doc_end = comment_end(line)
                    line = clean_comment(line)

            if doc_start:
                in_doc = True

            if not ((doc_start or doc_end) and line == "\n"):
                if not in_doc:
                    line = "   " + line
                rst.write(clean_line(line))

            if doc_end and i < last:
                rst.write("\n.. code-block:: c\n\n")
                in_doc = False
        rst.write("\n")
