_AN AID TO DOCUMENTING C REVISITED_
by Ron Winter

[LISTING ONE]

/*********************************************************************
                                  cpheader.h
 *********************************************************************/

#include <malloc.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define  Max_unget_buffer        20000
#define  Max_general_buffers     3000
#define  MAX_functions           5000
/* #define  Max_functions           4000 */
#define  Max_defined_functions   1400
#define  Max_files               1400
#define  Max_Recursion           50

#define  false       0
#define  true        1
#define  completed   2

#define  Escape      0x1b
#define  Control_z   0x1a

/*********************************************************************/
typedef struct the_Pages
   {
   int               on_this_page;
   struct the_Pages  *next_page_ptr;
   }linked_pages_list;
/**********************************************************************/
typedef struct
   {
   char              *functions_name;
   char              *its_filename;
   int               is_referenced;
   int               static_function;
   }function_type;
/**********************************************************************/
typedef struct
   {
   char              *source_filename;
   char              *source_file_comment;
   unsigned int      line_count;
   long              size;
   }file_record_type;
/**********************************************************************/
typedef struct                   /* this is the main data base record */
   {
   file_record_type  *file_record_ptr;
   char              *defined_function;
   function_type     *ptr_to_function_table;
   int               number_of_function_calls;
   linked_pages_list *ptr_to_page_list;
   int               number_of_references;
   int               static_definition;
   int               overlay_number;
   }data_base_record_type;
/**********************************************************************/

#if MAIN != 0
/***********************************************************************/

function_type              /* 6 */
   **sorted_called_list_ptrs,
   *function_list,
   *function_list_ptr;
int
   Max_functions,
   count_of_functions = 0;
/********************************/
file_record_type           /* 14 */
   *file_record_array,
   *file_record_array_ptr;
int
   count_of_source_files = 0;
/********************************/
data_base_record_type      /* 20 */
   *data_base_array,
   *data_base_array_ptr,
   **array_of_unused_ptrs_to_records,
   **array_of_ptrs_to_records;
int
   count_of_valid_records = 0;
/********************************/

char *recursion_array[ Max_Recursion ];
int recursion_depth = 0;

char nesting_display_buffer[ Max_general_buffers ];

char target[ 40 ] = "main";
FILE *output = NULL;

char push_buffer[ Max_unget_buffer ] = { 0, 0, 0, 0 };
char *push_buffer_ptr;

char file_comment_buffer[ Max_general_buffers ];
int first_comment;

int effective_width;

int
   page = 1,
   line = 0,
   defined_page_width =    80,
   defined_page_length =   60,
   defined_left_margin =   1,
   defined_right_margin =  1,
   stats_only =      false,
   g_lib_flag =      false,
   g_comment_flag =  false,
   g_dec_def_flag =  false,
   g_help_flag =     false,
   ibm_flag =        true,
   g_quiet_flag =    false,
   g_tech_flag =     false,
   g_ov_flag =       false,
   g_un_flag =       false,
   target_flag =     false;
int top_of_form_done;
char title[] =
/*       mm/dd/yy0 hh:mm:ss0 */
      { "                    C PRINTER - (c) 1987, 1988 rev. 1.3" };

/********************************************************************/

#else
/*********************************************************************/

extern function_type
   **sorted_called_list_ptrs,
   *function_list,
   *function_list_ptr;
extern file_record_type
   *file_record_array,
   *file_record_array_ptr;
extern data_base_record_type
   *data_base_array,
   *data_base_array_ptr,
   **array_of_unused_ptrs_to_records,
   **array_of_ptrs_to_records;
extern char *recursion_array[ ];
extern int
   count_of_valid_records,
   Max_functions,
   count_of_functions,
   count_of_source_files;
extern int page, line, recursion_depth;
extern int first_comment;
extern char nesting_display_buffer[ ];
extern char top_bottom_line_of_box[ ];
extern FILE *output;
extern char push_buffer[ ];
extern char *push_buffer_ptr;
extern char file_comment_buffer[ ];
extern int defined_page_width;
extern int defined_page_length;
extern int defined_left_margin;
extern int defined_right_margin;
extern int effective_width;
extern char target[ ];
extern int
   stats_only,
   g_lib_flag,
   g_comment_flag,
   g_dec_def_flag,
   g_help_flag,
   ibm_flag,
   g_quiet_flag,
   g_tech_flag,
   g_ov_flag,
   g_un_flag,
   target_flag;
extern int top_of_form_done;
extern char title[];
/*********************************************************************/

#endif
/**********************************************************************/

[LISTING TWO]

/*********************************************************************
                                     cp.c
  
static void near bump_line_count( void );
static void near do_top_of_page( void );
static void near deallocate_arrays( void );
static void near allocate_arrays( void );
static void near initialize_globals( void );
static void near build_records_from_list( FILE * );
static void near sort_the_data_base_array( void );
static void near count_all_defined_references( void );
static void near show_function_relationships( void );
static void near show_line_and_byte_counts( void );
static void near show_sorted_function_list( void );
static void near show_page_references( void );
static void near show_unused_if_any( );
static void near show_library_functions( void );
static void near show_files_leading_comments( );
       int       main( int, char ** );

 ***************************************************************************/

#define  MAIN  1
#include "cpheader.h"
#include "time.h"

extern int  near binary_search_sorted_data_base( char * );
extern void near build_box_parts( int );
extern int  near build_the_data_base( char *, char * );
extern void near check_for_new_page( void );
extern int  near doprint( int );
extern void near nasty( int );
extern void near process_arguments( int, int, char **, int );
extern void near scan_for_static_or_global( int *, int, char *, char * );
extern void near tab_to_left_margin( FILE * );

static void near allocate_arrays( void );
static void near build_records_from_list( FILE * );
static void near bump_line_count( void );
static void near count_all_defined_references( void );
static void near deallocate_arrays( void );
static void near do_top_of_page( void );
static void near initialize_globals( void );
static void near show_files_leading_comments( void );
static void near show_function_relationships( void );
static void near show_library_functions( void );
static void near show_line_and_byte_counts( void );
static void near show_page_references( void );
static void near show_sorted_function_list( void );
static void near show_unused_if_any( void );
static void near sort_the_data_base_array( void );
       int       main( int, char ** );

/***************************************************************************/

static void near bump_line_count( )
{
top_of_form_done = false;
++line;
check_for_new_page();
tab_to_left_margin( output );
}
/***************************************************************************/
static void near do_top_of_page( )
{
if( !top_of_form_done )
   {
   top_of_form_done = true;
   line = 9999;
   check_for_new_page();
   tab_to_left_margin( output );
   }
}
/***************************************************************************/
static void near deallocate_arrays( )
{
if( function_list )
   free( function_list );
if( file_record_array )
   free( file_record_array );
if( data_base_array )
   free( data_base_array );
if( sorted_called_list_ptrs )
   free( sorted_called_list_ptrs );
if( array_of_ptrs_to_records )
   free( array_of_ptrs_to_records );
}
/***************************************************************************/

static void near allocate_arrays( )
{
unsigned long length;

length = (unsigned long)Max_functions * sizeof( function_type );
if( length > 65535 )
   {
   (void)printf( "too many called functions ( go to huge model code )\n" );
   exit( 1 );
   }
else
   if(
      !( function_list =
         (function_type *)malloc( (unsigned int)length )
       )
     )
      {
      (void)printf( "No room for function_list\n" );
      exit( 1 );
      }
   else
      {
      if( !g_quiet_flag && g_tech_flag )
         (void)printf( "function list = %lu bytes long\n", length );
      }

length = (unsigned long)Max_files * sizeof( file_record_type );
if( length > 65535 )
   {
   (void)printf( "too many files ( go to huge model code )\n" );
   exit( 1 );
   }
else
   if(
      !( file_record_array =
         (file_record_type *)malloc( (unsigned int)length )
       )
     )
      {
      (void)printf( "No room for file_record_array\n" );
      exit( 1 );
      }
   else
      {
      if( !g_quiet_flag && g_tech_flag )
         (void)printf( "file record array = %lu bytes long\n", length );
      }

length =
   (unsigned long)Max_defined_functions * sizeof( data_base_record_type );
if( length > 65535 )
   {
   (void)printf( "too many defined functions ( go to huge model code )\n" );
   exit( 1 );
   }
else
   if(
      !( data_base_array =
         (data_base_record_type *)malloc( (unsigned int)length )
       )
     )
      {
      (void)printf( "No room for data_base_array\n" );
      exit( 1 );
      }
   else
      {
      if( !g_quiet_flag && g_tech_flag )
         (void)printf( "data base array = %lu bytes long\n", length );
      }

length =
   (unsigned long)Max_defined_functions * sizeof( data_base_record_type * );
if( length > 65535 )
   {
   (void)printf(
            "too many defined functions pointers( go to huge model code )\n"
               );
   exit( 1 );
   }
else
   if(
      !( array_of_ptrs_to_records =
         (data_base_record_type **)malloc( (unsigned int)length )
       )
     )
      {
      (void)printf( "No room for *array_of_ptrs_to_records\n" );
      exit( 1 );
      }
   else
      {
      if( !g_quiet_flag && g_tech_flag )
         (void)printf( "array of ptrs to data base = %lu bytes long\n",
                        length );
      }

length = (unsigned long)Max_functions * sizeof( function_type * );
if( length > 65535 )
   {
   (void)printf(
      "too many called function ptrs ( go to huge model code )\n"
               );
   exit( 1 );
   }
else
   if(
      !( sorted_called_list_ptrs =
            (function_type **)malloc( (unsigned int)length )
       )
     )
      {
      (void)printf( "No room for ptr function_list\n" );
      exit( 1 );
      }
   else
      {
      if( !g_quiet_flag && g_tech_flag )
         (void)printf( "sorted called list ptrs = %lu bytes long\n", length );
      }
}
/***************************************************************************/

