cgq
(for call graph query), a shell script that
generates who-calls-whom information. cgq
differs from the other call-graph generator in three ways:
cgi
is a shell script; the other call-graph generator is an Icon
program.
cgi
extracts its information from a realtional database containing the
sbdump
information; the other call-graph generator reads the
sbdump
files directly.
cgi
produces only the raw data for the call graph (that is, it produces
the who-calls-whom list); the other call-graph generator produces dot code to
draw the graph.
<cgq
>=
#!/bin/ksh
<shell boilerplate>
<process options>
<build the basic tables>
<filter the call-graph source nodes>
<filter the call-graph destination nodes>
<re-label the source call-graph nodes>
<re-label the destination call-graph nodes>
<write the call-graph data>
The analysis starts by constructing two tables: call_graph
and
containing_files
. Both tables re-represent the information in the
calling-information table in form more convenient for later analysis. Tbe
call_graph
table is the set of caller-called pairs; the
containing_files
table indicates which file contains a calling procedure.
The shell variable ctable
contains the name of the most recent version of
the call-graph table; as analysis proceedes it will generate new versions of
the call-graph table.
<build the basic tables>= (<-U) ctable=call_graph cat <<eot! | mysql mosaic create table $ctable ( caller varchar(40) not null, called varchar(40) not null ); insert into $ctable select distinct call_info.caller, call_info.calling from call_info ; create table containing_files ( file varchar(40) not null, proc varchar(40) not null ); insert into containing_files select distinct call_info.file, call_info.caller from call_info ; eot!
If the cgq
node-filter option -nf
contains the string sf=pat
, then
only those procedures defined in files with names matching pat
will be
included in the call graph. For example, sf=%gui%
, selects only those
procedures defined in files with names matching %gui%
(%
is the SQL
match-any metacharacter).
If a source-node filter was given, put the pattern in the shell variable
sf
, then construct a new call-graph table containing caller-called pairs in
which the caller is defined in a file with a properly matching name.
<filter the call-graph source nodes>= (<-U) sf=`expr "$nf" : '.*sf=\([^ ]*\)'` if [ "$sf" ] ; then otable=$ctable ctable="${ctable}x" cat <<eot! | mysql mosaic create table $ctable ( caller varchar(40) not null, called varchar(40) not null ); insert into $ctable select $otable.caller, $otable.called from containing_files, $otable where $otable.caller = containing_files.proc and containing_files.file like '$sf' ; drop table $otable; eot! fi
Do the same filtering on the destination nodes.
<filter the call-graph destination nodes>= (<-U) df=`expr "$nf" : '.*df=\([^ ]*\)'` if [ "$df" ] ; then otable=$ctable ctable="${ctable}x" cat <<eot! | mysql mosaic create table $ctable ( caller varchar(40) not null, called varchar(40) not null ); insert into $ctable select $otable.caller, $otable.called from containing_files, $otable where $otable.called = containing_files.proc and containing_files.file like '$df' ; drop table $otable; eot! fi
A node in the call graph may be labeled in one of two ways: with a procedure
name (the default) or with the name of the file containing the procedure. The
-nl
command-line option to cgq
determines which label to use.
If source nodes should be labeled with a file name, create a new call-graph table containing the new labels.
<re-label the source call-graph nodes>= (<-U) if [ `expr $nl : '^f'` = 1 ] ; then otable=$ctable ctable="${ctable}x" cat <<eot! | mysql mosaic create table $ctable ( caller varchar(40) not null, called varchar(40) not null ); insert into $ctable select distinct containing_files.file, $otable.called from containing_files, $otable where $otable.caller = containing_files.proc ; drop table $otable; eot! fi
Re-label the destiniation nodes too, if necessary.
<re-label the destination call-graph nodes>= (<-U) if [ `expr $nl : '^.f'` = 2 ] ; then otable=$ctable ctable="${ctable}x" cat <<eot! | mysql mosaic create table $ctable ( caller varchar(40) not null, called varchar(40) not null ); insert into $ctable select distinct $otable.caller, containing_files.file from containing_files, $otable where $otable.called = containing_files.proc ; drop table $otable; eot! fi
Write the call-graph table to an external text file and delete the temporary tables.
<write the call-graph data>= (<-U) ofile=call-graph rm -f /tmp/mysql/mosaic/$ofile cat <<eot! | mysql mosaic select * from $ctable into outfile '$ofile' ; drop table $ctable, containing_files; eot!
The -nf
options sets the node filter; the -nl
option sets the node
label.
<process options>= (<-U) nl=pp nf='' while [ $# -gt 0 ] do case $1 in -nf*) x=`expr $1 : '-nf\(.*\)'` if [ ! "$x" ] then shift 1 x=$1 fi [ "$x" ] || oops '-nf needs an argument' fi ;; -nl*) x=`expr $1 : '-nl\(.*\)'` if [ ! "$x" ] then shift 1 x=$1 fi [ "$x" ] || oops '-nl needs an argument' nl=$x ;; *) badcmd ;; esac shift 1 done [ `expr "$nl" : '^[pf][pf]$'` -ne 0 ] || badcmd
Miscelanious functions and definitions.
<shell boilerplate>= (<-U) function oops { # Print $1 to std-err and die. echo 1>&2 "$1." exit 1 } pgmname=`basename $0` function badcmd { # Print a bad command message and die. oops "Command format is \"$pgmname [-nl arg] [-nf arg]\"" } alias mysql=/tmp/bin/mysql alias mysqladmin=/tmp/bin/mysqladmin alias mysqlshow=/tmp/bin/mysqlshow
cgq
>: D1