home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / forut062.zip / ForUtil-0.62 / fflow / libflow.c < prev    next >
C/C++ Source or Header  |  1997-01-23  |  12KB  |  518 lines

  1. static char rcsId[]="$Source: /usr/local/rcs/ForUtil/fflow/RCS/libflow.c,v $";
  2. /*****
  3. * libflow.c : common flowgraph generation routines.
  4. *
  5. * This file Version    $Revision: 1.2 $
  6. *
  7. * Creation date:    Mon Aug 19 15:42:20 GMT+0100 1996
  8. * Last modification:     $Date: 1996/08/28 17:47:25 $
  9. * By:            $Author: koen $
  10. * Current State:    $State: Exp $
  11. *
  12. * Author:        koen
  13. * (C)Copyright 1995-1996 Ripley Software Development
  14. * All Rights Reserved
  15. *****/
  16. /*****
  17. * ChangeLog
  18. * $Log: libflow.c,v $
  19. * Revision 1.2  1996/08/28 17:47:25  koen
  20. * Added add_default_program, print_file_stats; reset_scanner. 
  21. * Changed sig_handler to print signal name on exit. 
  22. * Changed new_entry so only 1 allocation is done for name, file and path 
  23. * instead of three separate mallocs.
  24. *
  25. * Revision 1.1  1996/08/27 19:14:50  koen
  26. * Initial Revision
  27. *
  28. *****/ 
  29. /* needed to prevent multiple variable decls under MSDOS in sysdeps.h */
  30. #define LIBRARY_OBJECT
  31.  
  32. #ifdef HAVE_CONFIG_H
  33. #include "autoconf.h"
  34. #endif
  35.  
  36. #include <stdio.h>
  37. #include <stdlib.h> 
  38. #include <string.h>
  39. #include <signal.h>
  40.  
  41. #include "forutil.h"
  42. #include "memmacros.h"
  43. #include "libflow.h"
  44.  
  45. /**** Externally declared variables ****/
  46. extern FILE *yyin, *yyout;
  47.  
  48. /**** Public Variables ****/
  49. global_flow_data global_flow;
  50. flowInfo *flow;
  51. int action, Type, full_names, quiet, maxdepth, have_first_routine;
  52. int num_ignore, num_dirs_to_visit, num_extensions, num_files;
  53. int numroutine, numcall, numfunc;
  54. char progname[32];
  55. char curr_path[PATH_MAX], curr_file[NAME_MAX];
  56. char *ignore_list[MAXIGNORE];
  57. char *dirs_to_visit[MAXDIRS];
  58. char *ext_table[MAXEXTS];
  59. char **file_list;
  60.  
  61. #ifdef __MSDOS__
  62. unsigned long dir_mem, ext_mem, file_mem, ign_mem;
  63. int need_mem_info_for_msdos;
  64. static unsigned long list_mem = 0;
  65. #endif
  66.  
  67. /**** Private Function prototypes ****/
  68. static inline void getParent(flowInfo *list, flowInfo *call);
  69. static void add_default_program(void);
  70. static inline flowInfo *new_entry(char *name, int callline, char *path,
  71.     char *file, int num_args);
  72. static RETSIGTYPE sig_handler(int signum);
  73.  
  74. /* Exit procedure */
  75. #define SHUTUP(text,exitnum)    {if(yyin) { \
  76.             fprintf(stderr, "%s: %s (%s).\n", progname, \
  77.                 text, #exitnum); \
  78.             fprintf(stderr, "Stopping scanner\n"); \
  79.             fclose(yyin); fclose(yyout); } \
  80.             exit(exitnum+20); }
  81.  
  82. /****
  83. * Signal handler for a nice and clean exit
  84. ****/
  85. static RETSIGTYPE
  86. sig_handler(int signum)
  87. {
  88.     switch(signum)
  89.     {
  90.         case SIGUSR1:
  91.             SHUTUP("Memory allocation error", SIGUSR1);
  92.         case SIGSEGV:
  93.             SHUTUP("Segmentation violation", SIGSEGV);
  94. #ifdef SIGQUIT
  95.         case SIGQUIT:
  96.             SHUTUP("Interrupted by user", SIGQUIT);
  97. #endif
  98.         case SIGINT:
  99.             SHUTUP("Interrupted by user", SIGINT);
  100.         default:
  101.             SHUTUP("Terminated with unknown signal", signum);
  102.     }
  103. }
  104.  
  105. /*****
  106. * Create a new flowgraph entry
  107. * Args:
  108. * name: name of (program,subroutine,function)
  109. * callline: line where a call was made -or- where name was defined
  110. * path: pathname of file
  111. * file: name of file
  112. *****/
  113. static inline flowInfo
  114. *new_entry(char *name, int callline, char *path, char *file, int num_args)
  115. {
  116.     static flowInfo *list = NULL;
  117.     int buf_size = 0;
  118.  
  119.     /* allocate new entry, initialize every field to 0 */
  120.     checked_calloc(list, 1, flowInfo); 
  121.  
  122.     /*
  123.     * Due to our setup which attaches calls to a particular routine in a
  124.     * given file, calls do not have a file nor a path associated with them.
  125.     */
  126.     if(action != ADDCALL)
  127.     {
  128.         /* 
  129.         * size of block to allocate 
  130.         * each string needs room for a terminating \0 -> +3 (or 4) 
  131.         */
  132.         buf_size = strlen(name) + strlen(file) + 
  133.             (full_names ? strlen(path) + 4 : 3);
  134.         /* allocate block, initialize to 0 */
  135.         checked_calloc(list->name, buf_size, char);
  136.  
  137.         /* save routine name */
  138.         strcpy(list->name,name);
  139.  
  140.         /* save file name */
  141.         list->file = list->name + strlen(name)+2;
  142.         strcpy(list->file, file);
  143.         if(full_names)
  144.         {
  145.             /* save path name */
  146.             list->path = list->file + strlen(file)+2;
  147.             strcpy(list->path, path);
  148.         }
  149.     }
  150.     else
  151.     {
  152.         buf_size = strlen(name)+1;
  153.         checked_malloc(list->name, buf_size, char);
  154.         strcpy(list->name,name);
  155.     }
  156.     list->Type = Type;
  157.     list->defline = callline;
  158.     list->num_args = num_args;
  159. #ifdef __MSDOS__
  160.     list_mem += sizeof(flowInfo);
  161.     list_mem += len;
  162. #endif
  163.     return(list);
  164. }
  165.  
  166. /****
  167. * Add a routine definition
  168. ****/
  169. inline void
  170. add_new_func(char *name, int callline, char *path, char *file, int num_args)
  171. {
  172.     static flowInfo *new_func;
  173.  
  174.     new_func = new_entry(name, callline, path, file, num_args);
  175.  
  176.     /* indicate we have a routine definition for the current file */
  177.     have_first_routine = True;
  178.  
  179.     /* Data initialisation */
  180.     if(global_flow.head == NULL)
  181.     {
  182.         global_flow.head = new_func;
  183.         global_flow.current = new_func;
  184.         global_flow.call_head = NULL;
  185.         global_flow.current_call = NULL;
  186.     }
  187.     else
  188.     {
  189.         global_flow.current->next = new_func;
  190.         global_flow.current = new_func;
  191.         global_flow.call_head = NULL;
  192.         global_flow.current_call = NULL;
  193.     }
  194. }
  195.  
  196. /*****
  197. * Add a default program definition at line 1 of the current file.
  198. *****/
  199. static void
  200. add_default_program(void)
  201. {
  202.     char program[NAME_MAX];
  203.     char *chPtr;
  204.  
  205.     /* reset to 0 */
  206.     memset(program, '\0', NAME_MAX);
  207.  
  208.     /* check if the current file has an extension. If so, strip it of */
  209.     if((chPtr = strchr(curr_file, '.')) != NULL)
  210.         strncpy(program, curr_file, chPtr - curr_file);
  211.     else
  212.         strncpy(program, curr_file, NAME_MAX);
  213.  
  214.     /* print diagnostic message */
  215.     if(!quiet)
  216.     {
  217.         fprintf(stderr, "WARNING: no program entry point found in file ");
  218.         if(full_names)
  219.             fprintf(stderr, "%s%s\n", curr_path, curr_file);
  220.         else
  221.             fprintf(stderr, "%s\n", curr_file);
  222.         fprintf(stderr,"Using default program name %s at line 1\n", 
  223.             program);
  224.     }
  225.  
  226.     /* Set proper flags and create a new entry */
  227.     action = ADDFUNC;
  228.     Type   = PROGRAM;
  229.     add_new_func(program, 1, curr_path, curr_file, 0);
  230.  
  231.     /* Reset flags */
  232.     action = ADDCALL; 
  233.     Type   = UNKNOWN;
  234. }
  235.  
  236. /*****
  237. * Add a new call definition
  238. *****/
  239. inline void
  240. add_new_call(char *name, int callline, int num_args)
  241. {
  242.     static flowInfo *new_call;
  243.  
  244.     /* user forgot a program statement. Add one for him. */
  245.     if(!have_first_routine)
  246.         add_default_program();
  247.  
  248.     new_call = new_entry(name, callline, NULL, NULL, num_args);
  249.  
  250.     /* for data initialisation */
  251.     if(global_flow.call_head == NULL)
  252.     {
  253.         global_flow.call_head = new_call;
  254.         global_flow.current_call = new_call;
  255.         global_flow.current->calls = new_call;
  256.     }
  257.     else
  258.     {
  259.         global_flow.current_call->next = new_call;
  260.         global_flow.current_call = new_call;
  261.     }
  262. }
  263.  
  264. /*****
  265. * Find in which file a function call is defined
  266. * Very expensive (due to the strcasecmp call), but I don't see any other
  267. * way...
  268. *****/
  269. static inline void
  270. getParent(flowInfo *list, flowInfo *call)
  271. {
  272.     static flowInfo *tmp;
  273.     for(tmp = list; tmp != NULL; tmp = tmp->next) 
  274.     { 
  275. /*
  276.         if(!(strcasecmp(tmp->name, call->name)))
  277. */
  278. /* sad: on emx / gcc there is only strcmp under os/2 */
  279.  
  280.         if(!(strcmp(tmp->name, call->name)))
  281.             break;
  282.     }
  283.     if(tmp == NULL) 
  284.         return;
  285.     call->parent = tmp;
  286.     call->Type = KNOWN;
  287.     /* This one has been used, mark it */
  288.     tmp->called++;
  289.  
  290. /*****
  291. * Figure out where the calls made in each function are defined
  292. *****/
  293. flowInfo 
  294. *sortAll(flowInfo *list)
  295.     flowInfo *tmp, *tmp1; 
  296.     for(tmp = list; tmp != NULL; tmp = tmp->next) 
  297.     { 
  298.         for(tmp1 = tmp->calls; tmp1 != NULL; tmp1 = tmp1->next) 
  299.         { 
  300.             getParent(list, tmp1);
  301.             /* 
  302.             * sanity check: if the parent of the current routine
  303.             * or function is the routine/function itself, we are 
  304.             * recursing on ourselves..
  305.             */
  306.             if(tmp1->parent == tmp) 
  307.             {
  308.                 tmp->recursive = 1; 
  309.                 fprintf(stderr,"ERROR: function %s recurses "
  310.                     "into itself\n", tmp->name); 
  311.                 fprintf(stderr,"line %i in file %s%s.\n", 
  312.                     tmp1->defline, tmp->path, tmp->file); 
  313.                 exit(8);
  314.             } 
  315.         } 
  316.     } 
  317.     return(list); 
  318. }
  319.  
  320. /*****
  321. * Show what functions are never invoked
  322. *****/
  323. void
  324. print_unused_routines(FILE *file, flowInfo *list)
  325. {
  326.     flowInfo *tmp;
  327.  
  328.     for(tmp = list; tmp != NULL; tmp = tmp->next)
  329.     {
  330.         if(tmp->called == 0 && tmp->Type == SUBROUTINE)
  331.         {
  332.             fprintf(file, "SUBROUTINE %s is never invoked.\n\t(",
  333.                 tmp->name);
  334.             if(full_names)
  335.                 fprintf(file, "%s%s, line %i)\n",tmp->path, 
  336.                     tmp->file, tmp->defline);
  337.             else
  338.                 fprintf(file, "%s, line %i)\n", tmp->file,
  339.                     tmp->defline);
  340.         }
  341.     }
  342. }
  343.  
  344. /*****
  345. * Return 0 if the file given is to be ignored, something else otherwise
  346. *****/
  347. inline int
  348. ignore_this_file(char *file)
  349. {
  350.     register int i;
  351.     char *ret_val = NULL;
  352.     for(i = 0 ; i < num_ignore && 
  353.         (ret_val = strstr(file, ignore_list[i])) == NULL; i++)
  354.             /* do nothing */ ;
  355.     if(ret_val != NULL)
  356.     {
  357.         if(!quiet)
  358.             printf("Ignoring file %s\n", file);
  359.         return(0);
  360.     }
  361.     return(1);
  362. }
  363.  
  364. /*****
  365. * Reset necessary vars to start scanning the next file.
  366. * Returns a FILE handle upon success, NULL on failure.
  367. *****/
  368. FILE
  369. *reset_scanner(char *file_name)
  370. {
  371.     FILE *file;
  372.  
  373.     file = fopen(file_name, "r"); 
  374.     if(!file) 
  375.     {
  376.         perror(file_name); 
  377.         return NULL;
  378.     }
  379.     ParseFilename(file_name, curr_file, curr_path);
  380. #ifdef __MSDOS__
  381.     downcase(curr_file);
  382.     downcase(curr_path);
  383. #endif /* __MSDOS__ */
  384.     if(!quiet) 
  385.         printf("Scanning %s%s\n", curr_path, curr_file);
  386.     numroutine = numfunc = numcall= 0;
  387.     have_first_routine = False;
  388.     action = DONOTHING; 
  389.     return(file);
  390. }
  391.  
  392. /*****
  393. * Initialise all necessary global variables
  394. *****/
  395. void
  396. initialise(char *argv_nul)
  397. {
  398.     /* Initialise global flow to NULL. */
  399.     global_flow.head = NULL;
  400.     global_flow.current = NULL;
  401.     global_flow.call_head = NULL;
  402.     global_flow.current_call = NULL;
  403.  
  404.     flow = NULL;
  405.     full_names = quiet = 0;
  406.     num_ignore = num_dirs_to_visit = num_extensions = num_files = 0;
  407.  
  408.     /* get program name */
  409.     get_filename_part(argv_nul, progname);
  410.  
  411. #ifdef __MSDOS__
  412.     dir_mem = ext_mem = file_mem = ign_mem = 0;
  413.     need_mem_info_for_msdos = 0;
  414. #endif
  415. }
  416.  
  417. /*****
  418. * Install various signal handlers
  419. *****/
  420. void
  421. install_sig_handlers(void)
  422. {
  423.     /* install signal handlers */
  424.     signal(SIGUSR1, sig_handler);
  425.     signal(SIGINT, sig_handler);
  426.     signal(SIGSEGV, sig_handler);
  427. #ifdef SIGQUIT
  428.     signal(SIGQUIT, sig_handler);
  429. #endif
  430. }
  431.  
  432. /*****
  433. * Show initial settings 
  434. *****/
  435. void
  436. print_settings(void)
  437. {
  438.     int i;
  439.     if(num_dirs_to_visit != 0)
  440.     {
  441.         printf("List of directories to visit:\n");
  442.         for(i = 0 ; i < num_dirs_to_visit; i++)
  443.             printf("%s\n", dirs_to_visit[i]); 
  444.     }
  445.     if(num_extensions != 0)
  446.     {
  447.         printf("List of extensions to use:\n");
  448.         for(i = 0 ; i < num_extensions; i++)
  449.             printf("%s\n", ext_table[i]); 
  450.     }
  451.     if(num_ignore != 0)
  452.     {
  453.         printf("List of files to ignore:\n");
  454.         for(i = 0 ; i < num_ignore; i++)
  455.             printf("%s\n", ignore_list[i]); 
  456.     }
  457.  
  458.     printf("List of files to scan:\n");
  459.     for(i = 0 ; i < num_files; i++)
  460.         printf("%s\n", file_list[i]);
  461.     fflush(stdout);
  462. }
  463.  
  464. /*****
  465. * Print scan statistics for this file
  466. *****/
  467. void
  468. print_file_stats(FILE *file, char *file_name, int num_lines)
  469.     fprintf(file, "----------------------\n");
  470.     fprintf(file, "Scan statistics for   : %s\n", file_name);
  471.     fprintf(file, "Total lines           : %i\n", num_lines);
  472.     fprintf(file, "Function definitions  : %i\n", numfunc); 
  473.     fprintf(file, "Subroutine definitions: %i\n", numroutine); 
  474.     fprintf(file, "Total number of calls : %i\n", numcall); 
  475.     fprintf(file, "----------------------\n");
  476.  
  477. /*****
  478. * Report msdos memory usage
  479. *****/
  480. void
  481. print_dos_memory_usage(void)
  482. {
  483. #ifdef __MSDOS__
  484.     int i;
  485.     if(need_mem_info_for_msdos)
  486.     {
  487.         printf("\n------------------\n");
  488.         printf("MSDOS Memory Usage\n\n");
  489.         printf("Heap size is %u bytes\n", _heaplen);
  490.         printf("Stack size is %u bytes\n", _stklen);
  491.         printf("Memory used by flowInfo list: %lu bytes\n", list_mem);
  492.         dir_mem = sizeof(dirs_to_visit);
  493.         for(i = 0 ; i < num_dirs_to_visit; i++)
  494.             dir_mem += strlen(dirs_to_visit[i]);
  495.         printf("Memory used by dir list: %lu bytes\n", dir_mem);
  496.         ext_mem = sizeof(ext_table);
  497.         for(i = 0 ; i < num_extensions; i++)
  498.             ext_mem += strlen(ext_table[i]);
  499.         printf("Memory used by ext list: %lu bytes\n", ext_mem);
  500.         ign_mem = sizeof(ignore_list);
  501.         for(i = 0 ; i < num_ignore; i++)
  502.             ign_mem += strlen(ignore_list[i]);
  503.         printf("Memory used by ignore list: %lu bytes\n", ign_mem);
  504.         file_mem = sizeof(file_list);
  505.         for(i = 0 ; i < num_files; i++)
  506.             file_mem += strlen(file_list[i]);
  507.          printf("Memory used by file list: %lu bytes\n", file_mem);
  508.  
  509.         printf("Total memory used: %lu bytes\n",
  510.             list_mem + dir_mem + ext_mem + ign_mem + file_mem);
  511.     }
  512. #endif
  513. }
  514.