Reputation: 107
I'm writing a parser for the Netscreen firewall configuration files to create some scripts that do the same things as the scripts I have using PIX::Walker. I ran into a problem where the reference I create in the parseconfig sub looks fine in Dump 1, but is empty in Dump 2. I'm working on a cleaner approach right now, but I was wondering if anyone could tell me why Dump 2 shows that reference to be empty.
#!/usr/bin/perl
use strict;
use Getopt::Std;
use Data::Dumper;
my $usage = "Usage: isg-ppsrpt.pl -d config directory
-d is required
use portproto-rpt.pl -h to get this help\n\n";
my @firewalls = ("foo","bar","baz");
my %opts;
my %configs;
getopts('hd:', \%opts);
if ($opts{h}) { die $usage };
# Parser definition
my %parse;
$parse{service} = sub {
my $ref = shift;
my @elements = split(/\s+/, shift);
@elements[2] =~ /\"(\S+)\"/;
my $name = $1;
my $out;
if ($elements[4] =~ /tcp|udp/) {
$out->{proto} = $elements[4];
$out->{port} = $elements[-1];
}
if ($out) {push @{$ref->{service}{$name}}, $out};
};
foreach (@firewalls) {
my $fw = sprintf "%s\\%s.config",$opts{d},$_;
if (-e $fw) {
$configs{$_} = parseconfig($fw);
} else {
die "Cannot find config file for $_ in \n";
}
}
sub parseconfig {
my $configref;
my $configfile = shift;
open (CONFIG,"$configfile");
foreach my $line (<CONFIG>) {
chomp $line;
my $type = (split(/\s+/,$line))[1];
if ($parse{$type}) {
$parse{$type}($configref,$line);
}
print Dumper(%$configref); # Dump 1
}
close(CONFIG);
print Dumper(%$configref); # Dump 2
return($configref);
}
Upvotes: 1
Views: 125
Reputation: 386331
Through autovivification, you assign a hash reference to $ref
. However, that reference is never assigned fo $configref
in the caller.
Changing $ref
does not change $configref
, so $configref
remains undefined. Changing $_[0]
would change $configref
since $_[0]
is aliased to $configref
.
You must find a way of placing the same reference in $ref
and $configref
.
Solution 1:
$parse{service} = sub {
my $ref = $_[0] ||= {};
...
};
my $configref;
...
$parse{$type}($configref, $line);
Solution 2:
$parse{service} = sub {
my $ref = $_[0];
...
};
my %config;
...
$parse{$type}(\%config, $line);
Solution 3:
$parse{service} = sub {
my %config;
...
return %config;
};
my %config;
...
%config = ( %config, $parse{$type}($line) );
Upvotes: 1
Reputation: 98398
sub parseconfig {
my $configref;
....
if ($parse{$type}) {
$parse{$type}($configref,$line);
I don't know that this explains your problem, but it looks like you are relying on the called function to populate $configref. This will only work if it directly uses $_[0]
(an alias to the passed parameter $configref
); if it assigns it to a lexical and uses that, $configref
itself will be left undefined. Initializing $configref
to {}
in parseconfig fixes this.
Upvotes: 2