;# ;# 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 () { # 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