ACC SHELL
<?php
/**
* ETS - Easy Template System - 3.06a
* Copyright (C) 2002, 2003, 2004 Franck Marcia <phpets@hotmail.com>
* http://ets.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/**
* Size reducing behaviour
*/
define('_ETS_REDUCE_NULL', 0x0);
define('_ETS_REDUCE_OFF', 0x1);
define('_ETS_REDUCE_SPACES', 0x2);
define('_ETS_REDUCE_ALL', 0x4);
/**
* Parsing modes
*/
define('_ETS_DATA', 0x1);
define('_ETS_NAME', 0x2);
define('_ETS_CLOSING_TAG', 0x4);
define('_ETS_VALUE', 0x8);
define('_ETS_COMMENT', 0x10);
define('_ETS_CDATA', 0x20);
/**
* Parsing mode groups
*/
define('_ETS_GROUP0', _ETS_COMMENT + _ETS_CDATA);
/**
* Element types
*/
define('_ETS_NULL', 0x0);
define('_ETS_ROOT', 0x1);
define('_ETS_TEXT', 0x2);
define('_ETS_TAG', 0x4);
define('_ETS_ALT_TAG', 0x8);
define('_ETS_TEMPLATE', 0x10);
define('_ETS_SET', 0x20);
define('_ETS_SETVAL', 0x40);
define('_ETS_MIS', 0x80);
define('_ETS_MISVAL', 0x100);
define('_ETS_PHP', 0x200);
define('_ETS_CONST', 0x400);
define('_ETS_IF', 0x800);
define('_ETS_CODE', 0x1000);
define('_ETS_CHOOSE', 0x2000);
define('_ETS_WHENTEST', 0x4000);
define('_ETS_ELSE', 0x8000);
define('_ETS_CHOOSEVAR', 0x10000);
define('_ETS_WHENVAL', 0x20000);
define('_ETS_CALL', 0x40000);
define('_ETS_ARG', 0x80000);
define('_ETS_MIS_TEMPLATE', 0x100000);
define('_ETS_REDUCE', 0x200000);
define('_ETS_REPEAT', 0x400000);
define('_ETS_INCLUDE', 0x800000);
define('_ETS_INSERT', 0x1000000);
define('_ETS_EVAL', 0x2000000);
define('_ETS_SAFE', 0x4000000);
define('_ETS_ROOT_EVAL', 0x8000000);
/**
* Element type groups
*/
define('_ETS_CODEs', _ETS_CODE + _ETS_PHP);
define('_ETS_CHOOSEs', _ETS_CHOOSE + _ETS_CHOOSEVAR);
define('_ETS_SETs', _ETS_SET + _ETS_SETVAL);
define('_ETS_MISs', _ETS_MIS + _ETS_MISVAL);
// can't contain cdata, call, const, set, mis, choose, insert, eval, safe, if or repeat elements
define('_ETS_GROUP1', _ETS_CHOOSEs + _ETS_CALL + _ETS_CODEs + _ETS_ROOT);
// can't contain mask or include elements
define('_ETS_GROUP2', _ETS_CHOOSEs + _ETS_CALL + _ETS_CODEs);
// can't contain text or simple tag element
define('_ETS_GROUP3', _ETS_CHOOSEs + _ETS_CALL + _ETS_ROOT);
// doesn't store text when finding closing tag
define('_ETS_GROUP4', _ETS_CHOOSEs + _ETS_CALL);
/**
* Building directions
*/
define('_ETS_FORWARD', 0x1);
define('_ETS_BACKWARD', 0x2);
/**
* Building data types
*/
define('_ETS_MISSING', 0x1);
define('_ETS_SCALAR', 0x2);
define('_ETS_COMPLEX', 0x4);
/**
* Handler names
*/
define('_ETS_SOURCE_READ', 'ets_source_read_handler');
define('_ETS_CACHE_READ', 'ets_cache_read_handler');
define('_ETS_CACHE_WRITE', 'ets_cache_write_handler');
define('_ETS_STRING_READ', '_printts');
define('_ETS_ENTRY', 'main');
/**
* Template management class
* This class is intended to be used by printt functions only
*/
class _ets
{
/**
* Data tree
*/
var $datatree;
/**
* Mask tree
*/
var $masktree = array();
/**
* Indicate if handler functions are available
*/
var $external_source_read = FALSE;
var $external_cache_read = FALSE;
var $external_cache_write = FALSE;
/**
* Names of parsed containers
*/
var $containers = NULL;
/**
* Current container name to be parsed
*/
var $container = NULL;
/**
* Templates included at the root of other templates
*/
var $includes = NULL;
/**
* Flag which indicates if parse must be skipped for the current container
*/
var $skip = FALSE;
/***** E R R O R *****/
/**
* Check PHP error level
*/
function check_level($error_level, $errno, $message)
{
if (error_reporting() & $error_level) {
switch ($error_level) {
case E_NOTICE: $type = 'notice'; break;
case E_WARNING: $type = 'warning'; break;
case E_ERROR: $type = 'error'; break;
}
echo "<b>ETS $type:</b> $message";
}
if ($error_level == E_ERROR) {
exit;
}
}
/**
* Print out an error message
*/
function error($error_type, $errno, $message = '', $line = 0, $elt_type = _ETS_NULL)
{
switch ($error_type) {
case 0: // WARNING - wrong element in another or at root
if ($elt_type == _ETS_ROOT) {
$this->check_level(E_WARNING, $errno, "$message can't be defined outside a template on line $line of <b>{$this->container}</b><br>");
} else {
$this->check_level(E_WARNING, $errno, $this->elt_label($elt_type) . " can't contain $message on line $line of <b>{$this->container}</b><br>");
}
break;
case 1: // WARNING - unexpected closing tag
$this->check_level(E_WARNING, $errno, 'unexpected closing tag {/' . $message . "} on line $line of <b>{$this->container}</b><br>");
break;
case 2: // WARNING - unexpected character or space in tag
$this->check_level(E_WARNING, $errno, "$message on line $line of <b>{$this->container}</b><br>");
break;
case 3: // WARNING - end of comment or cdata not found
$this->check_level(E_WARNING, $errno, "end of " . $this->mode_label($elt_type) . " starting on line $line not found in <b>{$this->container}</b><br>");
break;
case 4: // WARNING - closing tag not found
$this->check_level(E_WARNING, $errno, "closing tag not found for " . $this->elt_label($elt_type) . " starting on line $line in <b>{$this->container}</b><br>");
break;
case 5: // NOTICE - container not found (include element with line number available)
$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in include element on line $line of <b>{$this->container}</b><br>");
break;
case 6: // NOTICE - duplicated use of reduce element (without line number available, with several containers)
$this->check_level(E_NOTICE, $errno, "$message<br>");
break;
case 7: // NOTICE - duplicated use of reduce element, invalid value for reduce element
$this->check_level(E_NOTICE, $errno, "$message on line $line of <b>{$this->container}</b><br>");
break;
case 8: // ERROR - entry mask not found
$this->check_level(E_ERROR, $errno, "unable to find entry mask $message<br>");
break;
case 9: // NOTICE - invalid datatree
$this->check_level(E_NOTICE, $errno, "datatree is not an array, an object or null<br>");
break;
case 10: // ERROR - invalid containers
$this->check_level(E_ERROR, $errno, "containers are not an array or a string<br>");
break;
case 11: // NOTICE - container not found (argument)
$this->check_level(E_NOTICE, $errno, "unable to get the content of $message given as argument<br>");
break;
case 12: // NOTICE - container not found (insert element)
$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in insert element<br>");
break;
case 13: // NOTICE - container not found (include element without line number available)
$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in include element<br>");
break;
case 14: // NOTICE - container not found (eval element)
$this->check_level(E_NOTICE, $errno, "unable to get the content of $message in eval element<br>");
break;
case 15: // NOTICE - wrong element in safe mode
$this->check_level(E_NOTICE, $errno, $this->elt_label($elt_type) . " disabled for security reasons<br>");
break;
case 16: // WARNING - template already defined (without line number available, with several containers) / container already used
$this->check_level(E_WARNING, $errno, "$message<br>");
break;
}
}
/**
* Define the label of a element type from an id
*/
function elt_label($eltid)
{
switch($eltid) {
case _ETS_ROOT: return 'root element';
case _ETS_TEXT: return 'text element';
case _ETS_TAG: return 'simple tag element';
case _ETS_ALT_TAG: return 'alternate tag element';
case _ETS_TEMPLATE: return 'template element';
case _ETS_SET: return 'set element';
case _ETS_SETVAL: return 'set-value element';
case _ETS_MIS: return 'missing element';
case _ETS_MISVAL: return 'missing-value element';
case _ETS_PHP: return 'PHP element';
case _ETS_CONST: return 'constant element';
case _ETS_IF: return 'if element';
case _ETS_CODE: return 'PHP code or test';
case _ETS_CHOOSE: return 'choose element';
case _ETS_WHENTEST: return 'when-test element';
case _ETS_ELSE: return 'else element';
case _ETS_CHOOSEVAR: return 'choose-variable element';
case _ETS_WHENVAL: return 'when-value element';
case _ETS_CALL: return 'call element';
case _ETS_ARG: return 'argument element';
case _ETS_MIS_TEMPLATE: return 'missing template element';
case _ETS_REDUCE: return 'reduce element';
case _ETS_REPEAT: return 'repeat element';
case _ETS_INCLUDE: return 'include element';
case _ETS_INSERT: return 'insert element';
case _ETS_EVAL: return 'eval element';
case _ETS_SAFE: return 'safe eval element';
case _ETS_ROOT_EVAL: return 'eval or safe element';
}
}
/**
* Define the label of a parsing mode from an id
*/
function mode_label($modeid)
{
switch($modeid) {
case _ETS_COMMENT: return 'comment';
case _ETS_CDATA: return 'cdata';
}
}
/***** P A R S I N G *****/
/**
* Store the size reducing behavior
*/
function store_reduce(&$elts, $value)
{
switch(strtoupper($value)) {
case 'OFF':
case 'NOTHING':
$elts['0reduce'] = _ETS_REDUCE_OFF;
return TRUE;
case 'SPACE':
case 'SPACES':
$elts['0reduce'] = _ETS_REDUCE_SPACES;
return TRUE;
case 'CRLF':
case 'ON':
case 'ALL':
$elts['0reduce'] = _ETS_REDUCE_ALL;
return TRUE;
default:
return FALSE;
}
}
/**
* Walk through a slash separated path of a node to build a tree
*/
function node_path_walk($elements, $rank, $ptype, &$i, &$line, $cvalue, $ncontent, $content, $code)
{
if (count($elements) == 1) {
$elt[$ptype . ':' . $i . ':' . $elements[0] . ':' . $cvalue] = $this->parse($code ? _ETS_CODE : $ptype, $i, $line, $ncontent, $content);
} else {
$element1 = array_shift($elements);
$masktype = ($ptype == _ETS_MIS || $ptype == _ETS_MISVAL) ? _ETS_MIS_TEMPLATE : _ETS_TEMPLATE;
$elt[$masktype . ':' . $i . '.' . $rank . ':' . $element1] = $this->node_path_walk($elements, $rank + 1, $ptype, $i, $line, $cvalue, $ncontent, $content, $code);
}
return $elt;
}
/**
* Store a new node in the template tree
*/
function store_node(&$elts, $ptype, &$i, &$line, $cname, $cvalue, $ncontent, $content, $code = FALSE)
{
$isabsolute = FALSE;
if ($cname{0} == '/' && $cname{1} == '/') {
$isabsolute = TRUE;
$cname = substr($cname, 2);
}
$elements = explode('/', $cname);
if (count($elements) == 1 && !$isabsolute) {
$elts[$ptype . ':' . $i . ':' . $cname . ':' . $cvalue] = $this->parse($code ? _ETS_CODE : $ptype, $i, $line, $ncontent, $content);
} else {
if ($isabsolute) {
$elts[_ETS_TEMPLATE . ':' . $i . '.1://'] = $this->node_path_walk($elements, 2, $ptype, $i, $line, $cvalue, $ncontent, $content, $code);
} else {
$element1 = array_shift($elements);
$masktype = ($ptype == _ETS_MIS || $ptype == _ETS_MISVAL) ? _ETS_MIS_TEMPLATE : _ETS_TEMPLATE;
$elts[$masktype . ':' . $i . '.1:' . $element1] = $this->node_path_walk($elements, 2, $ptype, $i, $line, $cvalue, $ncontent, $content, $code);
}
}
}
/**
* Walk through a slash separated path of a leaf to build a tree
*/
function leaf_path_walk($elements, $rank, $ptype, &$i, $cvalue)
{
if (count($elements) == 1) {
$elt[$ptype . ':' . $i . ':' . $elements[0] . ':' . $cvalue] = '';
} else {
$element1 = array_shift($elements);
$elt[_ETS_TEMPLATE . ':' . $i . '.' . $rank . ':' . $element1] = $this->leaf_path_walk($elements, $rank + 1, $ptype, $i, $cvalue);
}
return $elt;
}
/**
* Store a new leaf in the template tree
*/
function store_leaf(&$elts, $ptype, &$i, $cname, $cvalue = NULL)
{
$isabsolute = FALSE;
if ($cname{0} == '/' && $cname{1} == '/') {
$isabsolute = TRUE;
$cname = substr($cname, 2);
}
$elements = explode('/', $cname);
if (count($elements) == 1 && !$isabsolute) {
$elts[$ptype . ':' . $i . ':' . $cname . ':' . $cvalue] = '';
} else {
if ($isabsolute) {
$elts[_ETS_TEMPLATE . ':' . $i . '.1://'] = $this->leaf_path_walk($elements, 2, $ptype, $i, $cvalue);
} else {
$element1 = array_shift($elements);
$elts[_ETS_TEMPLATE . ':' . $i . '.1:' . $element1] = $this->leaf_path_walk($elements, 2, $ptype, $i, $cvalue);
}
}
}
/**
* Store a new text in the template tree
*/
function store_text(&$elts, &$i, $ptype, $ntext, $ctext)
{
if ($ntext == 1 && $ptype != _ETS_ROOT) {
$elts[_ETS_TEXT . ':' . $i] = $ctext;
}
}
/**
* Define if the parameter is a non printable character
*/
function is_space($char)
{
$asc = ord($char);
if ($asc == 32) {
return TRUE;
} elseif ($asc > 8 && $asc < 14) {
return TRUE;
}
return FALSE;
}
/**
* Recursively parse template
*/
function parse($ptype, &$i, &$line, $ncontent, $content)
{
$elts = array();
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$nspecial = 0;
$saveline = $line;
for ( ; $i < $ncontent; ++$i) {
// skip parsing when error
if ($this->skip) {
return array();
}
// current character and following
$c0 = $content{$i};
$c1 = $content{$i + 1};
$is_space0 = $this->is_space($c0);
$a0 = ord($c0);
// line count
if ($a0 == 10 || ($a0 == 13 && ord($c1) != 10)) {
++$line;
}
// data acquisition
if ($mode == _ETS_DATA) {
// tag?
if ($c0 == '{') {
$c2 = $content{$i + 2};
$c3 = $content{$i + 3};
$c4 = $content{$i + 4};
$c5 = $content{$i + 5};
$c6 = $content{$i + 6};
$c7 = $content{$i + 7};
// {* (comment)
if ($c1 == '*') {
if ($ptype & _ETS_CODEs) {
$this->error(0, 1, 'comment', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_COMMENT;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
++$i;
++$nspecial;
$saveline = $line;
// {# (cdata)
} elseif ($c1 == '#') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 2, 'cdata', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CDATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
++$i;
++$nspecial;
$saveline = $line;
// {mask:
} elseif ($c1 == 'm' && $c2 == 'a' && $c3 == 's' && $c4 == 'k' && $c5 == ':') {
if ($ptype & _ETS_GROUP2) {
$this->error(0, 3, 'template element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_TEMPLATE;
$i += 5;
// {call:
} elseif ($c1 == 'c' && $c2 == 'a' && $c3 == 'l' && $c4 == 'l' && $c5 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 4, 'call element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 6;
$index = _ETS_CALL . ':' . $i;
$elts[$index]['template'] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
$elts[$index]['args'] = $this->parse(_ETS_CALL, $i, $line, $ncontent, $content);
// {const:
} elseif ($c1 == 'c' && $c2 == 'o' && $c3 == 'n' && $c4 == 's' && $c5 == 't' && $c6 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 5, 'constant element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 7;
$elts[_ETS_CONST . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
--$i;
// {set:
} elseif ($c1 == 's' && $c2 == 'e' && $c3 == 't' && $c4 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 6, 'set element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_SET;
$i += 4;
// {mis:
} elseif ($c1 == 'm' && $c2 == 'i' && $c3 == 's' && $c4 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 7, 'missing element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_MIS;
$i += 4;
// {choose:
} elseif ($c1 == 'c' && $c2 == 'h' && $c3 == 'o' && $c4 == 'o' && $c5 == 's' && $c6 == 'e' && $c7 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 8, 'choose element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_CHOOSEVAR;
$i += 7;
// {arg:
} elseif ($c1 == 'a' && $c2 == 'r' && $c3 == 'g' && $c4 == ':') {
if ($ptype == _ETS_CALL) {
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_ARG;
$i += 4;
} else {
$this->error(0, 9, 'argument element', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {reduce:
} elseif ($c1 == 'r' && $c2 == 'e' && $c3 == 'd' && $c4 == 'u' && $c5 == 'c' && $c6 == 'e' && $c7 == ':') {
if ($ptype == _ETS_ROOT) {
if (!isset($elts['0reduce']) || $elts['0reduce'] == _ETS_REDUCE_NULL) {
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_REDUCE;
$i += 7;
} else {
$this->error(7, 10, 'reduce element already used', $line);
}
} else {
$this->error(0, 11, 'reduce element', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {include:
} elseif ($c1 == 'i' && $c2 == 'n' && $c3 == 'c' && $c4 == 'l' && $c5 == 'u' && $c6 == 'd' && $c7 == 'e' & $content{$i + 8} == ':') {
if ($ptype & _ETS_GROUP2) {
$this->error(0, 12, 'include element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 9;
$container_name = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
--$i;
if ($ptype == _ETS_ROOT) {
$return = NULL;
@eval('$return=(string)(' . implode('', $container_name) . ');');
if (isset($return)) {
$container = $this->container;
$skip = $this->skip;
$masktree = $this->read_container($return, _ETS_ROOT);
$this->container = $container;
$this->skip = $skip;
if ($masktree === FALSE) {
$this->error(5, 13, $return, $line);
} else {
$this->masktree = $this->masktree_merge($this->masktree, $masktree, $cvalue);
$elts['0include'][] = $return;
}
}
} else {
$elts[_ETS_INCLUDE . ':' . $i] = $container_name;
}
// {insert:
} elseif ($c1 == 'i' && $c2 == 'n' && $c3 == 's' && $c4 == 'e' && $c5 == 'r' && $c6 == 't' && $c7 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 14, 'insert element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 8;
$elts[_ETS_INSERT . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
--$i;
// {eval:
} elseif ($c1 == 'e' && $c2 == 'v' && $c3 == 'a' && $c4 == 'l' && $c5 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 15, 'eval element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 6;
$elts[_ETS_EVAL . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
--$i;
// {safe:
} elseif ($c1 == 's' && $c2 == 'a' && $c3 == 'f' && $c4 == 'e' && $c5 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 16, 'safe eval element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 6;
$elts[_ETS_SAFE . ':' . $i] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
--$i;
// {when:
} elseif ($c1 == 'w' && $c2 == 'h' && $c3 == 'e' && $c4 == 'n' && $c5 == ':') {
// of of whentest
if ($ptype == _ETS_CHOOSE) {
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 6;
$index = _ETS_WHENTEST . ':' . $i;
$elts['when'][$index]['test'] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
$elts['when'][$index]['true'] = $this->parse(_ETS_WHENTEST, $i, $line, $ncontent, $content);
}
// of whenval
elseif ($ptype == _ETS_CHOOSEVAR) {
$mode = _ETS_VALUE;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_WHENVAL;
switch ($c6) {
case '\'': $quotetype = 1; $i += 6; break;
case '"': $quotetype = 2; $i += 6; break;
default: $quotetype = 0; $i += 5; break;
}
} else {
$this->error(0, 17, 'when element', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {if:
} elseif ($c1 == 'i' && $c2 == 'f' && $c3 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 18, 'if element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 4;
$index = _ETS_IF . ':' . $i;
$elts[$index]['test'] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
$elts[$index]['true'] = $this->parse(_ETS_IF, $i, $line, $ncontent, $content);
// {repeat:
} elseif ($c1 == 'r' && $c2 == 'e' && $c3 == 'p' && $c4 == 'e' && $c5 == 'a' && $c6 == 't' && $c7 == ':') {
if ($ptype & _ETS_GROUP1) {
$this->error(0, 19, 'repeat element', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 8;
$index = _ETS_REPEAT . ':' . $i;
$elts[$index]['loops'] = $this->parse(_ETS_CODE, $i, $line, $ncontent, $content);
$elts[$index]['repeated'] = $this->parse(_ETS_REPEAT, $i, $line, $ncontent, $content);
// simple tag with absolute path
} elseif ($c1 == '/' && $c2 == '/') {
if ($ptype & _ETS_GROUP3) {
$this->error(0, 20, 'simple tag element with absolute path', $line, $ptype);
$this->skip = TRUE;
return array();
}
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cvalue = '';
$cname = '//';
$nametype = _ETS_TAG;
$i += 2;
// other simple tag
} elseif ($c1 != '/' && !$this->is_space($c1)) {
// {else
if ($c1 == 'e' && $c2 == 'l' && $c3 == 's' && $c4 == 'e' && ($this->is_space($c5) || $c5 == '}' )) {
if ($ptype & _ETS_CHOOSEs) {
$mode = _ETS_NAME;
$ntext = $nvalue = $nspace = 0;
$nname = 1;
$ctext = $cvalue = '';
$cname = 'else';
$nametype = _ETS_TAG;
$i += 4;
} else {
$this->error(0, 21, 'else element', $line, $ptype);
$this->skip = TRUE;
return array();
}
} elseif ($ptype & _ETS_GROUP3) {
$this->error(0, 22, 'simple tag element', $line, $ptype);
$this->skip = TRUE;
return array();
// other
} else {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_NAME;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = _ETS_TAG;
}
// {/mask
} elseif ($c1 == '/' && $c2 == 'm' && $c3 == 'a' && $c4 == 's' && $c5 == 'k') {
if ($ptype == _ETS_TEMPLATE) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 5;
} else {
$this->error(1, 23, 'mask', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/set
} elseif ($c1 == '/' && $c2 == 's' && $c3 == 'e' && $c4 == 't') {
if ($ptype & _ETS_SETs) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 4;
} else {
$this->error(1, 24, 'set', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/mis
} elseif ($c1 == '/' && $c2 == 'm' && $c3 == 'i' && $c4 == 's') {
if ($ptype & _ETS_MISs) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 4;
} else {
$this->error(1, 25, 'mis', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/php
} elseif ($c1 == '/' && $c2 == 'p' && $c3 == 'h' && $c4 == 'p') {
if ($ptype == _ETS_PHP) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 4;
} else {
$this->error(1, 26, 'PHP', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/if
} elseif ($c1 == '/' && $c2 == 'i' && $c3 == 'f') {
if ($ptype == _ETS_IF) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 3;
} else {
$this->error(1, 27, 'if', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/choose
} elseif ($c1 == '/' && $c2 == 'c' && $c3 == 'h' && $c4 == 'o' && $c5 == 'o' && $c6 == 's' && $c7 == 'e') {
if ($ptype & _ETS_CHOOSEs) {
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 7;
} else {
$this->error(1, 28, 'choose', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/call
} elseif ($c1 == '/' && $c2 == 'c' && $c3 == 'a' && $c4 == 'l' && $c5 == 'l') {
if ($ptype == _ETS_CALL) {
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 5;
} else {
$this->error(1, 29, 'call', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/arg
} elseif ($c1 == '/' && $c2 == 'a' && $c3 == 'r' && $c4 == 'g') {
if ($ptype == _ETS_ARG) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 4;
} else {
$this->error(1, 30, 'arg', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/when
} elseif ($c1 == '/' && $c2 == 'w' && $c3 == 'h' && $c4 == 'e' && $c5 == 'n') {
// of when val
if ($ptype == _ETS_WHENVAL) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 5;
// of when test
} elseif ($ptype == _ETS_WHENTEST) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 5;
} else {
$this->error(1, 31, 'when', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/else
} elseif ($c1 == '/' && $c2 == 'e' && $c3 == 'l' && $c4 == 's' && $c5 == 'e') {
if ($ptype == _ETS_ELSE) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 5;
} else {
$this->error(1, 32, 'else', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/repeat
} elseif ($c1 == '/' && $c2 == 'r' && $c3 == 'e' && $c4 == 'p' && $c5 == 'e' && $c6 == 'a' && $c7 == 't') {
if ($ptype == _ETS_REPEAT) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
$i += 7;
} else {
$this->error(1, 33, 'repeat', $line, $ptype);
$this->skip = TRUE;
return array();
}
// {/ (simplified closing tag)
} elseif ($c1 == '/' && ($c2 == '}' || $this->is_space($c2))) {
if ($ptype != _ETS_ROOT) {
if (!($ptype & _ETS_GROUP4)) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
}
$mode = _ETS_CLOSING_TAG;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
++$i;
} else {
$this->error(1, 34, '', $line, $ptype);
$this->skip = TRUE;
return array();
}
// text
} elseif (!($ptype & _ETS_GROUP3)) {
$ctext .= $c0;
$ntext = 1;
}
// end of code element
} elseif ($c0 == '}' && $ptype == _ETS_CODE) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
++$i;
return $elts;
// escape } with \} in code acquisition
} elseif ($c0 == '\\' && $c1 == '}' && $ptype == _ETS_CODE) {
$ctext .= '}';
$ntext = 1;
++$i;
// no text in choosevar element
} elseif ($ptype == _ETS_CHOOSE && !$is_space0) {
$this->error(2, 35, "unexpected character '$c0' in choose element", $line);
$this->skip = TRUE;
return array();
// no text in choose element
} elseif ($ptype == _ETS_CHOOSEVAR && !$is_space0) {
$this->error(2, 36, "unexpected character '$c0' in choose-variable element", $line);
$this->skip = TRUE;
return array();
// no text in call element
} elseif ($ptype == _ETS_CALL && !$is_space0) {
$this->error(2, 37, "unexpected character '$c0' in call element", $line);
$this->skip = TRUE;
return array();
// text
} elseif ($ptype != _ETS_ROOT) {
$ctext .= $c0;
$ntext = 1;
}
// name acquisition
} elseif ($mode == _ETS_NAME) {
// end of name acquisition
if ($c0 == '}' && $nname == 1) {
// reduce
if ($nametype == _ETS_REDUCE) {
if (!isset($elts['0reduce']) || $elts['0reduce'] == _ETS_REDUCE_NULL) {
if (!$this->store_reduce($elts, $cname)) {
$this->error(7, 38, "invalid value $cname for reduce element", $line);
}
}
// template
} elseif ($nametype == _ETS_TEMPLATE) {
++$i;
if ($ptype != _ETS_ROOT) {
$this->store_node($elts, _ETS_TEMPLATE, $i, $line, $cname, NULL, $ncontent, $content);
} elseif (isset($elts[$cname])) {
$this->error(2, 39, "template $cname already defined", $line);
$this->skip = TRUE;
return $elts; //array();
} else {
$elts[$cname] = $this->parse(_ETS_TEMPLATE, $i, $line, $ncontent, $content);
}
// set
} elseif ($nametype == _ETS_SET) {
++$i;
$this->store_node($elts, _ETS_SET, $i, $line, $cname, NULL, $ncontent, $content);
// mis
} elseif ($nametype == _ETS_MIS) {
++$i;
$this->store_node($elts, _ETS_MIS, $i, $line, $cname, NULL, $ncontent, $content);
// tag?
} elseif ($nametype == _ETS_TAG) {
// php
if ($cname == 'php') {
++$i;
$elts[_ETS_PHP . ':' . $i] = $this->parse(_ETS_PHP, $i, $line, $ncontent, $content);
// choose
} elseif ($cname == 'choose') {
++$i;
$elts[_ETS_CHOOSE . ':' . $i] = $this->parse(_ETS_CHOOSE, $i, $line, $ncontent, $content);
// else
} elseif (($ptype == _ETS_CHOOSE || $ptype == _ETS_CHOOSEVAR) && $cname == 'else') {
if (isset($elts['else'])) {
$this->error(2, 40, 'else element already exists in ' . $this->elt_label($ptype), $line);
$this->skip = TRUE;
return array();
} else {
++$i;
$elts['else'] = $this->parse(_ETS_ELSE, $i, $line, $ncontent, $content);
}
// tag!
} else {
$this->store_leaf($elts, _ETS_TAG, $i, $cname);
}
// choose var
} elseif ($nametype == _ETS_CHOOSEVAR) {
++$i;
$this->store_node($elts, _ETS_CHOOSEVAR, $i, $line, $cname, NULL, $ncontent, $content);
// arg
} elseif ($nametype == _ETS_ARG) {
++$i;
$this->store_node($elts, _ETS_ARG, $i, $line, $cname, NULL, $ncontent, $content);
}
$mode = _ETS_DATA;
// space in name acquisition
} elseif ($is_space0) {
if ($nname == 1) {
$nspace = 1;
} else {
$this->error(2, 41, "unexpected space before name", $line);
$this->skip = TRUE;
return array();
}
// start of value acquisition
} elseif ($c0 == ':' && $nname == 1 && ($nametype == _ETS_SET || $nametype == _ETS_MIS)) {
$cvalue = '';
$nvalue = 0;
$nspace = 0;
$mode = _ETS_VALUE;
switch ($c1) {
case '\'': $quotetype = 1; ++$i; break;
case '"': $quotetype = 2; ++$i; break;
default: $quotetype = 0; break;
}
// start of second name acquisition
} elseif ($c0 == ':' && $nametype == _ETS_TAG && $nname == 1 && $nvalue == 0) {
++$i;
$this->store_node($elts, _ETS_ALT_TAG, $i, $line, $cname, $cvalue, $ncontent, $content, TRUE);
--$i;
$mode = _ETS_DATA;
$ntext = $nname = $nvalue = $nspace = 0;
$ctext = $cname = $cvalue = '';
$nametype = NULL;
// data after trailing spaces
} elseif ($nspace == 1) {
$this->error(2, 42, "unexpected character '$c0' after spaces in name", $line);
$this->skip = TRUE;
return array();
// name acquisition
} elseif (($nname == 0 && preg_match('/[a-zA-Z_\.\x7f-\xff]/', $c0)) || ($nname == 1 && preg_match('/[\[\]\'\/a-zA-Z0-9_\.\x7f-\xff]/', $c0))) {
$cname .= $c0;
$nname = 1;
// absolute path at the beginning of name acquisition
} elseif ($c0 == '/' && $c1 == '/' && $nname == 0) {
$cname = '//';
++$i;
// error in name acquisition
} else {
$this->error(2, 43, "unexpected character '$c0' in name", $line);
$this->skip = TRUE;
return array();
}
// end of closing tag
} elseif ($mode == _ETS_CLOSING_TAG) {
if ($c0 == '}') {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
return $elts;
} elseif (!$is_space0) {
$this->error(2, 44, "unexpected character '$c0' in closing tag", $line);
$this->skip = TRUE;
return array();
}
// value acquisition
} elseif ($mode == _ETS_VALUE) {
// end of value acquisition
if ($c0 == '}' && $nvalue == 1 && ($quotetype == 0 || $nspace == 1 || $nspace == 2)) {
if ($nametype == _ETS_SET) {
++$i;
$this->store_node($elts, _ETS_SETVAL, $i, $line, $cname, $cvalue, $ncontent, $content);
} elseif ($nametype == _ETS_MIS) {
++$i;
$this->store_node($elts, _ETS_MISVAL, $i, $line, $cname, $cvalue, $ncontent, $content);
} elseif ($nametype == _ETS_WHENVAL) {
++$i;
$elts['when'][_ETS_WHENVAL . ':' . $i . '::' . $cvalue] = $this->parse(_ETS_WHENVAL, $i, $line, $ncontent, $content);
}
$mode = _ETS_DATA;
// no more character after space for single quoted string
} elseif ($c0 == '\'' && $quotetype == 1 && $nspace == 0) {
$nspace = 2;
// no more character after space for double quoted string
} elseif ($c0 == '"' && $quotetype == 2 && $nspace == 0) {
$nspace = 2;
// space in value acquisition
} elseif ($is_space0) {
if ($nvalue == 0 && $quotetype == 0) { // no value without quote
$this->error(2, 45, "unexpected space at the beginning of a value", $line);
$this->skip = TRUE;
return array();
} else { // value found or with quotes
if ($quotetype == 0) { // no quote
$nspace = 1;
} else { // with quotes
if ($nspace == 2) { // after quotes
$nspace = 1;
} else { // in quotes
$cvalue .= $c0;
$nvalue = 1;
}
}
}
// escape } with \} in value acquisition without quote
} elseif ($c0 == '\\' && $c1 == '}' && $nspace == 0) {
$cvalue .= '}';
$nvalue = 1;
++$i;
// espace ' with \' in value acquisition for single quoted string
} elseif ($c0 == '\\' && $c1 == '\'' && $quotetype == 1 && $nspace == 0) {
$cvalue .= '\'';
$nvalue = 1;
++$i;
// espace " with \" in value acquisition for single quoted string
} elseif ($c0 == '\\' && $c1 == '"' && $quotetype == 2 && $nspace == 0) {
$cvalue .= '"';
$nvalue = 1;
++$i;
// value acquisition
} elseif ($nspace == 0) {
$cvalue .= $c0;
$nvalue = 1;
// error in value acquisition
} else {
$this->error(2, 46, "unexpected character '$c0' in value", $line);
$this->skip = TRUE;
return array();
}
// comment
} elseif ($mode == _ETS_COMMENT) {
// nested
if ($c0 == '{' && $c1 == '*') {
++$i;
++$nspecial;
// end
} elseif ($c0 == '*' && $c1 == '}') {
++$i;
--$nspecial;
// last end
if ($nspecial == 0) {
$mode = _ETS_DATA;
}
}
// cdata
} elseif ($mode == _ETS_CDATA) {
// nested
if ($c0 == '{' && $c1 == '#') {
++$i;
++$nspecial;
// end
} elseif ($c0 == '#' && $c1 == '}') {
++$i;
--$nspecial;
// last end
if ($nspecial == 0) {
$mode = _ETS_DATA;
}
// text acquisition
} else {
switch ($c0) {
case "\n": $ctext .= "\1n\1"; break;
case "\r": $ctext .= "\1r\1"; break;
case "\t": $ctext .= "\1t\1"; break;
case " " : $ctext .= "\1s\1"; break;
default : $ctext .= $c0; break;
}
$ntext = 1;
}
}
}
// end
if ($mode & _ETS_GROUP0) {
$this->error(3, 47, '', $saveline, $mode);
$this->skip = TRUE;
return array();
}
if ($ptype == _ETS_ROOT_EVAL) {
$this->store_text($elts, $i, $ptype, $ntext, $ctext);
} elseif ($ptype != _ETS_ROOT) {
$this->error(4, 48, '', $saveline, $ptype);
$this->skip = TRUE;
return array();
}
return $elts;
}
/**
* Merge two template trees
*/
function masktree_merge($masktree1, $masktree2, $maskname)
{
$merged = array_merge($masktree1, $masktree2);
if (count($merged) < count($masktree1) + count($masktree2)) {
$keys1 = array_keys($masktree1);
$keys2 = array_keys($masktree2);
$keysm = array_merge($keys1, $keys2);
$keysc = array_count_values($keysm);
foreach ($keysc as $keyn => $keyc) {
if ($keyc > 1) {
if ($keyn == '0reduce') {
$this->error(6, 49, 'reduce element already used');
} elseif ($keyn != '0include') {
$this->error(16, 60, "template $keyn already defined in <b>$maskname</b>");
}
}
}
}
return $merged;
}
/***** C O N T E N T *****/
/**
* Read a stream and return its content or FALSE if fail
*/
function read_content()
{
if ($this->external_source_read) {
$fct = $this->source_read_name;
return $fct($this->container);
} else {
$content = FALSE;
if ($handle = @fopen($this->container, 'rb')) {
$size = @filesize($this->container);
$content = @fread($handle, $size);
fclose($handle);
}
return $content;
}
}
/**
* Return container content or masktree in container content
*/
function read_container($container, $parse)
{
$this->container = $container = trim($container);
$this->skip = FALSE;
// content must be parsed...
if ($parse != _ETS_TEXT) {
// null containers are avoid
if ($this->container === '' || strtoupper($this->container) == 'NULL') {
return array();
}
// check if container is already used
if ($parse == _ETS_ROOT) {
if (isset($this->containers[$container])) {
$this->error(16, 50, "container $container already used");
return array();
}
}
// cache handlers are available...
if ($this->external_cache_read && $this->external_cache_write) {
// the cache exists and is not obsolete
$fct = $this->cache_read_name;
if ($envelope = $fct($this->container)) {
// the cache is a valid envelope
if (isset($envelope) && $envelope{0} == 'E' && $envelope{1} == 'T' && $envelope{2} == 'S' && $envelope{3} == "\1") {
$masktree = unserialize(substr($envelope, 4));
// the envelope contains valid templates
if ($masktree && is_array($masktree)) {
$this->containers[$container] = TRUE;
// the container calls other containers
if (isset($masktree['0include'])) {
foreach ($masktree['0include'] as $includedname) {
$included = $this->read_container($includedname, _ETS_ROOT);
if ($included === FALSE) {
$this->error(13, 51, $includedname);
} else {
$masktree = $this->masktree_merge($masktree, $included, $includedname);
}
}
}
return $masktree;
}
}
}
// refresh the cache
$content = $this->read_content();
if ($content === FALSE) {
return FALSE;
}
$this->containers[$container] = TRUE;
$masktree = $this->parse($parse, $i = 0, $line = 1, strlen($content), "$content ");
$fct = $this->cache_write_name;
$fct($this->container, "ETS\1" . serialize($masktree));
return $masktree;
// .. or not
} else {
$content = $this->read_content();
if ($content === FALSE) {
return FALSE;
}
$this->containers[$container] = TRUE;
// return $this->parse($parse, $i = 0, $line = 1, strlen($content), "$content ");
$i = 0; $line = 1;
return $this->parse($parse, $i, $line, strlen($content), "$content ");
}
// .. or not
} else {
// null containers are avoid
if ($this->container === '' || strtoupper($this->container) == 'NULL') {
return '';
}
return $this->read_content();
}
}
/**
* Read containers then parse their content to build a template tree
*/
function parse_containers($containers)
{
// Construct an array of container names
if (!is_array($containers)) {
$containers = explode(',', $containers);
}
// Parse each container
foreach ($containers as $container) {
$masktree = $this->read_container($container, _ETS_ROOT);
if ($masktree === FALSE) {
$this->error(11, 52, $this->container);
} else {
$this->masktree = $this->masktree_merge($this->masktree, $masktree, $container);
}
}
}
/***** M A T C H I N G *****/
/**
* Retrieve the value of a string representation of a variable
*/
function get_value($parent, $varname)
{
if (isset($parent->$varname)) {
return $parent->$varname;
} else {
$elements = explode('[', $varname);
if (count($elements) == 1) {
return NULL;
} else {
$vartest = $parent;
foreach ($elements as $elementid => $element) {
if ($elementid == 0) {
$vartest = $parent->$element;
if (!isset($vartest)) {
return NULL;
}
} else {
$index = substr($element, 0, -1);
if ($index == '_first') {
$keys = array_keys($vartest);
$index = $keys[0];
} elseif ($index == '_last') {
$keys = array_keys($vartest);
$index = $keys[count($keys) - 2];
}
if (!isset($vartest[$index])) {
return NULL;
} else {
$vartest = $vartest[$index];
}
}
}
}
return $vartest;
}
}
/**
* Define the type of the current data, the direction and parent property
*/
function get_datatype($maskname, $carray, $incode, &$cindex, &$ckey, &$clast, &$datatree, &$datatype, &$direction, &$currentdata, $safemode)
{
// . from root
if ($maskname == '//' && !$safemode) {
$datatype = _ETS_COMPLEX;
$currentdata = $this->datatree;
if ($direction == _ETS_FORWARD) {
if (is_array($currentdata)) {
$currentdata['_parent'] = &$datatree;
} elseif (is_object($currentdata)) {
$currentdata->_parent = &$datatree;
}
}
// . parent
} elseif (($maskname == '..' || $maskname == '_parent') && !$safemode) {
if (is_array($datatree)) {
$datatype = _ETS_COMPLEX;
$currentdata = $datatree['_parent'];
$direction = _ETS_BACKWARD;
} elseif (is_object($datatree)) {
$datatype = _ETS_COMPLEX;
$currentdata = $datatree->_parent;
$direction = _ETS_BACKWARD;
} else {
$datatype = _ETS_MISSING;
$currentdata = NULL;
$direction = _ETS_FORWARD;
}
// . first sibling in an array
} elseif ($maskname == '_start') {
$direction = _ETS_FORWARD;
$keys = array_keys($carray);
$cindex = 0;
if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]])) {
$ckey = $keys[$cindex];
$clast = ($cindex == count($carray) - 2);
$currentdata = $carray[$ckey];
$datatype = _ETS_COMPLEX;
} else {
$currentdata = NULL;
$datatype = _ETS_MISSING;
}
// . previous sibling in an array
} elseif ($maskname == '_previous') {
$direction = _ETS_FORWARD;
$keys = array_keys($carray);
--$cindex;
if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]])) {
$ckey = $keys[$cindex];
$clast = FALSE;
$currentdata = $carray[$ckey];
$datatype = _ETS_COMPLEX;
} else {
$currentdata = NULL;
$datatype = _ETS_MISSING;
}
// . next sibling in an array
} elseif ($maskname == '_next') {
$direction = _ETS_FORWARD;
$keys = array_keys($carray);
++$cindex;
if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]]) && $keys[$cindex] != '_parent') {
$ckey = $keys[$cindex];
$clast = ($cindex == count($carray) - 2);
$currentdata = $carray[$ckey];
$datatype = _ETS_COMPLEX;
} else {
$currentdata = NULL;
$datatype = _ETS_MISSING;
}
// . last sibling in an array
} elseif ($maskname == '_end') {
$direction = _ETS_FORWARD;
$keys = array_keys($carray);
$cindex = count($keys) - 2;
if (isset($keys[$cindex]) && isset($carray[$keys[$cindex]])) {
$ckey = $keys[$cindex];
$clast = TRUE;
$currentdata = $carray[$ckey];
$datatype = _ETS_COMPLEX;
} else {
$currentdata = NULL;
$datatype = _ETS_MISSING;
}
// . real data
} else {
// retrieve the value
$currentdata = $this->get_value($datatree, $maskname);
if (isset($currentdata)) {
if (is_scalar($currentdata)) {
$direction = _ETS_FORWARD;
if ($currentdata === FALSE && !$incode) {
$datatype = _ETS_MISSING;
} elseif ($currentdata === '' && !$incode) {
$datatype = _ETS_MISSING;
} else {
$datatype = _ETS_SCALAR;
}
} elseif (is_object($currentdata) && count(get_object_vars($currentdata)) > 0) {
$datatype = _ETS_COMPLEX;
if ($direction == _ETS_FORWARD && !$safemode) {
$currentdata->_parent = &$datatree;
}
} elseif (is_array($currentdata) && count($currentdata) > 0) {
$datatype = _ETS_COMPLEX;
if ($direction == _ETS_FORWARD && !$safemode) {
$currentdata['_parent'] = &$datatree;
}
} else {
$direction = _ETS_FORWARD;
$datatype = _ETS_MISSING;
}
} else {
$direction = _ETS_FORWARD;
$datatype = _ETS_MISSING;
}
}
}
/**
* Add system variables to an object
*/
function add_system_var(&$datatree, $index, $last, $key)
{
$datatree->_key = $key;
$datatree->_index = $index;
$datatree->_rank = $index + 1;
$datatree->_odd = $datatree->_not_even = (1 == $datatree->_rank % 2);
$datatree->_even = $datatree->_not_odd = (0 == $datatree->_rank % 2);
$datatree->_first = (0 == $index);
$datatree->_middle = !$datatree->_first && !$last;
$datatree->_last = $last;
$datatree->_not_first = !$datatree->_first;
$datatree->_not_last = !$last;
$datatree->_not_middle = !$datatree->_middle;
}
/**
* Excerpt info defined in the index of each node of the template tree
*/
function parse_info($info)
{
$elements = explode(':', $info);
$count = count($elements);
if ($count > 4) {
for ($i = 4; $i < $count; ++$i) {
$elements[3] .= ':' . $elements[$i];
}
} else {
$elements = array_pad($elements, 4, '');
}
return array($elements[0], $elements[2], $elements[3]);
}
/**
* Protect non printable characters
*/
function protect_spaces($data)
{
$data = str_replace("\n", "\1n\1", $data);
$data = str_replace("\r", "\1r\1", $data);
$data = str_replace("\t", "\1t\1", $data);
return str_replace(" " , "\1s\1", $data);
}
/**
* Recursively match the template tree with the data tree
*/
function build_mask($datatree, $masktree, $direction = _ETS_FORWARD, $index = -1, $last = FALSE, $key = '', $incode = FALSE, $carray = array(), $safemode = FALSE)
{
$built = array();
// array
if (isset($datatree) && is_array($datatree) && count($datatree) > 0) {
$lindex = 0;
$count = count($datatree) - 1; // don't count parent element
foreach ($datatree as $dk => $dv) {
if (!is_scalar($dv) && $dk !== '_parent') {
if (is_object($dv)) {
$dv->_parent = &$datatree['_parent'];
} elseif (is_array($dv)) {
$dv['_parent'] = &$datatree['_parent'];
}
$built[] = $this->build_mask($dv, $masktree, $direction, $lindex, ($count == $lindex + 1), $dk, $incode, $datatree);
}
++$lindex;
}
return implode('', $built);
}
// define system variables
if (is_object($datatree) && $index > -1 && !isset($datatree->_key)) {
$this->add_system_var($datatree, $index, $last, $key);
}
// loop through each child element
foreach ($masktree as $maskinfo => $child) {
// save array information
$cindex = $index;
$clast = $last;
$ckey = $key;
// retrieve info from index
list($masktype, $maskname, $maskvalue) = $this->parse_info($maskinfo);
// in safe mode, only a subset of elements are available
if ($safemode) {
// retrieve datatype and direction and define parent property if necessary
$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, TRUE);
switch ($masktype) {
// content data element
case _ETS_TEXT:
$built[] = $child;
break;
// simple tag element are only used to place scalar values
case _ETS_TAG:
if ($datatype == _ETS_SCALAR) {
$built[] = $this->protect_spaces($currentdata);
}
break;
// set element
case _ETS_SET:
if ($datatype != _ETS_MISSING) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
}
break;
// mis element
case _ETS_MIS:
if ($datatype == _ETS_MISSING) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
}
break;
// set val element
case _ETS_SETVAL:
if ($datatype == _ETS_SCALAR) {
if ($currentdata == $maskvalue) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
}
}
break;
// mis val element
case _ETS_MISVAL:
if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
}
break;
// template element
case _ETS_TEMPLATE:
if ($datatype == _ETS_SCALAR) {
$built[] = $this->build_mask($datatree, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
} elseif ($datatype == _ETS_COMPLEX) {
$built[] = $this->build_mask($currentdata, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
}
break;
// other element: error
default:
$this->error(15, 53, '', 0, $masktype);
break;
}
// normal mode
} else {
switch ($masktype) {
// content data element
case _ETS_TEXT:
$built[] = $child;
break;
// php element
case _ETS_PHP:
$return = NULL;
@eval('$return=(string)(' . $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray) . ');');
if (isset($return)) {
$built[] = $return;
}
break;
// const element
case _ETS_CONST:
$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(string)(' . $template . ');');
if (isset($return) && isset($this->masktree[$return])) {
$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// call element
case _ETS_CALL:
$template = $this->build_mask($datatree, $child['template'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(string)(' . $template . ');');
if (isset($return) && isset($this->masktree[$return]) && isset($child['args'])) {
$argdatatree = $datatree;
foreach ($child['args'] as $arginfo => $argchild) {
list($argtype, $argname, $argvalue) = $this->parse_info($arginfo);
$argdatatree->$argname = $this->build_mask($datatree, $argchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
}
$built[] = $this->build_mask($argdatatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// include element
case _ETS_INCLUDE:
$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(string)(' . $container . ');');
if (isset($return)) {
$included = $this->read_container($return, _ETS_ROOT);
if ($included === FALSE) {
$this->error(13, 54, $return);
} else {
$this->masktree = $this->masktree_merge($this->masktree, $included, $maskvalue);
}
}
break;
// insert element
case _ETS_INSERT:
$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(string)(' . $container . ');');
if (isset($return)) {
$inserted = $this->read_container($return, _ETS_TEXT);
if ($inserted === FALSE) {
$this->error(12, 55, $return);
} else {
$built[] = $inserted;
}
}
break;
// eval and safe elements
case _ETS_EVAL:
case _ETS_SAFE:
$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(string)(' . $container . ');');
if (isset($return)) {
$evaluated = $this->read_container($return, _ETS_ROOT_EVAL);
if ($evaluated === FALSE) {
$this->error(14, 56, $return);
} else {
$built[] = $this->build_mask($datatree, $evaluated, $direction, $cindex, $clast, $ckey, $incode, $carray, $masktype == _ETS_SAFE);
}
}
break;
// other types of element
default:
// retrieve datatype and direction and define parent property if necessary
$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, $safemode);
switch ($masktype) {
// simple tag element
case _ETS_TAG:
if ($datatype == _ETS_SCALAR && isset($this->masktree[$maskname])) {
$built[] = $this->build_mask($datatree, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
} elseif ($datatype == _ETS_SCALAR) {
if ($incode) {
if ($currentdata === TRUE) {
$built[] = 'TRUE';
} elseif ($currentdata === FALSE) {
$built[] = 'FALSE';
} elseif (is_string($currentdata)) {
$built[] = '"' . addcslashes($currentdata, "\0..\31\"") . '"';
} else {
$built[] = $currentdata;
}
} else {
$built[] = $this->protect_spaces($currentdata);
}
} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$maskname])) {
$built[] = $this->build_mask($currentdata, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
} elseif ($datatype == _ETS_MISSING && $incode) {
$built[] = 'NULL';
}
break;
// alternate tag element
case _ETS_ALT_TAG:
$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(string)(' . $template . ');');
if (isset($return)) {
if ($datatype == _ETS_SCALAR && isset($this->masktree[$return])) {
$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$return])) {
$built[] = $this->build_mask($currentdata, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
} elseif ($datatype == _ETS_SCALAR) {
$built[] = $currentdata;
}
}
break;
// template element
case _ETS_TEMPLATE:
if ($datatype == _ETS_SCALAR) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
} elseif ($datatype == _ETS_COMPLEX) {
$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
} elseif ($datatype == _ETS_MISSING && $incode) {
$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// if element
case _ETS_IF:
$test = $this->build_mask($datatree, $child['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(bool)(' . $test . ');');
if ($return === TRUE) {
$built[] = $this->build_mask($datatree, $child['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// repeat element
case _ETS_REPEAT:
$loop = $this->build_mask($datatree, $child['loops'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(int)(' . $loop . ');');
for ($i = 0; $i < $return; ++$i) {
if (is_object($datatree)) {
$datatree->_count = $i + 1;
}
$built[] = $this->build_mask($datatree, $child['repeated'], $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// choose element
case _ETS_CHOOSE:
$notfound = TRUE;
if (isset($child['when'])) {
foreach ($child['when'] as $grandchild) {
$test = $this->build_mask($datatree, $grandchild['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
$return = NULL;
@eval('$return=(bool)(' . $test . ');');
if ($return === TRUE) {
$notfound = FALSE;
$built[] = $this->build_mask($datatree, $grandchild['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
break;
}
}
}
if ($notfound && isset($child['else'])) {
$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// choose variable element
case _ETS_CHOOSEVAR:
if ($datatype == _ETS_SCALAR) {
$notfound = TRUE;
if (isset($child['when'])) {
foreach ($child['when'] as $gcmaskinfo => $grandchild) {
list($gcmasktype, $gcmaskname, $gcmaskvalue) = $this->parse_info($gcmaskinfo);
if ($currentdata == $gcmaskvalue) {
$built[] = $this->build_mask($datatree, $grandchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
$notfound = FALSE;
}
}
}
if ($notfound && isset($child['else'])) {
$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
}
}
break;
// set element
case _ETS_SET:
if ($datatype != _ETS_MISSING) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// mis element
case _ETS_MIS:
if ($datatype == _ETS_MISSING) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// set val element
case _ETS_SETVAL:
if ($datatype == _ETS_SCALAR) {
if ($currentdata == $maskvalue) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
}
}
break;
// mis val element
case _ETS_MISVAL:
if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
// mis mask element
case _ETS_MIS_TEMPLATE:
if ($datatype == _ETS_MISSING || $datatype == _ETS_COMPLEX) {
$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
}
break;
}
break;
}
}
}
// done
return implode('', $built);
}
/***** I N T E R F A C E *****/
/**
* Build the result
*/
function build_all($datatree, $entry)
{
// No entry: stop
if (!isset($this->masktree[$entry])) {
$this->error(8, 57, $entry);
}
// Data tree
$this->datatree = $datatree;
if (is_array($this->datatree)) {
$this->datatree['_parent'] = NULL;
} elseif (is_object($this->datatree)) {
$this->datatree->_parent = NULL;
} elseif (isset($this->datatree)) {
$this->error(9, 58);
$this->datatree = NULL;
}
// Build
$built = $this->build_mask($this->datatree, $this->masktree[$entry]);
// Reduce and return
if (!isset($this->masktree['0reduce'])) {
$this->masktree['0reduce'] = _ETS_REDUCE_OFF;
}
switch ($this->masktree['0reduce']) {
case _ETS_REDUCE_OFF:
break;
case _ETS_REDUCE_SPACES:
$built = preg_replace('/(\r\n|\r|\n)+/sm', "\n", preg_replace('/[ \t]*?(\r\n|\r|\n)+[\t ]*/sm', "\n", $built));
break;
case _ETS_REDUCE_ALL:
$built = preg_replace('/[ \t]*?(\r\n|\r|\n)+[\t ]*/sm', '', $built);
break;
}
$built = str_replace("\1n\1", "\n", $built);
$built = str_replace("\1r\1", "\r", $built);
$built = str_replace("\1t\1", "\t", $built);
$built = str_replace("\1s\1", " ", $built);
return $built;
}
/**
* Contructor: create the template tree
*/
function _ets($containers, $hsr, $hcr, $hcw)
{
$this->source_read_name = $hsr;
$this->cache_read_name = $hcr;
$this->cache_write_name = $hcw;
$this->external_source_read = function_exists($hsr);
$this->external_cache_read = function_exists($hcr);
$this->external_cache_write = function_exists($hcw);
if (is_array($containers) || is_string($containers)) {
$this->parse_containers($containers);
} else {
$this->error(10, 59);
}
}
}
/**
* Source read handler for template string
*/
function _printts($id)
{
return $id;
}
/**
* Return a built template
*/
function sprintt($datatree, $containers, $entry = 'main', $hsr = _ETS_SOURCE_READ, $hcr = _ETS_CACHE_READ, $hcw = _ETS_CACHE_WRITE)
{
$ets = new _ets($containers, $hsr, $hcr, $hcw);
return $ets->build_all($datatree, $entry);
}
/**
* Print out a built template
*/
function printt($datatree, $containers, $entry = 'main', $hsr = _ETS_SOURCE_READ, $hcr = _ETS_CACHE_READ, $hcw = _ETS_CACHE_WRITE)
{
$ets = new _ets($containers, $hsr, $hcr, $hcw);
echo $ets->build_all($datatree, $entry);
}
/**
* Return the same value than missing element in PHP code
*/
function mis($value)
{
return is_null($value) || $value === '' || $value === FALSE || !is_scalar($value);
}
/**
* Return the same value than set element in PHP code
*/
function set($value)
{
return !mis($value);
}
/**
* Return a built template string
*/
function sprintts($datatree, $containers, $entry = 'main')
{
return sprintt($datatree, $containers, $entry, _ETS_STRING_READ, '', '');
}
/**
* Print out a built template string
*/
function printts($datatree, $containers, $entry = 'main')
{
printt($datatree, $containers, $entry, _ETS_STRING_READ, '', '');
}
?>
ACC SHELL 2018