/[corp_html]/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 - (hide annotations)
Mon Feb 19 18:12:21 2001 UTC (23 years, 2 months ago) by dpavlin
Branch: MAIN
Branch point for: dbp
Initial revision

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

  ViewVC Help
Powered by ViewVC 1.1.26