doxyfilter-perl.py
Go to the documentation of this file.
00001 #! /sbia/sbiasfw/external/python/epd/7.3.1/bin/python 00002 import sys; import os.path; __dir__ = os.path.dirname(os.path.realpath(__file__)); sys.path.insert(0, os.path.realpath(os.path.join(__dir__, 'python'))); sys.path.insert(0, os.path.realpath(os.path.join(__dir__, '.'))) # <-- added by BASIS 00003 ############################################################################## 00004 # @file doxyfilter-perl.py 00005 # @brief Doxygen filter for Perl modules. 00006 # 00007 # Copyright (c) 2012 University of Pennsylvania. All rights reserved.<br /> 00008 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file. 00009 # 00010 # Contact: SBIA Group <sbia-software at uphs.upenn.edu> 00011 # 00012 # @ingroup Tools 00013 ############################################################################## 00014 00015 import sys 00016 import re 00017 00018 if __name__ == "__main__": 00019 # parse arguments 00020 if len(sys.argv) != 2: 00021 sys.stderr.write("No file specified to process!\n") 00022 sys.exit(1) 00023 fileName = sys.argv[1] 00024 # open input file 00025 f = open(fileName, 'r') 00026 if not f: 00027 sys.stderr.write("Failed to open file " + fileName + " for reading!\n") 00028 sys.exit(1) 00029 # compile regular expressions 00030 reShaBang = re.compile(r"#!\s*/usr/bin/env\s+perl$|#!\s*/usr/bin/perl$") 00031 reConstant = re.compile(r"use\s+constant\s+(?P<name>\w+)(\s+.*|;)?$") 00032 reInclude = re.compile(r"use\s+(?P<module>[a-zA-Z:]+)(\s+.*|;)?$") 00033 reFunctionStart = re.compile(r"sub\s*(?P<name1>\w+)\s*{?$") 00034 reFunctionEnd = re.compile(r"}$") 00035 reCommentStart = re.compile(r"##+(?P<comment>.*)$") 00036 reCommentLine = re.compile(r"#+(?P<comment>.*)$") 00037 reParamDoc = re.compile(r"[\@\\]param\s*(\[\s*(?P<inout>in|out|in\s*,\s*out|out\s*,\s*in)\s*\]|\s*)\s+(?P<type>[$%@]\$?)?(?P<param>\w+)") 00038 # parse line-by-line and output pseudo C++ code to stdout 00039 previousBlock = '' # name of previous code block 00040 currentBlock = '' # name of current code block 00041 params = [] 00042 for line in f: 00043 line = line.strip() 00044 # skip sha-bang directive 00045 if reShaBang.match(line) is not None: 00046 sys.stdout.write("\n") 00047 continue 00048 # next comment line, 00049 if currentBlock == 'comment': 00050 m = reCommentLine.match(line) 00051 if m is not None: 00052 comment = m.group('comment') 00053 m = reParamDoc.search(line) 00054 if m is not None: 00055 inout = m.group('inout') 00056 argtype = m.group('type') 00057 param = m.group('param') 00058 params.append([inout, argtype, param]) 00059 comment = comment.replace(argtype + param, param) 00060 sys.stdout.write("///" + comment + "\n") 00061 continue 00062 else: 00063 previousBlock = currentBlock 00064 currentBlock = '' 00065 # continue processing of this (yet unhandled) line 00066 # inside function definition 00067 if currentBlock == 'function': 00068 m = reFunctionEnd.match(line) 00069 if m is not None: 00070 previousBlock = currentBlock 00071 currentBlock = '' 00072 sys.stdout.write("\n") 00073 continue 00074 # look for new comment block or block following a comment 00075 if currentBlock == '': 00076 # constant - before include match 00077 m = reConstant.match(line) 00078 if m is not None: 00079 name = m.group('name') 00080 sys.stdout.write("const " + name + ";\n") 00081 continue 00082 # include 00083 m = reInclude.match(line) 00084 if m is not None: 00085 module = m.group('module') 00086 if module in ('strict', 'warnings', 'constant'): 00087 sys.stdout.write('\n') 00088 else: 00089 module = module.replace('::', '/') 00090 sys.stdout.write("#include \"" + module + ".pm\"\n") 00091 continue 00092 # Doxygen comment 00093 m = reCommentStart.match(line) 00094 if m is not None: 00095 comment = m.group('comment') 00096 sys.stdout.write("///" + comment + "\n") 00097 currentBlock = 'comment' 00098 m = reParamDoc.search (line) 00099 if m is not None: 00100 param = m.group('param') 00101 params.append(param) 00102 continue 00103 # if previous block was a Doxygen comment process 00104 # supported following blocks such as variable setting 00105 # and function definition optionally only the one 00106 # inside the if-case of an if-else-clause 00107 if previousBlock == 'comment': 00108 # function 00109 m = reFunctionStart.match(line) 00110 if m is not None: 00111 name = m.group('name1') 00112 if not name: 00113 name = m.group('name2') 00114 sys.stdout.write("sub " + name + "(") 00115 for i in range(0, len(params)): 00116 if i > 0: 00117 sys.stdout.write(", ") 00118 inout = params[i][0] 00119 argtype = params[i][1] 00120 param = params[i][2] 00121 if inout: 00122 if 'out' in inout and 'in' in inout: inout = 'inout' 00123 elif 'out' in inout: inout = 'out' 00124 else: inout = 'in' 00125 else: inout = 'in' 00126 if argtype: 00127 if argtype == '$': argtype = 'scalar' 00128 elif argtype == '@': argtype = 'array' 00129 elif argtype == '%': argtype = 'hash' 00130 elif argtype == '$$': argtype = 'scalarref' 00131 elif argtype == '@$': argtype = 'arrayref' 00132 elif argtype == '%$': argtype = 'hashref' 00133 else: argtype = None 00134 if not argtype: argtype = inout 00135 sys.stdout.write(' '.join([argtype, param])) 00136 sys.stdout.write(");\n") 00137 currentBlock = 'function' 00138 params = [] 00139 continue 00140 # unhandled lines... 00141 if line != '': 00142 if previousBlock == 'comment': 00143 # prevent comments that are not associated with any 00144 # processed block to be merged with subsequent comments 00145 sys.stdout.write("class COMMENT_DUMPED_BY_DOXYGEN_FILTER;\n") 00146 else: 00147 sys.stdout.write("\n") 00148 previousBlock = '' 00149 else: 00150 sys.stdout.write("\n") 00151 else: 00152 sys.stdout.write("\n") 00153 # close input file 00154 f.close() 00155 # done 00156 sys.exit(0)