#!/usr/bin/perl -w # function_call_eval.pl # written by Meryll Larkin # March 2, 2013 # Updated June 6, 2016 # find all functions in script # determine which of them call the others # output: # list of functions by which calls which # list of functions by which is called by which # use strict; use Data::Dumper; my %functions; # functions => { # function_name => { # start_line_no => 35 # end_line_no => 65 # function1 => i_call # function2 => i_call # function3 => i_call # function4 => calls_me # } # preserve line order in script my @functions; $functions[0] = "MAIN"; my $DEBUG = 1; my $line_count = 0; my $script = $ARGV[0] || &get_script_name; open (INPUT, $script) || die "cannot open $script for reading " . $! . "\n"; # first make a hash of all the subroutines/functions $functions{"MAIN"}{"start_line_no"} = '1'; my $previous_function = "MAIN"; # use script name in output file name - remove the path first $script =~ s/^.*\///; my $output = $script . "_out.txt"; open (OUTPUT, ">>$output") || die "cannot open $output for writing " . $! . "\n"; print OUTPUT "Evaluating functions of script: $script\n\n"; while () { chomp(my $line = $_); $line_count++; # ignore comment lines next if ($line =~ /\s*\#/); # find lines that have names of functions on them next if ($line !~ /^\s*sub\s+\w+/); my $function = $line; # strip off "sub " $function =~ s/^\s*sub\s+//; # strip off " {"; $function =~ s/\s+\{\s*$//; print "$function $line_count\n" if ($DEBUG); print OUTPUT "$function $line_count\n" if ($DEBUG); push (@functions, $function); $functions{$previous_function}{"end_line_no"} = ($line_count -1); $functions{$function}{"start_line_no"} = $line_count; $previous_function = $function; } $functions{$previous_function}{"end_line_no"} = ($line_count - 1); # print Dumper(\%functions) if ($DEBUG); # print "\n" if ($DEBUG); for my $key (sort (keys %functions)) { my $start = $functions{$key}{"start_line_no"}; my $end = $functions{$key}{"end_line_no"}; print "$key\n" if ($DEBUG); print " start = $start end = $end\n" if($DEBUG); } close INPUT; print "\n" .'#***************************************************' . "\n"; print OUTPUT "\n" . '#***************************************************' ."\n"; print "\nMy Function Calls Out To:\n\n"; print OUTPUT "\nMy Function Calls Out to:\n\n"; $line_count = 0; my %function_calls; my @calls; open (INPUT, $script) || die "cannot open $script for reading " . $! . "\n"; while () { chomp(my $line = $_); $line_count++; # ignore comment lines next if ($line =~ /\s*\#/); # ignore empty lines and close bracket lines next if ($line !~ /\w+/); # ignore lines that are function declarations next if ($line =~ /^\s*sub\s+\w+/); for my $key (keys %functions) { if ($line =~ /$key/) { if ($line =~ /\W$key\W/) { # still not certain this is calling a function if (( $line =~ /&$key/) || ($line =~ /$key\s*\(/)) { # print "Found: $key on line number $line_count\n" if ($DEBUG); # can't use function call as key due to needs to be unique $function_calls{"$line_count"} = $key; # print "function_calls \{ $line_count \} = $key\n"; } } } next; } } close INPUT; my @calls_inside_function; for my $function (@functions) { print "$function\n"; print OUTPUT "$function\n"; my $start = $functions{$function}{"start_line_no"}; my $end = $functions{$function}{"end_line_no"}; for ($start .. $end) { my $line_no = $_; $line_no = "$line_no"; if (exists $function_calls{$line_no}) { my $call = $function_calls{$line_no}; print " $call\n"; print OUTPUT " $call\n"; $functions{$function}{$call} = "i_call"; $functions{$call}{$function} = "calls_me"; } } } print "\n" . '#***************************************************' . "\n"; print OUTPUT "\n" . '#***************************************************' . "\n"; print "\nThese Functions Call To Me:\n\n"; print OUTPUT "\nThese Functions Call To ME:\n\n"; for my $function (@functions) { print "$function\n"; print OUTPUT "$function\n"; for my $key (keys %{ $functions{$function} } ) { if ( $functions{$function}{$key} eq "calls_me" ) { print " $key\n"; print OUTPUT " $key\n"; } } print "\n"; print OUTPUT "\n"; } close OUTPUT; print "Output also printed to file: $output\n"; exit (0); ############################################################# sub get_script_name { print "Please provide name of script: "; chomp (my $script = ); return $script; } ############################################################# #--END --