static void near initialize_globals( )
{
int i;
char *cp;

function_list_ptr = function_list;
data_base_array_ptr = data_base_array;
file_record_array_ptr = file_record_array;

for( i = 0; i < Max_Recursion; ++i )
   recursion_array[ i ] = NULL;
build_box_parts( ibm_flag );
effective_width =             /******** set global output width ***********/
   defined_page_width - defined_left_margin - defined_right_margin;
if( effective_width < 40 )
   {
   (void)printf( "\nThe page width is too narrow( needs > 40 )." );
   exit( 1 );
   }

cp = &title[ 0 ];    /* insert date and nice time into title */
(void)_strdate( cp );
title[ 8 ] = ' ';
cp = &title[ 10 ];
(void)_strtime( cp );

title[ 15 ] = ' ';   /* knock off seconds */
title[ 16 ] = ' ';   /* put am, pm here */
title[ 17 ] = 'm';
title[ 18 ] = ' ';

i = atoi( &title[ 10 ] );  /* f/ military to civilian time */
title[ 16 ] = ( i < 12 )? (char)'a': (char)'p';

if( i == 0 )
   i = 12;
if( i >= 13 )
   i -= 12;

(void)sprintf( &title[ 10 ], "%2d", i );
title[ 12 ] = ':';

if( title[ 10 ] == '0' )
   title[ 10 ] = ' ';
}
/***********************************************************************/
static void near build_records_from_list( stream )
FILE  *stream;
{
char input_list_filename[ 129 ], input_line[ 129 ], overlay_number[ 129 ];
int l;

while( !feof( stream ) )
   {
   input_list_filename[ 0 ] = '\0';
   input_line[ 0 ] = '\0';
   overlay_number[ 0 ] = '\0';
   fgets( input_line, 128, stream );   /* ends at \n or eof */

   if(
      ( l = strlen( input_line ) ) > 1    /* ie not nul string */
     )
      {
      if( input_line[ l - 1 ] == '\n' )
         input_line[ l - 1 ] = '\0';

      l = sscanf( input_line, " %s %s ",
                  input_list_filename, overlay_number
                );
      if( !g_quiet_flag && g_tech_flag )
         {
         (void)printf( "pathname = %s ", input_list_filename );
         if( l )
            (void)printf( "overlay # = %s ", overlay_number );
         }
      (void)build_the_data_base( input_list_filename, overlay_number );
      }
   }
}
/***************************************************************************/

static void near sort_the_data_base_array( )
{
int i, still_sorting_flag;

for( i = 0, data_base_array_ptr = data_base_array;
     i < count_of_valid_records;
     ++i
   )
   array_of_ptrs_to_records[ i ] = data_base_array_ptr++;

if( !g_quiet_flag )
   {
   (void)printf( "\n\nSorting the function list...\n" );
   (void)printf( " of %d functions\n", count_of_valid_records );
   }
still_sorting_flag = true;
while( still_sorting_flag )
   {
   still_sorting_flag = false;
   if( !g_quiet_flag )
      {
      (void)printf( "." );
      }
   for( i = 0; i < count_of_valid_records - 1; ++i )
      {
      if( strcmp( array_of_ptrs_to_records[ i ]->defined_function,
                  array_of_ptrs_to_records[ i + 1 ]->defined_function ) > 0 )
         {
         still_sorting_flag = true;
         data_base_array_ptr = array_of_ptrs_to_records[ i ];
         array_of_ptrs_to_records[ i ] = array_of_ptrs_to_records[ i + 1 ];
         array_of_ptrs_to_records[ i + 1 ] = data_base_array_ptr;
         }
      }
   }
}
/************************************************************************/

static void near count_all_defined_references()
{
register int count;
int found;
register function_type *f_list_ptr;

f_list_ptr = function_list;         /* the full list */

for( count = 0; count < count_of_functions; ++count )
   {
   found = binary_search_sorted_data_base( f_list_ptr->functions_name );
   if( found >= 0 )
      scan_for_static_or_global( &found,
                                 f_list_ptr->static_function,
                                 f_list_ptr->functions_name,
                                 f_list_ptr->its_filename
                               );
   if( found >= 0 )
      array_of_ptrs_to_records[ found ]->number_of_references +=
         f_list_ptr->is_referenced;
   ++f_list_ptr;        /* for all defined functions */
   }
if( !g_quiet_flag && g_dec_def_flag )
   (void)printf( "\n" );
}
/***************************************************************************/

static void near show_function_relationships( )
{
int found;
int record_index;

found = binary_search_sorted_data_base( target );/* w/o knowing filename */
                  /* note if static, will find random one if more than */
                  /* one with same name */
if( found >= 0 )
   {
   recursion_depth = 0;
   if( !g_quiet_flag )
      {
      (void)printf( "Checking for usage...\n" );
      }
   count_all_defined_references();
   nesting_display_buffer[ 0 ] = '\0';
   if( !g_quiet_flag )
      {
      (void)printf( "Starting the printout...\n" );
      }
   if( !target_flag )               /* main is only called once */
      array_of_ptrs_to_records[ found ]->number_of_references = 1;
   line = 0;
   if( !stats_only )
      {
      (void)doprint( found );       /* of target function */
      for( record_index = 0;
           record_index < count_of_valid_records;
           ++record_index
         )
         {
         (void)fprintf( output, "\n" );
         ++line;
         if( array_of_ptrs_to_records[ record_index ]->number_of_references >
             1
           )
            (void)doprint( record_index );
         }
      }
   }
else        /* cant find target */
   {
   (void)printf( "cant find %s, exitting\n", target );
   exit( 1 );
   }
}
/***************************************************************************/

static void near show_line_and_byte_counts( )
{
long int total_byte_count;
long int total_line_count;
int i;

file_record_array_ptr = file_record_array;

do_top_of_page();
(void)fprintf( output, "File statistics:\n" );
bump_line_count();
total_byte_count = 0l;
total_line_count = 0l;
for( i = 0; i < count_of_source_files; ++i )
   {
   (void)fprintf( output,
                  "%-40s - %8u lines, %12ld bytes\n",
                  file_record_array_ptr->source_filename,
                  file_record_array_ptr->line_count,
                  file_record_array_ptr->size
                );
   bump_line_count();

   total_byte_count += file_record_array_ptr->size;
   total_line_count += file_record_array_ptr->line_count;
   ++file_record_array_ptr;
   }
(void)fputc( '\n', output );
bump_line_count();
(void)fprintf( output, "Totals:\n" );
bump_line_count();
/********                       "%-40s - %8u lines, %12ld bytes\n", *******/
(void)fprintf( output, "%4d files%-30s - %8ld lines, %12ld bytes\n",
               count_of_source_files, " ", total_line_count, total_byte_count
             );
bump_line_count();
(void)fputc( '\n', output );
bump_line_count();
(void)fprintf( output,
               " %d defined functions found.\n", count_of_valid_records
             );
bump_line_count();
(void)fprintf( output, "Averages:\n" );
bump_line_count();
(void)fprintf( output,
               "%6d lines/file, %6d functions/file, %6d lines/function\n",
               (int)( total_line_count / count_of_source_files ),
               (int)( count_of_valid_records / count_of_source_files ),
               (int)( total_line_count / count_of_valid_records )
             );
}
/***************************************************************************/

static void near show_sorted_function_list( )
{
int i, record_index;
long reference_total = 0;

do_top_of_page();

(void)fprintf( output, "Function index:\n" );
bump_line_count();

if( g_ov_flag )
   (void)fprintf( output, "%-39s %-28s %s %s\n",
                  "function", "in file", "ov#", "refs" );
else
   (void)fprintf( output, "%-39s %-28s    %s\n",
                  "function", "in file", "refs" );

bump_line_count();

for( i = 0; i < effective_width; ++i )
   (void)fputc( '_', output );
(void)fprintf( output, "\n" );
bump_line_count();

for( record_index = 0;
     record_index < count_of_valid_records;
     ++record_index
   )
   {
   data_base_array_ptr = array_of_ptrs_to_records[ record_index ];
   if( data_base_array_ptr->number_of_references > 0 )
      {   
      if( g_ov_flag && data_base_array_ptr->overlay_number )
         (void)fprintf( output, "%-7s%-32s %-28s %3d %d\n",
                        ( data_base_array_ptr->static_definition )?
                        "static": "",
                        data_base_array_ptr->defined_function,
                  ( data_base_array_ptr->file_record_ptr )->source_filename,
                        data_base_array_ptr->overlay_number,
                        data_base_array_ptr->number_of_references
                      );
      else
         (void)fprintf( output, "%-7s%-32s %-28s     %d\n",
                        ( data_base_array_ptr->static_definition )?
                        "static": "",
                        data_base_array_ptr->defined_function,
                  ( data_base_array_ptr->file_record_ptr )->source_filename,
                        data_base_array_ptr->number_of_references
                      );
      reference_total += (long)data_base_array_ptr->number_of_references;
      bump_line_count();
      }
   }
(void)fprintf( output, "%-7s%-32s %-28s     %s\n",
               " ", " ", " ", "____"
             );
bump_line_count();
(void)fprintf( output, "%-7s%-32s %-28s     %ld\n",
               " ", " ", "total ", reference_total
             );
bump_line_count();
}
/***************************************************************************/

