package Rose; use Win32::OLE; my $AUTHOR = 'Simon Johnston (skj@acm.org)'; my $NAME = 'Perl REI.'; my $VERSION = '1.0.1'; $COPYRIGHT = "$NAME Version $VERSION.\nCopyright (c) $AUTHOR 2000."; my %Types; my $RoseApp; my $curModel; my $curCategory; my $curClass; my $curOperation; my $curAttribute; my $curSubsystem; my $curModule; my @allRelations; sub new () { my $self = shift; my $type = ref($self) || $self; $Types{'$'} = 'String'; $Types{'%'} = 'Hash'; $Types{'@'} = 'Array'; my $RoseApp = Win32::OLE->GetActiveObject('Rose.Application') || Win32::OLE->new('Rose.Application');; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $RoseApp->{'Visible'} = 1; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curModel = $RoseApp->{'CurrentModel'}; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; warn "Error: no Model\n" if !defined($curModel); $curCategory = $curModel->{'RootCategory'}; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; warn "Error: no RootCategory\n" if !defined($curCategory); $curSubsystem = $curModel->{'RootSubsystem'}; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; warn "Error: no RootSubsystem\n" if !defined($curSubsystem); return bless {}, $type; } sub CreateRootPackage () { my $self = shift; my($name) = @_; my @path = split /::/, $name; foreach $package (@path) { $self->NewPackage($package); } } sub NewPackage () { my $self = shift; my($name) = @_; $name = "_" . $name; $curSubsystem = $curSubsystem->AddSubsystem ($name); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curSubsystem->SetCurrentPropertySetName ("Perl", "default"); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curCategory = $curCategory->AddCategory ($name); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curCategory->SetCurrentPropertySetName ("Perl", "default"); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curCategory->SetAssignedSubsystem ($curSubsystem); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; } sub PreviousPackage () { my $self = shift; $curSubsystem = $curSubsystem->{'ParentSubsystem'}; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; warn "Error: ParentSubsystem returned undef\n" if !defined($curSubsystem); $curCategory = $curCategory->{'ParentCategory'}; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; warn "Error: ParentCategory returned undef\n" if !defined($curCategory); } sub NewModule () { my $self = shift; my($name) = @_; $curModule = $curSubsystem->AddModule ($name); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curModule->{'AssignedLanguage'} = "Perl"; warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curModule->SetCurrentPropertySetName ("Perl", "default"); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; # # my $rdt = $curModule->{'Type'}; # warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; # # $rdt->{'Name'} = "PackageType"; # warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; # # $curModule->{'Type'} = $rdt; # warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; # # $curModule->{'Part'} = "Body"; # warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; } sub NewClass () { my $self = shift; my($name) = @_; print "Class: $name\n"; $curClass = $curCategory->AddClass ($name); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; if (!defined($curClass)) { $self->AddtoClass($name); warn "Warning: could not create class $name in $curCategory->{'Name'}\n"; } # $curClass->SetCurrentPropertySetName ("Perl", "default"); # warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curClass->SetAssignedModule ($curModule); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; } sub AddtoClass () { my $self = shift; my($name) = @_; my $theIndex; print "Adding to Class: $name\n"; $theIndex = $curCategory->{'Classes'}->FindFirst ($name); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curClass = $curCategory->{'Classes'}->GetAt ($theIndex); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; } sub FindClass () { my $self = shift; my($name) = @_; my $rootCategory; my $theIndex; $theIndex = $curModel->{'RootCategory'}->GetAllClasses()->FindFirst ($name); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curClass = $curModel->{'RootCategory'}->GetAllClasses()->GetAt ($theIndex); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; } sub FindModule () { my $self = shift; my($name) = @_; my $theIndex; print "Adding to Module: $name\n"; $theIndex = $curSubsystem->{'Modules'}->FindFirst ($name); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; $curClass = $curSubsystem->{'Modules'}->GetAt ($theIndex); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; } sub NewOperation () { my $self = shift; my($name, $params) = @_; $curOperation = $curClass->AddOperation ($name, ""); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; if ($params ne "") { my @all = split /,/, $params; my $i = 0; foreach $param (@all) { $param =~ /^\s*([\$\%\@])([a-zA-Z_:]+)/; my $value = ""; my $type = $Types{$1}; my $param = $2; if ($param ne "") { $curParameter = $curOperation->AddParameter($param, $type, $value, $i); if (Win32::OLE->LastError != 0 || !defined($curParameter)) { warn "Error: could not add parameter ($param, $type, $value, $i): " . Win32::OLE->LastError ; } } $i++; } } } sub NewAttribute () { my $self = shift; my($name, $value) = @_; $name =~ /^([\$\%\@])([a-zA-Z_:]+)/; $value = "" if !defined($value); my $type = $Types{$1}; $name = $2; $curAttribute = $curClass->AddAttribute ($name, $type, $value); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; } sub DeferRelationship () { my $self = shift; my($left, $rel, $right) = @_; push @allRelations, "$left,$rel,$right"; } sub AddDeferredRelationships () { my $self = shift; my $curAssociation; print "Adding relationships...\n"; foreach $relation (@allRelations) { ($left,$rel,$right) = split /,/, $relation; if ($left =~ /\.pm$/) { # $self->AddtoModule($left); # $curAssociation = $curClass->AddAssociation($rel, $right); # warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; # warn "Error: Could not create assoc between $left,$right\n " # if !defined($curAssociation); } else { $self->FindClass($left); if ($rel eq "ISA") { foreach my $parent (split / /, $right) { $curAssociation = $curClass->AddInheritRel("", $parent); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; warn "Error: Could not inherit $left from $parent\n " if !defined($curAssociation); } } else { $curAssociation = $curClass->AddAssociation($rel, $right); warn "Error: " . Win32::OLE->LastError if Win32::OLE->LastError != 0; warn "Error: Could not create assoc between $left,$right\n " if !defined($curAssociation); } } } } #============================================================================== package Rose::Perl; my $AUTHOR = 'Simon Johnston (skj@acm.org)'; my $NAME = 'Perl Reverse Engineer.'; my $VERSION = '1.0.1'; my $COPYRIGHT = "$NAME Version $VERSION.\nCopyright (c) $AUTHOR 1999-2000."; my $Rose; sub ReverseFile() { my($filename, %allpacks) = @_; print "File: $filename\n"; my $relname = $filename; unless (open FILE, "<$filename") { warn "Can't open file $filename: $!\n"; return ; } $Rose->NewModule($filename); while () { if (/^package\s+([^;]+);$/) { if ($allpacks{$1} == 1) { $relname = $1; $Rose->AddtoClass($1); } else { $allpacks{$1} = 1; $relname = $1; $Rose->NewClass($1); } } elsif (/^use\s+([^;\s]+)/) { $Rose->DeferRelationship($relname, "uses", $1); } elsif (/^require\s+([^;\s]+)/) { my $dep = $1; if ($1 =~ /^([\d\.]+)/) { $Rose->DeferRelationship($relname, "$dep", "perl"); } else { $Rose->DeferRelationship($relname, "requires", $dep); } } elsif (/^sub\s+(\S+)/) { my $name = $1; my $nextln = ; my $params = ""; if ($nextln =~ /\(([^\)]+)\)\s*=\s*\@\_/) { $params = $1; } $Rose->NewOperation($name, $params); } elsif (/^BEGIN\s+{/) { $Rose->NewOperation("BEGIN"); } elsif (/^END\s+{/) { $Rose->NewOperation("END"); } elsif (/^([\$\%\@][a-zA-Z_:]+)(.*$)/) { if ($1 eq "\@ISA") { my @MyISA2 = eval "\@MyISA $2"; $Rose->DeferRelationship($relname, "ISA", join(" ", @MyISA2)); } else { $Rose->NewAttribute($1); } } elsif (/^__END__/) { last; } } close FILE; } sub Reverse() { my($directory) = @_; opendir DIR, $directory; my @allfiles = grep !/^\.\.?$/, readdir DIR; my %allpacks; foreach my $filename (@allfiles) { my $fullname = "$directory/$filename"; if (-f $fullname && $filename =~ /\.pm$/) { &ReverseFile($fullname, %allpacks); } elsif (-d $fullname) { $Rose->NewPackage($filename); &Reverse($fullname); $Rose->PreviousPackage(); } } closedir DIR; } sub Usage () { if ($ARGV[0] eq "-V") { print STDERR "Library:\n$Rose::COPYRIGHT\n\n"; print STDERR "Main:\n$COPYRIGHT\n\n"; } print STDERR "See POD for more information.\n"; } sub Main () { if ($#ARGV < 1) { &Usage; } else { $Rose = Rose->new(); if ($ARGV[0] eq "-d") { $Rose->CreateRootPackage($ARGV[2]) if $ARGV[2] ne ""; &Reverse($ARGV[1]); $Rose->AddDeferredRelationships; } elsif ($ARGV[0] eq "-f") { $Rose->CreateRootPackage($ARGV[2]) if $ARGV[2] ne ""; &ReverseFile($ARGV[1]); $Rose->AddDeferredRelationships; } else { &Usage; } } } &Main; __END__ =head1 NAME preveng.pl - Reverse engineer a Perl library into Rational Rose. =head1 SYNOPSIS preveng.pl -[fd] name [root::package] =head1 DESCRIPTION =head1 AUTHOR Simon Johnston (skj@acm.org) =cut