Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

hash reference

by hotshot (Prior)
on Feb 06, 2002 at 07:55 UTC ( #143570=perlquestion: print w/ replies, xml ) Need Help??
hotshot has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys !

A little problem. I have a parser (not mine) for a configuration file (smb.conf if someone knows). this file as from the format:
[name1] key1 = value1 key2 = value2 ... [name2] key1 = value1 key2 = value2 ... # and so on
The problem is when I have something like this:
[name1] key1 = value1 key2 = value2 ... [name2] [name3] key1 = value1 key2 = value2 ...
as you can see name2 has no values, this thing is ok (default values are taken), but the parser I have doesn't return it, here is it's code:
sub smbconf_parse { my $smbconf = shift; my %smbconf; my $share = ''; if (! open(SMB, $smbconf)) { warn "Couldn't read smbconf file $smbconf\n"; warn "$!\n"; return 0; } while (<SMB>) { s/^\s+//g; s/\s+$//g; next if (/^$/); next if (/^\#/); next if (/^\;/); if (/^\[(.*)\]/) { $share = $1; ####### } else { my ($key, $value) = (/^(.*) ?\= (\S.*)/); $key =~ s/\s+$//; if ($value =~ /^\"(.*)\"$/) { $smbconf{$share}{$key} = $1; } elsif ($value =~ /\,/) { my @value = split(/\,/, $value); $smbconf{$share}{$key} = [ @value ]; } else { $smbconf{$share}{$key} = $value; } } } close SMB; return \%smbconf; }
I can see the problem, no hash entry is opened if it didn't find any key=value pairs, so I tried adding something like
$smbconf{$share} = ''; # just to open the entry
right after the line with $share = $1;, but that seemed to mess the whole parsing.

anyone has an idea ?

Hotshot

Comment on hash reference
Select or Download Code
Re: hash reference
by Zaxo (Archbishop) on Feb 06, 2002 at 08:14 UTC

    The smb.conf file is in a standard format popular with MS Windows and applications.for it. It will be no surprise that there is Config::IniFiles at CPAN to help parse them.

    One More Really Round Wheel.

    Update: That was too short. Here's a usage that gets you what you want:

    use Config::IniFiles; my $smb = new Config::IniFiles( -file => '/etc/samba/smb.conf'); print join $/, $smb->Sections; # prints the section names
    There are provisions for rewriting the file, but you'll have to take care of locking yourself. There is also a tied interface, but I'd be leary of that without built-in file locks.

    After Compline,
    Zaxo

Re: hash reference
by shotgunefx (Parson) on Feb 06, 2002 at 08:27 UTC
    I agree with Zaxo, but to answer your question, you could change this
    $share = $1; ####### to $share = $1; ####### $smbconf{$share} = ();


    -Lee

    "To be civilized is to deny one's nature."
Re: hash reference
by CharlesClarkson (Curate) on Feb 06, 2002 at 08:29 UTC

    Place this line before the $share = $1; line.

    $smbconf{$share} = undef unless exists $smbconf{$share} || $share eq '';


    HTH,
    Charles K. Clarkson
    Clarkson Energy Homes, Inc.
Re: hash reference
by snowcrash (Friar) on Feb 06, 2002 at 08:35 UTC
    in addition to what Zaxo replied:
    $smbconf{$share} seems to expect a reference to a hash, like your node's title states. you set it to a scalar, i.e. "", which seems to mess up somewhere else later. i guess it would work if you assign an empty hashref, $smbconf{$share} = {} (or some hashref containing default values?).

    hth,
    snowcrash
Re (tilly) 1: hash reference
by tilly (Archbishop) on Feb 06, 2002 at 08:35 UTC
    You need that to be initialized as a hash reference, else you are going to be doing unwanted symbolic referencing which you don't want. (Using strict.pm would have given you a more informative error message.)

    A better way to do that initialization is:

    $smbconf{$share} ||= {};
    (I use ||= in case you want a given section to be able to be declared, redeclared, and added to.)
Re: hash reference
by strat (Canon) on Feb 06, 2002 at 14:32 UTC
    I'd parse it in the following way... (haven't tested)
    sub ReadIniFile { my ($iniFile) = @_; my %config = (); local ($/) = undef; unless (open (INI, $iniFile)){ print (LOG "Error: couldn't read from INI $iniFile: $!\n"); die ("Error: couldn't read from INI $iniFile: $!\n"); } my $ini = <INI>; close (INI); my (@mainpoints) = ($ini =~ /(\[\w+?\])\n/g); # extract [.....] my ($x, @contents) = split(/\[\w+?\]/, $ini); @config{@mainpoints} = @contents; foreach (keys %config){ my %subHash = (); my @values = split(/\n+/, $config{$_}); foreach (@values){ my ($key, $val) = split(/\s*\:\s*/, $_, 2); next unless defined $key; next if $key eq ''; next if $key =~ /^\s*\#/; $subHash{lc($key)} = $val; } $config{$_} = \%subHash; } return (\%config); } # ReadIniFile

    Best regards,
    perl -e "$_=*F=>y~\*martinF~stronat~=>s~[^\w]~~g=>chop,print"

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://143570]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (18)
As of 2015-07-02 10:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (33 votes), past polls