static void near show_page_references( )
{
int pmax;          /* max x ref columns */
int i, pcnt;
linked_pages_list *p;

if( !stats_only && ( defined_page_length > 0 ) )
   {
   pmax = (int)( effective_width - 7 - 32 - 2 ) / 5;
   do_top_of_page();
   (void)fprintf( output, "Function cross reference:\n" );
   bump_line_count();

   for( i = 0; i < count_of_valid_records; ++i )
      {
      data_base_array_ptr = array_of_ptrs_to_records[ i ];
      if( data_base_array_ptr->number_of_references > 0 )
         {
         (void)fprintf( output, "%-7s%-32s- ",
                        ( data_base_array_ptr->static_definition )?
                        "static": "",
                        data_base_array_ptr->defined_function );
         p = data_base_array_ptr->ptr_to_page_list;
         if( p )
            {
            pcnt = 0;
            while( p->next_page_ptr )
               {
               (void)fprintf( output, "%4d,", p->on_this_page );
               p = p->next_page_ptr;
               ++pcnt;
               if( pcnt >= pmax )
                  {
                  (void)fputc( '\n', output );
                  bump_line_count();
                  (void)fprintf( output, "%7s%32s  ", " ", " " );
                  pcnt = 0;
                  }
               }
            (void)fprintf( output, "%4d\n", p->on_this_page );
            }
         else
            (void)fprintf( output, "\n" );
         bump_line_count();
         }
      }
   }
}
/***************************************************************************/

static void near show_unused_if_any( )
{
int i, unused_count, unused_index, count, still_sorting_flag;
data_base_record_type **unused_list_ptr_ptr, *unused_list_ptr;

do_top_of_page();
(void)fprintf( output, "Un-used function list:\n" );
bump_line_count();

unused_count = 0;
for( i = 0; i < count_of_valid_records; ++i )
   {
   data_base_array_ptr = array_of_ptrs_to_records[ i ];
   if( !data_base_array_ptr->number_of_references )
      {
      ++unused_count;
      if( !g_un_flag )
         {
         (void)fprintf( output,
                        "%-7s%-32s- %-33s\n",
                        ( data_base_array_ptr->static_definition )?
                        "static": "",
                        data_base_array_ptr->defined_function,
                     ( data_base_array_ptr->file_record_ptr )->source_filename
                      );
         bump_line_count();
         }
      }
   }
if( g_un_flag )               /* show sorted */
   {
   if( unused_count )
      {
      if(
         !( array_of_unused_ptrs_to_records =
            (data_base_record_type **)malloc( (unsigned int)unused_count )
          )
        )
         (void)printf( "No room for *array_of_unused_ptrs_to_records\n" );
      else
         {
         unused_index = 0;
         for( i = 0; i < count_of_valid_records; ++i )
            {
            data_base_array_ptr = array_of_ptrs_to_records[ i ];
            if( !data_base_array_ptr->number_of_references )
               {                    /* first just collect them */
               array_of_unused_ptrs_to_records[ unused_index++ ] =
                  data_base_array_ptr;
               }
            }                 /* so now there are unused_index of them */
         unused_list_ptr_ptr = array_of_unused_ptrs_to_records;
         still_sorting_flag = true;
         if( unused_count > 1 )
            {
            while( still_sorting_flag )
               {
               still_sorting_flag = false;
               if( !g_quiet_flag && g_tech_flag )
                  (void)printf( ".%d   \r", count );
               for( count = 0; count < unused_count - 1; ++count )
                  {
                  if( strcmp( unused_list_ptr_ptr[ count ]->
                              file_record_ptr->source_filename,
                              unused_list_ptr_ptr[ count + 1 ]->
                              file_record_ptr->source_filename
                            ) > 0
                    )
                     {
                     still_sorting_flag = true;
                     unused_list_ptr = unused_list_ptr_ptr[ count ];
                     unused_list_ptr_ptr[ count ] =
                        unused_list_ptr_ptr[ count + 1 ];
                     unused_list_ptr_ptr[ count + 1 ] = unused_list_ptr;
                     }
                  }
               }
            }
         for( i = 0; i < unused_count; ++i )
            {
            (void)fprintf( output,
                           "%-7s%-32s- %-33s\n",
                           ( unused_list_ptr_ptr[ i ]->static_definition )?
                           "static": "",
                           unused_list_ptr_ptr[ i ]->defined_function,
               ( unused_list_ptr_ptr[ i ]->file_record_ptr )->source_filename
                         );
            bump_line_count();
            }
         }
      }
   }
if( !unused_count )
   {
   tab_to_left_margin( output );
   (void)fprintf( output, "No un-used functions in the list.\n" );
   bump_line_count();
   }
else
   {
   (void)fprintf( output, "%-7s%-39s- %d\n", "", "totals", unused_count );
   bump_line_count();
   }
}
/************************************************************************/

static void near show_library_functions( )
{
register int count;
int found, total, still_sorting_flag, x_count, final_count, final_call;
function_type **f_list_ptr_ptr, *f_list_ptr;

if( g_lib_flag )
   {
   if( !g_quiet_flag && g_tech_flag )
      (void)printf( "collecting library functions...\n" );
   do_top_of_page();
   (void)fprintf( output, "Library functions:\n" );
   bump_line_count();

   total = 0;
   f_list_ptr = function_list;
   for( count = 0; count < count_of_functions; ++count )
      {
      if( !f_list_ptr->static_function )
         {
         if(
            ( found =
              binary_search_sorted_data_base( f_list_ptr->functions_name )
            ) < 0
           )
            sorted_called_list_ptrs[ total++ ] = f_list_ptr;
         }
      ++f_list_ptr;        /* for all called functions */
      }

   if( !g_quiet_flag && g_tech_flag )
      (void)printf( "gathering identical library functions...\n" );
   final_count = total;    /* number of calls to be collected and sorted */
   f_list_ptr_ptr = sorted_called_list_ptrs;
   for( count = 0; count < ( total - 1 ); ++count )
      {
      for( x_count = count + 1; x_count < total; ++x_count )
         {
         if( ( f_list_ptr_ptr[ count ]->functions_name[ 0 ] != '\0' ) &&
             !strcmp( f_list_ptr_ptr[ count ]->functions_name,
                      f_list_ptr_ptr[ x_count ]->functions_name )
           )
            {
            f_list_ptr_ptr[ count ]->is_referenced +=
               f_list_ptr_ptr[ x_count ]->is_referenced;
            f_list_ptr_ptr[ x_count ]->functions_name[ 0 ] = '\0';
            --final_count;
            }
         }
      }

   if( !g_quiet_flag && g_tech_flag )
      {
      (void)printf( "\nSorting the library function calls...\n" );
      }

   f_list_ptr_ptr = sorted_called_list_ptrs;
   still_sorting_flag = true;
   while( still_sorting_flag )
      {
      still_sorting_flag = false;
      if( !g_quiet_flag && g_tech_flag )
         (void)printf( ".%d   \r", count );
      for( count = 0; count < total - 1; ++count )
         {
         if( strcmp( f_list_ptr_ptr[ count ]->functions_name,
                     f_list_ptr_ptr[ count + 1 ]->functions_name ) > 0 )
            {
            still_sorting_flag = true;
            f_list_ptr = f_list_ptr_ptr[ count ];
            f_list_ptr_ptr[ count ] = f_list_ptr_ptr[ count + 1 ];
            f_list_ptr_ptr[ count + 1 ] = f_list_ptr;
            }
         }
      }
   if( !g_quiet_flag && g_tech_flag )
      (void)printf( "\n" );

   (void)fprintf( output, "%-32s %-28s\n",
                  "library function", "calls" );
   bump_line_count();

   for( count = 0; count < effective_width; ++count )
      (void)fputc( '_', output );
   (void)fprintf( output, "\n" );
   bump_line_count();

   final_call = 0;
   f_list_ptr_ptr = sorted_called_list_ptrs;
   for( count = 0; count < total; ++count )
      {
      if( ( *f_list_ptr_ptr )->functions_name[ 0 ] != '\0' )
         {
         (void)fprintf( output, "%-32s %d\n",
                        ( *f_list_ptr_ptr )->functions_name,
                        ( *f_list_ptr_ptr )->is_referenced
                      );
         final_call += ( *f_list_ptr_ptr )->is_referenced;
         bump_line_count();
         }
      ++f_list_ptr_ptr;
      }
   (void)fprintf( output, "Totals:\n" );
   bump_line_count();
   (void)fprintf( output, "%6d %-25s %d calls.\n",
                  final_count, "library functions,", final_call
                );
   bump_line_count();
   }
}
/************************************************************************/

