/[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.2 - (show 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 <?
2 /*
3 * Project: Smarty: the PHP compiling template engine
4 * File: Smarty.class.php
5 * Author: Monte Ohrt <monte@ispi.net>
6 * Andrei Zmievski <andrei@ispi.net>
7 *
8 * Version: 1.2.2
9 * Copyright: 2001 ispi of Lincoln, Inc.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 *
25 * You may contact the authors of Smarty by e-mail at:
26 * monte@ispi.net
27 * andrei@ispi.net
28 *
29 * Or, write to:
30 * Monte Ohrt
31 * CTO, ispi
32 * 237 S. 70th suite 220
33 * Lincoln, NE 68510
34 *
35 * The latest version of Smarty can be obtained from:
36 * http://www.phpinsider.com/
37 *
38 */
39
40 require("Smarty.addons.php");
41 require("Smarty.local.php");
42
43 class Smarty
44 {
45
46 // public vars
47 var $compile_check = true; // whether to check for compiling step or not:
48 // This is generally set to false once the
49 // application is entered into production and
50 // initially compiled. Leave set to true
51 // during development.
52
53 var $template_dir = "./templates"; // name of directory for templates
54 var $compile_dir = "./templates_c"; // name of directory for compiled templates
55
56
57 var $tpl_file_ext = ".tpl"; // template file extentions
58
59 var $allow_php = false; // whether or not to allow embedded php
60 // in the templates. By default, php tags
61 // are escaped.
62 var $left_delimiter = "{"; // template tag delimiters.
63 var $right_delimiter = "}";
64
65 var $config_dir = "./configs"; // directory where config files are located
66
67 var $custom_funcs = array( 'html_options' => 'smarty_func_html_options',
68 'html_select_date' => 'smarty_func_html_select_date',
69 'img' => 'smarty_func_img',
70 'html_checkboxes' => 'smarty_func_html_checkboxes',
71 );
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