""" Sometimes it is nice to have the data used by cscope accessible in a programatic way. The following python script extract the "functions called" information from cscope (function: callGraph) and produced an html file from them.
from csCallGraph import * acg=callGraph(entryFun,workingDir) entryFun is the function to start with (e.g. main) workingDir is the directory where cscope.out is located As a script it can be called like: csCallGraph main > myprogram.html """ import subprocess , os, sys def functionsCalled(entryFun,workingDir): cmd = "cscope -d -l -L -2%s"%entryFun process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, cwd=workingDir) csoutput= process.stdout.read() del process cslines=[arr.strip().split(' ') for arr in csoutput.split('\n') if len(arr.split(' '))>1] funsCalled={} for fl in cslines: if funsCalled.has_key(fl[0]): funsCalled[fl[0]]|=set([fl[1]]) else: funsCalled[fl[0]]=set([fl[1]]) allFuns=set(map(lambda x:x[1],cslines)) return (allFuns,funsCalled) def callGraph(entryFun,workingDir,cg={}): if not cg.has_key(entryFun): allFuns,funsCalled=functionsCalled(entryFun,workingDir) cg[entryFun]=funsCalled for af in allFuns: cg=callGraph(af,workingDir,cg) return cg def textCallGraph(acg): innerFuns=[(f,d,len(reduce(lambda x,y:x|y,d.values()))) for f,d in acg.items() if len(d)>0 ] leafFuns=[(f,d,0) for f,d in acg.items() if not len(d)>0 ] innerFuns.sort(lambda x,y: y[2]-x[2]) innerLen=len(innerFuns) leafLen=len(leafFuns) title=lambda aFun: '\n' + aFun + '\n' + '-'*len(aFun) def ff(aFun,funsCalled): fileFuns=zip(funsCalled.keys(),[' '+',\n '.join(funsCalledInFile) for funsCalledInFile in funsCalled.values()]) funIn=lambda f: '\n%s in '%f return title(aFun) + funIn(aFun) + funIn(aFun).join(map(lambda x:'%s:\n%s'%(x[0],x[1]),fileFuns)) strInner='\n'.join([ff(f[0],f[1]) for f in innerFuns]) strLeaves='\n'.join(map(lambda x:title(x[0]),leafFuns)) return strInner+'\n'+strLeaves def funWeights(acg): funWeights=dict([(f,reduce(lambda x,y:x|y,d.values())) for f,d in acg.items() if len(d)>0 ]+ [(f,[]) for f,d in acg.items() if not len(d)>0 ]) weights={} def calcWeights(af): if not weights.has_key(af): subFuns=funWeights[af] weights[af]=1 for f in subFuns: calcWeights(f) weights[af]+=weights[f] for af in funWeights.keys(): calcWeights(af) return weights def htmlCallGraph(acg): funW=funWeights(acg) innerFuns=[(f,d,funW[f]) for f,d in acg.items() if len(d)>0 ] leafFuns=[(f,d,0) for f,d in acg.items() if not len(d)>0 ] #innerFuns.sort(lambda x,y: y[2]-x[2])) def cfun(a,b): if b > a: return 1 elif b < a: return -1 return 0 innerFuns.sort(lambda x,y: cfun(x[2],y[2])) innerLen=len(innerFuns) leafLen=len(leafFuns) funDict=dict(zip(map(lambda x:x[0],innerFuns)+map(lambda x:x[0],leafFuns),range(innerLen+leafLen))) title=lambda aFun: '<hr><h4><a name=#f%i'%funDict[aFun]+'>' + aFun + ' (%i)'%funW[aFun] + '</a></h4>\n' def ff(aFun,funsCalled): fun=lambda y:'<a href=#f%i'%funDict[y]+' style="text-decoration:none">'+y+'</a>' fileFuns=zip(funsCalled.keys(),[',\n'.join(map(fun,funsCalledInFile)) for funsCalledInFile in funsCalled.values()]) funIn=lambda f: '<br><em>%s</em> in '%f return title(aFun) + funIn(aFun) + funIn(aFun).join(map(lambda x:'%s:\n%s'%(x[0],x[1]),fileFuns)) strInner='\n'.join([ff(f[0],f[1]) for f in innerFuns]) strLeaves='\n'.join(map(lambda x:title(x[0]),leafFuns)) return '<html>\n<body>\n'+strInner+'\n'+strLeaves+"</body>\n</html>\n" if __name__ == '__main__': if len(sys.argv) < 2: print 'Usage: csGragh.py entryFunction' sys.exit() entryFun=sys.argv[1] workingDir=os.getcwd() acg=callGraph(entryFun,workingDir) print htmlCallGraph(acg) -- http://mail.python.org/mailman/listinfo/python-list