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