[PREV - WARTS]    [TOP]
NEXT

GETTING_ONE_FRAME


This code isn't just warty, it's bit
rotted...  I don't try to do this any           (It doesn't even work
more so it hasn't been kept up-to-date.         over quite the same data
                                                structure as the last
  Take is as an example of the                  slide.)
  kind of gyrations you need to
  do if you want to map the
  change data from different
  substitution passes to one        You know you're in trouble
  coordinate system.                when the docs are twice the
                                    length of the code.

=item revise_locations

Example usage (note, revises structure in-place):

  revise_locations( $change_metadata );

Where the $change_metatdata is an aref of hrefs,
with keys such as "beg", "eng", "delta", "orig",
and so on (See L<do_finds_and_reps>).

This compensates for a problem in the change history recorded by
L<do_finds_and_reps>: Later passes with another substitution
command can move around the modified strings from previous
passes, so a revise_locations routine is needed to do some numerical
adjustment, re-interpreting previous passes in the light of later ones.


An example of some change metadata:

     beg     end   delta  orig
    ----    ----   -----  -------
       3      9     -4    'alpha'
      39     47     10    'ralpha'
     111    130      0    'XXX'
     320    332    -33    'blvd'

      12     23      6    'widget'
      33     80      6    'wadget'
      453   532      6    'wandat'

Given this data, we can see that the first pass needs to be
shifted forward by a delta of 6, acting at the end-point of each
changed region.

So any locations after 23 need to have 6 added to them (and
locations after 80 need another 6 and ones after 532 -- if there
were any -- would need another 6).

=cut

# So: we crunch through the data in reverse order,
# and record accumulated deltas, keyed by the location to apply
# them, i.e. to revise the beg  and end points.
# The size of earlier deltas is untouched, but the position
# the earlier deltas act upon is the revised position.
# One more time: beg and end are the endpoints of the *modified* region,
# after the change.

# Remember the context where these numbers were recorded:
#    s{}{pos()}eg
## pos() uses a fixed numbering, despite any length changes from the s///g,
## so when a "pass" is completed, we need to revise *that pass*
## and all of the later passes in the data (which are the already
## processed ones, because we're going through 'em in reverse).

sub revise_locations {
  my $data = shift;
  my %delta;
  my $last_pass = -1; # look ma, I'm defined.
  # begin with the last row of data, and count down
  for ( my $i = $#{ $data }; $i >= 0; $i-- ) {
    my $row = $data->[ $i ];
    my $pass = $row->{ pass };

    # deltas effect any locations after the point where they act
    foreach my $spot ( sort {$a <=> $b} keys %delta) {
      if ( $row->{ beg } >= $spot ) { # TODO >= ok?
        $row->{ beg } += $delta{ $spot };
      }
      if ( $row->{ end } >= $spot  ) { # TODO >= ok?
        $row->{ end } += $delta{ $spot };
      }
    } # end foreach spot

    # when the pass number changes, revise %delta using
    # all records already processed.
    # Each record's delta acts at the end of the modified region.
    if ($pass != $last_pass) {
      for ( my $j = $#{ $data }; $j >= $i; $j-- ) {
        my $row = $data->[ $j ];
        no warnings 'uninitialized';
        my $delta = $row->{ delta };

        my $old_end = $row->{ end } - $delta;
        $delta{ $old_end } += $delta;
#        $delta{ $old_end } -= $delta;

      }    # end for $j, for each row *later* than the $i row
    }
    $last_pass = $pass;
  }                             # end for $i, for each row
}
-------- [NEXT - SUBTLE_PROBLEM]