3 * Simple text template class. Does not handle caching.
9 # here is whats in each array node
10 define('YATT_NAME', 0); # node name
11 define('YATT_OUTPUT', 1); # output buffer for this node
12 define('YATT_CONTEXTS', 2); # not impl. in php: node context
13 define('YATT_DSTART', 3); # start of data/chilren nodes
15 # This sucks, but array_pop doesn't deal well with references
16 function &my_pop(&$array) {
17 if (!count($array)) return null;
19 $var =& $array[key($array)];
26 # Holds the template tree
32 # Holds information on errors
35 # INTERNAL: Push an error onto the error stack!
37 $args = func_get_args ();
38 $format = array_shift($args);
39 array_push($this->errors, vsprintf($format, $args));
40 return count($this->errors);
43 # INTERNAL: act as a callback for preg_replace_callback below
44 function pp_callback($matches) {
45 return $this->preprocess($matches[1]);
48 # INTERNAL: read file, preprocess for includes, strip out comments
49 function preprocess($fname) {
50 if (! ($data = file_get_contents($fname))) {
51 $this->error('INCLUDE(%s): can not open file!', $fname);
56 $data = preg_replace('/[ \t]*\%\[#\].*$/m', '', $data);
58 # fetch all includes (recursive!)
59 return preg_replace_callback(
60 '/^[ \t]*\%include[ \t]+\[([A-Za-z-_.]+)\][ \t]*$/im',
61 array(&$this, 'pp_callback'),
65 # load template file on class creation
66 # You can load multiple files
67 function load($fname) {
68 $data = $this->preprocess($fname);
72 $nchunks = preg_match_all(
73 '/(.*?)[ \t]*\%(begin|end)[\t ]+\[([A-Za-z-_]+)\][\t ]*$/ism',
74 $data, $matches, PREG_SET_ORDER);
76 # array[1] == text, array[2] == (begin|end), array[3] == NAME
77 for ($i = 0; $i < $nchunks; $i++) {
78 $text = $matches[$i][1];
79 $type = strtolower($matches[$i][2]);
80 $name = $matches[$i][3];
82 if ($text && (strlen($text) > 0)) {
83 array_push($cur, $text);
86 if (strcasecmp($type, 'begin') == 0) {
87 $new = array($name, '', '');
92 } else if (strcasecmp($type, 'end') == 0) {
93 if (strcmp($cur[YATT_NAME], $name)) {
94 return $this->error('LOAD(%s): Mismatched begin/end: got %s, wanted %s! aborting!',
95 $fname, $name, $cur[YATT_NAME]);
97 if (! ($cur =& my_pop($stack))) {
101 return $this->error('LOAD(%s): unknown tag type %s, aborting!', $fname, $type);
105 return $this->error('LOAD(%s): mismatched begin/end pairs at EOF!', $fname);
107 return count($this->errors);
110 # INTERNAL: Find the node that corrosponds to an OID
111 function &find_node($path) {
112 $oid = explode('.', $path);
115 while ($cmp = array_shift($oid)) {
117 for ($i = YATT_DSTART; $i < count($node); $i++) {
118 if (is_array($node[$i]) && (strcmp($node[$i][YATT_NAME], $cmp) == 0)) {
124 $this->error('FIND(%s): Could not find node %s', $path, $cmp);
131 # INTERNAL: Substitute some stuff!
132 function subst($matches) {
133 if (!isset($this->vars[$matches[1]])) {
134 $this->error('PARSE(): unbound variable %s', $matches[1]);
137 return $this->vars[$matches[1]];
140 # INTERNAL: Build the output for this node
141 function build_output(&$root, &$node) {
144 for ($i = YATT_DSTART; $i < count($node); $i++) {
145 if (is_array($node[$i])) {
146 $out .= $this->return_output($node[$i]);
151 while (preg_match('/\%\[([^][%]+)\]/', $buf)) {
153 # TODO: give the user more info when this happens.
154 $this->error('PARSE(): recursive subst in node %s?', $node[YATT_NAME]);
157 $buf = preg_replace_callback('/\%\[([^][%]+)\]/', array(&$root, 'subst'), $buf);
165 # INTERNAL: Return all of the generated output
166 function return_output(&$node) {
167 $out = $node[YATT_OUTPUT];
168 $node[YATT_OUTPUT] = '';
170 for ($i = YATT_DSTART; $i < count($node); $i++) {
171 if (is_array($node[$i])) {
172 $out .= $this->return_output($node[$i]);
178 # Create a new YATT instance.
180 $this->errors = array();
181 $this->obj = array('ROOT', '', '');
184 # Return output, starting at a given node
185 function output($path=NULL) {
186 $obj =& $this->find_node($path);
187 return $obj ? $this->return_output($obj) : FALSE;
190 # Generate text from an object tree
191 function parse($path) {
192 if ($obj =& $this->find_node($path)) {
193 $obj[YATT_OUTPUT] .= $this->build_output($this, $obj);
197 # Set a variable to some value
198 function set($var, $value=NULL) {
199 if (is_array($var)) {
200 $this->vars = array_merge($this->vars, $var);
202 $this->vars[$var] = $value;
206 # Get errors, or return FALSE if there are none.
207 # Resets error list to zero!
208 function get_errors() {
209 $err = $this->errors;
210 $this->errors = array();
211 return count($err) ? $err : FALSE;