/[hr-web]/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)
Fri Apr 20 08:25:32 2001 UTC (23 years ago) by dpavlin
Branch: MAIN, pliva
CVS Tags: r0, HEAD
Changes since 1.1: +0 -0 lines
initial import

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

  ViewVC Help
Powered by ViewVC 1.1.26