[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]