Schrift
[thread]8968[/thread]

Lib für ini-Datei-Verarbeitung: zur Verwendung / Weiterentwicklung



<< >> 7 Einträge, 1 Seite
Nordlicht
 2007-05-05 17:22
#76465 #76465
User since
2005-10-16
182 Artikel
BenutzerIn
[default_avatar]
Hi Leute,

ich wollte euch mal meine Mini-Bibliothek vorstellen, die ich zum Verwalten von Konfigurationsdateien (*.ini) verwende. Ich war mit den Möglichkeiten der Module, die ich gefunden hab nie zufrieden, deswegen hab ich mir was eigenes gebastelt, was meinem Geschmack entspricht.
Die Konfigurationsdatei sollte wie folgt aufgebaut sein:

Code: (dl )
1
2
3
4
5
6
7
8
[topic]
key=value
key=value
...
[topic]
key=value
key=value
...


Ich finde dieses Format sehr praktisch, deswegen benutze ich kaum noch was anderes. Man sucht nach einem Topic und ließt dann die key-value-Paare aus. Dadurch kann man den gleichen key auch mehrmals in verschiedenen Topics verwenden. Ich bin leider ziemlich schlecht im Dokumentieren, aber ich hoffe mal der Code erklärt sich selbst... :)


Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#/usr/bin/perl

use strict;
use warnings;

return 1;

sub read_ini
{
# reads an ini-file
# returns a hash containing the key-value pairs

my @content;
my %lines;
my $file=shift; # filename
my $name=shift; # name of target topic

open(IN,"<$file") or die "$!";
@content=<IN>;
close(IN);

my $i=0;
my $n=0;
for (@content)
{
$i++ if /\[.*?\]/io;
$n=$i if /\[$name\]/io;
$lines{"$1"}="$2" if /^(.*?)\=(.*)$/i and $i==$n;
last if $i>$n;
}
return %lines;
}


sub change_ini
{
# changes key-value pairs
# returns true when done

my @content;
my %lines;
my $file=shift; # filename
my $name=shift; # name of target topic
my $key=shift; # target key
my $value=shift; # new value

open(IN,"<$file") or die "$!";
@content=<IN>;
close(IN);

my $i=0;
my $n=0;
for (@content)
{
$i++ if /\[.*?\]/io;

$n=$i if /\[$name\]/io;

s/(^$key\=)(.*)$/$1$value/i, last if /(^$key\=)(.*)$/i and $i==$n;
}

open(IN,">$file") or die "$!";
for(@content)
{
print IN $_;
}
close(IN);
return 1;
}

sub ins_item_ini
{
# inserts a new key-value pair
# returns true when done
my @content;
my $file=shift; # filename
my $name=shift; # name of topic
my $new_kv=shift; # something like admin=123456

open(IN,"<$file") or die "$!";
@content=<IN>;
close(IN);

my $i=0;
my $n=0;
open(IN,">$file") or die "$!";
for(@content)
{
$i++ if /\[.*?\]/io;
$n=$i if /\[$name\]/io and $n ne '-';
if($n eq $i and $n ne '-')
{
print IN "$new_kv\n";
print IN $_;
$n='-';
}
else
{
print IN $_;
}
}
close(IN);
return 1;
}


Vorschläge für Optimierungen und Weiterentwicklungen sind erwünscht! Die Kritik am Programmierstil könnt ihr euch sparen, ich weiß, dass das Ding noch lange nicht optimal ist.
Ronnie
 2007-05-05 17:44
#76466 #76466
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Hallo Nordlicht,

für die Lesbarkeit, solltest du es aber durch perltidy jagen: perltidy -i=4 - das hilft schon viel.

Gruß,
Ronnie
renee
 2007-05-05 18:00
#76467 #76467
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Ich finde es ja ganz ok, wenn man sich hinsetzt und selbst was programmiert, aber was hat Dir an CPAN:Config::IniFiles nicht gefallen?

Ich hoffe, es ist ok, wenn ich ein paar Sachen anmerke...

*) Es wäre ganz schön, wenn Du auch ein Beispielprogramm mit Ausgaben posten würdest.

*) Wenn Du es mal weiterentwickeln willst, wäre es ja vielleicht zu überlegen, nicht immer wieder die Datei einzulesen, sondern den Inhalt zentral zu speichern

Es gibt noch ein paar Kleinigkeiten, aber ich finde es toll, dass hier jemand sein Skript vorstellt, das eine Hilfe für denjenigen ist!
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
Nordlicht
 2007-05-05 20:58
#76468 #76468
User since
2005-10-16
182 Artikel
BenutzerIn
[default_avatar]
Ich muss mich entschuldigen, offenbar ist der oben gepostete code fehlerhaft. Ich korrigiere das so schnell wie möglich.\n\n

<!--EDIT|Nordlicht|1178388854-->
Nordlicht
 2007-05-05 22:37
#76469 #76469
User since
2005-10-16
182 Artikel
BenutzerIn
[default_avatar]
strange... ich hab diese Funktionen doch schon so oft verwendet, was hab ich denn da bloß rumgebastelt, dass jetzt gar nix mehr geht...

tut mir echt leid, aber ich war eigentlich der Meinung die Datei wäre original und würde funktionieren. Jetzt geht gar nix mehr. Ich wollte gerade ein Beispielprogramm schreiben, da ging alles drunter und drüber.
Nordlicht
 2007-05-05 23:45
#76470 #76470
User since
2005-10-16
182 Artikel
BenutzerIn
[default_avatar]
Ich hab die richtige, funktionierende Version gefunden. Das kommt davon, wenn man keine Ordnung hält...

Also, dieser Code tut, was er soll.

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/C:/Perl/bin/perl.exe

