Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Handling different sections in config files

by pzbagel (Chaplain)
on May 15, 2003 at 03:36 UTC ( [id://258322]=perlquestion: print w/replies, xml ) Need Help??

pzbagel has asked for the wisdom of the Perl Monks concerning the following question:

I have a configuration file which is broken down into sections, each section is different and gets parsed by a different sub. All these subs are called from a general configuration parsing sub(&getconf). My problem is that the section-specific sub is the one that reads the header line for the next section and so the case statement in the parent sub never gets to read that input from the filehandle and can't figure out which sub to call to parse the next section of the file..

Simplified it looks like this:

sub getconf { while(<CONF>) { chomp; CASE: { /^\[Section1\]$/ && do{&parse_section1(\*CONF); last CASE;}; # More calls like the above }; } } sub parse_section1 { $CONF=shift; while(<$CONF>) { if (/^\[.*\]$/) { #Oops, we reached another section! #Now the next section delimiter is in $_ #Can I put it back in <$CONF>? return; } #Otherwise do something with the input } }

Now my input files look like this:

[Section1] var1=one var2=two var3=three [Section2] user1:pass1:50 user2:pass2:51

My initial idea is to somehow put $_ back into the filehandle in the parse_section1() sub before returning so that the parent sub can read it itself. I could swear I saw that described somewhere but searching several perl resources (on|off)-line didn't lead anywhere. Is this something that can be done?

If not, does anyone see a perlish solution to this problem. I know I can check a variable in getconf or something and return the line from parse_section1() to that variable, but I was wondering if there is something a little less mundane out there.

Thanks in advance.

Peter

P.S. please excuse any minor syntax errors in my code, I wanted to trim it down to just the essentials to describe the problem I have.

Replies are listed 'Best First'.
Re: Handling different sections in config files
by BrowserUk (Patriarch) on May 15, 2003 at 04:11 UTC

    This is the classic parser look-ahead problem that gave rise to the C ungetch() function.

    In this case, you would be better of using perl's nouce to read your file in paragraph mode (see perlvar:$/). Basically, if you set $/='', perl will read a paragraph (defined as a number of lines terminated by \n\n). You can then pass the entire section in to the appropriate sub, have it split it into lines and do it thing from there. Eg.

    #! perl -slw use strict; sub section1{ # Split into lines my @lines = split'\n', $_[0]; print 'Section 1 got:', $_ for @lines; } sub section2{ print 'Section2', @_; } # placeholder code. sub getconf{ local $/= ''; # Set paragraph mode on *locally* while( <DATA> ) { section1( $_ ), next if /^\[Section1]/; section2( $_ ), next if /^\[Section2]/; } } getconf(); __DATA__ [Section1] var1=one var2=two var3=three [Section2] user1:pass1:50 user2:pass2:51

    Output

    Section 1 got:[Section1] Section 1 got:var1=one Section 1 got:var2=two Section 1 got:var3=three Section2[Section2] user1:pass1:50 user2:pass2:51

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
Re: Handling different sections in config files
by Skeeve (Parson) on May 15, 2003 at 06:56 UTC
    As BrowserUK stated, this is a classical lookahead. So why not treat it as such?
    my($lookahead); nextline(); while (hasline()) { if ($lookahead=~ /^\s*$/) { nextline(); next; } die "fileformat error: $lookahead" if $lookahead!~ s/^\[([^]]+ +)\].*/$1/; SWITCH: for ($lookahead){ /^Section1$/ && do { nextline(); section1(); last SWITCH; }; /^Section2$/ && do { nextline(); section2(); last SWITCH; }; do { die "unhandled section: $_" }; } } sub section1 { while (hasline()) { return if $lookahead=~ /^\[/; print "S1: ",$lookahead; nextline(); } } sub section2 { while (hasline()) { return if $lookahead=~ /^\[/; print "S2: ",$lookahead; nextline(); } } sub nextline { $lookahead=<DATA>; } sub hasline { return defined $lookahead; } __END__ [Section1] var1=one var2=two var3=three [Section2] user1:pass1:50 user2:pass2:51
Re: Handling different sections in config files
by CukiMnstr (Deacon) on May 15, 2003 at 04:38 UTC
    I know this is not exactly what you are asking, but since BrowserUK answered your question, I thought maybe you can give AppConfig a try. I use it for parsing/handling/writing config files in the ".ini" format, and it works great.

    hope this helps,

Re: Handling different sections in config files
by hacker (Priest) on May 15, 2003 at 14:04 UTC
Re: Handling different sections in config files
by Nitrox (Chaplain) on May 15, 2003 at 12:26 UTC
    Another solution would be to "standardize" the config file so that each section followed the same format.
    [Section2] user1=pass1:50 user2=pass2:51
    Then simply use Config::IniFiles to tie the file to a hash:

    tie my %ini, 'Config::IniFiles', ( -file => "MyConfig.ini" );
    Then to retrieve the data from 'Section2':
    foreach $user (keys %{$ini{'Section2'}}) { ($pass, $uid) = split /:/, $ini{'accounts'}{$user}; #do something with the values here }
    -Nitrox
Re: Handling different sections in config files
by pzbagel (Chaplain) on May 15, 2003 at 06:58 UTC

    Thank you both for your answers. ++ all around! I will give that code a try BrowserUk. Now I think I will take a shot answering my own question. It came to me as I was re-watching the Matrix before I see Reloaded tomorrow. Go figure, as soon as you take your mind off of the code you get the answer.

    If I add an end-of-section tag to each section of the config file, my subs could return on the end-of-section tag and the opening tag for the next section will be queued up and ready to get read.

    Maybe I should just convert the config to XML:D

    Thanks again everyone.

    Good night!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (2)
As of 2024-07-21 22:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.