I'm having a bit of trouble writing a trace array for a structure traversal function.
Before someone points out Data::Walker and the like, here is my limitation: this is for a script to generate iptables / ipset save files - it needs to run on machines with perl 5.10+ without needing anything else (including MakeMaker - nothing - just runs out of the box). So, if a module isn't in core, I can't really use it. Nevermind the function name 'flatten' - I just want to get $path to work correctly. Thanks #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; my $deep = { 'foo' => [qw/ ugh umm arr /], 'bar' => [qw/ aaa bbb ccc /], 'baz' => [ 'fi' => [qw/ one two three /], 'fo' => [qw/ four five six /], 'fum' => [qw/ seven eight nine /], ], }; my ($new) = into_me($deep, undef, 'flatten_els'); print Dumper($new); sub flatten_els { my ($var, @etc) = @_; my ($path, $type) = @etc; print "path [" . join('] [', @$path) . "]\n"; return $var, @etc unless ($type =~ /^H /); $var = join(' ', values %$var); return $var, @etc; } # Traverse a variable with callbacks sub into_me { my ($vals, $kfunc, $vfunc, @etc) = @_; no strict 'refs'; # This should be private - you probably shouldn't call into_me with a path my $path; if (scalar(@etc) >= 1 and ref($etc[-1]) eq 'ARRAY' and $etc[-1]->[0] eq 'BASE') { $path = pop @etc; } else { push @$path, 'BASE'; } my $rtype = (ref(\$vals) eq 'SCALAR' ? 'SCALAR' : ref($vals)); my $ret; if ($rtype eq 'ARRAY') { for my $num (0 .. $#$vals) { next unless (defined($vals->[$num])); my $val = $vals->[$num]; my ($anum, $aval); ($anum, @etc) = $kfunc->($num, @etc, 'EL') if (defined($kfunc)); $anum //= $num; push @$path, "A $anum"; push @etc, $path; ($aval, @etc) = $vfunc->($val, @etc, 'VAL') if (defined($vfunc)); $aval //= $val; ($ret->[$anum], @etc) = into_me($aval, $kfunc, $vfunc, @etc); pop @$path; } } elsif ($rtype eq 'HASH') { foreach my $key (keys %$vals) { next unless (defined($vals->{$key})); my $val = $vals->{$key}; my ($akey, $aval); ($akey, @etc) = $kfunc->($key, @etc, 'KEY') if (defined($kfunc)); $akey //= $key; push @$path, "H $akey"; push @etc, $path; ($aval, @etc) = $vfunc->($val, @etc, 'VAL') if (defined($vfunc)); $aval //= $val; ($ret->{$akey}, @etc) = into_me($aval, $kfunc, $vfunc, @etc); pop @$path; } } elsif ($rtype eq 'SCALAR') { push @$path, "S $vals"; push @etc, $path; ($ret, @etc) = $vfunc->($vals, @etc); pop @$path; } else { $ret = $vals; } push @etc, $path; use strict 'refs'; return $ret, @etc; } -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/