use strict;
use warnings;

return 1;

sub read_ini
{
my @content;
my %lines;
my $file=shift;
my $name=shift;

open(IN,"<$file") or die "$!";
undef $_;
@content=<IN>;
close(IN);

my $i=0;
my $n=0;
for (@content)
{
$i++ if /\[.*?\]/i;
$n=$i if /\[$name\]/i;
$lines{"$1"}="$2" if /^(.*?)\=(.*)$/i and $i==$n;
}
return %lines;
}


sub change_ini
{
my @content;
my %lines;
my $file=shift;
my $name=shift;
my $key=shift;
my $value=shift;

open(IN,"<$file") or die "$!";
@content=<IN>;
close(IN);

my $i=0;
my $n=0;
for (@content)
{
$i++ if /\[.*?\]/io;
$n=$i if /\[$name\]/io;
s/(^$key\=)(.*)$/$1$value/i, last if /(^$key\=)(.*)$/i and $i==$n;
}

open(IN,">$file") or die "$!";
for(@content)
{
print IN $_;
}
close(IN);
}


sub insert_item
{
my @content;
my $file=shift;
my $name=shift;
my $new_kv=shift;

open(IN,"<$file") or die "$!";
@content=<IN>;
close(IN);

my $i=0;
my $n=0;
open(IN,">$file") or die "$!";
for(@content)
{
$i++ if /\[.*?\]/io;
$n=$i if /\[$name\]/io and $n ne '-';
if($n eq $i and $n ne '-')
{
print IN $_;
print IN "$new_kv\n";
$n='-';
}
else
{
print IN $_;
}
}
close(IN);
}

sub insert_topic
{
my $file=shift;
my $name=shift;

open(IN,">>$file") or die "$!";
print IN "[$name]\n";
close(IN);
}


und hier ein Beispiel:

in der Konfigurationsdatei befinden sich z.B. Serverkonfigurationsdaten (hier ausgedachte Werte, so wie sie in der xitami.aut des Xitami-Servers stehen könnten)
Code: (dl )
1
2
3
4
5
6
7
8
9
10
[Private]
Nordlicht=1234
[Documention]
all=*
webmask=local
[Stats]
Admin=QzeCat96
Root=PakYupTon
http-put=1
http-delete=1


Wir können nun folgende Dinge tun:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/C:/Perl/bin/perl.exe

use strict;
use warnings;
require 'ini.pl';

# Ein neues Wertepaar einfügen
insert_item('director.ini','Private','user2=4567');

# ein Wertepaar verändern
change_ini('director.ini','Private','Nordlicht','abcd');

# ein neues topic einfügen
insert_topic('director.ini','Admin');

# Konfiguration in einem topic auslesen
my %config = read_ini('director.ini','Stats');
while(my ($k,$v) = each(%config))
{
#und etwas damit tun...
print "$k - $v\n";
}


Dannach sollte die Datei so aussehen:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
[Private]
user2=4567
Nordlicht=abcd
[Documention]
all=*
webmask=local
[Stats]
Admin=QzeCat96
Root=PakYupTon
http-put=1
http-delete=1
[Admin]


Leider unterstützt bisher keine der Funktionen die Übergabe von Arrays als Parameterliste, man kann also keinen Array mit einzufügenden / auszulesenden Werten verwenden. Bis es soweit ist, muss man sich mit Schleifen behelfen, ungefähr so:

Code: (dl )
1
2
3
4
foreach(@pairs)
{
insert_item('director.ini','Private',$_);
}

Ich hab auch noch nicht getestet, wie sich das ganze mit Kommentaren verträgt, ich glaube gar nicht :)
Tja, soweit erstmal.\n\n

<!--EDIT|Nordlicht|1178394627-->
Ronnie
 2007-05-18 02:44
#76471 #76471
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Da ich gerade den YAPC::Asia Beitrag von mjd auf Google-Video gesehen habe und ein wenig im HOP gelesen habe, hier eine kleine, rudimentäre Spielerei zum Thema:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

package Token;
use Moose;

has 'type' => ( is => 'rw' );
has 'value' => ( is => 'rw' );

package Tokenizer;
use Moose;

has 'token' => (
isa => 'ArrayRef',
default => sub { [] },
is => 'rw',
);

sub tokenize {
my $self = shift;
my $stream = shift || '';

TOKEN: {
$self->add_token('SECTION', $1) if $stream =~ /\G\[(\w+)\]/gcx;
$self->add_token('VARIABLE', $1) if $stream =~ /\G(\w+)\s*=/gcx;
$self->add_token('VALUE', $1) if $stream =~ /\G(\w+)/gcx;
redo TOKEN if $stream =~ /\G\s+/gcx;
};
}

sub add_token {
my $self = shift;
my ($t, $v) = @_;
push @{$self->token}, Token->new( type => $t, value => $v );
}

package main;

my $d;
{
local($/);
$d = <DATA>;
}

my $t = Tokenizer->new;
$t->tokenize($d);

warn Dumper $t;

my %config;
my ($cur_section, $cur_variable, $cur_value);

for my $token (@{$t->token}) {
$cur_section = $token->value if $token->type eq 'SECTION';
die unless $cur_section;

$cur_variable = $token->value if $token->type eq 'VARIABLE';
$cur_value = $token->type eq 'VALUE' ? $token->value : undef;

push @{$config{$cur_section}->{$cur_variable}}, $cur_value
if (defined $cur_value and defined $cur_variable);
}

warn Dumper \%config;

__DATA__
[foo]
bar = buz
qiz = 42 17 23

[languages]
favorite = perl python ruby
disliked = C Java
<< >> 7 Einträge, 1 Seite



View all threads created 2007-05-05 17:22.