{ package Win32::ProjectBuilder::SSManager; require 5.004; use strict; use warnings; use Carp; use vars qw( @ISA $VERSION @EXPORT ); $VERSION = "0.01"; @ISA = qw( Exporter ); @EXPORT = (); use protect; use File::Basename qw( dirname ); use File::Path; use File::Spec::Functions qw( canonpath ); use Time::Local qw( timelocal ); use Win32::API; use Win32::OLE qw( in ); use Win32::OLE::Const; use Win32::OLE::Variant; use Win32::File; =head1 NAME Win32::ProjectBuilder::SSManager SSManager - Wrapper Class for SourceSafe OLE Server functions =head1 SYNOPSIS use Win32::ProjectBuilder::SSManager; my $refo_vssmanager; my ( $bool_labelonly, $bool_listonly ); my ( $refar_pattern, $refo_getitem, $refo_version ); my ( $s_ssinipath, $s_localbasepath, $s_passwd, $s_return , $s_const, $s_specpath, $s_username, $s_version ); my ( $s_itemflag, $s_flag ); my ( $ref_getitems ); my ( @ar_versions ); my ( %h_vssconst ); $s_ssinipath = "C:\\Program Files\\Microsoft Visual Studio\\". "Common\\VSS\\srcsafe.ini"; $s_username = "admin"; $s_passwd = ""; $s_return = -1; if ( defined( $refo_vssmanager = Win32::ProjectBuilder::SSManager-> new( $s_ssinipath, $s_username, $s_passwd ))) { $s_return = 0; $refo_vssmanager->autoundocheckout( 1 ); print "AutoUndoCheckout property is ". (( $refo_vssmanager->autoundocheckout ) ? ( "on.\n" ) : ( "off.\n" )); $s_specpath = "\$\/Someproject\/OrFile"; print "SpecPath is ".$refo_vssmanager->specpath.".\n"; $refo_vssmanager->specpath( $s_specpath ); print "SpecPath is ".$refo_vssmanager->specpath.".\n\n"; $s_localbasepath = "C:\\Temp\\Tempdownload\\$s_username"; print "VSSManager LocalBasePath is ". $refo_vssmanager->localbasepath.".\n"; $refo_vssmanager->localbasepath( $s_localbasepath ); print "VSSManager LocalBasePath is ". $refo_vssmanager->localbasepath.".\n\n"; %h_vssconst = $refo_vssmanager->const(); foreach $s_const ( keys %h_vssconst ) { print "Const $s_const = $h_vssconst{$s_const}.\n"; }; print "\n"; $bool_labelonly = 0; $s_flag = $refo_vssmanager->const( "VSSFLAG_RECURSYES" ); $s_version = "Fixed Login Crash"; $s_return = $refo_vssmanager->getversions( \@ar_versions , $s_flag, $s_version, $bool_labelonly ); if ( $s_return == 0 ) { print "Version entries=".( $#ar_versions + 1 ).".\n\n"; foreach $refo_version ( @ar_versions ) { print "Version Action=". $refo_version->action."\n"; print "Version Comment=". $refo_version->comment."\n"; print "Version Date=". $refo_version->date."\n"; print "Version Label=". $refo_version->label."\n"; print "Version Item Name=". $refo_version->ssitem->name."\n"; print "Version Item Spec=". $refo_version->ssitem->spec."\n"; print "Version Item Type=". $refo_version->ssitem->type."\n"; print "Version UserName=". $refo_version->username."\n"; print "Version VersionNumber=". $refo_version->versionnumber."\n"; print "\n"; }; undef @ar_versions; } else { print "OLE or user-defined error $s_return returned ". "from method getversions.\n"; }; $bool_listonly = 0; $s_itemflag = $refo_vssmanager->const( "VSSITEM_FILE" ); $refar_pattern = [ '*.dsp', '*.dsw' ]; $ref_getitems = []; $s_flag = $refo_vssmanager->const( "VSSFLAG_RECURSYES" ); $s_version = "26/02/02"; $s_return = $refo_vssmanager->getitems( $s_itemflag, $s_flag , $s_version, $refar_pattern, $ref_getitems , $bool_listonly ); if( $s_return == 0 ) { if ( ref( $ref_getitems ) =~ /SCALAR/ ) { print "Get Item entries=".${ $ref_getitems }. ".\n\n"; } elsif ( ref( $ref_getitems ) =~ /ARRAY/ ) { print "Get Item entries=". ( $#$ref_getitems + 1 ).".\n\n"; foreach $refo_getitem ( @{ $ref_getitems }) { print "Get Name=". $refo_getitem->name."\n"; print "Get Spec=". $refo_getitem->spec."\n"; print "Get Type=". $refo_getitem->type."\n"; print "Get LocalSpec=". $refo_getitem->localspec.".\n"; print "Get RealLocalSpec=". $refo_getitem->reallocalspec. ".\n"; print "Get Spec=". $refo_getitem->spec.".\n"; print "Get VersionNumber=". $refo_getitem->versionnumber. ".\n"; print "\n"; }; undef @{ $ref_getitems }; }; } else { print "OLE or user-defined error $s_return returned ". "from method getitems.\n"; }; }; exit $s_return; =head1 DESCRIPTION This module wraps a number of SourceSafe OLE Server functions in one-step function calls. Navigation in the SourceSafe database is handled in much the same way as navigating the file system at the command prompt, so that any action is applied to the current sourcesafe spec. Particularly it can handle files functions recursively which takes the burden of having to custom program the OLE SourceSafe Server in your script. Another enhancement is the ability to define wildcards that will filter the files and projects that the functions are meant to apply to. Along with the SSManager class there exist the SSFile , SSProject, SSCheckout, and SSVersion classes which are used to return the properties of their OLE object counterparts in SSManager methods. They have no functions and can not be publicly created. =head1 BUGS None discovered...yet. Not all SourceServer OLE functions are wrapped. =head1 AUTHOR Dominick Moré =cut use constant LOCALE_IDATE => 0x00000021; use constant LANG_NEUTRAL => 0x0; use constant SORT_DEFAULT => 0x0; use constant SUBLANG_DEFAULT => 0x1; use constant LANG_USER_DEFAULT => LANG_NEUTRAL | ( SUBLANG_DEFAULT * 0x400 ); use constant LOCALE_USER_DEFAULT => LANG_USER_DEFAULT | ( SORT_DEFAULT * 0x10000 ); Win32::OLE->Option( Warn => 0 ); members qw ( SSManager ); my $_debug = 0; my $refsub_getcwd = new Win32::API("kernel32", "GetCurrentDirectory", ['N', 'P'], 'N'); my $refsub_getlocaleinfo = new Win32::API("kernel32", "GetLocaleInfo", ['N', 'N', 'P', 'N'], 'N' ); our $refh_vssconst = Win32::OLE::Const->Load( 'Microsoft SourceSafe .*? Type Library' ) || croak "Unable to load SourceSafe constants.\n"; =head1 METHODS =head2 METHOD new The class constructor. Returns the class instance or undef on error. Arguments are: [ $s_ssinipath, $s_username, $s_userpwd ] =over =item * ( optional ) A string. Sets the the Sourcesafe inifilepath C property. Defaults to "". =item * ( optional ) A string. Sets the Sourcesafe Login username C property. Defaults to "". =item * ( optional ) A string. Sets the Sourcesafe Login password property. Defaults to "". =back =cut sub new( $;$$$ ) { is ('public'); my $s_proto = shift; my ( $s_ssinipath, $s_username, $s_userpwd ) = @_; my $s_class = ref( $s_proto ) || $s_proto; if ( $s_class ne __PACKAGE__ ) { carp "Illegal global call on a class ".__PACKAGE__." constructor.\n"; return undef; }; my( $bool_return, $bool_pathdefined ); $bool_return = $bool_pathdefined = 0; if ( defined($s_ssinipath) && ref( \$s_ssinipath ) =~ /SCALAR/i ) { if (($s_ssinipath !~ /^.+\.ini?$/i) || (!(-s $s_ssinipath) || !(-T $s_ssinipath))) { $s_ssinipath = ""; } else { $bool_pathdefined = 1; }; } else { $s_ssinipath = ""; }; if ((ref( \$s_username ) !~ /SCALAR/i ) || ( !$s_username )) { $s_username = ""; }; if ((ref( \$s_userpwd ) !~ /SCALAR/i ) || ( !$s_userpwd )) { $s_userpwd = ""; }; my $refh_newself = { AUTOUNCHKOUT => 0, CALLBACKARGS => undef, CALLBACKFUNC => undef, _DEBUG => \$_debug, DIRRECURSPAT => [], DIRRECURSFLAGS => 0, DIRRECURSITEMS => 0, INDIRRECURS => 0, INIFILEPATH => undef, ITEMSTACK => [], LOCALBASEPATH => undef, OBJ_VSS => undef, PROJECTRECURS => 0, USERNAME => "", USERPWD => "", VSSCONST => $refh_vssconst, }; my $refh_self = sub { is ('private'); return $refh_newself; }; bless ($refh_self, $s_class); if ( $refh_self->_initialize() == 0 ) { if ( $bool_pathdefined ) { $refh_self->open($s_ssinipath, $s_username, $s_userpwd); }; $refh_self->localbasepath( $ENV{"TEMP"} ); if ( !$refh_self->localbasepath ) { carp "Unable to set initial localpath in ". __PACKAGE__." constructor.\n"; undef $refh_self; }; } else { undef $refh_self; }; return $refh_self; }; sub DESTROY( $ ) { is ('public'); my $refh_self = shift; unless (ref( $refh_self ) && ($refh_self->isa(__PACKAGE__))) { carp "Illegal global call on a class ".__PACKAGE__." destructor.\n"; return undef; }; my $refh_data = &{$refh_self}; undef @{$refh_data->{'ITEMSTACK'}}; if ( $refh_self->specpath && $refh_data->{'AUTOUNCHKOUT'} ) { $refh_self->specpath("\$\/"); $refh_self->undocheckouts(); }; undef $refh_data->{'OBJ_VSS'}; undef $refh_self; }; =head2 METHOD checkinitems C This method checks in any items that match the parameter arguments in the current database specpath and are checked out in the context of the current SourceSafe username. The return value is "0" if the operation is successful. If the operation fails then the return value is either "-1" (in the case of a SSManager class internal error) or the SourceSafe OLE Server HRESULT. Arguments are: [ $s_vssitems, $s_vssflags, $s_comment, $refar_pattern, $refar_items ] =over =item * ( optional ) A number. Specifies whether the function acts on files and/or projects. Recognized values include the SourceSafe constants ( VSSITEM_FILE and VSSITEM_PROJECT ). Defaults to ( VSSITEM_FILE | VSSITEM_PROJECT ). =item * ( optional ) A number. Specifies the VSSFLAGS passed on to SourceSafe OLE function, Any SourceSafe VSSFLAG_* constants are valid values. Defaults to ( VSSFLAG_RECURSYES | VSSFLAG_GETYES | VSSFLAG_USERRONO | VSSFLAG_REPREPLACE | VSSFLAG_KEEPNO | VSSFLAG_UPDUNCH ). =item * ( optional ) A string. Specifies the comment that is passed to files checked in to SourceSafe. Defaults to "". =item * ( optional ) An array reference. Specifies a list of wildcards that are used to filter files and projects that the function acts upon. Wildcards my be specified as using the DOS typical '*' and '?' modifiers ( e.g. '*.txt' or '*.t??' ). Defaults to [ '*' ]. =item * ( optional ) An array or scalar reference. If the argument is neither it will be ignored. If the argument is a scalar reference then it will be filled with the count of checked-in items. If it is an array reference then it will be filled with a list of SSFile objects representing the files checked-in. The checkouts property of the SSFile objects are not filled. =back =cut sub checkinitems( $;$$$\@\@ ) { is ('public'); my $refh_self = shift; unless (ref( $refh_self ) && ($refh_self->isa(__PACKAGE__))) { carp "Illegal global call on a class ".(caller(0))[3]." method.\n"; return -1; }; my ( $s_vssitems, $s_vssflags, $s_comment, $refar_pattern, $refar_items ) = @_; my $refh_data = &{$refh_self}; my $refh_const = $refh_data->{'VSSCONST'}; if ( ref( $refar_items ) =~ /ARRAY/ ) { undef @{$refar_items}; } elsif ( ref( $refar_items ) =~ /SCALAR/ ) { ${$refar_items} = 0; } else { $refar_items = undef; }; $s_comment = undef unless( ref( \$s_comment ) =~ /SCALAR/ ); my $refh_arg = { 'ar_tempitems' => $refar_items, 's_comment' => $s_comment }; my $refc_chkincallback = sub { my ( $refo_vssitem, $refh_argt, $s_flags ) = @_; my ( $reh_checkout, $refh_item, $refo_checkout ); my ( $s_name, $s_path, $s_reallocalpath, $s_return , $s_spec, $s_type, $s_username ); my @ar_hresult; my $bool_checkedin = 0; $s_return = 0; $s_type = $refo_vssitem->{'Type'}; if ( $s_type == $refh_const->{'VSSITEM_PROJECT'} ) { return $s_return; }; $s_name = $refo_vssitem->{'Name'}; $s_spec = $refo_vssitem->{'Spec'}; $s_reallocalpath = ""; if ( $refh_const->{'VSSFILE_CHECKEDOUT_ME'} & $refo_vssitem->{'IsCheckedOut'} ) { foreach $refo_checkout ( in $refo_vssitem->{'Checkouts'} ) { $s_username = $refo_checkout->{'UserName'}; if ( $refh_data->{'USERNAME'} =~ /^$s_username$/i ) { $s_reallocalpath = $refo_checkout->{'LocalSpec'}. "\\$s_name"; $refo_vssitem->Checkin( Variant( VT_BSTR , $refh_argt->{'s_comment'} ) , Variant( VT_BSTR, $s_reallocalpath ) , Variant( VT_I4, $s_flags )); $s_return += Win32::OLE->LastError(); if ( $s_return ) { @ar_hresult = split( /\n/ , Win32::OLE->LastError()); undef $refo_checkout; carp "Error was \"".$ar_hresult[2]. "\" in method ". (caller(2))[3].".\n"; return $s_return; } else { $bool_checkedin = 1; }; }; }; }; if ( $bool_checkedin ) { if ( ${ $refh_data->{ '_DEBUG' }} ) { print "Checkin Item $s_reallocalpath in ". (caller(2))[3]." successful.\n"; }; if ( ref( $refh_argt->{'ar_tempitems'} ) =~ /ARRAY/ ) { if ( defined( $refh_item = SSFile->_new( $refo_vssitem->{'Deleted'}, $refo_vssitem->{'LocalSpec'}, $s_name, $s_spec, $s_type, $refo_vssitem->{'VersionNumber'}, $refo_vssitem->{'Binary'}, $refo_vssitem->{'IsCheckedOut'}, $refo_vssitem->{'IsDifferent'})) ) { push @{$refh_argt->{'ar_tempitems'}} , $refh_item; } else { carp "Unable to create SSItem ". $refo_vssitem->{'Spec'}. " in ".(caller(2))[3]." method.\n"; return $s_return = -1; }; } elsif ( ref( $refh_argt->{'ar_tempitems'} ) =~ /SCALAR/ ) { ${$refh_argt->{'ar_tempitems'}}++; }; }; return $s_return; }; my $s_return = $refh_self->_dirrecurse( $refc_chkincallback, $refh_arg , $s_vssitems, $s_vssflags, $refar_pattern ); if ( $s_return != 0 ) { if ( ref( $refar_items ) =~ /ARRAY/ ) { undef @{$refar_items}; } elsif ( ref( $refar_items ) =~ /SCALAR/ ) { ${$refar_items} = 0; }; }; $refh_arg = undef; $refc_chkincallback = undef; return $s_return; }; =head2 METHOD checkoutitems C This method checks out any items that match the parameter arguments in the current database specpath in the context of the current SourceSafe username. The return value is "0" if the operation is successful. If the operation fails then the return value is either "-1" (in the case of a SSManager class internal error) or the SourceSafe OLE Server HRESULT. Arguments are: [ $s_vssitems, $s_vssflags, $s_comment, $refar_pattern, $refar_items ] =over =item * ( optional ) A number. Specifies whether the function acts on files and/or projects. Recognized values are the SourceSafe constants ( VSSITEM_FILE and VSSITEM_PROJECT ). Defaults to ( VSSITEM_FILE | VSSITEM_PROJECT ). =item * ( optional ) A number. Specifies the VSSFLAGS passed on to SourceSafe OLE function Any SourceSafe VSSFLAG_* constants are valid values. Defaults to ( VSSFLAG_RECURSYES | VSSFLAG_GETYES | VSSFLAG_USERRONO | VSSFLAG_REPREPLACE | VSSFLAG_KEEPNO | VSSFLAG_UPDUNCH ). =item * ( optional ) A string. Specifies the comment that is passed to files checked in to SourceSafe. Defaults to "". =item * ( optional ) An array reference. Specifies a list of wildcards that are used to filter files and projects that the function acts upon. wildcards my be specified as using the DOS typical '*' and '?' modifiers ( e.g. '*.txt' or '*.t??' ). Defaults to [ '*' ]. =item * ( optional ) An array or scalar reference. If the argument is neither it will be ignored. If the argument is a scalar reference then it will be filled with the count of checked-in items. If it is an array reference then it will be filled with a list of SSFile objects representing the files checked-in. The checkouts property of the SSFile objects are filled with a single checkout object representing the file or project being checked out. =back =cut sub checkoutitems( $;$$$\@\@ ) { is ('public'); my $refh_self = shift; unless (ref( $refh_self ) && ($refh_self->isa(__PACKAGE__))) { carp "Illegal global call on a class ".(caller(0))[3]." method.\n"; return -1; }; my ( $s_vssitems, $s_vssflags, $s_comment, $refar_pattern, $refar_items ) = @_; my $refh_data = &{$refh_self}; my $refh_const = $refh_data->{'VSSCONST'}; if ( ref( $refar_items ) =~ /ARRAY/ ) { undef @{$refar_items}; } elsif ( ref( $refar_items ) =~ /SCALAR/ ) { ${$refar_items} = 0; } else { $refar_items = undef; }; $s_comment = undef unless( ref( \$s_comment ) =~ /SCALAR/ ); my $refh_arg = { 'ar_tempitems' => $refar_items, 's_comment' => $s_comment }; my $refc_chkoutcallback = sub { my ( $refo_vssitem, $refh_argt, $s_flags ) = @_; my ( $bool_ischeckedout ); my ( $refar_time, $refh_checkouts, $refh_item, $refo_checkout ); my ( $s_chkoutlocalspec, $s_localspec, $s_name, $s_reallocalpath , $s_return, $s_spec, $s_type, $s_username ); my ( @ar_hresult, @ar_splitpath ); $s_return = 0; $s_type = $refo_vssitem->{'Type'}; if ( $s_type == $refh_const->{'VSSITEM_PROJECT'} ) { return $s_return; }; $s_localspec = $refo_vssitem->{'LocalSpec'}; $s_name = $refo_vssitem->{'Name'}; $s_spec = $refo_vssitem->{'Spec'}; if ( !$refh_data->{'LOCALBASEPATH'} ) { if ( !$s_localspec ) { $s_reallocalpath = _getcwd()."\\$s_name"; } else { $s_reallocalpath = "$s_localspec\\$s_name"; }; } else { @ar_splitpath = split( /\//, $s_spec ); shift @ar_splitpath; $s_reallocalpath = $refh_data->{'LOCALBASEPATH'}."\\". join( "\\", @ar_splitpath ); }; $bool_ischeckedout = 0; if ( $refh_const->{'VSSFILE_CHECKEDOUT_ME'} & $refo_vssitem->{'IsCheckedOut'} ) { foreach $refo_checkout ( in $refo_vssitem->{'Checkouts'} ) { $s_chkoutlocalspec = $refo_checkout->{'LocalSpec'}. "\\$s_name"; $s_username = $refo_checkout->{'UserName'}; if (( $refh_data->{'USERNAME'} =~ /^$s_username$/i ) && ( lc( $s_chkoutlocalspec ) eq lc( $s_reallocalpath ))) { $bool_ischeckedout = 1; undef $refo_checkout; last; }; }; }; if ( !$bool_ischeckedout ) { $refo_vssitem->Checkout( Variant( VT_BSTR , $refh_argt->{'s_comment'} ) , Variant( VT_BSTR, $s_reallocalpath ) , Variant( VT_I4, $s_flags )); $s_return += Win32::OLE->LastError(); if ( $s_return ) { @ar_hresult = split( /\n/, Win32::OLE->LastError()); carp "Error was \"".$ar_hresult[2]."\" in method ". (caller(2))[3].".\n"; return $s_return; } else { $bool_ischeckedout = 1; }; }; if ( $bool_ischeckedout ) { if ( ${ $refh_data->{ '_DEBUG' }} ) { print "Checkout Item $s_reallocalpath in ". (caller(2))[3]." successful.\n"; }; if ( ref( $refh_argt->{'ar_tempitems'} ) =~ /ARRAY/ ) { if( defined( $refh_item = SSFile->_new( $refo_vssitem->{'Deleted'}, $s_localspec, $s_name, $s_spec, $s_type, $refo_vssitem->{'VersionNumber'}, $refo_vssitem->{'Binary'}, $refo_vssitem->{'IsCheckedOut'}, $refo_vssitem->{'IsDifferent'})) ) { $refh_item->reallocalspec( $s_reallocalpath ); if ( defined( $refo_checkout = $refo_vssitem->Checkouts( Variant( VT_BSTR , $refh_data->{'USERNAME'} )))) { push (@{$refar_time}, split( " " , $refo_checkout->{'Date'}-> Time("s m H"))); push (@{$refar_time}, split( " " , $refo_checkout->{'Date'}-> Date("d M yyyy"))); $refar_time->[4] -= 1; $refh_item->_insertcheckout( $refo_checkout->{'Comment'} , timelocal(@{$refar_time}) , $refo_checkout->{'LocalSpec'} , $refo_checkout->{'Machine'} , $refo_checkout->{'Project'} , $refo_checkout->{'UserName'} , $refo_checkout->{'VersionNumber'} ); }; push @{$refh_argt->{'ar_tempitems'}}, $refh_item; } else { carp "Unable to create SSItem ". $refo_vssitem->{'Spec'}. " in ".(caller(2))[3]." method.\n"; return $s_return = -1; }; } elsif ( ref( $refh_argt->{'ar_tempitems'} ) =~ /SCALAR/ ) { ${$refh_argt->{'ar_tempitems'}}++; }; }; return $s_return; }; my $s_return = $refh_self->_dirrecurse( $refc_chkoutcallback, $refh_arg , $s_vssitems, $s_vssflags, $refar_pattern ); if ( $s_return != 0 ) { if ( ref( $refar_items ) =~ /ARRAY/ ) { undef @{$refar_items}; } elsif ( ref( $refar_items ) =~ /SCALAR/ ) { ${$refar_items} = 0; }; }; $refh_arg = undef; $refc_chkoutcallback = undef; return $s_return; }; =head2 METHOD const C Returns the numeric value of the specified SourceSafe constant or returns a copy of the hash of SourceSafe constants when requested in an array/hash context. Returns undef if the constant name cannot be resolved. Arguments are: [ $s_constname ] =over =item * ( optional ) A string. The name of the wanted constant value. =back =cut sub const( $;$ ) { is ('public'); my $refh_self = shift; unless (ref( $refh_self ) && ($refh_self->isa(__PACKAGE__))) { carp "Illegal global call on a class ".(caller(0))[3]." property.\n"; return undef; }; my $s_constname = shift; if( $s_constname ) { my $refh_data = &{$refh_self}; if ( ref( \$s_constname ) =~ /SCALAR/i && exists( $refh_data->{'VSSCONST'}->{ $s_constname } )) { return $refh_data->{'VSSCONST'}->{ $s_constname }; } else { carp "Constant name \"$s_constname\" name does not exist ". "in property ".(caller(0))[3].".\n"; }; } elsif ( wantarray()) { my $refh_data = &{$refh_self}; return %{$refh_data->{'VSSCONST'}}; } else { carp "Constant name \"$s_constname\" name does not exist ". "in property ".(caller(0))[3].".\n"; }; return undef; }; sub _dirrecurse( $;\$$$$ ) { is ('private'); my $refh_self = shift; my $s_return = 0; my $refh_data = &{$refh_self}; unless (ref( $refh_self ) && ($refh_self->isa(__PACKAGE__))) { carp "Illegal global call on a class ".(caller(0))[3]." method.\n"; $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; return $s_return = -1; }; my ( $refc_callback, $s_callbackargs, $s_vssitems, $s_vssflags, $refar_pattern , $s_version, $bool_reset ) = @_; my ( $s_callreturn, $s_currentproj, $s_eval, $s_index, $s_name , $s_searchparam, $s_searchtype, $s_pattern, $s_type ); my ( $refar_tempdate, $refo_vssitem, $refo_vsssubitem ); my $bool_wasprojectrecurs = 0; my @ar_hresult; my $refh_const = $refh_data->{'VSSCONST'}; my $refh_searchtype = { NONE => 0, DATE => 1, LABEL => 2, VERSIONNUMBER => 3 }; if ($bool_reset ) { $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; return $s_return = 0; } elsif ( !$refh_data->{'INDIRRECURS'} && $refh_self->specpath ) { $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; if ( ref( $refc_callback ) !~ /CODE/i ) { $s_return = -1; carp "Callback function not specified in method ".(caller(1))[3].".\n"; return $s_return; } else { $refh_data->{'CALLBACKFUNC'} = $refc_callback; $refh_data->{'CALLBACKARGS'} = $s_callbackargs; }; if (( ref( \$s_vssitems ) =~ /SCALAR/i ) && defined( $s_vssitems )) { $s_vssitems =~ s/^\s*?(.*?)\s*?$/$1/; if ( $s_vssitems !~ /^\d+$/ ) { if ( $s_vssitems ) { $refh_data->{'DIRRECURSITEMS'} = eval("$s_vssitems"); } else { $refh_data->{'DIRRECURSITEMS'} = $refh_const->{'VSSITEM_FILE'} | $refh_const->{'VSSITEM_PROJECT'}; }; } else { $refh_data->{'DIRRECURSITEMS'} = $s_vssitems; }; } else { $refh_data->{'DIRRECURSITEMS'} = $refh_const->{'VSSITEM_FILE'} | $refh_const->{'VSSITEM_PROJECT'}; }; if ( !defined( $refh_data->{'DIRRECURSITEMS'} ) || $refh_data->{'DIRRECURSITEMS'} !~ /^\d+$/ ) { $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; carp "Argument s_vssitems '$s_vssitems' is meaningless in method ". (caller(1))[3].".\n"; return $s_return = -1; }; if (( ref( \$s_vssflags ) =~ /SCALAR/i ) && defined( $s_vssflags )) { $s_vssflags =~ s/^\s*?(.*?)\s*?$/$1/; if ( $s_vssflags !~ /^\d+$/ ) { if ( $s_vssflags ) { $refh_data->{'DIRRECURSFLAGS'} = eval("$s_vssflags"); } else { $refh_data->{'DIRRECURSFLAGS'} = ( $refh_const->{'VSSFLAG_RECURSYES'} | $refh_const->{'VSSFLAG_GETYES'} | $refh_const->{'VSSFLAG_USERRONO'} | $refh_const->{'VSSFLAG_REPREPLACE'} | $refh_const->{'VSSFLAG_KEEPNO'} | $refh_const->{'VSSFLAG_UPDUNCH'} ); }; } else { $refh_data->{'DIRRECURSFLAGS'} = $s_vssflags; }; } else { $refh_data->{'DIRRECURSFLAGS'} = ( $refh_const->{'VSSFLAG_RECURSYES'} | $refh_const->{'VSSFLAG_GETYES'} | $refh_const->{'VSSFLAG_USERRONO'} | $refh_const->{'VSSFLAG_REPREPLACE'} | $refh_const->{'VSSFLAG_KEEPNO'} | $refh_const->{'VSSFLAG_UPDUNCH'} ); }; if ( !defined( $refh_data->{'DIRRECURSFLAGS'} ) || $refh_data->{'DIRRECURSFLAGS'} !~ /^\d+$/ ) { $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; carp "Argument s_vssflags '$s_vssflags' is meaningless in method ". (caller(1))[3].".\n"; return $s_return = -1; } else { $refh_data->{'DIRRECURSFLAGS'} |= $refh_const->{'VSSFLAG_FORCEDIRNO'} if ( $refh_data->{'LOCALBASEPATH'} ); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_USERROYES'} if(( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_USERRONO'} ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_USERROYES'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_REPASK'} if( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_REPASK'} ); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_RECURSYES'} if(( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_RECURSNO'} ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_RECURSYES'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_FORCEDIRYES'} if(( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_FORCEDIRNO'} ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_FORCEDIRYES'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_KEEPYES'} if(( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_KEEPNO'} ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_KEEPYES'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_DELYES'} if((( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_DELNO'} ) || ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_DELNOREPLACE'} )) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_DELYES'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_DELNOREPLACE'} if(( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_DELNO'} ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_DELNOREPLACE'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_DELTAYES'} if(( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_DELTANO'} ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_DELTAYES'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_UPDUPDATE'} if(( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_UPDUNCH'} ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_UPDUPDATE'} )); $refh_data->{'DIRRECURSFLAGS'} ^= $refh_const->{'VSSFLAG_UPDASK'} if( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_UPDASK'} ); }; if ((ref( \$refar_pattern ) =~ /SCALAR/i ) && defined( $refar_pattern )) { my $s_temp = $refar_pattern; $s_temp =~ s/^\s*?(.*?)\s*?$/$1/; if ( $s_temp ) { push @{$refh_data->{'DIRRECURSPAT'}}, $s_temp; }; }; if ( ref( $refar_pattern ) =~ /ARRAY/i ) { my @ar_temp = @{$refar_pattern}; for ( $s_index = 0; $s_index <= $#ar_temp; $s_index++ ) { $ar_temp[$s_index] =~ s/(\/|\\|\||\:|\"|\<|\>)//g; $ar_temp[$s_index] =~ s/(\.|\^|\$|\+)/\\$1/ig; $ar_temp[$s_index] =~ s/(\*|\?)/\.$1/ig; if ( $ar_temp[$s_index] ) { push @{$refh_data->{'DIRRECURSPAT'}} , $ar_temp[$s_index]; }; }; }; $s_currentproj = $refh_data->{'OBJ_VSS'}->{'CurrentProject'}; if ( $s_currentproj ) { $s_searchtype = $refh_searchtype->{'NONE'}; if( ref( \$s_version ) =~ /SCALAR/i && $s_version ) { if ( $s_version =~ /^\s*?(\d+)\s*?$/ ) { $s_searchparam = $1; $s_searchtype = $refh_searchtype->{'VERSIONNUMBER'}; } elsif ( $s_version =~ /^\s*?(\d{1,4})\s*?(\\|\/|\.|-)\s*?(\d{1,2})\s*?\2\s*?(\d{1,4})\s*?$/ ) { $refar_tempdate = _splitdate( join( "/", ( $1, $3, $4 ))); if ( !( $refar_tempdate )) { $s_return = Win32::OLE->LastError(); $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; undef @{$refh_data->{'DIRRECURSPAT'}}; carp "Could not parse date \"$s_version\" ". "in method ". (caller(1))[3].".\n"; return $s_return = -1; }; $s_searchparam = join( "/", @{ $refar_tempdate }); $s_searchtype = $refh_searchtype->{'DATE'}; } else { $s_searchparam = $s_version; $s_searchtype = $refh_searchtype->{'LABEL'}; }; }; } else { $s_return = Win32::OLE->LastError(); $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; undef @{$refh_data->{'DIRRECURSPAT'}}; if ( $s_return ) { @ar_hresult = split( /\n/, Win32::OLE->LastError()); carp "Error was \"".$ar_hresult[2]."\".\n"; } else { carp "Could not get sourcesafe spec in method ". (caller(1))[3].".\n"; }; return $s_return || -1; }; if ( $s_searchtype ) { $refo_vssitem = $refh_data->{'OBJ_VSS'}->VSSItem(Variant( VT_BSTR , $s_currentproj ))-> Version( Variant( VT_BSTR, $s_searchparam )); if (( $s_searchtype != $refh_searchtype->{'VERSIONNUMBER'} ) && $refo_vssitem ) { $s_searchparam = $refo_vssitem->{'VersionNumber'}; undef $refo_vssitem; $refo_vssitem = $refh_data->{'OBJ_VSS'}-> VSSItem(Variant( VT_BSTR, $s_currentproj ))-> Version( Variant( VT_BSTR, $s_searchparam )); }; } else { $refo_vssitem = $refh_data->{'OBJ_VSS'}->VSSItem( Variant( VT_BSTR, $s_currentproj )); }; if ( !$refo_vssitem ) { $s_return = Win32::OLE->LastError(); $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; undef @{$refh_data->{'DIRRECURSPAT'}}; if ( $s_return ) { @ar_hresult = split( /\n/, Win32::OLE->LastError()); carp "Error was \"".$ar_hresult[2]."\" in method ". (caller(1))[3].".\n"; } else { carp "Could not get sourcesafe item \"$s_currentproj\" ". "in method ".(caller(1))[3].".\n"; }; return $s_return || -1; } else { $refh_data->{'INDIRRECURS'} = 1; }; } elsif ( $refh_data->{'INDIRRECURS'} ) { $refo_vssitem = $refh_data->{'ITEMSTACK'}-> [ $#{ $refh_data->{'ITEMSTACK'}} ]; } else { $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; carp "No specpath value defined in method ".(caller(1))[3].".\n"; return $s_return = -1; }; $bool_wasprojectrecurs = $refh_data->{'PROJECTRECURS'}; $s_type = $refo_vssitem->{'Type'}; if ( $refh_const->{'VSSITEM_PROJECT'} == $s_type ) { $s_eval = undef; if ( $#{$refh_data->{'DIRRECURSPAT'}} + 1 ) { $s_name = $refo_vssitem->{'Name'}; foreach $s_pattern ( @{$refh_data->{'DIRRECURSPAT'}} ) { last if ( $s_eval = ( $s_name =~ /^$s_pattern$/i )); }; } else { $s_eval = 1; }; if ( $s_eval ) { $s_callreturn = &{$refh_data->{'CALLBACKFUNC'}}( $refo_vssitem , $refh_data->{'CALLBACKARGS'} , $refh_data->{'DIRRECURSFLAGS'} , $refh_data->{'DIRRECURSITEMS'} ); if ( $s_callreturn != 0 ) { $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef $refo_vssitem; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; return $s_return = $s_callreturn; } else { $s_return = $s_callreturn; $refh_data->{'PROJECTRECURS'} = 1; }; }; foreach $refo_vsssubitem ( in $refo_vssitem->{'Items'} ) { $s_eval = undef; $s_type = $refo_vsssubitem->{'Type'}; if ( $refh_const->{'VSSITEM_FILE'} == ( $refh_data->{'DIRRECURSITEMS'} & $s_type )) { if ( !$refh_data->{'PROJECTRECURS'} && ( $#{$refh_data->{'DIRRECURSPAT'}} + 1 )) { $s_name = $refo_vsssubitem->{'Name'}; foreach $s_pattern ( @{$refh_data->{'DIRRECURSPAT'}} ) { last if ( $s_eval = $s_name =~ /^$s_pattern$/i ); }; } else { $s_eval = 1; }; if ( $s_eval ) { $s_callreturn = &{$refh_data->{'CALLBACKFUNC'}} ( $refo_vsssubitem , $refh_data->{'CALLBACKARGS'} , $refh_data->{'DIRRECURSFLAGS'} , $refh_data->{'DIRRECURSITEMS'} ); if ( $s_callreturn != 0 ) { $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; undef $refo_vsssubitem; undef $refo_vssitem; return $s_return = $s_callreturn; } else { $s_return = $s_callreturn; }; }; }; if (( $refh_const->{'VSSITEM_PROJECT'} == $s_type ) && ( $refh_data->{'DIRRECURSFLAGS'} & $refh_const->{'VSSFLAG_RECURSYES'} )) { push (@{$refh_data->{'ITEMSTACK'}}, $refo_vsssubitem ); $s_callreturn = $refh_self->_dirrecurse(); pop @{$refh_data->{'ITEMSTACK'}}; if ( $s_callreturn != 0 ) { $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; undef $refo_vsssubitem; undef $refo_vssitem; return $s_return = $s_callreturn; } else { $s_return = $s_callreturn; }; }; }; undef $refo_vsssubitem; undef $refo_vssitem; if ( $#{ $refh_data->{'ITEMSTACK'}} < 0 ) { $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; }; } elsif ( $refh_const->{'VSSITEM_FILE'} == ( $refh_data->{'DIRRECURSITEMS'} & $s_type )) { $s_eval = undef; if ( $#$refh_data->{'DIRRECURSPAT'} + 1 ) { $s_name = $refo_vssitem->{'Name'}; foreach $s_pattern ( @{$refh_data->{'DIRRECURSPAT'}} ) { last if ( $s_eval = $s_name =~ /^$s_pattern$/i ); }; } else { $s_eval = 1; }; if ( $s_eval ) { $s_return = &{$refh_data->{'CALLBACKFUNC'}}( $refo_vssitem , $refh_data->{'CALLBACKARGS'} , $refh_data->{'DIRRECURSFLAGS'} , $refh_data->{'DIRRECURSITEMS'} ); }; $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef $refo_vssitem; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; } else { $refh_data->{'CALLBACKARGS'} = undef; $refh_data->{'CALLBACKFUNC'} = undef; $refh_data->{'DIRRECURSFLAGS'} = undef; $refh_data->{'DIRRECURSITEMS'} = undef; $refh_data->{'INDIRRECURS'} = 0; $refh_data->{'PROJECTRECURS'} = 0; undef @{$refh_data->{'ITEMSTACK'}}; undef @{$refh_data->{'DIRRECURSPAT'}}; carp "VSSItem Type not identified in method ".(caller(1))[3].". Error ". "was \"".$ar_hresult[2]."\".\n"; $s_return = -1; };