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

So I have an INI file that looks something like this:

[Section1] Value1 Value2 Value3 [Section2] Value1 Value2 Value3

The existing modules for dealing with INI files (Config::Ini, for example) require that you have key=value pairs in your sections, and I can't seem to find one that can deal with this sort of thing. Short of using Parse::RecDescent, rolling my own (admittedly fairly trivial), or changing the INI file format, is there an easy way to deal with this sort of file?

Replies are listed 'Best First'.
Re: CPAN, why hast thou forsaken me?
by davorg (Chancellor) on Dec 20, 2000 at 21:23 UTC

    What sort of data structure do you want to store the config file in? This (untested) code builds a hash of arrays. The keys to the hash are the section names and the values are an array of the values within that section.

    my %config; my $section; open(CONF, 'config.ini') || die "Can't open conf.ini: $!\n"; while (<CONF>) { next unless /\S/; chomp; if (/\[(.+)\])/) { $section = $1; } else { push @{$config{$section}}, $_; } }

    Update: Bug corrected. Thanks to jeroenes for pointing it out.

    As for fundflow's comment. He has a good point. My solution would probably to read the first line separately and if it wasn't a 'section' line to die with an error.

    --
    <http://www.dave.org.uk>

    "Perl makes the fun jobs fun
    and the boring jobs bearable" - me

      And, indeed, this is more or less what I ended up using (mine populates a hash of hashes). I haven't discounted tye's idea of "fixing" Config::Ini, though...

      For the record:

      my $inifile='config.ini' my %words; my $section; open (INI,$inifile) || die "Couldn't open '$inifile': $!\n"; my $section='DEFAULT'; # Somewhere to store the garbage while (<INI>) { next unless /\S/; next if /^[;'#]/; # Ignore comments chomp; if (/\[(.+)\]/) { $section = $1; } else { $words{$section}{$_}=1; } } close(INI);
      I'm not really familiar with INI files, but it might make sense to initialize $section to something in case the first group is not declared. Something like
      my $section = "MAIN";
      Davorg, you may have forgotten a $. With the $:
      } else { push @{$config{$section}}, $_; }
      Jeroen
      I was dreaming of guitarnotes that would irritate an executive kind of guy (FZ)
(tye)Re: CPAN, why hast thou forsaken me?
by tye (Sage) on Dec 20, 2000 at 21:26 UTC

    Pick the best INI file parser on CPAN and patch it to support this format (notify the author(s) of your plans and work with them, of course).

            - tye (but my friends call me "Tye")
Re: CPAN, why hast thou forsaken me?
by jeroenes (Priest) on Dec 20, 2000 at 21:22 UTC
    If your whitespace is really neat, you could say:
    use SuperSplit; open (INI, "<file.ini"); $ini = supersplit( '\n', '\n\s*\n', \*INI);
    and there you have all your values in a 2D-array.

    Just today I posted Supersplit as a craft.

    Jeroen
    I was dreaming of guitarnotes that would irritate an executive kind of guy (FZ)

    Update: When I saw davorg's hashes, I wanted that too. It's really simple, just add the following lines:

    map{ $key=shift( @$_ ); ($key)=~ tr/[]//d; $hash->{$key}=[@$_]; } @$ini;
    Hope this helps
Re: CPAN, why hast thou forsaken me?
by Dominus (Parson) on Dec 21, 2000 at 05:07 UTC

      ...almost. Even their implementation looks to require a key=value pair, which is exactly what I don't have.