+ eval 'close(FLOCK'.($#filelocks+1).');' || warn "failed to close lock file $lockfile: $!";
+ unlink($lockfile) || warn "failed to remove lock file $lockfile: $!";
+}
+
+sub addfoundversions {
+ my $data = shift;
+ my $source = shift;
+ my $version = shift;
+ return unless defined $version;
+ undef $source if $source =~ m[(?:\s|/)];
+
+ foreach my $ver (split /[,\s]+/, $version) {
+ $ver = "$source/$ver" if defined $source;
+ unless (grep { $_ eq $ver } @{$data->{found_versions}}) {
+ push @{$data->{found_versions}}, $ver;
+ }
+ @{$data->{fixed_versions}} =
+ grep { $_ ne $ver } @{$data->{fixed_versions}};
+ }
+}
+
+sub removefoundversions {
+ my $data = shift;
+ my $source = shift;
+ my $version = shift;
+ return unless defined $version;
+ undef $source if $source =~ m[(?:\s|/)];
+
+ foreach my $ver (split /[,\s]+/, $version) {
+ $ver = "$source/$ver" if defined $source;
+ @{$data->{found_versions}} =
+ grep { $_ ne $ver } @{$data->{found_versions}};
+ }
+}
+
+sub addfixedversions {
+ my $data = shift;
+ my $source = shift;
+ my $version = shift;
+ return unless defined $version;
+ undef $source if $source =~ m[(?:\s|/)];
+
+ foreach my $ver (split /[,\s]+/, $version) {
+ $ver = "$source/$ver" if defined $source;
+ unless (grep { $_ eq $ver } @{$data->{fixed_versions}}) {
+ push @{$data->{fixed_versions}}, $ver;
+ }
+ @{$data->{found_versions}} =
+ grep { $_ ne $ver } @{$data->{found_versions}};
+ }
+}
+
+sub removefixedversions {
+ my $data = shift;
+ my $source = shift;
+ my $version = shift;
+ return unless defined $version;
+ undef $source if $source =~ m[(?:\s|/)];
+
+ foreach my $ver (split /[,\s]+/, $version) {
+ $ver = "$source/$ver" if defined $source;
+ @{$data->{fixed_versions}} =
+ grep { $_ ne $ver } @{$data->{fixed_versions}};
+ }