static void near show_files_leading_comments( )
{
int i;
char *cp;

if( g_comment_flag )
   {
   do_top_of_page();
   (void)fprintf( output, "File comments:\n" );
   bump_line_count();
   file_record_array_ptr = file_record_array;
   for( i = 0; i < count_of_source_files; ++i )
      {
      (void)fprintf( output, "%40s\n",
                     file_record_array_ptr->source_filename
                   );
      bump_line_count();
      cp = file_record_array_ptr->source_file_comment;
      while( *cp )
         {
         (void)fprintf( output, "%c", *cp );
         if( *++cp == '\n' )
            {
            bump_line_count();
            }
         }
      ++file_record_array_ptr;   
      do_top_of_page();          /* one page per comment at least */
      }
   }
}
/**********************************************************************/

int main( argc, argv )
char **argv;
int argc;
{
int   index, in_error = false, out_error = false;
FILE  *stream;

nasty( argc );

(void)printf( "\ncp - ver. 1.3,  (C)1987, 1988  Stewart A. Nutter\n" );
(void)printf( "    extended and corrected by  Ron Winter\n" );

index = 1;
if( !( stream = fopen( argv[ index ], "rt" ) ) )
   in_error = true;
else
   ++index;
if(
   ( argc > index ) &&
   (
    ( argv[ index ][ 0 ] != '/' ) && ( argv[ index ][ 0 ] != '-' )
   )
  )
   {
   output = fopen( argv[ 2 ], "w+" );     /******* wt+ <<<<<<<< ******/
   ++index;
   }
else
   output = fopen( "prn", "w+" );         /******** wt+ <<<<<< ********/

if( !output )
   out_error = true;

Max_functions = MAX_functions;
process_arguments( index, argc, argv, in_error || out_error );
if( in_error )
   {
   (void)printf( "\n can't open input list %s\n", argv[ 1 ] );
   exit( 1 );
   }
if( out_error )
   {
   (void)printf( "\n can't open output file, error %s\n", strerror( errno ) );
   exit( 1 );
   }
allocate_arrays( );
initialize_globals( );
(void)printf( "\n" );

build_records_from_list( stream );
sort_the_data_base_array( );
if( !g_quiet_flag )
   {
   (void)printf( "\n" );
   }
top_of_form_done = false;
show_function_relationships( );
show_page_references( );
show_line_and_byte_counts( );
show_sorted_function_list( );
show_unused_if_any( );
show_library_functions( );
show_files_leading_comments( );
deallocate_arrays( );

/************* done *****************/
(void)fprintf( output, "%c", 0x0c );   /* ff */

return false;     /* ok */
}
/********************************************************************/


[LISTING THREE]

/***********************************************************************
                                   cpinput.c
       void near nasty( int );
       void near process_arguments( int, int, char **, int );
************************************************************************/
#define  MAIN  0
#include "cpheader.h"

       void near nasty( int );
       void near process_arguments( int, int, char **, int );
/************************************************************************/

void near nasty( argc )
int argc;
{
if( argc < 2 )
   {
   (void)printf( "\ncp listfile [ outfile ] [\n" );
   (void)printf(
   "     /p:nn /w:nn /m:nn /r:nn /t:main /f:nnnn\n"
               );
   (void)printf(
   "     /l /n /s /q /d /c /h /x\n"
               );
   (void)printf(   "                        ]\n\n" );
   (void)printf(
   "     outfile            = prn\n" );
   (void)printf(
   "    p: page length      = %3d   [ 0, 50 -255 ]\n", defined_page_length
               );
   (void)printf(
   "     w: page width      = %3d   [ 80 - 255 ]\n", defined_page_width
               );
   (void)printf(
   "     m: left margin     = %2d    [ 0 - 30 ]\n", defined_left_margin
               );
   (void)printf(
   "     r: right margin     = %2d    [ 0 - 30 ]\n", defined_right_margin
               );
   (void)printf(
   "     t: target function  = %s\n", target
               );
   (void)printf(
   "     f: # of function calls = %4d    [ 2 - 5461 ]\n", MAX_functions
               );
   (void)printf(
   "     n: normal characters( ie not ibm character graphics )\n"
               );
   (void)printf(
   "     l  output library functions\n"
               );
   (void)printf(
   "     c  output file\'s 1st comment\n"
               );
   (void)printf(
   "     s  output statistics only\n"
               );
   (void)printf(
   "     d  show declarations and definitions\n"
               );
   (void)printf(
   "     o  show overlay information\n"
               );
   (void)printf(
   "     u  show unused sorted by filename\n"
               );
   (void)printf(
   "     q  show no messages\n"
               );
   (void)printf(
   "     h  show more help\n"
               );
   (void)printf(
   "     x  show tech info\n"
               );

   (void)printf( "\n" );
   exit( 0 );
   }
}
/**********************************************************************/
void near process_arguments( index, argc, argv, an_error )
int index, argc, an_error;
char **argv;
{
char c;
int i, tmp;

for( i = index; i < argc; ++i )
   {
   if( ( argv[ i ][ 0 ] == '/' ) || ( argv[ i ][ 0 ] == '-' ) )
      {
      c = (char)tolower( (int)argv[ i ][ 1 ] );
      switch( c )
         {
         case 'n':
            ibm_flag = ( ibm_flag )? false: true;
            break;
         case 'l':
            g_lib_flag = ( g_lib_flag )? false: true;
            break;
         case 'c':
            g_comment_flag = ( g_comment_flag )? false: true;
            break;
         case 'd':
            g_dec_def_flag = ( g_dec_def_flag )? false: true;
            break;
         case 's':
            stats_only = ( stats_only )? false: true;
            break;
         case 'q':
            g_quiet_flag = ( g_quiet_flag )? false: true;
            break;
         case 'o':
            g_ov_flag = true;
            break;
         case 'u':
            g_un_flag = true;
            break;
         case 'h':
            g_help_flag = true;
            break;
         case 'x':
            g_tech_flag = true;
            break;
         default:
          if( ( strlen( argv[ i ] ) > 3 ) && ( argv[ i ][ 2 ] == ':' ) )
              {
               tmp = atoi( &argv[ i ][ 3 ] );
               switch( c )
                  {
                  case 'p':
                   if( ( ( 50 < tmp ) && ( tmp < 256 ) ) || ( tmp == 0 ) )
                       defined_page_length = tmp;
                   break;
                  case 'm':
                     if( ( 0 <= tmp ) && ( tmp <= 30 ) )
                        defined_left_margin = tmp;
                     break;
                  case 'r':
                     if( ( 0 <= tmp ) && ( tmp <= 30 ) )
                        defined_right_margin = tmp;
                     break;
                  case 't':
                     (void)strcpy( target, &argv[ i ][ 3 ] );
                     target_flag = true;
                     break;
                  case 'w':
                     if( ( 79 < tmp ) && ( tmp < 256 ) )
                        defined_page_width = tmp;
                     break;
                  case 'f':
                     if( ( 1 < tmp ) && ( tmp < 5462 ) )
                        Max_functions = tmp;
                     break;
                  default:
                     (void)printf(
                         "\nUnknown argument character: %c, ignored!\n",
                           argv[ i ][ 1 ]
                              );
                     break;
                  }  /* end of switch on character after / or - */
               }     /* end of if :something */
            else
               (void)printf( "\nMissing : for argument %s, ignored!\n",
                             argv[ i ] );
            break;
         }           /* end of switch on character after / or - */
      }              /* end of if / or - */
   else
      (void)printf( "\nUnknown argument: %s, ignored!\n", argv[ i ] );
   }                 /* end of for loop on arguments */

if( g_tech_flag )
   {
   (void)printf( "\n" );
   (void)printf( "Notes: 1. Max recursive function displacement of %d.\n",
                 Max_Recursion
               );
   (void)printf(
"         2. Max # of unique function calls per defined function\n\
            for all defined functions is %d.\n",
   Max_functions );
   (void)printf( "         3. Max # of defined functions is %d.\n",
      Max_defined_functions );
   (void)printf( "\n" );
   (void)printf( "sizeof()\'s:\n" );
   (void)printf(
" function table = %u, contents = %u, data base = %u,\
 database = %u, lib = %u\n",
      sizeof( function_type ),
      sizeof( file_record_type ),
      sizeof( data_base_record_type ),
      sizeof( array_of_ptrs_to_records ),
      sizeof( sorted_called_list_ptrs )
               );
   (void)printf( "\n" );
   (void)printf(
   "The program will tend to show certain \'c\' functions as unused.\n" );
   (void)printf(
   "1. defined functions assigned to declared pointers to function names\n" );
   (void)printf(
   "   and executed as pointers to those function names won't be seen.\n" );
   (void)printf(
   "2. #if(s) controlling the generation of code especially with\n" );
   (void)printf(
   "   braces( { } ) in the conditional code section will especially\n" );
   (void)printf(
   "   screw up if there is an #else code part.  This program will work\n" );
   (void)printf(
   "   on both code parts of the conditional and most probably get out\n" );
   (void)printf(
   "   of sync with the braces. One might do a preprocessor pass compile\n" );
   (void)printf(
   "   and heave it\'s output files as input files at this program.\n" );
   (void)printf(
   "3. #define(s) that expand to functions and call functions will also\n" );
   (void)printf(
   "   be neglected.  The preprocessor may be used as stated above.\n" );
/******
   (void)printf(
   "\n" );
******/
   (void)printf( "\n" );
   }

if( g_help_flag )
   {
   (void)printf( "\n" );
   (void)printf(
   "The listfile argument is an ascii text file containing the list of\n"
               );
   (void)printf(
   "filenames to process, one filename per line (optional overlay number.)\n"
               );
   (void)printf(
   "The output file may be a device or a filename. If there is no\n"
               );
   (void)printf(
   "output filename, \'prn\' is assumed. Note that one may put \'con\'\n"
               );
   (void)printf(
   "here and view the output of the program before printing or saving\n"
               );
   (void)printf(
   "to a filename.\n"
               );
   (void)printf(
   "Also note that the output filename and the input filenames in the\n"
               );
   (void)printf(
   "listfile may be full pathnames with drives and or paths.\n"
               );
   (void)printf( "/ arguments accept the alternate - form.\n" );
   (void)printf( "For example: cp x y -s, cp /h, cp x -x /d -t:junk\n" );
   (void)printf( "arguments may be in upper or lower case.\n" );
   (void)printf( "Note that the target function is case sensitive\n" );
   (void)printf( "since it is a \'c\' function name.\n" );
   (void)printf( "\n" );
   }
if( an_error )
   {
   if( g_help_flag || g_tech_flag )
      exit( 0 );
   else
      (void)printf( "Oops..." );
   }
}
/***********************************************************************/


