A good data structure to store INI files.

M

Marc Lucksch

Brad said:
Whether or not this will serve your needs, I think one fairly
straight-forward data structure that can faithfully represent
typical ini file data is pairs of pairs. A "pairs" structure
is an array of single-key hashes as defined in
http://yaml.org/type/pairs.html

I didn't know about that one, this is an completely object based model.
(Or function based). Had I known about this one beforehand, I probably
would have just used it.

But what I want to have now, is more a perlish way to represent this
kind of data. While there can be multiple keys in one section, it is
quite rare. (The only once I know from the top of my head are fuse= and
surface_hit_effects=). There are also .ini files with sections out there
which have unique names. The current access I want is more perlish and easy.

How would you for example set the second fuse of the third ship
(section?) An operation likely to occour...

my @ships=$ini->get_values( "Ships" );
my $third=$ships[2];
my @fuses=$third->get_pos("fuse");
$third->set_pos("fuse",["fusename",0,10],$fuses[1]);


OR
($ini->get_pos( "Ship"
))[2]->set_pos("fuse",["fusename",0,10],(($ini->get_pos( "Ship"
))[2]->get_pos("fuse"))[1]

I want it more like:

$ini->{Ship}->[2]->{"fuse"}->[1]=["fusename",0,10];

And for the nickname of the only pilot:
$ini->{Pilot}->{"nickname"}->[0]="li_pilot_elite"; #->[0] is needed
# otherwise it would be ambigious, add another nickname or replace the
# first/all.

$ini->{Pilot}->[0]->{"nickname"}->[0]->[0]="li_pilot_elite";

This makes it easier to use and that should be (IMHO) a big focus in
development, even if I have to rack my brain over this and/or annoy you
guys with posts about it. (Those actually helped me a lot, thanks to all
again)

__POD__

Short term and style definition: (ini-file, Value can be escaped)

[Section]
Key = Value [, Value]; Comment

[;SkippedSection]
In your case the typical ini data is enhanced by assuming that
comma separated values should be loaded as arrays.
Yes, and thanks again for the nice module hint, maybe you can add a
solution to my critism (Setting a value for specific key) to your nice
module

Marc "Maluku" Lucksch
 
M

Marc Lucksch

Ben said:
I can't trigger this. If I've understood the rather bad English
correctly, the last set of tests (changing a not-array into an array and
expecting overload to immediately work) should, but clearly not. If you
can give an example of this failure, I'd be interested to see it.

Ben
First up, thanks a lot for this, I think I will make it the way you
outlined it here. (But not today, tired). So I won't need C::R (which is
in fact kinda scary, but quite easy)
Second, I thought it was my fault for not understanding it, good thing
I'm not the only one (or is it a good thing?)

I'm currently on autovification

my $ini=Data::INI->new();
$ini{Ship}{nickname}="li_elite";

and this cruft:

push @{$ini{Ship}},$data;
$#{$ini}=1;
%{$ini}=();
$#{$ini->{Ship}}=10;
$ini->{Copy}=$ini->{Ship};

And so on. (above already works)

Marc "Maluku" Lucksch

'You shouldn't mistake spam for social contact'
 
B

Brad Baxter

Marc said:
How would you for example set the second fuse of the third ship
(section?) An operation likely to occour...

my @ships=$ini->get_values( "Ships" );
my $third=$ships[2];
my @fuses=$third->get_pos("fuse");
$third->set_pos("fuse",["fusename",0,10],$fuses[1]);

my @ships=$ini->get_values( "Ship" );
my $third=$ships[2];
my @fuses=$third->get_pos("fuse");
$third->set("fuse",["fusename",0,10],$fuses[1]);

Yes, that's about it. But I'm not suggesting this is
the best approach for you. My point was just that ini
file data can be faithfully represented this way.

In your case, I think you need to separate the general
case of reading/writing ini files from your specific
needs. That is, read the configuration file into
whatever structure works best for your program, whether
or not that structure is general enough to work for
any ini file. Then if you need to write the data
back out, just make a routine for that.
 
B

Brad Baxter

Marc said:
I want it more like:

$ini->{Ship}->[2]->{"fuse"}->[1]=["fusename",0,10];

I think this would accomplish that. I doubt you really
care about retaining the order of the keys.

Comments are left as an exercise ...

Brad


#!/usr/local/bin/perl

use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Terse = 1;
$Data::Dumper::Indent = 1;

my %ini;
my $current;

while( <DATA> ) {
chomp;
if( /^\[(\w+)]/ ) {
my $section = $1;
$current = {};
push @{$ini{$section}}, $current;
}
elsif( /^(\w+)\s*=\s*(.*)/ ) {
my( $key, $val ) = ( $1, $2 );
$val = [ split /\s*,\s*/, $val ] if $val =~ /,/;
push @{$current->{$key}}, $val;
}
}

