errors, vsprintf($format, $args)); return count($this->errors); } # INTERNAL: act as a callback for preg_replace_callback below function pp_callback($matches) { return $this->preprocess($matches[1]); } # INTERNAL: read file, preprocess for includes, strip out comments function preprocess($fname) { if (! ($data = file_get_contents($fname))) { $this->error('INCLUDE(%s): can not open file!', $fname); return ''; } # strip all comments $data = preg_replace('/[ \t]*\%\[#\].*$/m', '', $data); # fetch all includes (recursive!) return preg_replace_callback( '/^[ \t]*\%include[ \t]+\[([A-Za-z-_.]+)\][ \t]*$/im', array(&$this, 'pp_callback'), $data); } # load template file on class creation # You can load multiple files function load($fname) { $data = $this->preprocess($fname); $stack = array(); $cur = &$this->obj; $nchunks = preg_match_all( '/(.*?)[ \t]*\%(begin|end)[\t ]+\[([A-Za-z-_]+)\][\t ]*$/ism', $data, $matches, PREG_SET_ORDER); # array[1] == text, array[2] == (begin|end), array[3] == NAME for ($i = 0; $i < $nchunks; $i++) { $text = $matches[$i][1]; $type = strtolower($matches[$i][2]); $name = $matches[$i][3]; if ($text && (strlen($text) > 0)) { array_push($cur, $text); } if (strcasecmp($type, 'begin') == 0) { $new = array($name, '', ''); $cur[] =& $new; $stack[] =& $cur; $cur = &$new; unset($new); } else if (strcasecmp($type, 'end') == 0) { if (strcmp($cur[YATT_NAME], $name)) { return $this->error('LOAD(%s): Mismatched begin/end: got %s, wanted %s! aborting!', $fname, $name, $cur[YATT_NAME]); } if (! ($cur =& my_pop($stack))) { $cur = &$this->obj; } } else { return $this->error('LOAD(%s): unknown tag type %s, aborting!', $fname, $type); } } if (count($stack)) { return $this->error('LOAD(%s): mismatched begin/end pairs at EOF!', $fname); } return count($this->errors); } # INTERNAL: Find the node that corrosponds to an OID function &find_node($path) { $oid = explode('.', $path); $node = &$this->obj; while ($cmp = array_shift($oid)) { $old = &$node; for ($i = YATT_DSTART; $i < count($node); $i++) { if (is_array($node[$i]) && (strcmp($node[$i][YATT_NAME], $cmp) == 0)) { $node = &$node[$i]; break; } } if ($old == $node) { $this->error('FIND(%s): Could not find node %s', $path, $cmp); return FALSE; } } return $node; } # INTERNAL: Substitute some stuff! function subst($matches) { if (!isset($this->vars[$matches[1]])) { $this->error('PARSE(): unbound variable %s', $matches[1]); return ''; } return $this->vars[$matches[1]]; } # INTERNAL: Build the output for this node function build_output(&$root, &$node) { $out = ''; for ($i = YATT_DSTART; $i < count($node); $i++) { if (is_array($node[$i])) { $out .= $this->return_output($node[$i]); } else { $buf = $node[$i]; $pass = 0; while (preg_match('/\%\[([^][%]+)\]/', $buf)) { if ($pass++ > 10) { # TODO: give the user more info when this happens. $this->error('PARSE(): recursive subst in node %s?', $node[YATT_NAME]); break; } $buf = preg_replace_callback('/\%\[([^][%]+)\]/', array(&$root, 'subst'), $buf); } $out .= $buf; } } return $out; } # INTERNAL: Return all of the generated output function return_output(&$node) { $out = $node[YATT_OUTPUT]; $node[YATT_OUTPUT] = ''; for ($i = YATT_DSTART; $i < count($node); $i++) { if (is_array($node[$i])) { $out .= $this->return_output($node[$i]); } } return $out; } # Create a new YATT instance. function YATT() { $this->errors = array(); $this->obj = array('ROOT', '', ''); } # Return output, starting at a given node function output($path=NULL) { $obj =& $this->find_node($path); return $obj ? $this->return_output($obj) : FALSE; } # Generate text from an object tree function parse($path) { if ($obj =& $this->find_node($path)) { $obj[YATT_OUTPUT] .= $this->build_output($this, $obj); } } # Set a variable to some value function set($var, $value=NULL) { if (is_array($var)) { $this->vars = array_merge($this->vars, $var); } else { $this->vars[$var] = $value; } } # Get errors, or return FALSE if there are none. # Resets error list to zero! function get_errors() { $err = $this->errors; $this->errors = array(); return count($err) ? $err : FALSE; } } ?>