[LISTING FOUR]

/***************************************************************************
                                   cpbuild.c
static void near mark_as_static( function_type *, char*, int );
static int near  test_and_add( function_type *, char *, int );
static void near unget_chars( char );
static char near get_chars( FILE * );
static char near get_to_next_possible_token( FILE * );
static int near  is_legal_identifier_character( char );
       int near  build_the_data_base( char * );
***************************************************************************/

#define  MAIN  0
#include "cpheader.h"

       int near  build_the_data_base( char * );
static char near get_chars( FILE * );
static char near get_to_next_possible_token( FILE * );
static int near  is_legal_identifier_character( char );
static void near mark_as_static( function_type *, char*, int );
static int near  test_and_add( function_type *, char *, int );
static void near unget_chars( char );

/***************************************************************************/
static void near mark_as_static( ptr_to_function_list, 
                                 name_of_static_function, count
                               )
char *name_of_static_function;
function_type *ptr_to_function_list;
int count;
{
int i;

for( i = 0; i < count; ++i )
   {
   if(
      !strcmp( name_of_static_function, ptr_to_function_list->functions_name )
     )
      ptr_to_function_list->static_function = true;
   ++ptr_to_function_list;
   }
}
/***************************************************************************/
#define KEYS   7

static int near test_and_add( ptr_to_function_list, string, count )
function_type *ptr_to_function_list;
char *string;
int count;
{
int i, is_a_new_function_name;
static char *keywords[ KEYS ] =
   {  /* must catch do (void)printf, while(), else (void)... etc. ***/
   "do", "while", "if", "else", "for", "switch", "return"
   };

for( i = 0; ( i < KEYS ) && ( strcmp( string, keywords[ i ] ) != 0 ); ++i )
   ;
if( i < KEYS )
   is_a_new_function_name = false;     /* ie a reserved word match */
else                                   /* is a function name */
   {
   for( i = 0; i < count; ++i )
      {
      if( !strcmp( string, ptr_to_function_list->functions_name ) )
         {                       /* function name matches */
         if( !ptr_to_function_list->static_function )
            break;               /* and isn't static */
         else
            {
            if( !strcmp( ptr_to_function_list->its_filename,
                         file_record_array_ptr->source_filename
                      )
              )
               break;            /* only statics in same file match */
            }
         }
      ++ptr_to_function_list;
      }
   if( i == count )
      {                                /* new function name */
      is_a_new_function_name = true;   /* add function name to list */
      if( ( function_list_ptr->functions_name = strdup( string ) ) == NULL )
         {
         (void)fprintf( stderr, "Ran out of memory.\n" );
         exit( 1 );
         }
      function_list_ptr->static_function = false;
      function_list_ptr->its_filename =
         file_record_array_ptr->source_filename;
      function_list_ptr->is_referenced = 1;

      ++function_list_ptr;             /* point to next empty cell */
      ++count_of_functions;            /* increase current size */
      if( count_of_functions > Max_functions )
         {
         (void)fprintf( stderr, "Too many functions.\n" );
         exit( 1 );
         }
      }
   else                                /* string already in function list */
      {
      is_a_new_function_name = false;
      ptr_to_function_list->is_referenced++;
      }
   }
return is_a_new_function_name;
}
/***************************************************************************/
static void near unget_chars( c )
char c;
{
if( ( push_buffer_ptr - push_buffer ) < Max_unget_buffer )
   *push_buffer_ptr++ = c;
else
   {
   (void)fprintf( stderr, "\nProgram syntax error:" );
   (void)fprintf( stderr, " Too many pushed characters.\n" );
   exit( 1 );
   }
}
/***************************************************************************/
static char near get_chars( stream )
FILE * stream;
{
register char c;

if( push_buffer_ptr != push_buffer )
   c = *--push_buffer_ptr;
else
   {
   c = (char)fgetc( stream );
   if( c == EOF )
      c = Control_z;
   if( c == 0x0a )
      {
      file_record_array_ptr->line_count++;
      file_record_array_ptr->size++;           /* count the unseen <cr> */
      }
   file_record_array_ptr->size++;
   }
return c;
}
/***************************************************************************/
static char near get_to_next_possible_token( stream )
FILE *stream;
{
register char
   c;
char
   next_char_peek;
int
   done;

static int       /* the only apparent reason these are static is for speed */
   quotes_flag =           false,
   comment_flag =          false,
   escape_sequence_flag =  false,
   pound_sign_flag =       false,
   ascii_quote_flag =      false;
static int
   fp = 0;   /*****<<<<< */
static char *cp;

done = false;
do {
   c = get_chars( stream );
   if( c != Control_z )
      {   
      if( comment_flag )
         {
/**************************
   process /* comment sequence of characters
***************************/
         if( first_comment == true )
            {
            if( fp < ( Max_general_buffers - 2 ) )
               {
               if(
                  ( c != '\n' ) &&
                  ( strlen( cp ) < effective_width )
                 )
                  {
                  file_comment_buffer[ fp++ ] = c;
                  file_comment_buffer[ fp ] = '\0';
                  }
               else        /* c == \n or length >= width */
                  {
                  file_comment_buffer[ fp++ ] = '\n';
                  file_comment_buffer[ fp ] = '\0';
                  cp = (char *)&file_comment_buffer[ fp ];
                  if( c != '\n' )
                     {
                     file_comment_buffer[ fp++ ] = c;
                     file_comment_buffer[ fp ] = '\0';
                     }
                  }
               }
/*          else     /* 1st comment exceeds buffer */
            }        /* end of if first_comment == true */
         if( c == '*' )
            {
            next_char_peek = get_chars( stream );
            if( next_char_peek == '/' )          /* close comment */
               {
               comment_flag = false;
               unget_chars( ' ' );  /* comments are white space in 'c' */
               if( first_comment == true )
                  {
                  first_comment = completed;
                  fp = 0;
                  cp = (char *)&file_comment_buffer[ fp ];
                  }
               }
            else        /* next_char_peek != '/' ie close comment */
               unget_chars( (char)next_char_peek );
            }  /* end of if c == '*' */
         }
      else     /* not /* */
         {
/**************************
   process \sequence character, hoping \" \' \\ etc inside " or '
***************************/
         if( escape_sequence_flag )
            escape_sequence_flag = false;
         else     /* not /*, not \ */
            {
/**************************
   process " string sequence of characters
***************************/
            if( quotes_flag )
               {
               if( c == '\\' )                  /* check for \'\n' */
                  {
                  next_char_peek = get_chars( stream );
                  if( next_char_peek != '\n' )  /* so not \'\n' */
                     {
                     escape_sequence_flag = true;
                     unget_chars( (char)next_char_peek );
                     }
/*******          else                          /* \'\n' continuation */
                  }
               else                             /* not \ */
                  if( c == '\"' )
                     quotes_flag = false;
               }
            else     /* not ", not /*, not \ */
               {
/**************************
   process ' ascii character sequence
***************************/
               if( ascii_quote_flag )
                  {
                  if( c == '\\' )
                     escape_sequence_flag = true;
                  else
                     if( c == '\'' )
                        ascii_quote_flag = false;
                  }
               else  /* not ', not ", not /*, not \ */
                  {
/**************************
   process # sequence of characters, ie #if, #define, etc.
   define causes code sequencing problems it would seem!
***************************/
                  if( pound_sign_flag )
                     {
                     if( c == '/' )       /* comments override #defines etc */
                        {
                        next_char_peek = get_chars( stream );
                        if( next_char_peek == '*' )
                           comment_flag = true;
                        else
                           unget_chars( (char)next_char_peek );
                        }
                     else
                        {
                        if( c == '\n' )
                           pound_sign_flag = false;
                        else                          /* c != \n */
                           {
                           if( c == '\\' )  /* check for \'\n' continuation */
                              {   
                              next_char_peek = get_chars( stream );
                              if( next_char_peek != '\n' ) /* it aint \'\n' */
                                 unget_chars( (char)next_char_peek );
/*                            else              /* \'\n' means continue # */
                              }
                           }
                        }
                     }
                  else     /* not ', not #, not ", not /*, not \ */
                     {
/**************************
   process anything else
***************************/
                     done = false;     /* assume a ' or " or # or /* */
                     switch( c )
                        {
                        case '\"':
                           quotes_flag = true;
                           break;
                        case '\'':
                           ascii_quote_flag = true;
                           break;
                        case '#':
                           pound_sign_flag = true;
                           break;
                        case '/':
                           next_char_peek = get_chars( stream );
                           if( next_char_peek == '*' )
                              {
                              comment_flag = true;
                              if( first_comment == false )
                                 {           /* the 1st comment of the file */
                                 first_comment = true;
                                 fp = 0;
                                 cp = (char *)&file_comment_buffer[ fp ];
                                 }
                              }
                           else
                              {
                              unget_chars( (char)next_char_peek );
                              done = true;   
                              }
                           break;
                        default:       /* a worthy character to return */
                           done = true;   
                        }
                     }     /* end of else not ascii */
                  }        /* end of else not # */
               }           /* end of else not " */
            }              /* end of else not /* */
         }                 /* end of else not \ */
      }                    /* end of if c != Control_z */
   }
while( !done && ( c != Control_z ) );
if( c == Control_z )
   {
   ascii_quote_flag = false;
   pound_sign_flag = false;
   quotes_flag = false;
   escape_sequence_flag = false;
   comment_flag = false;
   fp = 0;
   }
return c;
}
/***************************************************************************/
static int near is_legal_identifier_character( c )
char c;
{
if(
   ( ( 'A' <= c ) && ( c <= 'Z' ) ) ||
   ( ( 'a' <= c ) && ( c <= 'z' ) ) ||
   ( ( '0' <= c ) && ( c <= '9' ) ) ||
   ( c == '_')
  )
   return true;
else
   return false;
}
/***************************************************************************/
#define  C_line_length  512
#define  C_identifier_length  80

