/[hr-web]/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

Annotation of /inc/Smarty.class.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (hide annotations) (vendor branch)
Fri Apr 20 08:25:32 2001 UTC (23 years ago) by dpavlin
Branch: MAIN, pliva
CVS Tags: r0, HEAD
Changes since 1.1: +0 -0 lines
initial import

1 dpavlin 1.1 <?
2     /*
3     * Project: Smarty: the PHP compiling template engine
4     * File: Smarty.class.php
5     * Author: Monte Ohrt <monte@ispi.net>
6     * Andrei Zmievski <andrei@ispi.net>
7     *
8     * Version: 1.2.2
9     * Copyright: 2001 ispi of Lincoln, Inc.
10     *
11     * This program is free software; you can redistribute it and/or
12     * modify it under the terms of the GNU General Public License
13     * as published by the Free Software Foundation; either version 2
14     * of the License, or (at your option) any later version.
15     *
16     * This program is distributed in the hope that it will be useful,
17     * but WITHOUT ANY WARRANTY; without even the implied warranty of
18     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     * GNU General Public License for more details.
20     *
21     * You should have received a copy of the GNU General Public License
22     * along with this program; if not, write to the Free Software
23     * 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:
26     * monte@ispi.net
27     * andrei@ispi.net
28     *
29     * Or, write to:
30     * Monte Ohrt
31     * CTO, ispi
32     * 237 S. 70th suite 220
33     * Lincoln, NE 68510
34     *
35     * The latest version of Smarty can be obtained from:
36     * http://www.phpinsider.com/
37     *
38     */
39    
40     require("Smarty.addons.php");
41     require("Smarty.local.php");
42    
43     class Smarty
44     {
45    
46     // public vars
47     var $compile_check = true; // whether to check for compiling step or not:
48     // This is generally set to false once the
49     // application is entered into production and
50     // initially compiled. Leave set to true
51     // during development.
52    
53     var $template_dir = "./templates"; // name of directory for templates
54     var $compile_dir = "./templates_c"; // name of directory for compiled templates
55    
56    
57     var $tpl_file_ext = ".tpl"; // template file extentions
58    
59     var $allow_php = false; // whether or not to allow embedded php
60     // in the templates. By default, php tags
61     // are escaped.
62     var $left_delimiter = "{"; // template tag delimiters.
63     var $right_delimiter = "}";
64    
65     var $config_dir = "./configs"; // directory where config files are located
66    
67     var $custom_funcs = array( 'html_options' => 'smarty_func_html_options',
68     'html_select_date' => 'smarty_func_html_select_date',
69     //----- local
70     'img' => 'smarty_func_img',
71     'html_checkboxes' => 'smarty_func_html_checkboxes',
72     'input' => 'smarty_func_input',
73     'rinput' => 'smarty_func_rinput',
74     );
75    
76     var $custom_mods = array( 'lower' => 'strtolower',
77     'upper' => 'strtoupper',
78     'capitalize' => 'ucwords',
79     'escape' => 'smarty_mod_escape',
80     'truncate' => 'smarty_mod_truncate',
81     'spacify' => 'smarty_mod_spacify',
82     'date_format' => 'smarty_mod_date_format',
83     'string_format' => 'smarty_mod_string_format',
84     'replace' => 'smarty_mod_replace',
85     'strip_tags' => 'smarty_mod_strip_tags',
86     'default' => 'smarty_mod_default',
87     //----- local
88     'filesize' => 'smarty_mod_filesize',
89     );
90     var $global_assign = array( 'SCRIPT_NAME'
91     );
92    
93     // internal vars
94     var $_error_msg = false; // error messages
95     var $_tpl_vars = array();
96     var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part
97     var $_literal_blocks = array(); // keeps literal template blocks
98     var $_current_file = null; // the current template being compiled
99     var $_current_line_no = 1; // line number for error messages
100    
101    
102     /*======================================================================*\
103     Function: Smarty
104     Purpose: Constructor
105     \*======================================================================*/
106     function Smarty()
107     {
108     foreach ($this->global_assign as $var_name)
109     $this->assign($var_name, $GLOBALS[$var_name]);
110     }
111    
112    
113     /*======================================================================*\
114     Function: assign()
115     Purpose: assigns values to template variables
116     \*======================================================================*/
117    
118     function assign($tpl_var, $value = NULL)
119     {
120     if (is_array($tpl_var)){
121     foreach ($tpl_var as $key => $val) {
122     if (!empty($key))
123     $this->_tpl_vars[$key] = $val;
124     }
125     } else {
126     if (!empty($tpl_var) && isset($value))
127     $this->_tpl_vars[$tpl_var] = $value;
128     }
129     }
130    
131    
132     /*======================================================================*\
133     Function: append
134     Purpose: appens values to template variables
135     \*======================================================================*/
136     function append($tpl_var, $value = NULL)
137     {
138     if (is_array($tpl_var)) {
139     foreach ($tpl_var as $key => $val) {
140     if (!empty($key)) {
141     if (!is_array($this->_tpl_vars[$key]))
142     settype($this->_tpl_vars[$key], 'array');
143     $this->_tpl_vars[$key][] = $val;
144     }
145     }
146     } else {
147     if (!empty($tpl_var) && isset($value)) {
148     if (!is_array($this->_tpl_vars[$tpl_var]))
149     settype($this->_tpl_vars[$tpl_var], 'array');
150     $this->_tpl_vars[$tpl_var][] = $value;
151     }
152     }
153     }
154    
155    
156     /*======================================================================*\
157     Function: clear_assign()
158     Purpose: clear the given assigned template variable.
159     \*======================================================================*/
160    
161     function clear_assign($tpl_var)
162     {
163     unset($this->_tpl_vars[$tpl_var]);
164     }
165    
166     /*======================================================================*\
167     Function: clear_all_assign()
168     Purpose: clear all the assigned template variables.
169     \*======================================================================*/
170    
171     function clear_all_assign()
172     {
173     $this->_tpl_vars = array();
174     }
175    
176    
177     /*======================================================================*\
178     Function: get_template_vars
179     Purpose: Returns an array containing template variables
180     \*======================================================================*/
181     function &get_template_vars()
182     {
183     return $this->_tpl_vars;
184     }
185    
186    
187     /*======================================================================*\
188     Function: display()
189     Purpose: executes & displays the template results
190     \*======================================================================*/
191    
192     function display($tpl_file)
193     {
194     // compile files
195     $this->_compile($this->template_dir);
196     //assemble compile directory path to file
197     $_compile_file = $this->compile_dir.'/'.$tpl_file.'.php';
198    
199     extract($this->_tpl_vars);
200     include($_compile_file);
201     }
202    
203     /*======================================================================*\
204     Function: fetch()
205     Purpose: executes & returns the template results
206     \*======================================================================*/
207    
208     function fetch($tpl_file)
209     {
210     ob_start();
211     $this->display($tpl_file);
212     $results = ob_get_contents();
213     ob_end_clean();
214     return $results;
215     }
216    
217     /*======================================================================*\
218     Function: compile()
219     Purpose: called to compile the templates
220     \*======================================================================*/
221    
222     function _compile($tpl_dir)
223     {
224     if($this->compile_check)
225     {
226     if($this->_traverse_files($tpl_dir, 0))
227     return true;
228     else
229     return false;
230     }
231     else
232     return false;
233     }
234    
235     /*======================================================================*\
236     Function: _traverse_files()
237     Purpose: traverse the template files & process each one
238     \*======================================================================*/
239    
240     function _traverse_files($tpl_dir, $depth)
241     {
242     if(is_dir($tpl_dir)) {
243     if($tpl_dir)
244     $dir_handle = opendir($tpl_dir);
245    
246     while($curr_file = readdir($dir_handle)) {
247     if ($curr_file == '.' || $curr_file == '..')
248     continue;
249    
250     $filepath = $tpl_dir."/".$curr_file;
251     if(is_readable($filepath)) {
252     if(is_file($filepath) && preg_match('!' . preg_quote($this->tpl_file_ext, '!') . '$!', $curr_file)) {
253     if(!$this->_process_file($filepath))
254     return false;
255     } else if(is_dir($filepath)) {
256     if(!$this->_traverse_files($filepath, $depth + 1))
257     return false;
258     } else {
259     // invalid file type, skipping
260     $this->_set_error_msg("Invalid filetype for $filepath, skipping");
261     continue;
262     }
263     }
264     }
265     } else {
266     $this->_set_error_msg("Directory \"$tpl_dir\" does not exist or is not a directory.");
267     return false;
268     }
269    
270     return true;
271     }
272    
273     /*======================================================================*\
274     Function: _process_file()
275     Input: test template files for modifications
276     and execute the compilation for each
277     one requiring it.
278     \*======================================================================*/
279    
280     function _process_file($filepath)
281     {
282     if(preg_match("/^(.+)\/([^\/]+)$/", $filepath, $match)) {
283     $tpl_file_dir = $match[1];
284     $tpl_file_name = $match[2] . ".php";
285    
286     $compile_dir = preg_replace('!^' . preg_quote($this->template_dir, '!') . '!',
287     $this->compile_dir, $match[1]);
288    
289     //create directory if none exists
290     if(!file_exists($compile_dir)) {
291     $compile_dir_parts = preg_split('!/+!', $compile_dir);
292     $new_dir = "";
293     foreach ($compile_dir_parts as $dir_part) {
294     $new_dir .= $dir_part."/";
295     if (!file_exists($new_dir) && !mkdir($new_dir, 0755)) {
296     $this->_set_error_msg("problem creating directory \"$compile_dir\"");
297     return false;
298     }
299     }
300     }
301    
302     // compile the template file if none exists or has been modified
303     if (!file_exists($compile_dir."/".$tpl_file_name) ||
304     ($this->_modified_file($filepath, $compile_dir."/".$tpl_file_name))) {
305     if (!$this->_compile_file($filepath, $compile_dir."/".$tpl_file_name))
306     return false;
307     } else {
308     // no compilation needed
309     return true;
310     }
311     } else {
312     $this->_set_error_msg("problem matching \"$filepath.\"");
313     return false;
314     }
315    
316     return true;
317     }
318    
319     /*======================================================================*\
320     Function: _modified_file()
321     Input: return comparison of modification times of files
322     \*======================================================================*/
323    
324     function _modified_file($filepath, $compilepath)
325     {
326     if(filemtime($filepath) >= filemtime($compilepath))
327     return true;
328     return false;
329     }
330    
331     /*======================================================================*\
332     Function: _compile_file()
333     Input: compile a template file
334     \*======================================================================*/
335    
336     function _compile_file($filepath, $compilepath)
337     {
338     if (!($template_contents = $this->_read_file($filepath)))
339     return false;
340    
341     $this->_current_file = str_replace($this->template_dir . "/", "", $filepath);
342     $this->_current_line_no = 1;
343     $ldq = preg_quote($this->left_delimiter, '!');
344     $rdq = preg_quote($this->right_delimiter, '!');
345    
346     /* Pull out the literal blocks. */
347     preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_contents, $match);
348     $this->_literal_blocks = $match[1];
349     $template_contents = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s",
350     '{literal}', $template_contents);
351    
352     /* Gather all template tags. */
353     preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_contents, $match);
354     $template_tags = $match[1];
355     /* Split content by template tags to obtain non-template content. */
356     $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $template_contents);
357     if(!$this->allow_php) {
358     /* Escape php tags. */
359     $text_blocks = preg_replace('!<\?([^?]*?)\?>!', '&lt;?$1?&gt;', $text_blocks);
360     }
361    
362     /* Compile the template tags into PHP code. */
363     $compiled_tags = array();
364     for ($i = 0; $i < count($template_tags); $i++) {
365     $this->_current_line_no += substr_count($text_blocks[$i], "\n");
366     $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
367     $this->_current_line_no += substr_count($template_tags[$i], "\n");
368     }
369    
370     $compiled_contents = "";
371    
372     /* Interleave the compiled contents and text blocks to get the final result. */
373     for ($i = 0; $i < count($compiled_tags); $i++) {
374     $compiled_contents .= $text_blocks[$i].$compiled_tags[$i];
375     }
376     $compiled_contents .= $text_blocks[$i];
377    
378     /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
379     if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_contents, $match)) {
380     $strip_tags = $match[0];
381     $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
382     $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
383     for ($i = 0; $i < count($strip_tags); $i++)
384     $compiled_contents = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
385     $strip_tags_modified[$i], $compiled_contents, 1);
386     }
387    
388     if(!$this->_write_file($compilepath, $compiled_contents))
389     return false;
390    
391     return true;
392     }
393    
394     function _compile_tag($template_tag)
395     {
396     /* Matched comment. */
397     if ($template_tag{0} == '*' && $template_tag{strlen($template_tag)-1} == '*')
398     return "";
399    
400     /* Split tag into two parts: command and the arguments. */
401     preg_match('/^(
402     (?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'\s]+))+
403     )
404     (?:\s+(.*))?
405     /xs', $template_tag, $match);
406     list(, $tag_command, $tag_args) = $match;
407    
408     /* If the tag name matches a variable or section property definition,
409     we simply process it. */
410     if (preg_match('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tag_command) || // if a variable
411     preg_match('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tag_command) || // or a configuration variable
412     preg_match('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tag_command)) { // or a section property
413     settype($tag_command, 'array');
414     $this->_parse_vars_props($tag_command);
415     return "<?php print $tag_command[0]; ?>";
416     }
417    
418     switch ($tag_command) {
419     case 'include':
420     return $this->_compile_include_tag($tag_args);
421    
422     case 'if':
423     return $this->_compile_if_tag($tag_args);
424    
425     case 'else':
426     return '<?php else: ?>';
427    
428     case 'elseif':
429     return $this->_compile_if_tag($tag_args, true);
430    
431     case '/if':
432     return '<?php endif; ?>';
433    
434     case 'ldelim':
435     return $this->left_delimiter;
436    
437     case 'rdelim':
438     return $this->right_delimiter;
439    
440     case 'section':
441     array_push($this->_sectionelse_stack, false);
442     return $this->_compile_section_start($tag_args);
443    
444     case 'sectionelse':
445     $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;
446     return "<?php endfor; else: ?>";
447    
448     case '/section':
449     if (array_pop($this->_sectionelse_stack))
450     return "<?php endif; ?>";
451     else
452     return "<?php endfor; endif; ?>";
453    
454     case 'config_load':
455     return $this->_compile_config_load_tag($tag_args);
456    
457     case 'strip':
458     case '/strip':
459     return $this->left_delimiter.$tag_command.$this->right_delimiter;
460    
461     case 'literal':
462     list (,$literal_block) = each($this->_literal_blocks);
463     $this->_current_line_no += substr_count($literal_block, "\n");
464     return $literal_block;
465    
466     case 'insert':
467     return $this->_compile_insert_tag($tag_args);
468    
469     default:
470     if (isset($this->custom_funcs[$tag_command])) {
471     return $this->_compile_custom_tag($tag_command, $tag_args);
472     } else {
473     $this->_syntax_error("unknown tag - '$tag_command'", E_USER_WARNING);
474     return "";
475     }
476     }
477     }
478    
479    
480     function _compile_custom_tag($tag_command, $tag_args)
481     {
482     $attrs = $this->_parse_attrs($tag_args);
483     $function = $this->custom_funcs[$tag_command];
484     foreach ($attrs as $arg_name => $arg_value) {
485     if (is_bool($arg_value))
486     $arg_value = $arg_value ? 'true' : 'false';
487     $arg_list[] = "'$arg_name' => $arg_value";
488     }
489    
490     return "<?php $function(array(".implode(',', (array)$arg_list).")); ?>";
491     }
492    
493    
494     function _compile_insert_tag($tag_args)
495     {
496     $attrs = $this->_parse_attrs($tag_args);
497     $name = substr($attrs['name'], 1, -1);
498    
499     if (empty($name)) {
500     $this->_syntax_error("missing insert name");
501     }
502    
503     foreach ($attrs as $arg_name => $arg_value) {
504     if ($arg_name == 'name') continue;
505     if (is_bool($arg_value))
506     $arg_value = $arg_value ? 'true' : 'false';
507     $arg_list[] = "'$arg_name' => $arg_value";
508     }
509    
510     return "<?php print insert_$name(array(".implode(',', (array)$arg_list).")); ?>";
511     }
512    
513    
514     function _compile_config_load_tag($tag_args)
515     {
516     $attrs = $this->_parse_attrs($tag_args);
517    
518     if (empty($attrs['file'])) {
519     $this->_syntax_error("missing 'file' attribute in config_load tag");
520     }
521    
522     $output = "<?php if (!class_exists('Config_File'))\n" .
523     " include_once 'Config_File.class.php';\n" .
524     "if (!is_object(\$_conf_obj) || get_class(\$_conf_obj) != 'config_file') {\n" .
525     " \$_conf_obj = new Config_File('".$this->config_dir."');\n" .
526     "}\n" .
527     "\$_config = array_merge((array)\$_config, \$_conf_obj->get(".$attrs['file']."));\n";
528    
529     if (!empty($attrs['section']))
530     $output .= '$_config = array_merge((array)$_config, $_conf_obj->get('.$attrs['file'].', '.$attrs['section'].')); ';
531    
532     $output .= '?>';
533    
534     return $output;
535     }
536    
537    
538     function _compile_include_tag($tag_args)
539     {
540     $attrs = $this->_parse_attrs($tag_args);
541    
542     if (empty($attrs['file'])) {
543     $this->_syntax_error("missing 'file' attribute in include tag");
544     } else
545     $attrs['file'] = $this->_dequote($attrs['file']);
546    
547     if (count($attrs) > 1) {
548     $include_func_name = uniqid("_include_");
549     $include_file_name = $this->compile_dir.'/'.$attrs['file'];
550    
551     foreach ($attrs as $arg_name => $arg_value) {
552     if ($arg_name == 'file') continue;
553     if (is_bool($arg_value))
554     $arg_value = $arg_value ? 'true' : 'false';
555     $arg_list[] = "'$arg_name' => $arg_value";
556     }
557    
558     return "<?php " .
559     "function $include_func_name(\$file_name, \$def_vars, \$include_vars)\n" .
560     "{\n" .
561     " extract(\$def_vars);\n" .
562     " extract(\$include_vars);\n" .
563     " include \"\$file_name.php\";\n" .
564     "}\n" .
565     "$include_func_name(\"$include_file_name\", get_defined_vars(), array(".implode(',', (array)$arg_list)."));\n?>\n";
566     } else
567     return '<?php include "'.$this->compile_dir.'/'.$attrs['file'].'.php"; ?>';
568     }
569    
570     function _compile_section_start($tag_args)
571     {
572     $attrs = $this->_parse_attrs($tag_args);
573    
574     $output = "<?php ";
575     $section_name = $attrs['name'];
576     if (empty($section_name)) {
577     $this->_syntax_error("missing section name");
578     }
579    
580     $output .= "unset(\$_sections[$section_name]);\n";
581     $section_props = "\$_sections[$section_name]['properties']";
582    
583     foreach ($attrs as $attr_name => $attr_value) {
584     switch ($attr_name) {
585     case 'loop':
586     $output .= "{$section_props}['loop'] = is_array($attr_value) ? count($attr_value) : $attr_value;\n";
587     break;
588    
589     case 'show':
590     if (is_bool($attr_value))
591     $attr_value = $attr_value ? 'true' : 'false';
592     $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
593     break;
594    
595     default:
596     $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
597     break;
598     }
599     }
600    
601     if (isset($attrs['loop'])) {
602     $loop_check_code = "{$section_props}['loop'] > 0 && ";
603     } else {
604     $output .= "{$section_props}['loop'] = 1; #-fix- \n";
605     }
606    
607     if (isset($attrs['show'])) {
608     $show_check_code = "{$section_props}['show'] && ";
609     } else {
610     $output .= "{$section_props}['show'] = {$section_props}['loop'] > 0;\n";
611     }
612    
613     $output .= "if ($loop_check_code $show_check_code true): ";
614    
615     $output .= "
616     for ({$section_props}['index'] = 0;
617     {$section_props}['index'] < {$section_props}['loop'];
618     {$section_props}['index']++):\n";
619     $output .= "{$section_props}['rownum'] = {$section_props}['index'] + 1;\n";
620    
621     $output .= "?>\n";
622    
623     return $output;
624     }
625    
626     function _compile_if_tag($tag_args, $elseif = false)
627     {
628     /* Tokenize args for 'if' tag. */
629     preg_match_all('/(?:
630     "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | # match all double quoted strings allowed escaped double quotes
631     \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | # match all single quoted strings allowed escaped single quotes
632     [()] | # match parentheses
633     [^"\'\s()]+ # match any other token that is not any of the above
634     )/x', $tag_args, $match);
635     $tokens = $match[0];
636    
637     $this->_parse_vars_props($tokens);
638    
639     $is_arg_stack = array();
640    
641     for ($i = 0; $i < count($tokens); $i++) {
642     $token = &$tokens[$i];
643     switch ($token) {
644     case 'eq':
645     $token = '==';
646     break;
647    
648     case 'ne':
649     case 'neq':
650     $token = '!=';
651     break;
652    
653     case 'lt':
654     $token = '<';
655     break;
656    
657     case 'le':
658     case 'lte':
659     $token = '<=';
660     break;
661    
662     case 'gt':
663     $token = '>';
664     break;
665    
666     case 'ge':
667     case 'gte':
668     $token = '>=';
669     break;
670    
671     case 'and':
672     $token = '&&';
673     break;
674    
675     case 'or':
676     $token = '||';
677     break;
678    
679     case 'not':
680     $token = '!';
681     break;
682    
683     case 'mod':
684     $token = '%';
685     break;
686    
687     case '(':
688     array_push($is_arg_stack, $i);
689     break;
690    
691     case 'is':
692     /* If last token was a ')', we operate on the parenthesized
693     expression. The start of the expression is on the stack.
694     Otherwise, we operate on the last encountered token. */
695     if ($tokens[$i-1] == ')')
696     $is_arg_start = array_pop($is_arg_stack);
697     else
698     $is_arg_start = $i-1;
699     /* Construct the argument for 'is' expression, so it knows
700     what to operate on. */
701     $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
702    
703     /* Pass all tokens from next one until the end to the
704     'is' expression parsing function. The function will
705     return modified tokens, where the first one is the result
706     of the 'is' expression and the rest are the tokens it
707     didn't touch. */
708     $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
709    
710     /* Replace the old tokens with the new ones. */
711     array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
712    
713     /* Adjust argument start so that it won't change from the
714     current position for the next iteration. */
715     $i = $is_arg_start;
716     break;
717     }
718     }
719    
720     if ($elseif)
721     return '<?php elseif ('.implode(' ', $tokens).'): ?>';
722     else
723     return '<?php if ('.implode(' ', $tokens).'): ?>';
724     }
725    
726     function _parse_is_expr($is_arg, $tokens)
727     {
728     $expr_end = 0;
729    
730     if (($first_token = array_shift($tokens)) == 'not') {
731     $negate_expr = true;
732     $expr_type = array_shift($tokens);
733     } else
734     $expr_type = $first_token;
735    
736     switch ($expr_type) {
737     case 'even':
738     if ($tokens[$expr_end] == 'by') {
739     $expr_end++;
740     $expr_arg = $tokens[$expr_end++];
741     $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
742     }
743     else
744     $expr = "!($is_arg % 2)";
745     break;
746    
747     case 'odd':
748     if ($tokens[$expr_end] == 'by') {
749     $expr_end++;
750     $expr_arg = $tokens[$expr_end++];
751     $expr = "(($is_arg / $expr_arg) % $expr_arg)";
752     }
753     else
754     $expr = "($is_arg % 2)";
755     break;
756    
757     case 'div':
758     if ($tokens[$expr_end] == 'by') {
759     $expr_end++;
760     $expr_arg = $tokens[$expr_end++];
761     $expr = "!($is_arg % $expr_arg)";
762     } else {
763     $this->_syntax_error("expecting 'by' after 'div'");
764     }
765     break;
766    
767     default:
768     $this->_syntax_error("unknown 'is' expression - '$expr_type'");
769     break;
770     }
771    
772     if ($negate_expr) {
773     $expr = "!($expr)";
774     }
775    
776     array_splice($tokens, 0, $expr_end, $expr);
777    
778     return $tokens;
779     }
780    
781     function _parse_attrs($tag_args)
782     {
783     /* Tokenize tag attributes. */
784     preg_match_all('/(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
785     \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'=\s]+)
786     )+ |
787     [=]
788     /x', $tag_args, $match);
789     $tokens = $match[0];
790     $var_delims = array('$', '#', '%');
791    
792     $attrs = array();
793     /* Parse state:
794     0 - expecting attr name
795     1 - expecting '=' or another attr name
796     2 - expecting attr value (not '=') */
797     $state = 0;
798    
799     foreach ($tokens as $token) {
800     switch ($state) {
801     case 0:
802     /* If the token is a valid identifier, we set attribute name
803     and go to state 1. */
804     if (preg_match('!\w+!', $token)) {
805     $attr_name = $token;
806     $state = 1;
807     } else
808     $this->_syntax_error("invalid attribute name - '$token'");
809     break;
810    
811     case 1:
812     /* If the token is a valid identifier, the previously set
813     attribute name does not need an argument. We put it in
814     the attrs array, set the new attribute name to the
815     current token and don't switch state.
816    
817     If the token is '=', then we go to state 2. */
818     if ($token == '=') {
819     $state = 2;
820     } else
821     $this->_syntax_error("expecting '=' after attribute name");
822     break;
823    
824     case 2:
825     /* If token is not '=', we set the attribute value and go to
826     state 0. */
827     if ($token != '=') {
828     /* We booleanize the token if it's a non-quoted possible
829     boolean value. */
830     if (preg_match('!^(on|yes|true)$!', $token))
831     $token = true;
832     else if (preg_match('!^(off|no|false)$!', $token))
833     $token = false;
834     /* If the token is not variable (doesn't start with
835     '$', '#', or '%') and not enclosed in single or
836     double quotes we single-quote it. */
837     else if (!in_array($token{0}, $var_delims) &&
838     !(($token{0} == '"' || $token[0] == "'") &&
839     $token{strlen($token)-1} == $token{0}))
840     $token = "'".$token."'";
841    
842     $attrs[$attr_name] = $token;
843     $state = 0;
844     } else
845     $this->_syntax_error("'=' cannot be an attribute value");
846     break;
847     }
848     }
849    
850     $this->_parse_vars_props($attrs);
851    
852     return $attrs;
853     }
854    
855     function _preg_grep($pattern, $array)
856     {
857     $result = array();
858    
859     foreach ($array as $key => $entry) {
860     if (preg_match($pattern, $entry))
861     $result[$key] = $entry;
862     }
863    
864     return $result;
865     }
866    
867     function _parse_vars_props(&$tokens)
868     {
869     /* preg_grep() was fixed to return keys properly in 4.0.4 and later. To
870     allow people to use older versions of PHP we emulate preg_grep() and
871     use the version check to see what function to call. */
872     if (strnatcmp(PHP_VERSION, '4.0.4') >= 0) {
873     $var_exprs = preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
874     $conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
875     $sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
876     } else {
877     $var_exprs = $this->_preg_grep('!^\$(\w+/)*\w+(?>\.\w+)*(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
878     $conf_var_exprs = $this->_preg_grep('!^#(\w+)#(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
879     $sect_prop_exprs = $this->_preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:[^|]+)?)*$!', $tokens);
880     }
881    
882     if (count($var_exprs)) {
883     foreach ($var_exprs as $expr_index => $var_expr) {
884     $tokens[$expr_index] = $this->_parse_var($var_expr);
885     }
886     }
887    
888     if (count($conf_var_exprs)) {
889     foreach ($conf_var_exprs as $expr_index => $var_expr) {
890     $tokens[$expr_index] = $this->_parse_conf_var($var_expr);
891     }
892     }
893    
894     if (count($sect_prop_exprs)) {
895     foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {
896     $tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);
897     }
898     }
899     }
900    
901     function _parse_var($var_expr)
902     {
903     $modifiers = explode('|', substr($var_expr, 1));
904    
905     $sections = explode('/', array_shift($modifiers));
906     $props = explode('.', array_pop($sections));
907     $var_name = array_shift($props);
908    
909     $output = "\$$var_name";
910    
911     foreach ($sections as $section) {
912     $output .= "[\$_sections['$section']['properties']['index']]";
913     }
914     foreach ($props as $prop) {
915     $output .= "['$prop']";
916     }
917    
918     $this->_parse_modifiers($output, $modifiers);
919    
920     return $output;
921     }
922    
923     function _parse_conf_var($conf_var_expr)
924     {
925     $modifiers = explode('|', $conf_var_expr);
926    
927     $var_name = substr(array_shift($modifiers), 1, -1);
928    
929     $output = "\$_config['$var_name']";
930    
931     $this->_parse_modifiers($output, $modifiers);
932    
933     return $output;
934     }
935    
936     function _parse_section_prop($section_prop_expr)
937     {
938     $modifiers = explode('|', $section_prop_expr);
939    
940     preg_match('!%(\w+)\.(\w+)%!', array_shift($modifiers), $match);
941     $section_name = $match[1];
942     $prop_name = $match[2];
943    
944     $output = "\$_sections['$section_name']['properties']['$prop_name']";
945    
946     $this->_parse_modifiers($output, $modifiers);
947    
948     return $output;
949     }
950    
951     function _parse_modifiers(&$output, $modifiers)
952     {
953     foreach ($modifiers as $modifier) {
954     $modifier = explode(':', $modifier);
955     $modifier_name = array_shift($modifier);
956    
957     if ($modifier_name{0} == '@') {
958     $map_array = 'false';
959     $modifier_name = substr($modifier_name, 1);
960     } else
961     $map_array = 'true';
962    
963     /*
964     * First we lookup the modifier function name in the registered
965     * modifiers table.
966     */
967     $mod_func_name = $this->custom_mods[$modifier_name];
968    
969     /*
970     * If we don't find that modifier there, we assume it's just a PHP
971     * function name.
972     */
973     if (!isset($mod_func_name))
974     $mod_func_name = $modifier_name;
975    
976     $this->_parse_vars_props($modifier);
977    
978     if (count($modifier) > 0)
979     $modifier_args = ', '.implode(', ', $modifier);
980     else
981     $modifier_args = '';
982    
983     $output = "_smarty_mod_handler('$mod_func_name', $map_array, $output$modifier_args)";
984     }
985     }
986    
987    
988     /*======================================================================*\
989     Function: _dequote
990     Purpose: Remove starting and ending quotes from the string
991     \*======================================================================*/
992     function _dequote($string)
993     {
994     if (($string{0} == "'" || $string{0} == '"') &&
995     $string{strlen($string)-1} == $string{0})
996     return substr($string, 1, -1);
997     }
998    
999    
1000     /*======================================================================*\
1001     Function: _read_file()
1002     Purpose: read in a file
1003     \*======================================================================*/
1004    
1005     function _read_file($filename)
1006     {
1007     if(!($fd = fopen($filename, 'r'))) {
1008     $this->_set_error_msg("problem reading '$filename.'");
1009     return false;
1010     }
1011     $contents = fread($fd, filesize($filename));
1012     fclose($fd);
1013     return $contents;
1014     }
1015    
1016     /*======================================================================*\
1017     Function: _write_file()
1018     Purpose: write out a file
1019     \*======================================================================*/
1020    
1021     function _write_file($filename,$contents)
1022     {
1023     if(!($fd = fopen($filename, 'w'))) {
1024     $this->_set_error_msg("problem writing '$filename.'");
1025     return false;
1026     }
1027     fwrite($fd, $contents);
1028     fclose($fd);
1029     return true;
1030     }
1031    
1032     /*======================================================================*\
1033     Function: _set_error_msg()
1034     Purpose: set the error message
1035     \*======================================================================*/
1036    
1037     function _set_error_msg($error_msg)
1038     {
1039     $this->_error_msg="smarty error: $error_msg";
1040     return true;
1041     }
1042    
1043     /*======================================================================*\
1044     Function: _syntax_error
1045     Purpose: display Smarty syntax error
1046     \*======================================================================*/
1047     function _syntax_error($error_msg, $error_type = E_USER_ERROR)
1048     {
1049     trigger_error("Smarty: [in " . $this->_current_file . " line " .
1050     $this->_current_line_no . "]: syntax error: $error_msg", $error_type);
1051     }
1052     }
1053    
1054     ?>

  ViewVC Help
Powered by ViewVC 1.1.26