Ignore:
Timestamp:
12/17/09 19:28:55 (2 years ago)
Author:
CrawfordCurrie
Message:

Item2511: split macros out of the Foswiki.pm monster

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/core/lib/Foswiki.pm

    r5791 r5810  
    6161use Foswiki::Store           (); 
    6262use Foswiki::Users           (); 
    63 use Foswiki::PageCache       (); 
    6463 
    6564require 5.005;    # For regex objects and internationalisation 
    6665 
    6766# Site configuration constants 
    68 use vars qw( %cfg ); 
    69  
    70 # Uncomment this and the __END__ to enable AutoLoader 
    71 #use AutoLoader 'AUTOLOAD'; 
    72 # You then need to autosplit Foswiki.pm: 
    73 # cd lib 
    74 # perl -e 'use AutoSplit; autosplit("Foswiki.pm", "auto")' 
     67our %cfg; 
    7568 
    7669# Other computed constants 
    7770our $foswikiLibDir; 
    7871our %regex; 
    79 our %functionTags; 
     72our %macros; 
    8073our %contextFreeSyntax; 
    8174our $VERSION; 
     
    8477our $FALSE = 0; 
    8578our $engine; 
    86 our $ifParser; 
    87  
    88 # Token character that must not occur in any normal text - converted 
    89 # to a flag character if it ever does occur (very unlikely) 
    90 # Foswiki uses $TranslationToken to mark points in the text. This is 
    91 # normally \0, which is not a useful character in any 8-bit character 
    92 # set we can find, nor in UTF-8. But if you *do* encounter problems 
    93 # with it, the workaround is to change $TranslationToken to something 
    94 # longer that is unlikely to occur in your text - for example 
    95 # muRfleFli5ble8leep (do *not* use punctuation characters or whitspace 
    96 # in the string!) 
    97 # See Codev.NationalCharTokenClash for more. 
    98 our $TranslationToken = "\0"; 
     79our $TranslationToken = "\0"; # unused, but maintained for compatibility 
     80 
     81# Used by takeOut/putBack blocks 
     82our $BLOCKID = 0; 
     83our $OC = "<!--\0"; 
     84our $CC = "\0-->"; 
    9985 
    10086# Returns the full path of the directory containing Foswiki.pm 
     
    145131 
    146132BEGIN { 
     133    #Monitor::MARK("Start of BEGIN block in Foswiki.pm"); 
    147134    if (DEBUG) { 
    148135 
     
    170157 
    171158    # Default handlers for different %TAGS% 
    172     %functionTags = ( 
    173         ADDTOHEAD         => \&ADDTOHEAD, 
    174         ALLVARIABLES      => \&ALLVARIABLES, 
    175         ATTACHURL         => \&ATTACHURL, 
    176         ATTACHURLPATH     => \&ATTACHURLPATH, 
    177         COREPOD           => \&COREPOD, 
    178         DATE              => \&DATE, 
    179         DISPLAYTIME       => \&DISPLAYTIME, 
    180         ENCODE            => \&ENCODE, 
    181         ENV               => \&ENV, 
    182         FORMFIELD         => \&FORMFIELD, 
    183         FOREACH           => \&FOREACH, 
    184         GMTIME            => \&GMTIME, 
    185         GROUPINFO         => \&GROUPINFO, 
    186         GROUPS            => \&GROUPS, 
    187         HTTP_HOST         => \&HTTP_HOST_deprecated, 
    188         HTTP              => \&HTTP, 
    189         HTTPS             => \&HTTPS, 
    190         ICON              => \&ICON, 
    191         ICONURL           => \&ICONURL, 
    192         ICONURLPATH       => \&ICONURLPATH, 
    193         IF                => \&IF, 
    194         INCLUDE           => \&INCLUDE, 
    195         INTURLENCODE      => \&INTURLENCODE_deprecated, 
    196         LANGUAGES         => \&LANGUAGES, 
    197         MAKETEXT          => \&MAKETEXT, 
    198         META              => \&META, 
    199         METASEARCH        => \&METASEARCH, 
    200         NOP               => \&NOP, 
    201         PLUGINVERSION     => \&PLUGINVERSION, 
    202         PUBURL            => \&PUBURL, 
    203         PUBURLPATH        => \&PUBURLPATH, 
    204         QUERYPARAMS       => \&QUERYPARAMS, 
    205         QUERYSTRING       => \&QUERYSTRING, 
    206         RELATIVETOPICPATH => \&RELATIVETOPICPATH, 
    207         REMOTE_ADDR       => \&REMOTE_ADDR_deprecated, 
    208         REMOTE_PORT       => \&REMOTE_PORT_deprecated, 
    209         REMOTE_USER       => \&REMOTE_USER_deprecated, 
    210         REVINFO           => \&REVINFO, 
    211         REVTITLE          => \&REVTITLE, 
    212         REVARG            => \&REVARG, 
    213         SCRIPTNAME        => \&SCRIPTNAME, 
    214         SCRIPTURL         => \&SCRIPTURL, 
    215         SCRIPTURLPATH     => \&SCRIPTURLPATH, 
    216         SEARCH            => \&SEARCH, 
    217         SEP               => \&SEP, 
    218         SERVERTIME        => \&SERVERTIME, 
    219         SHOWPREFERENCE    => \&SHOWPREFERENCE, 
    220         SPACEDTOPIC       => \&SPACEDTOPIC_deprecated, 
    221         SPACEOUT          => \&SPACEOUT, 
    222         'TMPL:P'          => \&TMPLP, 
    223         TOPICLIST         => \&TOPICLIST, 
    224         URLENCODE         => \&ENCODE, 
    225         URLPARAM          => \&URLPARAM, 
    226         LANGUAGE          => \&LANGUAGE, 
    227         USERINFO          => \&USERINFO, 
    228         USERNAME          => \&USERNAME_deprecated, 
    229         VAR               => \&VAR, 
    230         WEBLIST           => \&WEBLIST, 
    231         WIKINAME          => \&WIKINAME_deprecated, 
    232         WIKIUSERNAME      => \&WIKIUSERNAME_deprecated, 
    233         DISPLAYDEPENDENCIES => \&DISPLAYDEPENDENCIES, 
     159    # Where an entry is set as 'undef', the tag will be demand-loaded 
     160    # from Foswiki::Macros, if it is used. This tactic is used to reduce 
     161    # the load time of this module, especially when it is used from 
     162    # REST handlers. 
     163    %macros = ( 
     164        ADDTOHEAD         => undef, 
     165        ALLVARIABLES      => 
     166          sub { $_[0]->{prefs}->stringify() }, 
     167        ATTACHURL         => 
     168          sub { return $_[0]->getPubUrl( 1, $_[2]->web, $_[2]->topic ); }, 
     169        ATTACHURLPATH     => 
     170          sub { return $_[0]->getPubUrl( 0, $_[2]->web, $_[2]->topic ); }, 
     171        DATE              => sub { 
     172            Foswiki::Time::formatTime( 
     173                time(), 
     174                $Foswiki::cfg{DefaultDateFormat}, 
     175                $Foswiki::cfg{DisplayTimeValues} 
     176               ); 
     177        }, 
     178        DISPLAYTIME       => sub { 
     179            Foswiki::Time::formatTime( 
     180                time(), 
     181                $_[1]->{_DEFAULT} || '', 
     182                $Foswiki::cfg{DisplayTimeValues} 
     183               ); 
     184        }, 
     185        ENCODE            => undef, 
     186        ENV               => undef, 
     187        FORMFIELD         => undef, 
     188        FOREACH           => undef, 
     189        GMTIME            => sub { 
     190            Foswiki::Time::formatTime( 
     191                time(), $_[1]->{_DEFAULT} || '', 'gmtime' ); 
     192        }, 
     193        GROUPINFO         => undef, 
     194        GROUPS            => undef, 
     195        HTTP_HOST         => 
     196          #deprecated functionality, now implemented using %ENV% 
     197          sub { $_[0]->{request}->header('Host') || '' }, 
     198        HTTP              => undef, 
     199        HTTPS             => undef, 
     200        ICON              => undef, 
     201        ICONURL           => 
     202          sub { $_[0]->getIconUrl( 1,  $_[1]->{_DEFAULT} || '' ); }, 
     203        ICONURLPATH       => 
     204          sub { $_[0]->getIconUrl( 0,  $_[1]->{_DEFAULT} || '' ); }, 
     205        IF                => undef, 
     206        INCLUDE           => undef, 
     207        INTURLENCODE      => undef, 
     208        LANGUAGE          => sub { $_[0]->i18n->language(); }, 
     209        LANGUAGES         => undef, 
     210        MAKETEXT          => undef, 
     211        META              => undef, 
     212        METASEARCH        => sub { 
     213            # DEPRECATED 
     214            $_[0]->search->searchMetaData($_[1]); 
     215        }, 
     216        NOP               => 
     217          # Remove NOP tag in template topics but show content. 
     218          # Used in template _topics_ (not templates, per se, but 
     219          # topics used as templates for new topics) 
     220          sub { $_[1]->{_RAW} ? $_[1]->{_RAW} : '<nop>' }, 
     221        PLUGINVERSION     => sub { 
     222            $_[0]->{plugins}->getPluginVersion( $_[1]->{_DEFAULT} ); 
     223        }, 
     224        PUBURL            => 
     225          sub { $_[0]->getPubUrl(1) }, 
     226        PUBURLPATH        => 
     227          sub { $_[0]->getPubUrl(0) }, 
     228        QUERYPARAMS       => undef, 
     229        QUERYSTRING       => 
     230          sub { $_[0]->{request}->queryString() }, 
     231        RELATIVETOPICPATH => undef, 
     232        REMOTE_ADDR       =>  
     233          # DEPRECATED, now implemented using %ENV% 
     234          #move to compatibility plugin in Foswiki 2.0 
     235          sub { $_[0]->{request}->remoteAddress() || ''; }, 
     236        REMOTE_PORT       => 
     237          # DEPRECATED 
     238          # CGI/1.1 (RFC 3875) doesn't specify REMOTE_PORT, 
     239          # but some webservers implement it. However, since 
     240          # it's not RFC compliant, Foswiki should not rely on 
     241          # it. So we get more portability. 
     242          sub { '' }, 
     243        REMOTE_USER       => 
     244          # DEPRECATED 
     245          sub { $_[0]->{request}->remoteUser() || '' }, 
     246        REVINFO           => undef, 
     247        REVTITLE          => undef, 
     248        REVARG            => undef, 
     249        SCRIPTNAME        => sub { $_[0]->{request}->action() }, 
     250        SCRIPTURL         => 
     251          sub { $_[0]->getScriptUrl( 1, $_[1]->{_DEFAULT} || '' ) }, 
     252        SCRIPTURLPATH     => 
     253          sub { $_[0]->getScriptUrl( 0, $_[1]->{_DEFAULT} || '' ) }, 
     254        SEARCH            => undef, 
     255        SEP               => 
     256          # Shortcut to %TMPL:P{"sep"}% 
     257          sub { $_[0]->templates->expandTemplate('sep') }, 
     258        SERVERTIME        => sub { 
     259            Foswiki::Time::formatTime( 
     260                time(), $_[1]->{_DEFAULT} || '', 'servertime' ); 
     261        }, 
     262        SHOWPREFERENCE    => undef, 
     263        SPACEDTOPIC       => undef, 
     264        SPACEOUT          => undef, 
     265        'TMPL:P'          => sub { $_[0]->templates->tmplP($_[1]) }, 
     266        TOPICLIST         => undef, 
     267        URLENCODE         => undef, 
     268        URLPARAM          => undef, 
     269        USERINFO          => undef, 
     270        USERNAME          => undef, 
     271        VAR               => undef, 
     272        WEBLIST           => undef, 
     273        WIKINAME          => undef, 
     274        WIKIUSERNAME      => undef, 
     275        DISPLAYDEPENDENCIES => undef, 
    234276 
    235277        # Constant tag strings _not_ dependent on config. These get nicely 
     
    292334 
    293335    # Constant tags dependent on the config 
    294     $functionTags{ALLOWLOGINNAME} = 
     336    $macros{ALLOWLOGINNAME} = 
    295337      sub { $Foswiki::cfg{Register}{AllowLoginName} || 0 }; 
    296     $functionTags{AUTHREALM}      = sub { $Foswiki::cfg{AuthRealm} }; 
    297     $functionTags{DEFAULTURLHOST} = sub { $Foswiki::cfg{DefaultUrlHost} }; 
    298     $functionTags{HOMETOPIC}      = sub { $Foswiki::cfg{HomeTopicName} }; 
    299     $functionTags{LOCALSITEPREFS} = sub { $Foswiki::cfg{LocalSitePreferences} }; 
    300     $functionTags{NOFOLLOW} = 
     338    $macros{AUTHREALM}      = sub { $Foswiki::cfg{AuthRealm} }; 
     339    $macros{DEFAULTURLHOST} = sub { $Foswiki::cfg{DefaultUrlHost} }; 
     340    $macros{HOMETOPIC}      = sub { $Foswiki::cfg{HomeTopicName} }; 
     341    $macros{LOCALSITEPREFS} = sub { $Foswiki::cfg{LocalSitePreferences} }; 
     342    $macros{NOFOLLOW} = 
    301343      sub { $Foswiki::cfg{NoFollow} ? 'rel=' . $Foswiki::cfg{NoFollow} : '' }; 
    302     $functionTags{NOTIFYTOPIC}     = sub { $Foswiki::cfg{NotifyTopicName} }; 
    303     $functionTags{SCRIPTSUFFIX}    = sub { $Foswiki::cfg{ScriptSuffix} }; 
    304     $functionTags{STATISTICSTOPIC} = sub { $Foswiki::cfg{Stats}{TopicName} }; 
    305     $functionTags{SYSTEMWEB}       = sub { $Foswiki::cfg{SystemWebName} }; 
    306     $functionTags{TRASHWEB}        = sub { $Foswiki::cfg{TrashWebName} }; 
    307     $functionTags{WIKIADMINLOGIN}  = sub { $Foswiki::cfg{AdminUserLogin} }; 
    308     $functionTags{USERSWEB}        = sub { $Foswiki::cfg{UsersWebName} }; 
    309     $functionTags{WEBPREFSTOPIC}   = sub { $Foswiki::cfg{WebPrefsTopicName} }; 
    310     $functionTags{WIKIPREFSTOPIC}  = sub { $Foswiki::cfg{SitePrefsTopicName} }; 
    311     $functionTags{WIKIUSERSTOPIC}  = sub { $Foswiki::cfg{UsersTopicName} }; 
    312     $functionTags{WIKIWEBMASTER}   = sub { $Foswiki::cfg{WebMasterEmail} }; 
    313     $functionTags{WIKIWEBMASTERNAME} = sub { $Foswiki::cfg{WebMasterName} }; 
     344    $macros{NOTIFYTOPIC}     = sub { $Foswiki::cfg{NotifyTopicName} }; 
     345    $macros{SCRIPTSUFFIX}    = sub { $Foswiki::cfg{ScriptSuffix} }; 
     346    $macros{STATISTICSTOPIC} = sub { $Foswiki::cfg{Stats}{TopicName} }; 
     347    $macros{SYSTEMWEB}       = sub { $Foswiki::cfg{SystemWebName} }; 
     348    $macros{TRASHWEB}        = sub { $Foswiki::cfg{TrashWebName} }; 
     349    $macros{WIKIADMINLOGIN}  = sub { $Foswiki::cfg{AdminUserLogin} }; 
     350    $macros{USERSWEB}        = sub { $Foswiki::cfg{UsersWebName} }; 
     351    $macros{WEBPREFSTOPIC}   = sub { $Foswiki::cfg{WebPrefsTopicName} }; 
     352    $macros{WIKIPREFSTOPIC}  = sub { $Foswiki::cfg{SitePrefsTopicName} }; 
     353    $macros{WIKIUSERSTOPIC}  = sub { $Foswiki::cfg{UsersTopicName} }; 
     354    $macros{WIKIWEBMASTER}   = sub { $Foswiki::cfg{WebMasterEmail} }; 
     355    $macros{WIKIWEBMASTERNAME} = sub { $Foswiki::cfg{WebMasterName} }; 
    314356 
    315357    # locale setup 
     
    336378    } 
    337379 
    338     $functionTags{CHARSET} = sub { 
     380    $macros{CHARSET} = sub { 
    339381        $Foswiki::cfg{Site}{CharSet} 
    340382          || 'iso-8859-1'; 
    341383    }; 
    342384 
    343     $functionTags{LANG} = sub { 
     385    $macros{LANG} = sub { 
    344386        $Foswiki::cfg{Site}{Locale} =~ m/^([a-z]+_[a-z]+)/i ? $1 : 'en_US'; 
    345387    }; 
     
    499541    die $@ if $@; 
    500542 
    501     Monitor::MARK('Static configuration loaded'); 
    502 } 
    503  
    504 =begin TML 
    505  
    506 ---++ ObjectMethod UTF82SiteCharSet( $utf8 ) -> $ascii 
    507  
    508 Auto-detect UTF-8 vs. site charset in string, and convert UTF-8 into site 
    509 charset. 
    510  
    511 =cut 
     543    #Monitor::MARK('End of BEGIN block in Foswiki.pm'); 
     544} 
    512545 
    513546sub UTF82SiteCharSet { 
     
    710743    $this->generateHTTPHeaders( $pageType, $contentType, $text, $cachedPage ); 
    711744 
    712     # SMELL: null operation. the http headers are written out during Foswiki::Engine::finalize 
    713     #$hdr = $this->{response}->printHeaders; 
     745    # SMELL: null operation. the http headers are written out 
     746    # during Foswiki::Engine::finalize 
     747    # $hdr = $this->{response}->printHeaders; 
    714748 
    715749    $this->{response}->print($text); 
     
    926960sub redirectto { 
    927961    my ( $this, $url ) = @_; 
    928     ASSERT($url); 
     962    ASSERT($url) if DEBUG; 
    929963 
    930964    my $redirecturl = $this->{request}->param('redirectto'); 
     
    9861020sub redirect { 
    9871021    my ( $this, $url, $passthru ) = @_; 
    988     ASSERT( defined $url ); 
     1022    ASSERT( defined $url ) if DEBUG; 
    9891023 
    9901024    return unless $this->{request}; 
     
    10981132 
    10991133sub getCGISession { 
    1100     my $this = shift; 
    1101     return $this->{users}->getCGISession(); 
     1134    $_[0]->{users}->getCGISession(); 
    11021135} 
    11031136 
     
    11121145 
    11131146sub getLoginManager { 
    1114     my $this = shift; 
    1115     ASSERT($this->{users}) if DEBUG; 
    1116     return $this->{users}->getLoginManager(); 
     1147    $_[0]->{users}->getLoginManager(); 
    11171148} 
    11181149 
     
    11461177    return 1 if ( $name =~ m/^$regex{topicNameRegex}$/o ); 
    11471178    return 0 unless $nonww; 
    1148     return 0 if $name =~ /$Foswiki::cfg{NameFilter}/; 
     1179    return 0 if $name =~ /$cfg{NameFilter}/o; 
    11491180    return 1; 
    11501181} 
     
    11811212# Note: must work on tainted names. 
    11821213sub isValidEmailAddress { 
    1183     my ($name) = @_; 
    1184     return $name =~ /^$regex{emailAddrRegex}$/; 
     1214    my $name = shift || ''; 
     1215    return $name =~ /^$regex{emailAddrRegex}$/o; 
    11851216} 
    11861217 
     
    14131444=begin TML 
    14141445 
    1415 ---++ ObjectMethod mapToIconFileName( $fileName, $default ) -> $fileName 
    1416  
    1417 Maps from a filename (or just the extension) to the name of the 
    1418 file that contains the image for that file type. 
    1419  
    1420 =cut 
    1421  
    1422 sub mapToIconFileName { 
    1423     my ( $this, $fileName, $default ) = @_; 
    1424  
    1425     my @bits = ( split( /\./, $fileName ) ); 
    1426     my $fileExt = lc( $bits[$#bits] ); 
    1427  
    1428     unless ( $this->{_ICONMAP} ) { 
    1429         my $iconTopic = $this->{prefs}->getPreference('ICONTOPIC'); 
    1430         if ( defined($iconTopic) ) { 
    1431             my ( $web, $topic ) = 
    1432               $this->normalizeWebTopicName( $this->{webName}, $iconTopic ); 
    1433             my $topicObject = Foswiki::Meta->new( $this, $web, $topic ); 
    1434             local $/; 
    1435             try { 
    1436                 my $icons = 
    1437                   $topicObject->openAttachment( '_filetypes.txt', '<' ); 
    1438                 %{ $this->{_ICONMAP} } = split( /\s+/, <$icons> ); 
    1439                 $icons->close(); 
    1440             } 
    1441             catch Error with { 
    1442                 ASSERT( 0, $_[0] ) if DEBUG; 
    1443                 %{ $this->{_ICONMAP} } = (); 
    1444             }; 
    1445         } 
    1446         else { 
    1447             return $default || $fileName; 
    1448         } 
    1449     } 
    1450  
    1451     return $this->{_ICONMAP}->{$fileExt} || $default || 'else'; 
    1452 } 
    1453  
    1454 =begin TML 
    1455  
    14561446---++ ObjectMethod normalizeWebTopicName( $web, $topic ) -> ( $web, $topic ) 
    14571447 
     
    15261516sub new { 
    15271517    my ( $class, $defaultUser, $query, $initialContext ) = @_; 
    1528     ASSERT( !$query || UNIVERSAL::isa( $query, 'Foswiki::Request' ) ); 
    1529     Monitor::MARK("Static compilation complete"); 
     1518    Monitor::MARK("Static init over; make Foswiki object"); 
     1519    ASSERT( !$query || UNIVERSAL::isa( $query, 'Foswiki::Request' ) ) if DEBUG; 
    15301520 
    15311521    # Compatibility; not used except maybe in plugins 
     
    15581548    $this->{context}      = $initialContext; 
    15591549 
    1560     $this->{cache} = new Foswiki::PageCache( $this ) 
    1561       if ($Foswiki::cfg{Cache}{Enabled}); 
     1550    if ($Foswiki::cfg{Cache}{Enabled}) { 
     1551        require Foswiki::PageCache; 
     1552        $this->{cache} = new Foswiki::PageCache( $this ) 
     1553    } 
    15621554    my $prefs = new Foswiki::Prefs($this); 
    15631555    $this->{prefs}   = $prefs; 
     
    15681560    $this->{store}   = $Foswiki::cfg{Store}{Implementation}->new(); 
    15691561 
     1562    #Monitor::MARK("Created store"); 
     1563 
    15701564    $this->{users}   = new Foswiki::Users($this); 
     1565 
     1566    #Monitor::MARK("Created users object"); 
    15711567 
    15721568    # Load (or create) the CGI session 
     
    17161712    $prefs->loadDefaultPreferences(); 
    17171713 
     1714    #Monitor::MARK("Loaded default prefs"); 
     1715 
    17181716    # SMELL: what happens if we move this into the Foswiki::Users::new? 
    17191717    $this->{user} = $this->{users}->initialiseUser( $this->{remoteUser} ); 
     1718 
     1719    #Monitor::MARK("Initialised user"); 
    17201720 
    17211721    # Static session variables that can be expanded in topics when they 
     
    17451745    $prefs->pushTopicContext( $this->{webName}, $this->{topicName} ); 
    17461746 
     1747    #Monitor::MARK("Preferences all set up"); 
     1748 
    17471749    # Finish plugin initialization - register handlers 
    17481750    $this->{plugins}->enable(); 
    17491751 
    1750     Monitor::MARK("Foswiki session created"); 
     1752    Monitor::MARK("Foswiki object created"); 
    17511753 
    17521754    return $this; 
     
    19181920    my $this = shift; 
    19191921 
     1922    # Print any macros that are never loaded 
     1923    #print STDERR "NEVER USED\n"; 
     1924    #for my $i (keys %macros) { 
     1925    #    print STDERR "\t$i\n" unless defined $macros{$i}; 
     1926    #} 
    19201927    $_->finish() foreach values %{ $this->{forms} }; 
    19211928    $this->{plugins}->finish()   if $this->{plugins}; 
     
    20182025} 
    20192026 
    2020 # Add a web reference to a [[...][...]] link in an included topic 
    2021 sub _fixIncludeLink { 
    2022     my ( $web, $link, $label ) = @_; 
    2023  
    2024     # Detect absolute and relative URLs and web-qualified wikinames 
    2025     if ( $link =~ 
    2026 m#^($regex{webNameRegex}\.|$regex{defaultWebNameRegex}\.|$regex{linkProtocolPattern}:|/)#o 
    2027       ) 
    2028     { 
    2029         if ($label) { 
    2030             return "[[$link][$label]]"; 
    2031         } 
    2032         else { 
    2033             return "[[$link]]"; 
    2034         } 
    2035     } 
    2036     elsif ( !$label ) { 
    2037  
    2038         # Must be wikiword or spaced-out wikiword (or illegal link :-/) 
    2039         $label = $link; 
    2040     } 
    2041  
    2042     # If link is only an anchor, leave it as is (Foswikitask:Item771) 
    2043     return "[[$link][$label]]" if $link =~ /^#/; 
    2044     return "[[$web.$link][$label]]"; 
    2045 } 
    2046  
    2047 # Replace web references in a topic. Called from forEachLine, applying to 
    2048 # each non-verbatim and non-literal line. 
    2049 sub _fixupIncludedTopic { 
    2050     my ( $text, $options ) = @_; 
    2051  
    2052     my $fromWeb = $options->{web}; 
    2053  
    2054     unless ( $options->{in_noautolink} ) { 
    2055  
    2056         # 'TopicName' to 'Web.TopicName' 
    2057         $text =~ 
    2058           s#(?:^|(?<=[\s(]))($regex{wikiWordRegex})(?=\s|\)|$)#$fromWeb.$1#go; 
    2059     } 
    2060  
    2061     # Handle explicit [[]] everywhere 
    2062     # '[[TopicName][...]]' to '[[Web.TopicName][...]]' 
    2063     $text =~ s/\[\[([^]]+)\](?:\[([^]]+)\])?\]/ 
    2064       _fixIncludeLink( $fromWeb, $1, $2 )/geo; 
    2065  
    2066     return $text; 
    2067 } 
    2068  
    20692027=begin TML 
    20702028 
     
    20852043    $pattern =~ s/(^|[^\\])([\$\@])/$1\\$2/g; 
    20862044    return $pattern; 
    2087 } 
    2088  
    2089 =begin TML 
    2090  
    2091 ---++ StaticMethod applyPatternToIncludedText( $text, $pattern ) -> $text 
    2092  
    2093 Apply a pattern on included text to extract a subset 
    2094  
    2095 =cut 
    2096  
    2097 sub applyPatternToIncludedText { 
    2098     my ( $text, $pattern ) = @_; 
    2099  
    2100     $pattern = Foswiki::Sandbox::untaint( $pattern, \&validatePattern ); 
    2101  
    2102     try { 
    2103         $text =~ s/$pattern/$1/is; 
    2104     } 
    2105     catch Error::Simple with { 
    2106         $text = ''; 
    2107     }; 
    2108     return $text; 
    2109 } 
    2110  
    2111 # 
    2112 # SMELL: this is _not_ a tag handler in the sense of other builtin tags, 
    2113 # because it requires far more context information (the text of the topic) 
    2114 # than any handler. 
    2115 # SMELL: as a tag handler that also semi-renders the topic to extract the 
    2116 # headings, this handler would be much better as a preRenderingHandler in 
    2117 # a plugin (where head, script and verbatim sections are already protected) 
    2118 # 
    2119 #    * $text  : ref to the text of the current topic 
    2120 #    * $topic : the topic we are in 
    2121 #    * $web   : the web we are in 
    2122 #    * $args  : 'Topic' [web='Web'] [depth='N'] 
    2123 # Return value: $tableOfContents 
    2124 # Handles %<nop>TOC{...}% syntax.  Creates a table of contents 
    2125 # using Foswiki bulleted 
    2126 # list markup, linked to the section headings of a topic. A section heading is 
    2127 # entered in one of the following forms: 
    2128 #    * $headingPatternSp : \t++... spaces section heading 
    2129 #    * $headingPatternDa : ---++... dashes section heading 
    2130 #    * $headingPatternHt : &lt;h[1-6]> HTML section heading &lt;/h[1-6]> 
    2131 sub _TOC { 
    2132     my ( $this, $text, $topicObject, $args ) = @_; 
    2133  
    2134     require Foswiki::Attrs; 
    2135     my $params    = new Foswiki::Attrs($args); 
    2136     my $sameTopic = 1;                           # is the toc for this topic? 
    2137  
    2138     my $tocTopic = $params->{_DEFAULT}; 
    2139     my $tocWeb   = $params->{web}; 
    2140  
    2141     if ( $tocTopic || $tocWeb ) { 
    2142         $tocWeb   ||= $topicObject->web; 
    2143         $tocTopic ||= $topicObject->topic; 
    2144         ( $tocTopic, $tocWeb ) = 
    2145           $this->normalizeWebTopicName( $tocTopic, $tocWeb ); 
    2146  
    2147         if ( $tocWeb eq $topicObject->web && $tocTopic eq $topicObject->topic ) 
    2148         { 
    2149             $sameTopic = 1; 
    2150         } 
    2151         else { 
    2152  
    2153             # Data for topic coming from another topic 
    2154             $params->{differentTopic} = 1; 
    2155             $topicObject = Foswiki::Meta->load( $this, $tocWeb, $tocTopic ); 
    2156             if ( !$topicObject->haveAccess('VIEW') ) { 
    2157                 return $this->inlineAlert( 'alerts', 'access_denied', $tocWeb, 
    2158                     $tocTopic ); 
    2159             } 
    2160             $text      = $topicObject->text; 
    2161             $sameTopic = 0; 
    2162         } 
    2163     } 
    2164  
    2165     return $this->renderer->renderTOC( $text, $topicObject, $params, 
    2166         $sameTopic ); 
    21672045} 
    21682046 
     
    26872565} 
    26882566 
     2567=begin TML 
     2568 
     2569---++ StaticMethod takeOutBlocks( \$text, $tag, \%map ) -> $text 
     2570   * =$text= - Text to process 
     2571   * =$tag= - XML-style tag. 
     2572   * =\%map= - Reference to a hash to contain the removed blocks 
     2573 
     2574Return value: $text with blocks removed 
     2575 
     2576Searches through $text and extracts blocks delimited by an XML-style tag, 
     2577storing the extracted block, and replacing with a token string which is 
     2578not affected by TML rendering.  The text after these substitutions is 
     2579returned. 
     2580 
     2581=cut 
     2582 
     2583sub takeOutBlocks { 
     2584    my ( $intext, $tag, $map ) = @_; 
     2585 
     2586    return $intext unless ( $intext =~ m/<$tag\b/i ); 
     2587 
     2588    my $out   = ''; 
     2589    my $depth = 0; 
     2590    my $scoop; 
     2591    my $tagParams; 
     2592 
     2593    foreach my $token ( split( /(<\/?$tag[^>]*>)/i, $intext )) { 
     2594        if ( $token =~ /<$tag\b([^>]*)?>/i ) { 
     2595            $depth++; 
     2596            if ( $depth eq 1 ) { 
     2597                $tagParams = $1; 
     2598                next; 
     2599            } 
     2600        } 
     2601        elsif ( $token =~ /<\/$tag>/i ) { 
     2602            if ( $depth > 0 ) { 
     2603                $depth--; 
     2604                if ( $depth eq 0 ) { 
     2605                    my $placeholder = "$tag$BLOCKID"; 
     2606                    $BLOCKID++; 
     2607                    $map->{$placeholder}{text}   = $scoop; 
     2608                    $map->{$placeholder}{params} = $tagParams; 
     2609                    $out .= "$OC$placeholder$CC"; 
     2610                    $scoop = ''; 
     2611                    next; 
     2612                } 
     2613            } 
     2614        } 
     2615        if ( $depth > 0 ) { 
     2616            $scoop .= $token; 
     2617        } 
     2618        else { 
     2619            $out .= $token; 
     2620        } 
     2621    } 
     2622 
     2623    # unmatched tags 
     2624    if ( defined($scoop) && ( $scoop ne '' ) ) { 
     2625        my $placeholder = "$tag$BLOCKID"; 
     2626        $BLOCKID++; 
     2627        $map->{$placeholder}{text}   = $scoop; 
     2628        $map->{$placeholder}{params} = $tagParams; 
     2629        $out .= "$OC$placeholder$CC"; 
     2630    } 
     2631 
     2632    return $out; 
     2633} 
     2634 
     2635=begin TML 
     2636 
     2637---++ StaticMethod putBackBlocks( \$text, \%map, $tag, $newtag, $callBack ) -> $text 
     2638 
     2639Return value: $text with blocks added back 
     2640   * =\$text= - reference to text to process 
     2641   * =\%map= - map placeholders to blocks removed by takeOutBlocks 
     2642   * =$tag= - Tag name processed by takeOutBlocks 
     2643   * =$newtag= - Tag name to use in output, in place of $tag. 
     2644     If undefined, uses $tag. 
     2645   * =$callback= - Reference to function to call on each block 
     2646     being inserted (optional) 
     2647 
     2648Reverses the actions of takeOutBlocks. 
     2649 
     2650Each replaced block is processed by the callback (if there is one) before 
     2651re-insertion. 
     2652 
     2653Parameters to the outermost cut block are replaced into the open tag, 
     2654even if that tag is changed. This allows things like =&lt;verbatim class=''>= 
     2655to be changed to =&lt;pre class=''>= 
     2656 
     2657If you set $newtag to '', replaces the taken-out block with the contents 
     2658of the block, not including the open/close. This is used for &lt;literal>, 
     2659for example. 
     2660 
     2661=cut 
     2662 
     2663sub putBackBlocks { 
     2664    my ( $text, $map, $tag, $newtag, $callback ) = @_; 
     2665 
     2666    $newtag = $tag if ( !defined($newtag) ); 
     2667 
     2668    foreach my $placeholder ( keys %$map ) { 
     2669        if ( $placeholder =~ /^$tag\d+$/ ) { 
     2670            my $params = $map->{$placeholder}{params} || ''; 
     2671            my $val = $map->{$placeholder}{text}; 
     2672            $val = &$callback($val) if ( defined($callback) ); 
     2673            if ( $newtag eq '' ) { 
     2674                $$text =~ s($OC$placeholder$CC)($val); 
     2675            } 
     2676            else { 
     2677                $$text =~ s($OC$placeholder$CC) 
     2678                           (<$newtag$params>$val</$newtag>); 
     2679            } 
     2680            delete( $map->{$placeholder} ); 
     2681        } 
     2682    } 
     2683} 
     2684 
    26892685# Process Foswiki %TAGS{}% by parsing the input tokenised into 
    26902686# % separated sections. The parser is a simple stack-based parse, 
     
    27012697 
    27022698    #no tags to process 
    2703     return $text unless ( $text =~ /(%)/ ); 
     2699    return $text unless ( $text =~ /%/ ); 
    27042700 
    27052701    unless ($depth) { 
     
    27142710 
    27152711    my $verbatim = {}; 
    2716     $text = $this->renderer->takeOutBlocks( $text, 'verbatim', 
    2717                                                $verbatim); 
     2712    $text = takeOutBlocks( $text, 'verbatim', $verbatim); 
    27182713 
    27192714    my $dirtyAreas = {}; 
    2720     $text = $this->renderer->takeOutBlocks( $text, 'dirtyarea', $dirtyAreas)  
     2715    $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas)  
    27212716      if $Foswiki::cfg{Cache}{Enabled}; 
    2722  
    2723  
    2724     # See Item1442 
    2725     #my $percent = ($TranslationToken x 3).'%'.($TranslationToken x 3); 
    27262717 
    27272718    my @queue = split( /(%)/, $text ); 
     
    27482739            if ( $stackTop =~ /}$/s ) { 
    27492740                while ( scalar(@stack) 
    2750                     && $stackTop !~ /^%($regex{tagNameRegex}){.*}$/so ) 
     2741                    && $stackTop !~ /^%$regex{tagNameRegex}\{.*}$/so ) 
    27512742                { 
    27522743                    my $top = $stackTop; 
     
    27642755 
    27652756                #print STDERR ' ' x $tell,"POP $tag\n"; 
     2757                Monitor::MARK("Before $tag"); 
    27662758                my $e = &$tagf( $this, $tag, $args, $topicObject ); 
     2759                Monitor::MARK("After $tag"); 
    27672760 
    27682761                if ( defined($e) ) { 
     
    27702763                    #print STDERR ' ' x $tell--,"EXPANDED $tag -> $e\n"; 
    27712764                    $stackTop = pop(@stack); 
    2772                     unless ( $e =~ /(%)/ ) { 
    2773  
    2774 #SMELL: this is a profiler speedup found by Sven on the last day of 4.2.1 
    2775 #TODO: I don't think this parser should be in this section - re-analysis desired. 
    2776 #print STDERR "no tags to recurse\n"; 
     2765                    # Don't bother recursively expanding unless there are 
     2766                    # unexpanded tags in the result. 
     2767                    unless ( $e =~ /%$regex{tagNameRegex}(?:{.*})?%/o ) { 
    27772768                        $stackTop .= $e; 
    27782769                        next; 
     
    27842775                        $depth - 1 ); 
    27852776                } 
    2786                 else {    # expansion failed 
    2787                       #print STDERR ' ' x $tell++,"EXPAND $tag FAILED\n"; 
    2788                       # To handle %NOP 
    2789                       # correctly, we have to handle the %VAR% case differently 
    2790                       # to the %VAR{}% case when a variable expansion fails. 
    2791                       # This is so that recursively define variables e.g. 
    2792                       # %A%B%D% expand correctly, but at the same time we ensure 
    2793                       # that a mismatched }% can't accidentally close a context 
    2794                       # that was left open when a tag expansion failed. 
    2795                       # However Cairo didn't do this, so for compatibility 
    2796                       # we have to accept that %NOP can never be fixed. if it 
    2797                       # could, then we could uncomment the following: 
     2777                else { 
     2778                    #print STDERR ' ' x $tell++,"EXPAND $tag FAILED\n"; 
     2779                    # To handle %NOP 
     2780                    # correctly, we have to handle the %VAR% case differently 
     2781                    # to the %VAR{}% case when a variable expansion fails. 
     2782                    # This is so that recursively define variables e.g. 
     2783                    # %A%B%D% expand correctly, but at the same time we ensure 
     2784                    # that a mismatched }% can't accidentally close a context 
     2785                    # that was left open when a tag expansion failed. 
     2786                    # However TWiki didn't do this, so for compatibility 
     2787                    # we have to accept that %NOP can never be fixed. if it 
     2788                    # could, then we could uncomment the following: 
    27982789 
    27992790                    #if( $stackTop =~ /}$/ ) { 
     
    28022793                    #    # onto the stack, but we don't want it to match the 
    28032794                    #    # tag expression again. So we protect the %'s 
    2804                     #    $stackTop = $percent.$expr.$percent; 
     2795                    #    $stackTop = "&#37;$expr&#37;"; 
    28052796                    #} else 
    2806                     { 
     2797                    #{ 
    28072798 
    28082799                        # %VAR% case. 
     
    28132804                        push( @stack, $stackTop ); 
    28142805                        $stackTop = '%';    # open new context 
    2815                     } 
     2806                    #} 
    28162807                } 
    28172808            } 
     
    28342825    } 
    28352826 
    2836     #$stackTop =~ s/$percent/%/go; 
    2837  
    2838     $this->renderer->putBackBlocks( \$stackTop, $dirtyAreas, 'dirtyarea' ) 
     2827    putBackBlocks( \$stackTop, $dirtyAreas, 'dirtyarea' ) 
    28392828      if $Foswiki::cfg{Cache}{Enabled}; 
    2840     $this->renderer->putBackBlocks( \$stackTop, $verbatim, 'verbatim' ); 
     2829    putBackBlocks( \$stackTop, $verbatim, 'verbatim' ); 
    28412830 
    28422831    #print STDERR "FINAL $stackTop\n"; 
     
    28562845    my $e = $this->{prefs}->getPreference($tag); 
    28572846    unless ( defined($e) ) { 
    2858         if ( !defined($e) && defined( $functionTags{$tag} ) ) { 
    2859             $e = &{ $functionTags{$tag} }( 
     2847        if ( !defined($e) && exists( $macros{$tag} ) ) { 
     2848            unless ( defined( $macros{$tag} )) { 
     2849                # Demand-load the macro module 
     2850                die $tag unless $tag =~ /([A-Z_:]+)/i; 
     2851                $tag = $1; 
     2852                eval "require Foswiki::Macros::$tag"; 
     2853                die $@ if $@; 
     2854                $macros{$tag} = eval "\\&$tag"; 
     2855                die $@ if $@; 
     2856            } 
     2857            $e = &{ $macros{$tag} }( 
    28602858                $this, new Foswiki::Attrs( $args, $contextFreeSyntax{$tag} ), 
    28612859                $topicObject 
     
    29662964sub registerTagHandler { 
    29672965    my ( $tag, $fnref, $syntax ) = @_; 
    2968     $functionTags{$tag} = $fnref; 
     2966    $macros{$tag} = $fnref; 
    29692967    if ( $syntax && $syntax eq 'context-free' ) { 
    29702968        $contextFreeSyntax{$tag} = 1; 
     
    30023000    #their verbatim blocks safetly. 
    30033001    my $verbatim={}; 
    3004     $text = $this->renderer->takeOutBlocks( $text, 'verbatim', 
    3005                                               $verbatim); 
     3002    $text = takeOutBlocks( $text, 'verbatim', $verbatim); 
    30063003 
    30073004    # take out dirty areas 
    30083005    my $dirtyAreas = {}; 
    3009     $text = $this->renderer->takeOutBlocks( $text, 'dirtyarea', $dirtyAreas ) 
     3006    $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas ) 
    30103007      if $Foswiki::cfg{Cache}{Enabled}; 
    30113008 
     
    30243021    $this->innerExpandMacros( \$text, $topicObject ); 
    30253022 
    3026     $text = $this->renderer->takeOutBlocks( $text, 'verbatim', $verbatim ); 
     3023    $text = takeOutBlocks( $text, 'verbatim', $verbatim ); 
    30273024 
    30283025    # Plugin Hook 
     
    30423039    # are complete, and has to reprocess the entire topic. 
    30433040 
    3044     $text =~ s/%TOC(?:{(.*?)})?%/$this->_TOC($text, $topicObject, $1)/ge; 
     3041    if ($text =~ /%TOC(?:{.*})?%/ ) { 
     3042        require Foswiki::Macros::TOC; 
     3043        $text =~ s/%TOC(?:{(.*?)})?%/$this->TOC($text, $topicObject, $1)/ge; 
     3044    } 
    30453045 
    30463046    # Codev.FormattedSearchWithConditionalOutput: remove <nop> lines, 
     
    30513051 
    30523052    # restore dirty areas 
    3053     $this->renderer->putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' ) 
     3053    putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' ) 
    30543054      if $Foswiki::cfg{Cache}{Enabled}; 
    30553055 
    3056  
    3057     $this->renderer->putBackBlocks( \$text, $verbatim, 'verbatim' ); 
     3056    putBackBlocks( \$text, $verbatim, 'verbatim' ); 
    30583057 
    30593058    # Foswiki Plugin Hook (for cache Plugins only) 
     
    30673066=begin TML 
    30683067 
    3069 ---++ ObjectMethod addToHead( $tag, $header, $requires, $topicObject ) 
     3068---++ ObjectMethod addToHEAD( $tag, $header, $requires, $topicObject ) 
    30703069 
    30713070Add =$html= to the HEAD tag of the page currently being generated. 
     
    31963195} 
    31973196 
    3198 # generate an include warning 
    3199 # SMELL: varying number of parameters idiotic to handle for customized $warn 
    3200 sub _includeWarning { 
    3201     my $this    = shift; 
    3202     my $warn    = shift; 
    3203     my $message = shift; 
    3204  
    3205     if ( $warn eq 'on' ) { 
    3206         return $this->inlineAlert( 'alerts', $message, @_ ); 
    3207     } 
    3208     elsif ( isTrue($warn) ) { 
    3209  
    3210         # different inlineAlerts need different argument counts 
    3211         my $argument = ''; 
    3212         if ( $message eq 'topic_not_found' ) { 
    3213             my ( $web, $topic ) = @_; 
    3214             $argument = "$web.$topic"; 
    3215         } 
    3216         else { 
    3217             $argument = shift; 
    3218         } 
    3219         $warn =~ s/\$topic/$argument/go if $argument; 
    3220         return $warn; 
    3221     }    # else fail silently 
    3222     return ''; 
    3223 } 
    3224  
    32253197=begin TML 
    32263198 
     
    32833255} 
    32843256 
    3285 #------------------------------------------------------------------- 
    3286 # Tag Handlers 
    3287 #------------------------------------------------------------------- 
    3288  
    3289 sub ADDTOHEAD { 
    3290     my ( $this, $args, $topicObject ) = @_; 
    3291  
    3292     my $_DEFAULT = $args->{_DEFAULT}; 
    3293     my $text     = $args->{text}; 
    3294     my $topic    = $args->{topic}; 
    3295     my $requires = $args->{requires}; 
    3296     if ( defined $args->{topic} ) { 
    3297         my ( $web, $topic ) = 
    3298           $this->normalizeWebTopicName( $topicObject->web, $args->{topic} ); 
    3299  
    3300         # prevent deep recursion 
    3301         $web =~ s/\//\./g; 
    3302         unless ($this->{_addedToHEAD}{"$web.$topic"}) { 
    3303           my $atom = Foswiki::Meta->new( $this, $web, $topic ); 
    3304           $text = $atom->text(); 
    3305           $this->{_addedToHEAD}{"$web.$topic"} = 1; 
    3306         } 
    3307     } 
    3308     $text = $_DEFAULT unless defined $text; 
    3309     $text = ''        unless defined $text; 
    3310  
    3311     $this->addToHEAD( $_DEFAULT, $text, $requires, $topicObject ); 
    3312     return ''; 
    3313 } 
    3314  
    3315 sub FORMFIELD { 
    3316     my ( $this, $args, $topicObject ) = @_; 
    3317     if ( $args->{topic} ) { 
    3318         my ( $web, $topic ) = 
    3319           $this->normalizeWebTopicName( $topicObject->web, $args->{topic} ); 
    3320         $topicObject = new Foswiki::Meta( $this, $web, $topic ); 
    3321     } 
    3322     else { 
    3323  
    3324         # SMELL: horrible hack; assumes the current rev comes from the 'rev' 
    3325         # parameter. There has to be a better way! 
    3326         my $query = $this->{request}; 
    3327         $args->{rev} ||= $query->param('rev') if ($query); 
    3328     } 
    3329     return $this->renderer->renderFORMFIELD( $args, $topicObject ); 
    3330 } 
    3331  
    3332 sub TMPLP { 
    3333     my ( $this, $params ) = @_; 
    3334     return $this->templates->tmplP($params); 
    3335 } 
    3336  
    3337 sub VAR { 
    3338     my ( $this, $params, $topicObject ) = @_; 
    3339     my $key = $params->{_DEFAULT}; 
    3340     return '' unless $key; 
    3341     my $web = $params->{web} || $topicObject->web; 
    3342     my $topic = $topicObject->topic; 
    3343  
    3344     # handle %USERSWEB%-type cases 
    3345     ( $web, $topic ) = $this->normalizeWebTopicName( $web, $topic ); 
    3346  
    3347     my $webObject = Foswiki::Meta->new( $this, $web ); 
    3348  
    3349     # always return a value, even when the key isn't defined 
    3350     return $webObject->getPreference($key) || ''; 
    3351 } 
    3352  
    3353 sub PLUGINVERSION { 
    3354     my ( $this, $params ) = @_; 
    3355     $this->{plugins}->getPluginVersion( $params->{_DEFAULT} ); 
    3356 } 
    3357  
    3358 sub IF { 
    3359     my ( $this, $params, $topicObject ) = @_; 
    3360  
    3361     unless ($ifParser) { 
    3362         require Foswiki::If::Parser; 
    3363         $ifParser = new Foswiki::If::Parser(); 
    3364     } 
    3365  
    3366     my $texpr = $params->{_DEFAULT}; 
    3367     my $expr; 
    3368     my $result; 
    3369  
    3370     # Recursion block. 
    3371     $this->{evaluating_if} ||= {}; 
    3372  
    3373     # Block after 5 levels. 
    3374     if (   $this->{evaluating_if}->{$texpr} 
    3375         && $this->{evaluating_if}->{$texpr} > 5 ) 
    3376     { 
    3377         delete $this->{evaluating_if}->{$texpr}; 
    3378         return ''; 
    3379     } 
    3380     $this->{evaluating_if}->{$texpr}++; 
    3381     try { 
    3382         $expr = $ifParser->parse($texpr); 
    3383         if ( $expr->evaluate( tom => $topicObject, data => $topicObject ) ) { 
    3384             $params->{then} = '' unless defined $params->{then}; 
    3385             $result = expandStandardEscapes( $params->{then} ); 
    3386         } 
    3387         else { 
    3388             $params->{else} = '' unless defined $params->{else}; 
    3389             $result = expandStandardEscapes( $params->{else} ); 
    3390         } 
    3391     } 
    3392     catch Foswiki::Infix::Error with { 
    3393         my $e = shift; 
    3394         $result = 
    3395           $this->inlineAlert( 'alerts', 'generic', 'IF{', $params->stringify(), 
    3396             '}:', $e->{-text} ); 
    3397     } 
    3398     finally { 
    3399         delete $this->{evaluating_if}->{$texpr}; 
    3400     }; 
    3401     return $result; 
    3402 } 
    3403  
    3404 # Processes a specific instance %<nop>INCLUDE{...}% syntax. 
    3405 # Returns the text to be inserted in place of the INCLUDE command. 
    3406 # $includingTopicObject should be for the immediate parent topic in the 
    3407 # include hierarchy. Works for both URLs and absolute server paths. 
    3408 sub INCLUDE { 
    3409     my ( $this, $params, $includingTopicObject ) = @_; 
    3410  
    3411     # remember args for the key before mangling the params 
    3412     my $args = $params->stringify(); 
    3413  
    3414     # Remove params, so they don't get expanded in the included page 
    3415     my %control; 
    3416     for my $p qw(_DEFAULT pattern rev section raw warn) { 
    3417         $control{$p} = $params->remove($p); 
    3418     } 
    3419  
    3420     $control{warn} ||= $this->{prefs}->getPreference('INCLUDEWARNING'); 
    3421  
    3422     # make sure we have something to include. If we don't do this, then 
    3423     # normalizeWebTopicName will default to WebHome. TWikibug:Item2209. 
    3424     unless ( $control{_DEFAULT} ) { 
    3425         return $this->_includeWarning( $control{warn}, 'bad_include_path', '' ); 
    3426     } 
    3427  
    3428     # Filter out '..' from path to prevent includes of '../../file' 
    3429     if ( $Foswiki::cfg{DenyDotDotInclude} && $control{_DEFAULT} =~ /\.\./ ) { 
    3430         return $this->_includeWarning( $control{warn}, 'bad_include_path', 
    3431             $control{_DEFAULT} ); 
    3432     } 
    3433  
    3434     # no sense in considering an empty string as an unfindable section 
    3435     delete $control{section} 
    3436       if ( defined( $control{section} ) && $control{section} eq '' ); 
    3437     $control{raw} ||= ''; 
    3438     $control{inWeb}   = $includingTopicObject->web; 
    3439     $control{inTopic} = $includingTopicObject->topic; 
    3440  
    3441     # Protocol links e.g. http:, https:, doc: 
    3442     if ( $control{_DEFAULT} =~ /^([a-z]+):/ ) { 
    3443         my $handler = $1; 
    3444         eval 'use Foswiki::IncludeHandlers::' . $handler; 
    3445         die $@ if ($@); 
    3446         unless ($@) { 
    3447             $handler = 'Foswiki::IncludeHandlers::' . $handler; 
    3448             return $handler->INCLUDE( $this, \%control, $params ); 
    3449         } 
    3450     } 
    3451  
    3452     # No protocol handler; must be a topic reference 
    3453  
    3454     my $text = ''; 
    3455     my $includedWeb; 
    3456     my $includedTopic = $control{_DEFAULT}; 
    3457     $includedTopic =~ s/\.txt$//;    # strip optional (undocumented) .txt 
    3458  
    3459     ( $includedWeb, $includedTopic ) = 
    3460       $this->normalizeWebTopicName( $includingTopicObject->web, 
    3461         $includedTopic ); 
    3462  
    3463     # See Codev.FailedIncludeWarning for the history. 
    3464     unless ( $this->{store}->topicExists( $includedWeb, $includedTopic ) ) { 
    3465         return _includeWarning( $this, $control{warn}, 'topic_not_found', 
    3466             $includedWeb, $includedTopic ); 
    3467     } 
    3468  
    3469     # prevent recursive includes. Note that the inclusion of a topic into 
    3470     # itself is not blocked; however subsequent attempts to include the 
    3471     # topic will fail. There is a hard block of 99 on any recursive include. 
    3472     my $key = $includingTopicObject->web . '.' . $includingTopicObject->topic; 
    3473     my $count = grep( $key, keys %{ $this->{_INCLUDES} } ); 
    3474     $key .= $args; 
    3475     if ( $this->{_INCLUDES}->{$key} || $count > 99 ) { 
    3476         return _includeWarning( $this, $control{warn}, 'already_included', 
    3477             "$includedWeb.$includedTopic", '' ); 
    3478     } 
    3479  
    3480     # Push the topic context to the included topic, so we can create 
    3481     # local (SESSION) macro definitions without polluting the including 
    3482     # topic namespace. 
    3483     $this->{prefs}->pushTopicContext( $this->{webName}, $this->{topicName} ); 
    3484  
    3485     $this->{_INCLUDES}->{$key} = 1; 
    3486  
    3487     my $includedTopicObject = 
    3488       Foswiki::Meta->load( $this, $includedWeb, $includedTopic, $control{rev} ); 
    3489     unless ( $includedTopicObject->haveAccess('VIEW') ) { 
    3490         if ( isTrue( $control{warn} ) ) { 
    3491             return $this->inlineAlert( 'alerts', 'access_denied', 
    3492                 "[[$includedWeb.$includedTopic]]" ); 
    3493         }    # else fail silently 
    3494         return ''; 
    3495     } 
    3496     my $memWeb   = $this->{prefs}->getPreference('INCLUDINGWEB'); 
    3497     my $memTopic = $this->{prefs}->getPreference('INCLUDINGTOPIC'); 
    3498  
    3499     my $dirtyAreas = {}; 
    3500     try { 
    3501  
    3502         # Copy params into session level preferences. That way finalisation 
    3503         # will apply to them. These preferences will be popped when the topic 
    3504         # context is restored after the include. 
    3505         $this->{prefs}->setSessionPreferences(%$params); 
    3506  
    3507         # Set preferences that finalisation does *not* apply to 
    3508         $this->{prefs}->setInternalPreferences( 
    3509             INCLUDINGWEB   => $includingTopicObject->web, 
    3510             INCLUDINGTOPIC => $includingTopicObject->topic 
    3511         ); 
    3512  
    3513         $text = $includedTopicObject->text; 
    3514  
    3515         # Simplify leading, and remove trailing, newlines. If we don't remove 
    3516         # trailing, it becomes impossible to %INCLUDE a topic into a table. 
    3517         $text =~ s/^[\r\n]+/\n/; 
    3518         $text =~ s/[\r\n]+$//; 
    3519  
    3520         # remove everything before and after the default include block unless 
    3521         # a section is explicitly defined 
    3522         if ( !$control{section} ) { 
    3523             $text =~ s/.*?%STARTINCLUDE%//s; 
    3524             $text =~ s/%STOPINCLUDE%.*//s; 
    3525         } 
    3526  
    3527         # prevent dirty areas in included topics from being parsed  
    3528         $text = $this->renderer->takeOutBlocks( $text, 'dirtyarea', $dirtyAreas)  
    3529           if $Foswiki::cfg{Cache}{Enabled}; 
    3530  
    3531         # handle sections 
    3532         my ( $ntext, $sections ) = parseSections($text); 
    3533  
    3534         my $interesting = ( defined $control{section} ); 
    3535         if ( $interesting || scalar(@$sections) ) { 
    3536  
    3537             # Rebuild the text from the interesting sections 
    3538             $text = ''; 
    3539             foreach my $s (@$sections) { 
    3540                 if (   $control{section} 
    3541                     && $s->{type} eq 'section' 
    3542                     && $s->{name} eq $control{section} ) 
    3543                 { 
    3544                     $text .= 
    3545                       substr( $ntext, $s->{start}, $s->{end} - $s->{start} ); 
    3546                     $interesting = 1; 
    3547                     last; 
    3548                 } 
    3549                 elsif ( $s->{type} eq 'include' && !$control{section} ) { 
    3550                     $text .= 
    3551                       substr( $ntext, $s->{start}, $s->{end} - $s->{start} ); 
    3552                     $interesting = 1; 
    3553                 } 
    3554             } 
    3555         } 
    3556  
    3557         if ( $interesting and ( length($text) eq 0 ) ) { 
    3558             $text = 
    3559               _includeWarning( $this, $control{warn}, 'topic_section_not_found', 
    3560                 $includedWeb, $includedTopic, $control{section} ); 
    3561         } 
    3562         else { 
    3563  
    3564             # If there were no interesting sections, restore the whole text 
    3565             $text = $ntext unless $interesting; 
    3566  
    3567             $text = applyPatternToIncludedText( $text, $control{pattern} ) 
    3568               if ( $control{pattern} ); 
    3569  
    3570             # Do not show TOC in included topic if TOC_HIDE_IF_INCLUDED 
    3571             # preference has been set 
    3572             if ( isTrue( $this->{prefs}->getPreference('TOC_HIDE_IF_INCLUDED') ) 
    3573               ) 
    3574             { 
    3575                 $text =~ s/%TOC(?:{(.*?)})?%//g; 
    3576             } 
    3577  
    3578             $this->innerExpandMacros( \$text, $includedTopicObject ); 
    3579  
    3580             # 4th parameter tells plugin that its called for an included file 
    3581             $this->{plugins} 
    3582               ->dispatch( 'commonTagsHandler', $text, $includedTopic, 
    3583                 $includedWeb, 1, $includedTopicObject ); 
    3584  
    3585             # We have to expand tags again, because a plugin may have inserted 
    3586             # additional tags. 
    3587             $this->innerExpandMacros( \$text, $includedTopicObject ); 
    3588  
    3589             # If needed, fix all 'TopicNames' to 'Web.TopicNames' to get the 
    3590             # right context so that links continue to work properly 
    3591             if ( $includedWeb ne $includingTopicObject->web ) { 
    3592                 my $removed = {}; 
    3593  
    3594                 $text = $this->renderer->forEachLine( 
    3595                     $text, 
    3596                     \&_fixupIncludedTopic, 
    3597                     { 
    3598                         web        => $includedWeb, 
    3599                         pre        => 1, 
    3600                         noautolink => 1 
    3601                     } 
    3602                 ); 
    3603  
    3604                 # handle tags again because of plugin hook 
    3605                 innerExpandMacros( $this, \$text, $includedTopicObject ); 
    3606             } 
    3607         } 
    3608     } 
    3609     finally { 
    3610  
    3611         # always restore the context, even in the event of an error 
    3612         delete $this->{_INCLUDES}->{$key}; 
    3613  
    3614         $this->{prefs}->setInternalPreferences( 
    3615             INCLUDINGWEB   => $memWeb, 
    3616             INCLUDINGTOPIC => $memTopic 
    3617         ); 
    3618  
    3619         # restoring dirty areas 
    3620         $this->renderer->putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' ) 
    3621           if $Foswiki::cfg{Cache}{Enabled}; 
    3622  
    3623         ( $this->{webName}, $this->{topicName} ) = 
    3624           $this->{prefs}->popTopicContext(); 
    3625     }; 
    3626  
    3627     return $text; 
    3628 } 
    3629  
    3630 sub HTTP { 
    3631     my ( $this, $params ) = @_; 
    3632     my $res; 
    3633     if ( $params->{_DEFAULT} ) { 
    3634         $res = $this->{request}->http( $params->{_DEFAULT} ); 
    3635     } 
    3636     $res = '' unless defined($res); 
    3637     return $res; 
    3638 } 
    3639  
    3640 sub HTTPS { 
    3641     my ( $this, $params ) = @_; 
    3642     my $res; 
    3643     if ( $params->{_DEFAULT} ) { 
    3644         $res = $this->{request}->https( $params->{_DEFAULT} ); 
    3645     } 
    3646     $res = '' unless defined($res); 
    3647     return $res; 
    3648 } 
    3649  
    3650 #deprecated functionality, now implemented using %ENV% 
    3651 #move to compatibility plugin in Foswiki 2.0 
    3652 sub HTTP_HOST_deprecated { 
    3653     return $_[0]->{request}->header('Host') || ''; 
    3654 } 
    3655  
    3656 #deprecated functionality, now implemented using %ENV% 
    3657 #move to compatibility plugin in Foswiki 2.0 
    3658 sub REMOTE_ADDR_deprecated { 
    3659     return $_[0]->{request}->remoteAddress() || ''; 
    3660 } 
    3661  
    3662 #deprecated functionality, now implemented using %ENV% 
    3663 #move to compatibility plugin in Foswiki 2.0 
    3664 sub REMOTE_PORT_deprecated { 
    3665  
    3666     # CGI/1.1 (RFC 3875) doesn't specify REMOTE_PORT, 
    3667     # but some webservers implement it. However, since 
    3668     # it's not RFC compliant, Foswiki should not rely on 
    3669     # it. So we get more portability. 
    3670     return ''; 
    3671 } 
    3672  
    3673 #deprecated functionality, now implemented using %ENV% 
    3674 #move to compatibility plugin in Foswiki 
    3675 sub REMOTE_USER_deprecated { 
    3676     return $_[0]->{request}->remoteUser() || ''; 
    3677 } 
    3678  
    3679 # Only does simple search for topicmoved at present, can be expanded when required 
    3680 # SMELL: this violates encapsulation of Store and Meta, by exporting 
    3681 # the assumption that meta-data is stored embedded inside topic 
    3682 # text. 
    3683 sub METASEARCH { 
    3684     my ( $this, $params ) = @_; 
    3685  
    3686     return $this->search->searchMetaData($params); 
    3687 } 
    3688  
    3689 sub DATE { 
    3690     my $this = shift; 
    3691     return Foswiki::Time::formatTime( 
    3692         time(), 
    3693         $Foswiki::cfg{DefaultDateFormat}, 
    3694         $Foswiki::cfg{DisplayTimeValues} 
    3695     ); 
    3696 } 
    3697  
    3698 sub GMTIME { 
    3699     my ( $this, $params ) = @_; 
    3700     return Foswiki::Time::formatTime( time(), $params->{_DEFAULT} || '', 
    3701         'gmtime' ); 
    3702 } 
    3703  
    3704 sub SERVERTIME { 
    3705     my ( $this, $params ) = @_; 
    3706     return Foswiki::Time::formatTime( time(), $params->{_DEFAULT} || '', 
    3707         'servertime' ); 
    3708 } 
    3709  
    3710 sub DISPLAYTIME { 
    3711     my ( $this, $params ) = @_; 
    3712     return Foswiki::Time::formatTime( 
    3713         time(), 
    3714         $params->{_DEFAULT} || '', 
    3715         $Foswiki::cfg{DisplayTimeValues} 
    3716     ); 
    3717 } 
    3718  
    3719 #| $web | web and  | 
    3720 #| $topic | topic to display the name for | 
    3721 #| $formatString | format string (like in search) | 
    3722 sub REVINFO { 
    3723     my ( $this, $params, $topicObject ) = @_; 
    3724     my $format = $params->{_DEFAULT} || $params->{format}; 
    3725     my $web    = $params->{web}      || $topicObject->web; 
    3726     my $topic  = $params->{topic}    || $topicObject->topic; 
    3727     my $cgiQuery = $this->{request}; 
    3728     my $cgiRev   = ''; 
    3729     $cgiRev = $cgiQuery->param('rev') if ($cgiQuery); 
    3730     my $rev = $params->{rev} || $cgiRev || ''; 
    3731  
    3732     ( $web, $topic ) = $this->normalizeWebTopicName( $web, $topic ); 
    3733     if ( $web ne $topicObject->web || $topic ne $topicObject->topic ) { 
    3734         $topicObject = Foswiki::Meta->new( $this, $web, $topic ); 
    3735         unless ( $topicObject->haveAccess('VIEW') ) { 
    3736             return $this->inlineAlert( 'alerts', 'access_denied', $web, 
    3737                 $topic ); 
    3738         } 
    3739     } 
    3740  
    3741     return $this->renderer->renderRevisionInfo( $topicObject, $rev, $format ); 
    3742 } 
    3743  
    3744 sub REVTITLE { 
    3745     my ( $this, $params, $topicObject ) = @_; 
    3746     my $request = $this->{request}; 
    3747     my $out     = ''; 
    3748     if ($request) { 
    3749         my $rev = $request->param('rev'); 
    3750         $out = '(r' . $rev . ')' if ($rev); 
    3751     } 
    3752     return $out; 
    3753 } 
    3754  
    3755 sub REVARG { 
    3756     my ( $this, $params ) = @_; 
    3757     my $request = $this->{request}; 
    3758     my $out     = ''; 
    3759     if ($request) { 
    3760         my $rev = $request->param('rev'); 
    3761         $out = '&rev=' . $rev if ($rev); 
    3762     } 
    3763     return $out; 
    3764 } 
    3765  
    3766 sub ENCODE { 
    3767     my ( $this, $params ) = @_; 
    3768     my $type = $params->{type} || 'url'; 
    3769  
    3770     # Value 0 can be valid input so we cannot use simple = || '' 
    3771     my $text = defined( $params->{_DEFAULT} ) ? $params->{_DEFAULT} : ''; 
    3772     return _encode( $type, $text ); 
    3773 } 
    3774  
    3775 sub _encode { 
    3776     my ( $type, $text ) = @_; 
    3777  
    3778     if ( $type =~ /^entit(y|ies)$/i ) { 
    3779         return entityEncode($text); 
    3780     } 
    3781     elsif ( $type =~ /^html$/i ) { 
    3782         return entityEncode( $text, "\n\r" ); 
    3783     } 
    3784     elsif ( $type =~ /^quotes?$/i ) { 
    3785  
    3786         # escape quotes with backslash (Bugs:Item3383 fix) 
    3787         $text =~ s/\"/\\"/go; 
    3788         return $text; 
    3789     } 
    3790     elsif ( $type =~ /^url$/i ) { 
    3791         $text =~ s/\r*\n\r*/<br \/>/;    # Legacy. 
    3792         return urlEncode($text); 
    3793     } 
    3794     elsif ( $type =~ /^(off|none)$/i ) { 
    3795  
    3796         # no encoding 
    3797         return $text; 
    3798     } 
    3799     else {                               # safe or default 
    3800                                          # entity encode ' " < > and % 
    3801         $text =~ s/([<>%'"])/'&#'.ord($1).';'/ge; 
    3802         return $text; 
    3803     } 
    3804 } 
    3805  
    3806 sub ENV { 
    3807     my ( $this, $params ) = @_; 
    3808  
    3809     my $key = $params->{_DEFAULT}; 
    3810     return '' 
    3811       unless $key 
    3812           && defined $Foswiki::cfg{AccessibleENV} 
    3813           && $key =~ /$Foswiki::cfg{AccessibleENV}/o; 
    3814     my $val; 
    3815     if ( $key =~ /^HTTPS?_(\w+)/ ) { 
    3816         $val = $this->{request}->header($1); 
    3817     } 
    3818     elsif ( $key eq 'REQUEST_METHOD' ) { 
    3819         $val = $this->{request}->method; 
    3820     } 
    3821     elsif ( $key eq 'REMOTE_USER' ) { 
    3822         $val = $this->{request}->remoteUser; 
    3823     } 
    3824     elsif ( $key eq 'REMOTE_ADDR' ) { 
    3825         $val = $this->{request}->remoteAddress; 
    3826     } 
    3827     else { 
    3828  
    3829         # TSA SMELL: Foswiki::Request doesn't support 
    3830         # SERVER_\w+, REMOTE_HOST and REMOTE_IDENT. 
    3831         # Use %ENV as fallback, but for ones above 
    3832         # wil probably not behave as expected if 
    3833         # running with non-CGI engine. 
    3834         $val = $ENV{$key}; 
    3835     } 
    3836     return defined $val ? $val : 'not set'; 
    3837 } 
    3838  
    3839 sub SEARCH { 
    3840     my ( $this, $params, $topicObject ) = @_; 
    3841  
    3842     # pass on all attrs, and add some more 
    3843     #$params->{_callback} = undef; 
    3844     $params->{inline}    = 1; 
    3845     $params->{baseweb}   = $topicObject->web; 
    3846     $params->{basetopic} = $topicObject->topic; 
    3847     $params->{search}    = $params->{_DEFAULT} if defined $params->{_DEFAULT}; 
    3848     $params->{type}      = $this->{prefs}->getPreference('SEARCHVARDEFAULTTYPE') 
    3849       unless ( $params->{type} ); 
    3850     my $s; 
    3851     try { 
    3852         $s = $this->search->searchWeb(%$params); 
    3853     } 
    3854     catch Error::Simple with { 
    3855         my $message = (DEBUG) ? shift->stringify() : shift->{-text}; 
    3856  
    3857         # Block recursions kicked off by the text being repeated in the 
    3858         # error message 
    3859         $message =~ s/%([A-Z]*[{%])/%<nop>$1/g; 
    3860         $s = $this->inlineAlert( 'alerts', 'bad_search', $message ); 
    3861     }; 
    3862  
    3863     return $s; 
    3864 } 
    3865  
    3866 sub FOREACH { 
    3867     my ( $this, $params, $topicObject ) = @_; 
    3868  
    3869     # pass on all attrs, and add some more 
    3870     #$params->{_callback} = undef; 
    3871     $params->{inline}    = 1; 
    3872     $params->{baseweb}   = $topicObject->web; 
    3873     $params->{basetopic} = $topicObject->topic; 
    3874     $params->{search}    = $params->{_DEFAULT} if defined $params->{_DEFAULT}; 
    3875     $params->{type}      = $this->{prefs}->getPreference('SEARCHVARDEFAULTTYPE') 
    3876       unless ( $params->{type} ); 
    3877 #    $params->{format}      = '$topic'  unless ( defined($params->{format}) ); 
    3878 #TODO: change to $n some time. 
    3879     $params->{separator}      = "\n"  unless ( defined($params->{separator}) ); 
    3880 #    $params->{header}      = ''  unless ( $params->{header} ); 
    3881 #    $params->{footer}      = ''  unless ( $params->{footer} ); 
    3882     my $s; 
    3883     try { 
    3884         my $webObject = Foswiki::Meta->new( $this, $params->{baseweb} ); 
    3885         my $topicString = $params->{_DEFAULT} || ''; 
    3886         #from Search::_makeTopicPattern (plus an added . to allow web.topic) 
    3887         my @topics = map { s/[^\*\_\-\+\.$Foswiki::regex{mixedAlphaNum}]//go; s/\*/\.\*/go; $_ } 
    3888             split( /,\s*/, $topicString ); 
    3889  
    3890         my $query;  #query node 
    3891         my $searchString = ''; 
    3892         require Foswiki::Search::InfoCache; 
    3893         my $infoCache = new Foswiki::Search::InfoCache($this, $params->{baseweb}, \@topics); 
    3894         my ( $ttopics, $searchResult, $tmplTail ) = $this->search->formatResults($webObject, $query, $searchString, $infoCache, $params); 
    3895         $s = $searchResult; 
    3896     } 
    3897     catch Error::Simple with { 
    3898         my $message = (DEBUG) ? shift->stringify() : shift->{-text}; 
    3899  
    3900         # Block recursions kicked off by the text being repeated in the 
    3901         # error message 
    3902         $message =~ s/%([A-Z]*[{%])/%<nop>$1/g; 
    3903         $s = $this->inlineAlert( 'alerts', 'bad_search', $message ); 
    3904     }; 
    3905     return $s; 
    3906 } 
    3907  
    3908 sub WEBLIST { 
    3909     my ( $this, $params ) = @_; 
    3910  
    3911     # List of webs to consider; default is all public webs 
    3912     my $webs = $params->{webs} || 'public'; 
    3913     my @webslist = split( /,\s*/, $webs ); 
    3914  
    3915     # Modifier on "public" and "webtemplate" pseudo-webs 
    3916     my $rootWeb = $params->{subwebs}; 
    3917  
    3918     # the web= parameter, *not* the web being listed 
    3919     my $web = $params->{web} || ''; 
    3920     $web =~ s#\.#/#go; 
    3921  
    3922     # Output format 
    3923     my $format = $params->{_DEFAULT} || $params->{'format'} || '$name'; 
    3924     $format ||= '$name'; 
    3925  
    3926     my $separator = $params->{separator} || "\n"; 
    3927     $separator =~ s/\$n/\n/; 
    3928  
    3929     my $selection = $params->{selection} || ''; 
    3930     $selection =~ s/\,/ /g; 
    3931     $selection = " $selection "; 
    3932  
    3933     my $marker = $params->{marker} || 'selected="selected"'; 
    3934  
    3935     my @list = (); 
    3936     foreach my $aweb (@webslist) { 
    3937         if ( $aweb =~ /^(public|webtemplate)$/ ) { 
    3938             require Foswiki::WebFilter; 
    3939             my $filter; 
    3940             if ( $aweb eq 'public' ) { 
    3941                 $filter = new Foswiki::WebFilter('user,public,allowed'); 
    3942             } 
    3943             elsif ( $aweb eq 'webtemplate' ) { 
    3944                 $filter = new Foswiki::WebFilter('template,allowed'); 
    3945             } 
    3946             push( @list, $this->deepWebList( $filter, $rootWeb ) ); 
    3947         } 
    3948         else { 
    3949             push( @list, $aweb ) if ( $this->webExists($aweb) ); 
    3950         } 
    3951     } 
    3952  
    3953     my @items; 
    3954     foreach my $item (@list) { 
    3955         my $line = $format; 
    3956         $line =~ s/\$web\b/$web/g; 
    3957         $line =~ s/\$name\b/$item/g; 
    3958         $line =~ s/\$qname/"$item"/g; 
    3959         my $indenteditem = $item; 
    3960         $indenteditem =~ s#/$##g; 
    3961         $indenteditem =~ s#\w+/#%TMPL:P{"webListIndent"}%#g; 
    3962         $line         =~ s/\$indentedname/$indenteditem/g; 
    3963         my $mark = ( $selection =~ / \Q$item\E / ) ? $marker : ''; 
    3964         $line =~ s/\$marker/$mark/g; 
    3965         push( @items, $line ); 
    3966     } 
    3967     return join( $separator, @items ); 
    3968 } 
    3969  
    3970 sub TOPICLIST { 
    3971     my ( $this, $params ) = @_; 
    3972     my $format = $params->{_DEFAULT} || $params->{'format'} || '$topic'; 
    3973     my $separator = $params->{separator} || "\n"; 
    3974     $separator =~ s/\$n/\n/; 
    3975     my $selection = $params->{selection} || ''; 
    3976     $selection =~ s/\,/ /g; 
    3977     $selection = " $selection "; 
    3978     my $marker = $params->{marker} || 'selected="selected"'; 
    3979  
    3980     my $web = $params->{web} || $this->{webName}; 
    3981     $web =~ s#\.#/#go; 
    3982  
    3983     my $webObject = Foswiki::Meta->new( $this, $web ); 
    3984     return '' 
    3985       if $web ne $this->{webName} 
    3986           && $webObject->getPreference('NOSEARCHALL'); 
    3987  
    3988     my @items; 
    3989     my $it = $webObject->eachTopic(); 
    3990     while ( $it->hasNext() ) { 
    3991         my $item = $it->next(); 
    3992         my $line = $format; 
    3993         $line =~ s/\$web\b/$web/g; 
    3994         $line =~ s/\$topic\b/$item/g; 
    3995         $line =~ s/\$name\b/$item/g;     # Undocumented, DO NOT REMOVE 
    3996         $line =~ s/\$qname/"$item"/g;    # Undocumented, DO NOT REMOVE 
    3997         my $mark = ( $selection =~ / \Q$item\E / ) ? $marker : ''; 
    3998         $line =~ s/\$marker/$mark/g; 
    3999         $line = expandStandardEscapes($line); 
    4000         push( @items, $line ); 
    4001     } 
    4002     return join( $separator, @items ); 
    4003 } 
    4004  
    4005 sub QUERYSTRING { 
    4006     my $this = shift; 
    4007     return $this->{request}->queryString(); 
    4008 } 
    4009  
    4010 sub QUERYPARAMS { 
    4011     my ( $this, $params ) = @_; 
    4012     return '' unless $this->{request}; 
    4013     my $format = 
    4014       defined $params->{format} 
    4015       ? $params->{format} 
    4016       : '$name=$value'; 
    4017     my $separator = defined $params->{separator} ? $params->{separator} : "\n"; 
    4018     my $encoding = $params->{encoding} || 'safe'; 
    4019  
    4020     my @list; 
    4021     foreach my $name ( $this->{request}->param() ) { 
    4022  
    4023         # Issues multi-valued parameters as separate hiddens 
    4024         my $value = $this->{request}->param($name); 
    4025         $value = '' unless defined $value; 
    4026         $name  = _encode( $encoding, $name ); 
    4027         $value = _encode( $encoding, $value ); 
    4028  
    4029         my $entry = $format; 
    4030         $entry =~ s/\$name/$name/g; 
    4031         $entry =~ s/\$value/$value/; 
    4032         push( @list, $entry ); 
    4033     } 
    4034     return join( $separator, @list ); 
    4035 } 
    4036  
    4037 sub URLPARAM { 
    4038     my ( $this, $params ) = @_; 
    4039     my $param     = $params->{_DEFAULT} || ''; 
    4040     my $newLine   = $params->{newline}; 
    4041     my $encode    = $params->{encode} || 'safe'; 
    4042     my $multiple  = $params->{multiple}; 
    4043     my $separator = $params->{separator}; 
    4044     $separator = "\n" unless ( defined $separator ); 
    4045  
    4046     my $value; 
    4047     if ( $this->{request} ) { 
    4048         if ( Foswiki::isTrue($multiple) ) { 
    4049             my @valueArray = $this->{request}->param($param); 
    4050             if (@valueArray) { 
    4051  
    4052                 # join multiple values properly 
    4053                 unless ( $multiple =~ m/^on$/i ) { 
    4054                     my $item = ''; 
    4055                     @valueArray = map { 
    4056                         $item = $_; 
    4057                         $_    = $multiple; 
    4058                         $_ .= $item unless (s/\$item/$item/go); 
    4059                         $_ 
    4060                     } @valueArray; 
    4061                 } 
    4062                 $value = join( $separator, @valueArray ); 
    4063             } 
    4064         } 
    4065         else { 
    4066             $value = $this->{request}->param($param); 
    4067         } 
    4068     } 
    4069     if ( defined $value ) { 
    4070         $value =~ s/\r?\n/$newLine/go if ( defined $newLine ); 
    4071         if ( $encode =~ /^entit(y|ies)$/i ) { 
    4072             $value = entityEncode($value); 
    4073         } 
    4074         elsif ( $encode =~ /^quotes?$/i ) { 
    4075             $value =~ 
    4076               s/\"/\\"/go;    # escape quotes with backslash (Bugs:Item3383 fix) 
    4077         } 
    4078         elsif ( $encode =~ /^(off|none)$/i ) { 
    4079  
    4080             # no encoding 
    4081         } 
    4082         elsif ( $encode =~ /^url$/i ) { 
    4083             $value =~ s/\r*\n\r*/<br \/>/;    # Legacy 
    4084             $value = urlEncode($value); 
    4085         } 
    4086         else {                                # safe or default 
    4087                                               # entity encode ' " < > and % 
    4088             $value =~ s/([<>%'"])/'&#'.ord($1).';'/ge; 
    4089         } 
    4090     } 
    4091     unless ( defined $value ) { 
    4092         $value = $params->{default}; 
    4093         $value = '' unless defined $value; 
    4094     } 
    4095  
    4096     # Block expansion of %URLPARAM in the value to prevent recursion 
    4097     $value =~ s/%URLPARAM{/%<nop>URLPARAM{/g; 
    4098     return $value; 
    4099 } 
    4100  
    4101 # This routine was introduced to URL encode Mozilla UTF-8 POST URLs in the 
    4102 # TWiki Feb2003 release - encoding is no longer needed since UTF-URLs are now 
    4103 # directly supported, but it is provided for backward compatibility with 
    4104 # skins that may still be using the deprecated %INTURLENCODE%. 
    4105 sub INTURLENCODE_deprecated { 
    4106     my ( $this, $params ) = @_; 
    4107  
    4108     # Just strip double quotes, no URL encoding - Mozilla UTF-8 URLs 
    4109     # directly supported now 
    4110     return $params->{_DEFAULT} || ''; 
    4111 } 
    4112  
    4113 # This routine is deprecated as of DakarRelease, 
    4114 # and is maintained only for backward compatibility. 
    4115 # Spacing of WikiWords is now done with %SPACEOUT% 
    4116 # (and the private routine _SPACEOUT). 
    4117 # Move to compatibility module in Foswiki 2.0 
    4118 sub SPACEDTOPIC_deprecated { 
    4119     my ( $this, $params, $topicObject ) = @_; 
    4120     my $topic = spaceOutWikiWord( $topicObject->topic ); 
    4121     $topic =~ s/ / */g; 
    4122     return urlEncode($topic); 
    4123 } 
    4124  
    4125 sub SPACEOUT { 
    4126     my ( $this, $params ) = @_; 
    4127     my $spaceOutTopic = $params->{_DEFAULT}; 
    4128     my $sep           = $params->{'separator'}; 
    4129     $spaceOutTopic = spaceOutWikiWord( $spaceOutTopic, $sep ); 
    4130     return $spaceOutTopic; 
    4131 } 
    4132  
    4133 sub ICON { 
    4134     my ( $this, $params ) = @_; 
    4135     my $file = $params->{_DEFAULT} || ''; 
    4136  
    4137     # Try to map the file name to see if there is a matching filetype image 
    4138     # If no mapping could be found, use the file name that was passed 
    4139     my $iconFileName = $this->mapToIconFileName( $file, $file ); 
    4140     return '' unless $iconFileName; 
    4141     return $this->renderer->renderIconImage( 
    4142         $this->getIconUrl( 0, $iconFileName ), 
    4143         $iconFileName ); 
    4144 } 
    4145  
    4146 sub ICONURL { 
    4147     my ( $this, $params ) = @_; 
    4148     my $file = ( $params->{_DEFAULT} || '' ); 
    4149  
    4150     return $this->getIconUrl( 1, $file ); 
    4151 } 
    4152  
    4153 sub ICONURLPATH { 
    4154     my ( $this, $params ) = @_; 
    4155     my $file = ( $params->{_DEFAULT} || '' ); 
    4156  
    4157     return $this->getIconUrl( 0, $file ); 
    4158 } 
    4159  
    4160 sub RELATIVETOPICPATH { 
    4161     my ( $this, $params, $topicObject ) = @_; 
    4162     my $topic = $params->{_DEFAULT}; 
    4163  
    4164     return '' unless $topic; 
    4165  
    4166     my $relPath; 
    4167  
    4168     # if there is no dot in $topicObject->topic, no web has been specified 
    4169     if ( index( $topic, '.' ) == -1 ) { 
    4170  
    4171         # add local web 
    4172         $relPath = $topicObject->web() . '/' . $topic; 
    4173     } 
    4174     else { 
    4175         $relPath = $topic;    #including dot 
    4176     } 
    4177  
    4178     # replace dot by slash is not necessary; System.MyTopic is a valid url 
    4179     # add ../ if not already present to make a relative file reference 
    4180     if ( $relPath !~ m!^../! ) { 
    4181         $relPath = "../$relPath"; 
    4182     } 
    4183     return $relPath; 
    4184 } 
    4185  
    4186 sub ATTACHURLPATH { 
    4187     my ( $this, $params, $topicObject ) = @_; 
    4188     return $this->getPubUrl( 0, $topicObject->web, $topicObject->topic ); 
    4189 } 
    4190  
    4191 sub ATTACHURL { 
    4192     my ( $this, $params, $topicObject ) = @_; 
    4193     return $this->getPubUrl( 1, $topicObject->web, $topicObject->topic ); 
    4194 } 
    4195  
    4196 sub LANGUAGE { 
    4197     my $this = shift; 
    4198     return $this->i18n->language(); 
    4199 } 
    4200  
    4201 sub LANGUAGES { 
    4202     my ( $this, $params ) = @_; 
    4203     my $format    = $params->{format}    || "   * \$langname"; 
    4204     my $separator = $params->{separator} || "\n"; 
    4205     $separator =~ s/\\n/\n/g; 
    4206     my $selection = $params->{selection} || ''; 
    4207     $selection =~ s/\,/ /g; 
    4208     $selection = " $selection "; 
    4209     my $marker = $params->{marker} || 'selected="selected"'; 
    4210  
    4211     # $languages is a hash reference: 
    4212     my $languages = $this->i18n->enabled_languages(); 
    4213  
    4214     my @tags = sort( keys( %{$languages} ) ); 
    4215  
    4216     my $result = ''; 
    4217     my $i      = 0; 
    4218     foreach my $lang (@tags) { 
    4219         my $item = $format; 
    4220         my $name = ${$languages}{$lang}; 
    4221         $item =~ s/\$langname/$name/g; 
    4222         $item =~ s/\$langtag/$lang/g; 
    4223         my $mark = ( $selection =~ / \Q$lang\E / ) ? $marker : ''; 
    4224         $item =~ s/\$marker/$mark/g; 
    4225         $result .= $separator if $i; 
    4226         $result .= $item; 
    4227         $i++; 
    4228     } 
    4229  
    4230     return $result; 
    4231 } 
    4232  
    4233 sub MAKETEXT { 
    4234     my ( $this, $params ) = @_; 
    4235  
    4236     my $str = $params->{_DEFAULT} || $params->{string} || ""; 
    4237     return "" unless $str; 
    4238  
    4239     # escape everything: 
    4240     $str =~ s/\[/~[/g; 
    4241     $str =~ s/\]/~]/g; 
    4242  
    4243     # restore already escaped stuff: 
    4244     $str =~ s/~~\[/~[/g; 
    4245     $str =~ s/~~\]/~]/g; 
    4246  
    4247     # unescape parameters and calculate highest parameter number: 
    4248     my $max = 0; 
    4249     $str =~ s/~\[(\_(\d+))~\]/ $max = $2 if ($2 > $max); "[$1]"/ge; 
    4250     $str =~ 
    4251 s/~\[(\*,\_(\d+),[^,]+(,([^,]+))?)~\]/ $max = $2 if ($2 > $max); "[$1]"/ge; 
    4252  
    4253     # get the args to be interpolated. 
    4254     my $argsStr = $params->{args} || ""; 
    4255  
    4256     my @args = split( /\s*,\s*/, $argsStr ); 
    4257  
    4258     # fill omitted args with zeros 
    4259     while ( ( scalar @args ) < $max ) { 
    4260         push( @args, 0 ); 
    4261     } 
    4262  
    4263     # do the magic: 
    4264     my $result = $this->i18n->maketext( $str, @args ); 
    4265  
    4266     # replace accesskeys: 
    4267     $result =~ 
    4268       s#(^|[^&])&([a-zA-Z])#$1<span class='foswikiAccessKey'>$2</span>#g; 
    4269  
    4270     # replace escaped amperstands: 
    4271     $result =~ s/&&/\&/g; 
    4272  
    4273     return $result; 
    4274 } 
    4275  
    4276 sub SCRIPTNAME { 
    4277     return $_[0]->{request}->action; 
    4278 } 
    4279  
    4280 sub SCRIPTURL { 
    4281     my ( $this, $params ) = @_; 
    4282     my $script = $params->{_DEFAULT} || ''; 
    4283  
    4284     return $this->getScriptUrl( 1, $script ); 
    4285 } 
    4286  
    4287 sub SCRIPTURLPATH { 
    4288     my ( $this, $params ) = @_; 
    4289     my $script = $params->{_DEFAULT} || ''; 
    4290  
    4291     return $this->getScriptUrl( 0, $script ); 
    4292 } 
    4293  
    4294 sub PUBURL { 
    4295     my $this = shift; 
    4296     return $this->getPubUrl(1); 
    4297 } 
    4298  
    4299 sub PUBURLPATH { 
    4300     my $this = shift; 
    4301     return $this->getPubUrl(0); 
    4302 } 
    4303  
    4304 sub ALLVARIABLES { 
    4305     return shift->{prefs}->stringify(); 
    4306 } 
    4307  
    4308 # Poor-man's content access. 
    4309 sub META { 
    4310     my ( $this, $params, $topicObject ) = @_; 
    4311      
    4312     $topicObject->reload() unless $topicObject->getLoadedRev(); 
    4313  
    4314     my $option = $params->{_DEFAULT} || ''; 
    4315  
    4316     if ( $option eq 'form' ) { 
    4317  
    4318         # META:FORM and META:FIELD 
    4319         return $topicObject->renderFormForDisplay(); 
    4320     } 
    4321     elsif ( $option eq 'formfield' ) { 
    4322  
    4323         # a formfield from within topic text 
    4324         return $topicObject->renderFormFieldForDisplay( $params->get('name'), 
    4325             '$value', $params ); 
    4326     } 
    4327     elsif ( $option eq 'attachments' ) { 
    4328  
    4329         # renders attachment tables 
    4330         return $this->attach->renderMetaData( $topicObject, $params ); 
    4331     } 
    4332     elsif ( $option eq 'moved' ) { 
    4333         return $this->renderer->renderMoved( $topicObject, $params ); 
    4334     } 
    4335     elsif ( $option eq 'parent' ) { 
    4336  
    4337         # Only parent parameter has the format option and should do std escapes 
    4338         return expandStandardEscapes( 
    4339             $this->renderer->renderParent( $topicObject, $params ) ); 
    4340     } 
    4341  
    4342     # return nothing if invalid parameter 
    4343     return ''; 
    4344 } 
    4345  
    4346 # Remove NOP tag in template topics but show content. Used in template 
    4347 # _topics_ (not templates, per se, but topics used as templates for new 
    4348 # topics) 
    4349 sub NOP { 
    4350     my ( $this, $params ) = @_; 
    4351  
    4352     return '<nop>' unless $params->{_RAW}; 
    4353  
    4354     return $params->{_RAW}; 
    4355 } 
    4356  
    4357 # Shortcut to %TMPL:P{"sep"}% 
    4358 sub SEP { 
    4359     my $this = shift; 
    4360     return $this->templates->expandTemplate('sep'); 
    4361 } 
    4362  
    4363 #deprecated functionality, now implemented using %USERINFO% 
    4364 #move to compatibility plugin in Foswiki 2.0 
    4365 sub WIKINAME_deprecated { 
    4366     my ( $this, $params ) = @_; 
    4367  
    4368     $params->{format} = $this->{prefs}->getPreference('WIKINAME') 
    4369       || '$wikiname'; 
    4370  
    4371     return $this->USERINFO($params); 
    4372 } 
    4373  
    4374 #deprecated functionality, now implemented using %USERINFO% 
    4375 #move to compatibility plugin in Foswiki 2.0 
    4376 sub USERNAME_deprecated { 
    4377     my ( $this, $params ) = @_; 
    4378  
    4379     $params->{format} = $this->{prefs}->getPreference('USERNAME') 
    4380       || '$username'; 
    4381  
    4382     return $this->USERINFO($params); 
    4383 } 
    4384  
    4385 #deprecated functionality, now implemented using %USERINFO% 
    4386 #move to compatibility plugin in Foswiki 2.0 
    4387 sub WIKIUSERNAME_deprecated { 
    4388     my ( $this, $params ) = @_; 
    4389  
    4390     $params->{format} = $this->{prefs}->getPreference('WIKIUSERNAME') 
    4391       || '$wikiusername'; 
    4392  
    4393     return $this->USERINFO($params); 
    4394 } 
    4395  
    4396 sub USERINFO { 
    4397     my ( $this, $params ) = @_; 
    4398     my $format = $params->{format} || '$username, $wikiusername, $emails'; 
    4399  
    4400     my $user = $this->{user}; 
    4401  
    4402     if ( $params->{_DEFAULT} ) { 
    4403         $user = $params->{_DEFAULT}; 
    4404         return '' if !$user; 
    4405  
    4406         # map wikiname to a login name 
    4407         $user = $this->{users}->getCanonicalUserID($user); 
    4408         return '' unless $user; 
    4409         return '' 
    4410           if ( $Foswiki::cfg{AntiSpam}{HideUserDetails} 
    4411             && !$this->{users}->isAdmin( $this->{user} ) 
    4412             && $user ne $this->{user} ); 
    4413     } 
    4414  
    4415     return '' unless $user; 
    4416  
    4417     my $info = $format; 
    4418  
    4419     if ( $info =~ /\$username/ ) { 
    4420         my $username = $this->{users}->getLoginName($user); 
    4421         $username = 'unknown' unless defined $username; 
    4422         $info =~ s/\$username/$username/g; 
    4423     } 
    4424     if ( $info =~ /\$wikiname/ ) { 
    4425         my $wikiname = $this->{users}->getWikiName($user); 
    4426         $wikiname = 'UnknownUser' unless defined $wikiname; 
    4427         $info =~ s/\$wikiname/$wikiname/g; 
    4428     } 
    4429     if ( $info =~ /\$wikiusername/ ) { 
    4430         my $wikiusername = $this->{users}->webDotWikiName($user); 
    4431         $wikiusername = "$Foswiki::cfg{UsersWebName}.UnknownUser" 
    4432           unless defined $wikiusername; 
    4433         $info =~ s/\$wikiusername/$wikiusername/g; 
    4434     } 
    4435     if ( $info =~ /\$emails/ ) { 
    4436         my $emails = join( ', ', $this->{users}->getEmails($user) ); 
    4437         $info =~ s/\$emails/$emails/g; 
    4438     } 
    4439     if ( $info =~ /\$groups/ ) { 
    4440         my @groupNames; 
    4441         my $it = $this->{users}->eachMembership($user); 
    4442         while ( $it->hasNext() ) { 
    4443             my $group = $it->next(); 
    4444             push( @groupNames, $group ); 
    4445         } 
    4446         my $groups = join( ', ', @groupNames ); 
    4447         $info =~ s/\$groups/$groups/g; 
    4448     } 
    4449     if ( $info =~ /\$cUID/ ) { 
    4450         my $cUID = $user; 
    4451         $info =~ s/\$cUID/$cUID/g; 
    4452     } 
    4453     if ( $info =~ /\$admin/ ) { 
    4454         my $admin = $this->{users}->isAdmin($user) ? 'true' : 'false'; 
    4455         $info =~ s/\$admin/$admin/g; 
    4456     } 
    4457  
    4458     return $info; 
    4459 } 
    4460  
    4461 sub GROUPINFO { 
    4462     my ( $this, $params ) = @_; 
    4463  
    4464     my $group = $params->{_DEFAULT}; 
    4465     my $format = $params->{format}; 
    4466     my $sep = $params->{separator}; $sep = ', ' unless defined $sep; 
    4467     my $limit = $params->{limit} || 100000000; 
    4468     my $limited = $params->{limited}; $limited = '' unless defined $limited; 
    4469     my $header = $params->{header}; $header = '' unless defined $header; 
    4470     my $footer = $params->{footer}; $footer = '' unless defined $footer; 
    4471  
    4472     my $it;#erator 
    4473     my @rows; 
    4474     if ($group) { 
    4475         $it = $this->{users}->eachGroupMember($group); 
    4476         $format = '$wikiusername' unless defined $format; 
    4477     } else { 
    4478         $it = $this->{users}->eachGroup(); 
    4479         $format = '$name' unless defined $format; 
    4480     } 
    4481     while ($it->hasNext()) { 
    4482         my $cUID = $it->next(); 
    4483         my $row = $format; 
    4484         if ($group) { 
    4485             next unless($this->{users}->groupAllowsView( $group )); 
    4486             my $wname = $this->{users}->getWikiName( $cUID ); 
    4487             my $uname = $this->{users}->getLoginName( $cUID ); 
    4488             my $wuname = $this->{users}->webDotWikiName( $cUID ); 
    4489             my $change = $this->{users}->groupAllowsChange( $group ); 
    4490  
    4491             $row =~ s/\$wikiname/$wname/ge; 
    4492             $row =~ s/\$username/$uname/ge; 
    4493             $row =~ s/\$wikiusername/$wuname/ge; 
    4494             $row =~ s/\$name/$group/g; 
    4495             $row =~ s/\$allowschange/$change/ge; 
    4496         } else { 
    4497             # all groups 
    4498             next unless($this->{users}->groupAllowsView( $cUID )); 
    4499             my $change = $this->{users}->groupAllowsChange( $cUID ); 
    4500              
    4501             $row =~ s/\$name/$cUID/g; 
    4502             $row =~ s/\$allowschange/$change/ge; 
    4503         } 
    4504         push(@rows, $row); 
    4505         last if (--$limit == 0); 
    4506     } 
    4507     $footer = $limited.$footer if $limit == 0; 
    4508     return expandStandardEscapes($header.join($sep, @rows).$footer); 
    4509 } 
    4510  
    4511 # Legacy 
    4512 sub GROUPS { 
    4513     my ( $this, $params ) = @_; 
    4514  
    4515     my $groups = $this->{users}->eachGroup(); 
    4516     my @table; 
    4517     while ( $groups->hasNext() ) { 
    4518         my $group = $groups->next(); 
    4519  
    4520         # Nop it to prevent wikiname expansion unless the topic exists. 
    4521         my $groupLink = "<nop>$group"; 
    4522         $groupLink = '[[' . $Foswiki::cfg{UsersWebName} . ".$group][$group]]" 
    4523           if ( $this->topicExists( $Foswiki::cfg{UsersWebName}, $group ) ); 
    4524         my $descr        = "| $groupLink |"; 
    4525         my $it           = $this->{users}->eachGroupMember($group); 
    4526         my $limit_output = 32; 
    4527         while ( $it->hasNext() ) { 
    4528             my $user = $it->next(); 
    4529             $descr .= ' [[' 
    4530               . $this->{users}->webDotWikiName($user) . '][' 
    4531               . $this->{users}->getWikiName($user) . ']]'; 
    4532             if ( $limit_output == 0 ) { 
    4533                 $descr .= '<div>%MAKETEXT{"user list truncated"}%</div>'; 
    4534                 last; 
    4535             } 
    4536             $limit_output--; 
    4537         } 
    4538         push( @table, "$descr |" ); 
    4539     } 
    4540  
    4541     return '| *Group* | *Members* |' . "\n" . join( "\n", sort @table ); 
    4542 } 
    4543  
    4544 sub DISPLAYDEPENDENCIES { 
    4545     my ( $this, $params ) = @_; 
    4546  
    4547     my $web = $params->{web} || $this->{webName}; 
    4548     my $topic = $params->{topic} || $this->{topicName}; 
    4549     my $header = $params->{header} || ''; 
    4550     my $footer = $params->{footer} || ''; 
    4551     my $format = $params->{format} || '   1 [[$web.$topic]]'; 
    4552     my $separator = $params->{sep} || $params->{separator} || "\n"; 
    4553     my $exclude = $params->{exclude}; 
    4554  
    4555     ($web, $topic) = $this->normalizeWebTopicName($web, $topic); 
    4556  
    4557     my $deps = $this->{cache}->getDependencies($web, $topic); 
    4558     my @lines; 
    4559     my $thisWeb; 
    4560     my $thisTopic; 
    4561     foreach my $dep (sort @$deps) { 
    4562       next if $exclude && $dep =~ /$exclude/; 
    4563       $dep =~ /^(.*)[\.\/](.*?)$/; 
    4564       $thisWeb = $1; 
    4565       $thisTopic = $2; 
    4566       my $text = $format; 
    4567       $text =~ s/\$web/$thisWeb/g; 
    4568       $text =~ s/\$topic/$thisTopic/g; 
    4569       push @lines, $text; 
    4570     } 
    4571     return '' unless @lines; 
    4572     return expandStandardEscapes($header.join($separator, @lines).$footer); 
    4573 } 
    4574  
    4575 sub SHOWPREFERENCE { 
    4576     my ( $this, $params ) = @_; 
    4577     my $tml = ''; 
    4578     if ( $params->{_DEFAULT} ) { 
    4579         foreach my $preference ( split( /[, ]+/, $params->{_DEFAULT} ) ) { 
    4580             $tml .= $this->{prefs}->stringify($preference); 
    4581         } 
    4582     } 
    4583     else { 
    4584         $tml = $this->{prefs}->stringify(); 
    4585     } 
    4586     return $tml; 
    4587 } 
    4588  
    458932571; 
    45903258__DATA__ 
    4591 # Foswiki - The Free and Open Source Wiki, http://foswiki.org/ 
    4592 # 
    4593 # Copyright (C) 2008 Foswiki Contributors. Foswiki Contributors 
    4594 # are listed in the AUTHORS file in the root of this distribution. 
    4595 # NOTE: Please extend that file, not this notice. 
    4596 # 
    4597 # Additional copyrights apply to some or all of the code in this 
    4598 # file as follows: 
    4599 # 
    4600 # Copyright (C) 1999-2007 Peter Thoeny, peter@thoeny.org 
    4601 # and TWiki Contributors. All Rights Reserved. TWiki Contributors 
    4602 # are listed in the AUTHORS file in the root of this distribution. 
    4603 # Based on parts of Ward Cunninghams original Wiki and JosWiki. 
    4604 # Copyright (C) 1998 Markus Peter - SPiN GmbH (warpi@spin.de) 
    4605 # Some changes by Dave Harris (drh@bhresearch.co.uk) incorporated 
    4606 # 
    4607 # This program is free software; you can redistribute it and/or 
    4608 # modify it under the terms of the GNU General Public License 
    4609 # as published by the Free Software Foundation; either version 2 
    4610 # of the License, or (at your option) any later version. For 
    4611 # more details read LICENSE in the root of this distribution. 
    4612 # 
    4613 # This program is distributed in the hope that it will be useful, 
    4614 # but WITHOUT ANY WARRANTY; without even the implied warranty of 
    4615 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
    4616 # 
    4617 # As per the GPL, removal of this notice is prohibited. 
     3259Foswiki - The Free and Open Source Wiki, http://foswiki.org/ 
     3260 
     3261Copyright (C) 2008-2009 Foswiki Contributors. Foswiki Contributors 
     3262are listed in the AUTHORS file in the root of this distribution. 
     3263NOTE: Please extend that file, not this notice. 
     3264 
     3265Additional copyrights apply to some or all of the code in this 
     3266file as follows: 
     3267 
     3268Copyright (C) 1999-2007 Peter Thoeny, peter@thoeny.org 
     3269and TWiki Contributors. All Rights Reserved. TWiki Contributors 
     3270are listed in the AUTHORS file in the root of this distribution. 
     3271Based on parts of Ward Cunninghams original Wiki and JosWiki. 
     3272Copyright (C) 1998 Markus Peter - SPiN GmbH (warpi@spin.de) 
     3273Some changes by Dave Harris (drh@bhresearch.co.uk) incorporated 
     3274 
     3275This program is free software; you can redistribute it and/or 
     3276modify it under the terms of the GNU General Public License 
     3277as published by the Free Software Foundation; either version 2 
     3278of the License, or (at your option) any later version. For 
     3279more details read LICENSE in the root of this distribution. 
     3280 
     3281This program is distributed in the hope that it will be useful, 
     3282but WITHOUT ANY WARRANTY; without even the implied warranty of 
     3283MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
     3284 
     3285As per the GPL, removal of this notice is prohibited. 
Note: See TracChangeset for help on using the changeset viewer.