1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
#!/usr/bin/env python3
from optparse import OptionParser
import glob
import io
import os
import re
import sys
def read_file(name, normalize=True):
""" Read a file. """
try:
with open(name, 'r', encoding='utf-8') as f:
# read the data
data = f.read()
if normalize:
# normalize line endings
data = data.replace("\r\n", "\n")
return data
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to read file ' + name + ': ' + strerror)
raise
def write_file(name, data):
""" Write a file. """
try:
with open(name, 'w', encoding='utf-8') as f:
# write the data
if sys.version_info.major == 2:
f.write(data.decode('utf-8'))
else:
f.write(data)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to write file ' + name + ': ' + strerror)
raise
def auto_check_header(file):
groups_to_check = []
data = read_file(file)
if not 'addon_auto_check' in data:
return ''
for line in io.StringIO(data):
line = re.search(r"^.*\/\/\/.*@copydetails *(.*)(_header|_source)_addon_auto_check.*", line, flags=re.UNICODE)
if line and line.group(1):
group = line.group(1)
if group in groups_to_check:
continue
print(' - Found use with %s' % group)
groups_to_check.append(line.group(1))
return groups_to_check
def parse_header(file, group, new_path=''):
header_sources = ''
header_addon = ''
source_addon = ''
data = read_file(file)
group_found = False
group_start = False
virtual_function_start = False
for line in io.StringIO(data):
if not group_found and 'defgroup ' + group in line:
group_found = True
continue
elif group_found and not group_start and '///@{' in line:
group_start = True
continue
elif group_start and '///@}' in line:
break
elif re.match(r'^.*//.*', line) or re.match(r'^.*//.*', line) or line == '\n' or not group_start:
continue
if re.match(r'^.*virtual.*', line):
virtual_function_start = True
if virtual_function_start:
header_sources += re.sub(r"^\s+", "", line, flags=re.UNICODE)
if virtual_function_start and re.match(r'^.*}.*', line):
virtual_function_start = False
if not group_found:
return ""
header_sources = header_sources.replace("\n", "")
header_sources = " ".join(re.split("\s+", header_sources, flags=re.UNICODE))
header_sources = header_sources.replace("}", "}\n")
header_sources = header_sources.replace("= 0;", "= 0;\n")
header_sources = header_sources.replace(",", ", ")
# Generate class header part of list
header_addon += '/// @defgroup ' + group + '_header_addon_auto_check Group header include\n'
header_addon += '/// @ingroup ' + group + '\n'
header_addon += '///@{\n'
header_addon += '/// *Header parts:*\n'
header_addon += '/// ~~~~~~~~~~~~~{.cpp}\n'
header_addon += '///\n'
for line in io.StringIO(header_sources):
line = re.search(r"^.*virtual.([A-Za-z1-9].*\(.*\))", line, flags=re.UNICODE)
if line:
header_addon += '/// ' + re.sub(' +', ' ', line.group(1)) + ' override;\n'
header_addon += '///\n'
header_addon += '/// ~~~~~~~~~~~~~\n'
header_addon += '///@}\n\n'
# Generate class source part of list
source_addon += '/// @defgroup ' + group + '_source_addon_auto_check Group source include\n'
source_addon += '/// @ingroup ' + group + '\n'
source_addon += '///@{\n'
source_addon += '/// *Source parts:*\n'
source_addon += '/// ~~~~~~~~~~~~~{.cpp}\n'
source_addon += '///\n'
for line in io.StringIO(header_sources):
line = line.replace("{", "\n{\n ")
line = line.replace("}", "\n}")
for line in io.StringIO(line + '\n'):
func = re.search(r"^.*(virtual *) *(.*) ([a-z|A-Z|0-9].*)(\(.*\))", line, flags=re.UNICODE)
if func:
source_addon += '/// ' + re.sub(' +', ' ', func.group(2) + ' CMyInstance::' + func.group(3) + func.group(4) + '\n')
else:
source_addon += '/// ' + line
if '= 0' in line:
source_addon += '/// {\n'
source_addon += '/// // Required in interface to have!\n'
source_addon += '/// // ...\n'
source_addon += '/// }\n'
source_addon += '/// ~~~~~~~~~~~~~\n'
source_addon += '///@}\n\n'
return header_addon + source_addon
def print_error(msg):
print('Error: %s\nSee --help for usage.' % msg)
# cannot be loaded as a module
if __name__ != "__main__":
sys.stderr.write('This file cannot be loaded as a module!')
sys.exit()
# parse command-line options
disc = """
This utility generate group list about addon header sources to add inside doxygen.
"""
parser = OptionParser(description=disc)
parser.add_option(
'--header-file',
dest='headerfile',
metavar='DIR',
help='the to checked header [required]')
parser.add_option(
'--doxygen-group',
dest='doxygengroup',
help='the to checked doxygen group inside header [required]')
(options, args) = parser.parse_args()
docs = ''
groups_to_check = []
# Check about use of helper docs
if options.doxygengroup is None:
print('Scaning about used places...')
headers = glob.glob("../include/kodi/**/*.h", recursive=True)
for header in headers:
group = auto_check_header(header)
if group:
groups_to_check += group
else:
groups_to_check.append(options.doxygengroup)
# Generate the helper docs
if options.headerfile is None:
headers = glob.glob("../include/kodi/**/*.h", recursive=True)
print('Parsing about docs:')
for header in headers:
print(' - %s' % header)
for group in groups_to_check:
docs += parse_header(header, group)
else:
for group in groups_to_check:
docs += parse_header(options.headerfile, group)
write_file("../include/groups.dox", docs)
|