home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 9
/
MEDIASHARE_09.ISO
/
clarion
/
showtree.zip
/
SHOWTREE.C
< prev
next >
Wrap
Text File
|
1989-04-13
|
20KB
|
717 lines
/*****************************************************************************
Program Name │ ShowTree
Version │ 1.0
│
Created │ 89/04/02 - Mike Hanson
Revised │
│
Company │ BoxSoft Development
│ Computer Information Management Ltd.
│ White City, SK
│ S0G 5B0 CANADA (306)781-2554
│
Purpose │ Print calling tree based on Clarion XRF file.
│
Usage │ ShowTree <appname>
│
│ The <appname> must NOT include an extension.
│ The XRF and CLA files must be in the current directory.
*****************************************************************************/
/****************
header files
****************/
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <alloc.h>
#include <math.h>
/***********
defines
***********/
#define MAX_CALLS_ON_LINE (9) /* max calls on XRF line */
#define MAX_CALLS (10*52*MAX_CALLS_ON_LINE) /* max calls in XRF file */
#define MAX_PROCS (10*52) /* max procs in app */
#define MAX_DEPTH (100) /* max calling depth */
#define FORMFEED (12)
#define ESC (27)
/************
typedefs
************/
typedef char PROC[12]; /* procedure type */
typedef char MODULE[8]; /* module type */
typedef char LINE[5]; /* line # type */
typedef char FILL; /* fill (waste) */
typedef struct _CALL_TABLE { /* pointer to call table entry */
MODULE calling_module;
LINE calling_line;
PROC calling_proc;
PROC called_proc;
} CALL_TABLE;
typedef struct _PROC_TABLE { /* pointer to procedure table entry */
MODULE module;
LINE line;
PROC name;
} PROC_TABLE;
/********************
global variables
********************/
struct _XRF_LINE { /* XRF line */
PROC called_proc;
FILL fill_1[13];
MODULE declared_in_module;
LINE declared_in_line;
FILL fill_3[3];
MODULE calling_module;
LINE calling_line[MAX_CALLS_ON_LINE];
} line;
PROC_TABLE *proc[MAX_PROCS]; /* procedure table */
CALL_TABLE *call[MAX_CALLS]; /* call table */
char link[MAX_DEPTH]; /* vertical line flags (see build_table) */
int nprocs=0; /* procs counter */
int ncalls=0; /* call counter */
/***********************
function prototypes
***********************/
void main ( int argc,
char *argv[] );
void check_parms ( int argc,
char *argv[] );
void bad_parms ( );
void scan_xrf_file ( char *appname );
void get_first_app_line ( char *appname,
LINE *l );
void get_line ( FILE *file );
void no_memory ( );
void finish_call_table ( );
int find_proc_proc_by_module ( CALL_TABLE *c );
void output_tree ( char *appname );
int find_proc_start ( PROC procname );
void build_tree ( int first_call,
int level );
void make_output_str ( CALL_TABLE *c,
char *text );
int lookup_proc_proc ( PROC p );
void sort ( void *arr[],
size_t n,
int (*comp)() );
int comp_proc_module_line ( PROC_TABLE *proc1,
PROC_TABLE *proc2 );
int comp_call_module_line ( CALL_TABLE *call1,
CALL_TABLE *call2 );
int comp_call_proc_line ( CALL_TABLE *call1,
CALL_TABLE *call2 );
int comp_call_calling_proc ( CALL_TABLE *call1,
CALL_TABLE *call2 );
/*****************************************************************************
main() - calls major code sections
*****************************************************************************/
void main ( int argc,
char *argv[] )
{
printf("ShowTree 1.0 - Mike Hanson, BoxSoft Development\n\n");
printf("Checking parameters...\n");
check_parms(argc, argv);
printf("Scanning XRF file...\n");
scan_xrf_file(argv[1]);
printf("Finishing call table...\n");
finish_call_table();
printf("Generating tree...\n");
output_tree(argv[1]);
}
/*****************************************************************************
check_parms() - checks for valid command line parameters
*****************************************************************************/
void check_parms ( int argc,
char *argv[] )
{
char fname[13];
if (argc != 2) bad_parms();
strupr(argv[1]);
if (strchr(argv[1], '.')) bad_parms();
strcat(strcpy(fname,argv[1]),".XRF");
if (!fopen(fname,"rt")) {
printf("Cannot access XRF file!\x07\n");
bad_parms();
}
strcat(strcpy(fname,argv[1]),".CLA");
if (!fopen(fname,"rt")) {
printf("Cannot access CLA file!\x07\n");
bad_parms();
}
fcloseall();
}
/*****************************************************************************
bad_parms() - called if command line parameters are bad
*****************************************************************************/
void bad_parms()
{
printf("\nUsage: ShowTree <AppName> <MainProc>\n\n");
printf("Do NOT include a file extension!\n\n");
exit(1);
}
/*****************************************************************************
scan_xrf_file() - reads XRF file, builds proc and call tables
*****************************************************************************/
void scan_xrf_file ( char *appname ) /* appname is argv[1] */
{
PROC current_proc ;
MODULE current_module ;
char fname[13] ;
FILE *xrf_file ;
int x ;
char t[80];
LINE first_app_line;
PROC main_proc;
strcat(strcpy(fname, appname), ".XRF");
xrf_file = fopen(fname, "rt");
get_first_app_line(appname, &first_app_line);
memset(main_proc, ' ', sizeof(PROC));
memcpy(main_proc, appname, strlen(appname));
for (;;) {
while (!feof(xrf_file) && line.called_proc[0] != FORMFEED)
get_line(xrf_file);
if (feof(xrf_file))
break;
else {
get_line(xrf_file);
get_line(xrf_file);
if (!memcmp(&line, "PROCEDURES", 10))
for (x=0; x<4; x++) get_line(xrf_file);
else
continue;
}
while (!feof(xrf_file)) {
get_line(xrf_file);
if (strlen((char*) &line) < sizeof(PROC))
break;
if (isalpha(line.called_proc[0])) {
memcpy(current_proc,
line.called_proc,
sizeof(PROC));
proc[nprocs] = (PROC_TABLE*) malloc(sizeof(PROC_TABLE));
if (!proc[nprocs]) no_memory();
memcpy(proc[nprocs]->name,
line.called_proc,
sizeof(PROC));
if (memcmp(proc[nprocs]->name, main_proc, sizeof(PROC))) {
memcpy(proc[nprocs]->module,
line.declared_in_module,
sizeof(PROC));
memcpy(proc[nprocs]->line,
line.declared_in_line,
sizeof(LINE));
} else {
memcpy(proc[nprocs]->module,
line.calling_module,
sizeof(MODULE));
memcpy(proc[nprocs]->line,
line.calling_line[0],
sizeof(LINE));
}
++nprocs;
}
if (isalpha(line.calling_module[0]))
memcpy(current_module,
line.calling_module,
sizeof(MODULE));
for ( x = 0 ; /* start at 0 */
line.calling_line[x][0] != '\n'
&& x < MAX_CALLS_ON_LINE;
x++ ) { /* increment count */
if ( memcmp(line.calling_module,
main_proc,
sizeof(MODULE)) == 0
&& memcmp(line.calling_line[x],
first_app_line,
sizeof(LINE)) < 0 )
continue;
call[ncalls] = (CALL_TABLE *)
malloc(sizeof(CALL_TABLE)); /* allocate memory */
if (!call[ncalls]) no_memory();
memset(call[ncalls], ' ', sizeof(CALL_TABLE));
memcpy(call[ncalls]->calling_module, /* get module */
current_module,
sizeof(MODULE));
memcpy(call[ncalls]->calling_line, /* get line */
line.calling_line[x],
sizeof(LINE));
memcpy(call[ncalls]->called_proc, /* get called proc */
current_proc,
sizeof(PROC));
++ncalls; /* inc call counter */
}
}
}
fclose(xrf_file);
}
/*****************************************************************************
get_first_app_line() - scans CLA file for first line after map
(XRF file includes map declarations as calls)
The determined line is placed into the LINE
parameter.
*****************************************************************************/
void get_first_app_line ( char *appname, /* argv[1] */
LINE *l ) /* pointer to LINE var */
{
char fname[13];
FILE *cla_file;
char buf[255];
int within_map = 0;
char *ptr;
int pos = 0;
strcat(strcpy(fname, appname), ".CLA");
cla_file = fopen(fname, "rt");
while (!feof(cla_file)) {
fgets(buf, sizeof(buf), cla_file);
++pos ;
if (!within_map && (ptr = strstr(buf, "MAP")))
within_map = ptr - buf ;
if ( within_map && (ptr = strchr(buf, '.'))
&& ptr - buf == within_map )
break;
}
sprintf(buf, "%*d", sizeof(LINE), pos);
memcpy(l, buf, sizeof(LINE));
}
/*****************************************************************************
get_line() - reads a line from XRF file and puts it in variable "line"
*****************************************************************************/
void get_line ( FILE *file ) /* file is the XRF file stream */
{
char ln[255];
if (!feof(file)) {
fgets(ln, sizeof(ln), file);
memcpy(&line, ln, sizeof(line));
}
}
/*****************************************************************************
no_memory() - called if too many procs and/or calls
*****************************************************************************/
void no_memory()
{
printf("Out of memory!\007\n");
exit(1);
}
/*****************************************************************************
finish_call_table() - looks-up calling_proc in proc table for each call
(calling_proc is not included in XRF file)
*****************************************************************************/
void finish_call_table()
{
int x, y ;
sort((void*) proc, nprocs, comp_proc_module_line);
sort((void*) call, ncalls, comp_call_module_line);
for (x=0; x < ncalls; x++)
if ((y = find_proc_proc_by_module(call[x])) != -1)
memcpy(call[x]->calling_proc, proc[y]->name, sizeof(PROC));
}
/*****************************************************************************
find_proc_proc_by_module() - Search the proc table using module name and
line number to find a calling_proc for the
specified call
*****************************************************************************/
find_proc_proc_by_module ( CALL_TABLE *c ) /* "c" is a pointer to the */
{ /* call containing the module*/
int x, flag=0, module_match; /* name and line number */
for (x=0; x < nprocs; x++) {
module_match = !memcmp( proc[x]->module,
c->calling_module,
sizeof(MODULE));
if (module_match) flag = 1;
if (flag && (!module_match
|| (module_match
&& memcmp( proc[x]->line,
c->calling_line,
sizeof(LINE)) > 0 )))
break;
}
if ( memcmp( proc[x-1]->module,
c->calling_module,
sizeof(MODULE)) == 0 )
return(x-1);
else
return(-1);
}
/*****************************************************************************
output_tree() - This procedure creates the tree for the application. It
opens the output file and calls build_tree to recurse
through the call table.
*****************************************************************************/
FILE *outfile;
void output_tree ( char *appname ) /* appname is argv[1] */
{
char fname[13];
PROC mainproc;
int start;
strcat(strcpy(fname, appname), ".XRT");
outfile = fopen(fname, "wt");
sort((void*) call, ncalls, comp_call_proc_line);
memset(mainproc, ' ', sizeof(PROC));
memcpy(mainproc, appname, strlen(appname));
fprintf(outfile, "%.*s\n", sizeof(PROC), mainproc);
printf("%.*s\n", sizeof(PROC), mainproc);
start = find_proc_start(mainproc);
if (start != -1) build_tree(start, 0);
fclose(outfile);
}
/*****************************************************************************
find_proc_start() - finds the start of calls made from a given proc. If
the specified proc has no calls, -1 is returned.
*****************************************************************************/
int find_proc_start ( PROC procname ) /* procname is the desired proc */
{
int x;
for (x=0; x < ncalls; x++)
if (!memcmp(call[x]->calling_proc, procname, sizeof(PROC)))
break;
if (x == ncalls)
return (-1);
else
return (x);
}
/*****************************************************************************
build_tree() - this function is recursive. It is continually called for
each level of procedure calls. When it calls it self, it
sets "link" which is used to determine which vertical bars
are continued (printed).
*****************************************************************************/
void build_tree ( int first_call, /* first call for calling_proc */
int level ) /* recursion depth */
{
int s = first_call;
int l, x;
char text[sizeof(PROC)+sizeof(MODULE)+4];
int start, more=1;
for ( s = first_call;
comp_call_calling_proc(call[first_call], call[s]) == 0
&& more;
s++ ) {
if ( !memcmp ( call[s]->called_proc,
"CHKERR ",
sizeof(PROC)))
continue;
else {
for (x = s-1; x >= first_call; x--)
if (memcmp(call[x]->called_proc,
call[s]->called_proc,
sizeof(PROC)) == 0 )
break;
if (x >= first_call) continue;
}
for (l=0; l<level; l++)
if (link[l]) {
fprintf(outfile, "│ ");
printf("│ ");
} else {
fprintf(outfile, " ");
printf(" ");
}
if (more = more_calls(first_call, s)) {
fprintf(outfile, "├─");
printf("├─");
} else {
fprintf(outfile, "└─");
printf("└─");
}
make_output_str(call[s], text);
fprintf(outfile, "%s\n", text);
printf("%s\n", text);
start = find_proc_start(call[s]->called_proc);
if (start != -1) {
link[level] = more;
build_tree(start, l+1);
}
}
}
/*****************************************************************************
more_calls() - checks for additional calls from current proc that are not
duplicates or CHKERR.
*****************************************************************************/
int more_calls ( int first, /* first call for the calling_proc */
int current ) /* current call (after first) */
{
int flag = 0;
int x;
for ( ++current;
comp_call_calling_proc ( call[first], call[current] ) == 0;
++current ) {
if ( memcmp ( call[current]->called_proc,
"CHKERR ",
sizeof(PROC)) != 0 ) {
for (x=current-1; x>=first; x--)
if (memcmp(call[x]->called_proc,
call[current]->called_proc,
sizeof(PROC)) == 0 )
break;
if (x<first) {
flag=1;
break;
}
}
}
return (flag);
}
/****************************************************************************
make_output_str() - creates output string with proc name and module with
the format "PROCNAME (MODULE)"
*****************************************************************************/
void make_output_str ( CALL_TABLE *c, /* pointer to call */
char *text ) /* buffer for output text */
{
char *p ;
int x ;
memset(text, ' ', sizeof(PROC)+sizeof(MODULE)+4);
memcpy(text, c->called_proc, sizeof(PROC));
p = strchr(text, ' ') + 1 ;
*(p++) = '(' ;
x = lookup_proc_proc(c->called_proc);
memcpy(p, proc[x]->module, sizeof(MODULE));
p = strchr(p, ' ') ;
*(p++) = ')' ;
*p = NULL ;
}
/*****************************************************************************
lookup_proc_proc() - used to find a proc's module name using the proc name
*****************************************************************************/
int lookup_proc_proc ( PROC p ) /* p contains name to be looked-up */
{
int x ;
for (x=0; x < nprocs; x++)
if (!memcmp(proc[x]->name, p, sizeof(PROC)))
break;
return (x);
}
/*****************************************************************************
sort() - sorts pointers to calls/procs using specified compare function.
This is a SHELL sort taken from Numerical Recipes in C (page 245)
*****************************************************************************/
#define ALN2I 1.442695022
#define TINY 1.0e-5
void sort ( void *arr[], /* pointer to an array of pointers */
size_t n, /* number of elements in array */
int (*comp)()) /* pointer to comparison function */
{
int nn,m,j,i,lognb2;
void *t;
lognb2=(log((double) n)*ALN2I+TINY);
m=n;
for (nn=1; nn<=lognb2; nn++) {
m >>= 1;
for (j=m+1; j<=n; j++) {
i=j-m;
t=arr[j-1];
while (i >= 1 && comp(arr[i-1], t) > 0) {
arr[i+m-1]=arr[i-1];
i -= m;
}
arr[i+m-1]=t;
}
}
}
/*****************************************************************************
comp_proc_module_line() - compare module+line for two procs
*****************************************************************************/
int comp_proc_module_line ( PROC_TABLE *proc1, /* pointer to proc */
PROC_TABLE *proc2 ) /* pointer to proc */
{
int x;
if (x = memcmp ( proc1->module,
proc2->module,
sizeof(MODULE) ))
return (x);
else
return ( memcmp ( proc1->line,
proc2->line,
sizeof(LINE) ));
}
/*****************************************************************************
comp_call_module_line() - compare module+line for two calls
*****************************************************************************/
int comp_call_module_line ( CALL_TABLE *call1, /* pointer to call */
CALL_TABLE *call2 ) /* pointer to call */
{
int x;
if (x = memcmp ( call1->calling_module,
call2->calling_module,
sizeof(MODULE) ))
return (x);
else
return ( memcmp ( call1->calling_line,
call2->calling_line,
sizeof(LINE) ));
}
/*****************************************************************************
comp_call_proc_line() - compare proc+line for two calls
*****************************************************************************/
int comp_call_proc_line ( CALL_TABLE *call1, /* pointer to call */
CALL_TABLE *call2 ) /* pointer to call */
{
int x ;
if ( x = memcmp ( call1->calling_proc,
call2->calling_proc,
sizeof(PROC) ))
return(x);
else
return ( memcmp ( call1->calling_line,
call2->calling_line,
sizeof(LINE) ));
}
/*****************************************************************************
comp_call_calling_proc() = compare calling_proc for two calls
*****************************************************************************/
int comp_call_calling_proc ( CALL_TABLE *call1, /* pointer to call */
CALL_TABLE *call2 ) /* pointer to call */
{
return (memcmp ( call1->calling_proc,
call2->calling_proc,
sizeof(PROC) ));
}
/*****************************************************************************
show() - used for debugging. Shows call or proc table, 20 lines at a time
This funtion is not normally called if the program is working.
(Yes folks, it's wasted space!)
*****************************************************************************/
show ( char type, /* 'p' = proc table, 'c' = call table */
int point ) /* extra number to show source file position */
{
int x=0, y;
printf("%c/%d nprocs=%d ncalls=%d\n", type, point, nprocs, ncalls);
for (y=0; y < ((type == 'c') ? ncalls : nprocs); y++) {
printf("%4d│%.*s\n", y,
((type=='c')?sizeof(CALL_TABLE):sizeof(PROC_TABLE))-1,
(type == 'c') ? (char*) call[y] : (char *) proc[y]);
if (++x == 20) {
if (getch() == ESC) exit(0);
x = 0;
}
}
if (getch() == ESC) exit(0);
return(0);
}