OSSP CVS Repository

ossp - Check-in [4540]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 4540
Date: 2004-Apr-23 15:09:50 (local)
2004-Apr-23 13:09:50 (UTC)
User:rse
Branch:
Comment: complete code cleanups and documentation
Tickets:
Inspections:
Files:
ossp-pkg/cvsfusion/RCS.pm      1.3 -> 1.4     176 inserted, 85 deleted

ossp-pkg/cvsfusion/RCS.pm 1.3 -> 1.4

--- RCS.pm       2004/04/23 12:21:44     1.3
+++ RCS.pm       2004/04/23 13:09:50     1.4
@@ -38,12 +38,16 @@
 @ISA       = qw(Exporter);
 @EXPORT_OK = qw(new destroy DESTROY dump);
 
-sub new ($) {
-    my $proto = shift;
+#   create new object
+sub new ($;$) {
+    my ($proto, $file) = @_;
+
+    #   create new object
     my $class = ref($proto) || $proto;
     my $self = {};
     bless ($self, $class);
 
+    #   initialize object
     $self->{'tool'} = {
         'rcs'  => 'rcs',
         'co'   => 'co',
@@ -51,23 +55,30 @@
     };
     $self->{'rcs'} = {};
 
+    #   optionally load file into object
+    $rcs->load($file) if (defined($file));
+
+    #   return new object
     return $self;
 }
 
+#   destroy object (explicit destructor)
 sub destroy ($) {
-    my $self = shift;
+    my ($self) = @_;
     return;
 }
 
+#   destroy object (implicit destructor)
 sub DESTROY ($) {
-    my $self = shift;
+    my ($self) = @_;
     $self->destroy;
     return;
 }
 
+#   dump object internals (debugging only)
 sub dump ($;$) {
-    my $self = shift;
-    my $name = shift || "xxx";
+    my ($self, $name) = @_;
+    $name ||= "rcs";
     eval {
         use Data::Dumper;
     };
@@ -81,9 +92,9 @@
     return $dump;
 }
 
+#   get and/or set paths to external tools
 sub tool ($;$) {
-    my $self = shift;
-    my ($tool, $path) = @_;
+    my ($self, $tool, $path) = @_;
     my $old = $self->{'tool'}->{$tool};
     if (not defined($old)) {
         croak "tool \"$tool\" not known";
@@ -94,13 +105,15 @@
     return $old;
 }
 
-#  quote/unquote a RCS string
+#   INTERNAL: quote a RCS string
 sub _string_quote {
     my ($str) = @_;
     $str =~ s|\@|\@\@|sg;
     $str = '@' . $str . '@';
     return $str;
 }
+
+#   INTERNAL: unquote a RCS string
 sub _string_unquote {
     my ($str) = @_;
     $str =~ s|^\@(.*)\@$|$1|s;
@@ -108,9 +121,9 @@
     return $str;
 }
 
+#   load an RCS file into object
 sub load ($$) {
-    my $self = shift;
-    my ($file) = @_;
+    my ($self, $file) = @_;
 
     #   read RCS file into buffer
     my $io = new IO::File "<$file"
@@ -119,6 +132,17 @@
     $rcs .= $_ while (<$io>);
     $io->close;
 
+    #   parse RCS file content into object
+    $self->parse($rcs);
+
+    return;
+}
+
+#   parse a RCS file content into object
+#   (see rcsfile(5) for reference)
+sub parse ($$) {
+    my ($self, $rcs) = @_;
+
     #   clear RCS structure
     $self->{'rcs'} = {
         'header'    => { -order => [] },
@@ -266,12 +290,88 @@
             last;
         }
     }
+
     return;
 }
 
+#   INTERNAL: return ordered list of revisions
+#   (either in branch-first or next-first traversal order)
+sub _revlist ($$) {
+    my ($self, $branchfirst) = @_;
+    my @revs = ();
+    &nextrev(\@revs, $self->{'rcs'}->{'header'}->{'head'}, $branchfirst);
+    sub nextrev ($$$) {
+        my ($revs, $rev, $branchfirst) = @_;
+        push(@{$revs}, $rev);
+        my $next     = $self->{'rcs'}->{'delta'}->{$rev}->{'next'};
+        my $branches = $self->{'rcs'}->{'delta'}->{$rev}->{'branches'};
+        if ($branchfirst) {
+            foreach my $branch (@{$branches}) {
+                &nextrev($revs, $branch, $branchfirst); 
+            }
+            &nextrev($revs, $next, $branchfirst) if (defined($next) and $next ne '');
+        }
+        else {
+            &nextrev($revs, $next, $branchfirst) if (defined($next) and $next ne '');
+            foreach my $branch (@{$branches}) {
+                &nextrev($revs, $branch, $branchfirst); 
+            }
+        }
+        return;
+    }
+    return @revs;
+}
+
+#   INTERNAL: generate output of a value in RCS syntax and layout
+sub _genvalue ($$) {
+    my ($val, $tag) = @_;
+    my $rcs = '';
+    if (ref($val) eq 'ARRAY' and @{$val} > 0) {
+        foreach my $v (@{$val}) {
+            $rcs .= "\n\t$v";
+        }
+    }
+    elsif (ref($val) eq 'HASH' and keys(%{$val}) > 0) {
+        if (defined($val->{-order})) {
+            foreach my $v (@{$val->{-order}}) {
+                $rcs .= sprintf("\n\t%s:%s", $v, $val->{$v});
+            }
+        }
+        else {
+            foreach my $v (keys(%{$val})) {
+                $rcs .= sprintf("\n\t%s:%s", $v, $val->{$v});
+            }
+        }
+    }
+    elsif (not ref($val) and $val ne '') {
+        if ($tag eq '@') {
+            $rcs .= "\t" . &_string_quote($val);
+        }
+        else {
+            $rcs .= "\t$val";
+        }
+    }
+    return $rcs;
+}
+
+#   save object into RCS file
+#   (see rcsfile(5) for reference)
 sub save ($$) {
-    my $self = shift;
-    my ($file) = @_;
+    my ($self, $file) = @_;
+
+    #   format object as RCS file content
+    my $rcs = $self->format();
+
+    #   write RCS file content to RCS file
+    my $io = new IO::File ">$file"
+        or croak "RCS file \"$file\": cannot open for writing";
+    $io->print($rcs);
+    $io->close;
+}
+
+#   format object as RCS file content
+sub format ($) {
+    my ($self) = @_;
     my $rcs = '';
 
     #   define known keywords
@@ -290,75 +390,14 @@
         $tag = $1 if ($header =~ s/([@\-])$//s);
         my $val = $self->{'rcs'}->{'header'}->{$header};
         if (defined($val)) {
-            $rcs .= $header;
-            if (ref($val) eq 'ARRAY') {
-                if (@{$val} > 0) {
-                    foreach my $v (@{$val}) {
-                        $rcs .= "\n\t$v";
-                    }
-                }
-            }
-            elsif (ref($val) eq 'HASH') {
-                if (keys(%{$val}) > 0) {
-                    if (defined($val->{-order})) {
-                        foreach my $v (@{$val->{-order}}) {
-                            $rcs .= sprintf("\n\t%s:%s", $v, $val->{$v});
-                        }
-                    }
-                    else {
-                        foreach my $v (keys(%{$val})) {
-                            $rcs .= sprintf("\n\t%s:%s", $v, $val->{$v});
-                        }
-                    }
-                }
-            }
-            else {
-                if ($val ne '') {
-                    if ($tag eq '@') {
-                        $rcs .= "\t" . &_string_quote($val);
-                    }
-                    else {
-                        $rcs .= "\t$val";
-                    }
-                }
-            }
-            $rcs .= ";";
+            $rcs .= $header . &_genvalue($val, $tag). ";";
             $rcs .= ($tag eq '-' ? " " : "\n");
         }
     }
     $rcs .= "\n";
 
     #   generate delta section(s)
-    sub revlist ($$) {
-        my ($self, $branchfirst) = @_;
-        my @revs = ();
-        &nextrev(\@revs, $self->{'rcs'}->{'header'}->{'head'}, $branchfirst);
-        sub nextrev ($$$) {
-            my ($revs, $rev, $branchfirst) = @_;
-            push(@{$revs}, $rev);
-            my $next     = $self->{'rcs'}->{'delta'}->{$rev}->{'next'};
-            my $branches = $self->{'rcs'}->{'delta'}->{$rev}->{'branches'};
-            if ($branchfirst) {
-                foreach my $branch (@{$branches}) {
-                    &nextrev($revs, $branch, $branchfirst);
-                }
-                if (defined($next) and $next ne '') {
-                    &nextrev($revs, $next, $branchfirst);
-                }
-            }
-            else {
-                if (defined($next) and $next ne '') {
-                    &nextrev($revs, $next, $branchfirst);
-                }
-                foreach my $branch (@{$branches}) {
-                    &nextrev($revs, $branch, $branchfirst);
-                }
-            }
-            return;
-        }
-        return @revs;
-    }
-    my @revlist = &revlist($self, 0);
+    my @revlist = &_revlist($self, 0);
     foreach my $rev (@revlist) {
         my $delta = $self->{'rcs'}->{'delta'}->{$rev};
         $rcs .= "\n";
@@ -381,7 +420,7 @@
     $rcs .= "\n\ndesc\n" . &_string_quote($desc) . "\n";
 
     #   generate deltatext section(s)
-    @revlist = &revlist($self, 1);
+    @revlist = &_revlist($self, 1);
     foreach my $rev (@revlist) {
         my $delta = $self->{'rcs'}->{'delta'}->{$rev};
         $rcs .= "\n";
@@ -391,13 +430,7 @@
         $rcs .= "text\n" . &_string_quote($delta->{'text'}) . "\n";
     }
 
-    #   write new RCS file for disk
-    my $io = new IO::File ">$file"
-        or croak "RCS file \"$file\": cannot open for writing";
-    $io->print($rcs);
-    $io->close;
-
-    return;
+    return $rcs;
 }
 
 __END__
@@ -410,7 +443,65 @@
 
 =head1 DESCRIPTION
 
-...FIXME...
+This is a Perl API for reading and writing RCS files (I<filename>C<,v>).
+It understands the syntax as documented in rcsfile(5) of GNU RCS version
+5.7. It tries hard to save RCS files in a determined internal keyword
+and revision order.
+
+=head1 METHODS
+
+=over 4
+
+=item C<my $rcs = >B<new>C< RCS>[C< $filename>]C<;>
+
+This creates a new RCS object and (for convinience reasons) optionally
+loads an RCS file via C<$rcs-E<gt>>B<load>C<($filename)> into it.
+
+=item C<$rcs-E<gt>>B<destroy>C<;>
+
+=item C<undef $rcs;>
+
+This destroys the RCS object.
+
+=item [C<my $old_path = >]C<$rcs-E<gt>>B<tool>C<(">I<tool>C<", $path);>
+
+=item C<my $path = $rcs-E<gt>>B<tool>C<(">I<tool>C<");>
+
+This sets and/or gets the path to the external command I<tool>. Used
+I<tool>s are C<rcs>, C<co> and C<diff> from GNU RCS and GNU DiffUtils.
+
+=item C<$rcs-E<gt>>B<parse>C<($filename, $rcstext);>
+
+This parses the RCS file content in C<$rcstext> and
+and stores the result in RCS object C<$rcs>.
+
+=item C<my $rcstext = $rcs-E<gt>>B<format>C<($filename);>
+
+This formats and returns the RCS file content in C<$rcs>.
+
+=item C<$rcs-E<gt>>B<load>C<($filename);>
+
+This loads the RCS file under C<$filename> into RCS object C<$rcs>.
+
+=item C<$rcs-E<gt>>B<save>C<($filename);>
+
+This saves the RCS file content from RCS object C<$rcs> under C<$filename>.
+
+=back
+
+=head1 SEE ALSO
+
+rcsfile(5).
+
+=head1 HISTORY
+
+The Perl B<RCS> module was implemented in April 2004 for use in B<OSSP
+cvsfusion> in order to support the fusion of two CVS repositories on the
+RCS file level.
+
+=head1 AUTHOR
+
+Ralf S. Engelschall E<lt>rse@engelschall.comE<gt>
 
 =cut
 

CVSTrac 2.0.1