#!/usr/bin/env python # 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("^\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(" \*/$", 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 "_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 if len(sys.argv) < 2: print("Usage: python c2rst.py input.c/h output.rst") exit(0) with open(sys.argv[1]) as f: c = f.readlines() with open(sys.argv[2], 'w') as rst: 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