• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • Examples
  • File List

E:/E/GEAMP/www/openbiz/openbiz/others/Smarty/libs/Smarty_Compiler.class.php

00001 <?php
00002 
00029 /* $Id: Smarty_Compiler.class.php,v 1.370 2005/08/04 19:43:21 messju Exp $ */
00030 
00035 class Smarty_Compiler extends Smarty {
00036 
00037     // internal vars
00041     var $_folded_blocks         =   array();    // keeps folded template blocks
00042     var $_current_file          =   null;       // the current template being compiled
00043     var $_current_line_no       =   1;          // line number for error messages
00044     var $_capture_stack         =   array();    // keeps track of nested capture buffers
00045     var $_plugin_info           =   array();    // keeps track of plugins to load
00046     var $_init_smarty_vars      =   false;
00047     var $_permitted_tokens      =   array('true','false','yes','no','on','off','null');
00048     var $_db_qstr_regexp        =   null;        // regexps are setup in the constructor
00049     var $_si_qstr_regexp        =   null;
00050     var $_qstr_regexp           =   null;
00051     var $_func_regexp           =   null;
00052     var $_reg_obj_regexp        =   null;
00053     var $_var_bracket_regexp    =   null;
00054     var $_num_const_regexp      =   null;
00055     var $_dvar_guts_regexp      =   null;
00056     var $_dvar_regexp           =   null;
00057     var $_cvar_regexp           =   null;
00058     var $_svar_regexp           =   null;
00059     var $_avar_regexp           =   null;
00060     var $_mod_regexp            =   null;
00061     var $_var_regexp            =   null;
00062     var $_parenth_param_regexp  =   null;
00063     var $_func_call_regexp      =   null;
00064     var $_obj_ext_regexp        =   null;
00065     var $_obj_start_regexp      =   null;
00066     var $_obj_params_regexp     =   null;
00067     var $_obj_call_regexp       =   null;
00068     var $_cacheable_state       =   0;
00069     var $_cache_attrs_count     =   0;
00070     var $_nocache_count         =   0;
00071     var $_cache_serial          =   null;
00072     var $_cache_include         =   null;
00073 
00074     var $_strip_depth           =   0;
00075     var $_additional_newline    =   "\n";
00076 
00081     function Smarty_Compiler()
00082     {
00083         // matches double quoted strings:
00084         // "foobar"
00085         // "foo\"bar"
00086         $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
00087 
00088         // matches single quoted strings:
00089         // 'foobar'
00090         // 'foo\'bar'
00091         $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
00092 
00093         // matches single or double quoted strings
00094         $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
00095 
00096         // matches bracket portion of vars
00097         // [0]
00098         // [foo]
00099         // [$bar]
00100         $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
00101 
00102         // matches numerical constants
00103         // 30
00104         // -12
00105         // 13.22
00106         $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)';
00107 
00108         // matches $ vars (not objects):
00109         // $foo
00110         // $foo.bar
00111         // $foo.bar.foobar
00112         // $foo[0]
00113         // $foo[$bar]
00114         // $foo[5][blah]
00115         // $foo[5].bar[$foobar][4]
00116         $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))';
00117         $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d>\[\]]';
00118         $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
00119                 . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
00120         $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
00121 
00122         // matches config vars:
00123         // #foo#
00124         // #foobar123_foo#
00125         $this->_cvar_regexp = '\#\w+\#';
00126 
00127         // matches section vars:
00128         // %foo.bar%
00129         $this->_svar_regexp = '\%\w+\.\w+\%';
00130 
00131         // matches all valid variables (no quotes, no modifiers)
00132         $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
00133            . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
00134 
00135         // matches valid variable syntax:
00136         // $foo
00137         // $foo
00138         // #foo#
00139         // #foo#
00140         // "text"
00141         // "text"
00142         $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';
00143 
00144         // matches valid object call (one level of object nesting allowed in parameters):
00145         // $foo->bar
00146         // $foo->bar()
00147         // $foo->bar("text")
00148         // $foo->bar($foo, $bar, "text")
00149         // $foo->bar($foo, "foo")
00150         // $foo->bar->foo()
00151         // $foo->bar->foo->bar()
00152         // $foo->bar($foo->bar)
00153         // $foo->bar($foo->bar())
00154         // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar))
00155         $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
00156         $this->_obj_restricted_param_regexp = '(?:'
00157                 . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'
00158                 . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)';
00159         $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
00160                 . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';
00161         $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp
00162                 . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)';
00163         $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
00164         $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)';
00165         
00166         // matches valid modifier syntax:
00167         // |foo
00168         // |@foo
00169         // |foo:"bar"
00170         // |foo:$bar
00171         // |foo:"bar":$foobar
00172         // |foo|bar
00173         // |foo:$foo->bar
00174         $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|'
00175            . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
00176 
00177         // matches valid function name:
00178         // foo123
00179         // _foo_bar
00180         $this->_func_regexp = '[a-zA-Z_]\w*';
00181 
00182         // matches valid registered object:
00183         // foo->bar
00184         $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
00185 
00186         // matches valid parameter values:
00187         // true
00188         // $foo
00189         // $foo|bar
00190         // #foo#
00191         // #foo#|bar
00192         // "text"
00193         // "text"|bar
00194         // $foo->bar
00195         $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
00196            . $this->_var_regexp . '|' . $this->_num_const_regexp  . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
00197 
00198         // matches valid parenthesised function parameters:
00199         //
00200         // "text"
00201         //    $foo, $bar, "text"
00202         // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
00203         $this->_parenth_param_regexp = '(?:\((?:\w+|'
00204                 . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
00205                 . $this->_param_regexp . ')))*)?\))';
00206 
00207         // matches valid function call:
00208         // foo()
00209         // foo_bar($foo)
00210         // _foo_bar($foo,"bar")
00211         // foo123($foo,$foo->bar(),"foo")
00212         $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
00213            . $this->_parenth_param_regexp . '))';
00214     }
00215 
00225     function _compile_file($resource_name, $source_content, &$compiled_content)
00226     {
00227 
00228         if ($this->security) {
00229             // do not allow php syntax to be executed unless specified
00230             if ($this->php_handling == SMARTY_PHP_ALLOW &&
00231                 !$this->security_settings['PHP_HANDLING']) {
00232                 $this->php_handling = SMARTY_PHP_PASSTHRU;
00233             }
00234         }
00235 
00236         $this->_load_filters();
00237 
00238         $this->_current_file = $resource_name;
00239         $this->_current_line_no = 1;
00240         $ldq = preg_quote($this->left_delimiter, '~');
00241         $rdq = preg_quote($this->right_delimiter, '~');
00242 
00243         // run template source through prefilter functions
00244         if (count($this->_plugins['prefilter']) > 0) {
00245             foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
00246                 if ($prefilter === false) continue;
00247                 if ($prefilter[3] || is_callable($prefilter[0])) {
00248                     $source_content = call_user_func_array($prefilter[0],
00249                                                             array($source_content, &$this));
00250                     $this->_plugins['prefilter'][$filter_name][3] = true;
00251                 } else {
00252                     $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented");
00253                 }
00254             }
00255         }
00256 
00257         /* fetch all special blocks */
00258         $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s";
00259 
00260         preg_match_all($search, $source_content, $match,  PREG_SET_ORDER);
00261         $this->_folded_blocks = $match;
00262         reset($this->_folded_blocks);
00263 
00264         /* replace special blocks by "{php}" */
00265         $source_content = preg_replace($search.'e', "'"
00266                                        . $this->_quote_replace($this->left_delimiter) . 'php'
00267                                        . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'"
00268                                        . $this->_quote_replace($this->right_delimiter)
00269                                        . "'"
00270                                        , $source_content);
00271 
00272         /* Gather all template tags. */
00273         preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match);
00274         $template_tags = $_match[1];
00275         /* Split content by template tags to obtain non-template content. */
00276         $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content);
00277 
00278         /* loop through text blocks */
00279         for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
00280             /* match anything resembling php tags */
00281             if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) {
00282                 /* replace tags with placeholders to prevent recursive replacements */
00283                 $sp_match[1] = array_unique($sp_match[1]);
00284                 usort($sp_match[1], '_smarty_sort_length');
00285                 for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
00286                     $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);
00287                 }
00288                 /* process each one */
00289                 for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
00290                     if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
00291                         /* echo php contents */
00292                         $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
00293                     } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
00294                         /* quote php tags */
00295                         $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);
00296                     } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
00297                         /* remove php tags */
00298                         $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
00299                     } else {
00300                         /* SMARTY_PHP_ALLOW, but echo non php starting tags */
00301                         $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
00302                         $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
00303                     }
00304                 }
00305             }
00306         }
00307 
00308         /* Compile the template tags into PHP code. */
00309         $compiled_tags = array();
00310         for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
00311             $this->_current_line_no += substr_count($text_blocks[$i], "\n");
00312             $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
00313             $this->_current_line_no += substr_count($template_tags[$i], "\n");
00314         }
00315         if (count($this->_tag_stack)>0) {
00316             list($_open_tag, $_line_no) = end($this->_tag_stack);
00317             $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__);
00318             return;
00319         }
00320 
00321         /* Reformat $text_blocks between 'strip' and '/strip' tags,
00322            removing spaces, tabs and newlines. */
00323         $strip = false;
00324         for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
00325             if ($compiled_tags[$i] == '{strip}') {
00326                 $compiled_tags[$i] = '';
00327                 $strip = true;
00328                 /* remove leading whitespaces */
00329                 $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]);
00330             }
00331             if ($strip) {
00332                 /* strip all $text_blocks before the next '/strip' */
00333                 for ($j = $i + 1; $j < $for_max; $j++) {
00334                     /* remove leading and trailing whitespaces of each line */
00335                     $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]);
00336                     if ($compiled_tags[$j] == '{/strip}') {                       
00337                         /* remove trailing whitespaces from the last text_block */
00338                         $text_blocks[$j] = rtrim($text_blocks[$j]);
00339                     }
00340                     $text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>";
00341                     if ($compiled_tags[$j] == '{/strip}') {
00342                         $compiled_tags[$j] = "\n"; /* slurped by php, but necessary
00343                                     if a newline is following the closing strip-tag */
00344                         $strip = false;
00345                         $i = $j;
00346                         break;
00347                     }
00348                 }
00349             }
00350         }
00351         $compiled_content = '';
00352 
00353         /* Interleave the compiled contents and text blocks to get the final result. */
00354         for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
00355             if ($compiled_tags[$i] == '') {
00356                 // tag result empty, remove first newline from following text block
00357                 $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]);
00358             }
00359             $compiled_content .= $text_blocks[$i].$compiled_tags[$i];
00360         }
00361         $compiled_content .= $text_blocks[$i];
00362 
00363         // remove \n from the end of the file, if any
00364         if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) {
00365             $compiled_content = substr($compiled_content, 0, -1);
00366         }
00367 
00368         if (!empty($this->_cache_serial)) {
00369             $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content;
00370         }
00371 
00372         // remove unnecessary close/open tags
00373         $compiled_content = preg_replace('~\?>\n?<\?php~', '', $compiled_content);
00374 
00375         // run compiled template through postfilter functions
00376         if (count($this->_plugins['postfilter']) > 0) {
00377             foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
00378                 if ($postfilter === false) continue;
00379                 if ($postfilter[3] || is_callable($postfilter[0])) {
00380                     $compiled_content = call_user_func_array($postfilter[0],
00381                                                               array($compiled_content, &$this));
00382                     $this->_plugins['postfilter'][$filter_name][3] = true;
00383                 } else {
00384                     $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
00385                 }
00386             }
00387         }
00388 
00389         // put header at the top of the compiled template
00390         $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
00391         $template_header .= "         compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
00392 
00393         /* Emit code to load needed plugins. */
00394         $this->_plugins_code = '';
00395         if (count($this->_plugin_info)) {
00396             $_plugins_params = "array('plugins' => array(";
00397             foreach ($this->_plugin_info as $plugin_type => $plugins) {
00398                 foreach ($plugins as $plugin_name => $plugin_info) {
00399                     $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], ";
00400                     $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
00401                 }
00402             }
00403             $_plugins_params .= '))';
00404             $plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
00405             $template_header .= $plugins_code;
00406             $this->_plugin_info = array();
00407             $this->_plugins_code = $plugins_code;
00408         }
00409 
00410         if ($this->_init_smarty_vars) {
00411             $template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
00412             $this->_init_smarty_vars = false;
00413         }
00414 
00415         $compiled_content = $template_header . $compiled_content;
00416         return true;
00417     }
00418 
00425     function _compile_tag($template_tag)
00426     {
00427         /* Matched comment. */
00428         if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
00429             return '';
00430         
00431         /* Split tag into two three parts: command, command modifiers and the arguments. */
00432         if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp
00433                 . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
00434                       (?:\s+(.*))?$
00435                     ~xs', $template_tag, $match)) {
00436             $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
00437         }
00438         
00439         $tag_command = $match[1];
00440         $tag_modifier = isset($match[2]) ? $match[2] : null;
00441         $tag_args = isset($match[3]) ? $match[3] : null;
00442 
00443         if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {
00444             /* tag name is a variable or object */
00445             $_return = $this->_parse_var_props($tag_command . $tag_modifier);
00446             return "<?php echo $_return; ?>" . $this->_additional_newline;
00447         }
00448 
00449         /* If the tag name is a registered object, we process it. */
00450         if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) {
00451             return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
00452         }
00453 
00454         switch ($tag_command) {
00455             case 'include':
00456                 return $this->_compile_include_tag($tag_args);
00457 
00458             case 'include_php':
00459                 return $this->_compile_include_php_tag($tag_args);
00460 
00461             case 'if':
00462                 $this->_push_tag('if');
00463                 return $this->_compile_if_tag($tag_args);
00464 
00465             case 'else':
00466                 list($_open_tag) = end($this->_tag_stack);
00467                 if ($_open_tag != 'if' && $_open_tag != 'elseif')
00468                     $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
00469                 else
00470                     $this->_push_tag('else');
00471                 return '<?php else: ?>';
00472 
00473             case 'elseif':
00474                 list($_open_tag) = end($this->_tag_stack);
00475                 if ($_open_tag != 'if' && $_open_tag != 'elseif')
00476                     $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
00477                 if ($_open_tag == 'if')
00478                     $this->_push_tag('elseif');
00479                 return $this->_compile_if_tag($tag_args, true);
00480 
00481             case '/if':
00482                 $this->_pop_tag('if');
00483                 return '<?php endif; ?>';
00484 
00485             case 'capture':
00486                 return $this->_compile_capture_tag(true, $tag_args);
00487 
00488             case '/capture':
00489                 return $this->_compile_capture_tag(false);
00490 
00491             case 'ldelim':
00492                 return $this->left_delimiter;
00493 
00494             case 'rdelim':
00495                 return $this->right_delimiter;
00496 
00497             case 'section':
00498                 $this->_push_tag('section');
00499                 return $this->_compile_section_start($tag_args);
00500 
00501             case 'sectionelse':
00502                 $this->_push_tag('sectionelse');
00503                 return "<?php endfor; else: ?>";
00504                 break;
00505 
00506             case '/section':
00507                 $_open_tag = $this->_pop_tag('section');
00508                 if ($_open_tag == 'sectionelse')
00509                     return "<?php endif; ?>";
00510                 else
00511                     return "<?php endfor; endif; ?>";
00512 
00513             case 'foreach':
00514                 $this->_push_tag('foreach');
00515                 return $this->_compile_foreach_start($tag_args);
00516                 break;
00517 
00518             case 'foreachelse':
00519                 $this->_push_tag('foreachelse');
00520                 return "<?php endforeach; else: ?>";
00521 
00522             case '/foreach':
00523                 $_open_tag = $this->_pop_tag('foreach');
00524                 if ($_open_tag == 'foreachelse')
00525                     return "<?php endif; unset(\$_from); ?>";
00526                 else
00527                     return "<?php endforeach; endif; unset(\$_from); ?>";
00528                 break;
00529 
00530             case 'strip':
00531             case '/strip':
00532                 if ($tag_command{0}=='/') {
00533                     $this->_pop_tag('strip');
00534                     if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
00535                         $this->_additional_newline = "\n";
00536                         return '{' . $tag_command . '}';
00537                     }
00538                 } else {
00539                     $this->_push_tag('strip');
00540                     if ($this->_strip_depth++==0) { /* outermost opening {strip} */
00541                         $this->_additional_newline = "";
00542                         return '{' . $tag_command . '}';
00543                     }
00544                 }
00545                 return '';
00546 
00547             case 'php':
00548                 /* handle folded tags replaced by {php} */
00549                 list(, $block) = each($this->_folded_blocks);
00550                 $this->_current_line_no += substr_count($block[0], "\n");
00551                 /* the number of matched elements in the regexp in _compile_file()
00552                    determins the type of folded tag that was found */
00553                 switch (count($block)) {
00554                     case 2: /* comment */
00555                         return '';
00556 
00557                     case 3: /* literal */
00558                         return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline;
00559 
00560                     case 4: /* php */
00561                         if ($this->security && !$this->security_settings['PHP_TAGS']) {
00562                             $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__);
00563                             return;
00564                         }
00565                         return '<?php ' . $block[3] .' ?>';
00566                 }
00567                 break;
00568 
00569             case 'insert':
00570                 return $this->_compile_insert_tag($tag_args);
00571 
00572             default:
00573                 if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
00574                     return $output;
00575                 } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
00576                     return $output;
00577                 } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
00578                     return $output;                    
00579                 } else {
00580                     $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
00581                 }
00582 
00583         }
00584     }
00585 
00586 
00596     function _compile_compiler_tag($tag_command, $tag_args, &$output)
00597     {
00598         $found = false;
00599         $have_function = true;
00600 
00601         /*
00602          * First we check if the compiler function has already been registered
00603          * or loaded from a plugin file.
00604          */
00605         if (isset($this->_plugins['compiler'][$tag_command])) {
00606             $found = true;
00607             $plugin_func = $this->_plugins['compiler'][$tag_command][0];
00608             if (!is_callable($plugin_func)) {
00609                 $message = "compiler function '$tag_command' is not implemented";
00610                 $have_function = false;
00611             }
00612         }
00613         /*
00614          * Otherwise we need to load plugin file and look for the function
00615          * inside it.
00616          */
00617         else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {
00618             $found = true;
00619 
00620             include_once $plugin_file;
00621 
00622             $plugin_func = 'smarty_compiler_' . $tag_command;
00623             if (!is_callable($plugin_func)) {
00624                 $message = "plugin function $plugin_func() not found in $plugin_file\n";
00625                 $have_function = false;
00626             } else {
00627                 $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);
00628             }
00629         }
00630 
00631         /*
00632          * True return value means that we either found a plugin or a
00633          * dynamically registered function. False means that we didn't and the
00634          * compiler should now emit code to load custom function plugin for this
00635          * tag.
00636          */
00637         if ($found) {
00638             if ($have_function) {
00639                 $output = call_user_func_array($plugin_func, array($tag_args, &$this));
00640                 if($output != '') {
00641                 $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)
00642                                    . $output
00643                                    . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';
00644                 }
00645             } else {
00646                 $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
00647             }
00648             return true;
00649         } else {
00650             return false;
00651         }
00652     }
00653 
00654 
00665     function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)
00666     {
00667         if ($tag_command{0} == '/') {
00668             $start_tag = false;
00669             $tag_command = substr($tag_command, 1);
00670         } else
00671             $start_tag = true;
00672 
00673         $found = false;
00674         $have_function = true;
00675 
00676         /*
00677          * First we check if the block function has already been registered
00678          * or loaded from a plugin file.
00679          */
00680         if (isset($this->_plugins['block'][$tag_command])) {
00681             $found = true;
00682             $plugin_func = $this->_plugins['block'][$tag_command][0];
00683             if (!is_callable($plugin_func)) {
00684                 $message = "block function '$tag_command' is not implemented";
00685                 $have_function = false;
00686             }
00687         }
00688         /*
00689          * Otherwise we need to load plugin file and look for the function
00690          * inside it.
00691          */
00692         else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {
00693             $found = true;
00694 
00695             include_once $plugin_file;
00696 
00697             $plugin_func = 'smarty_block_' . $tag_command;
00698             if (!function_exists($plugin_func)) {
00699                 $message = "plugin function $plugin_func() not found in $plugin_file\n";
00700                 $have_function = false;
00701             } else {
00702                 $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);
00703 
00704             }
00705         }
00706 
00707         if (!$found) {
00708             return false;
00709         } else if (!$have_function) {
00710             $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
00711             return true;
00712         }
00713 
00714         /*
00715          * Even though we've located the plugin function, compilation
00716          * happens only once, so the plugin will still need to be loaded
00717          * at runtime for future requests.
00718          */
00719         $this->_add_plugin('block', $tag_command);
00720 
00721         if ($start_tag)
00722             $this->_push_tag($tag_command);
00723         else
00724             $this->_pop_tag($tag_command);
00725 
00726         if ($start_tag) {
00727             $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);
00728             $attrs = $this->_parse_attrs($tag_args);
00729             $_cache_attrs='';
00730             $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs);
00731             $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); ';
00732             $output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);';
00733             $output .= 'while ($_block_repeat) { ob_start(); ?>';
00734         } else {
00735             $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); ';
00736             $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat=false)';
00737             if ($tag_modifier != '') {
00738                 $this->_parse_modifiers($_out_tag_text, $tag_modifier);
00739             }
00740             $output .= 'echo '.$_out_tag_text.'; } ';
00741             $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>';
00742         }
00743 
00744         return true;
00745     }
00746 
00747 
00756     function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output)
00757     {
00758         $found = false;
00759         $have_function = true;
00760 
00761         /*
00762          * First we check if the custom function has already been registered
00763          * or loaded from a plugin file.
00764          */
00765         if (isset($this->_plugins['function'][$tag_command])) {
00766             $found = true;
00767             $plugin_func = $this->_plugins['function'][$tag_command][0];
00768             if (!is_callable($plugin_func)) {
00769                 $message = "custom function '$tag_command' is not implemented";
00770                 $have_function = false;
00771             }
00772         }
00773         /*
00774          * Otherwise we need to load plugin file and look for the function
00775          * inside it.
00776          */
00777         else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) {
00778             $found = true;
00779 
00780             include_once $plugin_file;
00781 
00782             $plugin_func = 'smarty_function_' . $tag_command;
00783             if (!function_exists($plugin_func)) {
00784                 $message = "plugin function $plugin_func() not found in $plugin_file\n";
00785                 $have_function = false;
00786             } else {
00787                 $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true);
00788 
00789             }
00790         }
00791 
00792         if (!$found) {
00793             return false;
00794         } else if (!$have_function) {
00795             $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
00796             return true;
00797         }
00798 
00799         /* declare plugin to be loaded on display of the template that
00800            we compile right now */
00801         $this->_add_plugin('function', $tag_command);
00802 
00803         $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);
00804         $attrs = $this->_parse_attrs($tag_args);
00805         $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs='');
00806 
00807         $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)";
00808         if($tag_modifier != '') {
00809             $this->_parse_modifiers($output, $tag_modifier);
00810         }
00811 
00812         if($output != '') {
00813             $output =  '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';'
00814                 . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline;
00815         }
00816 
00817         return true;
00818     }
00819 
00828     function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)
00829     {
00830         if ($tag_command{0} == '/') {
00831             $start_tag = false;
00832             $tag_command = substr($tag_command, 1);
00833         } else {
00834             $start_tag = true;
00835         }
00836 
00837         list($object, $obj_comp) = explode('->', $tag_command);
00838 
00839         $arg_list = array();
00840         if(count($attrs)) {
00841             $_assign_var = false;
00842             foreach ($attrs as $arg_name => $arg_value) {
00843                 if($arg_name == 'assign') {
00844                     $_assign_var = $arg_value;
00845                     unset($attrs['assign']);
00846                     continue;
00847                 }
00848                 if (is_bool($arg_value))
00849                     $arg_value = $arg_value ? 'true' : 'false';
00850                 $arg_list[] = "'$arg_name' => $arg_value";
00851             }
00852         }
00853 
00854         if($this->_reg_objects[$object][2]) {
00855             // smarty object argument format
00856             $args = "array(".implode(',', (array)$arg_list)."), \$this";
00857         } else {
00858             // traditional argument format
00859             $args = implode(',', array_values($attrs));
00860             if (empty($args)) {
00861                 $args = 'null';
00862             }
00863         }
00864 
00865         $prefix = '';
00866         $postfix = '';
00867         $newline = '';
00868         if(!is_object($this->_reg_objects[$object][0])) {
00869             $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
00870         } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {
00871             $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
00872         } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {
00873             // method
00874             if(in_array($obj_comp, $this->_reg_objects[$object][3])) {
00875                 // block method
00876                 if ($start_tag) {
00877                     $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); ";
00878                     $prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); ";
00879                     $prefix .= "while (\$_block_repeat) { ob_start();";
00880                     $return = null;
00881                     $postfix = '';
00882             } else {
00883                     $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); ";
00884                     $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat=false)";
00885                     $postfix = "} array_pop(\$this->_tag_stack);";
00886                 }
00887             } else {
00888                 // non-block method
00889                 $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)";
00890             }
00891         } else {
00892             // property
00893             $return = "\$this->_reg_objects['$object'][0]->$obj_comp";
00894         }
00895 
00896         if($return != null) {
00897             if($tag_modifier != '') {
00898                 $this->_parse_modifiers($return, $tag_modifier);
00899             }
00900 
00901             if(!empty($_assign_var)) {
00902                 $output = "\$this->assign('" . $this->_dequote($_assign_var) ."',  $return);";
00903             } else {
00904                 $output = 'echo ' . $return . ';';
00905                 $newline = $this->_additional_newline;
00906             }
00907         } else {
00908             $output = '';
00909         }
00910 
00911         return '<?php ' . $prefix . $output . $postfix . "?>" . $newline;
00912     }
00913 
00920     function _compile_insert_tag($tag_args)
00921     {
00922         $attrs = $this->_parse_attrs($tag_args);
00923         $name = $this->_dequote($attrs['name']);
00924 
00925         if (empty($name)) {
00926             $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__);
00927         }
00928 
00929         if (!empty($attrs['script'])) {
00930             $delayed_loading = true;
00931         } else {
00932             $delayed_loading = false;
00933         }
00934 
00935         foreach ($attrs as $arg_name => $arg_value) {
00936             if (is_bool($arg_value))
00937                 $arg_value = $arg_value ? 'true' : 'false';
00938             $arg_list[] = "'$arg_name' => $arg_value";
00939         }
00940 
00941         $this->_add_plugin('insert', $name, $delayed_loading);
00942 
00943         $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))";
00944 
00945         return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline;
00946     }
00947 
00954     function _compile_include_tag($tag_args)
00955     {
00956         $attrs = $this->_parse_attrs($tag_args);
00957         $arg_list = array();
00958 
00959         if (empty($attrs['file'])) {
00960             $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
00961         }
00962 
00963         foreach ($attrs as $arg_name => $arg_value) {
00964             if ($arg_name == 'file') {
00965                 $include_file = $arg_value;
00966                 continue;
00967             } else if ($arg_name == 'assign') {
00968                 $assign_var = $arg_value;
00969                 continue;
00970             }
00971             if (is_bool($arg_value))
00972                 $arg_value = $arg_value ? 'true' : 'false';
00973             $arg_list[] = "'$arg_name' => $arg_value";
00974         }
00975 
00976         $output = '<?php ';
00977 
00978         if (isset($assign_var)) {
00979             $output .= "ob_start();\n";
00980         }
00981 
00982         $output .=
00983             "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";
00984 
00985 
00986         $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
00987         $output .= "\$this->_smarty_include($_params);\n" .
00988         "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
00989         "unset(\$_smarty_tpl_vars);\n";
00990 
00991         if (isset($assign_var)) {
00992             $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
00993         }
00994 
00995         $output .= ' ?>';
00996 
00997         return $output;
00998 
00999     }
01000 
01007     function _compile_include_php_tag($tag_args)
01008     {
01009         $attrs = $this->_parse_attrs($tag_args);
01010 
01011         if (empty($attrs['file'])) {
01012             $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__);
01013         }
01014 
01015         $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);
01016         $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';
01017 
01018         $arg_list = array();
01019         foreach($attrs as $arg_name => $arg_value) {
01020             if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {
01021                 if(is_bool($arg_value))
01022                     $arg_value = $arg_value ? 'true' : 'false';
01023                 $arg_list[] = "'$arg_name' => $arg_value";
01024             }
01025         }
01026 
01027         $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))";
01028 
01029         return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
01030     }
01031 
01032 
01039     function _compile_section_start($tag_args)
01040     {
01041         $attrs = $this->_parse_attrs($tag_args);
01042         $arg_list = array();
01043 
01044         $output = '<?php ';
01045         $section_name = $attrs['name'];
01046         if (empty($section_name)) {
01047             $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
01048         }
01049 
01050         $output .= "unset(\$this->_sections[$section_name]);\n";
01051         $section_props = "\$this->_sections[$section_name]";
01052 
01053         foreach ($attrs as $attr_name => $attr_value) {
01054             switch ($attr_name) {
01055                 case 'loop':
01056                     $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
01057                     break;
01058 
01059                 case 'show':
01060                     if (is_bool($attr_value))
01061                         $show_attr_value = $attr_value ? 'true' : 'false';
01062                     else
01063                         $show_attr_value = "(bool)$attr_value";
01064                     $output .= "{$section_props}['show'] = $show_attr_value;\n";
01065                     break;
01066 
01067                 case 'name':
01068                     $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
01069                     break;
01070 
01071                 case 'max':
01072                 case 'start':
01073                     $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
01074                     break;
01075 
01076                 case 'step':
01077                     $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
01078                     break;
01079 
01080                 default:
01081                     $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__);
01082                     break;
01083             }
01084         }
01085 
01086         if (!isset($attrs['show']))
01087             $output .= "{$section_props}['show'] = true;\n";
01088 
01089         if (!isset($attrs['loop']))
01090             $output .= "{$section_props}['loop'] = 1;\n";
01091 
01092         if (!isset($attrs['max']))
01093             $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
01094         else
01095             $output .= "if ({$section_props}['max'] < 0)\n" .
01096                        "    {$section_props}['max'] = {$section_props}['loop'];\n";
01097 
01098         if (!isset($attrs['step']))
01099             $output .= "{$section_props}['step'] = 1;\n";
01100 
01101         if (!isset($attrs['start']))
01102             $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
01103         else {
01104             $output .= "if ({$section_props}['start'] < 0)\n" .
01105                        "    {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" .
01106                        "else\n" .
01107                        "    {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
01108         }
01109 
01110         $output .= "if ({$section_props}['show']) {\n";
01111         if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {
01112             $output .= "    {$section_props}['total'] = {$section_props}['loop'];\n";
01113         } else {
01114             $output .= "    {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n";
01115         }
01116         $output .= "    if ({$section_props}['total'] == 0)\n" .
01117                    "        {$section_props}['show'] = false;\n" .
01118                    "} else\n" .
01119                    "    {$section_props}['total'] = 0;\n";
01120 
01121         $output .= "if ({$section_props}['show']):\n";
01122         $output .= "
01123             for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
01124                  {$section_props}['iteration'] <= {$section_props}['total'];
01125                  {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
01126         $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
01127         $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
01128         $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
01129         $output .= "{$section_props}['first']      = ({$section_props}['iteration'] == 1);\n";
01130         $output .= "{$section_props}['last']       = ({$section_props}['iteration'] == {$section_props}['total']);\n";
01131 
01132         $output .= "?>";
01133 
01134         return $output;
01135     }
01136 
01137 
01144     function _compile_foreach_start($tag_args)
01145     {
01146         $attrs = $this->_parse_attrs($tag_args);
01147         $arg_list = array();
01148 
01149         if (empty($attrs['from'])) {
01150             return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
01151         }
01152         $from = $attrs['from'];
01153 
01154         if (empty($attrs['item'])) {
01155             return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
01156         }
01157         $item = $this->_dequote($attrs['item']);
01158         if (!preg_match('~^\w+$~', $item)) {
01159             return $this->_syntax_error("'foreach: item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
01160         }
01161 
01162         if (isset($attrs['key'])) {
01163             $key  = $this->_dequote($attrs['key']);
01164             if (!preg_match('~^\w+$~', $key)) {
01165                 return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
01166             }
01167             $key_part = "\$this->_tpl_vars['$key'] => ";
01168         } else {
01169             $key = null;
01170             $key_part = '';
01171         }
01172 
01173         if (isset($attrs['name'])) {
01174             $name = $attrs['name'];
01175         } else {
01176             $name = null;
01177         }
01178 
01179         $output = '<?php ';
01180         $output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }";
01181         if (isset($name)) {
01182             $foreach_props = "\$this->_foreach[$name]";
01183             $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n";
01184             $output .= "if ({$foreach_props}['total'] > 0):\n";
01185             $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
01186             $output .= "        {$foreach_props}['iteration']++;\n";
01187         } else {
01188             $output .= "if (count(\$_from)):\n";
01189             $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
01190         }
01191         $output .= '?>';
01192 
01193         return $output;
01194     }
01195 
01196 
01205     function _compile_capture_tag($start, $tag_args = '')
01206     {
01207         $attrs = $this->_parse_attrs($tag_args);
01208 
01209         if ($start) {
01210             if (isset($attrs['name']))
01211                 $buffer = $attrs['name'];
01212             else
01213                 $buffer = "'default'";
01214 
01215             if (isset($attrs['assign']))
01216                 $assign = $attrs['assign'];
01217             else
01218                 $assign = null;
01219             $output = "<?php ob_start(); ?>";
01220             $this->_capture_stack[] = array($buffer, $assign);
01221         } else {
01222             list($buffer, $assign) = array_pop($this->_capture_stack);
01223             $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ";
01224             if (isset($assign)) {
01225                 $output .= " \$this->assign($assign, ob_get_contents());";
01226             }
01227             $output .= "ob_end_clean(); ?>";
01228         }
01229 
01230         return $output;
01231     }
01232 
01240     function _compile_if_tag($tag_args, $elseif = false)
01241     {
01242 
01243         /* Tokenize args for 'if' tag. */
01244         preg_match_all('~(?>
01245                 ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
01246                 ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)?    | # var or quoted string
01247                 \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@    | # valid non-word token
01248                 \b\w+\b                                                        | # valid word token
01249                 \S+                                                           # anything else
01250                 )~x', $tag_args, $match);
01251 
01252         $tokens = $match[0];
01253 
01254         if(empty($tokens)) {
01255             $_error_msg .= $elseif ? "'elseif'" : "'if'";
01256             $_error_msg .= ' statement requires arguments'; 
01257             $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__);
01258         }
01259             
01260                 
01261         // make sure we have balanced parenthesis
01262         $token_count = array_count_values($tokens);
01263         if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
01264             $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
01265         }
01266 
01267         $is_arg_stack = array();
01268 
01269         for ($i = 0; $i < count($tokens); $i++) {
01270 
01271             $token = &$tokens[$i];
01272 
01273             switch (strtolower($token)) {
01274                 case '!':
01275                 case '%':
01276                 case '!==':
01277                 case '==':
01278                 case '===':
01279                 case '>':
01280                 case '<':
01281                 case '!=':
01282                 case '<>':
01283                 case '<<':
01284                 case '>>':
01285                 case '<=':
01286                 case '>=':
01287                 case '&&':
01288                 case '||':
01289                 case '|':
01290                 case '^':
01291                 case '&':
01292                 case '~':
01293                 case ')':
01294                 case ',':
01295                 case '+':
01296                 case '-':
01297                 case '*':
01298                 case '/':
01299                 case '@':
01300                     break;
01301 
01302                 case 'eq':
01303                     $token = '==';
01304                     break;
01305 
01306                 case 'ne':
01307                 case 'neq':
01308                     $token = '!=';
01309                     break;
01310 
01311                 case 'lt':
01312                     $token = '<';
01313                     break;
01314 
01315                 case 'le':
01316                 case 'lte':
01317                     $token = '<=';
01318                     break;
01319 
01320                 case 'gt':
01321                     $token = '>';
01322                     break;
01323 
01324                 case 'ge':
01325                 case 'gte':
01326                     $token = '>=';
01327                     break;
01328 
01329                 case 'and':
01330                     $token = '&&';
01331                     break;
01332 
01333                 case 'or':
01334                     $token = '||';
01335                     break;
01336 
01337                 case 'not':
01338                     $token = '!';
01339                     break;
01340 
01341                 case 'mod':
01342                     $token = '%';
01343                     break;
01344 
01345                 case '(':
01346                     array_push($is_arg_stack, $i);
01347                     break;
01348 
01349                 case 'is':
01350                     /* If last token was a ')', we operate on the parenthesized
01351                        expression. The start of the expression is on the stack.
01352                        Otherwise, we operate on the last encountered token. */
01353                     if ($tokens[$i-1] == ')')
01354                         $is_arg_start = array_pop($is_arg_stack);
01355                     else
01356                         $is_arg_start = $i-1;
01357                     /* Construct the argument for 'is' expression, so it knows
01358                        what to operate on. */
01359                     $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
01360 
01361                     /* Pass all tokens from next one until the end to the
01362                        'is' expression parsing function. The function will
01363                        return modified tokens, where the first one is the result
01364                        of the 'is' expression and the rest are the tokens it
01365                        didn't touch. */
01366                     $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
01367 
01368                     /* Replace the old tokens with the new ones. */
01369                     array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
01370 
01371                     /* Adjust argument start so that it won't change from the
01372                        current position for the next iteration. */
01373                     $i = $is_arg_start;
01374                     break;
01375 
01376                 default:
01377                     if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) {
01378                             // function call
01379                             if($this->security &&
01380                                !in_array($token, $this->security_settings['IF_FUNCS'])) {
01381                                 $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
01382                             }
01383                     } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') {
01384                         // variable function call
01385                         $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);                      
01386                     } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) {
01387                         // object or variable
01388                         $token = $this->_parse_var_props($token);
01389                     } elseif(is_numeric($token)) {
01390                         // number, skip it
01391                     } else {
01392                         $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__);
01393                     }
01394                     break;
01395             }
01396         }
01397 
01398         if ($elseif)
01399             return '<?php elseif ('.implode(' ', $tokens).'): ?>';
01400         else
01401             return '<?php if ('.implode(' ', $tokens).'): ?>';
01402     }
01403 
01404 
01405     function _compile_arg_list($type, $name, $attrs, &$cache_code) {
01406         $arg_list = array();
01407 
01408         if (isset($type) && isset($name)
01409             && isset($this->_plugins[$type])
01410             && isset($this->_plugins[$type][$name])
01411             && empty($this->_plugins[$type][$name][4])
01412             && is_array($this->_plugins[$type][$name][5])
01413             ) {
01414             /* we have a list of parameters that should be cached */
01415             $_cache_attrs = $this->_plugins[$type][$name][5];
01416             $_count = $this->_cache_attrs_count++;
01417             $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');";
01418 
01419         } else {
01420             /* no parameters are cached */
01421             $_cache_attrs = null;
01422         }
01423 
01424         foreach ($attrs as $arg_name => $arg_value) {
01425             if (is_bool($arg_value))
01426                 $arg_value = $arg_value ? 'true' : 'false';
01427             if (is_null($arg_value))
01428                 $arg_value = 'null';
01429             if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {
01430                 $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)";
01431             } else {
01432                 $arg_list[] = "'$arg_name' => $arg_value";
01433             }
01434         }
01435         return $arg_list;
01436     }
01437 
01445     function _parse_is_expr($is_arg, $tokens)
01446     {
01447         $expr_end = 0;
01448         $negate_expr = false;
01449 
01450         if (($first_token = array_shift($tokens)) == 'not') {
01451             $negate_expr = true;
01452             $expr_type = array_shift($tokens);
01453         } else
01454             $expr_type = $first_token;
01455 
01456         switch ($expr_type) {
01457             case 'even':
01458                 if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
01459                     $expr_end++;
01460                     $expr_arg = $tokens[$expr_end++];
01461                     $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
01462                 } else
01463                     $expr = "!(1 & $is_arg)";
01464                 break;
01465 
01466             case 'odd':
01467                 if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
01468                     $expr_end++;
01469                     $expr_arg = $tokens[$expr_end++];
01470                     $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
01471                 } else
01472                     $expr = "(1 & $is_arg)";
01473                 break;
01474 
01475             case 'div':
01476                 if (@$tokens[$expr_end] == 'by') {
01477                     $expr_end++;
01478                     $expr_arg = $tokens[$expr_end++];
01479                     $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")";
01480                 } else {
01481                     $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__);
01482                 }
01483                 break;
01484 
01485             default:
01486                 $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__);
01487                 break;
01488         }
01489 
01490         if ($negate_expr) {
01491             $expr = "!($expr)";
01492         }
01493 
01494         array_splice($tokens, 0, $expr_end, $expr);
01495 
01496         return $tokens;
01497     }
01498 
01499 
01506     function _parse_attrs($tag_args)
01507     {
01508 
01509         /* Tokenize tag attributes. */
01510         preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+)
01511                          )+ |
01512                          [=]
01513                         ~x', $tag_args, $match);
01514         $tokens       = $match[0];
01515 
01516         $attrs = array();
01517         /* Parse state:
01518             0 - expecting attribute name
01519             1 - expecting '='
01520             2 - expecting attribute value (not '=') */
01521         $state = 0;
01522 
01523         foreach ($tokens as $token) {
01524             switch ($state) {
01525                 case 0:
01526                     /* If the token is a valid identifier, we set attribute name
01527                        and go to state 1. */
01528                     if (preg_match('~^\w+$~', $token)) {
01529                         $attr_name = $token;
01530                         $state = 1;
01531                     } else
01532                         $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
01533                     break;
01534 
01535                 case 1:
01536                     /* If the token is '=', then we go to state 2. */
01537                     if ($token == '=') {
01538                         $state = 2;
01539                     } else
01540                         $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
01541                     break;
01542 
01543                 case 2:
01544                     /* If token is not '=', we set the attribute value and go to
01545                        state 0. */
01546                     if ($token != '=') {
01547                         /* We booleanize the token if it's a non-quoted possible
01548                            boolean value. */
01549                         if (preg_match('~^(on|yes|true)$~', $token)) {
01550                             $token = 'true';
01551                         } else if (preg_match('~^(off|no|false)$~', $token)) {
01552                             $token = 'false';
01553                         } else if ($token == 'null') {
01554                             $token = 'null';
01555                         } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) {
01556                             /* treat integer literally */
01557                         } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) {
01558                             /* treat as a string, double-quote it escaping quotes */
01559                             $token = '"'.addslashes($token).'"';
01560                         }
01561 
01562                         $attrs[$attr_name] = $token;
01563                         $state = 0;
01564                     } else
01565                         $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
01566                     break;
01567             }
01568             $last_token = $token;
01569         }
01570 
01571         if($state != 0) {
01572             if($state == 1) {
01573                 $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
01574             } else {
01575                 $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
01576             }
01577         }
01578 
01579         $this->_parse_vars_props($attrs);
01580 
01581         return $attrs;
01582     }
01583 
01590     function _parse_vars_props(&$tokens)
01591     {
01592         foreach($tokens as $key => $val) {
01593             $tokens[$key] = $this->_parse_var_props($val);
01594         }
01595     }
01596 
01605     function _parse_var_props($val)
01606     {
01607         $val = trim($val);
01608 
01609         if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) {
01610             // $ variable or object
01611             $return = $this->_parse_var($match[1]);
01612             $modifiers = $match[2];
01613             if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) {
01614                 $_default_mod_string = implode('|',(array)$this->default_modifiers);
01615                 $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
01616             }
01617             $this->_parse_modifiers($return, $modifiers);
01618             return $return;
01619         } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
01620                 // double quoted text
01621                 preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
01622                 $return = $this->_expand_quoted_text($match[1]);
01623                 if($match[2] != '') {
01624                     $this->_parse_modifiers($return, $match[2]);
01625                 }
01626                 return $return;
01627             }
01628         elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
01629                 // numerical constant
01630                 preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
01631                 if($match[2] != '') {
01632                     $this->_parse_modifiers($match[1], $match[2]);
01633                     return $match[1];
01634                 }
01635             }
01636         elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
01637                 // single quoted text
01638                 preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
01639                 if($match[2] != '') {
01640                     $this->_parse_modifiers($match[1], $match[2]);
01641                     return $match[1];
01642                 }
01643             }
01644         elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
01645                 // config var
01646                 return $this->_parse_conf_var($val);
01647             }
01648         elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
01649                 // section var
01650                 return $this->_parse_section_prop($val);
01651             }
01652         elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {
01653             // literal string
01654             return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"');
01655         }
01656         return $val;
01657     }
01658 
01665     function _expand_quoted_text($var_expr)
01666     {
01667         // if contains unescaped $, expand it
01668         if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) {
01669             $_match = $_match[0];
01670             rsort($_match);
01671             reset($_match);
01672             foreach($_match as $_var) {
01673                 $var_expr = str_replace ($_var, '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."', $var_expr);
01674             }
01675             $_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr);
01676         } else {
01677             $_return = $var_expr;
01678         }
01679         // replace double quoted literal string with single quotes
01680         $_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return);
01681         return $_return;
01682     }
01683 
01691     function _parse_var($var_expr)
01692     {
01693         $_has_math = false;
01694         $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
01695 
01696         if(count($_math_vars) > 1) {
01697             $_first_var = "";
01698             $_complete_var = "";
01699             $_output = "";
01700             // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter)
01701             foreach($_math_vars as $_k => $_math_var) {
01702                 $_math_var = $_math_vars[$_k];
01703 
01704                 if(!empty($_math_var) || is_numeric($_math_var)) {
01705                     // hit a math operator, so process the stuff which came before it
01706                     if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) {
01707                         $_has_math = true;
01708                         if(!empty($_complete_var) || is_numeric($_complete_var)) {
01709                             $_output .= $this->_parse_var($_complete_var);
01710                         }
01711 
01712                         // just output the math operator to php
01713                         $_output .= $_math_var;
01714 
01715                         if(empty($_first_var))
01716                             $_first_var = $_complete_var;
01717 
01718                         $_complete_var = "";
01719                     } else {
01720                         $_complete_var .= $_math_var;
01721                     }
01722                 }
01723             }
01724             if($_has_math) {
01725                 if(!empty($_complete_var) || is_numeric($_complete_var))
01726                     $_output .= $this->_parse_var($_complete_var);
01727 
01728                 // get the modifiers working (only the last var from math + modifier is left)
01729                 $var_expr = $_complete_var;
01730             }
01731         }
01732 
01733         // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)
01734         if(is_numeric($var_expr{0}))
01735             $_var_ref = $var_expr;
01736         else
01737             $_var_ref = substr($var_expr, 1);
01738         
01739         if(!$_has_math) {
01740             
01741             // get [foo] and .foo and ->foo and (...) pieces
01742             preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match);
01743                         
01744             $_indexes = $match[0];
01745             $_var_name = array_shift($_indexes);
01746 
01747             /* Handle $smarty.* variable references as a special case. */
01748             if ($_var_name == 'smarty') {
01749                 /*
01750                  * If the reference could be compiled, use the compiled output;
01751                  * otherwise, fall back on the $smarty variable generated at
01752                  * run-time.
01753                  */
01754                 if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {
01755                     $_output = $smarty_ref;
01756                 } else {
01757                     $_var_name = substr(array_shift($_indexes), 1);
01758                     $_output = "\$this->_smarty_vars['$_var_name']";
01759                 }
01760             } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) {
01761                 // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers
01762                 if(count($_indexes) > 0)
01763                 {
01764                     $_var_name .= implode("", $_indexes);
01765                     $_indexes = array();
01766                 }
01767                 $_output = $_var_name;
01768             } else {
01769                 $_output = "\$this->_tpl_vars['$_var_name']";
01770             }
01771 
01772             foreach ($_indexes as $_index) {
01773                 if ($_index{0} == '[') {
01774                     $_index = substr($_index, 1, -1);
01775                     if (is_numeric($_index)) {
01776                         $_output .= "[$_index]";
01777                     } elseif ($_index{0} == '$') {
01778                         if (strpos($_index, '.') !== false) {
01779                             $_output .= '[' . $this->_parse_var($_index) . ']';
01780                         } else {
01781                             $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]";
01782                         }
01783                     } else {
01784                         $_var_parts = explode('.', $_index);
01785                         $_var_section = $_var_parts[0];
01786                         $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';
01787                         $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]";
01788                     }
01789                 } else if ($_index{0} == '.') {
01790                     if ($_index{1} == '$')
01791                         $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]";
01792                     else
01793                         $_output .= "['" . substr($_index, 1) . "']";
01794                 } else if (substr($_index,0,2) == '->') {
01795                     if(substr($_index,2,2) == '__') {
01796                         $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
01797                     } elseif($this->security && substr($_index, 2, 1) == '_') {
01798                         $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
01799                     } elseif ($_index{2} == '$') {
01800                         if ($this->security) {
01801                             $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
01802                         } else {
01803                             $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}';
01804                         }
01805                     } else {
01806                         $_output .= $_index;
01807                     }
01808                 } elseif ($_index{0} == '(') {
01809                     $_index = $this->_parse_parenth_args($_index);
01810                     $_output .= $_index;
01811                 } else {
01812                     $_output .= $_index;
01813                 }
01814             }
01815         }
01816 
01817         return $_output;
01818     }
01819 
01826     function _parse_parenth_args($parenth_args)
01827     {
01828         preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match);
01829         $orig_vals = $match = $match[0];
01830         $this->_parse_vars_props($match);
01831         $replace = array();
01832         for ($i = 0, $count = count($match); $i < $count; $i++) {
01833             $replace[$orig_vals[$i]] = $match[$i];
01834         }
01835         return strtr($parenth_args, $replace);
01836     }
01837 
01843     function _parse_conf_var($conf_var_expr)
01844     {
01845         $parts = explode('|', $conf_var_expr, 2);
01846         $var_ref = $parts[0];
01847         $modifiers = isset($parts[1]) ? $parts[1] : '';
01848 
01849         $var_name = substr($var_ref, 1, -1);
01850 
01851         $output = "\$this->_config[0]['vars']['$var_name']";
01852 
01853         $this->_parse_modifiers($output, $modifiers);
01854 
01855         return $output;
01856     }
01857 
01864     function _parse_section_prop($section_prop_expr)
01865     {
01866         $parts = explode('|', $section_prop_expr, 2);
01867         $var_ref = $parts[0];
01868         $modifiers = isset($parts[1]) ? $parts[1] : '';
01869 
01870         preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
01871         $section_name = $match[1];
01872         $prop_name = $match[2];
01873 
01874         $output = "\$this->_sections['$section_name']['$prop_name']";
01875 
01876         $this->_parse_modifiers($output, $modifiers);
01877 
01878         return $output;
01879     }
01880 
01881 
01889     function _parse_modifiers(&$output, $modifier_string)
01890     {
01891         preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match);
01892         list(, $_modifiers, $modifier_arg_strings) = $_match;
01893 
01894         for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
01895             $_modifier_name = $_modifiers[$_i];
01896 
01897             if($_modifier_name == 'smarty') {
01898                 // skip smarty modifier
01899                 continue;
01900             }
01901 
01902             preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match);
01903             $_modifier_args = $_match[1];
01904 
01905             if ($_modifier_name{0} == '@') {
01906                 $_map_array = false;
01907                 $_modifier_name = substr($_modifier_name, 1);
01908             } else {
01909                 $_map_array = true;
01910             }
01911 
01912             if (empty($this->_plugins['modifier'][$_modifier_name])
01913                 && !$this->_get_plugin_filepath('modifier', $_modifier_name)
01914                 && function_exists($_modifier_name)) {
01915                 if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {
01916                     $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
01917                 } else {
01918                     $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name,  null, null, false);
01919                 }
01920             }
01921             $this->_add_plugin('modifier', $_modifier_name);
01922 
01923             $this->_parse_vars_props($_modifier_args);
01924 
01925             if($_modifier_name == 'default') {
01926                 // supress notifications of default modifier vars and args
01927                 if($output{0} == '$') {
01928                     $output = '@' . $output;
01929                 }
01930                 if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') {
01931                     $_modifier_args[0] = '@' . $_modifier_args[0];
01932                 }
01933             }
01934             if (count($_modifier_args) > 0)
01935                 $_modifier_args = ', '.implode(', ', $_modifier_args);
01936             else
01937                 $_modifier_args = '';
01938 
01939             if ($_map_array) {
01940                 $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))";
01941 
01942             } else {
01943 
01944                 $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)";
01945 
01946             }
01947         }
01948     }
01949 
01950 
01958     function _add_plugin($type, $name, $delayed_loading = null)
01959     {
01960         if (!isset($this->_plugin_info[$type])) {
01961             $this->_plugin_info[$type] = array();
01962         }
01963         if (!isset($this->_plugin_info[$type][$name])) {
01964             $this->_plugin_info[$type][$name] = array($this->_current_file,
01965                                                       $this->_current_line_no,
01966                                                       $delayed_loading);
01967         }
01968     }
01969 
01970 
01977     function _compile_smarty_ref(&$indexes)
01978     {
01979         /* Extract the reference name. */
01980         $_ref = substr($indexes[0], 1);
01981         foreach($indexes as $_index_no=>$_index) {
01982             if ($_index{0} != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) {
01983                 $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
01984             }
01985         }
01986 
01987         switch ($_ref) {
01988             case 'now':
01989                 $compiled_ref = 'time()';
01990                 $_max_index = 1;
01991                 break;
01992 
01993             case 'foreach':
01994                 array_shift($indexes);
01995                 $_var = $this->_parse_var_props(substr($indexes[0], 1));
01996                 $_propname = substr($indexes[1], 1);
01997                 $_max_index = 1;
01998                 switch ($_propname) {
01999                     case 'index':
02000                         array_shift($indexes);
02001                         $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)";
02002                         break;
02003                         
02004                     case 'first':
02005                         array_shift($indexes);
02006                         $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)";
02007                         break;
02008 
02009                     case 'last':
02010                         array_shift($indexes);
02011                         $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])";
02012                         break;
02013                         
02014                     case 'show':
02015                         array_shift($indexes);
02016                         $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)";
02017                         break;
02018                         
02019                     default:
02020                         unset($_max_index);
02021                         $compiled_ref = "\$this->_foreach[$_var]";
02022                 }
02023                 break;
02024 
02025             case 'section':
02026                 array_shift($indexes);
02027                 $_var = $this->_parse_var_props(substr($indexes[0], 1));
02028                 $compiled_ref = "\$this->_sections[$_var]";
02029                 break;
02030 
02031             case 'get':
02032                 $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']";
02033                 break;
02034 
02035             case 'post':
02036                 $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']";
02037                 break;
02038 
02039             case 'cookies':
02040                 $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']";
02041                 break;
02042 
02043             case 'env':
02044                 $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']";
02045                 break;
02046 
02047             case 'server':
02048                 $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']";
02049                 break;
02050 
02051             case 'session':
02052                 $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']";
02053                 break;
02054 
02055             /*
02056              * These cases are handled either at run-time or elsewhere in the
02057              * compiler.
02058              */
02059             case 'request':
02060                 if ($this->request_use_auto_globals) {
02061                     $compiled_ref = '$_REQUEST';
02062                     break;
02063                 } else {
02064                     $this->_init_smarty_vars = true;
02065                 }
02066                 return null;
02067 
02068             case 'capture':
02069                 return null;
02070 
02071             case 'template':
02072                 $compiled_ref = "'$this->_current_file'";
02073                 $_max_index = 1;
02074                 break;
02075 
02076             case 'version':
02077                 $compiled_ref = "'$this->_version'";
02078                 $_max_index = 1;
02079                 break;
02080 
02081             case 'const':
02082                 if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) {
02083                     $this->_syntax_error("(secure mode) constants not permitted",
02084                                          E_USER_WARNING, __FILE__, __LINE__);
02085                     return;
02086                 }
02087                 array_shift($indexes);
02088                 if (preg_match('!^\.\w+$!', $indexes[0])) {
02089                     $compiled_ref = '@' . substr($indexes[0], 1);
02090                 } else {
02091                     $_val = $this->_parse_var_props(substr($indexes[0], 1));
02092                     $compiled_ref = '@constant(' . $_val . ')';
02093                 }
02094                 $_max_index = 1;
02095                 break;
02096 
02097             case 'config':
02098                 $compiled_ref = "\$this->_config[0]['vars']";
02099                 $_max_index = 3;
02100                 break;
02101 
02102             case 'ldelim':
02103                 $compiled_ref = "'$this->left_delimiter'";
02104                 break;
02105 
02106             case 'rdelim':
02107                 $compiled_ref = "'$this->right_delimiter'";
02108                 break;
02109                 
02110             default:
02111                 $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);
02112                 break;
02113         }
02114 
02115         if (isset($_max_index) && count($indexes) > $_max_index) {
02116             $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
02117         }
02118 
02119         array_shift($indexes);
02120         return $compiled_ref;
02121     }
02122 
02133     function _compile_plugin_call($type, $name) {
02134         if (isset($this->_plugins[$type][$name])) {
02135             /* plugin loaded */
02136             if (is_array($this->_plugins[$type][$name][0])) {
02137                 return ((is_object($this->_plugins[$type][$name][0][0])) ?
02138                         "\$this->_plugins['$type']['$name'][0][0]->"    /* method callback */
02139                         : (string)($this->_plugins[$type][$name][0][0]).'::'    /* class callback */
02140                        ). $this->_plugins[$type][$name][0][1];
02141 
02142             } else {
02143                 /* function callback */
02144                 return $this->_plugins[$type][$name][0];
02145 
02146             }
02147         } else {
02148             /* plugin not loaded -> auto-loadable-plugin */
02149             return 'smarty_'.$type.'_'.$name;
02150 
02151         }
02152     }
02153 
02157     function _load_filters()
02158     {
02159         if (count($this->_plugins['prefilter']) > 0) {
02160             foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
02161                 if ($prefilter === false) {
02162                     unset($this->_plugins['prefilter'][$filter_name]);
02163                     $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
02164                     require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
02165                     smarty_core_load_plugins($_params, $this);
02166                 }
02167             }
02168         }
02169         if (count($this->_plugins['postfilter']) > 0) {
02170             foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
02171                 if ($postfilter === false) {
02172                     unset($this->_plugins['postfilter'][$filter_name]);
02173                     $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
02174                     require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
02175                     smarty_core_load_plugins($_params, $this);
02176                 }
02177             }
02178         }
02179     }
02180 
02181 
02188     function _quote_replace($string)
02189     {
02190         return strtr($string, array('\\' => '\\\\', '$' => '\\$'));
02191     }
02192 
02201     function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)
02202     {
02203         $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type);
02204     }
02205 
02206 
02213     function _push_cacheable_state($type, $name) {
02214         $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
02215         if ($_cacheable
02216             || 0<$this->_cacheable_state++) return '';
02217         if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));
02218         $_ret = 'if ($this->caching && !$this->_cache_including) { echo \'{nocache:'
02219             . $this->_cache_serial . '#' . $this->_nocache_count
02220             . '}\';}';
02221         return $_ret;
02222     }
02223 
02224 
02231     function _pop_cacheable_state($type, $name) {
02232         $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
02233         if ($_cacheable
02234             || --$this->_cacheable_state>0) return '';
02235         return 'if ($this->caching && !$this->_cache_including) { echo \'{/nocache:'
02236             . $this->_cache_serial . '#' . ($this->_nocache_count++)
02237             . '}\';}';
02238     }
02239 
02240 
02245     function _push_tag($open_tag)
02246     {
02247         array_push($this->_tag_stack, array($open_tag, $this->_current_line_no));
02248     }
02249 
02256     function _pop_tag($close_tag)
02257     {
02258         $message = '';
02259         if (count($this->_tag_stack)>0) {
02260             list($_open_tag, $_line_no) = array_pop($this->_tag_stack);
02261             if ($close_tag == $_open_tag) {
02262                 return $_open_tag;
02263             }
02264             if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) {
02265                 return $this->_pop_tag($close_tag);
02266             }
02267             if ($close_tag == 'section' && $_open_tag == 'sectionelse') {
02268                 $this->_pop_tag($close_tag);
02269                 return $_open_tag;
02270             }
02271             if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') {
02272                 $this->_pop_tag($close_tag);
02273                 return $_open_tag;
02274             }
02275             if ($_open_tag == 'else' || $_open_tag == 'elseif') {
02276                 $_open_tag = 'if';
02277             } elseif ($_open_tag == 'sectionelse') {
02278                 $_open_tag = 'section';
02279             } elseif ($_open_tag == 'foreachelse') {
02280                 $_open_tag = 'foreach';
02281             }
02282             $message = " expected {/$_open_tag} (opened line $_line_no).";
02283         }
02284         $this->_syntax_error("mismatched tag {/$close_tag}.$message",
02285                              E_USER_ERROR, __FILE__, __LINE__);
02286     }
02287 
02288 }
02289 
02298 function _smarty_sort_length($a, $b)
02299 {
02300     if($a == $b)
02301         return 0;
02302 
02303     if(strlen($a) == strlen($b))
02304         return ($a > $b) ? -1 : 1;
02305 
02306     return (strlen($a) > strlen($b)) ? -1 : 1;
02307 }
02308 
02309 
02310 /* vim: set et: */
02311 
02312 ?>

Generated on Thu Apr 19 2012 17:01:16 for openbiz by  doxygen 1.7.2