/[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.3 - (hide annotations)
Sat Mar 17 15:46:05 2001 UTC (23 years, 2 months ago) by dpavlin
Branch: MAIN
Changes since 1.2: +4 -1 lines
nukleus for filesize var modifier

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

  ViewVC Help
Powered by ViewVC 1.1.26