home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / c / msc51 / example / cflow.c next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  43.7 KB  |  1,236 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. typedef unsigned int size_t;
  5.  
  6. extern char *strchr(char *, int);
  7. extern char *strcpy(char *, char *);
  8. extern char *strdup(char *);
  9. extern int atoi(char *);
  10. extern int strcmp(char *, char *);
  11. extern void *malloc(size_t);
  12. extern void exit(int);
  13. extern void free(void *);
  14.  
  15. int lineno;                    /* The current line number being parsed */
  16. int level;                    /* The level of quotes or comments being parsed */
  17. int parens;                    /* current parenthesis level */
  18. int braces;                    /* current curly brace level */
  19. int totalfuncs;                /* total number of functions seen */
  20.  
  21. #define PARENS(c) ( ( c == '(' ) - ( c == ')' ) )
  22. #define BRACES(c) ( ( c == '{' ) - ( c == '}' ) )
  23.  
  24. #define INITIA 0     /* Initial state of input stream machine */
  25. #define BEGCOM 1     /* Possible beginning of comment state */
  26. #define COMMEN 2     /* In comment state */
  27. #define AFTCOM 3     /* Possible end of comment state */
  28. #define DOUBQT 4     /* In double quote state */
  29. #define DBQTBS 5     /* Backslash in double quote state */
  30. #define SINGQT 6     /* In single quote state */
  31. #define SGQTBS 7     /* Backslash in single quote state */
  32. #define POUND 8     /* Preprocessor directive */
  33. #define BKSLHPND 9     /* Backslash in preprocessor directive */
  34.  
  35. #define TYPE 16         /* This character might preceed a possible return type */
  36. #define NAME 32     /* This character might preceed a possible function name */
  37.  
  38. #define HASHSIZE ( 2 << 10 )    /* Must be a power of two */
  39. #if 0
  40. #define MYBUFSIZ 15872            /* Size of buffer used on input stream */
  41. #endif
  42.  
  43. /****************************************************************/
  44. /**                                                            **/
  45. /**   ARGUMENTS: a structure capable of keeping info on the    **/
  46. /**              particular state of a file stream             **/
  47. /**                                                            **/
  48. /**   RETURN: none                                             **/
  49. /**                                                            **/
  50. /**   DESCRIPTION: SAVEPLACE saves the position in the buffer, **/
  51. /**   the line number, the current count of braces, and parens **/
  52. /**                                                            **/
  53. /**   GLOBAL VARS REFERENCED: lineno, braces, parens.          **/
  54. /**                                                            **/
  55. /**   GLOBAL VARS MODIFIED: none                               **/
  56. /**                                                            **/
  57. /****************************************************************/
  58.  
  59. #define SAVEPLACE(x) (x).lineno = lineno; (x).braces = braces; \
  60. (x).parens = parens; (x).place = ftell( fp )
  61.  
  62. /****************************************************************/
  63. /**                                                            **/
  64. /**   ARGUMENTS: a structure capable of keeping info on the    **/
  65. /**              particular state of a file stream.            **/
  66. /**                                                            **/
  67. /**   RETURN: none                                             **/
  68. /**                                                            **/
  69. /**   DESCRIPTION: RECOVERPLACE macro restores the position,   **/
  70. /**   the line number, the current count of braces, and parens **/
  71. /**   of the last time a SAVEPLACE was done to the argument.   **/
  72. /**                                                            **/
  73. /**   GLOBAL VARS REFERENCED: lineno, braces, parens.          **/
  74. /**                                                            **/
  75. /**   GLOBAL VARS MODIFIED: lineno, braces, parens, fp         **/
  76. /**                                                            **/
  77. /****************************************************************/
  78.  
  79. #define RECOVERPLACE(x) lineno = (x).lineno; braces = \
  80. (x).braces; parens = (x).parens; fseek( fp, (x).place, 0 )
  81.  
  82. /***************************************************************************/
  83. /**                                                                       **/
  84. /**  Global struct/union/enums                                            **/
  85. /**                                                                       **/
  86. /***************************************************************************/
  87.  
  88. enum relationchoice {
  89.         CALLER,
  90.         CALLEE
  91.     };
  92.  
  93. struct placeptr {
  94.         long place;            /* position as reported/used by ftell/fseek */
  95.         int parens;            /* parenthesis level to save/recover */
  96.         int braces;            /* curly brace level to save/recover */
  97.         int lineno;            /* The current line number being parsed */
  98.         };
  99.  
  100. struct func_ref_type {
  101.         char *name;                /* name of function referenced */
  102.         char *type;                /* type fo functions return */
  103.         char *pnext_func_ref;    /* pointer to next function in hashtable */
  104.         char *pcallerlist;        /* singly linked list of pointers to functions
  105.                                     callee's */
  106.         char *pcalleelist;        /* singly linked list of pointers to functions
  107.                                     caller's */
  108.         char *file_name;        /* name of file containing function reference */
  109.         int lineno;                /* line number of reference to function */
  110.         int xref;                /* cross reference of last pruning */
  111.         };
  112.  
  113.     /* hash table */
  114. struct func_ref_type *hashtbl[ HASHSIZE ] = { (struct func_ref_type *)NULL };
  115.  
  116. struct listtype {
  117.         struct func_ref_type *pelist;
  118.         char *pnext_func_ref;    /* pointer to next element of list */
  119.         char *file_name;        /* name of file where reference occoured */
  120.         int lineno;                /* line number where reference occoured */
  121.         };
  122.  
  123. struct listtype ellipses = {     /* A null list element for pruning purposes */
  124.                             (struct func_ref_type *)NULL, 
  125.                             (char *)NULL, 
  126.                             (char *)NULL, 
  127.                             0 
  128.                             };
  129.  
  130. struct placeptr last_func_name;
  131. struct placeptr last_func_ret_type;
  132.  
  133.  
  134. /***************************************************************************/
  135. /**                                                                       **/
  136. /**  Function prototypes                                                  **/
  137. /**                                                                       **/
  138. /***************************************************************************/
  139.  
  140. int mycompare( char **, char ** );
  141. int getsucc();                
  142. int hashfunc( char * );
  143. int ismember( char *, char *[] );
  144. int main( int, char *[] );
  145. int nsuccmemb( char * );
  146. int succpos( int );
  147.  
  148. static void quicksort( char *, char * );
  149. static void swap ( char *, register char *, unsigned int );
  150. struct func_ref_type *findname( char * );
  151. struct func_ref_type *makename( char * );
  152.  
  153. void addlist( struct func_ref_type *, struct func_ref_type *, char *, 
  154.             int, enum relationchoice );
  155. void dumptree( struct func_ref_type *, int, enum relationchoice );
  156. void findproc( void );
  157. void initstatemachine();
  158. void qsort( char *, unsigned int, unsigned int, int (*)( char **, char ** ) );
  159. void readtoken( char *, char * );  
  160. void sortdump( enum relationchoice );
  161.  
  162.  
  163.  
  164. /***************************************************************************/
  165. /**                                                                       **/
  166. /**  Global declarations                                                  **/
  167. /**                                                                       **/
  168. /***************************************************************************/
  169.  
  170. char *defaulttype = "int";        /* Pointer to the default return type for C */
  171. char *endofsp = "Out of space";    /* Pointer to error message */
  172. char *reswords[] = {             /* reserved words that could look like 
  173.                                                                 functions */
  174.                     "if", 
  175.                     "while", 
  176.                     "for", 
  177.                     "return",
  178.                        "sizeof", 
  179.                        "switch", 
  180.                     NULL 
  181.                     };
  182.  
  183. char alphanum[] =                 /* array of alpha numeric characters */
  184. "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789";
  185.                                 /* delimiters used by cflow */
  186. char delimits[] = " !@#$%^&*()-+=<>,.?/:;~`'|\n\\\t";
  187. char filename[ 30 ];            /* Contains the name of the current file 
  188.                                                             being scanned */
  189.                                 /* array of state transitions for input
  190.                                     state machine */
  191. char gotonextstate[ 10 ][ 128 ] = { 0 };
  192. #if 0
  193. char mybuffer[ MYBUFSIZ ];        /* Buffer for the input file */
  194. #endif
  195. char parentproc[ 2048 ];            /* Name of current parent procedure */
  196. char procname[ 2048 ];            /* Contains the name of the procedure 
  197.                                                 reference being scanned */
  198. char spceq[] = " \t\n\r";        /* whitespace */
  199. char *typename;            /* Contains the name of the return type of the  
  200.                                                 reference being scanned */
  201.  
  202. FILE *fp;                        /* File pointer used for input */
  203. int cutoff = 35;                /* Maximum depth of output ( default 35 ) */
  204. int verbose = 0;                /* Verbose flag ( 0 off, 1 on ) */
  205. enum relationchoice relationship = CALLEE;        
  206.                                 /* relationship wanted on output 
  207.                                                         ( default CALLEE ) */
  208. int xref = 0;                    /* Starting xref number */
  209.  
  210. /****************************************************************/
  211. /**                                                            **/
  212. /**   ARGUMENTS: count of command line arguments               **/
  213. /**              a pointer to the array of command line args.  **/
  214. /**                                                            **/
  215. /**   RETURN: 0 if no errors, -1 if out of memory.             **/
  216. /**                                                            **/
  217. /**   DESCRIPTION: This program scanns the flags, and sets     **/
  218. /**   appropriate flags.  After this all of the remaining args **/
  219. /**   that can be opened as files are opened and the contents  **/
  220. /**   scanned for function references.  These are put in lists **/
  221. /**   such that each function has a linked list of caller to   **/
  222. /**   that function, and of callees of that function.  On      **/
  223. /**   output either the callee tree(s) is/are printed, or the  **/
  224. /**   callers trees are printed under control of the -r flag.  **/
  225. /**   If there is more than one tree to be printed, then the   **/
  226. /**   function names, which are the roots of the trees, are    **/
  227. /**   sorted lexicographically before output.                  **/
  228. /**                                                            **/
  229. /**   GLOBAL VARS REFERENCED: verbose, cutoff, relationship    **/
  230. /**                           parens, braces, lineno, level,   **/
  231. /**                           totalfuncs                       **/
  232. /**                                                            **/
  233. /**   GLOBAL VARS MODIFIED: verbose, cutoff, relationship      **/
  234. /**                         parens, braces, lineno, level,     **/
  235. /**                         totalfuncs                         **/
  236. /**                                                            **/
  237. /****************************************************************/
  238.  
  239. int main( argc, argv )
  240.  
  241.     int argc;
  242.     char *argv[];
  243.  
  244.     int c;
  245.     if ( argc < 2 )
  246.         {
  247.         printf( "usage: cflow [-v][-r][-d] filelist" );
  248.         }
  249.     else
  250.         {
  251.         initstatemachine();
  252.         while ( --argc > 0 )
  253.             {                     /* for all flags/files on the command line */    
  254.             ++argv;
  255.             if ( ( c = **argv ) == '-' || c == '/' )
  256.                 {    /* we are processing a flag */
  257.                 while ( c = *(++(*argv)) )
  258.                     {
  259.                     switch( c )
  260.                         {    
  261.  
  262.                     case 'v': /* be verbose on self references */
  263.                     case 'V':
  264.                             verbose++;
  265.                             break;
  266.  
  267.                     case 'r': /* reverse the caller:callee relationship */
  268.                     case 'R':    
  269.                             relationship = CALLER;
  270.                             break;
  271.  
  272.                     case 'd': /* set the flow graph cutoff depth */
  273.                     case 'D':
  274.                             if ( isdigit(*(++(*argv))) )
  275.                                 {
  276.                                 cutoff = atoi( *argv );
  277.                                 }
  278.                             break;
  279.                         }
  280.                     }    /* End of while */
  281.                 }
  282.             else
  283.                 {    /* we are processing a file, and should be done 
  284.                         with flags */
  285.                 if ( ( fp = fopen( *argv, "rt" ) ) == NULL )
  286.                     { 
  287.                     printf( "cflow: can't open %s\n", *argv );
  288.                     }
  289.                 else
  290.                     {
  291. #if 0
  292.                     setvbuf( fp, mybuffer, _IOFBF, (unsigned int)sizeof( mybuffer ) );
  293. #endif
  294.                     puts( *argv );
  295.                     strcpy( filename, *argv );
  296.                     totalfuncs = parens = braces = level = 0;
  297.                     lineno = 1;
  298.                     SAVEPLACE( last_func_name );
  299.                     SAVEPLACE( last_func_ret_type );
  300.                     while ( succpos( '(' ) )
  301.                         {            /* we have found a begin paren */
  302.                         findproc();
  303.                         }    /* End of while */
  304.                     fclose( fp );
  305.                     }
  306.                 }
  307.             }    /* End of while */
  308.         }
  309.     if ( relationship == CALLEE )
  310.         {    /* "normal" caller:callee relationship */
  311.         if ( findname( "main" ) )
  312.             {    /* Found main */
  313.             dumptree( findname( "main" ), 0, relationship );
  314.             }
  315.         else
  316.             {    /* No main found */
  317.             sortdump( relationship );
  318.             }
  319.         }
  320.     else
  321.         {    /* reverse caller:callee relationship */
  322.         sortdump( relationship );
  323.         }
  324.     return( 0 );
  325. }
  326.  
  327.  
  328.  
  329. /****************************************************************/
  330. /**                                                            **/
  331. /**   ARGUMENTS: none                                          **/
  332. /**                                                            **/
  333. /**   RETURN: none                                             **/
  334. /**                                                            **/
  335. /**   DESCRIPTION: findproc locates the name of the function   **/
  336. /**   preceeding the parenthesis, and figures out whether we   **/
  337. /**   are looking at a function definition, or a function call **/
  338. /**   also adds to the caller, and callee list of the function **/
  339. /**   as appropriate. ( see addlist() )                        **/
  340. /**                                                            **/
  341. /**   GLOBAL VARS REFERENCED: last_func_ret_type,              **/
  342. /**                           last_func_name, alphanum,        **/
  343. /**                           procname, braces, parentproc,    **/
  344. /**                           lineno, parens, spceq,           **/
  345. /**                           defaulttype                      **/
  346. /**                                                            **/
  347. /**   GLOBAL VARS MODIFIED: none                               **/
  348. /**                                                            **/
  349. /**                                                            **/
  350. /****************************************************************/
  351.  
  352. void findproc()
  353.  
  354. {
  355.     char *thisplace;
  356.     long sizetype;
  357.     int oldlineno, oldbraces, oldparens;
  358.     struct placeptr place, typeplace, tplace;
  359.     struct func_ref_type *alist, *blist;
  360.     SAVEPLACE( place );
  361.     typeplace = last_func_ret_type;
  362.     place.place++;
  363.     RECOVERPLACE( last_func_name );
  364.     sizetype = last_func_name.place;
  365.     readtoken( alphanum, procname );
  366.     if ( ! braces )
  367.         {
  368.         strcpy( parentproc, procname );
  369.         }
  370.     if ( *procname && strchr( alphanum, *procname ) && 
  371.             ( ismember( procname, reswords ) == -1 ) )
  372.         {        /* This is a function call, prototype, or definition */
  373.         oldlineno = lineno;
  374.         oldbraces = braces;
  375.         oldparens = parens + 1;
  376.         while ( succpos( ')' ) )
  377.             {
  378.             getsucc();
  379.             if ( parens <= oldparens )
  380.                 {
  381.                 break;
  382.                 }
  383.             }
  384.         nsuccmemb( spceq ); 
  385.         if ( getsucc() != ';' || oldbraces != 0 )
  386.             {    /* This is a call or a definition */
  387.             alist = makename( parentproc );
  388.             blist = makename( procname );
  389.  
  390.             if ( oldbraces )
  391.                 {    /* This is scanning a call */
  392.                 addlist( alist, blist, filename, oldlineno, CALLEE );
  393.                 addlist( blist, alist, filename, oldlineno, CALLER );
  394.                 }
  395.             else
  396.                 {    /* This is scanning a definition */
  397.                 if ( alist->file_name )
  398.                     {
  399.                     free( alist->file_name );
  400.                     }
  401.                 alist->file_name = strdup( filename );
  402.                 alist->lineno = oldlineno;
  403.                 }
  404.             }
  405.         else
  406.             {    /* This is scanning a prototype */
  407.             RECOVERPLACE( typeplace );
  408.                         /* remove starting whitespace */
  409.             nsuccmemb( spceq ); 
  410.             SAVEPLACE( typeplace );
  411.             sizetype -= typeplace.place;
  412.             if ( ( thisplace = typename = malloc( sizetype+ 1 ) ) == NULL )
  413.                 {
  414.                 fprintf( stderr, endofsp );
  415.                 exit( -1 );
  416.                 }
  417.             for ( thisplace = typename; --sizetype >= 0L; )
  418.                 {
  419.                 *thisplace++ = (char)getsucc();
  420.                 }    /* End of for */
  421.             *thisplace = '\0';
  422.             alist = makename( procname );
  423.             if ( alist->type != defaulttype )
  424.                 {
  425.                 free( alist->type );
  426.                 }
  427.             alist->type = typename;
  428.             }
  429.         }
  430.     RECOVERPLACE( place );
  431.  
  432.  
  433. /****************************************************************/
  434. /**                                                            **/
  435. /**   ARGUMENTS: a token name.                                 **/
  436. /**                                                            **/
  437. /**   RETURN: a pointer to a struct func_ref_type              **/
  438. /**                                                            **/
  439. /**   DESCRIPTION: makename sets up an function reference      **/
  440. /**   structure for hash lookup later.                         **/
  441. /**                                                            **/
  442. /**   GLOBAL VARS REFERENCED: hashtbl, hashval, totalfuncs,    **/
  443. /**                           endofsp                          **/
  444. /**                                                            **/
  445. /**                                                            **/
  446. /**   GLOBAL VARS MODIFIED: hashtbl, hashval, totalfuncs       **/
  447. /**                                                            **/
  448. /****************************************************************/
  449.  
  450. struct func_ref_type *makename( nameptr )
  451.  
  452.     char *nameptr;
  453.  
  454. {
  455.     struct func_ref_type *pelist;
  456.     int hashval;
  457.     int newel = 1;
  458.     pelist = hashtbl[ hashval = hashfunc( nameptr ) ];
  459.     if ( pelist )
  460.         {
  461.         while ( ( newel = strcmp( nameptr, pelist->name ) ) &&
  462.                 pelist->pnext_func_ref )
  463.             {    
  464.             pelist = (struct func_ref_type *)pelist->pnext_func_ref;
  465.             }    /* End of while */
  466.         if ( newel )
  467.             {
  468.             if ( ( pelist->pnext_func_ref = 
  469.                     malloc( sizeof( struct func_ref_type ) ) ) == NULL )
  470.                 {
  471.                 fprintf( stderr, endofsp );
  472.                 exit( -1 );
  473.                 }
  474.             pelist = (struct func_ref_type *)(pelist->pnext_func_ref);
  475.             totalfuncs++;
  476.             }
  477.         }
  478.     else
  479.         {
  480.         if ( ( pelist = ( hashtbl[ hashval ] 
  481.             = (struct func_ref_type *)malloc( 
  482.             sizeof( struct func_ref_type ) ) ) ) == NULL )
  483.             {
  484.             fprintf( stderr, endofsp );
  485.             exit( -1 );
  486.             }
  487.         totalfuncs++;
  488.         }
  489.     if ( newel )
  490.         {    /* Initialize function name node to undefined state. */
  491.         pelist->pcallerlist = NULL;
  492.         pelist->pnext_func_ref = NULL;
  493.         pelist->type = defaulttype;
  494.         pelist->pcalleelist = NULL;
  495.         pelist->file_name = NULL;
  496.         pelist->name = strdup( nameptr );
  497.         }
  498.     if ( pelist == NULL )
  499.             {
  500.             fprintf( stderr, endofsp );
  501.             exit( -1 );
  502.             }
  503.     return( pelist );
  504. }
  505.  
  506.  
  507. /****************************************************************/
  508. /**                                                            **/
  509. /**   ARGUMENTS: a token name.                                 **/
  510. /**                                                            **/
  511. /**   RETURN: a pointer to a struct func_ref_type              **/
  512. /**                                                            **/
  513. /**   DESCRIPTION: findname returns a function reference to    **/
  514. /**   the structure whose name field matches the token name,   **/
  515. /**   or NULL in the case of no match.                         **/
  516. /**                                                            **/
  517. /**   GLOBAL VARS REFERENCED: hashval, hashfunc                **/
  518. /**                                                            **/
  519. /**   GLOBAL VARS MODIFIED: none                               **/
  520. /**                                                            **/
  521. /****************************************************************/
  522.  
  523. struct func_ref_type *findname( nameptr )
  524.  
  525.     char *nameptr;
  526.  
  527. {
  528.     struct func_ref_type *pelist;
  529.     int hashval;
  530.     pelist = hashtbl[ hashval = hashfunc( nameptr ) ];
  531.     if ( pelist )
  532.         {
  533.         while ( strcmp( nameptr, pelist->name ) &&
  534.                 pelist->pnext_func_ref )
  535.             {    
  536.             pelist = (struct func_ref_type *)pelist->pnext_func_ref;
  537.             }    /* End of while */
  538.         }
  539.     return( pelist );
  540. }
  541.  
  542.  
  543.  
  544. /****************************************************************/
  545. /**                                                            **/
  546. /**   ARGUMENTS: token to get hashed                           **/
  547. /**                                                            **/
  548. /**   RETURN: hash value.                                      **/
  549. /**                                                            **/
  550. /**   DESCRIPTION: hashfunc hashes tokens based on the sum     **/
  551. /**   of all the characters in the token.                      **/
  552. /**                                                            **/
  553. /**   GLOBAL VARS REFERENCED: hashval, hashfunc                **/
  554. /**                                                            **/
  555. /**   GLOBAL VARS MODIFIED: none                               **/
  556. /**                                                            **/
  557. /****************************************************************/
  558.  
  559. int hashfunc( token )
  560.  
  561.     char *token;
  562.  
  563. {
  564.     int retval = 0;
  565.     for ( ; *token ; retval += *token++ )
  566.         ;
  567.     return( retval & ( HASHSIZE - 1 ) );
  568. }
  569.  
  570.  
  571. /****************************************************************/
  572. /**                                                            **/
  573. /**   ARGUMENTS: Two function reference pointers, the          **/
  574. /**              filename where the reference took place.      **/
  575. /**              The line number where the reference occoured. **/
  576. /**              And the relation between the first two        **/
  577. /**              references.                                   **/
  578. /**                                                            **/
  579. /**   RETURN: void                                             **/
  580. /**                                                            **/
  581. /**   DESCRIPTION: addlist adds one function to the others     **/
  582. /**   CALLEE/CALLER list the list being chosen by the relation **/
  583. /**   being passed in.                                         **/
  584. /**                                                            **/
  585. /**   GLOBAL VARS REFERENCED: endofsp                          **/
  586. /**                                                            **/
  587. /**   GLOBAL VARS MODIFIED: none                               **/
  588. /**                                                            **/
  589. /****************************************************************/
  590.  
  591. void addlist( pafunc, pbfunc, filename, lineno, relation )
  592.  
  593.     struct func_ref_type *pafunc;
  594.     struct func_ref_type *pbfunc;
  595.     char *filename;
  596.     int lineno;
  597.     enum relationchoice relation;
  598.  
  599. {
  600.     struct listtype *listptr;
  601.     char *parentptr;
  602.     if ( ( ( relation == CALLEE ) ? 
  603.             pafunc->pcalleelist : pafunc->pcallerlist ) == NULL )
  604.         {
  605.         if ( ( listptr = (struct listtype *)malloc( 
  606.                 sizeof( struct listtype ) ) ) == NULL )
  607.             {
  608.             fprintf( stderr, endofsp );
  609.             exit( -1 );
  610.             }
  611.         if ( relation == CALLEE )
  612.             {
  613.             pafunc->pcalleelist = (char *)listptr;
  614.             }
  615.         else
  616.             {
  617.             pafunc->pcallerlist = (char *)listptr;
  618.             }
  619.         }
  620.     else
  621.         {
  622.         listptr = (struct listtype *)( relation == CALLEE ? 
  623.                             pafunc->pcalleelist : pafunc->pcallerlist );
  624.         while ( listptr->pnext_func_ref )
  625.             {    /* walk the list, and insert at the end */
  626.             listptr = (struct listtype *)listptr->pnext_func_ref;
  627.             }    /* End of while */
  628.         if ( ( listptr->pnext_func_ref = (char *)malloc( 
  629.                 sizeof( struct listtype ) ) ) == NULL )
  630.             {
  631.             fprintf( stderr, endofsp );
  632.             exit( -1 );
  633.             }
  634.         listptr = (struct listtype *)listptr->pnext_func_ref;
  635.         }
  636.     
  637.     listptr->pelist = pbfunc;
  638.     listptr->pnext_func_ref = NULL;
  639.     listptr->file_name = strdup( filename );
  640.     listptr->lineno = lineno;
  641. }
  642.  
  643.  
  644. /****************************************************************/
  645. /**                                                            **/
  646. /**   ARGUMENTS: pointer to a function reference.              **/
  647. /**              level of nesting so far.                      **/
  648. /**              relation to use.                              **/
  649. /**                                                            **/
  650. /**   RETURN: none                                             **/
  651. /**                                                            **/
  652. /**   DESCRIPTION: dumptree prints out the current nesting     **/
  653. /**   level of relation and calls itself recursively for lower **/
  654. /**   nesting levels.                                          **/
  655. /**                                                            **/
  656. /**   GLOBAL VARS REFERENCED: cutoff, verbose, ellipses        **/
  657. /**                                                            **/
  658. /**   GLOBAL VARS MODIFIED: none                               **/
  659. /**                                                            **/
  660. /****************************************************************/
  661.  
  662. void dumptree( pafunc, level, relation )
  663.  
  664.     struct func_ref_type *pafunc;
  665.     int level;
  666.     enum relationchoice relation;
  667.  
  668. {
  669.     struct listtype *roverptr;
  670.     struct listtype *beginlist;
  671.     struct func_ref_type *old_pafunc;
  672.     char *old_nextptr;
  673.     int i;
  674.     if ( pafunc && level < cutoff )
  675.         {            /* There is a branch below this level */
  676.         if ( !level )
  677.             {
  678.             printf( "%4d", level );
  679.             for ( i = 0; i <= level; i++ )
  680.                 {
  681.                 putchar( '\t' );
  682.                 }    /* End of for */
  683.  
  684.             if ( pafunc->file_name )
  685.                 {    /* a definition has been found */
  686.                 printf( "%s:%s() <%s,%d>\n", pafunc->name, pafunc->type, 
  687.                     pafunc->file_name, pafunc->lineno );
  688.                 }
  689.             else
  690.                 {
  691.                 printf( "%s:%s() <,>\n", pafunc->name, pafunc->type );
  692.                 }
  693.             level++;
  694.             }
  695.         if ( relation == CALLEE )
  696.             {
  697.             beginlist = roverptr = (struct listtype *)pafunc->pcalleelist;
  698.             }
  699.         else
  700.             {
  701.             beginlist = roverptr = (struct listtype *)pafunc->pcallerlist;
  702.             }
  703.  
  704.         while ( roverptr )
  705.             {        /* Walk the list of CALLER/CALLEE's */
  706.             if ( !verbose && beginlist != &ellipses && beginlist == roverptr )
  707.                 {
  708.                 printf( "(%3d)", xref );
  709.                 }
  710.             else
  711.                 {
  712.                 printf( "     ", xref );
  713.                 }
  714.             printf( "%4d", level );
  715.  
  716.             for ( i = 0; i <= level; i++ )
  717.                 {
  718.                 putchar( '\t' );
  719.                 }    /* End of for */
  720.  
  721.             if ( roverptr->pelist != (struct func_ref_type *)NULL )
  722.                 {
  723.                 printf( "%s:%s() <%s,%d>", roverptr->pelist->name, 
  724.                     roverptr->pelist->type, roverptr->file_name, 
  725.                     roverptr->lineno );
  726.                 }
  727.             else
  728.                 {
  729.                 printf( "...relations shown at (%1d)", pafunc->xref );
  730.                 }
  731.             old_pafunc = roverptr->pelist;
  732.             old_nextptr = roverptr->pnext_func_ref;
  733.             if ( !verbose && beginlist != &ellipses && beginlist == roverptr )
  734.                 {
  735.                 free( beginlist->file_name );
  736.                 free( beginlist );
  737.                 pafunc->xref = xref++;
  738.                 if ( relation == CALLEE )
  739.                     {
  740.                     pafunc->pcalleelist = (char *)&ellipses;
  741.                     }
  742.                 else
  743.                     {
  744.                     pafunc->pcallerlist = (char *)&ellipses;
  745.                     }
  746.                 }
  747.             putchar( '\n' );
  748.             dumptree( old_pafunc, level + 1, relation );
  749.             roverptr = (struct listtype *)old_nextptr;
  750.             }    /* End of while */
  751.         }
  752. }
  753.  
  754. /****************************************************************/
  755. /**                                                            **/
  756. /**   ARGUMENTS: none                                          **/
  757. /**                                                            **/
  758. /**   RETURN: none                                             **/
  759. /**                                                            **/
  760. /**   DESCRIPTION: initstatemachine sets up which state to go  **/
  761. /**   to given which state is currently active and which       **/
  762. /**   character has been read in.                              **/
  763. /**                                                            **/
  764. /**   GLOBAL VARS REFERENCED: gotonextstate                    **/
  765. /**                                                            **/
  766. /**   GLOBAL VARS MODIFIED: gotonextstate                      **/
  767. /**                                                            **/
  768. /****************************************************************/
  769.  
  770. void initstatemachine()
  771.  
  772. {
  773.     int character;
  774.     for ( character = 0; character < 128; character++ )
  775.         {    /* set up the majority of state jumps */
  776.         if ( !isalnum( character ) && character != '_' && character != '(' )
  777.             {
  778.             gotonextstate[ INITIA ][ character ] = NAME;
  779.             }
  780.         else
  781.             {
  782.             gotonextstate[ INITIA ][ character ] = INITIA;
  783.             }
  784.         gotonextstate[ BEGCOM ][ character ] = INITIA;
  785.         gotonextstate[ COMMEN ][ character ] = COMMEN;
  786.         gotonextstate[ AFTCOM ][ character ] = COMMEN;
  787.         gotonextstate[ DOUBQT ][ character ] = DOUBQT;
  788.         gotonextstate[ DBQTBS ][ character ] = DOUBQT;
  789.         gotonextstate[ SINGQT ][ character ] = SINGQT;
  790.         gotonextstate[ SGQTBS ][ character ] = SINGQT;
  791.         gotonextstate[ POUND ][ character ] = POUND;
  792.         gotonextstate[ BKSLHPND ][ character ] = POUND;
  793.         }    /* End of for */
  794.     /* Now set all of the exceptions */
  795.  
  796.     gotonextstate[ INITIA ][ ';' ] = TYPE;    /* preceeding beginning of a type */
  797.     gotonextstate[ INITIA ][ ',' ] = TYPE;    
  798.     gotonextstate[ INITIA ][ '{' ] = TYPE;    
  799.     gotonextstate[ INITIA ][ '}' ] = TYPE;    
  800.  
  801.     gotonextstate[ AFTCOM ][ '*' ] = AFTCOM;    /* possible end of comment */
  802.     gotonextstate[ AFTCOM ][ '/' ] = INITIA;    /* end comment is confirmed */
  803.     gotonextstate[ BEGCOM ][ '*' ] = COMMEN;    /* possible end of comment */
  804.     gotonextstate[ COMMEN ][ '*' ] = AFTCOM;    /* possible end of comment */
  805.     gotonextstate[ DOUBQT ][ '"' ] = INITIA;    /* end of double quoted stuff */
  806.     gotonextstate[ DOUBQT ][ '\\' ] = DBQTBS;    /* protect the next character */
  807.     gotonextstate[ INITIA ][ '"' ] = DOUBQT;    /* double quoted stuff */
  808.     gotonextstate[ INITIA ][ '#' ] = POUND;        /* beginning of preprcssr */
  809.     gotonextstate[ INITIA ][ '/' ] = BEGCOM;    /* beginning of comment*/
  810.     gotonextstate[ INITIA ][ '\'' ] = SINGQT;    /* single quoted stuff */
  811.     gotonextstate[ POUND ][ '\\' ] = BKSLHPND;    /* backslash in preprocessor */
  812.     gotonextstate[ POUND ][ '\n' ] = TYPE;        /* end of preprocessor */
  813.     gotonextstate[ SINGQT ][ '\'' ] = INITIA;    /* end of single quoted stuff */
  814.     gotonextstate[ SINGQT ][ '\\' ] = SGQTBS;    /* protect the next character */
  815. }
  816.  
  817.  
  818. /****************************************************************/
  819. /**                                                            **/
  820. /**   ARGUMENTS: relationship to use for outputting trees.     **/
  821. /**                                                            **/
  822. /**   RETURN: none                                             **/
  823. /**                                                            **/
  824. /**   DESCRIPTION: sortdump looks at all of the function names **/
  825. /**   and sorts them using qsort.  Then the functions are      **/
  826. /**   dumped out using dumptree with the relation wanted being **/
  827. /**   passed on to dumptree.                                   **/
  828. /**                                                            **/
  829. /**   GLOBAL VARS REFERENCED: totalfuncs, endofsp, hashtbl     **/
  830. /**                                                            **/
  831. /**   GLOBAL VARS MODIFIED: none                               **/
  832. /**                                                            **/
  833. /****************************************************************/
  834.  
  835. void sortdump( relationship )
  836.  
  837.     enum relationchoice relationship;
  838.  
  839. {
  840.     int hashlook;
  841.     struct func_ref_type **ppelist;
  842.     struct func_ref_type *pcollisionwalker;
  843.     struct func_ref_type **ppsorttable;
  844.     if ( ( ppsorttable = (struct func_ref_type **)malloc( 
  845.             sizeof(struct func_ref_type *) * ( totalfuncs + 1 ) ) ) == NULL )
  846.         {
  847.         fprintf( stderr, endofsp );
  848.         exit( -1 );
  849.         }
  850.     ppelist = ppsorttable;
  851.     for ( hashlook = 0; hashlook < HASHSIZE; hashlook++ )
  852.         {                /* for each element in the hash table */
  853.         if ( hashtbl[ hashlook ] )
  854.             {
  855.             pcollisionwalker = *ppelist = hashtbl[ hashlook ];
  856.             ppelist++;
  857.             while ( pcollisionwalker->pnext_func_ref )
  858.                 {        /* for each collision element */
  859.                 pcollisionwalker = 
  860.                     (struct func_ref_type *)pcollisionwalker->pnext_func_ref;
  861.                 *ppelist = pcollisionwalker;
  862.                 ppelist++;
  863.                 }    /* End of while */
  864.             }
  865.         }    /* End of for */
  866.     qsort( (char *)ppsorttable, totalfuncs, sizeof(struct func_ref_type *), 
  867.             mycompare );
  868.     ppelist = ppsorttable;
  869.     while ( ppelist < (ppsorttable + totalfuncs) )
  870.         {
  871.         putchar( '\n' );
  872.         dumptree( *ppelist, 0, relationship );
  873.         ppelist++;
  874.         }    /* End of while */
  875. }
  876.  
  877. /****************************************************************/
  878. /**                                                            **/
  879. /**   ARGUMENTS: pointers to two function reference nodes      **/
  880. /**                                                            **/
  881. /**   RETURN: 1, 0, or -1                                      **/
  882. /**                                                            **/
  883. /**   DESCRIPTION: compare compares the two function names in  **/
  884. /**   the structures pointed to by ppa, and ppb.  The return   **/
  885. /**   value is the result of the strcmp of these two names.    **/
  886. /**                                                            **/
  887. /**   GLOBAL VARS REFERENCED: none                             **/
  888. /**                                                            **/
  889. /**   GLOBAL VARS MODIFIED: none                               **/
  890. /**                                                            **/
  891. /****************************************************************/
  892.  
  893. int mycompare( ppa, ppb )
  894.  
  895.     char **ppa;
  896.     char **ppb;
  897.  
  898. {
  899.     return( strcmp( ((struct func_ref_type *)(*ppa))->name, 
  900.             ((struct func_ref_type *)(*ppb))->name ) );
  901. }
  902.  
  903.  
  904. /****************************************************************/
  905. /**                                                            **/
  906. /**   ARGUMENTS: none                                          **/
  907. /**                                                            **/
  908. /**   RETURN: an integer                                       **/
  909. /**                                                            **/
  910. /**   DESCRIPTION: This state machine reads in characters and  **/
  911. /**   keeps reading in characters until an initial state is    **/
  912. /**   reached, this means the character being read is not in a **/
  913. /**   comment, or quoted.  Also tags are marked to show the    **/
  914. /**   possible start of function names, and type returns.  In  **/
  915. /**   addition a count of parens and braces is made for use    **/
  916. /**   elsewhere.                                               **/
  917. /**                                                            **/
  918. /**   GLOBAL VARS REFERENCED: lineno, parens, gotonextstate,   **/
  919. /**                           braces, last_func_ret_type,      **/
  920. /**                           last_func_name                   **/
  921. /**                                                            **/
  922. /**   GLOBAL VARS MODIFIED:   lineno, parens, braces,          **/
  923. /**                           last_func_ret_type,              **/
  924. /**                           last_func_name                   **/
  925. /**                                                            **/
  926. /****************************************************************/
  927.  
  928. int getsucc()
  929.  
  930.  
  931. {
  932.     static int near    c;
  933.     static int near state = INITIA;    /* start things out in the initial state */
  934.     static int near previousstate;
  935.     do
  936.         {
  937.         if ( ( c = getc( fp ) ) == '\n' )
  938.             {
  939.             lineno++;
  940.             }
  941.         if ( c == EOF )
  942.             {
  943.             return( EOF );
  944.             }
  945.         previousstate = state & 15;
  946.         state = gotonextstate[ state & 15 ][ c ];
  947.         } while ( ( state & 15 ) != INITIA 
  948.                 || (  previousstate != INITIA && previousstate != BEGCOM ) );
  949.         /* Keep eating characters until we are out of comments and quotes */
  950.  
  951.     if ( previousstate == BEGCOM )
  952.         {    /* This is the only context sensitive area, if a '/' is seen 
  953.             followed by anything but a '*' then we must back up */
  954.         ungetc( c, fp );
  955.         return( '/' );
  956.         }
  957.     if ( state == TYPE )
  958.         {        /* Save the location of the last function return value */
  959.         SAVEPLACE( last_func_ret_type );
  960.         braces += BRACES( c );
  961.         }
  962.     else
  963.         {
  964.         parens += PARENS( c );
  965.         if ( state == NAME )
  966.             {
  967.             SAVEPLACE( last_func_name );
  968.             }
  969.         }
  970.     return( c );
  971. }
  972.  
  973.  
  974.  
  975.  
  976. /****************************************************************/
  977. /**                                                            **/
  978. /**   ARGUMENTS: character                                     **/
  979. /**                                                            **/
  980. /**   RETURN: character                                        **/
  981. /**                                                            **/
  982. /**   DESCRIPTION: succpos finds the next succesive position   **/
  983. /**   in a file that matches the character passed into it.     **/
  984. /**                                                            **/
  985. /**   GLOBAL VARS REFERENCED: none                             **/
  986. /**                                                            **/
  987. /**   GLOBAL VARS MODIFIED: none                               **/
  988. /**                                                            **/
  989. /****************************************************************/
  990.  
  991. int succpos( c )   /* Sets pointer to next position of character [c] */
  992.     int c;
  993. {
  994.     static int near tmpc;
  995.     while ( ( c != ( tmpc = getsucc() ) ) && ( tmpc != EOF    ) )
  996.         ;
  997.     if( tmpc != EOF )
  998.         {
  999.         ungetc( c, fp );
  1000.         return( 1 );
  1001.         }
  1002.     return( 0 );
  1003. }
  1004.  
  1005.  
  1006.  
  1007. /****************************************************************/
  1008. /**                                                            **/
  1009. /**   ARGUMENTS: character pointer                             **/
  1010. /**                                                            **/
  1011. /**   RETURN: character                                        **/
  1012. /**                                                            **/
  1013. /**   DESCRIPTION: nsuccmemb finds the next succesive character**/
  1014. /**   using getsucc that is not a member of the characters     **/
  1015. /**   pointed to by the variable passed in.                    **/
  1016. /**                                                            **/
  1017. /**   GLOBAL VARS REFERENCED: none                             **/
  1018. /**                                                            **/
  1019. /**   GLOBAL VARS MODIFIED: none                               **/
  1020. /**                                                            **/
  1021. /****************************************************************/
  1022.  
  1023. int nsuccmemb( lstr )
  1024.  
  1025.     char *lstr;
  1026. {
  1027.     int c;
  1028.     if( ( c = getsucc() ) != EOF )
  1029.         {
  1030.         while ( ( strchr( lstr, c ) != NULL ) && ( c != EOF ) )
  1031.             {
  1032.             c = getsucc();
  1033.             }    /* End of while */
  1034.         ungetc( c, fp );
  1035.         }
  1036.     return( c != EOF );
  1037. }
  1038.  
  1039.  
  1040.  
  1041. /****************************************************************/
  1042. /**                                                            **/
  1043. /**   ARGUMENTS: character pointers                            **/
  1044. /**                                                            **/
  1045. /**   RETURN: none                                             **/
  1046. /**                                                            **/
  1047. /**   DESCRIPTION: readtoken reads in characters using getsucc **/
  1048. /**   as long as the characters are members of characters      **/
  1049. /**   pointed to by plegalstr, these characters are put into   **/
  1050. /**   the place pointed to by ptokenstr, and null terminated.  **/
  1051. /**                                                            **/
  1052. /**   GLOBAL VARS REFERENCED: none                             **/
  1053. /**                                                            **/
  1054. /**   GLOBAL VARS MODIFIED: none                               **/
  1055. /**                                                            **/
  1056. /****************************************************************/
  1057.  
  1058. void readtoken( plegalstr, ptokenstr )    /* Reads token composed of
  1059.                                            *plegalstr into *ptokenstr */
  1060.     char *plegalstr;
  1061.     char *ptokenstr;
  1062.  
  1063. {
  1064.     int c;
  1065.     struct placeptr place;
  1066.     SAVEPLACE( place );
  1067.     RECOVERPLACE( place );
  1068.     while ( ( c = getsucc() ) && strchr( plegalstr, c ) && c != EOF )
  1069.         {
  1070.         *ptokenstr++ = (char )c;
  1071.         }    /* End of while */
  1072.     *ptokenstr = 0;
  1073. }
  1074.  
  1075.  
  1076. /****************************************************************/
  1077. /**                                                            **/
  1078. /**   ARGUMENTS: character pointer, and an array of character  **/
  1079. /**              pointers.                                     **/
  1080. /**                                                            **/
  1081. /**   RETURN: integer                                          **/
  1082. /**                                                            **/
  1083. /**   DESCRIPTION: ismember returns -1 if ptoken is not a      **/
  1084. /**   member of any of the characters pointed to in the array  **/
  1085. /**   plistwords,  if the ptoken is a member, the position in  **/
  1086. /**   that array is returned.                                  **/
  1087. /**                                                            **/
  1088. /**   GLOBAL VARS REFERENCED: none                             **/
  1089. /**                                                            **/
  1090. /**   GLOBAL VARS MODIFIED: none                               **/
  1091. /**                                                            **/
  1092. /****************************************************************/
  1093.  
  1094. int ismember( ptoken, plistwords )
  1095.     char *ptoken, *plistwords[];
  1096. {
  1097.     int i = 0;
  1098.     while ( *plistwords && strcmp( ptoken, *plistwords ) )
  1099.         {
  1100.         *++plistwords;
  1101.         ++i;
  1102.         }    /* End of while */
  1103.     return( ( *plistwords == NULL || strcmp( ptoken, *plistwords ) ) ? -1 : i );
  1104. }
  1105.  
  1106.  
  1107.  
  1108. static unsigned int width;
  1109. static int (*compare)( char **, char ** );
  1110.  
  1111.  
  1112.  
  1113. /****************************************************************/
  1114. /**                                                            **/
  1115. /**   ARGUMENTS:     base = (char *) pointer to base of array   **/
  1116. /**           num  = (unsigned) number of elements in the array  **/
  1117. /**       wid  = (unsigned) width in bytes of each array element **/
  1118. /**        comp = (int (*) ()) pointer to function returning      **/
  1119. /**        analog of strncmp for strings, but supplied for        **/
  1120. /**        comparing the array elements.  It accepts 2 pointers   **/
  1121. /**        to elements and returns neg if 1<2, 0 if 1=2,          **/
  1122. /**        pos if 1>2.                                            **/
  1123. /**                                                            **/
  1124. /**   RETURN: none                                             **/
  1125. /**                                                            **/
  1126. /**   DESCRIPTION: qsort quick sorts an array of elements in   **/
  1127. /**   place.                                                   **/
  1128. /**                                                            **/
  1129. /**   GLOBAL VARS REFERENCED: array starting at base           **/
  1130. /**                                                            **/
  1131. /**   GLOBAL VARS MODIFIED: array starting at base             **/
  1132. /**                                                            **/
  1133. /****************************************************************/
  1134.  
  1135. void qsort( base, num, wid, comp )
  1136.  
  1137.     char *base;
  1138.     unsigned int num;
  1139.     unsigned int wid;
  1140.     int (*comp)( char **, char ** );
  1141.  
  1142. {
  1143.     register char *q = base;
  1144.     register char *p = base + wid;
  1145.     int i = num - 1;
  1146.     int sort = 0;    /* set to non-zero if sort must be done */
  1147.             /* (some element is out of order) */
  1148.  
  1149.     if ( num )
  1150.         {
  1151.         while ( i-- ) 
  1152.             {
  1153.             if ( (*comp)( (char **)q, (char **)p ) > 0 ) 
  1154.                 {
  1155.                 sort++;
  1156.                 break;
  1157.                 }
  1158.  
  1159.             q = p;
  1160.             p += wid;
  1161.             }
  1162.         }
  1163.  
  1164.     if (sort) 
  1165.         {
  1166.         width = wid;
  1167.         compare = comp;
  1168.         quicksort( base, base + (num - 1) * width );
  1169.         }
  1170. }
  1171.  
  1172.  
  1173. static void quicksort( lo, hi )
  1174.  
  1175.     char *lo;
  1176.     char *hi;
  1177.  
  1178. {
  1179.     register char *higuy = hi + width;
  1180.     register char *loguy = lo;
  1181.  
  1182.     while ( lo < hi ) 
  1183.         {
  1184.         for ( ; ; ) 
  1185.             {
  1186.             do    {
  1187.                 loguy += width;
  1188.                 } while (loguy < hi && (*compare)( (char **)loguy, (char **)lo ) <= 0);
  1189.  
  1190.             do    {
  1191.                 higuy -= width;
  1192.                 } while (higuy > lo && (*compare)( (char **)higuy, (char **)lo ) >= 0);
  1193.  
  1194.             if (higuy <= loguy)
  1195.                 break;
  1196.  
  1197.             swap( loguy, higuy, width );
  1198.             }    /* End of for */
  1199.  
  1200.         swap( lo, higuy, width );
  1201.         if ( higuy - lo >= hi - higuy ) 
  1202.             {
  1203.             quicksort( higuy + width, hi );
  1204.             hi = higuy - width;
  1205.             loguy = lo;
  1206.             }
  1207.         else 
  1208.             {
  1209.             quicksort( lo, higuy - width );
  1210.             loguy = lo = higuy + width;
  1211.             higuy = hi + width;
  1212.             }
  1213.         }    /* End of while */
  1214. }
  1215.  
  1216.  
  1217.  
  1218. static void swap ( one, two, w )
  1219.  
  1220.     char *one;
  1221.     register char *two;
  1222.     unsigned int w;
  1223.  
  1224. {
  1225.     char temp;
  1226.  
  1227.     while ( w-- ) 
  1228.         {
  1229.         temp = *one;
  1230.         *one++ = *two;
  1231.         *two++ = temp;
  1232.         }
  1233. }
  1234.