;#
;# Copyright (c) 1995-1997
;# Ikuo Nakagawa. All rights reserved.
;#
;# Redistribution and use in source and binary forms, with or without
;# modification, are permitted provided that the following conditions
;# are met:
;#
;# 1. Redistributions of source code must retain the above copyright
;# notice unmodified, this list of conditions, and the following
;# disclaimer.
;# 2. Redistributions in binary form must reproduce the above copyright
;# notice, this list of conditions and the following disclaimer in the
;# documentation and/or other materials provided with the distribution.
;#
;# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
;# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
;# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
;# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
;# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
;# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
;# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
;# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
;# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
;# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;#
;# $Id: Loader.pm,v 1.22 1997/09/26 04:48:33 ikuo Exp $
;#
package Fan::Loader;
use strict;
use vars qw($VERSION $LOG);
use Carp;
use Fan::Param;
use AutoLoader 'AUTOLOAD';
$VERSION = '0.02';
$LOG = 5;
;# A special marker for AutoSplit.
1;
__END__
;#
sub DESTROY ($) {
my $self = shift;
carp("Loader DESTROYING $self") if $LOG >= 6;
}
;#
sub new ($;%) {
my $this = shift;
my $class = ref($this) || $this;
my %param = @_;
my $keys = $param{loader_keys};
my $nest = $param{loader_nest};
my $self = {
loader_keys => ref($keys) eq 'HASH' ? $keys : undef,
loader_nest => ref($nest) eq 'HASH' ? $nest : undef,
loader_db => {},
loader_current => 'DEFAULT'
};
bless $self, $class or croak("Loader::new bless: $!");
carp("Loader CREATING $self") if $LOG >= 6;
$self;
}
;#
;# $loader->search($package_name [, $create]);
;#
sub search ($;$$) {
my $self = shift;
my $name = shift;
my $genflag = shift;
$name = $self->{loader_current} if $name eq '';
$name ne '' or confess("Empty name was detected");
# Is there a database for given name?
my $p = $self->{loader_db}->{$name};
# Check value and create a new one if needed.
if (!ref($p)) { # $p->isa('Fan::Param') must also be true.
unless ($genflag) {
#warn("search: $name not found.\n");
# We can't generate a new one.
return undef; # simply return FALSE.
}
$p = Fan::Param->new(
param_name => $name,
param_keys => $self->{loader_keys}
);
ref($p) or carp("Can't create Param object"), return undef;
$self->{loader_db}->{$name} = $p;
#warn("search: $name = $p created.\n");
}
# DEBUG only
ref($p) && $p->isa('Fan::Param')
or confess("$p must be a Param object");
# Register this object as `current' param.
$self->{loader_current} = $name;
#warn("search: $name = $p found.\n");
# return Param object.
$p;
}
;#
;# undef name ... clear a variable `name'.
;# name ... set the value of `name' to 1.
;# name = value ... set the value of `name' to `value'.
;# name += value ... add \n + `value' to `name'.
;#
;# 1 will be returned on success.
;# when name has special meaning,... what shall we do?
;#
sub parse_line ($$;$) {
my $self = shift;
my $nest = $self->{loader_nest}; # hash ref.
local $_ = shift; # an input line.
my $param = @_ ? shift : ''; # Param object or Param name.
my $p;
# check param...
if (ref($param) && $param->isa('Fan::Param')) {
$p= $param;
} else {
ref($p= $self->search($param, 1)) && $p->isa('Fan::Param')
or confess("Can't get a Param object for $param");
}
# Trim leading/trailing spaces.
s/^\s+//; s/\s+$//;
# Skip comment or null lines.
return 0 if /^$/ || /^#/;
# Set default value of the result.
my($key, $val, $todo);
# Parse this line.
if (/^$/ || /^#/) { # skip comment lines.
return '';
} elsif (/^delete\s+/) { # delete variable.
($key, $val, $todo) = ($', undef, 'delete');
} elsif (/^undef\s+/) { # set undef... TO BE FIXED.
($key, $val, $todo) = ($', '', 'setval');
} elsif (/\s*\+=\s*/) { # add value.
($key, $val, $todo) = ($`, $', 'addval');
} elsif (/\s*=\s*/) { # set value.
($key, $val, $todo) = ($`, $', 'setval');
} else { # set to 1.
($key, $val, $todo) = ($_, 1, 'setval');
}
# Convert `-' to `_'.
$key =~ y/-/_/;
#warn("loader: key=$key, val=$val, todo=$todo\n");
# Check special action.
if (ref($nest) eq 'HASH' && exists($nest->{$key})) {
my $s = $nest->{$key}; # make a copy...
my $result;
if ($s =~ s/^!//) {
local $_ = $val;
$result = eval $s;
croak("loader: ".$@) if $@;
} else {
($result = $s) =~ s/\$_/$val/g;
}
if (!defined($result)) {
croak("loader: wrong usage of $key");
}
if ($result eq '') {
croak("loader: empty name found");
}
return $result;
}
# To check errors.
my $err = 0;
# Do real action.
if ($todo eq '') {
;
} elsif ($todo eq 'delete') {
$err++ if !defined($p->delete($key));
} elsif ($todo eq 'addval') {
$err++ if !defined($p->addval($key, $val));
} elsif ($todo eq 'setval') {
$err++ if !defined($p->setval($key, $val));
} else { # what? this can't be happen.
confess("loader: unexpected todo");
}
# Check the result.
if ($err) {
croak("loader: \"$key\" unrecognized parameter");
}
# Result is an empty string for normal cases.
'';
}
;#
;# $p->parse_option(\@ARRAY);
;#
sub parse_option ($\@;$) {
my $self = shift; # loader
my $array = shift; # reference to ARRAY
my $param_name = @_ ? shift : '';
my $p = $self->search($param_name, 1);
# DEBUG only
ref($p) && $p->isa('Fan::Param')
or confess("$p must be a Param object");
# Array format is "--tag=value".
while (@{$array} && ${$array}[$[] =~ s/^--//) {
my $x = $self->parse_line(shift(@{$array}), $p);
if (!defined($x)) {
croak("loader: error found in parse_option");
} elsif ($x eq '') { # good.
;
} else {
$p = $self->search($x, 1);
# DEBUG only
ref($p) && $p->isa('Fan::Param')
or confess("$p must be a Param object");
}
}
# This routine returns # of (key, val) pairs we changed.
1;
}
;# Load file and set parameters.
;#
;# $p->parse_file(filename);
;#
sub parse_file ($$;$) {
my $self = shift;
my $file = shift;
my $param_name = @_ ? shift : '';
my $p = $self->search($param_name, 1);
# DEBUG only
ref($p) && $p->isa('Fan::Param')
or confess("$p must be a Param object");
# Check filename, add prefix is filename is relative path.
if ($file !~ /^\// && $self->{loader_prefix} ne '') {
$file = $self->{loader_prefix}.'/'.$file;
}
# Open file
local *FILE;
unless (open(FILE, $file)) {
carp("$self: open($file) - $!") if $LOG > 4;
return undef;
}
# Reading lines
my $line = '';
local $_;
while (<FILE>) {
# strip CR/LF at end.
chomp;
s/\r?$//;
# for cont'd lines
if ($line ne '') {
s/^\s+// ; # strip leading spaces
$_ = $line.$_; # concat to saved line
}
$line = $_, next if s/\\$//; # cont'd line
# found one line.
$line = ''; # clear
# trim leading/trailing spaces, and skip comment lines.
s/^\s+//; s/\s+$//;
next if /^$/ || /^#/;
# try to parse, and check result
my $x = $self->parse_line($_, $p);
if (!defined($x)) {
croak("$file($.): error was detected");
} elsif ($x eq '') { # good.
;
} else {
$p = $self->search($x, 1);
# DEBUG only
ref($p) && $p->isa('Fan::Param')
or confess("$p must be a Param object");
}
}
# we may be able to comment out the next line.
close(FILE);
# Returns # of ($key, $val) pairs we changed.
1;
}
;#
;# $loader->combine_hash(\%hash [, 'PARAM_NAME' [, $override]])
;#
sub combine_hash ($\%;$$) {
my $self = shift;
my $hash = shift;
my $param_name = @_ ? shift : '';
my $p = $self->search($param_name, 1);
my $f = shift;
ref($hash) eq 'HASH'
or carp("$hash must be HASH"), return undef;
my $param = Fan::Param->new(
param_name => 'temp',
param_keys => $self->{loader_keys},
%{$hash});
ref($param) && $param->isa('Fan::Param') or return undef;
$p->combine($param, $f);
}
;#
sub merge_hash ($\%;$) {
my $self = shift;
my $hash = shift;
my $param_name = @_ ? shift : '';
my $p = $self->search($param_name, 1);
my $f = shift;
$self->combine_hash($hash, $param_name, 1);
}
;# dump all Param objects in registry.
sub dumpall ($) {
my $self = shift; # loader
my $name;
my $param;
while (($name, $param) = each %{$self->{loader_db}}) {
$param->dump;
}
}
;#
;# $loader->get_value('key-you-want', 'key-of-param', 'key-of-param',...);
;#
sub get_value ($$@) {
my $self = shift;
my $want = shift;
my @keys = @_;
my $val = undef;
# warn("try get value of \"$want\" from (".join(', ', @keys).")\n");
while (@keys) {
my $key = pop(@keys);
my $p = $self->{loader_db}->{$key};
if (ref($p) && $p->isa('Fan::Param')) {
# warn(" try $key\n");
my $v = $p->getval($want);
if (defined($v)) {
$val = $v.$val;
# warn(" found val = $v\n");
last if $v !~ /^\n/;
}
}
}
# not found...
# { my $v = $val; $v =~ s/\n/ /g; warn(" returning val = $v\n"); }
$val;
}
;# end of Fan::Loader module
syntax highlighted by Code2HTML, v. 0.9.1