ElectricWeasel
ElectricWeasel

Reputation: 107

Can anyone tell me why my reference isn't getting returned?

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

Answers (2)

ikegami
ikegami

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

ysth
ysth

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

Related Questions