home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 6 / FreshFish_September1994.bin / new / dev / c / hce / examples / clib / cflow / cflow.c < prev    next >
C/C++ Source or Header  |  1992-09-02  |  21KB  |  836 lines

  1. /* CFLOW.C - A C Function Call Chart Generator
  2.  *
  3.  * Version 1.00         December 21st, 1986
  4.  *
  5.  * SYNOPSIS:
  6.  *
  7.  * CFLOW accepts C source code via the standard input and
  8.  * produces a listing of the hierarchy of C function calls
  9.  * on the standard output. Recursive functions are explicitly
  10.  * identified in the listing. The command line format is:
  11.  *
  12.  *      CFLOW < source_file
  13.  *
  14.  * The output listing identifies all functions in the source
  15.  * code and the functions they call (#include files are not
  16.  * recognized). If only specific functions are of interest,
  17.  * (e.g. - fcn1, fcn2, fcn3), a listing for these functions
  18.  * only and the functions they call can be specified with the
  19.  * command line:
  20.  *
  21.  *      CFLOW < source_file fcn1 fcn2 fcn3
  22.  *
  23.  * MODIFICATIONS:
  24.  *
  25.  *   V1.00        - beta test release
  26.  *
  27.  * Adapted from:  "CALLS.C"
  28.  *                The C Programming Tutor
  29.  *                L.A. Wortman & T.O. Sidebottom
  30.  *                Prentice Hall Publishing
  31.  *
  32.  * Adaptation by: Ian Ashdown
  33.  *                byHeart Software
  34.  *                620 Ballantree Road
  35.  *                West Vancouver, B.C.
  36.  *                Canada V7S 1W3
  37.  *
  38.  * USAGE: CFLOW [function_name ...]
  39.  *
  40.  * DIAGNOSTICS:
  41.  *
  42.  * Exit status is 0 if no problems encountered, 2 otherwise.
  43.  *
  44.  * BUGS:
  45.  *
  46.  * Identifiers are limited to 32 characters in length.
  47.  * Recursive calling depth is set at 25.
  48.  *
  49.  **********************************************************************
  50.  *                          LAST CHANGES                              *
  51.  **********************************************************************
  52.  *
  53.  * 14 June, 1994 - Jason Petty
  54.  *
  55.  * Now checks if called from CLI or if invalid file, shows usage then exits
  56.  * with an error status. Does not use 'stdin' for input but instead
  57.  * requires user to specify a filename on the command line.
  58.  *
  59.  * To clear things up a bit here's the Usage:
  60.  *
  61.  *            CFLOW <source_filename> <function name 1> <funcn2> <funcn3>
  62.  *
  63.  * If called:  CFLOW <filename>
  64.  * without function name then the default is to list 'main()'. 
  65.  *
  66.  * Changes marked VANSOFT.
  67.  */
  68.  
  69. /*** INCLUDE FILES ***/
  70.  
  71. #include <stdio.h>
  72.  
  73. /*** DEFINITIONS ***/
  74.  
  75. #define BOOL            int
  76. #define DEFINED         1       /* Result of find_next() */
  77. #define DEFINING        0       /* Result of find_next() */
  78. #define FALSE           0
  79. #define HASH_TABLE_FULL -1      /* Indicates hash table overflow */
  80. #define HT_SIZE         1009    /* Must be a prime number */
  81. #define INDENT          "    "  /* Default output indentation */
  82. #define INDENT_SIZE     4       /* Number of spaces in indentation */
  83. #define MAXDEPTH        25      /* Maximum recursive-calling depth */
  84. #define MAXSYMLEN       32      /* Maximum significant characters
  85.                                    in a symbol */
  86. #define PGWIDTH         80      /* Default output page width */
  87. #define TRUE            1
  88.  
  89. /*** CODE MACROS ***/
  90.  
  91. #define GENERATE_NEW_INDEX(x,y)  (((x+y*y) % HT_SIZE)+1)
  92.  
  93. /*** TYPEDEFS ***/
  94.  
  95. typedef struct itype
  96. {
  97.   struct ntype *name_defn;      /* Name for this instance */
  98.   struct itype *next_callee;    /* Next instance called */
  99. }
  100. INSTANCE,
  101. *P_INSTANCE;
  102.  
  103. typedef struct ntype
  104. {
  105.   char fcn_name[MAXSYMLEN];    /* Unique function name */
  106.   int call_cnt,                /* Number of times function called */
  107.       first_num;               /* Line when function name first printed */
  108.   struct ntype *next_pname;    /* Next function name in the list */
  109.   P_INSTANCE first_callee;     /* Pointer to instance describing the
  110.                                 * first call for this function */
  111. }
  112. NAME,
  113. *P_NAME;
  114.  
  115. /*** GLOBAL VARIABLES ***/
  116.  
  117. int line_cnt = 0,       /* Line count */
  118.     maxact_index = 0,   /* Indexes active list from 0 to MAXDEPTH */
  119.     tabs_page = (PGWIDTH-MAXSYMLEN)/INDENT_SIZE,  /* Tabs per page */
  120.     bkt_cnt = 0;        /* Keeps track of the nesting of brackets. A
  121.                          * function found when "bkt_cnt" is zero
  122.                          * must be its DEFINING occurrence, since
  123.                          * function invocations must always appear
  124.                          * within some block of code. */
  125. char *hash_table[HT_SIZE];
  126. BOOL terse = TRUE;
  127. P_NAME name_head = NULL,
  128.        active_list[MAXDEPTH];      /* Used by output() to avoid */
  129.                                    /* infinite recursion */
  130.  
  131. FILE *infile=NULL;          /* Don't use stdin. Added, VANSOFT. */
  132. char *malloc();
  133. void usage();
  134.  
  135.  
  136. void usage(op) /* Added. VANSOFT. */
  137. int op;
  138. {
  139.  printf("\n\nCFLOW V1.0 - 21.12.86.\n");
  140.  printf("Authors:  L.A. Wortman, T.O. Sidebottom & Ian Ashdown.\n\n");
  141.  
  142.  printf("SYNOPSIS:\n");
  143.  printf("CFLOW accepts C source code via the standard input and\n");
  144.  printf("produces a listing of the hierarchy of C function calls\n");
  145.  printf("on the standard output. Recursive functions are explicitly\n");
  146.  printf("identified in the listing.\n\n");
  147.  
  148.  printf("USAGE:  CFLOW <source_file> <function_name1> <funcn2> <funcn3>\n\n");
  149.  
  150.  if(!op) /* exit error. */
  151.     exit(10);
  152. }
  153.  
  154. /*** MAIN BODY OF CODE ***/
  155.  
  156. int main(argc,argv)
  157. int argc;
  158. char *argv[];
  159. {
  160.   int actlist_index,
  161.       arg_index = 2,
  162.       fcn_use,
  163.       hashtbl_index;
  164.   char id[MAXSYMLEN];
  165.   P_NAME pcaller,
  166.          pname,
  167.          look_for(),
  168.          find_name();
  169.   BOOL insert_word();
  170.   void new_fcn(),
  171.        output(),
  172.        error();
  173.  
  174.      if(!argc)     /* May have been run from Workbench. VANSOFT. */
  175.         exit(10);
  176.      if(argc <= 1) /* Not enough args. VANSOFT. */
  177.         usage(NULL);
  178.  
  179.      if(!(infile = fopen(argv[1], "r"))) /* Added, VANSOFT. */
  180.            {
  181.             usage(1);  /* 1 = don't 'exit()' yet. */
  182.             fprintf(stdout, "%s: Can't access %s!\n\n",argv[0],argv[1]);
  183.             exit(10);  /* exit error. */ 
  184.             }
  185.  
  186.   /* Initialize the hash table */
  187.  
  188.   for(hashtbl_index = 0; hashtbl_index < HT_SIZE; hashtbl_index++)
  189.     hash_table[hashtbl_index] = NULL;
  190.  
  191.   /* The following are keywords that look like function calls in C */
  192.  
  193.   insert_word("for");
  194.   insert_word("if");
  195.   insert_word("return");
  196.   insert_word("sizeof");
  197.   insert_word("switch");
  198.   insert_word("while");
  199.  
  200.   /* Initialize the active list */
  201.  
  202.   for(actlist_index = 0; actlist_index < MAXDEPTH; )
  203.     active_list[actlist_index++] = NULL;
  204.  
  205.   /* Parse the input stream and build the appropriate tables */
  206.  
  207.   pcaller = NULL;
  208.   while((fcn_use = find_next(id,pcaller)) != EOF)
  209.     if(fcn_use == DEFINING)
  210.       pcaller = find_name(id);
  211.     else
  212.       new_fcn(id,pcaller);
  213.  
  214.   /* If there are any command line arguments, they are the names
  215.    * of the functions from which to begin the call charts.
  216.    */
  217.  
  218.   if(arg_index < argc)
  219.   {
  220.     do
  221.     {
  222.       if(pname = look_for(argv[arg_index]))
  223.       {
  224.         output(pname,NULL);
  225.         putchar('\n');
  226.       }
  227.       else
  228.         printf("\007\nERROR: Function %s not found.\n",
  229.             argv[arg_index]);
  230.     }
  231.     while((++arg_index) < argc)
  232.       ;
  233.   }
  234.   else
  235.   {
  236.     /* Print beginning with "main", if there is one */
  237.  
  238.     if(pname = look_for("main"))
  239.     {
  240.       output(pname,NULL);
  241.       putchar('\n');
  242.       pname->call_cnt = 1;  /* Don't print "main" again later */
  243.     }
  244.  
  245.     /* Now print all functions not called by anyone else */
  246.  
  247.     for(pname = name_head; pname; pname = pname->next_pname)
  248.       if(pname->call_cnt == NULL)
  249.       {
  250.         output(pname,NULL);
  251.         putchar('\n');
  252.       }
  253.  
  254.     /* Finally, print any mutually recursive functions */
  255.  
  256.     for(pname = name_head; pname; pname = pname->next_pname)
  257.       if(pname->first_num == NULL)
  258.       {
  259.         output(pname,NULL);
  260.         putchar('\n');
  261.       }
  262.   }
  263. }
  264.  
  265. /*** FUNCTIONS ***/
  266.  
  267. /* FIND_NEXT() - Sets its argument to the name of the next function
  268.  *               found in the input stream. It returns as its value
  269.  *               DEFINING if this is the defining occurrence of the
  270.  *               function, DEFINED if it is simply an invocation of
  271.  *               the function, and EOF if the input stream is
  272.  *               exhausted.
  273.  */
  274.  
  275. int find_next(id,cur_fcn)
  276. char *id;
  277. P_NAME cur_fcn;
  278. {
  279.   int cur_ch;
  280.   BOOL find_word(),
  281.        is_valid(),
  282.        seen();
  283.   void scan(),
  284.        error();
  285.  
  286.   while(TRUE)
  287.   {
  288.     cur_ch = getc(infile);
  289.     if(is_valid(cur_ch))
  290.     {
  291.