/[pliva-si]/inc/Smarty.class.php
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /inc/Smarty.class.php

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1.1.1 by ravilov, Mon Jun 25 09:57:25 2001 UTC revision 1.3 by dpavlin, Mon Mar 18 11:37:07 2002 UTC
# Line 1  Line 1 
1  <?  <?php
2  /*  /*
3   * Project:             Smarty: the PHP compiling template engine   * Project:     Smarty: the PHP compiling template engine
4   * File:                Smarty.class.php   * File:        Smarty.class.php
5   * Author:              Monte Ohrt <monte@ispi.net>   * Author:      Monte Ohrt <monte@ispi.net>
6   *              Andrei Zmievski <andrei@ispi.net>   *              Andrei Zmievski <andrei@ispi.net>
7   *   *
8   * Version:             1.2.2   * Version:             1.3.0
9   * Copyright:           2001 ispi of Lincoln, Inc.   * Copyright:           2001 ispi of Lincoln, Inc.
10   *                                 *              
11   * This program is free software; you can redistribute it and/or   * This library is free software; you can redistribute it and/or
12   * modify it under the terms of the GNU General Public License   * modify it under the terms of the GNU Lesser General Public
13   * as published by the Free Software Foundation; either version 2   * License as published by the Free Software Foundation; either
14   * of the License, or (at your option) any later version.   * version 2.1 of the License, or (at your option) any later version.
15   *   *
16   * This program is distributed in the hope that it will be useful,   * This library is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   * GNU General Public License for more details.   * Lesser General Public License for more details.
20   *   *
21   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU Lesser General Public
22   * along with this program; if not, write to the Free Software   * License along with this library; if not, write to the Free Software
23   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24   *   *
25   * You may contact the authors of Smarty by e-mail at:   * You may contact the authors of Smarty by e-mail at:
26   * monte@ispi.net   * monte@ispi.net
# Line 37  Line 37 
37   *   *
38   */   */
39    
40  require("Smarty.addons.php");  require('Smarty.addons.php');
41  require("Smarty.local.php");  require("Smarty.local.php");
42    
43    define("SMARTY_PHP_PASSTHRU",0);
44    define("SMARTY_PHP_QUOTE",1);
45    define("SMARTY_PHP_REMOVE",2);
46    define("SMARTY_PHP_ALLOW",3);
47    
48  class Smarty  class Smarty
49  {  {
50    
51          // public vars      // public vars
52          var     $compile_check  =       true;   // whether to check for compiling step or not:      var $template_dir    =  './templates';     // name of directory for templates  
53                                                                          // This is generally set to false once the      var $compile_dir     =  './templates_c';   // name of directory for compiled templates
54                                                                          // application is entered into production and      var $config_dir      =  './configs';       // directory where config files are located
55                                                                          // initially compiled. Leave set to true  
56                                                                          // during development.      var $global_assign   =  array('SCRIPT_NAME'); // variables from the GLOBALS array
57                                                      // that are implicitly assigned
58          var $template_dir                       =       "./templates"; // name of directory for templates                                                          // to all templates  
59          var $compile_dir                        =       "./templates_c"; // name of directory for compiled templates          var $compile_check   =  true;       // whether to check for compiling step or not:
60                                                    // This is generally set to false once the
61                                                    // application is entered into production and
62          var $tpl_file_ext                       =       ".tpl"; // template file extentions                                          // initially compiled. Leave set to true
63                                                    // during development. true/false default true.
64          var $allow_php                          =       false;          // whether or not to allow embedded php  
65                                                                                                  // in the templates. By default, php tags      var $force_compile   =  false;      // force templates to compile every time.
66                                                                                                  // are escaped.                                          // if cache file exists, it will
67          var $left_delimiter                     =       "{";            // template tag delimiters.                                          // override compile_check and force_compile.
68          var $right_delimiter            =       "}";                                          // true/false. default false.
69        var $caching         =  false;      // whether to use caching or not. true/false
70          var $config_dir                         =       "./configs";    // directory where config files are located      var $cache_dir       =  './cache';  // name of directory for template cache
71        var $cache_lifetime  =  3600;       // number of seconds cached content will persist.
72          var $custom_funcs                       =       array(  'html_options'          => 'smarty_func_html_options',                                          // 0 = never expires. default is one hour (3600)
73                                                                                          'html_select_date'      => 'smarty_func_html_select_date',  
74                                                                                  //----- local      var $tpl_file_ext    =  '.tpl';     // template file extention
75        
76        var $php_handling    =  SMARTY_PHP_PASSTHRU; // how smarty handles php tags
77                                            // possible values:
78                                            // SMARTY_PHP_PASSTHRU -> echo tags as is
79                                            // SMARTY_PHP_QUOTE    -> escape tags as entities
80                                            // SMARTY_PHP_REMOVE   -> remove php tags
81                                            // SMARTY_PHP_ALLOW    -> execute php tags
82                                            // default: SMARTY_PHP_PASSTHRU
83    
84        var $left_delimiter  =  '{';        // template tag delimiters.
85        var $right_delimiter =  '}';
86    
87    
88        var $custom_funcs    =  array(  'html_options'      => 'smarty_func_html_options',
89                                        'html_select_date'  => 'smarty_func_html_select_date',
90                                        'header'            => 'smarty_func_header',
91    
92    //----- local custom_funcs
93          'img'           => 'smarty_func_img',          'img'           => 'smarty_func_img',
94          'html_checkboxes' => 'smarty_func_html_checkboxes',          'html_checkboxes' => 'smarty_func_html_checkboxes',
95          'input'         => 'smarty_func_input',          'input'         => 'smarty_func_input',
96          'rinput'        => 'smarty_func_rinput',          'rinput'        => 'smarty_func_rinput',
97                                                                                   );          'textarea'      => 'smarty_func_textarea',
98            
99          var $custom_mods                        =       array(  'lower'                 => 'strtolower',                                   );
100                                                                                          'upper'                 => 'strtoupper',      
101                                                                                          'capitalize'    => 'ucwords',      var $custom_mods     =  array(  'lower'         => 'strtolower',
102                                                                                          'escape'                => 'smarty_mod_escape',                                      'upper'         => 'strtoupper',
103                                                                                          'truncate'              => 'smarty_mod_truncate',                                      'capitalize'    => 'ucwords',
104                                                                                          'spacify'               => 'smarty_mod_spacify',                                      'escape'        => 'smarty_mod_escape',
105                                                                                          'date_format'   => 'smarty_mod_date_format',                                      'truncate'      => 'smarty_mod_truncate',
106                                                                                          'string_format' => 'smarty_mod_string_format',                                      'spacify'       => 'smarty_mod_spacify',
107                                                                                          'replace'               => 'smarty_mod_replace',                                      'date_format'   => 'smarty_mod_date_format',
108                                                                                          'strip_tags'    => 'smarty_mod_strip_tags',                                      'string_format' => 'smarty_mod_string_format',
109                                                                                          'default'               => 'smarty_mod_default',                                      'replace'       => 'smarty_mod_replace',
110                                                                                  //----- local                                      'strip_tags'    => 'smarty_mod_strip_tags',
111                                                                                          'filesize' => 'smarty_mod_filesize',                                      'default'       => 'smarty_mod_default',
112                                                                                   );  
113          var $global_assign                      =       array(  'SCRIPT_NAME'  //----- local custom_mods
114                                                                                   );          'filesize' => 'smarty_mod_filesize',
115            
116          // internal vars                                   );
117          var $_error_msg                         =       false;          // error messages      
118          var $_tpl_vars                          =       array();      // internal vars
119          var $_sectionelse_stack         =       array();        // keeps track of whether section had 'else' part      var $_error_msg             =   false;      // error messages. true/false
120          var $_literal_blocks            =       array();        // keeps literal template blocks      var $_tpl_vars              =   array();
121          var $_current_file                      =       null;           // the current template being compiled      var $_sectionelse_stack     =   array();    // keeps track of whether section had 'else' part
122          var $_current_line_no           =       1;                      // line number for error messages      var $_literal_blocks        =   array();    // keeps literal template blocks
123        var $_current_file          =   null;       // the current template being compiled
124                var $_current_line_no       =   1;          // line number for error messages
125  /*======================================================================*\      var $_smarty_md5            =   'f8d698aea36fcbead2b9d5359ffca76f'; // md5 checksum of the string 'Smarty'
126          Function: Smarty  
127          Purpose:  Constructor      
128  \*======================================================================*/  /*======================================================================*\
129          function Smarty()      Function: Smarty
130          {      Purpose:  Constructor
131                  foreach ($this->global_assign as $var_name)  \*======================================================================*/
132                          $this->assign($var_name, $GLOBALS[$var_name]);      function Smarty()
133          }      {
134            foreach ($this->global_assign as $var_name)
135                $this->assign($var_name, $GLOBALS[$var_name]);
136  /*======================================================================*\      }
137          Function:       assign()  
138          Purpose:        assigns values to template variables  
139  \*======================================================================*/  /*======================================================================*\
140        Function:   assign()
141          function assign($tpl_var, $value = NULL)      Purpose:    assigns values to template variables
142          {  \*======================================================================*/
143                  if (is_array($tpl_var)){  
144                          foreach ($tpl_var as $key => $val) {      function assign($tpl_var, $value = NULL)
145                                  if (!empty($key))      {
146                                          $this->_tpl_vars[$key] = $val;          if (is_array($tpl_var)){
147                          }              foreach ($tpl_var as $key => $val) {
148                  } else {                  if (!empty($key))
149                          if (!empty($tpl_var) && isset($value))                      $this->_tpl_vars[$key] = $val;
150                                  $this->_tpl_vars[$tpl_var] = $value;              }
151                  }          } else {
152          }              if (!empty($tpl_var) && isset($value))
153                    $this->_tpl_vars[$tpl_var] = $value;
154                    }
155  /*======================================================================*\      }
156          Function: append  
157          Purpose:  appens values to template variables      
158  \*======================================================================*/  /*======================================================================*\
159          function append($tpl_var, $value = NULL)      Function: append
160          {      Purpose:  appens values to template variables
161                  if (is_array($tpl_var)) {  \*======================================================================*/
162                          foreach ($tpl_var as $key => $val) {      function append($tpl_var, $value = NULL)
163                                  if (!empty($key)) {      {
164                                          if (!is_array($this->_tpl_vars[$key]))          if (is_array($tpl_var)) {
165                                                  settype($this->_tpl_vars[$key], 'array');              foreach ($tpl_var as $key => $val) {
166                                          $this->_tpl_vars[$key][] = $val;                  if (!empty($key)) {
167                                  }                      if (!is_array($this->_tpl_vars[$key]))
168                          }                          settype($this->_tpl_vars[$key], 'array');
169                  } else {                      $this->_tpl_vars[$key][] = $val;
170                          if (!empty($tpl_var) && isset($value)) {                  }
171                                  if (!is_array($this->_tpl_vars[$tpl_var]))              }
172                                          settype($this->_tpl_vars[$tpl_var], 'array');          } else {
173                                  $this->_tpl_vars[$tpl_var][] = $value;              if (!empty($tpl_var) && isset($value)) {
174                          }                  if (!is_array($this->_tpl_vars[$tpl_var]))
175                  }                      settype($this->_tpl_vars[$tpl_var], 'array');
176          }                  $this->_tpl_vars[$tpl_var][] = $value;
177                }
178            }
179  /*======================================================================*\      }
180          Function:       clear_assign()  
181          Purpose:        clear the given assigned template variable.  
182  \*======================================================================*/  /*======================================================================*\
183        Function:   clear_assign()
184          function clear_assign($tpl_var)      Purpose:    clear the given assigned template variable.
185          {  \*======================================================================*/
186                  unset($this->_tpl_vars[$tpl_var]);  
187          }      function clear_assign($tpl_var)
188        {
189  /*======================================================================*\          if(is_array($tpl_var))
190          Function:       clear_all_assign()              foreach($tpl_var as $curr_var)
191          Purpose:        clear all the assigned template variables.                  unset($this->_tpl_vars[$curr_var]);
192  \*======================================================================*/          else
193                unset($this->_tpl_vars[$tpl_var]);
194          function clear_all_assign()      }
195          {  
196                  $this->_tpl_vars = array();      
197          }  /*======================================================================*\
198        Function: register_function
199        Purpose:  Registers custom function to be used in templates
200  /*======================================================================*\  \*======================================================================*/
201          Function: get_template_vars      function register_function($function, $function_impl)
202          Purpose:  Returns an array containing template variables      {
203  \*======================================================================*/          $this->custom_funcs[$function] = $function_impl;
204          function &get_template_vars()      }
205          {  
206                  return $this->_tpl_vars;      
207          }  /*======================================================================*\
208        Function: register_modifier
209        Purpose:  Registers modifier to be used in templates
210  /*======================================================================*\  \*======================================================================*/
211          Function:       display()      function register_modifier($modifier, $modifier_impl)
212          Purpose:        executes & displays the template results      {
213  \*======================================================================*/          $this->custom_mods[$modifier] = $modifier_impl;
214        }
215          function display($tpl_file)  
216          {      
217                  // compile files  /*======================================================================*\
218                  $this->_compile($this->template_dir);      Function:   clear_cache()
219                  //assemble compile directory path to file      Purpose:    clear cached content for the given template and cache id
220                  $_compile_file = $this->compile_dir.'/'.$tpl_file.'.php';  \*======================================================================*/
221                    
222                  extract($this->_tpl_vars);                    function clear_cache($tpl_file, $cache_id = null)
223                  include($_compile_file);      {
224          }                $cache_tpl_md5 = md5(realpath($this->template_dir.'/'.$tpl_file));
225                            $cache_dir = $this->cache_dir.'/'.$cache_tpl_md5;
226  /*======================================================================*\          
227          Function:       fetch()          if (!is_dir($cache_dir))
228          Purpose:        executes & returns the template results              return false;
229  \*======================================================================*/  
230            if (isset($cache_id)) {
231          function fetch($tpl_file)              $cache_id_md5 = md5($cache_id);
232          {              $cache_id_dir = substr($cache_id_md5, 0, 2);
233                  ob_start();              $cache_file = "$cache_dir/$cache_id_dir/{$cache_tpl_md5}_$cache_id_md5.cache";
234                  $this->display($tpl_file);              return (bool)(is_file($cache_file) && unlink($cache_file));
235                  $results = ob_get_contents();          } else
236                  ob_end_clean();              return $this->_clear_tpl_cache_dir($cache_tpl_md5);
237                  return $results;      }
238          }      
239        
240  /*======================================================================*\  /*======================================================================*\
241          Function:       compile()      Function:   clear_all_cache()
242          Purpose:        called to compile the templates      Purpose:    clear the entire contents of cache (all templates)
243  \*======================================================================*/  \*======================================================================*/
244    
245          function _compile($tpl_dir)      function clear_all_cache()
246          {      {
247                  if($this->compile_check)          if (!is_dir($this->cache_dir))
248                  {              return false;
249                          if($this->_traverse_files($tpl_dir, 0))  
250                                  return true;          $dir_handle = opendir($this->cache_dir);
251                          else          while ($curr_dir = readdir($dir_handle)) {
252                                  return false;              if ($curr_dir == '.' || $curr_dir == '..' ||
253                  }                  !is_dir($this->cache_dir.'/'.$curr_dir))
254                  else                  continue;
255                          return false;  
256          }              $this->_clear_tpl_cache_dir($curr_dir);
257            }
258  /*======================================================================*\          closedir($dir_handle);
259          Function:       _traverse_files()  
260          Purpose:        traverse the template files & process each one          return true;
261  \*======================================================================*/      }
262    
263          function _traverse_files($tpl_dir, $depth)  
264          {  /*======================================================================*\
265                  if(is_dir($tpl_dir)) {      Function:   is_cached()
266                          if($tpl_dir)      Purpose:    test to see if valid cache exists for this template
267                                  $dir_handle = opendir($tpl_dir);  \*======================================================================*/
268    
269                          while($curr_file = readdir($dir_handle)) {      function is_cached($tpl_file, $cache_id = null)
270                                  if ($curr_file == '.' || $curr_file == '..')      {
271                                          continue;          if (!$this->caching)
272                return false;
273                                  $filepath = $tpl_dir."/".$curr_file;  
274                                  if(is_readable($filepath)) {          // cache name = template path + cache_id
275                                          if(is_file($filepath) && preg_match('!' . preg_quote($this->tpl_file_ext, '!') . '$!', $curr_file)) {          $cache_tpl_md5 = md5(realpath($this->template_dir.'/'.$tpl_file));
276                                                  if(!$this->_process_file($filepath))          $cache_id_md5 = md5($cache_id);
277                                                          return false;          $cache_id_dir = substr($cache_id_md5, 0, 2);
278                                          } else if(is_dir($filepath)) {          $cache_file = $this->cache_dir."/$cache_tpl_md5/$cache_id_dir/{$cache_tpl_md5}_$cache_id_md5.cache";
279                                                  if(!$this->_traverse_files($filepath, $depth + 1))  
280                                                          return false;          if (file_exists($cache_file) &&
281                                          } else {              ($this->cache_lifetime == 0 ||
282                                                  // invalid file type, skipping               (time() - filemtime($cache_file) <= $this->cache_lifetime)))
283                                                  $this->_set_error_msg("Invalid filetype for $filepath, skipping");              return true;
284                                                  continue;          else
285                                          }              return false;
286                                  }          
287                          }      }
288                  } else {      
289                          $this->_set_error_msg("Directory \"$tpl_dir\" does not exist or is not a directory.");          
290                          return false;  /*======================================================================*\
291                  }      Function:   clear_all_assign()
292        Purpose:    clear all the assigned template variables.
293                  return true;  \*======================================================================*/
294          }  
295        function clear_all_assign()
296  /*======================================================================*\      {
297          Function:       _process_file()          $this->_tpl_vars = array();
298          Input:          test template files for modifications      }
299                                  and execute the compilation for each  
300                                  one requiring it.  
301  \*======================================================================*/  /*======================================================================*\
302        Function: get_template_vars
303          function _process_file($filepath)      Purpose:  Returns an array containing template variables
304          {  \*======================================================================*/
305                  if(preg_match("/^(.+)\/([^\/]+)$/", $filepath, $match)) {      function &get_template_vars()
306                          $tpl_file_dir = $match[1];                            {
307                          $tpl_file_name = $match[2] . ".php";          return $this->_tpl_vars;
308        }
309                          $compile_dir = preg_replace('!^' . preg_quote($this->template_dir, '!') . '!',  
310                                                                                  $this->compile_dir, $match[1]);  
311    /*======================================================================*\
312                          //create directory if none exists      Function:   display()
313                          if(!file_exists($compile_dir)) {      Purpose:    executes & displays the template results
314                                  $compile_dir_parts = preg_split('!/+!', $compile_dir);  \*======================================================================*/
315                                  $new_dir = "";  
316                                  foreach ($compile_dir_parts as $dir_part) {      function display($tpl_file, $cache_id = null)
317                                          $new_dir .= $dir_part."/";      {
318                                          if (!file_exists($new_dir) && !mkdir($new_dir, 0755)) {          $this->fetch($tpl_file, $cache_id, true);
319                                                  $this->_set_error_msg("problem creating directory \"$compile_dir\"");      }  
320                                                  return false;                                    
321                                          }  /*======================================================================*\
322                                  }      Function:   fetch()
323                          }      Purpose:    executes & returns or displays the template results
324    \*======================================================================*/
325                          // compile the template file if none exists or has been modified  
326                          if (!file_exists($compile_dir."/".$tpl_file_name) ||      function fetch($tpl_file, $cache_id = null, $display = false)
327                                  ($this->_modified_file($filepath, $compile_dir."/".$tpl_file_name))) {      {
328                                  if (!$this->_compile_file($filepath, $compile_dir."/".$tpl_file_name))          global $HTTP_SERVER_VARS;
329                                          return false;                            
330                          } else {          if ($this->caching) {
331                                  // no compilation needed              // cache name = template path + cache_id
332                                  return true;              $cache_tpl_md5 = md5(realpath($this->template_dir.'/'.$tpl_file));
333                          }              $cache_id_md5 = md5($cache_id);
334                  } else {              $cache_id_dir = substr($cache_id_md5, 0, 2);
335                          $this->_set_error_msg("problem matching \"$filepath.\"");              $cache_file = $this->cache_dir."/$cache_tpl_md5/$cache_id_dir/{$cache_tpl_md5}_$cache_id_md5.cache";
336                          return false;              
337                  }              if (file_exists($cache_file) &&
338                    ($this->cache_lifetime == 0 ||
339                  return true;                   (time() - filemtime($cache_file) <= $this->cache_lifetime))) {
340          }                  $results = $this->_read_file($cache_file);
341                    $results = $this->_process_cached_inserts($results);
342  /*======================================================================*\                  if ($display) {
343          Function:       _modified_file()                      echo $results;
344          Input:          return comparison of modification times of files                      return;
345  \*======================================================================*/                  } else
346                        return $results;
347          function _modified_file($filepath, $compilepath)              }
348          {          }
349                  if(filemtime($filepath) >= filemtime($compilepath))  
350                          return true;          // compile files
351                  return false;          $this->_compile($this->template_dir);
352          }          //assemble compile directory path to file
353            $_compile_file = $this->compile_dir."/".$tpl_file.".php";
354  /*======================================================================*\  
355          Function:       _compile_file()          extract($this->_tpl_vars);
356          Input:          compile a template file  
357  \*======================================================================*/          // if we just need to display the results, don't perform output
358            // buffering - for speed
359          function _compile_file($filepath, $compilepath)          if ($display && !$this->caching)
360          {              include($_compile_file);
361                  if (!($template_contents = $this->_read_file($filepath)))          else {
362                          return false;              ob_start();
363                include($_compile_file);
364                  $this->_current_file = str_replace($this->template_dir . "/", "", $filepath);              $results = ob_get_contents();
365                  $this->_current_line_no = 1;              ob_end_clean();
366                  $ldq = preg_quote($this->left_delimiter, '!');          }
367                  $rdq = preg_quote($this->right_delimiter, '!');  
368            if($this->caching) {
369                  /* Pull out the literal blocks. */              $this->_write_file($cache_file, $results, true);
370                  preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_contents, $match);              $results = $this->_process_cached_inserts($results);
371                  $this->_literal_blocks = $match[1];          }
372                  $template_contents = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s",  
373                                                                                    '{literal}', $template_contents);          if ($display) {
374                echo $results;
375                  /* Gather all template tags. */              return;
376                  preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_contents, $match);          } else
377                  $template_tags = $match[1];              return $results;
378                  /* Split content by template tags to obtain non-template content. */      }  
379                  $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $template_contents);      
380                  if(!$this->allow_php) {  /*======================================================================*\
381                          /* Escape php tags. */      Function:   compile()
382                          $text_blocks = preg_replace('!<\?([^?]*?)\?>!', '&lt;?$1?&gt;', $text_blocks);      Purpose:    called to compile the templates
383                  }  \*======================================================================*/
384    
385                  /* Compile the template tags into PHP code. */      function _compile($tpl_dir)
386                  $compiled_tags = array();      {
387                  for ($i = 0; $i < count($template_tags); $i++) {          if($this->compile_check || $this->force_compile)
388                          $this->_current_line_no += substr_count($text_blocks[$i], "\n");          {
389                          $compiled_tags[] = $this->_compile_tag($template_tags[$i]);              if($this->_traverse_files($tpl_dir, 0))
390                          $this->_current_line_no += substr_count($template_tags[$i], "\n");                  return true;
391                  }              else
392                    return false;
393                  $compiled_contents = "";          } else
394                                return false;
395                  /* Interleave the compiled contents and text blocks to get the final result. */      }  
396                  for ($i = 0; $i < count($compiled_tags); $i++) {      
397                          $compiled_contents .= $text_blocks[$i].$compiled_tags[$i];  /*======================================================================*\
398                  }      Function:   _traverse_files()
399                  $compiled_contents .= $text_blocks[$i];      Purpose:    traverse the template files & process each one
400                    \*======================================================================*/
401                  /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */  
402                  if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_contents, $match)) {      function _traverse_files($tpl_dir, $depth)
403                          $strip_tags = $match[0];      {
404                          $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);          $retval = true;
405                          $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);  
406                          for ($i = 0; $i < count($strip_tags); $i++)          if (is_dir($tpl_dir)) {
407                                  $compiled_contents = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",              $dir_handle = opendir($tpl_dir);
408                                                                                                    $strip_tags_modified[$i], $compiled_contents, 1);              while ($curr_file = readdir($dir_handle)) {
409                  }                  if ($curr_file == '.' || $curr_file == '..')
410                        continue;
411                  if(!$this->_write_file($compilepath, $compiled_contents))  
412                          return false;                  $filepath = $tpl_dir.'/'.$curr_file;
413                    if (is_readable($filepath)) {
414                  return true;                      if (is_file($filepath) && substr($curr_file, -strlen($this->tpl_file_ext)) == $this->tpl_file_ext) {
415          }                          if (!$this->_process_file($filepath)) {
416                                $retval = false;
417          function _compile_tag($template_tag)                              break;
418          {                          }
419                  /* Matched comment. */                      } else if (is_dir($filepath)) {
420                  if ($template_tag{0} == '*' && $template_tag{strlen($template_tag)-1} == '*')                          if (!$this->_traverse_files($filepath, $depth + 1)) {
421                          return "";                              $retval = false;
422                                break;
423                  /* Split tag into two parts: command and the arguments. */                          }
424                  preg_match('/^(                      } else {
425                                             (?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'\s]+))+                          // invalid file type, skipping
426                                            )                          $this->_set_error_msg("Invalid filetype for $filepath, skipping");
427                                        (?:\s+(.*))?                          continue;
428                                          /xs', $template_tag, $match);                      }
429                  list(, $tag_command, $tag_args) = $match;                  }
430                }
431                  /* If the tag name matches a variable or section property definition,  
432                     we simply process it. */              closedir($dir_handle);
433                  if (preg_match('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tag_command) ||      // if a variable              return $retval;
434                          preg_match('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tag_command)            ||  // or a configuration variable          } else {
435                          preg_match('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tag_command)) {    // or a section property              $this->_set_error_msg("Directory \"$tpl_dir\" does not exist or is not a directory.");
436                          settype($tag_command, 'array');              return false;
437                          $this->_parse_vars_props($tag_command);          }
438                          return "<?php print $tag_command[0]; ?>";      }
439                  }  
440    /*======================================================================*\
441                  switch ($tag_command) {      Function:   _process_file()
442                          case 'include':      Input:      test template files for modifications
443                                  return $this->_compile_include_tag($tag_args);                  and execute the compilation for each
444                    one requiring it.
445                          case 'if':  \*======================================================================*/
446                                  return $this->_compile_if_tag($tag_args);  
447        function _process_file($filepath)
448                          case 'else':      {
449                                  return '<?php else: ?>';          if(preg_match("/^(.+)\/([^\/]+)$/", $filepath, $match)) {
450                $tpl_file_dir = $match[1];          
451                          case 'elseif':              $tpl_file_name = $match[2] . '.php';
452                                  return $this->_compile_if_tag($tag_args, true);  
453                $compile_dir = preg_replace('!^' . preg_quote($this->template_dir, '!') . '!',
454                          case '/if':                                          $this->compile_dir, $match[1]);
455                                  return '<?php endif; ?>';  
456                //create directory if none exists
457                          case 'ldelim':              $this->_create_dir_structure($compile_dir);
458                                  return $this->left_delimiter;  
459                // compile the template file if none exists or has been modified or recompile is forced
460                          case 'rdelim':              if ($this->force_compile || !file_exists($compile_dir."/".$tpl_file_name) ||
461                                  return $this->right_delimiter;                  ($this->_modified_file($filepath, $compile_dir."/".$tpl_file_name))) {
462                    if (!$this->_compile_file($filepath, $compile_dir."/".$tpl_file_name))
463                          case 'section':                      return false;
464                                  array_push($this->_sectionelse_stack, false);              } else {
465                                  return $this->_compile_section_start($tag_args);                  // no compilation needed
466                    return true;
467                          case 'sectionelse':              }
468                                  $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;          } else {
469                                  return "<?php endfor; else: ?>";              $this->_set_error_msg("problem matching \"$filepath.\"");
470                return false;
471                          case '/section':          }
472                                  if (array_pop($this->_sectionelse_stack))  
473                                          return "<?php endif; ?>";          return true;
474                                  else      }
475                                          return "<?php endfor; endif; ?>";  
476    /*======================================================================*\
477                          case 'config_load':      Function: _create_dir_structure
478                                  return $this->_compile_config_load_tag($tag_args);      Purpose:  create full directory structure
479    \*======================================================================*/
480                          case 'strip':      function _create_dir_structure($dir)
481                          case '/strip':      {
482                                  return $this->left_delimiter.$tag_command.$this->right_delimiter;          if (!file_exists($dir)) {
483                $dir_parts = preg_split('!/+!', $dir, -1, PREG_SPLIT_NO_EMPTY);
484                          case 'literal':              $new_dir = ($dir{0} == '/') ? '/' : '';
485                                  list (,$literal_block) = each($this->_literal_blocks);              foreach ($dir_parts as $dir_part) {
486                                  $this->_current_line_no += substr_count($literal_block, "\n");                  $new_dir .= $dir_part;
487                                  return $literal_block;                  if (!file_exists($new_dir) && !mkdir($new_dir, 0755)) {
488                        $this->_set_error_msg("problem creating directory \"$dir\"");
489                          case 'insert':                      return false;              
490                                  return $this->_compile_insert_tag($tag_args);                  }
491                    $new_dir .= '/';
492                          default:              }
493                                  if (isset($this->custom_funcs[$tag_command])) {          }
494                                          return $this->_compile_custom_tag($tag_command, $tag_args);      }
495                                  } else {  
496                                          $this->_syntax_error("unknown tag - '$tag_command'", E_USER_WARNING);  /*======================================================================*\
497                                          return "";      Function:   _modified_file()
498                                  }      Input:      return comparison of modification times of files
499                  }  \*======================================================================*/
500          }  
501        function _modified_file($filepath, $compilepath)
502        {
503          function _compile_custom_tag($tag_command, $tag_args)          if (filemtime($filepath) >= filemtime($compilepath))
504          {              return true;
505                  $attrs = $this->_parse_attrs($tag_args);          return false;
506                  $function = $this->custom_funcs[$tag_command];      }
507                  foreach ($attrs as $arg_name => $arg_value) {  
508                          if (is_bool($arg_value))  /*======================================================================*\
509                                  $arg_value = $arg_value ? 'true' : 'false';      Function:   _compile_file()
510                          $arg_list[] = "'$arg_name' => $arg_value";      Input:      compile a template file
511                  }  \*======================================================================*/
512    
513                  return "<?php $function(array(".implode(',', (array)$arg_list).")); ?>";      function _compile_file($filepath, $compilepath)
514          }      {
515            if (!($template_contents = $this->_read_file($filepath)))
516                return false;
517          function _compile_insert_tag($tag_args)  
518          {          $this->_current_file = str_replace($this->template_dir . '/', '', $filepath);
519                  $attrs = $this->_parse_attrs($tag_args);          $this->_current_line_no = 1;
520                  $name = substr($attrs['name'], 1, -1);          $ldq = preg_quote($this->left_delimiter, '!');
521            $rdq = preg_quote($this->right_delimiter, '!');
522                  if (empty($name)) {  
523                          $this->_syntax_error("missing insert name");          /* Pull out the literal blocks. */
524                  }          preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_contents, $match);
525            $this->_literal_blocks = $match[1];
526                  foreach ($attrs as $arg_name => $arg_value) {          $template_contents = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s",
527                          if ($arg_name == 'name') continue;                                            '{literal}', $template_contents);
528                          if (is_bool($arg_value))  
529                                  $arg_value = $arg_value ? 'true' : 'false';          /* Gather all template tags. */
530                          $arg_list[] = "'$arg_name' => $arg_value";          preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_contents, $match);
531                  }          $template_tags = $match[1];
532            /* Split content by template tags to obtain non-template content. */
533                  return "<?php print insert_$name(array(".implode(',', (array)$arg_list).")); ?>";          $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $template_contents);
534          }  
535            /* TODO: speed up the following with preg_replace and /F once we require that version of PHP */
536            
537          function _compile_config_load_tag($tag_args)          /* loop through text blocks */
538          {          for ($curr_tb = 0; $curr_tb <= count($text_blocks); $curr_tb++) {
539                  $attrs = $this->_parse_attrs($tag_args);              /* match anything within <? ?> */
540                if (preg_match_all('!(<\?[^?]*?\?>|<script\s+language\s*=\s*[\"\']?php[\"\']?\s*>)!is', $text_blocks[$curr_tb], $sp_match)) {
541                  if (empty($attrs['file'])) {                  /* found at least one match, loop through each one */
542                          $this->_syntax_error("missing 'file' attribute in config_load tag");                  for ($curr_sp = 0; $curr_sp < count($sp_match[0]); $curr_sp++) {
543                  }                      if (preg_match('!^(<\?(php\s|\s|=\s)|<script\s*language\s*=\s*[\"\']?php[\"\']?\s*>)!is', $sp_match[0][$curr_sp])) {
544                            /* php tag */
545                  $output  = "<?php if (!class_exists('Config_File'))\n" .                          if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
546                                     "    include_once 'Config_File.class.php';\n" .                              /* echo php contents */
547                             "if (!is_object(\$_conf_obj) || get_class(\$_conf_obj) != 'config_file') {\n" .                              $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '<?php echo \''.str_replace("'", "\'", $sp_match[0][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
548                                     "    \$_conf_obj  = new Config_File('".$this->config_dir."');\n" .                         } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
549                             "}\n" .                              /* quote php tags */
550                                     "\$_config = array_merge((array)\$_config, \$_conf_obj->get(".$attrs['file']."));\n";                              $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], htmlspecialchars($sp_match[0][$curr_sp]), $text_blocks[$curr_tb]);
551                            } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
552                  if (!empty($attrs['section']))                              /* remove php tags */
553                          $output .= '$_config = array_merge((array)$_config, $_conf_obj->get('.$attrs['file'].', '.$attrs['section'].')); ';                              if (substr($sp_match[0][$curr_sp], 0, 2) == '<?')
554                                    $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '', $text_blocks[$curr_tb]);
555                  $output .= '?>';                              else
556                                    /* attempt to remove everything between <script ...> and </script> */
557                  return $output;                                  $text_blocks[$curr_tb] = preg_replace('!'.preg_quote($sp_match[0][$curr_sp], '!').'.*?</script\s*>!is', '', $text_blocks[$curr_tb]);
558          }                          }
559                        } else
560                            /* echo the non-php tags */
561          function _compile_include_tag($tag_args)                          $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '<?php echo \''.str_replace("'", "\'", $sp_match[0][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
562          {                  }
563                  $attrs = $this->_parse_attrs($tag_args);              }
564            }
565                  if (empty($attrs['file'])) {                        
566                          $this->_syntax_error("missing 'file' attribute in include tag");          /* Compile the template tags into PHP code. */
567                  } else          $compiled_tags = array();
568                          $attrs['file'] = $this->_dequote($attrs['file']);          for ($i = 0; $i < count($template_tags); $i++) {
569                $this->_current_line_no += substr_count($text_blocks[$i], "\n");
570                  if (count($attrs) > 1) {              $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
571                          $include_func_name = uniqid("_include_");              $this->_current_line_no += substr_count($template_tags[$i], "\n");
572                          $include_file_name = $this->compile_dir.'/'.$attrs['file'];          }
573    
574                          foreach ($attrs as $arg_name => $arg_value) {          $compiled_contents = '';
575                                  if ($arg_name == 'file') continue;          
576                                  if (is_bool($arg_value))          /* Interleave the compiled contents and text blocks to get the final result. */
577                                          $arg_value = $arg_value ? 'true' : 'false';          for ($i = 0; $i < count($compiled_tags); $i++) {
578                                  $arg_list[] = "'$arg_name' => $arg_value";              $compiled_contents .= $text_blocks[$i].$compiled_tags[$i];
579                          }          }
580            $compiled_contents .= $text_blocks[$i];
581                          return  "<?php " .          
582                                          "function $include_func_name(\$file_name, \$def_vars, \$include_vars)\n" .          /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
583                                          "{\n" .          if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_contents, $match)) {
584                                          "       extract(\$def_vars);\n" .              $strip_tags = $match[0];
585                                          "       extract(\$include_vars);\n" .              $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
586                                          "       include \"\$file_name.php\";\n" .              $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
587                                          "}\n" .              for ($i = 0; $i < count($strip_tags); $i++)
588                                          "$include_func_name(\"$include_file_name\", get_defined_vars(), array(".implode(',', (array)$arg_list)."));\n?>\n";                  $compiled_contents = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
589                  } else                                                    $strip_tags_modified[$i], $compiled_contents, 1);
590                           return '<?php include "'.$this->compile_dir.'/'.$attrs['file'].'.php"; ?>';          }
591          }  
592            if(!$this->_write_file($compilepath, $compiled_contents))
593          function _compile_section_start($tag_args)              return false;
594          {  
595                  $attrs = $this->_parse_attrs($tag_args);          return true;
596        }
597                  $output = "<?php ";  
598                  $section_name = $attrs['name'];  /*======================================================================*\
599                  if (empty($section_name)) {      Function: _process_cached_inserts
600                          $this->_syntax_error("missing section name");      Purpose:  Replace cached inserts with the actual results
601                  }  \*======================================================================*/
602        function _process_cached_inserts($results)
603                  $output .= "unset(\$_sections[$section_name]);\n";      {
604                  $section_props = "\$_sections[$section_name]['properties']";          preg_match_all('!'.$this->_smarty_md5.'{insert_cache (.*)}'.$this->_smarty_md5.'!Uis',
605                           $results, $match);
606                  foreach ($attrs as $attr_name => $attr_value) {          list($cached_inserts, $insert_args) = $match;
607                          switch ($attr_name) {  
608                                  case 'loop':          for ($i = 0; $i < count($cached_inserts); $i++) {
609                                          $output .= "{$section_props}['loop'] = is_array($attr_value) ? count($attr_value) : $attr_value;\n";              $args = unserialize($insert_args[$i]);
610                                          break;              $name = $args['name'];
611                unset($args['name']);
612                                  case 'show':  
613                                          if (is_bool($attr_value))              $function_name = 'insert_' . $name;
614                                                  $attr_value = $attr_value ? 'true' : 'false';              $replace = $function_name($args);
615                                          $output .= "{$section_props}['$attr_name'] = $attr_value;\n";  
616                                          break;              $results = str_replace($cached_inserts[$i], $replace, $results);
617            }
618                                  default:  
619                                          $output .= "{$section_props}['$attr_name'] = $attr_value;\n";          return $results;
620                                          break;      }  
621                          }  
622                  }  
623    /*======================================================================*\
624                  if (isset($attrs['loop'])) {      Function: _compile_tag
625                          $loop_check_code = "{$section_props}['loop'] > 0 && ";      Purpose:  Compile a template tag
626                  } else {  \*======================================================================*/
627                          $output .= "{$section_props}['loop'] = 1; #-fix- \n";      function _compile_tag($template_tag)
628                  }      {
629            /* Matched comment. */
630                  if (isset($attrs['show'])) {          if ($template_tag{0} == '*' && $template_tag{strlen($template_tag)-1} == '*')
631                          $show_check_code = "{$section_props}['show'] && ";              return '';
632                  } else {  
633                          $output .= "{$section_props}['show'] = {$section_props}['loop'] > 0;\n";          $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
634                  }  
635            /* Split tag into two parts: command and the arguments. */
636                  $output .= "if ($loop_check_code $show_check_code true): ";          preg_match('/^(
637                           (?: ' . $qstr_regexp . ' | (?>[^"\'\s]+))+
638                  $output .= "                        )
639                          for ({$section_props}['index'] = 0;                        (?:\s+(.*))?
640                                   {$section_props}['index'] < {$section_props}['loop'];                      /xs', $template_tag, $match);
641                                   {$section_props}['index']++):\n";          list(, $tag_command, $tag_args) = $match;
642                  $output .= "{$section_props}['rownum'] = {$section_props}['index'] + 1;\n";  
643            /* If the tag name matches a variable or section property definition,
644                  $output .= "?>\n";             we simply process it. */
645            if (preg_match('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) ||   // if a variable
646                  return $output;              preg_match('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)     ||  // or a configuration variable
647          }              preg_match('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)) {    // or a section property
648                settype($tag_command, 'array');
649          function _compile_if_tag($tag_args, $elseif = false)              $this->_parse_vars_props($tag_command);
650          {              return "<?php echo $tag_command[0]; ?>\n";
651                  /* Tokenize args for 'if' tag. */          }
652                  preg_match_all('/(?:  
653                                                   "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"                 | # match all double quoted strings allowed escaped double quotes          switch ($tag_command) {
654                                                   \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'             | # match all single quoted strings allowed escaped single quotes              case 'include':
655                                                   [()]                                                                   | # match parentheses                  return $this->_compile_include_tag($tag_args);
656                                                   [^"\'\s()]+                                                      # match any other token that is not any of the above  
657                                                  )/x', $tag_args, $match);              case 'if':
658                  $tokens = $match[0];                  return $this->_compile_if_tag($tag_args);
659    
660                  $this->_parse_vars_props($tokens);              case 'else':
661                    return '<?php else: ?>';
662                  $is_arg_stack = array();  
663                                case 'elseif':
664                  for ($i = 0; $i < count($tokens); $i++) {                  return $this->_compile_if_tag($tag_args, true);
665                          $token = &$tokens[$i];  
666                          switch ($token) {              case '/if':
667                                  case 'eq':                  return '<?php endif; ?>';
668                                          $token = '==';  
669                                          break;              case 'ldelim':
670                    return $this->left_delimiter;
671                                  case 'ne':  
672                                  case 'neq':              case 'rdelim':
673                                          $token = '!=';                  return $this->right_delimiter;
674                                          break;  
675                case 'section':
676                                  case 'lt':                  array_push($this->_sectionelse_stack, false);
677                                          $token = '<';                  return $this->_compile_section_start($tag_args);
678                                          break;  
679                case 'sectionelse':
680                                  case 'le':                  $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;
681                                  case 'lte':                  return "<?php endfor; else: ?>";
682                                          $token = '<=';  
683                                          break;              case '/section':
684                    if (array_pop($this->_sectionelse_stack))
685                                  case 'gt':                      return "<?php endif; ?>";
686                                          $token = '>';                  else
687                                          break;                      return "<?php endfor; endif; ?>";
688                                    
689                                  case 'ge':              case 'config_load':
690                                  case 'gte':                  return $this->_compile_config_load_tag($tag_args);
691                                          $token = '>=';  
692                                          break;              case 'strip':
693                case '/strip':
694                                  case 'and':                  return $this->left_delimiter.$tag_command.$this->right_delimiter;
695                                          $token = '&&';  
696                                          break;              case 'literal':
697                    list (,$literal_block) = each($this->_literal_blocks);
698                                  case 'or':                  $this->_current_line_no += substr_count($literal_block, "\n");
699                                          $token = '||';                  return $literal_block;
700                                          break;  
701                case 'insert':
702                                  case 'not':                  return $this->_compile_insert_tag($tag_args);
703                                          $token = '!';  
704                                          break;              default:
705                    if (isset($this->custom_funcs[$tag_command])) {
706                                  case 'mod':                      return $this->_compile_custom_tag($tag_command, $tag_args);
707                                          $token = '%';                  } else {
708                                          break;                      $this->_syntax_error("unknown tag - '$tag_command'", E_USER_WARNING);
709                        return;
710                                  case '(':                  }
711                                          array_push($is_arg_stack, $i);          }
712                                          break;      }
713    
714                                  case 'is':      function _compile_custom_tag($tag_command, $tag_args)
715                                          /* If last token was a ')', we operate on the parenthesized      {
716                                             expression. The start of the expression is on the stack.          $function = $this->custom_funcs[$tag_command];
717                                             Otherwise, we operate on the last encountered token. */  
718                                          if ($tokens[$i-1] == ')')          if (!function_exists($function)) {
719                                                  $is_arg_start = array_pop($is_arg_stack);              $this->_syntax_error("custom function '$tag_command' is not implemented", E_USER_WARNING);
720                                          else              return;
721                                                  $is_arg_start = $i-1;          }
722                                          /* Construct the argument for 'is' expression, so it knows          
723                                             what to operate on. */          $attrs = $this->_parse_attrs($tag_args);
724                                          $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));          foreach ($attrs as $arg_name => $arg_value) {
725                if (is_bool($arg_value))
726                                          /* Pass all tokens from next one until the end to the                  $arg_value = $arg_value ? 'true' : 'false';
727                                             'is' expression parsing function. The function will              $arg_list[] = "'$arg_name' => $arg_value";
728                                             return modified tokens, where the first one is the result          }
729                                             of the 'is' expression and the rest are the tokens it  
730                                             didn't touch. */          return "<?php $function(array(".implode(',', (array)$arg_list).")); ?>";
731                                          $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));      }
732    
733                                          /* Replace the old tokens with the new ones. */  
734                                          array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);  /*======================================================================*\
735        Function: _compile_insert_tag
736                                          /* Adjust argument start so that it won't change from the      Purpose:  Compile {insert ...} tag
737                                             current position for the next iteration. */  \*======================================================================*/
738                                          $i = $is_arg_start;      function _compile_insert_tag($tag_args)
739                                          break;      {
740                          }          $attrs = $this->_parse_attrs($tag_args);
741                  }          $name = substr($attrs['name'], 1, -1);
742    
743                  if ($elseif)          if (empty($name)) {
744                          return '<?php elseif ('.implode(' ', $tokens).'): ?>';              $this->_syntax_error("missing insert name");
745                  else          }
746                          return '<?php if ('.implode(' ', $tokens).'): ?>';  
747          }          foreach ($attrs as $arg_name => $arg_value) {
748                if (is_bool($arg_value))
749          function _parse_is_expr($is_arg, $tokens)                  $arg_value = $arg_value ? 'true' : 'false';
750          {              $arg_list[] = "'$arg_name' => $arg_value";
751                  $expr_end = 0;          }
752    
753                  if (($first_token = array_shift($tokens)) == 'not') {          return "<?php echo _smarty_insert_handler(array(".implode(', ', (array)$arg_list)."), \$this->caching, \$this->_smarty_md5); ?>\n";
754                          $negate_expr = true;      }  
755                          $expr_type = array_shift($tokens);  
756                  } else  
757                          $expr_type = $first_token;  /*======================================================================*\
758        Function: _compile_config_load_tag
759                  switch ($expr_type) {      Purpose:  Compile {config_load ...} tag
760                          case 'even':  \*======================================================================*/
761                                  if ($tokens[$expr_end] == 'by') {      function _compile_config_load_tag($tag_args)
762                                          $expr_end++;      {
763                                          $expr_arg = $tokens[$expr_end++];          $attrs = $this->_parse_attrs($tag_args);
764                                          $expr = "!(($is_arg / $expr_arg) % $expr_arg)";  
765                                  }          if (empty($attrs['file'])) {
766                                  else              $this->_syntax_error("missing 'file' attribute in config_load tag");
767                                          $expr = "!($is_arg % 2)";          }
768                                  break;  
769            $output  = "<?php if (!class_exists('Config_File'))\n" .
770                          case 'odd':                     "    include_once 'Config_File.class.php';\n" .
771                                  if ($tokens[$expr_end] == 'by') {                     "if (!is_object(\$_conf_obj) || get_class(\$_conf_obj) != 'config_file') {\n" .
772                                          $expr_end++;                     "    \$_conf_obj  = new Config_File('".$this->config_dir."');\n" .
773                                          $expr_arg = $tokens[$expr_end++];                     "}\n" .
774                                          $expr = "(($is_arg / $expr_arg) % $expr_arg)";                     "\$_config = array_merge((array)\$_config, \$_conf_obj->get(".$attrs['file']."));\n";
775                                  }  
776                                  else          if (!empty($attrs['section']))
777                                          $expr = "($is_arg % 2)";              $output .= '$_config = array_merge((array)$_config, $_conf_obj->get('.$attrs['file'].', '.$attrs['section'].')); ';
778                                  break;  
779            $output .= '?>';
780                          case 'div':  
781                                  if ($tokens[$expr_end] == 'by') {          return $output;
782                                          $expr_end++;      }
783                                          $expr_arg = $tokens[$expr_end++];  
784                                          $expr = "!($is_arg % $expr_arg)";  
785                                  } else {  /*======================================================================*\
786                                          $this->_syntax_error("expecting 'by' after 'div'");      Function: _compile_include_tag
787                                  }      Purpose:  Compile {include ...} tag
788                                  break;  \*======================================================================*/
789        function _compile_include_tag($tag_args)
790                          default:      {
791                                  $this->_syntax_error("unknown 'is' expression - '$expr_type'");          $attrs = $this->_parse_attrs($tag_args);
792                                  break;  
793                  }          if (empty($attrs['file'])) {
794                $this->_syntax_error("missing 'file' attribute in include tag");
795                  if ($negate_expr) {          } else
796                          $expr = "!($expr)";              $attrs['file'] = $this->_dequote($attrs['file']);
797                  }  
798            if (count($attrs) > 1) {
799                  array_splice($tokens, 0, $expr_end, $expr);              $include_func_name = uniqid("_include_");
800                $include_file_name = $this->compile_dir.'/'.$attrs['file'];
801                  return $tokens;  
802          }              foreach ($attrs as $arg_name => $arg_value) {
803                    if ($arg_name == 'file') continue;
804          function _parse_attrs($tag_args)                  if (is_bool($arg_value))
805          {                      $arg_value = $arg_value ? 'true' : 'false';
806                  /* Tokenize tag attributes. */                  $arg_list[] = "'$arg_name' => $arg_value";
807                  preg_match_all('/(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"       |              }
808                                                    \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     | (?>[^"\'=\s]+)  
809                                                   )+ |              return  "<?php " .
810                                                   [=]                      "if (!function_exists('$include_func_name')) {\n".
811                                              /x', $tag_args, $match);                      "   function $include_func_name(\$file_name, \$def_vars, \$include_vars)\n" .
812                  $tokens = $match[0];                      "   {\n" .
813                  $var_delims = array('$', '#', '%');                      "       extract(\$def_vars);\n" .
814                        "       extract(\$include_vars);\n" .
815                  $attrs = array();                      "       include \"\$file_name.php\";\n" .
816                  /* Parse state:                      "   }\n" .
817                          0 - expecting attr name                      "}\n" .
818                          1 - expecting '=' or another attr name                      "$include_func_name(\"$include_file_name\", get_defined_vars(), array(".implode(',', (array)$arg_list)."));\n?>";
819                          2 - expecting attr value (not '=') */          } else
820                  $state = 0;               return '<?php include "'.$this->compile_dir.'/'.$attrs['file'].'.php"; ?>';
821        }
822                  foreach ($tokens as $token) {  
823                          switch ($state) {  
824                                  case 0:  /*======================================================================*\
825                                          /* If the token is a valid identifier, we set attribute name      Function: _compile_section_start
826                                             and go to state 1. */      Purpose:  Compile {section ...} tag
827                                          if (preg_match('!\w+!', $token)) {  \*======================================================================*/
828                                                  $attr_name = $token;      function _compile_section_start($tag_args)
829                                                  $state = 1;      {
830                                          } else          $attrs = $this->_parse_attrs($tag_args);
831                                                  $this->_syntax_error("invalid attribute name - '$token'");  
832                                          break;          $output = "<?php ";
833            $section_name = $attrs['name'];
834                                  case 1:          if (empty($section_name)) {
835                                          /* If the token is a valid identifier, the previously set              $this->_syntax_error("missing section name");
836                                             attribute name does not need an argument. We put it in          }
837                                             the attrs array, set the new attribute name to the  
838                                             current token and don't switch state.          $output .= "unset(\$_sections[$section_name]);\n";
839            $section_props = "\$_sections[$section_name]['properties']";
840                                             If the token is '=', then we go to state 2. */  
841                                          if ($token == '=') {          foreach ($attrs as $attr_name => $attr_value) {
842                                                  $state = 2;              switch ($attr_name) {
843                                          } else                  case 'loop':
844                                                  $this->_syntax_error("expecting '=' after attribute name");                      $output .= "{$section_props}['loop'] = is_array($attr_value) ? count($attr_value) : $attr_value;\n";
845                                          break;                      break;
846    
847                                  case 2:                  case 'show':
848                                          /* If token is not '=', we set the attribute value and go to                      if (is_bool($attr_value))
849                                             state 0. */                          $attr_value = $attr_value ? 'true' : 'false';
850                                          if ($token != '=') {                      $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
851                                                  /* We booleanize the token if it's a non-quoted possible                      break;
852                                                     boolean value. */  
853                                                  if (preg_match('!^(on|yes|true)$!', $token))                  default:
854                                                          $token = true;                      $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
855                                                  else if (preg_match('!^(off|no|false)$!', $token))                      break;
856                                                          $token = false;              }
857                                                  /* If the token is not variable (doesn't start with          }
858                                                     '$', '#', or '%') and not enclosed in single or  
859                                                     double quotes we single-quote it. */          if (isset($attrs['loop'])) {
860                                                  else if (!in_array($token{0}, $var_delims) &&              $loop_check_code = "{$section_props}['loop'] > 0 && ";
861                                                                   !(($token{0} == '"' || $token[0] == "'") &&          } else {
862                                                                   $token{strlen($token)-1} == $token{0}))              $output .= "{$section_props}['loop'] = 1;\n";
863                                                          $token = "'".$token."'";          }
864    
865                                                  $attrs[$attr_name] = $token;          if (isset($attrs['show'])) {
866                                                  $state = 0;              $show_check_code = "{$section_props}['show'] && ";
867                                          } else          } else {
868                                                  $this->_syntax_error("'=' cannot be an attribute value");              $output .= "{$section_props}['show'] = {$section_props}['loop'] > 0;\n";
869                                          break;          }
870                          }  
871                  }          $output .= "if ($loop_check_code $show_check_code true): ";
872    
873                  $this->_parse_vars_props($attrs);          $output .= "
874                for ({$section_props}['index'] = 0;
875                  return $attrs;                   {$section_props}['index'] < {$section_props}['loop'];
876          }                   {$section_props}['index']++):\n";
877            $output .= "{$section_props}['rownum'] = {$section_props}['index'] + 1;\n";
878          function _preg_grep($pattern, $array)  
879          {          $output .= "?>";
880                  $result = array();  
881            return $output;
882                  foreach ($array as $key => $entry) {      }
883                          if (preg_match($pattern, $entry))  
884                                  $result[$key] = $entry;  
885                  }  /*======================================================================*\
886        Function: _compile_if_tag
887                  return $result;      Purpose:  Compile {if ...} tag
888          }  \*======================================================================*/
889                function _compile_if_tag($tag_args, $elseif = false)
890          function _parse_vars_props(&$tokens)      {
891          {          /* Tokenize args for 'if' tag. */
892                  /* preg_grep() was fixed to return keys properly in 4.0.4 and later. To          preg_match_all('/(?:
893                     allow people to use older versions of PHP we emulate preg_grep() and                           "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"         | # match all double quoted strings allowed escaped double quotes
894                     use the version check to see what function to call. */                           \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     | # match all single quoted strings allowed escaped single quotes
895                  if (strnatcmp(PHP_VERSION, '4.0.4') >= 0) {                           [()]                                   | # match parentheses
896                          $var_exprs = preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);                           [^"\'\s()]+                              # match any other token that is not any of the above
897                          $conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);                          )/x', $tag_args, $match);
898                          $sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);          $tokens = $match[0];
899                  } else {  
900                          $var_exprs = $this->_preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);          $this->_parse_vars_props($tokens);
901                          $conf_var_exprs = $this->_preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);  
902                          $sect_prop_exprs = $this->_preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);          $is_arg_stack = array();
903                  }          
904            for ($i = 0; $i < count($tokens); $i++) {
905                  if (count($var_exprs)) {              $token = &$tokens[$i];
906                          foreach ($var_exprs as $expr_index => $var_expr) {              switch ($token) {
907                                  $tokens[$expr_index] = $this->_parse_var($var_expr);                  case 'eq':
908                          }                      $token = '==';
909                  }                      break;
910                    
911                  if (count($conf_var_exprs)) {                  case 'ne':
912                          foreach ($conf_var_exprs as $expr_index => $var_expr) {                  case 'neq':
913                                  $tokens[$expr_index] = $this->_parse_conf_var($var_expr);                      $token = '!=';
914                          }                      break;
915                  }  
916                    case 'lt':
917                  if (count($sect_prop_exprs)) {                      $token = '<';
918                          foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {                      break;
919                                  $tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);  
920                          }                  case 'le':
921                  }                  case 'lte':
922          }                      $token = '<=';
923                        break;
924          function _parse_var($var_expr)  
925          {                  case 'gt':
926                  $modifiers = explode('|', substr($var_expr, 1));                      $token = '>';
927                        break;
928                  $sections = explode('/', array_shift($modifiers));                  
929                  $props = explode('.', array_pop($sections));                  case 'ge':
930                  $var_name = array_shift($props);                  case 'gte':
931                        $token = '>=';
932                  $output = "\$$var_name";                      break;
933    
934                  foreach ($sections as $section) {                  case 'and':
935                          $output .= "[\$_sections['$section']['properties']['index']]";                      $token = '&&';
936                  }                      break;
937                  foreach ($props as $prop) {  
938                          $output .= "['$prop']";                  case 'or':
939                  }                      $token = '||';
940                        break;
941                  $this->_parse_modifiers($output, $modifiers);  
942                    case 'not':
943                  return $output;                      $token = '!';
944          }                      break;
945    
946          function _parse_conf_var($conf_var_expr)                  case 'mod':
947          {                      $token = '%';
948                  $modifiers = explode('|', $conf_var_expr);                      break;
949    
950                  $var_name = substr(array_shift($modifiers), 1, -1);                  case '(':
951                        array_push($is_arg_stack, $i);
952                  $output = "\$_config['$var_name']";                      break;
953    
954                  $this->_parse_modifiers($output, $modifiers);                  case 'is':
955                        /* If last token was a ')', we operate on the parenthesized
956                  return $output;                         expression. The start of the expression is on the stack.
957          }                         Otherwise, we operate on the last encountered token. */
958                        if ($tokens[$i-1] == ')')
959          function _parse_section_prop($section_prop_expr)                          $is_arg_start = array_pop($is_arg_stack);
960          {                      else
961                  $modifiers = explode('|', $section_prop_expr);                          $is_arg_start = $i-1;
962                        /* Construct the argument for 'is' expression, so it knows
963                  preg_match('!%(\w+)\.(\w+)%!', array_shift($modifiers), $match);                         what to operate on. */
964                  $section_name = $match[1];                      $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
965                  $prop_name = $match[2];  
966                        /* Pass all tokens from next one until the end to the
967                  $output = "\$_sections['$section_name']['properties']['$prop_name']";                         'is' expression parsing function. The function will
968                           return modified tokens, where the first one is the result
969                  $this->_parse_modifiers($output, $modifiers);                         of the 'is' expression and the rest are the tokens it
970                           didn't touch. */
971                  return $output;                      $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
972          }  
973                        /* Replace the old tokens with the new ones. */
974          function _parse_modifiers(&$output, $modifiers)                      array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
975          {  
976                  foreach ($modifiers as $modifier) {                      /* Adjust argument start so that it won't change from the
977                          $modifier = explode(':', $modifier);                         current position for the next iteration. */
978                          $modifier_name = array_shift($modifier);                      $i = $is_arg_start;
979                        break;
980                          if ($modifier_name{0} == '@') {              }
981                                  $map_array = 'false';          }
982                                  $modifier_name = substr($modifier_name, 1);  
983                          } else          if ($elseif)
984                                  $map_array = 'true';              return '<?php elseif ('.implode(' ', $tokens).'): ?>';
985            else
986                          /*              return '<?php if ('.implode(' ', $tokens).'): ?>';
987                           * First we lookup the modifier function name in the registered      }
988                           * modifiers table.  
989                           */      function _parse_is_expr($is_arg, $tokens)
990                          $mod_func_name = $this->custom_mods[$modifier_name];      {
991            $expr_end = 0;
992                          /*  
993                           * If we don't find that modifier there, we assume it's just a PHP          if (($first_token = array_shift($tokens)) == 'not') {
994                           * function name.              $negate_expr = true;
995                           */              $expr_type = array_shift($tokens);
996                          if (!isset($mod_func_name))          } else
997                                  $mod_func_name = $modifier_name;              $expr_type = $first_token;
998    
999                          $this->_parse_vars_props($modifier);          switch ($expr_type) {
1000                case 'even':
1001                          if (count($modifier) > 0)                  if ($tokens[$expr_end] == 'by') {
1002                                  $modifier_args = ', '.implode(', ', $modifier);                      $expr_end++;
1003                          else                      $expr_arg = $tokens[$expr_end++];
1004                                  $modifier_args = '';                      $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
1005                    }
1006                          $output = "_smarty_mod_handler('$mod_func_name', $map_array, $output$modifier_args)";                  else
1007                  }                      $expr = "!($is_arg % 2)";
1008          }                  break;
1009            
1010                case 'odd':
1011  /*======================================================================*\                  if ($tokens[$expr_end] == 'by') {
1012          Function: _dequote                      $expr_end++;
1013          Purpose:  Remove starting and ending quotes from the string                      $expr_arg = $tokens[$expr_end++];
1014  \*======================================================================*/                      $expr = "(($is_arg / $expr_arg) % $expr_arg)";
1015          function _dequote($string)                  }
1016          {                  else
1017                  if (($string{0} == "'" || $string{0} == '"') &&                      $expr = "($is_arg % 2)";
1018                          $string{strlen($string)-1} == $string{0})                  break;
1019                          return substr($string, 1, -1);  
1020          }              case 'div':
1021                    if ($tokens[$expr_end] == 'by') {
1022                                $expr_end++;
1023  /*======================================================================*\                      $expr_arg = $tokens[$expr_end++];
1024          Function:       _read_file()                      $expr = "!($is_arg % $expr_arg)";
1025          Purpose:        read in a file                  } else {
1026  \*======================================================================*/                      $this->_syntax_error("expecting 'by' after 'div'");
1027                    }
1028          function _read_file($filename)                  break;
1029          {  
1030                  if(!($fd = fopen($filename, 'r'))) {              default:
1031                          $this->_set_error_msg("problem reading '$filename.'");                  $this->_syntax_error("unknown 'is' expression - '$expr_type'");
1032                          return false;                  break;
1033                  }          }
1034                  $contents = fread($fd, filesize($filename));  
1035                  fclose($fd);          if ($negate_expr) {
1036                  return $contents;              $expr = "!($expr)";
1037          }          }
1038    
1039  /*======================================================================*\          array_splice($tokens, 0, $expr_end, $expr);
1040          Function:       _write_file()  
1041          Purpose:        write out a file          return $tokens;
1042  \*======================================================================*/      }
1043    
1044          function _write_file($filename,$contents)  
1045          {  /*======================================================================*\
1046                  if(!($fd = fopen($filename, 'w'))) {      Function: _parse_attrs
1047                          $this->_set_error_msg("problem writing '$filename.'");      Purpose:  Parse attribute string
1048                          return false;  \*======================================================================*/
1049                  }      function _parse_attrs($tag_args, $quote = true)
1050                  fwrite($fd, $contents);      {
1051                  fclose($fd);          /* Tokenize tag attributes. */
1052                  return true;          preg_match_all('/(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"       |
1053          }                            \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     | (?>[^"\'=\s]+)
1054                             )+ |
1055  /*======================================================================*\                           [=]
1056          Function:       _set_error_msg()                          /x', $tag_args, $match);
1057          Purpose:        set the error message          $tokens       = $match[0];
1058  \*======================================================================*/          $var_delims   = array('$', '#', '%');
1059    
1060          function _set_error_msg($error_msg)          $attrs = array();
1061          {          /* Parse state:
1062                  $this->_error_msg="smarty error: $error_msg";              0 - expecting attribute name
1063                  return true;              1 - expecting '='
1064          }              2 - expecting attribute value (not '=') */
1065            $state = 0;
1066  /*======================================================================*\  
1067          Function: _syntax_error          foreach ($tokens as $token) {
1068          Purpose:  display Smarty syntax error              switch ($state) {
1069  \*======================================================================*/                  case 0:
1070          function _syntax_error($error_msg, $error_type = E_USER_ERROR)                      /* If the token is a valid identifier, we set attribute name
1071          {                         and go to state 1. */
1072                  trigger_error("Smarty: [in " . $this->_current_file . " line " .                      if (preg_match('!^\w+$!', $token)) {
1073                                            $this->_current_line_no . "]: syntax error: $error_msg", $error_type);                          $attr_name = $token;
1074          }                          $state = 1;
1075                        } else
1076                            $this->_syntax_error("invalid attribute name - '$token'");
1077                        break;
1078    
1079                    case 1:
1080                        /* If the token is '=', then we go to state 2. */
1081                        if ($token == '=') {
1082                            $state = 2;
1083                        } else
1084                            $this->_syntax_error("expecting '=' after attribute name");
1085                        break;
1086    
1087                    case 2:
1088                        /* If token is not '=', we set the attribute value and go to
1089                           state 0. */
1090                        if ($token != '=') {
1091                            /* We booleanize the token if it's a non-quoted possible
1092                               boolean value. */
1093                            if (preg_match('!^(on|yes|true)$!', $token))
1094                                $token = true;
1095                            else if (preg_match('!^(off|no|false)$!', $token))
1096                                $token = false;
1097                            /* If the token is not variable (doesn't start with
1098                               '$', '#', or '%') and not enclosed in single or
1099                               double quotes we single-quote it. */
1100                            else if ($quote && !in_array($token{0}, $var_delims) &&
1101                                     !(($token{0} == '"' || $token[0] == "'") &&
1102                                     $token{strlen($token)-1} == $token{0}))
1103                                $token = "'".$token."'";
1104    
1105                            $attrs[$attr_name] = $token;
1106                            $state = 0;
1107                        } else
1108                            $this->_syntax_error("'=' cannot be an attribute value");
1109                        break;
1110                }
1111            }
1112    
1113            $this->_parse_vars_props($attrs);
1114    
1115            return $attrs;
1116        }
1117    
1118    
1119    /*======================================================================*\
1120        Function: _preg_grep
1121        Purpose:  Emulate PHP's preg_grep()
1122    \*======================================================================*/
1123        function _preg_grep($pattern, $array)
1124        {
1125            $result = array();
1126    
1127            foreach ($array as $key => $entry) {
1128                if (preg_match($pattern, $entry))
1129                    $result[$key] = $entry;
1130            }
1131    
1132            return $result;
1133        }
1134        
1135        function _parse_vars_props(&$tokens)
1136        {
1137            $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
1138    
1139            /* preg_grep() was fixed to return keys properly in 4.0.4 and later. To
1140               allow people to use older versions of PHP we emulate preg_grep() and
1141               use the version check to see what function to call. */
1142            if (strnatcmp(PHP_VERSION, '4.0.4') >= 0) {
1143                $var_exprs = preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:(?>' .  $qstr_regexp . '|[^|]+))*)*$!', $tokens);
1144                $conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
1145                $sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:(?>' .  $qstr_regexp .  '|[^|]+))*)*$!', $tokens);
1146            } else {
1147                $var_exprs = $this->_preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:(?>' .  $qstr_regexp .  '|[^|]+))*)*$!', $tokens);
1148                $conf_var_exprs = $this->_preg_grep('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
1149                $sect_prop_exprs = $this->_preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:(?>' .  $qstr_regexp .  '|[^|]+))*)*$!', $tokens);
1150            }
1151    
1152            if (count($var_exprs)) {
1153                foreach ($var_exprs as $expr_index => $var_expr) {
1154                    $tokens[$expr_index] = $this->_parse_var($var_expr);
1155                }
1156            }
1157            
1158            if (count($conf_var_exprs)) {
1159                foreach ($conf_var_exprs as $expr_index => $var_expr) {
1160                    $tokens[$expr_index] = $this->_parse_conf_var($var_expr);
1161                }
1162            }
1163    
1164            if (count($sect_prop_exprs)) {
1165                foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {
1166                    $tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);
1167                }
1168            }
1169        }
1170    
1171        function _parse_var($var_expr)
1172        {
1173            list($var_ref, $modifiers) = explode('|', substr($var_expr, 1), 2);
1174    
1175            $sections = explode('/', $var_ref);
1176            $props = explode('.', array_pop($sections));
1177            $var_name = array_shift($props);
1178    
1179            $output = "\$$var_name";
1180    
1181            foreach ($sections as $section) {
1182                $output .= "[\$_sections['$section']['properties']['index']]";
1183            }
1184            foreach ($props as $prop) {
1185                $output .= "['$prop']";
1186            }
1187    
1188            $this->_parse_modifiers($output, $modifiers);
1189    
1190            return $output;
1191        }
1192    
1193        function _parse_conf_var($conf_var_expr)
1194        {
1195            list($var_ref, $modifiers) = explode('|', $conf_var_expr, 2);
1196    
1197            $var_name = substr($var_ref, 1, -1);
1198    
1199            $output = "\$_config['$var_name']";
1200    
1201            $this->_parse_modifiers($output, $modifiers);
1202    
1203            return $output;
1204        }
1205    
1206        function _parse_section_prop($section_prop_expr)
1207        {
1208            list($var_ref, $modifiers) = explode('|', $section_prop_expr, 2);
1209    
1210            preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
1211            $section_name = $match[1];
1212            $prop_name = $match[2];
1213    
1214            $output = "\$_sections['$section_name']['properties']['$prop_name']";
1215    
1216            $this->_parse_modifiers($output, $modifiers);
1217    
1218            return $output;
1219        }
1220    
1221        function _parse_modifiers(&$output, $modifier_string)
1222        {
1223            $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
1224            preg_match_all('!\|(@?\w+)((?>:(?:'. $qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $match);
1225            list(, $modifiers, $modifier_arg_strings) = $match;
1226    
1227            for ($i = 0; $i < count($modifiers); $i++) {
1228                $modifier_name = $modifiers[$i];
1229                preg_match_all('!:(' . $qstr_regexp . '|[^:]+)!', $modifier_arg_strings[$i], $match);
1230                $modifier_args = $match[1];
1231    
1232                if ($modifier_name{0} == '@') {
1233                    $map_array = 'false';
1234                    $modifier_name = substr($modifier_name, 1);
1235                } else
1236                    $map_array = 'true';
1237    
1238                /*
1239                 * First we lookup the modifier function name in the registered
1240                 * modifiers table.
1241                 */
1242                $mod_func_name = $this->custom_mods[$modifier_name];
1243    
1244                /*
1245                 * If we don't find that modifier there, we assume it's just a PHP
1246                 * function name.
1247                 */
1248                if (!isset($mod_func_name))
1249                    $mod_func_name = $modifier_name;
1250    
1251                if (!function_exists($mod_func_name)) {
1252                    $this->_syntax_error("modifier '$modifier_name' is not implemented", E_USER_WARNING);
1253                    continue;
1254                }
1255    
1256                $this->_parse_vars_props($modifier_args);
1257    
1258                if (count($modifier_args) > 0)
1259                    $modifier_args = ', '.implode(', ', $modifier_args);
1260                else
1261                    $modifier_args = '';
1262    
1263                $output = "_smarty_mod_handler('$mod_func_name', $map_array, $output$modifier_args)";
1264            }
1265        }
1266        
1267    
1268    /*======================================================================*\
1269        Function: _dequote
1270        Purpose:  Remove starting and ending quotes from the string
1271    \*======================================================================*/
1272        function _dequote($string)
1273        {
1274            if (($string{0} == "'" || $string{0} == '"') &&
1275                $string{strlen($string)-1} == $string{0})
1276                return substr($string, 1, -1);
1277            else
1278                return $string;
1279        }
1280    
1281        
1282    /*======================================================================*\
1283        Function:   _read_file()
1284        Purpose:    read in a file
1285    \*======================================================================*/
1286    
1287        function _read_file($filename)
1288    
1289        {
1290            if (!($fd = fopen($filename, 'r'))) {
1291                $this->_set_error_msg("problem reading '$filename.'");
1292                return false;
1293            }
1294            flock($fd, LOCK_SH);
1295            $contents = fread($fd, filesize($filename));
1296            fclose($fd);
1297            return $contents;
1298        }
1299    
1300    /*======================================================================*\
1301        Function:   _write_file()
1302        Purpose:    write out a file
1303    \*======================================================================*/
1304    
1305        function _write_file($filename, $contents, $create_dirs = false)
1306        {
1307            if($create_dirs)
1308                $this->_create_dir_structure(dirname($filename));
1309            
1310            if (!($fd = fopen($filename, 'a'))) {
1311                $this->_set_error_msg("problem writing '$filename.'");
1312                return false;
1313            }
1314            flock($fd, LOCK_EX);
1315    
1316            $fd_safe = fopen($filename, 'w');
1317    
1318            fwrite($fd_safe, $contents);
1319            fclose($fd_safe);
1320            fclose($fd);
1321    
1322            return true;
1323        }    
1324    
1325    
1326    /*======================================================================*\
1327        Function: _clear_tpl_cache_dir
1328        Purpose:  Clear the specified template cache
1329    \*======================================================================*/
1330        function _clear_tpl_cache_dir($cache_tpl_md5)
1331        {
1332            $cache_dir = $this->cache_dir.'/'.$cache_tpl_md5;
1333    
1334            if (!is_dir($cache_dir))
1335                return false;
1336    
1337            $dir_handle = opendir($cache_dir);
1338            while ($curr_dir = readdir($dir_handle)) {
1339                $cache_path_dir = $cache_dir.'/'.$curr_dir;
1340                if ($curr_dir == '.' || $curr_dir == '..' ||
1341                    !is_dir($cache_path_dir))
1342                    continue;
1343    
1344                $dir_handle2 = opendir($cache_path_dir);
1345                while ($curr_file = readdir($dir_handle2)) {
1346                    if ($curr_file == '.' || $curr_file == '..')
1347                        continue;
1348    
1349                    $cache_file = $cache_path_dir.'/'.$curr_file;
1350                    if (is_file($cache_file))
1351                        unlink($cache_file);
1352                }
1353                closedir($dir_handle2);
1354                @rmdir($cache_path_dir);
1355            }
1356            closedir($dir_handle);
1357            @rmdir($cache_dir);
1358    
1359            return true;
1360        }
1361    
1362    
1363    /*======================================================================*\
1364        Function:   _set_error_msg()
1365        Purpose:    set the error message
1366    \*======================================================================*/
1367    
1368        function _set_error_msg($error_msg)
1369        {
1370            $this->_error_msg="smarty error: $error_msg";
1371            return true;
1372        }
1373    
1374    /*======================================================================*\
1375        Function: _syntax_error
1376        Purpose:  display Smarty syntax error
1377    \*======================================================================*/
1378        function _syntax_error($error_msg, $error_type = E_USER_ERROR)
1379        {
1380            trigger_error("Smarty: [in " . $this->_current_file . " line " .
1381                          $this->_current_line_no . "]: syntax error: $error_msg", $error_type);
1382        }
1383  }  }
1384    
1385    /* vim: set expandtab: */
1386    
1387  ?>  ?>

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.3

  ViewVC Help
Powered by ViewVC 1.1.26