#!/usr/bin/perl -w ####################################################################################### # A tool for creating graphs of module usage patterns based on graphviz. # # Copyright (c) 2005, Ioan Sucan, released under the Gnu General Public License (GPL) # # see http://www.gnu.org/copyleft/gpl.html # # $URL: svn://kwarc.eecs.iu-bremen.de/repos/kwarc/projects/content/bin/sgraph$ # # $Date: 2005-10-04 19:31:43 +0200 (Tue, 04 Oct 2005) $ $Rev: 4376 $ # ####################################################################################### use strict; use Getopt::Long; use Modparse; use Pod::Usage; my $input = "-", my $output = "out", my $format = "ps"; my $root, my $stop_at_end=0, my $use_grouping = 0; my $rmdot = 0, my $verbose=0, my $theory = '', my $srange = ''; my %arg_snippath; my @snippathList; sub group_name{ my ($st) = @_; if ($st =~ /^(.*[\/\\])?([^\/\\]+)\.[^\.\/\\]*$/) { $st = $2; } elsif ($st =~ /^(.*[\/\\])?([^\.\/\\]+)$/) { $st = $2; } $st =~ s/-/_/g; return $st; } GetOptions("output=s" => \$output, "format=s" => \$format, "nodot" => sub {$rmdot = 1;}, "root=s" => \$root, "theory=s" => \$theory, "sliderange=s" => \$srange, "path=s" => \%arg_snippath, "defpath=s" => \@snippathList, "verbose" => sub {$verbose = 1;}, "grouping" => sub {$use_grouping = 1}, "stop" => sub {$stop_at_end = 1}, "help" => sub {pod2usage(2)}); $output = $1 if ($output =~ m/([^.]+)\..*/); $input = $ARGV[0] if ($#ARGV>=0); $root = group_name($input) unless $root; my %data = (); my %group = (); my $mp = Modparse->new(snippathList=>\@snippathList, snippath=>\%arg_snippath, stopAtEnd=>$stop_at_end, verbose=>$verbose, onBegin=>sub { $_[0]->{perm}->{slide} = 0; $_[0]->{perm}->{linecount} = 0; if ($srange =~ /(\d+)\:(\d+)/){ ($_[0]->{perm}->{sbegin}, $_[0]->{perm}->{send}) = ($1, $2); $_[0]->{perm}->{in_sliderange} = ($_[0]->{perm}->{sbegin}<1); } else { $_[0]->{perm}->{in_sliderange} = 1; }}, onBeginFile=>sub { $_[0]->{grp} = group_name($_[0]->{filename}); }, onBeginModule=>sub { if ($_[0]->{perm}->{in_sliderange} && (my $id = $_[0]->{module_id})){ $id =~ s/[:-]/_/g; my $uses = ''; if ($_[0]->{module_args} =~ /uses=(([\w-]+)|(\{[\w,-]+\}))/){ $uses = $1; $uses =~ s/,/;/g; $uses =~ s/[:-]/_/g; } $data{$id}=$uses; $group{$id}=$_[0]->{perm}->{grp}; }}, onEveryLine=>sub { $_[0]->{perm}->{linecount}++; print ". " if ($_[0]->{pack}->{verbose} && ($_[0]->{perm}->{linecount} % 1000==0)); $_[0]->{perm}->{slide}++ if $_[0]->{simple_tex} =~ /\\begin\{slide\}/; $_[0]->{perm}->{in_sliderange}=($_[0]->{perm}->{slide}<=$_[0]->{perm}->{send} && $_[0]->{perm}->{slide}>=$_[0]->{perm}->{sbegin}) if ($_[0]->{perm}->{sbegin} && $_[0]->{perm}->{send}); }); print "\nGenerating graph...\n" if $verbose; $mp->execute($input); my @queue=(); if ($theory){ $theory =~ s/-/_/g; if ($data{$theory}){ my $start = 0, my $end = 1, my %already_in; $queue[0] = $theory; $already_in{$theory} = 1; while ($start<$end){ my $idx, my $usesx; $idx = $queue[$start]; $usesx = $data{$queue[$start]}; $start++; if ($usesx){ $usesx =~ s/\{//; $usesx =~ s/\}//; foreach (split(/;/,$usesx)){ next if $already_in{$_}; $queue[$end] = $_; $already_in{$_} = 1; $end++; } } } } } else{ @queue = keys %data; } open(FOUT,">$output.dot") or die "Can't open output file\n"; print FOUT "digraph TEX {\n"; print FOUT "$root [shape=box];\n"; if ($use_grouping){ my %subgraph = (); foreach (@queue){ $subgraph{$group{$_}}.="$_;"; } foreach my $subgr (keys %subgraph){ print FOUT "subgraph cluster_$subgr {\n"; print FOUT "color = blue;\n"; print FOUT "label = $subgr;\n"; print FOUT "$subgraph{$subgr}\n"; print FOUT "}\n"; } } my $lk = 0; for my $idx (@queue){ my $usesx = $data{$idx}; $lk=$lk+($usesx =~ tr/;//)+1; if ($usesx){ print FOUT "$idx -> $usesx;\n"; } else { print FOUT "$idx -> $root;\n"; } } print "Number of links: $lk\n" if $verbose; print FOUT "}\n"; close(FOUT); `dot -T$format -o $output.$format $output.dot`; unlink "$output.dot" if ($rmdot==1); print "Done.\n" if $verbose; __END__ =head1 SYNOPSIS sgraph [options] .tex input file; stdin by default Options: --output output file; out.dot by default --format output format; .ps by default; for available formats, see dot --help --nodot do not generate .dot file, just target format --root the 'root' of the graph. (name of course) --theory generate a subgraph for the theory --sliderange only look at the given slide range; (2:16 for example) --path XXX specify the value of \XXX (some snippath) in case it is = somePath not defined in the processed .tex file --defpath XXX specify which \XXX (snippath definitions) to look for --stop stop reading data when \end{document} is found, not at EOF --grouping group modules within sections. --verbose verbose on --help this screen Example: ./sgraph slides.tex -o graph -f ps -n -t TCN --sliderange 20:10000 -r GenCS -v