home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / forut062.zip / ForUtil-0.62 / fflow / libflow.c.orig < prev    next >
Text File  |  1997-01-23  |  12KB  |  513 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.         if(!(strcasecmp(tmp->name, call->name)))
  276.             break;
  277.     }
  278.     if(tmp == NULL) 
  279.         return;
  280.     call->parent = tmp;
  281.     call->Type = KNOWN;
  282.     /* This one has been used, mark it */
  283.     tmp->called++;
  284.  
  285. /*****
  286. * Figure out where the calls made in each function are defined
  287. *****/
  288. flowInfo 
  289. *sortAll(flowInfo *list)
  290.     flowInfo *tmp, *tmp1; 
  291.     for(tmp = list; tmp != NULL; tmp = tmp->next) 
  292.     { 
  293.         for(tmp1 = tmp->calls; tmp1 != NULL; tmp1 = tmp1->next) 
  294.         { 
  295.             getParent(list, tmp1);
  296.             /* 
  297.             * sanity check: if the parent of the current routine
  298.             * or function is the routine/function itself, we are 
  299.             * recursing on ourselves..
  300.             */
  301.             if(tmp1->parent == tmp) 
  302.             {
  303.                 tmp->recursive = 1; 
  304.                 fprintf(stderr,"ERROR: function %s recurses "
  305.                     "into itself\n", tmp->name); 
  306.                 fprintf(stderr,"line %i in file %s%s.\n", 
  307.                     tmp1->defline, tmp->path, tmp->file); 
  308.                 exit(8);
  309.             } 
  310.         } 
  311.     } 
  312.     return(list); 
  313. }
  314.  
  315. /*****
  316. * Show what functions are never invoked
  317. *****/
  318. void
  319. print_unused_routines(FILE *file, flowInfo *list)
  320. {
  321.     flowInfo *tmp;
  322.  
  323.     for(tmp = list; tmp != NULL; tmp = tmp->next)
  324.     {
  325.         if(tmp->called == 0 && tmp->Type == SUBROUTINE)
  326.         {
  327.             fprintf(file, "SUBROUTINE %s is never invoked.\n\t(",
  328.                 tmp->name);
  329.             if(full_names)
  330.                 fprintf(file, "%s%s, line %i)\n",tmp->path, 
  331.                     tmp->file, tmp->defline);
  332.             else
  333.                 fprintf(file, "%s, line %i)\n", tmp->file,
  334.                     tmp->defline);
  335.         }
  336.     }
  337. }
  338.  
  339. /*****
  340. * Return 0 if the file given is to be ignored, something else otherwise
  341. *****/
  342. inline int
  343. ignore_this_file(char *file)
  344. {
  345.     register int i;
  346.     char *ret_val = NULL;
  347.     for(i = 0 ; i < num_ignore && 
  348.         (ret_val = strstr(file, ignore_list[i])) == NULL; i++)
  349.             /* do nothing */ ;
  350.     if(ret_val != NULL)
  351.     {
  352.         if(!quiet)
  353.             printf("Ignoring file %s\n", file);
  354.         return(0);
  355.     }
  356.     return(1);
  357. }
  358.  
  359. /*****
  360. * Reset necessary vars to start scanning the next file.
  361. * Returns a FILE handle upon success, NULL on failure.
  362. *****/
  363. FILE
  364. *reset_scanner(char *file_name)
  365. {
  366.     FILE *file;
  367.  
  368.     file = fopen(file_name, "r"); 
  369.     if(!file) 
  370.     {
  371.         perror(file_name); 
  372.         return NULL;
  373.     }
  374.     ParseFilename(file_name, curr_file, curr_path);
  375. #ifdef __MSDOS__
  376.     downcase(curr_file);
  377.     downcase(curr_path);
  378. #endif /* __MSDOS__ */
  379.     if(!quiet) 
  380.         printf("Scanning %s%s\n", curr_path, curr_file);
  381.     numroutine = numfunc = numcall= 0;
  382.     have_first_routine = False;
  383.     action = DONOTHING; 
  384.     return(file);
  385. }
  386.  
  387. /*****
  388. * Initialise all necessary global variables
  389. *****/
  390. void
  391. initialise(char *argv_nul)
  392. {
  393.     /* Initialise global flow to NULL. */
  394.     global_flow.head = NULL;
  395.     global_flow.current = NULL;
  396.     global_flow.call_head = NULL;
  397.     global_flow.current_call = NULL;
  398.  
  399.     flow = NULL;
  400.     full_names = quiet = 0;
  401.     num_ignore = num_dirs_to_visit = num_extensions = num_files = 0;
  402.  
  403.     /* get program name */
  404.     get_filename_part(argv_nul, progname);
  405.  
  406. #ifdef __MSDOS__
  407.     dir_mem = ext_mem = file_mem = ign_mem = 0;
  408.     need_mem_info_for_msdos = 0;
  409. #endif
  410. }
  411.  
  412. /*****
  413. * Install various signal handlers
  414. *****/
  415. void
  416. install_sig_handlers(void)
  417. {
  418.     /* install signal handlers */
  419.     signal(SIGUSR1, sig_handler);
  420.     signal(SIGINT, sig_handler);
  421.     signal(SIGSEGV, sig_handler);
  422. #ifdef SIGQUIT
  423.     signal(SIGQUIT, sig_handler);
  424. #endif
  425. }
  426.  
  427. /*****
  428. * Show initial settings 
  429. *****/
  430. void
  431. print_settings(void)
  432. {
  433.     int i;
  434.     if(num_dirs_to_visit != 0)
  435.     {
  436.         printf("List of directories to visit:\n");
  437.         for(i = 0 ; i < num_dirs_to_visit; i++)
  438.             printf("%s\n", dirs_to_visit[i]); 
  439.     }
  440.     if(num_extensions != 0)
  441.     {
  442.         printf("List of extensions to use:\n");
  443.         for(i = 0 ; i < num_extensions; i++)
  444.             printf("%s\n", ext_table[i]); 
  445.     }
  446.     if(num_ignore != 0)
  447.     {
  448.         printf("List of files to ignore:\n");
  449.         for(i = 0 ; i < num_ignore; i++)
  450.             printf("%s\n", ignore_list[i]); 
  451.     }
  452.  
  453.     printf("List of files to scan:\n");
  454.     for(i = 0 ; i < num_files; i++)
  455.         printf("%s\n", file_list[i]);
  456.     fflush(stdout);
  457. }
  458.  
  459. /*****
  460. * Print scan statistics for this file
  461. *****/
  462. void
  463. print_file_stats(FILE *file, char *file_name, int num_lines)
  464.     fprintf(file, "----------------------\n");
  465.     fprintf(file, "Scan statistics for   : %s\n", file_name);
  466.     fprintf(file, "Total lines           : %i\n", num_lines);
  467.     fprintf(file, "Function definitions  : %i\n", numfunc); 
  468.     fprintf(file, "Subroutine definitions: %i\n", numroutine); 
  469.     fprintf(file, "Total number of calls : %i\n", numcall); 
  470.     fprintf(file, "----------------------\n");
  471.  
  472. /*****
  473. * Report msdos memory usage
  474. *****/
  475. void
  476. print_dos_memory_usage(void)
  477. {
  478. #ifdef __MSDOS__
  479.     int i;
  480.     if(need_mem_info_for_msdos)
  481.     {
  482.         printf("\n------------------\n");
  483.         printf("MSDOS Memory Usage\n\n");
  484.         printf("Heap size is %u bytes\n", _heaplen);
  485.         printf("Stack size is %u bytes\n", _stklen);
  486.         printf("Memory used by flowInfo list: %lu bytes\n", list_mem);
  487.         dir_mem = sizeof(dirs_to_visit);
  488.         for(i = 0 ; i < num_dirs_to_visit; i++)
  489.             dir_mem += strlen(dirs_to_visit[i]);
  490.         printf("Memory used by dir list: %lu bytes\n", dir_mem);
  491.         ext_mem = sizeof(ext_table);
  492.         for(i = 0 ; i < num_extensions; i++)
  493.             ext_mem += strlen(ext_table[i]);
  494.         printf("Memory used by ext list: %lu bytes\n", ext_mem);
  495.         ign_mem = sizeof(ignore_list);
  496.         for(i = 0 ; i < num_ignore; i++)
  497.             ign_mem += strlen(ignore_list[i]);
  498.         printf("Memory used by ignore list: %lu bytes\n", ign_mem);
  499.         file_mem = sizeof(file_list);
  500.         for(i = 0 ; i < num_files; i++)
  501.             file_mem += strlen(file_list[i]);
  502.          printf("Memory used by file list: %lu bytes\n", file_mem);
  503.  
  504.         printf("Total memory used: %lu bytes\n",
  505.             list_mem + dir_mem + ext_mem + ign_mem + file_mem);
  506.     }
  507. #endif
  508. }
  509.