#!/usr/bin/python import os import sys def find_line(lineno, file, words): ch = words[0][0] while 1: line = file.readline() if not line: return None, None lineno += 1 if line[0] != ch: continue w = line.split() if w and w[0] in words: # removed "and len(w) == 1" b/c of lines "} /* comment */" break return lineno, w def find_inlines(filename): #print filename lineno = 0 file = open(filename) while 1: line = file.readline() if not line: break lineno += 1 words = line.split() # Usually, "static inline" are the first words. # If "static" isn't first, we usually are looking at a weird macro. # However, this is seen in the wild: #notrace static inline u64 vgetsns(int *mode) #notrace static int __always_inline do_realtime(struct timespec *ts) if words and words[0] == "notrace": del words[0] if words and words[0] != "static": continue while words: w = words[0] if w == "inline" or w == "__always_inline" or w == "__inline__" or w == "__inline": break del words[0] if not words: continue # next line # found "static ... inline" inline_line = lineno while 1: while not words: line = file.readline() if not line: break lineno += 1 words = line.split() if not words: # eof break w = words[0] if "(" in w: break del words[0] if not words: continue # next line # found "... func(..." funcline = lineno # TODO: deal with "func (..." funcname = w[:w.index("(")] # deal with "... char *func(..." while funcname.startswith("*"): funcname = funcname[1:] # detect null inlines with "{ }" or "{}" bodies on the same line as funcname # detect forward inlines: "inline f();" while words: if words[0].startswith("{"): # not really exact match... break if ";" in words[0]: # works only if it's on the same line. Counterexample: net/ipv4/netfilter/nf_nat_snmp_basic.c::mangle_address() break del words[0] if words: continue # next line # detect a macroized function (such as name##_readl) if not funcname.replace("_", "a").isalnum(): continue # next line lineno, words = find_line(lineno, file, ["{", "{}"]) if not lineno: #eof sys.stderr.write("{0}:{1}:{2}: can't find start\n".format(filename, funcline, funcname)) break start = lineno if words[0] == "{}" or (len(words) > 1 and words[1] == "}"): # the body is "{ }" or "{}" on a separate line inline_len = 0 else: lineno, words = find_line(lineno, file, ["}", "};"]) if not lineno: #eof sys.stderr.write("{0}:{1}:{2}: can't find end\n".format(filename, funcline, funcname)) break if words[0] == "};": sys.stderr.write("{0}:{1}: possibly bogus semicolon\n".format(filename, lineno)) inline_len = lineno-1 - start sys.stdout.write("{0}:{1}:{2}:{3}\n".format(filename, inline_line, funcname, inline_len)) for dirname, dirnames, filenames in os.walk('.'): dirnames.sort() filenames.sort() if dirname.startswith("./"): dirname = dirname[2:] for filename in filenames: if filename.endswith(".h"): find_inlines(os.path.join(dirname, filename)) if filename.endswith(".c"): find_inlines(os.path.join(dirname, filename)) for subdirname in dirnames: #print os.path.join(dirname, subdirname) pass # Advanced usage: # editing the 'dirnames' list will stop os.walk() from recursing into there. if '.git' in dirnames: # don't go into any .git directories. dirnames.remove('.git')