int near build_the_data_base( the_filename )
char * the_filename;
{
static char fake_comment[ ] = "no room!";
int found_a_possible_function;
int brace_count, body_found;
int open_parenthesis, parenthesis_count;
int at_end_of_source_file;
int dummy_index, total_called_count;
int function_definition_flag, static_flag;
int analyze_buffer_flag = false;
char c;
char *function_name_buffer_ptr;
char function_name_buffer[ C_identifier_length ];
char look_ahead_buffer[ C_line_length + 1 ];
FILE *stream;
data_base_record_type *data_base_ptr, *starting_data_base_ptr;
function_type *starting_called_function_ptr;

if( !g_quiet_flag )
   {
   (void)printf( "Processing file: %-12s\n", the_filename );
   }
if( !( stream = fopen( the_filename, "r" ) ) )  /***** rt <<<<<<<<<< */
   {
   (void)printf( "Cant open %s\n", the_filename );
   return -1;
   }

push_buffer_ptr = push_buffer;         /* reset input character stack */
                                       /* add file name to data base */
if( !( file_record_array_ptr->source_filename = strdup( the_filename ) ) )
   {
   (void)printf( "Ran out of memory.\n" );
   exit( 1 );
   }

starting_called_function_ptr = function_list_ptr;
starting_data_base_ptr = data_base_array_ptr; /* mark start of defined list */

look_ahead_buffer[ 0 ] = '\0';

first_comment = false;
file_comment_buffer[ 0 ] = '\0';

file_record_array_ptr->line_count = 0;  /* clear it's variables */
file_record_array_ptr->size = 0l;

function_name_buffer_ptr = function_name_buffer;
function_name_buffer[ 0 ] = '\0';

static_flag = false;
found_a_possible_function = false;
open_parenthesis = false;
body_found = false;

brace_count = 0;
parenthesis_count = 0;

at_end_of_source_file = false;
while( !at_end_of_source_file )
   {
   c = get_to_next_possible_token( stream );
   switch( c )
      {
      case '{':
         ++brace_count;
         break;
      case '}':
         --brace_count;
         break;
      case Control_z:
         at_end_of_source_file = true;
         analyze_buffer_flag = true;
         break;
      case '(':
         if( !open_parenthesis )
            ++open_parenthesis;
         analyze_buffer_flag = true;
         break;
      case ' ':                  /* this is where we eat white space */
      case '\v':
      case '\b':
      case '\f':
      case '\t':
      case '\r':
      case '\n':
         do {
            c = get_to_next_possible_token( stream );
            }
         while(
               ( c == '\f' ) || ( c == ' ' ) || ( c == '\v' ) ||
               ( c == '\b' ) || ( c == '\t' ) || ( c == '\r' ) ||
               ( c == '\n' )
              );
         unget_chars( c ); /* put next non white character back */

         if( c != '(' )
            analyze_buffer_flag = true;
/***     else  /* c == '(' and next pass will find it */
         break;
      default:
         if( is_legal_identifier_character( c ) )
            {                          /* it's a good identifier character */
            *function_name_buffer_ptr++ = c;
            *function_name_buffer_ptr = '\0';
            }
         else                          /* it aint, so toss it */
            {
            if( static_flag && ( c == ';' ) )
               static_flag = false;
/*          if( c != '*' ) */
            analyze_buffer_flag = true;
            }
         break;
      }                    /* end of preliminary character parse */
/*****************
   start checking characters accumulated in function_name_buffer[]
******************/
   if( analyze_buffer_flag )
      {
      analyze_buffer_flag = false;
      if(
         function_name_buffer[ 0 ] &&        /* ie not null string */
         (                                   /* & not number */
          ( function_name_buffer[ 0 ] < '0' ) ||
          ( function_name_buffer[ 0 ] > '9' )
         )
        )
         found_a_possible_function = true;
      else                                   /* it aint an identifier */
         {                                   /* so erase buffer */
         function_name_buffer_ptr = function_name_buffer;
         function_name_buffer[ 0 ] = '\0';
         if( static_flag && ( c == ';' ) )
            static_flag = false;
         open_parenthesis = false;
         }
      }                       /* end of analyze_buffer_flag */
/*****************
   if function_name_buffer[] has legal function name, scan ahead
******************/
   if( found_a_possible_function )
      {
      found_a_possible_function = false;
      *function_name_buffer_ptr = '\0';   /* append nul char to end */
      if( !static_flag )                  /* don't retest if true */
         if( !strcmp( function_name_buffer, "static" ) )
            static_flag = true;
      if( open_parenthesis )
         {
         open_parenthesis = false;
         if( !brace_count )
            {                             /* ie outside any function body */
            parenthesis_count = 1;
            for( dummy_index = 0;
                 ( dummy_index < C_line_length ) && parenthesis_count;
                 ++dummy_index
               )
               {                          /* scan ahead for function() */
               c = get_to_next_possible_token( stream );
               if( c == Control_z )
                  break;            /* dummy_index not bumped */
               look_ahead_buffer[ dummy_index ] = c;
               look_ahead_buffer[ dummy_index + 1 ] = '\0';
               switch( c )
                  {
                  case '(':
                     ++parenthesis_count;
                     break;
                  case ')':
                     --parenthesis_count;
                     break;
                  }           /* dummy_index is bumped */
               }              /* end of for loop scanning for (...) */
            if( ( c == Control_z ) || ( !parenthesis_count ) )
               --dummy_index;
            function_definition_flag = false;
            for( ++dummy_index;
                 ( dummy_index < C_line_length ) && !function_definition_flag;
                 ++dummy_index
               )
               {                 /* what happens past (..) */
               c = get_to_next_possible_token( stream );
               if( c == Control_z )
                  break;            /* w/ function_definition_flag == false */
               look_ahead_buffer[ dummy_index ] = c;
               look_ahead_buffer[ dummy_index + 1 ] = '\0';
               switch( c )
                  {
                  case ' ':         /* this is where we eat white space */
                  case '\v':
                  case '\b':
                  case '\f':
                  case '\t':
                  case '\n':
                  case '\r':
                     break;
                  case '{':
                     ++body_found;
                     break;
                  case ';':
                  case ',':
                  case '(':            /* at (*)() type declaration */
                     if( !body_found )
                        {
                        function_definition_flag = true; /* declaration */
                        if( !g_quiet_flag )
                           {
                           if( g_dec_def_flag )
                              {
                              if( static_flag )
                                 (void)printf( " static" );
                              else
                                 (void)printf( "       " );
                              (void)printf( " declaration " );
                              (void)printf( "%s(%s\n",
                                            function_name_buffer,
                                            look_ahead_buffer );
                              }
                           }
                        }
                     break;
                  default:          /* any other non white character means */
                     function_definition_flag = completed;
                     if( !g_quiet_flag )
                        {
                        if( g_dec_def_flag )
                           {
                           if( static_flag )
                              (void)printf( "static " );
                           else
                              (void)printf( "       " );
                           (void)printf( "define " );
                           }   
                        }
                     break;
                  }           /* dummy_index is bumped */
               }              /* end of for loop parsing character after ) */
            body_found = false;
            if( function_definition_flag == false )
               {
               (void)printf( "\nSyntax error: " );
               (void)printf( "Function description.\n" );
               look_ahead_buffer[ dummy_index ] = '\0';
               (void)printf( "\n%s\n", look_ahead_buffer );
               exit( 1 );
               }
            while( dummy_index )
               {                       /* put all characters after ( back */
               unget_chars( look_ahead_buffer[ dummy_index - 1 ] );
               --dummy_index;
               }
            if( function_definition_flag == completed )
               {
               if( !g_quiet_flag )
                  {
                  if( g_dec_def_flag )
                     (void)printf( "%-40s\n", function_name_buffer );
                  }
/*******************
   this element can distinguish static functions
   in different files with the same name
 *******************/
               data_base_array_ptr->file_record_ptr = file_record_array_ptr;
               data_base_array_ptr->number_of_function_calls = 0;
               data_base_array_ptr->ptr_to_function_table = function_list_ptr;
               data_base_array_ptr->static_definition = static_flag;
               static_flag = false;

               if(
                  !( data_base_array_ptr->defined_function =
                     strdup( function_name_buffer )
                   )
                 )
                  {
                  (void)printf( "\nRan out of memory( for strdup() )." );
                  exit( 1 );
                  }
               data_base_array_ptr->number_of_references = 0;
               data_base_array_ptr->ptr_to_page_list = NULL;

               data_base_ptr = data_base_array_ptr; /* save current pointer */
               ++data_base_array_ptr;                 /* next entry */
               ++count_of_valid_records;
               if( count_of_valid_records > Max_defined_functions )
                  {
                  (void)printf( "\nToo many new functions\n" );
                  exit( 1 );
                  }
               }        /* end of function definition */
            static_flag = false;
            }
         else                    /* brace_count is not zero */
            {                    /* so inside a function */
            data_base_ptr->number_of_function_calls +=
               test_and_add( data_base_ptr->ptr_to_function_table,
                             function_name_buffer,
                             data_base_ptr->number_of_function_calls
                           );
            }
         look_ahead_buffer[ 0 ] = '\0';   /* reset tail buffer */
         static_flag = false;
         }                       /* end of parenthesis */
      function_name_buffer_ptr = function_name_buffer;   /* reset buffer */
      *function_name_buffer_ptr = '\0';
      }                    /* end of found_a_possible_function */
   }                       /* end of while !at_end_of_source_file */
(void)fclose( stream );
if( !g_quiet_flag )
   {
   (void)printf( "\n" );
   }

if(
   !( file_record_array_ptr->source_file_comment =
      strdup( file_comment_buffer )
    )
  )
    file_record_array_ptr->source_file_comment = fake_comment;

/***** mark called functions in list as static if in defined list *******/
total_called_count = 0;
data_base_ptr = starting_data_base_ptr;
while( data_base_ptr != data_base_array_ptr )
   {
   total_called_count += data_base_ptr->number_of_function_calls;
   ++data_base_ptr;
   }
data_base_ptr = starting_data_base_ptr;
while( data_base_ptr < data_base_array_ptr )
   {
   if( data_base_ptr->static_definition )
      mark_as_static( starting_called_function_ptr,
                      data_base_ptr->defined_function,
                      total_called_count
                    );
   ++data_base_ptr;
   }
++file_record_array_ptr;      /* next file name entry */
++count_of_source_files;
if( count_of_source_files >= Max_files )
   {
   (void)printf( "\nError: too many files to process.\n" );
   exit( 1 );
   }
return at_end_of_source_file;
}
/***************************************************************************/


