Channels ▼
RSS

Database

Automatic Module Control Revisted

Source Code Accompanies This Article. Download It Now.


Ron is a faithful Dr. Dobb's subscriber, and has been a microcomputer aficionado for many years. He is a software engineer at SPEX in Edison, N.J. You can contact him at P.O. Box 4143, Metuchen, N.J. 08840.


This article is a follow up to Stewart Nutter's article "An Aid To Documenting C," DDJ, August 1988. In that article, Stewart presented a printer program he called cp (for C printer), which allowed programmers to document C source-code modules. When I first saw the program, I realized that it addressed my needs in a general way, but as presented the program was just not sufficient.

After entering the source as printed (and adding a few missing ++s and fixing a few other minor typos) I got cp to run. Two things struck me immediately: Lowercase ls as variables are amazingly similar to 1s in small type, and the program crashed when I gave my target program as input! By this time my curiosity was sufficiently aroused, so I decided I had better understand the program before changing it too much, or it might never work.

What appeared to be a simple task became instead a small research project into the C language. It is amazing how much C code you can write without really understanding why C is the way it is. The process of correcting the code so that it would follow the rules of a C compiler and linker helped me understand the role of functions, and brought me a deeper understanding of computer languages and an appreciation for what they do. Nevertheless, you usually only go far enough to get the job done. In the case of cp, I realized that if I went much further, the program would start to become a compiler! That's a thought I try not to consider too seriously.

Rewriting Without Rewriting

When I began rewriting Stewart's original program, all of my prejudices and preferences in style came to bear upon the code in a fit of global search and replacements. My own C style is "pascalean" in indenting and braces, with highly descriptive functions and variable names, especially globals.

Every function in the original program is in my own version of cp, but the names have been changed to make them a little clearer (at least to me). Some new functions have been added. Function declarations are included, and two new files were added: cpbuild.c and cpinput.c. cpbuild.c contains all the code needed by the original function xref( ). The second file, cpinput c, handles the prompting and parameter parsing that the program does at start-up.

My cp program consists of the following files: CPHEADER.H, the header file (Listing One, page 73); CP.C, the main source file (Listing Two, page 73); CPINPUT.C, the command-line parser (Listing Three , page 78); CP BUILD.C, the front-end section of the program (Listing Four, page 79); CPFUNCTS.C, the back-end section (Listing Five, page 83); CP, the make file (Listing Six, page 85); and CPLIST, the input file to execute the program on itself (Listing Seven, page 85).

The make file now uses the /packcode directive in the linker command. This allows me to make all the functions "near," even in different files in large model programs, as long as the code size is less than a segment. The effect is to have the speed and size of a small model program with respect to the code. The arguments to the program are much the same as they were in the original program. Some new parameters are: n for normal (as opposed to IBM) character graphics, f for size of called function array, l for library call statistics, q for quiet mode, d to show declarations and definitions on the console as they are found, h to show more help than is shown when cp is executed with no arguments, and x to show some technical information. The program now can take uppercase or lowercase parameters with either the "-" or "/" switch character.

Figure 1 shows a sample printout of the the cp program; Figure 2 shows a portion of a typical report the program produces.

Repairing the Algorithms

A minor deficiency of the original code is that it incorrectly assumes that a function definition ends with a new line. A more correct algorithm scans forward from possible identifiers; if an open parenthesis is found, it then scans for the matching close parenthesis and checks the next non-white character. As in "Find That Function!" by Marvin Hymowech (also in August 1988), the key is to note that if this next character is a comma or semicolon, a declaration or prototype has been found. In either ANSI style or standard C, definitions have either an open brace or variable declaration(s) following the close parenthesis.

I had to overcome two major deficiencies in the original code. The first was the lack of treatment of static functions. The second was the way leading comments were stored. In the original code, the strdup( ) was not checked for failure at the end of the function xref( ), so it crashed on my large program. I made a minor change to the program that dressed up the form of the tree-structured output. The connecting lines did not stop when there was nothing underneath to connect them to. Finally, I added a toggle for IBM character graphics to draw the tree in fine style.

