#!/usr/bin/env python import sys, os, re, glob try: import io except ImportError: import cStringIO as io def usage(): sys.stdout.write( """usage: mdoc.py set group file [files...] Add the tag "\\ingroup group" to all the doxygen comment with a \\class tag in it. usage: mdoc.py check group file [files...] Check that the tag "\\ingroup group" is in all the doxygen comment with a \\class tag in it. If the tag is not there, a warning is displayed with the file name, the line number and the class name. The return value is 0 when all the doxygen comments have the tag, and 1 when at least one doxygen comment don't have it. usage: mdoc.py massive-set [ITK-source] Add the tag "\\ingroup module" to all the headers in ITK, where 'module' is the module name of the header. usage: mdoc.py massive-check [ITK-source] Check that all the headers in ITK have their module name in their \\ingroup tag. As for 'check', a warning is displayed if the tag is missing and 1 is returned. \n""" ) def setGroup(fname, group): # sys.stderr.write("Processing "+ fname +"\n") f = open(fname, "r", encoding="utf-8") out = io.StringIO() # load everything in memory fcontent = f.read() f.close() # now parse all the doxygen fields last = 0 for m in re.finditer(r"/\*\*(.*?)\*/", fcontent, re.DOTALL): # write what is before the doxygen field to the output out.write(fcontent[last : m.start(1)]) last = m.end(1) dcontent = m.group(1) # we don't care about doxygen fields not about a class if r"\class" in dcontent and dcontent != r" \class classname ": # do we have a line with the expected content? if re.search(r"\ingroup .*" + group + r"(\s|$)", dcontent, re.MULTILINE): # yes - just keep the content unchanged out.write(dcontent) else: # add the expected group if "\n" in dcontent: # this is a multiline content. Find the indent indent = re.search(r"( *)(\*|$)", dcontent).group(1) lastLine = dcontent.splitlines()[-1] if re.match(r"^ *$", lastLine): out.write(dcontent + "* \\ingroup " + group + "\n" + indent) else: out.write( dcontent.rstrip() + "\n" + indent + "* \\ingroup " + group + "\n" + indent ) else: out.write(dcontent + " \\ingroup " + group + " ") else: out.write(dcontent) out.write(fcontent[last:]) # we can save the content to the original file f = open(fname, "w", encoding="utf-8") f.write(out.getvalue()) f.close() def checkGroup(fname, group): # sys.stderr.write("Checking"+ fname + "\n") f = open(fname, "r", encoding="utf-8") # load everything in memory fcontent = f.read() f.close() # now parse all the doxygen fields ret = 0 for m in re.finditer(r"/\*\*(.*?)\*/", fcontent, re.DOTALL): dcontent = m.group(1) # we don't care about doxygen fields not about a class if r"\class" in dcontent and dcontent != r" \class classname ": # do we have a line with the expected content? if not re.search( r"\\ingroup .*" + group + r"(\s|$)", dcontent, re.MULTILINE ): # get class name and the line for debug output cname = re.search(r"\\class +([^ ]*)", dcontent).group(1).strip() line = len(fcontent[: m.start(1)].splitlines()) sys.stderr.write( r'%s:%s: error: "\ingroup %s" not set in class %s.' % (fname, line, group, cname) + "\n" ) ret = 1 return ret def main(): # first arg is the command command = sys.argv[1] if command == "set": if len(sys.argv) < 4: usage() return 1 # second arg is the module name, and the rest are the files to process module = sys.argv[2] files = sys.argv[3:] for fname in files: setGroup(fname, module) return 0 elif command == "massive-set": if len(sys.argv) < 2: usage() return 1 if len(sys.argv) >= 3: d = sys.argv[2] else: d = sys.path[0] + "/../.." cmm = os.path.abspath(d + "/*/*/*/itk-module.cmake") for fname in glob.glob(cmm): f = file(fname, "r", encoding="utf-8") mcontent = f.read() f.close() module = re.search(r"itk_module\(([^ )]+)", mcontent).group(1) dname = os.path.dirname(fname) for fname2 in glob.glob(dname + "/include/*.h"): setGroup(fname2, module) return 0 elif command == "check": if len(sys.argv) < 4: usage() return 1 # second arg is the module name, and the rest are the files to process module = sys.argv[2] files = sys.argv[3:] ret = 0 count = 0 for fname in files: if os.path.isdir(fname): for fname2 in glob.glob(fname + "/*.h"): count += 1 ret = max(ret, checkGroup(fname2, module)) else: count += 1 ret = max(ret, checkGroup(fname, module)) sys.stderr.write(str(count) + " headers checked." + "\n") return ret elif command == "massive-check": if len(sys.argv) < 2: usage() return 1 if len(sys.argv) >= 3: d = sys.argv[2] else: d = sys.path[0] + "/../.." cmm = os.path.abspath(d + "/*/*/*/itk-module.cmake") ret = 0 count = 0 for fname in glob.glob(cmm): f = file(fname, "r", encoding="utf-8") mcontent = f.read() f.close() module = re.search(r"itk_module\(([^ )]+)", mcontent).group(1) dname = os.path.dirname(fname) for fname2 in glob.glob(dname + "/include/*.h"): count += 1 ret = max(ret, checkGroup(fname2, module)) sys.stderr.write(str(count) + " headers checked." + "\n") return ret else: sys.stderr.write("Unknown command" + command + "\n") usage() return 1 if __name__ == "__main__": ret = main() sys.exit(ret)