package cfgfile; # Copyright (C) 1999 Norman Walsh, # This program is free software; you can redistribute it and/or modify # it under the same terms as Perl itself. # # WARRANTY # # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR # PURPOSE. use strict; use XML::Parser; { package cfgfile::cfgentry; sub new { my($type) = shift; my($name) = shift; my($value) = shift; my(%attr) = @_; my($class) = ref($type) || $type; my($self) = {}; $attr{'name'} = $name; $attr{'value'} = $value; $self->{'NAME'} = $name; $self->{'VALUE'} = $value; %{$self->{'ATTR'}} = %attr; return bless $self, $class; } sub write { my($self) = shift; local(*F) = shift; my($count, $key); print F " {'ATTR'}}) { my(%attr) = %{$self->{'ATTR'}}; if ($attr{$key} =~ /\"/) { print F " $key='", $attr{$key}, "'"; } else { print F " $key=\"", $attr{$key}, "\""; } } print F "/>\n"; } sub name { my($self) = shift; return $self->{'NAME'}; } sub getValue { my($self) = shift; return $self->{'VALUE'}; } sub setValue { my($self) = shift; my($value) = shift; $self->{'VALUE'} = $value; return $value; } } { package cfgfile::cfgsection; sub new { my($type) = shift; my($name) = shift; my(%attr) = @_; my($class) = ref($type) || $type; my($self) = {}; $attr{'name'} = $name; $self->{'NAME'} = $name; %{$self->{'ATTR'}} = %attr; $self->{'ENTRIES'} = []; $self->{'ENASSOC'} = {}; $self->{'ECOUNT'} = 0; return bless $self, $class; } sub write { my($self) = shift; local(*F) = shift; my($count, $key); print F "{'ATTR'}}) { my(%attr) = %{$self->{'ATTR'}}; if ($attr{$key} =~ /\"/) { print F " $key='", $attr{$key}, "'"; } else { print F " $key=\"", $attr{$key}, "\""; } } print F ">\n"; for ($count = 0; defined($self->{'ENTRIES'}->[$count]); $count++) { my($entry) = $self->{'ENTRIES'}->[$count]; $entry->write(*F); } print F "\n"; } sub name { my($self) = shift; return $self->{'NAME'}; } sub getEntry { my($self) = shift; my($name) = shift; my($num) = shift; my($count); # if $name and $num are defined, return the $num'th $name # if $name is defined and $num isn't, return the _LAST_ $name # if $name is '*' and $num is defined, return the $num'th entry # if $name and $num are both undefined, return undef if (defined($num)) { for ($count = 0; defined($self->{'ENTRIES'}->[$count]); $count++) { if (($name eq '*') || ($name eq $self->{'ENTRIES'}->[$count]->name())) { $num--; return $self->{'ENTRIES'}->[$count] if $num == 0; } } return undef; } elsif (defined($name)) { return $self->{'ENASSOC'}->{$name}; } else { return undef; } } sub addEntry { my($self) = shift; my($name) = shift; my($value) = shift; my(%attr) = @_; my($entry) = new cfgfile::cfgentry $name, $value, %attr; $self->{'ENTRIES'}->[$self->{'ECOUNT'}] = $entry; $self->{'ECOUNT'}++; $self->{'ENASSOC'}->{$name} = $entry; return $entry; } } my($self); # package global so that the start_handler can access it. sub new { my($type, $cfgfile) = @_; my($class) = ref($type) || $type; $self = {}; $self->{'SECTIONS'} = []; $self->{'SECASSOC'} = {}; $self->{'SCOUNT'} = 0; $self->{'CURSEC'} = 0; bless $self, $class; my $parser = new XML::Parser(ErrorContext => 2); $parser->setHandlers(Start => \&cfgfile::start_handler); $parser->parsefile($cfgfile); return $self; } sub write { my($self) = shift; local(*F) = shift; my($count); print F "\n"; print F "\n"; for ($count = 0; defined($self->{'SECTIONS'}->[$count]); $count++) { my($section) = $self->{'SECTIONS'}->[$count]; $section->write(*F); } print F "\n"; } sub addSection { my($self) = shift; my($name) = shift; my(%attr) = @_; my($sec) = new cfgfile::cfgsection $name, %attr; $self->{'SECTIONS'}->[$self->{'SCOUNT'}] = $sec; $self->{'SCOUNT'}++; $self->{'CURSEC'} = $sec; $self->{'SECASSOC'}->{$name} = $sec if ! exists $self->{'SECASSOC'}->{$name}; return $sec; } sub getProfileSection { my($self) = shift; my($name) = shift; my($num) = shift; my($count); # if $name and $num are defined, return the $num'th $name # if $name is defined and $num isn't, return the _LAST_ $name # if $name is '*' and $num is defined, return the $num'th entry # if $name and $num are both undefined, return undef if (defined($num)) { for ($count = 0; defined($self->{'SECTIONS'}->[$count]); $count++) { if (($name eq '*') || ($name eq $self->{'SECTIONS'}->[$count]->name())) { $num--; return $self->{'SECTIONS'}->[$count] if $num == 0; } } return undef; } elsif (defined($name)) { return $self->{'SECASSOC'}->{$name}; } else { return undef; } } sub getProfileString { my($self) = shift; my($secname) = shift; my($varname) = shift; my($default) = shift; my($section) = $self->{'SECASSOC'}->{$secname}; return $default if !$section; my($entry) = $section->getEntry($varname); return $entry->getValue() if $entry; return $default; } sub setProfileString { my($self) = shift; my($secname) = shift; my($varname) = shift; my($value) = shift; my($section) = $self->getProfileSection($secname); my(%attr) = (); $section = $self->addSection($secname) if !$section; my($entry) = $section->getEntry($varname); if ($entry) { return $entry->setValue($value); } else { $section->addEntry($varname, $value, %attr); return $value; } } sub start_handler { my $p = shift; my $el = shift; my %attr = @_; if ($el eq 'section') { my($name) = $attr{'name'}; $self->addSection($name, %attr); } elsif ($el eq 'entry') { my($name) = $attr{'name'}; my($val) = $attr{'value'}; $self->{'CURSEC'}->addEntry($name, $val, %attr); } } 1;