I discovered that you must really understand what constitutes a correct C program first before you can parse it for function definitions and function calls. The scanner, called getnext( ) in the original, incorrectly scanned quoted (") strings and pound sign (#) statements. They both allow the line continuation form of backslash followed immediately by a new line. Also, comments are considered white space in a #statement construction. The function is now called get_to_next_possible_token( ), and it handles these situations correctly.

Figure 2: Sample report from the cp program

  Function Index:
  function                                     in file        references
  ______________________________________________________________________

  static allocate_arrays                       cp.c           1
            binary_search_sorted_data_base     cpfuncts.c     4
            build_box_parts                    cpfuncts.c     1
  static build_records_from_list               cp.c           1
            build_the_data_base                cpbuild.c      1
  static bump_line_count                       cp.c           29
            check_for_new_page                 cpfuncts.c     4
  static count_all_defined_references          cp.c           1
  static deallocate_arrays                     cp.c           1
  static do_top_of_page                        cp.c           7
            doprint                            cpfuncts.c     3
  static draw_output_block                     cpfuncts.c     4
  static get_chars                             cpbuild.c      6
  static get_to_next_possible_token            cpbuild.c      4
  static initialize_globals                    cp.c           1
  static is_legal_identifier_character         cpbuild.c      1
  main                                         cp.c           1
  static mark_as_static                        cpbuild.c      1
            nasty                              cpinput.c      1
  process_arguments                            cpinput.c      1
  static recursion_check                       cpfuncts.c     1
  scan_for_static_or_global                    cpfuncts.c     2
  static setpage                               cpfuncts.c     3
  static show_files_leading_comments           cp.c           1
  static show_function_relationships           cp.c           1
  static show_library_functions                cp.c           1
  static show_line_and_byte_counts             cp.c           1
  static show_page_references                  cp.c           1
  static show_sorted_function_list             cp.c           1
  static show_unused_if_any                    cp.c           1
  static sort_the_data_base_array              cp.c           1
            tab_to_left_margin                 cpfuncts.c     9
  static test_and_add                          cpbuild.c      1
  static unget_chars                           cpbuild.c      8
  Un-used function list:                       -cpfuncts.c
  static stop

I corrected the treatment of static functions. First, you have to recognize them, and then mark them when they are entered into the data base. It is also necessary to mark them in the called-function list with their file name, if they are called at any time in the file under analysis. In C, you can have many functions with the same name in a program, as long as only one of them is not static and each is in a different file. This requires a change to the way the defined function call count is done and the way the output tree is checked. Basically, the binary search of the sorted data base must be called with the understanding that there might be more than one defined function with the same name. If the called function is in a different file from the defined function and the defined function is static, it should not match. You must search adjacent names in the ASCII sorted list for a called function that is (first) static in the defined functions file, (second) not static and in any file, else it must be a library function. This also reflects upon the recursion check. All of these issues are addressed in the new version of the program. A function is recursive if it calls a function with the same name (perhaps through other functions) and the test checks that the file name associated with the called function is the same as the file name of the calling function. This avoids the trap of function x() say in file 1, calling function y() in file 2, and y() calling static function x( ) in file 2. The original code would say incorrectly that function x() was recursive.

More Details.

*

A Few Extras

The point of making the called function array programmable is to allow you to shrink its storage requirements and thus allow the program to run in less memory. This allows the program to be launched with impunity from within editors, TSRs, Windows, DESQ-view, and so on.

As stated in the code comments, this program will not see the relationship between functions when they are called indirectly via pointers to functions. Also, functions in the body of a #define will be missed. Code in both #if and #else will also be scanned, possibly noting more function calls and perhaps even getting out of sync with respect to opening and closing braces. This may be annoying but as long as you are aware of it, I don't think it's too serious. If needed, you could pass the source through the preprocessor first before processing it with cp.

The code now catches all of the initial comments in a file. I am not sure what it did in the original code. The temporary buffer for it is 3K. Compile it bigger if you wish. The look-ahead buffer that scans between matching parentheses in a function declaration or definition is the manifest constant c_line_length, which is set to 512. If you are even more verbose in your style than I am, you may want to make this larger (a co-worker of mine is, so his is 2048!). The called function array size is the number of unique functions per function definition for all function definitions in the program, so the number of function calls can exceed this number. These arrays are mallocd so that if they need to exceed a full segment, one only has to change the malloc()s to halloc()s, the associated free()s to hfree()s, and then the really tedious part, chasing all associated global and local variables (usually pointers to these arrays) and changing all their definitions to huge, such as some_type *some_type_pointer to some_type huge*some_type_pointer. A large model recompile is all that is required. This is all Microsoft C 5.x specific talk, though I assume similar constructs exist in other Cs on the IBM PC/XT/AT platform. I would expect these huge arrays are not needed until one must analyze a really large C program, perhaps something on the order of 1-2-3 release 3!

The Loose Ends

The parser still worries me. It catches all the stuff I have thrown at it, but because I am still not sure how it works (!), I feel that it may still have some black holes. I can't follow its execution by looking at it; I just go on faith. The next version will probably return a space for any white space character. That is, put the white space testing into get_to_next_possible-token(). This should clean up build_the_data_base() a little.

I would like to contemplate the data structures a little and perhaps come up with something a little less ugly than what exists now, especially the structure elements that mark statics. There must be a neater way of doing this. You may want to add yet another input toggle to plot unused functions. This is useful in a C program that uses pointers to functions. You may not be able to see who calls the function, but you can plot it anyway.

For those of you with really big programs, you could go to halloc() for the arrays. After qualifying the declarations of pointers with the huge attribute, a large model recompile is all that is required to allow arrays larger than the 64K limit imposed by malloc().

Two more items complete the wish list. The first is hooking in the page linker to the library calls in doprint() so that a cross reference to library calls may be generated. The last is to sort the defined functions on entry rather than at the end. This would free up run-time dynamic memory and would not create a significant time penalty; in fact, it might actually speed things up!

Late Additions

At the request of a co-worker (yes, the same one!) the input buffer for the input file name list was extended from 20 bytes to 128 bytes. Apparently his sources were really scattered about his directory tree, and so some of his pathnames were quite long, hence the change to the buffer size. A small change was also made to allow an optional string following each input file pathname. This string is atoi()d, and if it is not 0, it is added to the tree structure defining box and added as a column in the sorted function list. Its intended usage is the overlay number of the function. Overlays are the trick that allows you to write code and .exe files that may wildly exceed 640K or whatever your memory space is. This is yet another argument to the program, its default is off. The reason for this is to study the program flow of the tree diagram to check for one overlay, calling another in order to prevent thrashing in a loop, speeding up execution by combining them into one overlay and so on.

I imagine other uses could be put into this extra information, the interpretation is up to the user. The same (!) co-worker also asked that the unused function list be sorted by filename. Yes, he had a lot of them! Because the sorting routine was already in place for the used functions, it was simple enough to clone it into the unused list display function.

Last Words

I trust that more C wizards will pop up and carry this ball a little further. I only carried it as far as I needed for my purposes. The C program that cp is now maintaining is over 4.2 million bytes, over 117,000 lines, 198 files, uses 993 defined functions called 4600 times, with 192 library functions called 3118 times! As you can imagine, this program does a wonderful job at wearing out printers! Thanks to Stewart for the great idea and for doing all the initial dirty work.

C Printer for VMS and Unix

Kevin E. Poole

Kevin is a software design engineer on the Boeing automated software engineering (BASE) project. The BASE project increases quality and productivity in the development of embedded computer software. The capabilities presented in the article are part of the BASE documentation production system. Kevin can be contacted at 14424 34th Ave. S., #2, Seattle, WA 98168.

I modified Ron Winter's PC/MS-DOS C Printer Utility (CP), presented in the accompanying article, to run on two additional operating systems: VAX VMS and VAX Unix. The modifications are divided into four sets of steps: The first set involves creating the makefiles, the second set involves modifying the C source code, the third involves compiling and running the new CP, and the fourth set provides two optional enhancements to CP. The listings in my version were developed using DEC VAX VMS 5.1-1 and DEC VAX Unix BSD 4.3.

Creating the makefiles

Step 1: An MMS utility description file was created for the VMS operating system, as shown in Listing One (page 86).

Step 2: The make utility makefile shown in Listing Two (page 86) was created for the Unix operating system.

Step 3: CP uses command-line options, so the following line should be added to the VMS login.com file to create a foreign command to run CP:

  CP == "$DEVICE:[YOUR_            ACCOUNT .CP]CP.EXE"

Step 4: Because the C Printer executable is called "cp," it was necessary to change it to something else so that it would not be confused with the Unix cp command. CP (printed in bold in my Listing Two) was changed to mycp. You can name it whatever you like.

Modifying the C Code

Because of space constraints, the entire source code for the VMS and the Unix version of the cp program are not included with this article. Instead, I've provided code that should be inserted into Ron's program, as well as code that should replace portions of his listings. Ron's listings will be prefaced by the letters "RW" (RW-Listing One, for example) so as not to be confused with the listings in this article. However, the complete system is available on the DDJ listings disk, the DDJ Forum on CompuServe, and on the DDJ Listing Service.

Step 1: Define one constant per operating system using C preprocessor #define commands. These constants are used in conjunction with the #if and #endif structures to surround code that is to be conditionally compiled. The lines in Listing Three (page 86) should be inserted into RW-Listing One between lines 3 and 4.

Step 2: The Microsoft C function declarations contain the reserved word "near," which is not supported by VMS or Unix. The function declaration blocks at the top of each source file ending in ".c" must be duplicated. Surround one block with the #if MSDOS and #endif pair. Surround the other block with the #if VMS and #endif pair. From the VMS block remove all instances of the "near" reserved word. The lines in Listing Four (page 86) should replace lines 27 through 52 in RW-Listing Two. The other source files must also be modified in this way. The Unix compiler produces syntax errors on function declarations, so they were omitted.

The Microsoft C function definitions also contain the reserved word "near." Function definitions containing the "near" reserved word must be duplicated. Remove the "near" reserved word from the duplicated definitions to support VMS and Unix. Surround the original and duplicate definitions with the #if MSDOS, #elseif, and #endif structure as in Listing Five (page 86), which replaces line 56 in RW-Listing Two. All function definitions in source files ending in .c should be changed in this way.

Step 3: Each compiler supplies a different set of include files. Where the include file names are the same, the contents most often differ. The lines in Listing Six (page 86) replace lines 5 through 9 in RW-Listing One and the lines in Listing Seven (page 86) replace line 25 in RW-Listing Two to make the necessary include-file modifications.

Step 4: A few library functions in the MS-DOS version were not found in either of the VAX C libraries. The strdup( ) function must be added to the code for VMS and Unix to duplicate the functionality of the missing library function. The function in Listing Eight (page 86) should be inserted between lines 824 and 825 in RW-Listing Two.

The CP report header contains the current date and time that is provided by the MS-DOS _strdate() and _strtime() functions. Although not in the same format, this information is provided by the time() and localtime() functions in VMS and Unix. A new function was created for VMS and Unix using the appropriate library calls. The MS-DOS code was moved into a function body and replaced by a call to the new function. The function call in Listing Nine (page 86) replaces lines 233 through 256 of RW-Listing Two and the functions in Listing Ten (page 86) should be inserted between lines 210 and 211 in RW-Listing Two.

Step 5: The MS-DOS and VMS tolower() library function returns the lowercase equivalent of an uppercase character or the same character if it is already lowercase. In Unix the function works the same if the character is uppercase, but it makes a lowercase character even lower, returning some character that is not a valid command-line option. Replace line 93 in RW-Listing Three with the code in Listing Eleven (page 88), which uses the islower() function to check the case of a character and passes the character to the tolower() function only if it is uppercase.

Step 6: CP directs output to the CRT by specifying that the outfile be "CON." On PC/MS-DOS, CON is a reserved system device and is therefore automatically assigned. On VMS and Unix the code in Listing Twelve (page 88) must replace line 850 in RW-Listing Two to facilitate this option.

Step 7: The Unix C compiler detected an error that neither the Microsoft nor the VMS compiler found. Replace line 868 in RW-Listing Two with the line in Listing Thirteen to remove the use of a variable called "errno" that was used but never declared and could cause a run-time error.

Step 8: Memory size limitations are not a concern on the virtual machines for the requirements of the C printer. Replace lines 95, 117, 140, 163, 188 in RW-Listing Two with the line in Listing Fourteen (page 88) to use the MS-DOS constant to inhibit CP's byte limit errors on VMS and Unix.

Compiling and Running CP

Step 1: After completing the steps required to modify the C source code, the code can be compiled on all of the supported operating systems using the make utilities and files.

Step 2: CP does not interpret C preprocessor directives, so compile the code with the C preprocessor and then run CP on the preprocessed code. Listings Fifteen (page 88) and Sixteen (page 88) contain the commands needed to run the C preprocessor on the CP source files on VMS and Unix, respectively.

Step 3: The cp.cpi file shown in Listing Seventeen (page 88) must be used as the list file to run CP on the preprocessed source code. If run on VMS or Unix, the -n option should be used to suppress IBM-type graphics characters in the output.

Enhancing CP

The following enhancements to the C Printer were developed to support the construction of design documents for software created by The Boeing Company.

Step 1: Path names can be very long in hierarchical directory structures, so it is necessary to modify CP in order that it will accept these long names in its list file. Insert the line in Listing Eighteen (page 88) between lines 18 and 19 of RW-Listing One and change the value of the LEN_FILE constant to the maximum size needed.

The rest of the changes needed are made by replacing line 262 of RW-Listing Two with the code in Listing Nineteen (page 88) and line 270 of RW-Listing Two with the code in Listing Twenty (page 88).

Step 2: When using long file names, the boxes that are displayed by CP get overrun. The b option has been added to CP to allow the size of the box to be varied at run time. See Listings Twenty-One through Twenty-Nine (pages 88-89) for the code and instructions needed to implement this option. The bounds-checking values (Listings Twenty-Eight and Twenty-Nine) and the default value (Listing Twenty-Five) can be changed to suit your needs. Listing Twenty-Seven will correct two errors with the help screen that were most likely inadvertently left out of the original program. Due to lack of space, the details of the code will not be discussed. If you have any questions about this option or about any aspect of the C Printer write me at the address given at the beginning of this article.

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




<a name="02a9_000f"></A><a name="02a9_000f"></A>
<a name="02a9_0010"></A>
[LISTING TWO]
<a name="02a9_0010"></A>

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





<a name="02a9_0011"></A><a name="02a9_0011"></A>
<a name="02a9_0012"></A>
[LISTING THREE]
<a name="02a9_0012"></A>

/***********************************************************************
                                   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..." );
   }
}
/***********************************************************************/





<a name="02a9_0013"></A><a name="02a9_0013"></A>
<a name="02a9_0014"></A>
[LISTING FOUR]
<a name="02a9_0014"></A>

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





<a name="02a9_0015"></A><a name="02a9_0015"></A>
<a name="02a9_0016"></A>
[LISTING FIVE]
<a name="02a9_0016"></A>

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





<a name="02a9_0017"></A><a name="02a9_0017"></A>
<a name="02a9_0018"></A>
[LISTING SIX]
<a name="02a9_0018"></A>

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;






<a name="02a9_0019"></A><a name="02a9_0019"></A>
<a name="02a9_001a"></A>
[LISTING SEVEN]
<a name="02a9_001a"></A>

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



===============================================================

_C PRINTER FOR VMS AND UNIX_
by Kevin E. Poole

SIDEBAR TO _AUTOMATIC MODULE CONTROL REVISITED_ BY RON WINTER


<a name="02a9_001b"></A><a name="02a9_001b"></A>
<a name="02a9_001c"></A>
[LISTING ONE]
<a name="02a9_001c"></A>

!
!  VAX/VMS MMS Description File
!
! DEFINITIONS:
H = cpheader.h
!
! CP
!
cp DEPENDS_ON cp.obj cpbuild.obj cpfuncts.obj cpinput.obj
   LINK/EXEC=cp cp.obj,cpbuild.obj,cpfuncts.obj,cpinput.obj
   PURGE *.obj, *.exe

cp.obj DEPENDS_ON $(H) cp.c
   cc cp.c

cpbuild.obj DEPENDS_ON $(H) cpbuild.c
   cc cpbuild.c

cpfuncts.obj DEPENDS_ON $(H) cpfuncts.c
   cc cpfuncts.c

cpinput.obj DEPENDS_ON $(H) cpinput.c
       cc cpinput.c





<a name="02a9_001d"></A><a name="02a9_001d"></A>
<a name="02a9_001e"></A>
[LISTING TWO]
<a name="02a9_001e"></A>

#
# VAX/Unix Makefile
#
# DEFINITIONS:
#
H = cpheader.h
#
# CP
#
cp : cp.o cpbuild.o cpfuncts.o cpinput.o
   cc -o cp cp.o cpbuild.o cpfuncts.o cpinput.o

cp.o : $H cp.c
   cc -c cp.c

cpbuild.o : $H cpbuild.c
   cc -c cpbuild.c

cpfuncts.o : $H cpfuncts.c
   cc -c cpfuncts.c

cpinput.o : $H cpinput.c
   cc -c cpinput.c





<a name="02a9_001f"></A><a name="02a9_001f"></A>
<a name="02a9_0020"></A>
[LISTING THREE]
<a name="02a9_0020"></A>

#define MSDOS 0    /* Set the appropriate constant */
#define VMS 0      /* to one (1) before compiling. */
#define UNIX 1      /* All others are zero (0)      */





<a name="02a9_0021"></A><a name="02a9_0021"></A>
<a name="02a9_0022"></A>
[LISTING FOUR]
<a name="02a9_0022"></A>

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

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

#if MSDOS
extern int  near binary_search_sorted_data_base( char * );
extern void near build_box_parts( int );
extern int  near build_the_data_base( 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 );
static char* near strdup( char * );
static void near timedate( char * );
       int  near main( int, char ** );
#endif






<a name="02a9_0023"></A><a name="02a9_0023"></A>
<a name="02a9_0024"></A>
[LISTING FIVE]
<a name="02a9_0024"></A>

#if MSDOS
static void near bump_line_count( )
#else
static void bump_line_count( )
#endif





<a name="02a9_0025"></A><a name="02a9_0025"></A>
<a name="02a9_0026"></A>
[LISTING SIX]
<a name="02a9_0026"></A>

#if MSDOS
#include <malloc.h>
#include <conio.h>
#include <stdlib.h>
#endif

#include <ctype.h>  /* this is for the 'tolower' function */
#include <stdio.h>
#include <string.h>






<a name="02a9_0027"></A><a name="02a9_0027"></A>
<a name="02a9_0028"></A>
[LISTING SEVEN]
<a name="02a9_0028"></A>

#if MSDOS
#include "time.h"
#else
#include <time.h>
#endif





<a name="02a9_0029"></A><a name="02a9_0029"></A>
<a name="02a9_002a"></A>
[LISTING EIGHT]
<a name="02a9_002a"></A>

#if !MSDOS
char *strdup(orig)
char *orig;
{
   char *ptr;

   ptr = (char *) malloc( (strlen(orig) * sizeof(char)) + 1);

   if(ptr != NULL)
   {
      strcpy(ptr,orig);
   }

   return(ptr);
}
#endif





<a name="02a9_002b"></A><a name="02a9_002b"></A>
<a name="02a9_002c"></A>
[LISTING NINE]
<a name="02a9_002c"></A>

   timedate(title);





<a name="02a9_002d"></A><a name="02a9_002d"></A>
<a name="02a9_002e"></A>
[LISTING TEN]
<a name="02a9_002e"></A>

/************************************************************/
#if !MSDOS
static void timedate(ret_time)
char *ret_time;
{
  struct tm *time_structure;
  int time_val, i;
  static char *hour[2] = {"am","pm"};
  char temp[19];

  time(&time_val);
  time_structure = localtime(&time_val);

  i = 0;
  if((time_structure->tm_hour >= 12)&&(time_structure->tm_hour<24)) i=1;

  if(time_structure->tm_hour > 12)
      time_structure->tm_hour = (time_structure->tm_hour)-12;
  sprintf(temp,"%d/%d/%d  %d:%02d %s",
              time_structure->tm_mon,
              time_structure->tm_mday,
              time_structure->tm_year,
              time_structure->tm_hour,
              time_structure->tm_min,
              hour[i]);
  i=0;
  while(temp[i]!='\0')
  {
     ret_time[i] = temp[i];
     i++;
  }
}
#endif

#if MSDOS
static void near timedate(ret_time)
char *ret_time;
{
  char *cp;
  int i;

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

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

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

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

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

  if( ret_time[ 10 ] == '0' )
     ret_time[ 10 ] = ' ';
}
#endif

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





 
 
[LISTING ELEVEN]
 

      if(islower((int)argv[i][1]))
    c = argv[i][1];
      else
    c = (char)tolower( (int)argv[ i ][ 1 ] );





 
 
[LISTING TWELVE]
 

   if( strcmp(argv[2],"con") == 0)
      output = stderr;
   else
      output = fopen( argv[ 2 ], "w+" );     /******* wt+ <<<<<<<< ******/





 
[LISTING THIRTEEN]
 

   (void)printf( "\n can't open output file.\n");



 
[LISTING FOURTEEN]
 

if( (length > 65535) && (MSDOS) )



 
[LISTING FIFTEEN]
 

$ CC/PREPROCESS_ONLY CP.C
$ CC/PREPROCESS_ONLY CPBUILD.C
$ CC/PREPROCESS_ONLY CPINPUT.C
$ CC/PREPROCESS_ONLY CPFUNCTS.C
$ CC/PREPROCESS_ONLY CPHEADER.H



 
[LISTING SIXTEEN]
 

cc -E cp.c >cp.i
cc -E cpbuild.c >cpbuild.i
cc -E cpinput.c >cpinput.i
cc -E cpfuncts.c >cpfuncts.i
cc -E cpheader.h >cpheader.i





 
[LISTING SEVENTEEN]
 

cp.i
cpinput.i
cpbuild.i
cpfuncts.i
cpheader.h





 
[LISTING EIGHTEEN]
 

#define  LEN_INFILE  256






 
[LISTING NINETEEN]
 

char input_list_filename[ LEN_INFILE ], input_line[ LEN_INFILE ];
char overlay_number[ LEN_INFILE ];





 
[LISTING TWENTY]
 

fgets( input_line, LEN_INFILE-1, stream );   /* ends at \n or eof */




 
[LISTING TWENTY-ONE]
 

Replaces line 20 of Listing Five

   *top_line_of_box, *bottom_line_of_box,




 
[LISTING TWENTY-TWO]
 

Replaces lines 73 thru 75 of Listing Five

if( !( top_line_of_box =(char *)malloc( defined_box_width * sizeof(char) ))
  )
{
   (void)fprintf( stderr, "Ran out of memory for top line of box.\n" );
   exit( 1 );
}

if( !( bottom_line_of_box =(char *)malloc( defined_box_width * sizeof(char) ))
  )
{
   (void)fprintf( stderr, "Ran out of memory for bottom line of box.\n" );
   exit( 1 );
}

top_line_of_box[ 0 ] = upper_left_corner;
bottom_line_of_box[ 0 ] = lower_left_corner;
for( i = 1; i <= (defined_box_width - 3); ++i )




 
[LISTING TWENTY-THREE]
 

Replaces lines 215 and 216 of Listing Five

                name_of_file,
                description,




 
[LISTING TWENTY-FOUR]
 

Replaces lines 228 thru 274 of Listing Five

unsigned int string_length;
int x;
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 ***/
   {
   if( g_ov_flag && ov_num )
      {
      (void)fprintf( output, "%s%c%c%c%s %3d",
           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, ov_num);
      for(x=strlen(name_of_function);x < defined_box_width-7;x++)
    putc(' ',output);
      putc(wall,output);
      putc('\n',output);
      }
   else
      {
      (void)fprintf( output, "%s%c%c%c%s    ",
           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);
      for(x=strlen(name_of_function);x < defined_box_width-7;x++)
    putc(' ',output);
      putc(wall,output);
      putc('\n',output);
      }
   }
else           /****** main or defined box starting ***********/
   {
   if( g_ov_flag && ov_num )
      {
      (void)fprintf( output,    "%c%c%s %3d",
           ibm_line, left_attach, name_of_function, ov_num);
      for(x=strlen(name_of_function);x < defined_box_width-7;x++)
    putc(' ',output);
      putc(wall,output);
      putc('\n',output);
      }
   else
      {
      (void)fprintf( output,    "%c%c%s    ",
           ibm_line, left_attach, name_of_function);
      for(x=strlen(name_of_function);x < defined_box_width-7;x++)
    putc(' ',output);
      putc(wall,output);
      putc('\n',output);
      }
   }
/******* 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%s   %8s%3d",
          lead_in_string, wall,  name_of_file, description, either_count);
   for(x=strlen(name_of_file);x < defined_box_width-17;x++) putc(' ',output);
   putc(wall,output);
   putc('\n',output);



 
[LISTING TWENTY-FIVE]
 

Insert between 109 and 110 of Listing One

   defined_box_width =      40,





[LISTING TWENTY-SIX]

Insert between 160 and 161 of Listing One

extern int defined_box_width;




[LISTING TWENTY-SEVEN]
Replaces lines 20 through 25 of Listing Three

    "     /p:nn /w:nn /m:nn /r:nn /t:main /f:nnnn /b:nn\n"
          );
   (void)printf(
   "     /l /n /s /q /d /o /u /c /h /x\n"
          );
   (void)printf(   "                        ]\n" );





[LISTING TWENTY-EIGHT]

Insert between 45 and 46 of Listing Three

   (void)printf(
   "     b: width of func. box  = %2d    [ 20 - 255 ]\n", defined_box_width
          );




[LISTING TWENTY-NINE]

Insert between 155 and 156 of Listing Three


        case 'b':
           if( ( 20 < tmp ) && ( tmp < 255 ) )
         defined_box_width = tmp;
           break;



Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video