_counter'}\n"; return $current->{'_copy'}; } my $new = {}; foreach my $key ('type', 'text') { $new->{$key} = $current->{$key} if (exists($current->{$key})); } $current->{'_copy'} = $new; if (exists($current->{'text'})) { if ($current->{'info'} and defined($current->{'info'}->{'inserted'})) { $new->{'info'} = {'inserted' => $current->{'info'}->{'inserted'}}; } return $new; } my $command_or_type = ''; if (defined($current->{'cmdname'})) { $new->{'cmdname'} = $current->{'cmdname'}; $command_or_type = '@'.$current->{'cmdname'}; } elsif ($current->{'type'}) { $command_or_type = $current->{'type'}; } #print STDERR "CTNEW $current ".debug_print_element($current)." $new\n"; foreach my $key ('args', 'contents') { if ($current->{$key}) { if (ref($current->{$key}) ne 'ARRAY') { my $command_or_type = ''; if ($new->{'cmdname'}) { $command_or_type = '@'.$new->{'cmdname'}; } elsif ($new->{'type'}) { $command_or_type = $new->{'type'}; } print STDERR "BUG: Not an array [$command_or_type] $key ". ref($current->{$key})."\n"; } $new->{$key} = []; foreach my $child (@{$current->{$key}}) { my $added = _copy_tree($child); $added->{'parent'} = $new; push @{$new->{$key}}, $added; } } } foreach my $info_type ('info', 'extra') { next if (!$current->{$info_type}); $new->{$info_type} = {}; foreach my $key (sort(keys(%{$current->{$info_type}}))) { my $value = $current->{$info_type}->{$key}; if (ref($value) eq '') { $new->{$info_type}->{$key} = $value; } elsif (ref($value) eq 'ARRAY') { # authors manual_content menus node_content if (ref($value->[0]) eq 'HASH') { #print STDERR "II ARRAY $key $value\n"; $new->{$info_type}->{$key} = []; foreach my $target (@{$value}) { push @{$new->{$info_type}->{$key}}, _copy_tree($target); } } elsif (ref($value->[0]) eq '') { # misc_args index_entry $new->{$info_type}->{$key} = [@$value]; } else { print STDERR "Unexpected array $info_type [$command_or_type]{$key}: " .ref($value->[0])."\n"; } } elsif (ref($value) eq 'HASH') { #print STDERR "II HASH $key $value\n"; if ($extra_directions{$key}) { $new->{$info_type}->{$key} = {}; foreach my $direction (sort (keys(%$value))) { my $target = $value->{$direction}; $new->{$info_type}->{$key}->{$direction} = _copy_tree($target); } } else { if (not defined($value->{'cmdname'}) and not defined($value->{'type'}) and not defined($value->{'text'}) and not defined($value->{'extra'}) and not defined($value->{'contents'}) and not defined($value->{'args'}) and scalar(keys(%$value))) { print STDERR "HASH NOT ELEMENT $info_type [$command_or_type]{$key}\n"; } $new->{$info_type}->{$key} = _copy_tree($value); } } else { print STDERR "Unexpected $info_type [$command_or_type]{$key}: " .ref($value)."\n"; } } } return $new; } sub _remove_element_copy_info($;$); sub _remove_element_copy_info($;$) { my $current = shift; my $level = shift; my $command_or_type = ''; if ($current->{'cmdname'}) { $command_or_type = '@'.$current->{'cmdname'}; } elsif ($current->{'type'}) { $command_or_type = $current->{'type'}; } $level = 0 if (!defined($level)); if (!$current->{'_copy'}) { #print STDERR "DONE $current ".debug_print_element($current)."\n"; return; } delete $current->{'_copy'}; $level++; #print STDERR (' ' x $level) # .Texinfo::Common::debug_print_element($current).": $current\n"; foreach my $key ('args', 'contents') { if ($current->{$key}) { my $index = 0; foreach my $child (@{$current->{$key}}) { _remove_element_copy_info($child, $level); $index++; } } } foreach my $info_type ('info', 'extra') { next if (!$current->{$info_type}); foreach my $key (sort(keys(%{$current->{$info_type}}))) { my $value = $current->{$info_type}->{$key}; #print STDERR (' ' x $level) . "K $info_type $key |$value\n"; if (ref($value) eq 'ARRAY') { if (ref($value->[0]) eq 'HASH') { #print STDERR (' ' x $level) . # "Array $command_or_type $info_type -> $key\n"; # authors manual_content menus node_content for (my $index = 0; $index < scalar(@{$value}); $index++) { #my $context = "$info_type [$command_or_type]{$key} [$index]"; _remove_element_copy_info($value->[$index], $level); } } } elsif (ref($value) eq 'HASH') { #print STDERR (' ' x $level) # . "Hash $command_or_type $info_type -> $key\n"; if ($extra_directions{$key}) { foreach my $direction (sort(keys(%$value))) { #my $context = "$info_type [$command_or_type]{$key} {$direction}"; _remove_element_copy_info($value->{$direction}, $level); } } else { if (not defined($value->{'cmdname'}) and not defined($value->{'type'}) and not defined($value->{'text'}) and not defined($value->{'extra'}) and not defined($value->{'contents'}) and not defined($value->{'args'}) and scalar(keys(%$value))) { print STDERR "HASH NOT ELEMENT $info_type [$command_or_type]{$key}\n"; } _remove_element_copy_info($value, $level); } } } } } sub copy_tree($) { my $current = shift; my $copy = _copy_tree($current); _remove_element_copy_info($current, $copy); return $copy; } # Never overriden by XS version sub copy_treeNonXS($) { my $current = shift; my $copy = _copy_tree($current); _remove_element_copy_info($current, $copy); return $copy; } sub copy_contents($;$) { my $element = shift; my $type = shift; my $tmp = {'contents' => $element->{'contents'}}; my $copy = copy_tree($tmp); if (defined($type)) { $copy->{'type'} = $type; } return $copy; } sub copy_contentsNonXS($;$) { my $element = shift; my $type = shift; my $tmp = {'contents' => $element->{'contents'}}; my $copy = copy_treeNonXS($tmp); if (defined($type)) { $copy->{'type'} = $type; } return $copy; }