c2rst.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #!/usr/bin/env python
  2. # This Source Code Form is subject to the terms of the Mozilla Public
  3. # License, v. 2.0. If a copy of the MPL was not distributed with this
  4. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  5. import sys
  6. import re
  7. # Converts a header file to restructured text documentation
  8. #
  9. # All text in /** */ comments becomes restructured text. Everything else is
  10. # included as a code-block with C syntax highlighting.
  11. #
  12. # The beginning and end of the header are removed.
  13. # - Find the first /** */ comment -> start of the documentation
  14. # - Find the last line beginning with "#ifdef" -> end of the documentation
  15. remove_keyword = [" UA_EXPORT", " UA_FUNC_ATTR_WARN_UNUSED_RESULT",
  16. " UA_FUNC_ATTR_MALLOC", " UA_RESTRICT "]
  17. def clean_comment(line):
  18. m = re.search("^\s*(\* |/\*\* )(.*?)( \*/)?$", line)
  19. if not m:
  20. return "\n"
  21. return m.group(2) + "\n"
  22. def clean_line(line):
  23. for keyword in remove_keyword:
  24. line = line.replace(keyword, "")
  25. return line
  26. def comment_start(line):
  27. m = re.search("^\s*/\*\*[ \n]", line)
  28. if not m:
  29. return False
  30. return True
  31. def comment_end(line):
  32. m = re.search(" \*/$", line)
  33. if not m:
  34. return False
  35. return True
  36. def first_line(c):
  37. "Searches for the first comment"
  38. for i in range(len(c)):
  39. if comment_start(c[i]):
  40. return i
  41. return -1
  42. def last_line(c):
  43. "Searches for the latest ifdef (closing the include guard)"
  44. reg = re.compile("^#ifdef")
  45. for i in range(len(c)-1,1,-1):
  46. if "_UA_END_DECLS" in c[i]:
  47. reg = re.compile("^_UA_END_DECLS")
  48. last = 1
  49. for i in range(len(c)-1,1,-1):
  50. m = reg.match(c[i])
  51. if m:
  52. last = i
  53. break
  54. # skip empty lines at the end
  55. for i in range(last-1,1,-1):
  56. if len(c[i].strip()) > 0:
  57. return i
  58. return len(c)-1
  59. if len(sys.argv) < 2:
  60. print("Usage: python c2rst.py input.c/h output.rst")
  61. exit(0)
  62. with open(sys.argv[1]) as f:
  63. c = f.readlines()
  64. with open(sys.argv[2], 'w') as rst:
  65. in_doc = False
  66. last = last_line(c)
  67. for i in range(first_line(c), last+1):
  68. line = c[i]
  69. doc_start = False
  70. doc_end = False
  71. if in_doc:
  72. doc_end = comment_end(line)
  73. line = clean_comment(line)
  74. else:
  75. doc_start = comment_start(line)
  76. if doc_start:
  77. doc_end = comment_end(line)
  78. line = clean_comment(line)
  79. if doc_start:
  80. in_doc = True
  81. if not ((doc_start or doc_end) and line == "\n"):
  82. if not in_doc:
  83. line = " " + line
  84. rst.write(clean_line(line))
  85. if doc_end and i < last:
  86. rst.write("\n.. code-block:: c\n\n")
  87. in_doc = False