_AN AID TO DOCUMENTING C REVISITED_ by Ron Winter [LISTING ONE] /********************************************************************* cpheader.

h *********************************************************************/ #include #include #include #include #include <malloc.h> <conio.h> <stdio.h> <string.h> <stdlib.h> 20000 3000 5000 4000 */ 1400 1400 50

#define Max_unget_buffer #define Max_general_buffers #define MAX_functions /* #define Max_functions #define Max_defined_functions #define Max_files #define Max_Recursion #define #define #define #define #define false true completed Escape Control_z 0 1 2 0x1b 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 static static static static static static static static static static static static static static void void void void void void void void void void void void void void void int near near near near near near near near near near near near near near near bump_line_count( void ); do_top_of_page( void ); deallocate_arrays( void ); allocate_arrays( void ); initialize_globals( void ); build_records_from_list( FILE * ); sort_the_data_base_array( void ); count_all_defined_references( void ); show_function_relationships( void ); show_line_and_byte_counts( void ); show_sorted_function_list( void ); show_page_references( void ); show_unused_if_any( ); show_library_functions( void ); show_files_leading_comments( ); main( int, char ** );

***************************************************************************/ #define MAIN 1 #include "cpheader.h" #include "time.h" extern extern extern extern extern extern extern extern extern static static static static static static static int void int void int void void void void void void void void void void void near near near near near near near near near near near near near near near near binary_search_sorted_data_base( char * ); build_box_parts( int ); build_the_data_base( char *, char * ); check_for_new_page( void ); doprint( int ); nasty( int ); process_arguments( int, int, char **, int ); scan_for_static_or_global( int *, int, char *, char * ); tab_to_left_margin( FILE * ); allocate_arrays( void ); build_records_from_list( FILE * ); bump_line_count( void ); count_all_defined_references( void ); deallocate_arrays( void ); do_top_of_page( void ); initialize_globals( void );

static static static static static static static static

void void void void void void void void int

near near near near near near near near

show_files_leading_comments( void ); show_function_relationships( void ); show_library_functions( void ); show_line_and_byte_counts( void ); show_page_references( void ); show_sorted_function_list( void ); show_unused_if_any( void ); sort_the_data_base_array( void ); 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[ title[ title[ title[ 15 16 17 18 ] ] ] ] = = = = ' '; ' '; 'm'; ' '; /* knock off seconds */ /* put am, pm here */

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 ); if( ) ( l = strlen( input_line ) ) > 1 { /* ie not nul string */

/* ends at \n or eof */

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" );

} } 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();

++line; if( array_of_ptrs_to_records[ record_index ]->number_of_references > 1 ) (void)doprint( record_index ); }

(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 ] );

} } else (void)printf( "\nUnknown argument: %s, ignored!\n", argv[ i ] ); } /* end of for loop on arguments */

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 - */

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" static static static static static static int near char near char near int near void near int near void near build_the_data_base( char * ); get_chars( FILE * ); get_to_next_possible_token( FILE * ); is_legal_identifier_character( char ); mark_as_static( function_type *, char*, int ); test_and_add( function_type *, char *, int ); 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 */ {

} 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.

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 == '*' */

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

} } } } } }

} 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;

{ 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 */

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; file_record_array_ptr->size = 0l; /* clear it's variables */

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 void near void near int near void near void near binary_search_sorted_data_base( char * ); build_box_parts( int ); check_for_new_page( void ); doprint( int ); scan_for_static_or_global( int *, int, char *, char * ); 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 = ibm_line = bottom_attach = upper_left_corner = lower_left_corner = upper_right_corner = lower_right_corner = left_attach = right_attach = } else { wall = ibm_line = bottom_attach = upper_left_corner =

'\xb3'; '\xc4'; '\xc2'; '\xda'; '\xc0'; '\xbf'; '\xd9'; '\xb4'; '\xc3';

'|'; '-'; '+'; '+';

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 #