--- D:\progs\src\TWiki20030811beta\lib\TWiki\Prefs.pm Thu May 01 00:21:46 2003 +++ lib/TWiki/Prefs.pm Tue Aug 19 12:13:52 2003 @@ -32,6 +32,16 @@ $defaultWebName $altWebName @altPrefsKeys @altPrefsValues ); +use vars qw( + %webPrefsStorages @defPrefsStorage +); + +# Each storage is an array: +# (\@prefsKeys, \@prefsValues, \%prefsHash, \%finalKeys) +# @prefsKeys and @prefsValues hold keys and values, just as before. +# %prefsHash holds references to @prefsValues elements. +# keys(%finalKeys) is a list of final prefs. + $finalPrefsName = "FINALPREFERENCES"; @@ -48,11 +58,19 @@ $defaultWebName = $theWebName; $altWebName = ""; @finalPrefsKeys = (); - getPrefsFromTopic( $TWiki::twikiWebname, $TWiki::wikiPrefsTopicname ); # site-level - getPrefsFromTopic( $TWiki::mainWebname, $TWiki::wikiPrefsTopicname ); # alternate site-level - getPrefsFromTopic( $theWebName, $TWiki::webPrefsTopicname ); # web-level + + # (%hash is used, but order is preserved, too) + @defPrefsStorage = ( [], [], {}, {} ); + %webPrefsStorages = ( $theWebName, \@defPrefsStorage ); + + prvReadPrefsToStorage( $TWiki::twikiWebname, $TWiki::wikiPrefsTopicname, + \@defPrefsStorage); # site-level + prvReadPrefsToStorage( $TWiki::mainWebname, $TWiki::wikiPrefsTopicname, + \@defPrefsStorage); # alternate site-level + prvReadPrefsToStorage( $theWebName, $TWiki::webPrefsTopicname, + \@defPrefsStorage); # web-level if( $theWikiUserName =~ /^(.*)\.(.*)$/ ) { - getPrefsFromTopic( $1, $2 ); # user-level + prvReadPrefsToStorage( $1, $2, \@defPrefsStorage); # user-level } return; @@ -60,13 +78,13 @@ # ========================= -sub getPrefsFromTopic +sub prvReadPrefsToStorage { - my ( $theWeb, $theTopic, $theKeyPrefix ) = @_; + my ( $theWeb, $theTopic, $theStorageRef, $theKeyPrefix ) = @_; my( $meta, $text ) = &TWiki::Store::readTopic( $theWeb, $theTopic, 1 ); - $text =~ s/\r/\n/go; - $text =~ s/\n+/\n/go; + $text =~ s/\r/\n/g; + $text =~ s/\n+/\n/g; my $keyPrefix = $theKeyPrefix || ""; # prefix is for plugin prefs my $key = ""; @@ -75,7 +93,7 @@ foreach( split( /\n/, $text ) ) { if( /^\t+\*\sSet\s([a-zA-Z0-9_]*)\s\=\s*(.*)/ ) { if( $isKey ) { - prvAddToPrefsList( $key, $value ); + prvAddPrefToStorage( $key, $value, $theStorageRef ); } $key = "$keyPrefix$1"; $value = defined $2 ? $2 : ""; @@ -85,13 +103,13 @@ # follow up line, extending value $value .= "\n$_"; } else { - prvAddToPrefsList( $key, $value ); + prvAddPrefToStorage( $key, $value, $theStorageRef ); $isKey = 0; } } } if( $isKey ) { - prvAddToPrefsList( $key, $value ); + prvAddPrefToStorage( $key, $value, $theStorageRef ); } my %form = $meta->findOne( "FORM" ); @@ -101,14 +119,29 @@ $key = $field->{"name"}; $value = $field->{"value"}; my $attributes = $field->{"attributes"}; - if( $attributes && $attributes =~ /[S]/o ) { - prvAddToPrefsList( $key, $value ); + if( $attributes && $attributes =~ /[S]/ ) { + prvAddPrefToStorage( $key, $value, $theStorageRef ); } } } - @finalPrefsKeys = split( /[\,\s]+/, getPreferencesValue( $finalPrefsName ) ); + my $myPrefsHashRef = $theStorageRef->[2]; + my $myFinalKeysHashRef = $theStorageRef->[3]; + + foreach ( split( /[\,\s]+/, $myPrefsHashRef->{$finalPrefsName} ) ) { + $myFinalKeysHashRef->{$_} = 1; + } +} + +# ========================= +sub getPrefsFromTopic +{ + my ( $theWeb, $theTopic, $theKeyPrefix ) = @_; + + # This sub always reads preferences to the "default" + # (current web's) storage. + prvReadPrefsToStorage( $theWeb, $theTopic, \@defPrefsStorage, $theKeyPrefix ); } # ========================= @@ -126,8 +159,8 @@ $key = $field->{"name"}; $value = $field->{"value"}; my $attributes = $field->{"attributes"}; - if( $attributes =~ /[S]/o ) { - $value =~ s/\n/\\\n/o; + if( $attributes =~ /[S]/ ) { + $value =~ s/\n/\\\n/; TWiki::writeDebug( "updateSetFromForm: \"$key\"=\"$value\"" ); # Worry about verbatim? Multi-lines if ( $line =~ s/^(\t+\*\sSet\s$key\s\=\s*).*$/$1$value/g ) { @@ -145,44 +178,46 @@ } # ========================= -sub prvAddToPrefsList +sub prvAddPrefToStorage { - my ( $theKey, $theValue ) = @_; + my ( $theKey, $theValue, $theStorageRef ) = @_; - my $final; - foreach $final ( @finalPrefsKeys ) { - if( $theKey eq $final ) { - # this key is final, may not be overridden - return; - } - } + my ( $myPrefsKeysArrayRef, $myPrefsValuesArrayRef, + $myPrefsHashRef, $myFinalKeysHashRef ) = @$theStorageRef; - $theValue =~ s/\t/ /go; # replace TAB by space - $theValue =~ s/([^\\])\\n/$1\n/go; # replace \n by new line - $theValue =~ s/([^\\])\\\\n/$1\\n/go; # replace \\n by \n - $theValue =~ s/`//go; # filter out dangerous chars - my $x; - my $found = 0; - for( $x = 0; $x < @prefsKeys; $x++ ) { - if( $prefsKeys[$x] eq $theKey ) { - if( ( $theKey eq $finalPrefsName ) && ( $prefsValues[$x] ) ) { - # merge the values of existing key - $prefsValues[$x] .= ", $theValue"; - } else { - # replace value of existing key - $prefsValues[$x] = $theValue; - } - $found = "1"; - last; + if( exists $myFinalKeysHashRef->{$theKey} ) { + # this key is final, may not be overridden + return; + } + + $theValue =~ s/\t/ /g; # replace TAB by space + $theValue =~ s/([^\\])\\n/$1\n/g; # replace \n by new line + $theValue =~ s/([^\\])\\\\n/$1\\n/g; # replace \\n by \n + $theValue =~ s/`//g; # filter out dangerous chars + + if( exists( $myPrefsHashRef->{$theKey} ) ) { + # deal with an existing value + my $myPrefValueRef = $myPrefsHashRef->{$theKey}; + if( $theKey eq $finalPrefsName ) { + # merge the values of existing key + $$myPrefValueRef .= ", $theValue"; + } else { + # replace value of existing key + $$myPrefValueRef = $theValue; } - } - if( ! $found ) { - # append to list - $prefsKeys[@prefsKeys] = $theKey; - $prefsValues[@prefsValues] = $theValue; + } else { + # append the new key/value pair ... + my $newindex = @$myPrefsKeysArrayRef; + + $myPrefsKeysArrayRef->[$newindex] = $theKey; + $myPrefsValuesArrayRef->[$newindex] = $theValue; + + # ... and remember the reference in hash + $myPrefsHashRef->{$theKey} = \$myPrefsValuesArrayRef->[$newindex]; } } +# PavelGoran: it seems to be non-needed? # ========================= sub prvHandlePrefsValue { @@ -209,16 +244,20 @@ sub handlePreferencesTags { # modify argument directly, e.g. call by reference + + my( $myPrefsKeysArrayRef, $myPrefsValuesArrayRef ) = @defPrefsStorage[0, 1]; + + # this is the only place where order *may* be important my $x; my $term; - for( $x = 0; $x < @prefsKeys; $x++ ) { - $term = "\%$prefsKeys[$x]\%"; - $_[0] =~ s/$term/&prvHandlePrefsValue($x)/ge; + for( $x = 0; $x < @$myPrefsKeysArrayRef; $x++ ) { + $term = "\%$myPrefsKeysArrayRef->[$x]\%"; + $_[0] =~ s/$term/$myPrefsValuesArrayRef->[$x]/g; } if( $_[0] =~ /%VAR{(.*?)}%/ ) { # handle web specific variables - $_[0] =~ s/%VAR{(.*?)}%/&prvHandleWebVariable($1)/geo; + $_[0] =~ s/%VAR{(.*?)}%/&prvHandleWebVariable($1)/ge; } } @@ -227,44 +266,28 @@ { my ( $theKey, $theWeb ) = @_; - my $x; - my $sessionValue = &TWiki::getSessionValue( $theKey ); if( defined( $sessionValue ) ) { return $sessionValue; } - if( ( ! $theWeb ) || ( $theWeb eq $defaultWebName ) ) { - # search the default web - for( $x = 0; $x < @prefsKeys; $x++ ) { - if( $prefsKeys[$x] eq $theKey ) { - return $prefsValues[$x]; - } + my $storage; + if( $theWeb ) { + # read web preferences (or simply get the storage, if already read) + $storage = prvRetrieveWebPrefs( $theWeb ); + if( ! $storage ) { + return ''; } - } elsif( &TWiki::Store::webExists( $theWeb ) ) { - # search the alternate web, rebuild prefs if necessary - if( $theWeb ne $altWebName ) { - $altWebName = $theWeb; - @finalPrefsKeys = (); - my @saveKeys = @prefsKeys; # quick hack, this stinks - my @saveValues = @prefsValues; # ditto - @prefsKeys = (); - @prefsValues = (); - getPrefsFromTopic( $TWiki::twikiWebname, $TWiki::wikiPrefsTopicname ); - getPrefsFromTopic( $altWebName, $TWiki::webPrefsTopicname ); - @altPrefsKeys = @prefsKeys; # quick hack, this stinks - @altPrefsValues = @prefsValues; # quick hack, this stinks - @prefsKeys = @saveKeys; # quick hack, this stinks - @prefsValues = @saveValues; # quick hack, this stinks + } else { + $storage = \@defPrefsStorage; + } - } - for( $x = 0; $x < @altPrefsKeys; $x++ ) { - if( $altPrefsKeys[$x] eq $theKey ) { - return $altPrefsValues[$x]; - } - } + my $myWebPrefsHashRef = $storage->[2]; + if( exists $myWebPrefsHashRef->{$theKey} ) { + return ${$myWebPrefsHashRef->{$theKey}}; # double dereferencing } - return ""; + + return ''; } # ========================= @@ -273,14 +296,37 @@ my ( $theKey, $theWeb ) = @_; my $flag = getPreferencesValue( $theKey, $theWeb ); - $flag =~ s/^\s*(.*?)\s*$/$1/goi; - $flag =~ s/off//goi; - $flag =~ s/no//goi; + $flag =~ s/^\s*(.*?)\s*$/$1/gi; + $flag =~ s/off//gi; + $flag =~ s/no//gi; if( $flag ) { return 1; } else { return 0; } +} + +# ========================= +sub prvRetrieveWebPrefs +{ + my( $theWeb ) = @_; + if( exists $webPrefsStorages{$theWeb} ) { + return $webPrefsStorages{$theWeb} + } + + if( &TWiki::Store::webExists( $theWeb ) ) { + my @newstorage = ( [], [], {}, {} ); + $webPrefsStorages{$theWeb} = \@newstorage; + + prvReadPrefsToStorage( $TWiki::twikiWebname, $TWiki::wikiPrefsTopicname, + \@newstorage ); + prvReadPrefsToStorage( $theWeb, $TWiki::webPrefsTopicname, + \@newstorage ); + + return \@newstorage; + } + + return undef; } # =========================