$ini{Ship}[2]{"fuse"}[1]=["fusename",0,10];

# view internal structure
print Dumper \%ini;

# rewrite the ini file data
for my $section ( keys %ini ) {
for my $href ( @{$ini{$section}} ) {
print "[$section]\n";
for my $key ( keys %$href ) {
for my $val ( @{$href->{ $key }} ) {
$val = join( ', ', @$val ) if ref $val eq 'ARRAY';
print "$key = $val\n";
}
}
print "\n";
}
}

__DATA__

[Ship]
ids_name = 237033
ids_info = 66567
ids_info1 = 66567
ship_class = 1
nickname = li_elite
LODranges = 0, 75, 150, 1300
fuse = intermed_damage_smallship01, 0.000000, 400
fuse = intermed_damage_smallship02, 0.000000, 200
;#Well its a lot more in one section, but this proves the point.

[Ship]
ids_name = 237033
ids_info = 66567
ship_class = 1
nickname = li_elite2
LODranges = 0, 175, 150, 1300
fuse = intermed_damage_smallship01, 0.000000, 400
fuse = intermed_damage_smallship02, 0.000000, 200
fuse = intermed_damage_smallship03, 0.000000, 133
;.... (about 250kb of this)

[Ship]
ids_name = 237033
ids_info = 66567
ship_class = 1
nickname = li_elite2
LODranges = 0, 175, 150, 1300
fuse = intermed_damage_smallship01, 0.000000, 400
fuse = intermed_damage_smallship02, 0.000000, 200
fuse = intermed_damage_smallship03, 0.000000, 133
;.... (about 250kb of this)
 
M

Marc Lucksch

Brad said:
Marc said:
I want it more like:

$ini->{Ship}->[2]->{"fuse"}->[1]=["fusename",0,10];

I think this would accomplish that. I doubt you really
care about retaining the order of the keys.
I do care about that because the fuses for example have to be in order,
otherwise you get a critical from the game.

Currently I'm writing on a datastructure to represent all .ini files I
know of and write them out again unchanged (except for whitespace).

The whole point is it being easy to use (for now, speed comes later)

So if there is only one fuse and one ship and fuse in only one value:

print $ini->{Ship}->{fuse}.

Or if there are mulitple fuses:
print $ini->{Ship}->{fuse}; #Gets the first
print $ini->{Ship}->{fuse}->[1]; #Gets the second.

But that code shouldn't just break on two Ship's or 500 Ship's, so
without an following arrayref, it just gets the first.

This even works this way:

$ini->[0] #First section, returns {key,value}
pop @$ini; #remove the last entry, whatever key also returns {key,value}

pop @{$ini->{Ship}} # Remove the last ship and fetch it.

my $value=Data::INI->new();
push @{$ini->{ship}},$value; #Yes 'ship' is written small on purpose.
pop @{$ini->{Ship}} ( =$value ) #yes 'Ship' is ucfirst on purpose.
push @{$ini->{ship}},$value;
pop @$ini; ( ={ship=>$value} )

Same of course for keys of those sections.

Because there are in my opionion two ways to look at this data, as a
hash with keys (multiple or not) unordered or as an array of hashes with
one entry which are in the right order. Both have pros and cons, that's
why I think I want both of them.
In your case, I think you need to separate the general
case of reading/writing ini files from your specific
needs. That is, read the configuration file into
whatever structure works best for your program, whether
or not that structure is general enough to work for
any ini file. Then if you need to write the data
back out, just make a routine for that.

Yes. Especially since there are two parsers (.ini and BINI) and to
writers (.ini and BINI).
But one thing: I don't want an structure for my program, I want the
best/easiest structure for someone using my lib.

Marc "Maluku" Lucksch

__DATA__

It looks somewhat like this: (Parser will be written later)

#Excerpt of 0_basic.t

use Data::INI;

my $ini=Data::INI->new();
$ini->{KEY}="Foo";
is($ini->{KeY}->[0]->[0],"Foo","Getting full key KEY");
is($ini->{KEy}->[0],"Foo","Getting half key KEY");
ok(exists $ini->{KEY},"KEY exists");
is($ini->{KEY},"Foo","Getting short key KEY");
ok(exists $ini->[0],"index 0 exists");
is($ini->[0]->[1],"Foo","Getting array index 0");

$ini->{KEY}->[0]="Bar";
#Same tests except Foo is now bar
#...

$ini->{Test}->[0]->[0]="foobar";
#tests to chech for foobar in Test

#$ini->{halfadd}=["foobar"];
#Same tests for halfadd

#Autovivification has to work as well:
my $ini=Data::INI->new();
$ini->{Foo}->[0]->{nickname}="test";
push @{$ini->{Bar}->{nickname}->[0]},"test2";
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top