[LISTING FIVE]

/***************************************************************************
                                  cpfuncts.c
       void near build_box_parts( int );
       void near tab_to_left_margin( FILE * );
static void near stop( void );
static void near setpage( data_base_record_type * );
static int  near recursion_check( char *, int );
       void near check_for_new_page( void );
static void near draw_output_block( char *, char *, char *,
                                    char *, int, int, int );
       int near  doprint( int );
       void near scan_for_static_or_global( int *, int, char *, char * );
       int near  binary_search_sorted_data_base( char * );
  
 ***************************************************************************/

#define  MAIN  0
#include "cpheader.h"

static char
   top_line_of_box[ 37 ], bottom_line_of_box[ 37 ],
   wall, ibm_line, bottom_attach,
   upper_left_corner, lower_left_corner,
   upper_right_corner, lower_right_corner,
   left_attach, right_attach;

static char *recursion_filename, *test_filename;
static int static_recursion;

       int near  binary_search_sorted_data_base( char * );
       void near build_box_parts( int );
       void near check_for_new_page( void );
       int near  doprint( int );
       void near scan_for_static_or_global( int *, int, char *, char * );
       void near tab_to_left_margin( FILE * );

static void near draw_output_block( char *, char *, char *,
                                    char *, int, int, int );
static int near  recursion_check( char *, int );
static void near stop( void );
static void near setpage( data_base_record_type * );

/***************************************************************************/
void near build_box_parts( is_ibm )
int is_ibm;
{
int i;

if( is_ibm )
   {
   wall =               '\xb3';
   ibm_line =           '\xc4';
   bottom_attach =      '\xc2';
   upper_left_corner =  '\xda';
   lower_left_corner =  '\xc0';
   upper_right_corner = '\xbf';
   lower_right_corner = '\xd9';
   left_attach =        '\xb4';
   right_attach =       '\xc3';
   }
else
   {
   wall =               '|';
   ibm_line =           '-';
   bottom_attach =      '+';
   upper_left_corner =  '+';
   lower_left_corner =  '+';
   upper_right_corner = '+';
   lower_right_corner = '+';
   left_attach =        '+';
   right_attach =       '+';
   }

top_line_of_box[ 0 ] = upper_left_corner;   
bottom_line_of_box[ 0 ] = lower_left_corner;
for( i = 1; i <= 34; ++i )
   {
   top_line_of_box[ i ] = ibm_line;
   bottom_line_of_box[ i ] = ibm_line;
   }
top_line_of_box[ i ] = upper_right_corner;
bottom_line_of_box[ i ] = lower_right_corner;
top_line_of_box[ ++i ] = '\0';
bottom_line_of_box[ i ] = '\0';
}
/***************************************************************************/
void near tab_to_left_margin( output )
FILE *output;
{
register int i;

for( i = 0; i < defined_left_margin; ++i )
   (void)fputc( ' ', output );
}
/***************************************************************************/
static void near stop()
{
(void)printf( "hello" );
}
/***************************************************************************/
static void near setpage( data_base_ptr )
data_base_record_type *data_base_ptr;
{
linked_pages_list *page_list_ptr;

page_list_ptr = data_base_ptr->ptr_to_page_list;
if( page_list_ptr == NULL )
   {
   if(
      !( page_list_ptr =
         (linked_pages_list *)malloc( sizeof( linked_pages_list ) )
       )
     )
      {
      (void)fprintf( stderr, "Ran out of memory for page # list.\n" );
      exit( 1 );
      }

   data_base_ptr->ptr_to_page_list = page_list_ptr;
   }
else
   {
   while( page_list_ptr->next_page_ptr )
      page_list_ptr = page_list_ptr->next_page_ptr;

   if(
      !( page_list_ptr->next_page_ptr =
         (linked_pages_list *)malloc( sizeof( linked_pages_list ) )
       )
     )
      {
      (void)fprintf( stderr, "Ran out of memory for page # list.\n" );
      exit( 1 );
      }

   page_list_ptr = page_list_ptr->next_page_ptr;
   }
page_list_ptr->next_page_ptr = NULL;
page_list_ptr->on_this_page = page - 1;
}
/***************************************************************************/
static int near recursion_check( string, static_call )
char *string;
int static_call;
{
register char **recursion_array_ptr;

recursion_array_ptr = recursion_array;
if( static_recursion )
   {                             /* defined function is static */
   while(
         *recursion_array_ptr && /* not null */
                                 /* and different function names */
         ( strcmp( *recursion_array_ptr, string ) ||
                                 /* or same function names and */
                                 /* in different files */
           strcmp( test_filename, recursion_filename )
         )
        )
   ++recursion_array_ptr;
   }
else
   {                             /* defined function is not static */
   while(
         *recursion_array_ptr && /* not null & */
                                 /* and different function names */
         ( strcmp( *recursion_array_ptr, string ) ||
                                 /* or same function names and */
           static_call           /* called is static */
         )
        )
      ++recursion_array_ptr;
   }
return ( *recursion_array_ptr )? true: false;
}
/***************************************************************************/
void near check_for_new_page()
{
int i;

if( defined_page_length == 0 && line == 9999 )
   {
   (void)fprintf( output, "\n\n\n\n" );
   line = 0;
   }
else
   {
   if( defined_page_length != 0 )
      {
      if( line > ( defined_page_length - 5 ) )
         {
         (void)fprintf( output, "\f" );
         line = 0;
         }
      if( line == 0 )
         {
         top_of_form_done = true;
         tab_to_left_margin( output );
         (void)fprintf( output, "%s", title );
         for( i = strlen( title ); i < ( effective_width - 10 ); ++i )
            (void)fputc( ' ', output );
         (void)fprintf( output, "Page:%4d\n", page );
         tab_to_left_margin( output );
         for( i = 0; i < effective_width; ++i )
            (void)fputc( '_', output );
         (void)fprintf( output, "\n\n" );
         line = 3;
         ++page;
         }
      }
   }
}
/***************************************************************************/
static void near draw_output_block( lead_in_string,
                                    name_of_function,
                                    description,
                                    name_of_file,
                                    either_count,
                                    tail_flag,
                                    kill_flag
                                  )
