#!/usr/bin/env python2 # # Extract function call names from source C/H files. # # Useful for e.g. hunting non-Duktape library calls. Function calls can # also be determined from object files, but some function calls are # compilation option specific, so it's better to find them from source # files. # # Example run: # # $ python util/find_func_calls.py src/*.c src/*.h | \ # grep -v -i -P ^duk_ | grep -v -P '^(sizeof|va_start|va_end|va_arg)' | \ # sort | uniq | less # import os import sys import re re_linecont = re.compile(r'\\\n') re_comment = re.compile(r'/\*.*?\*/', re.DOTALL) re_func_call = re.compile(r'([A-Za-z_][A-Za-z0-9_]+)\(') re_string = re.compile(r'"(\\"|[^"])*"') def stripLineContinuations(x): res = re.sub(re_linecont, ' ', x) #print(res) return res def stripComments(x): res = re.sub(re_comment, '/*omit*/', x) #print(res) return res def stripStrings(x): res = re.sub(re_string, '"..."', x) #print(res) return res def findFuncCalls(d, fn): res = [] for line in d.split('\n'): if len(line) >= 1 and line[0] == '#': # Preprocessor lines contain function call like # syntax but are not function calls. continue for m in re_func_call.finditer(line): res.append({ 'name': m.group(1), 'filename': fn }) return res def main(): # Duktape code does not have a space between a function name and # an open parenthesis. If the regexp includes an optional space, # it will provide a lot of false matches. for fn in sys.argv[1:]: f = open(fn, 'rb') d = f.read() f.close() # Strip line continuations, comments, and strings so that # we minimize false matches. d = stripLineContinuations(d) d = stripComments(d) d = stripStrings(d) # Find function calls (close enough). for i in findFuncCalls(d, fn): #print '%s' % i['name'] print '%-25s%s' % (i['name'], i['filename']) if __name__ == '__main__': main()