| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 | #!/usr/bin/env python2.3import re, sysimport textwrapfiles = sys.argv[1:]funcDeclaredIn = {}fileDeclares = {}functionCalls = {}funcCalledByFile = {}funcCalledByFunc = {}cpp_re = re.compile(r'//.*$')c_re = re.compile(r'/[*]+(?:[^*]+|[*]+[^/*])*[*]+/', re.M|re.S)for fname in files:    f = open(fname, 'r')    curFunc = "???"    functionCalls.setdefault(curFunc,{})    lineno = 0    body = f.read()    body = cpp_re.sub(" ",body)    body = c_re.sub(" ",body)    #if fname == 'dns.c': print body    for line in body.split("\n"):        lineno += 1        m = re.match(r'^[^\s/].*\s(\w+)\([^;]*$', line)        if m:            #print line, "->", m.group(1)            curFunc = m.group(1)            if curFunc[0] == '_': curFunc = curFunc[1:]            functionCalls.setdefault(curFunc,{})            funcDeclaredIn[m.group(1)] = fname            fileDeclares.setdefault(fname, {})[m.group(1)] = 1            continue        m = re.match(r'^(\w+)\([^;]', line)        if m:            #print line, "->", m.group(1)            curFunc = m.group(1)            if curFunc[0] == '_': curFunc = curFunc[1:]            functionCalls.setdefault(curFunc,{})            funcDeclaredIn[m.group(1)] = fname            fileDeclares.setdefault(fname, {})[m.group(1)] = 1            continue        while line:            m = re.search(r'(\w+)\(', line)            if not m: break            #print fname, line, curFunc, "->", m.group(1)            fn = m.group(1)            if fn[0] == '_':                fn = fn[1:]            functionCalls[curFunc][m.group(1)] = 1            #if curFunc == "???":            #    print ">>!!!!! at %s:%s"%(fname,lineno)            funcCalledByFunc.setdefault(m.group(1), {})[curFunc]=1            funcCalledByFile.setdefault(m.group(1), {})[fname]=1            line = line[m.end():]    f.close()fileUsers = {}fileUses = {}for fname in files:    print "%s:"%fname    users = {}    for func in fileDeclares[fname]:        cb = funcCalledByFile.get(func,{}).keys()        for f in cb: users[f] = 1        #print "users[%s] = %s"%(f,users[f])    users = users.keys()    users.sort()    fileUsers[fname] = users    for user in users:        fileUses.setdefault(user,[]).append(fname)        if user == fname: continue        print "  from %s:"%user        for func in fileDeclares[fname]:            if funcCalledByFile.get(func,{}).get(user,0):                print "    %s()"%funcdef wrap(s, pre):    return textwrap.fill(s,                         width=77, initial_indent=pre,                         subsequent_indent=" "*len(pre))for fname in files:    print    print "===== %s"%fname    print wrap(" ".join(fileUses[fname]),               "        Calls: ")    print wrap(" ".join(fileUsers[fname]),              "    Called by: ")print "=============================="funcnames = functionCalls.keys()funcnames.sort()if 1:    for func in funcnames:        print "===== %s"%func        callers = [c for c in funcCalledByFunc.get(func,{}).keys()                   if c != "???"]        callers.sort()        called = [c for c in functionCalls[func].keys() if c != "???" and                  c in funcnames]        called.sort()        print wrap(" ".join(callers),                   "  Called by:")        print wrap(" ".join(called),                   "      Calls:")# simple topological sort.functionDepth = {}while 1:    BIG = 1000000    any = 0    for func in funcnames:        if functionDepth.has_key(func):            continue        called = [c for c in functionCalls[func] if c != func and                  functionCalls.has_key(c)]        if len(called) == 0:            functionDepth[func] = 0            #print "Depth(%s)=%s"%(func,0)            any = 1            continue        calledDepths = [ functionDepth.get(c,BIG) for c in called ]        if max(calledDepths) < BIG:            d = functionDepth[func] = max(calledDepths)+1            #print "Depth(%s)=%s"%(func,d)            any = 1            continue    if not any:        break# compute lexical closure.cycCalls = {}for func in funcnames:    if not functionDepth.has_key(func):        calls = [ c for c in functionCalls[func] if c != func and                  functionCalls.has_key(c) and not functionDepth.has_key(c)]        cycCalls[func] = d = {}        for c in calls:            d[c]=1cycNames = cycCalls.keys()while 1:    any = 0    for func in cycNames:        L = len(cycCalls[func])        for called in cycCalls[func].keys():            cycCalls[func].update(cycCalls[called])        if L != len(cycCalls[func]):            any = 1    if not any:        breakdepthList = [ (v,k) for k,v in functionDepth.items() ]depthList.sort()cycList = [ (len(v),k) for k,v in cycCalls.items() ]cycList.sort()for depth,name in depthList:    print "Depth[%s]=%s"%(name,depth)for bredth,name in cycList:    print "Width[%s]=%s"%(name,bredth)print "Sorted %s / %s"%(len(functionDepth),len(funcnames))
 |