"""
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(e ntryFun,working Dir)
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,worki ngDir):
cmd = "cscope -d -l -L -2%s"%entryFun
process = subprocess.Pope n(cmd, stdout=subproce ss.PIPE, shell=True,
cwd=workingDir)
csoutput= process.stdout. read()
del process
cslines=[arr.strip().spl it(' ') 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,funsCa lled)
def callGraph(entry Fun,workingDir, cg={}):
if not cg.has_key(entr yFun):
allFuns,funsCal led=functionsCa lled(entryFun,w orkingDir)
cg[entryFun]=funsCalled
for af in allFuns:
cg=callGraph(af ,workingDir,cg)
return cg
def textCallGraph(a cg):
innerFuns=[(f,d,len(reduce (lambda x,y:x|y,d.value s()))) 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(in nerFuns)
leafLen=len(lea fFuns)
title=lambda aFun: '\n' + aFun + '\n' + '-'*len(aFun)
def ff(aFun,funsCal led):
fileFuns=zip(fu nsCalled.keys() ,[' '+',\n '.join(funsCall edInFile)
for funsCalledInFil e in funsCalled.valu es()])
funIn=lambda f: '\n%s in '%f
return title(aFun) + funIn(aFun) + funIn(aFun).joi n(map(lambda
x:'%s:\n%s'%(x[0],x[1]),fileFuns))
strInner='\n'.j oin([ff(f[0],f[1]) for f in innerFuns])
strLeaves='\n'. join(map(lambda x:title(x[0]),leafFuns))
return strInner+'\n'+s trLeaves
def funWeights(acg) :
funWeights=dict ([(f,reduce(lambd a x,y:x|y,d.value s())) 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=funWeig hts[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(a cg):
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(in nerFuns)
leafLen=len(lea fFuns)
funDict=dict(zi p(map(lambda x:x[0],innerFuns)+map (lambda
x:x[0],leafFuns),rang e(innerLen+leaf Len)))
title=lambda aFun: '<hr><h4><a name=#f%i'%funD ict[aFun]+'>' + aFun + '
(%i)'%funW[aFun] + '</a></h4>\n'
def ff(aFun,funsCal led):
fun=lambda y:'<a href=#f%i'%funD ict[y]+'
style="text-decoration:none ">'+y+'</a>'
fileFuns=zip(fu nsCalled.keys() ,[',\n'.join(map( fun,funsCalledI nFile))
for funsCalledInFil e in funsCalled.valu es()])
funIn=lambda f: '<br><em>%s</emin '%f
return title(aFun) + funIn(aFun) + funIn(aFun).joi n(map(lambda
x:'%s:\n%s'%(x[0],x[1]),fileFuns))
strInner='\n'.j oin([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.ar gv[1]
workingDir=os.g etcwd()
acg=callGraph(e ntryFun,working Dir)
print htmlCallGraph(a cg)
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(e ntryFun,working Dir)
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,worki ngDir):
cmd = "cscope -d -l -L -2%s"%entryFun
process = subprocess.Pope n(cmd, stdout=subproce ss.PIPE, shell=True,
cwd=workingDir)
csoutput= process.stdout. read()
del process
cslines=[arr.strip().spl it(' ') 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,funsCa lled)
def callGraph(entry Fun,workingDir, cg={}):
if not cg.has_key(entr yFun):
allFuns,funsCal led=functionsCa lled(entryFun,w orkingDir)
cg[entryFun]=funsCalled
for af in allFuns:
cg=callGraph(af ,workingDir,cg)
return cg
def textCallGraph(a cg):
innerFuns=[(f,d,len(reduce (lambda x,y:x|y,d.value s()))) 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(in nerFuns)
leafLen=len(lea fFuns)
title=lambda aFun: '\n' + aFun + '\n' + '-'*len(aFun)
def ff(aFun,funsCal led):
fileFuns=zip(fu nsCalled.keys() ,[' '+',\n '.join(funsCall edInFile)
for funsCalledInFil e in funsCalled.valu es()])
funIn=lambda f: '\n%s in '%f
return title(aFun) + funIn(aFun) + funIn(aFun).joi n(map(lambda
x:'%s:\n%s'%(x[0],x[1]),fileFuns))
strInner='\n'.j oin([ff(f[0],f[1]) for f in innerFuns])
strLeaves='\n'. join(map(lambda x:title(x[0]),leafFuns))
return strInner+'\n'+s trLeaves
def funWeights(acg) :
funWeights=dict ([(f,reduce(lambd a x,y:x|y,d.value s())) 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=funWeig hts[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(a cg):
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(in nerFuns)
leafLen=len(lea fFuns)
funDict=dict(zi p(map(lambda x:x[0],innerFuns)+map (lambda
x:x[0],leafFuns),rang e(innerLen+leaf Len)))
title=lambda aFun: '<hr><h4><a name=#f%i'%funD ict[aFun]+'>' + aFun + '
(%i)'%funW[aFun] + '</a></h4>\n'
def ff(aFun,funsCal led):
fun=lambda y:'<a href=#f%i'%funD ict[y]+'
style="text-decoration:none ">'+y+'</a>'
fileFuns=zip(fu nsCalled.keys() ,[',\n'.join(map( fun,funsCalledI nFile))
for funsCalledInFil e in funsCalled.valu es()])
funIn=lambda f: '<br><em>%s</emin '%f
return title(aFun) + funIn(aFun) + funIn(aFun).joi n(map(lambda
x:'%s:\n%s'%(x[0],x[1]),fileFuns))
strInner='\n'.j oin([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.ar gv[1]
workingDir=os.g etcwd()
acg=callGraph(e ntryFun,working Dir)
print htmlCallGraph(a cg)