/[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

Contents of /inc/Smarty.class.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Mon Feb 19 18:12:21 2001 UTC (23 years, 2 months ago) by dpavlin
Branch: dbp
CVS Tags: alpha
Changes since 1.1: +0 -0 lines
alpha

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