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/


Reply via email to