char *lead_in_string,
   *name_of_function,
   *description,
   *name_of_file;
int either_count, tail_flag, kill_flag;
{
unsigned int string_length;
static char alternate_lead_in[ 140 ];

/******* 1st line ***********************************************************/
tab_to_left_margin( output );
(void)fprintf( output, "%s %s\n", lead_in_string, top_line_of_box );

/******* 2nd line ***********************************************************/
tab_to_left_margin( output );
string_length = strlen( lead_in_string );
if( string_length )        /******* ie not main or defined function box ***/
   {
   (void)strncpy( alternate_lead_in, lead_in_string, --string_length );
   alternate_lead_in[ string_length++ ] = '\0'; /* restore string_length */
   }
if( string_length )        /******* ie not main or defined function box ***/
   (void)fprintf( output, "%s%c%c%c%-33s %c\n",
                  alternate_lead_in,
/***  if( kill_flag )      /****** last line to this box ******************/
/***  else                 /****** line continues downwards ***************/
                  ( kill_flag )? lower_left_corner: right_attach,
                  ibm_line, left_attach, name_of_function, wall );
else                       /****** main or defined box starting ***********/
   (void)fprintf( output,     "%c%c%-33s %c\n",
                  ibm_line, left_attach, name_of_function, wall );

/******* 3rd line ***********************************************************/
tab_to_left_margin( output );
if( string_length-- )      /***** kill outside vertical line on last box ****/
   lead_in_string[ string_length++ ] = ( kill_flag )? (char)' ': wall;
(void)fprintf( output, "%s %c%-20s %8s%3d  %c\n",
               lead_in_string, wall, description,
               name_of_file, either_count, wall );

/******* 4th line ***********************************************************/
tab_to_left_margin( output );
bottom_line_of_box[ 2 ] =  /******** if defined box has calls ***********/
   ( tail_flag && either_count )? bottom_attach: ibm_line;
(void)fprintf( output, "%s %s\n", lead_in_string, bottom_line_of_box );

line += 4;
top_of_form_done = false;
}
/***************************************************************************/
static char library_string[] = { "(library)" };
static char usage_string[] =   { "Used=" };
static char funct_string[] =   { "Functs=" };

int near doprint( index )
int index;
{
int
   loop_counter,
   max_count,
   starting_index,
   found,
   return_value;
data_base_record_type *record_ptr;
function_type *f_list_ptr;

static int kill_flag = false;

starting_index = index;
record_ptr = array_of_ptrs_to_records[ starting_index ];

recursion_array[ recursion_depth ] = record_ptr->defined_function;
if( !recursion_depth )
   {
   recursion_filename = record_ptr->file_record_ptr->source_filename;
                        /* add function to list for recursion check */
   static_recursion = record_ptr->static_definition;
   }
check_for_new_page();
setpage( array_of_ptrs_to_records[ starting_index ] );

return_value = page - 1;               /* must be a relic! */
                                       /* start w/ target function */
draw_output_block( nesting_display_buffer,
                   record_ptr->defined_function,
                   ( record_ptr->file_record_ptr )->source_filename,
                   funct_string,
                   record_ptr->number_of_function_calls,
                   true,
                   kill_flag
                 );

++recursion_depth;
                           /****   mystic width = 4 *****/
(void)strcat( nesting_display_buffer, "   |" );
nesting_display_buffer[ strlen( nesting_display_buffer ) - 1 ] = wall;

max_count = record_ptr->number_of_function_calls;
for( loop_counter = 0, f_list_ptr = record_ptr->ptr_to_function_table;
     loop_counter < max_count;
     ++loop_counter, ++f_list_ptr
   )
   {
   kill_flag = ( loop_counter == ( max_count - 1 ) )? true: false;
   check_for_new_page();
                           /* is called function defined? */
   found = binary_search_sorted_data_base( f_list_ptr->functions_name );
   if( found >= 0 )
      {
      scan_for_static_or_global( &found,
                                 f_list_ptr->static_function,
                                 f_list_ptr->functions_name,
                                 f_list_ptr->its_filename
                               );

      }
   if( found >= 0 )        /* yes */
      {
      test_filename = f_list_ptr->its_filename;
      if( recursion_check( f_list_ptr->functions_name,
                           f_list_ptr->static_function )
        )
         {
/*         tab_to_left_margin( output );
/*         (void)fprintf( output, "%s\n", nesting_display_buffer ); */
         setpage( array_of_ptrs_to_records[ found ] );
/*         ++line; */
         top_of_form_done = false;
         draw_output_block( nesting_display_buffer,
                            f_list_ptr->functions_name,
                            "(recursive)",
                            "",
                            0,
                            false,
                            kill_flag
                          );
         }
      else        /* not recursive and found >= 0 */
         {
         if( array_of_ptrs_to_records[ found ]->number_of_references == 1 )
            {                       /* got a new function */
/*            tab_to_left_margin( output );
/*            (void)fprintf( output, "%s\n", nesting_display_buffer );
/*            ++line;
/*            top_of_form_done = false; */
            doprint( found );           /* used only once */
            }
         else
            {                       /* a previously defined function */
/*            tab_to_left_margin( output );
/*            (void)fprintf( output, "%s\n", nesting_display_buffer ); */
            setpage( array_of_ptrs_to_records[ found ] );
/*            ++line;
/*            top_of_form_done = false; */
            draw_output_block( nesting_display_buffer,
                               f_list_ptr->functions_name,
                               "(defined)",
                               usage_string,
                               f_list_ptr->is_referenced,
                               false,
                               kill_flag
                             ); 
            }
         }
      }
   else           /* found = -1 ie not defined means */
      {           /* a library function */
/*      tab_to_left_margin( output );
/*      (void)fprintf( output, "%s\n", nesting_display_buffer );
/*      ++line;
/*      top_of_form_done = false; */
      draw_output_block( nesting_display_buffer,
                         f_list_ptr->functions_name,
                         library_string,
                         usage_string,
                         f_list_ptr->is_referenced,
                         false,
                         kill_flag
                       );
      }
   }           /* end of loop on all called functions */

                           /* remove function f/ recursion list */
recursion_array[ recursion_depth ] = NULL;
                           /****   mystic width = 4 *****/
nesting_display_buffer[ strlen( nesting_display_buffer ) - 4 ] = '\0';
--recursion_depth;
return return_value;
}
/***************************************************************************/
void near scan_for_static_or_global(
                              index_ptr, is_static, function_name, file_name
                                   )
int *index_ptr, is_static;
char *function_name, *file_name;
{
int index;

index = *index_ptr;
if( index )
   while( index-- )
      if( strcmp( function_name,
                  array_of_ptrs_to_records[ index ]->defined_function )
        )
         {
         ++index;       /* exit at last matching defined function */
         break;
         }
do {
   if(
      ( !is_static && !array_of_ptrs_to_records[ index ]->static_definition
      ) ||
      ( is_static &&
        array_of_ptrs_to_records[ index ]->static_definition &&
        !strcmp( array_of_ptrs_to_records[ index ]->
                  file_record_ptr->source_filename,
                 file_name
               )
      )
     )
      break;
   }
while(
      ( ++index < count_of_functions ) &&
      !strcmp( function_name,
               array_of_ptrs_to_records[ index ]->defined_function
             )
     );
if(
   ( index >= count_of_functions ) ||
   strcmp( function_name, array_of_ptrs_to_records[ index ]->defined_function
         )
  )
   index = -1;
*index_ptr = index;
}
/***************************************************************************/
int near binary_search_sorted_data_base( key )
char *key;
{
int lo, hi, index;
int doesnt_match;

lo = 0;
hi = count_of_valid_records - 1;
index = ( hi - lo ) / 2;

while( true )
   {
   doesnt_match =
      strcmp( key, array_of_ptrs_to_records[ index ]->defined_function );
   if( !doesnt_match )        /* a match found at index */
      break;
   if( lo >= hi )             /* no match found */
      {
      index = -1;
      break;
      }
   if( doesnt_match < 0 )     /* key < choice so go downwards */
      hi = index - 1;
   else                       /* key > choice so go upwards */
      lo = index + 1;
   index = ( hi + lo ) / 2;   /* new choice */
   }
return index;
}
/***************************************************************************/


[LISTING SIX]

cp.obj : cp.c cpheader.h cp
        cl -AL -c cp.c

cpinput.obj : cpinput.c cpheader.h cp
        cl -AL -c cpinput.c

cpfuncts.obj : cpfuncts.c cpheader.h cp
        cl -AL -c cpfuncts.c

cpbuild.obj: cpbuild.c cpheader.h cp
        cl -AL cpbuild.c -c

cp.exe : cp.obj cpinput.obj cpfuncts.obj cpbuild.obj cp
        link cp+ cpinput+ cpbuild+ cpfuncts/packcode/st:16000,,cp;



[LISTING SEVEN]

cpheader.h
cp.c
cpbuild.c
cpfuncts.c
cpinput.c


