/[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.2 - (hide annotations)
Sat Mar 3 12:56:17 2001 UTC (23 years, 2 months ago) by dpavlin
Branch: MAIN
Changes since 1.1: +3 -1 lines
lokalne promjene u Smarty.local.php

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

  ViewVC Help
Powered by ViewVC 1.1.26