home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 6
/
FreshFish_September1994.bin
/
new
/
dev
/
c
/
hce
/
examples
/
clib
/
cflow
/
cflow.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-02
|
21KB
|
836 lines
/* CFLOW.C - A C Function Call Chart Generator
*
* Version 1.00 December 21st, 1986
*
* SYNOPSIS:
*
* CFLOW accepts C source code via the standard input and
* produces a listing of the hierarchy of C function calls
* on the standard output. Recursive functions are explicitly
* identified in the listing. The command line format is:
*
* CFLOW < source_file
*
* The output listing identifies all functions in the source
* code and the functions they call (#include files are not
* recognized). If only specific functions are of interest,
* (e.g. - fcn1, fcn2, fcn3), a listing for these functions
* only and the functions they call can be specified with the
* command line:
*
* CFLOW < source_file fcn1 fcn2 fcn3
*
* MODIFICATIONS:
*
* V1.00 - beta test release
*
* Adapted from: "CALLS.C"
* The C Programming Tutor
* L.A. Wortman & T.O. Sidebottom
* Prentice Hall Publishing
*
* Adaptation by: Ian Ashdown
* byHeart Software
* 620 Ballantree Road
* West Vancouver, B.C.
* Canada V7S 1W3
*
* USAGE: CFLOW [function_name ...]
*
* DIAGNOSTICS:
*
* Exit status is 0 if no problems encountered, 2 otherwise.
*
* BUGS:
*
* Identifiers are limited to 32 characters in length.
* Recursive calling depth is set at 25.
*
**********************************************************************
* LAST CHANGES *
**********************************************************************
*
* 14 June, 1994 - Jason Petty
*
* Now checks if called from CLI or if invalid file, shows usage then exits
* with an error status. Does not use 'stdin' for input but instead
* requires user to specify a filename on the command line.
*
* To clear things up a bit here's the Usage:
*
* CFLOW <source_filename> <function name 1> <funcn2> <funcn3>
*
* If called: CFLOW <filename>
* without function name then the default is to list 'main()'.
*
* Changes marked VANSOFT.
*/
/*** INCLUDE FILES ***/
#include <stdio.h>
/*** DEFINITIONS ***/
#define BOOL int
#define DEFINED 1 /* Result of find_next() */
#define DEFINING 0 /* Result of find_next() */
#define FALSE 0
#define HASH_TABLE_FULL -1 /* Indicates hash table overflow */
#define HT_SIZE 1009 /* Must be a prime number */
#define INDENT " " /* Default output indentation */
#define INDENT_SIZE 4 /* Number of spaces in indentation */
#define MAXDEPTH 25 /* Maximum recursive-calling depth */
#define MAXSYMLEN 32 /* Maximum significant characters
in a symbol */
#define PGWIDTH 80 /* Default output page width */
#define TRUE 1
/*** CODE MACROS ***/
#define GENERATE_NEW_INDEX(x,y) (((x+y*y) % HT_SIZE)+1)
/*** TYPEDEFS ***/
typedef struct itype
{
struct ntype *name_defn; /* Name for this instance */
struct itype *next_callee; /* Next instance called */
}
INSTANCE,
*P_INSTANCE;
typedef struct ntype
{
char fcn_name[MAXSYMLEN]; /* Unique function name */
int call_cnt, /* Number of times function called */
first_num; /* Line when function name first printed */
struct ntype *next_pname; /* Next function name in the list */
P_INSTANCE first_callee; /* Pointer to instance describing the
* first call for this function */
}
NAME,
*P_NAME;
/*** GLOBAL VARIABLES ***/
int line_cnt = 0, /* Line count */
maxact_index = 0, /* Indexes active list from 0 to MAXDEPTH */
tabs_page = (PGWIDTH-MAXSYMLEN)/INDENT_SIZE, /* Tabs per page */
bkt_cnt = 0; /* Keeps track of the nesting of brackets. A
* function found when "bkt_cnt" is zero
* must be its DEFINING occurrence, since
* function invocations must always appear
* within some block of code. */
char *hash_table[HT_SIZE];
BOOL terse = TRUE;
P_NAME name_head = NULL,
active_list[MAXDEPTH]; /* Used by output() to avoid */
/* infinite recursion */
FILE *infile=NULL; /* Don't use stdin. Added, VANSOFT. */
char *malloc();
void usage();
void usage(op) /* Added. VANSOFT. */
int op;
{
printf("\n\nCFLOW V1.0 - 21.12.86.\n");
printf("Authors: L.A. Wortman, T.O. Sidebottom & Ian Ashdown.\n\n");
printf("SYNOPSIS:\n");
printf("CFLOW accepts C source code via the standard input and\n");
printf("produces a listing of the hierarchy of C function calls\n");
printf("on the standard output. Recursive functions are explicitly\n");
printf("identified in the listing.\n\n");
printf("USAGE: CFLOW <source_file> <function_name1> <funcn2> <funcn3>\n\n");
if(!op) /* exit error. */
exit(10);
}
/*** MAIN BODY OF CODE ***/
int main(argc,argv)
int argc;
char *argv[];
{
int actlist_index,
arg_index = 2,
fcn_use,
hashtbl_index;
char id[MAXSYMLEN];
P_NAME pcaller,
pname,
look_for(),
find_name();
BOOL insert_word();
void new_fcn(),
output(),
error();
if(!argc) /* May have been run from Workbench. VANSOFT. */
exit(10);
if(argc <= 1) /* Not enough args. VANSOFT. */
usage(NULL);
if(!(infile = fopen(argv[1], "r"))) /* Added, VANSOFT. */
{
usage(1); /* 1 = don't 'exit()' yet. */
fprintf(stdout, "%s: Can't access %s!\n\n",argv[0],argv[1]);
exit(10); /* exit error. */
}
/* Initialize the hash table */
for(hashtbl_index = 0; hashtbl_index < HT_SIZE; hashtbl_index++)
hash_table[hashtbl_index] = NULL;
/* The following are keywords that look like function calls in C */
insert_word("for");
insert_word("if");
insert_word("return");
insert_word("sizeof");
insert_word("switch");
insert_word("while");
/* Initialize the active list */
for(actlist_index = 0; actlist_index < MAXDEPTH; )
active_list[actlist_index++] = NULL;
/* Parse the input stream and build the appropriate tables */
pcaller = NULL;
while((fcn_use = find_next(id,pcaller)) != EOF)
if(fcn_use == DEFINING)
pcaller = find_name(id);
else
new_fcn(id,pcaller);
/* If there are any command line arguments, they are the names
* of the functions from which to begin the call charts.
*/
if(arg_index < argc)
{
do
{
if(pname = look_for(argv[arg_index]))
{
output(pname,NULL);
putchar('\n');
}
else
printf("\007\nERROR: Function %s not found.\n",
argv[arg_index]);
}
while((++arg_index) < argc)
;
}
else
{
/* Print beginning with "main", if there is one */
if(pname = look_for("main"))
{
output(pname,NULL);
putchar('\n');
pname->call_cnt = 1; /* Don't print "main" again later */
}
/* Now print all functions not called by anyone else */
for(pname = name_head; pname; pname = pname->next_pname)
if(pname->call_cnt == NULL)
{
output(pname,NULL);
putchar('\n');
}
/* Finally, print any mutually recursive functions */
for(pname = name_head; pname; pname = pname->next_pname)
if(pname->first_num == NULL)
{
output(pname,NULL);
putchar('\n');
}
}
}
/*** FUNCTIONS ***/
/* FIND_NEXT() - Sets its argument to the name of the next function
* found in the input stream. It returns as its value
* DEFINING if this is the defining occurrence of the
* function, DEFINED if it is simply an invocation of
* the function, and EOF if the input stream is
* exhausted.
*/
int find_next(id,cur_fcn)
char *id;
P_NAME cur_fcn;
{
int cur_ch;
BOOL find_word(),
is_valid(),
seen();
void scan(),
error();
while(TRUE)
{
cur_ch = getc(infile);
if(is_valid(cur_ch))
{