bjori Sun Aug 5 14:49:55 2007 UTC Added files: /phd mktoc.php /phd/include PhDFormat.class.php /phd/formats php.php /phd/themes phpweb.php
Modified files: /phd build.php /phd/include PhDReader.class.php /phd/formats xhtml.php Log: Import PhD rev2
http://cvs.php.net/viewvc.cgi/phd/build.php?r1=1.4&r2=1.5&diff_format=u Index: phd/build.php diff -u phd/build.php:1.4 phd/build.php:1.5 --- phd/build.php:1.4 Fri Jul 27 23:09:27 2007 +++ phd/build.php Sun Aug 5 14:49:55 2007 @@ -1,15 +1,109 @@ +#!/home/bjori/.apps/bin/php <?php -require_once 'config.php'; -require_once 'formats/xhtml.php'; +/* $Id: build.php,v 1.5 2007/08/05 14:49:55 bjori Exp $ */ -$phd = new PhDXHTMLReader( "${OPTIONS[ 'xml_root' ]}/.manual.xml" ); -$phd->seek( "function.dotnet-load" ); -echo date( DATE_RSS )." done seeking\n"; - -ob_start(); -while( $phd->nextNode() ) { - print $phd->transform(); +function err($no, $str, $file, $line) { + global $notify; + if (strpos($str, "No mapper") !== false) { +// $notify->update("Another missing function", strstr($str, "'"))->show(); + return false; + } + + $err = new PHNotify("Something wrong!", "$str\n$file:$line\n", "dialog-error"); + $err + ->urgency(PHNotify::URGENCY_CRITICAL) + ->timeout(PHNotify::EXPIRES_NEVER) + ->hint("x", 1680/2)->hint("y", 1050/2) + ->show(); + return false; +} + +if ($err = extension_loaded("phnotify")) { + $notify = new PHNotify("Starting build"); + $notify->urgency(PHNotify::URGENCY_LOW)->hint("x", 1680)->hint("y", 10)->show(); + $start = microtime(true); + set_error_handler("err"); +} + +require "include/PhDReader.class.php"; +require "include/PhDFormat.class.php"; +require "formats/xhtml.php"; +require "formats/php.php"; +require "themes/phpweb.php"; +require "mktoc.php"; + +if ($err) { + $mktoc = microtime(true); + $notify + ->update("mktoc finished", sprintf("mktoc ran for <b>%d</b> sec", $mktoc-$start)) + ->show(); +} + +$reader = new PhDReader("/home/bjori/php/doc/.manual.xml"); +$format = new phpweb($reader, $IDs, $IDMap); + +$map = $format->getMap(); + +while($reader->read()) { + $type = $reader->nodeType; + $name = $reader->name; + + switch($type) { + case XMLReader::ELEMENT: + case XMLReader::END_ELEMENT: + $open = $type == XMLReader::ELEMENT; + + $funcname = "format_$name"; + if (isset($map[$name])) { + $tag = $map[$name]; + if (is_array($tag)) { + $tag = $reader->notXPath($tag); + } + if (strncmp($tag, "format_", 7)) { + $retval = $format->transformFromMap($open, $tag, $name); + break; + } + $funcname = $tag; + } + + $retval = $format->{$funcname}($open, $name); + break; + + case XMLReader::TEXT: + $retval = htmlspecialchars($reader->value, ENT_QUOTES); + break; + + case XMLReader::CDATA: + $retval = $format->CDATA($reader->value); + break; + + case XMLReader::COMMENT: + case XMLReader::WHITESPACE: + case XMLReader::SIGNIFICANT_WHITESPACE: + case XMLReader::DOC_TYPE: + /* swallow it */ + continue 2; + + default: + trigger_error("Don't know how to handle {$name} {$type}", E_USER_ERROR); + return; + } + $format->appendData($retval, $reader->isChunk); +} + +copy("cache/manual.php", "cache/index.php"); +$reader->close(); + +if ($err) { + $end = microtime(true); + $notify + ->update( + "PhD build finished", + sprintf("mktoc build: <b>%d</b> sec\nPhD build : <b>%d</b> sec\n--\nTotal time: <b>%d</b> seconds\n", $mktoc-$start, $end-$mktoc, $end-$start)) + ->show(); } -$phd->close(); +/* +* vim600: sw=4 ts=4 fdm=syntax syntax=php et +* vim<600: sw=4 ts=4 +*/ -?> http://cvs.php.net/viewvc.cgi/phd/include/PhDReader.class.php?r1=1.6&r2=1.7&diff_format=u Index: phd/include/PhDReader.class.php diff -u phd/include/PhDReader.class.php:1.6 phd/include/PhDReader.class.php:1.7 --- phd/include/PhDReader.class.php:1.6 Sat Jul 28 23:58:06 2007 +++ phd/include/PhDReader.class.php Sun Aug 5 14:49:55 2007 @@ -1,165 +1,224 @@ <?php +/* $Id: PhDReader.class.php,v 1.7 2007/08/05 14:49:55 bjori Exp $ */ +//6271 -/* $Id: PhDReader.class.php,v 1.6 2007/07/28 23:58:06 gwynne Exp $ - +-------------------------------------------------------------------------+ - | Copyright(c) 2007 | - | Authors: | - | Gwynne Raskind <[EMAIL PROTECTED]> | - | Hannes Magnusson <[EMAIL PROTECTED]> | - | This source file is subject to the license that is bundled with this | - | package in the file LICENSE, and is available through the | - | world-wide-web at the following url: | - | http://phd.php.net/LICENSE | - +-------------------------------------------------------------------------+ - | The base class for reading the giant XML blob. This is intended for | - | extension by output formats, and then for further extension by output | - | themes. This class should not be instantiated directly. | - +-------------------------------------------------------------------------+ -*/ - -abstract class PhDReader extends XMLReader { - - protected $map = array(); - - public function __construct( $file, $encoding = "utf-8", $options = NULL ) { - - if ( !parent::open( $file, $encoding, $options ) ) { - throw new Exception(); - } - - } - - public function __destruct() { +class PhDReader extends XMLReader { + const XMLNS_XML = "http://www.w3.org/XML/1998/namespace"; + const XMLNS_XLINK = "http://www.w3.org/1999/xlink"; + const XMLNS_PHD = "http://www.php.net/ns/phd"; + const OPEN_CHUNK = 0x01; + const CLOSE_CHUNK = 0x02; + + private $STACK = array(); + private $LAST_DEPTH = -1; + private $lastChunkDepth = -1; + + public $isChunk = false; + + protected $CHUNK_ME = array( /* {{{ */ + 'article' => true, + 'appendix' => true, + 'bibliography' => array( + /* DEFAULT */ false, + 'article' => true, + 'book' => true, + 'part' => true, + ), + 'book' => true, + 'chapter' => true, + 'colophon' => true, + 'glossary' => array( + /* DEFAULT */ false, + 'article' => true, + 'book' => true, + 'part' => true, + ), + 'index' => array( + /* DEFAULT */ false, + 'article' => true, + 'book' => true, + 'part' => true, + ), + 'part' => true, + 'preface' => true, + 'refentry' => true, + 'reference' => true, + 'sect1' => 'isSectionChunk', + /* + 'sect2' => 'format_section_chunk', + 'sect3' => 'format_section_chunk', + 'sect4' => 'format_section_chunk', + 'sect5' => 'format_section_chunk', + */ + 'section' => 'isSectionChunk', + 'set' => true, + 'setindex' => true, + ); /* }}} */ + + public function __construct($file, $encoding = "UTF-8", $options = NULL) { + if (!XMLReader::open($file, $encoding, $options)) { + throw new Exception(); + } } - - /* Format subclasses must implement these to make them real formats. */ - abstract public function getFormatName(); - abstract protected function transformFromMap( $open, $name ); - - /* These are new functions, extending XMLReader. */ - - /* Seek to an ID within the file. */ - public function seek( $id ) { - - while( parent::read() ) { - if ( $this->nodeType == XMLREADER::ELEMENT && $this->hasAttributes && - $this->moveToAttributeNs( "id", "http://www.w3.org/XML/1998/namespace" ) && $this->value == $id ) { - return $this->moveToElement(); - } - } - return FALSE; - } - - /* Go to the next useful node in the file. */ - public function nextNode() { - - while( $this->read() ) { - switch( $this->nodeType ) { - - case XMLReader::ELEMENT: - if ( $this->isEmptyElement ) { - continue; - } - - case XMLReader::TEXT: - case XMLReader::CDATA: - case XMLReader::END_ELEMENT: - return TRUE; - } - } - return FALSE; - - } - - /* Read a node with the right name? */ - public function readNode( $nodeName ) { - - return $this->read() && !( $this->nodeType == XMLReader::END_ELEMENT && $this->name == $nodeName ); + public function notXPath($tag) { + $depth = $this->depth; + do { + if (isset($tag[$this->STACK[--$depth]])) { + $tag = $tag[$this->STACK[$depth]]; + } else { + $tag = $tag[0]; + } + } while (is_array($tag)); + return $tag; + } - } - - /* Get the content of a named node, or the current node. */ - public function readContent( $node = NULL ) { + /* Seek to an ID within the file. */ + public function seek($id) { + while(XMLReader::read()) { + if ($this->nodeType === XMLREADER::ELEMENT && $this->hasAttributes && XMLReader::moveToAttributeNs("id", self::XMLNS_XML) && $this->value === $id) { + return XMLReader::moveToElement(); + } + } + return false; + } - $retval = ""; - if ( !$node ) { - $node = $this->name; - } - if ( $this->readNode( $node ) ) { - $retval = $this->value; - $this->read(); // Jump over END_ELEMENT too - } - return $retval; + /* Get the ID of current node */ + public function getID() { + if ($this->hasAttributes && XMLReader::moveToAttributeNs("id", self::XMLNS_XML)) { + $id = $this->value; + XMLReader::moveToElement(); + return $id; + } + return ""; + } - } - + public function read() { + $this->isChunk = false; + if(XMLReader::read()) { + $type = $this->nodeType; + switch($type) { + case XMLReader::ELEMENT: + $name = $this->name; + $depth = $this->depth; + if ($this->LAST_DEPTH >= $depth) { + $this->PREVIOUS_SIBLING = $this->STACK[$depth]; + } + $this->STACK[$depth] = $name; + $isChunk = $this->isChunk($name); + if ($isChunk) { + $this->isChunk = PhDReader::OPEN_CHUNK; + $this->chunkDepths[] = $this->lastChunkDepth = $depth; + } + break; + + case XMLReader::END_ELEMENT: + $depth = $this->depth; + if ($this->lastChunkDepth == $depth) { + array_pop($this->chunkDepths); + $this->lastChunkDepth = end($this->chunkDepths); + $this->isChunk = PhDReader::CLOSE_CHUNK; + } + $this->LAST_DEPTH = $depth; + break; + } + return true; + } + return false; + } + /* Get the attribute value by name, if exists. */ - public function readAttribute( $attr ) { + public function readAttribute($attr) { + $retval = XMLReader::moveToAttribute($attr) ? $this->value : ""; + XMLReader::moveToElement(); + return $retval; + } + public function readAttributeNs($attr, $ns) { + $retval = XMLReader::moveToAttributeNs($attr, $ns) ? $this->value : ""; + XMLReader::moveToElement(); + return $retval; + } + /* Get all attributes of current node */ + public function getAttributes() { + if ($this->hasAttributes) { + $attrs = array(); + XMLReader::moveToFirstAttribute(); + do { + $attrs[$this->name] = $this->value; + } while (XMLReader::moveToNextAttribute()); + XMLReader::moveToElement(); + return $attrs; + } + return array(); + } - return $this->moveToAttribute( $attr ) ? $this->value : ""; - } + /* Get the content of a named node, or the current node. */ + public function readContent($node = null) { + $retval = ""; - /* Handle unmapped nodes. */ - public function __call( $func, $args ) { + if($this->isEmptyElement) { + return $retval; + } + if (!$node) { + $node = $this->name; + } + $retval = ""; + while (PhDReader::readNode($node)) { + $retval .= $this->value; + } + return $retval; + } + /* Read $nodeName until END_ELEMENT */ + public function readNode($nodeName) { + return XMLReader::read() && !($this->nodeType === XMLReader::END_ELEMENT && $this->name == $nodeName); + } - if ( $this->nodeType == XMLReader::END_ELEMENT ) { - /* ignore */ return; + + public function isChunk($tag) { + if (isset($this->CHUNK_ME[$tag])) { + $isChunk = $this->CHUNK_ME[$tag]; + if (is_array($isChunk)) { + $isChunk = $this->notXPath($isChunk); + } + if (!is_bool($isChunk)) { + return call_user_func(array($this, $isChunk), $tag); + } + return $isChunk; } - trigger_error( "No mapper for $func", E_USER_WARNING ); - - /* NOTE: - * The _content_ of the element will get processed even though we dont - * know how to handle the elment itself - */ - return ""; - + return false; } - - /* Perform a transformation. */ - public function transform() { - - $type = $this->nodeType; - $name = $this->name; - - switch( $type ) { - - case XMLReader::ELEMENT: - case XMLReader::END_ELEMENT: - if( isset( $this->map[ $name ] ) ) { - return $this->transformFromMap( $type == XMLReader::ELEMENT, $name ); - } - return call_user_func( array( $this, "format_${name}" ), $type == XMLReader::ELEMENT ); - break; - - case XMLReader::TEXT: - return $this->value; - break; - - case XMLReader::CDATA: - return $this->highlight_php_code( $this->value ); - break; - - case XMLReader::COMMENT: - case XMLReader::WHITESPACE: - case XMLReader::SIGNIFICANT_WHITESPACE: - /* swallow it */ - /* XXX This could lead to a recursion overflow if a lot of comment nodes get strung together. */ - $this->read(); - return $this->transform(); - - default: - trigger_error( "Dunno what to do with {$this->name} {$this->nodeType}", E_USER_ERROR ); - return ""; - } - + public function isSectionChunk($tag) { + if ($this->PREVIOUS_SIBLING == $tag && $this->checkSectionDepth()) { + return true; + } + return false; + } + protected function checkSectionDepth() { + static $allowedParents = array("section", "sect2", "sect3", "sect4", "sect5"); + static $chunkers = array( + "sect1", "preface", "chapter", "appendix", "article", "part", "reference", "refentry", + "index", "bibliography", "glossary", "colopone", "book", "set", "setindex", "legalnotice", + ); + + $nodeDepth = $this->depth; + $i = 1; + do { + if (in_array($this->STACK[$nodeDepth-$i], $allowedParents)) { + ++$i; + continue; + } + break; + } while(true); + if ($i <= 1 && in_array($this->STACK[$nodeDepth-$i], $chunkers)) { + return true; + } + return false; } - } /* * vim600: sw=4 ts=4 fdm=syntax syntax=php et * vim<600: sw=4 ts=4 */ -?> + http://cvs.php.net/viewvc.cgi/phd/formats/xhtml.php?r1=1.7&r2=1.8&diff_format=u Index: phd/formats/xhtml.php diff -u phd/formats/xhtml.php:1.7 phd/formats/xhtml.php:1.8 --- phd/formats/xhtml.php:1.7 Sat Jul 28 23:58:06 2007 +++ phd/formats/xhtml.php Sun Aug 5 14:49:55 2007 @@ -1,196 +1,382 @@ <?php +/* $Id: xhtml.php,v 1.8 2007/08/05 14:49:55 bjori Exp $ */ -/* $Id: xhtml.php,v 1.7 2007/07/28 23:58:06 gwynne Exp $ - +-------------------------------------------------------------------------+ - | Copyright(c) 2007 | - | Authors: | - | Gwynne Raskind <[EMAIL PROTECTED]> | - | Hannes Magnusson <[EMAIL PROTECTED]> | - | This source file is subject to the license that is bundled with this | - | package in the file LICENSE, and is available through the | - | world-wide-web at the following url: | - | http://phd.php.net/LICENSE | - +-------------------------------------------------------------------------+ - | The XHTML output format class. This should not be instantiated | - | directly; it is intended for extension by a theme class. | - | XXX This is temporarily untrue for "let's get it started" purposes. | - +-------------------------------------------------------------------------+ -*/ - -/* Grab the PhDReader parent class. */ -require_once 'include/PhDReader.class.php'; - -class PhDXHTMLReader extends PhDReader { +class XHTMLPhDFormat extends PhDFormat { + protected $map = array( /* {{{ */ + 'article' => 'format_container_chunk', + 'author' => 'div', + 'authorgroup' => 'div', /* DocBook-xsl prints out "by" (i.e. "PHP Manual by ...") */ + 'appendix' => 'format_container_chunk', + 'application' => 'span', + 'bibliography' => array( + /* DEFAULT */ 'div', + 'article' => 'format_chunk', + 'book' => 'format_chunk', + 'part' => 'format_chunk', + ), + 'book' => 'format_container_chunk', + 'chapter' => 'format_container_chunk', + 'colophon' => 'format_chunk', + 'firstname' => 'span', + 'surname' => 'span', + 'othername' => 'span', + 'honorific' => 'span', + 'glossary' => array( + /* DEFAULT */ 'div', + 'article' => 'format_chunk', + 'book' => 'format_chunk', + 'part' => 'format_chunk', + ), + 'classname' => 'span', + 'code' => 'code', + 'collab' => 'span', + 'collabname' => 'span', + 'command' => 'span', + 'computeroutput' => 'span', + 'constant' => 'span', + 'emphasis' => 'em', + 'enumname' => 'span', + 'entry' => array( + /* DEFAULT */ 'format_entry', + 'row' => array( + /* DEFAULT */ 'format_row_entry', + 'thead' => 'format_thead_entry', + 'tfoot' => 'format_tfoot_entry', + 'tbody' => 'format_tbody_entry', + ), + ), + 'envar' => 'span', + 'filename' => 'span', + 'glossterm' => 'span', + 'holder' => 'span', + 'index' => array( + /* DEFAULT */ 'div', + 'article' => 'format_chunk', + 'book' => 'format_chunk', + 'part' => 'format_chunk', + ), + 'info' => 'div', + 'informaltable' => 'table', + 'itemizedlist' => 'ul', + 'listitem' => array( + /* DEFAULT */ 'li', + 'varlistentry' => 'format_varlistentry_listitem', + ), + 'literal' => 'span', + 'mediaobject' => 'div', + 'methodparam' => 'span', + 'member' => 'li', + 'note' => 'div', + 'option' => 'span', + 'orderedlist' => 'ol', + 'para' => 'p', + 'parameter' => 'tt', + 'part' => 'format_container_chunk', + 'partintro' => 'div', + 'personname' => 'span', + 'preface' => 'format_chunk', + 'productname' => 'span', + 'propname' => 'span', + 'property' => 'span', + 'proptype' => 'span', + 'refentry' => 'format_chunk', + 'reference' => 'format_container_chunk', + 'sect1' => 'format_chunk', + 'sect2' => 'format_chunk', + 'sect3' => 'format_chunk', + 'sect4' => 'format_chunk', + 'sect5' => 'format_chunk', + 'section' => 'format_chunk', + 'set' => 'format_chunk', + 'setindex' => 'format_chunk', + 'simplelist' => 'ul', + 'simpara' => 'p', + 'systemitem' => 'format_systemitem', + 'table' => 'format_table', + 'term' => 'span', + 'title' => array( + /* DEFAULT */ 'h1', + 'legalnotice' => 'h4', + 'section' => 'h2', + 'sect1' => 'h2', + 'sect2' => 'h3', + 'sect3' => 'h4', + 'refsect1' => 'h3', + 'example' => 'h4', + 'note' => 'h4', + ), + 'type' => 'format_type', + 'userinput' => 'format_userinput', + 'variablelist' => 'format_variablelist', + 'varlistentry' => 'format_varlistentry', + 'varname' => 'var', + 'xref' => 'format_link', + 'year' => 'span', + ); /* }}} */ - protected $map = array( - 'application' => 'span', - 'classname' => 'span', - 'code' => 'code', - 'collab' => 'span', - 'collabname' => 'span', - 'command' => 'span', - 'computeroutput' => 'span', - 'constant' => 'span', - 'emphasis' => 'em', - 'enumname' => 'span', - 'envar' => 'span', - 'filename' => 'span', - 'glossterm' => 'span', - 'holder' => 'span', - 'informaltable' => 'table', - 'itemizedlist' => 'ul', - 'listitem' => 'li', - 'literal' => 'span', - 'mediaobject' => 'div', - 'methodparam' => 'span', - 'member' => 'li', - 'note' => 'div', - 'option' => 'span', - 'orderedlist' => 'ol', - 'para' => 'p', - 'parameter' => 'span', - 'productname' => 'span', - 'propname' => 'span', - 'property' => 'span', - 'proptype' => 'span', - 'simplelist' => 'ul', - 'simpara' => 'p', - 'title' => 'h1', - 'year' => 'span', - ); + protected $CURRENT_ID = ""; + protected $ext = "html"; - public function __construct( $file, $encoding = 'utf-8', $options = NULL ) { - parent::__construct( $file, $encoding, $options ); + public function __construct(PhDReader $reader, array $IDs, array $IDMap, $ext = "html") { + parent::__construct($reader, $IDs, $IDMap, $ext); } - - public function __destruct() { + /* Overwrite PhDFormat::readContent() to convert special HTML chars */ + public function readContent($content = null) { + return htmlspecialchars(PhDFormat::readContent($content), ENT_QUOTES, "UTF-8"); } - - public function getFormatName() { + public function __call($func, $args) { + if ($args[0]) { + trigger_error("No mapper found for '{$func}'", E_USER_WARNING); + return "<font color='red' size='+3'>{$args[1]}</font>"; + } + return "<font color='red' size='+3'>/{$args[1]}</font>"; + } + public function transformFromMap($open, $tag, $name) { + if ($open) { + return sprintf('<%s class="%s">', $tag, $name); + } + return "</$tag>"; + } + public function CDATA($str) { + return sprintf('<div class="phpcode">%s</div>', highlight_string($str, 1)); + } + + public function format_container_chunk($open, $name) { + $this->CURRENT_ID = $id = PhDFormat::getID(); + if ($open) { + return sprintf('<div id="%s" class="%s">', $id, $name); + } + return "</div>"; + } + public function format_chunk($open, $name) { + $this->CURRENT_ID = $id = PhDFormat::getID(); + if ($open) { + return sprintf('<div id="%s" class="%s">', $id, $name); + } + return "</div>"; + } + public function format_function($open, $name) { + return sprintf('<a href="function.%s.html">%1$s</a>', $this->readContent()); + } + public function format_refsect1($open, $name) { + if ($open) { + return sprintf('<div class="refsect %s">', PhDFormat::readAttribute("role")); + } + return "</div>\n"; + } + public function format_link($open, $name) { + $content = $fragment = ""; + $class = $name; + if($linkto = PhDFormat::readAttribute("linkend")) { + $id = $href = PhDFormat::getFilename($linkto); + if ($id != $linkto) { + $fragment = "#$linkto"; + } + $href .= ".".$this->ext; + } elseif($href = PhDFormat::readAttributeNs("href", PhDReader::XMLNS_XLINK)) { + $content = "» "; + $class .= " external"; + } + $content .= $name == "xref" ? PhDFormat::getDescription($id, false) : $this->readContent($name); + return sprintf('<a href="%s%s" class="%s">%s</a>', $href, $fragment, $class, $content); + } + public function format_methodsynopsis($open, $root) { + /* We read this element to END_ELEMENT so $open is useless */ + $content = '<div class="methodsynopsis">'; + + while($child = PhDFormat::getNextChild($root)) { + if ($child["type"] == XMLReader::END_ELEMENT) { + $content .= "</span>\n"; + continue; + } + $name = $child["name"]; + switch($name) { + case "type": + case "parameter": + case "methodname": + $content .= sprintf('<span class="%s">%s</span>', $name, $this->readContent($name)); + break; + + case "methodparam": + $content .= '<span class="methodparam">'; + break; + } + } + $content .= "</div>"; + return $content; + } + public function format_refnamediv($open, $root) { + while ($child = PhDFormat::getNextChild($root)) { + $name = $child["name"]; + switch($name) { + case "refname": + $refname = $this->readContent($name); + break; + case "refpurpose": + $refpurpose = $this->readContent($name); + break; + } + } - return 'XHTML 1.0 Transitional'; - + return sprintf('<div class="refnamediv"><span class="refname">%s</span><span class="refpurpose">%s</span></div>', $refname, $refpurpose); + } + public function format_variablelist($open, $name) { + if ($open) { + return "<dl>\n"; + } + return "</dl>\n"; + } + public function format_varlistentry($open, $name) { + if ($open) { + $id = PhDFormat::getID(); + if ($id) { + return sprintf('<dt id="%s">', $id); + } + return "<dt>\n"; + } + return "</dt>\n"; + } + public function format_varlistentry_listitem($open, $name) { + if ($open) { + return "<dd>\n"; + } + return "</dd>\n"; + } + public function format_userinput($open, $name) { + if ($open) { + return sprintf('<strong class="%s"><code>', $name); + } + return "</code></strong>\n"; + } + public function format_systemitem($open, $name) { + if ($open) { + switch($this->readAttribute("role")) { + case "directive": + /* FIXME: Different roles should probably be handled differently */ + default: + return sprintf('<code class="systemitem %s">', $name); + } + } + return "</code>\n"; + } + public function format_type($open, $name) { + $type = $this->readContent($name); + $t = strtolower($type); + $href = $fragment = ""; + + switch($t) { + case "bool": + $href = "language.types.boolean"; + break; + case "int": + $href = "language.types.integer"; + break; + case "double": + $href = "language.types.float"; + break; + case "boolean": + case "integer": + case "float": + case "string": + case "array": + case "object": + case "resource": + case "null": + $href = "language.types.$t"; + break; + case "mixed": + case "number": + case "callback": + $href = "language.pseudo-types"; + $fragment = "language.types.$t"; + break; + } + if ($href) { + return sprintf('<a href="%s.%s%s" class="%s %s">%5$s</a>', $href, $this->ext, ($fragment ? "#$fragment" : ""), $name, $type); + } + return sprintf('<span class="%s %s">%2$s</span>', $name, $type); } - - public function format_refentry( $open ) { - if ( $open ) { - return '<div>'; - } - - echo "</div>"; - if ( $this->hasAttributes && $this->moveToAttributeNs( "id", "http://www.w3.org/XML/1998/namespace" ) ) { - $id = $this->value; - } - $content = ob_get_contents(); - ob_clean(); - file_put_contents( "cache/$id.html", $content ); - - } - - public function format_function( $open ) { - - return sprintf( '<a href="function.%1$s.html">%1$s</a>', $this->readContent() ); - - } - - public function format_refsect1( $open ) { - - if ( $open ) { - return sprintf( '<div class="refsect %s">', $this->readAttribute( "role" ) ); - } - return "</div>\n"; - - } - - public function format_link( $open ) { - - $this->moveToNextAttribute(); - $href = $this->value; - $class = $this->name; - $content = $this->readContent( "link" ); - return sprintf( '<a href="%s" class="%s">%s</a>', $href, $class, $content ); - - } - - public function format_methodsynopsis( $open ) { - - /* We read this element to END_ELEMENT so $open is useless */ - $content = '<div class="methodsynopsis">'; - $root = $this->name; - - while( $this->readNode( $root ) ) { - if ( $this->nodeType == XMLReader::END_ELEMENT ) { - $content .= "</span>\n"; - continue; - } - $name = $this->name; - switch($name) { - case "type": - case "parameter": - case "methodname": - $content .= sprintf( '<span class="%s">%s</span>', $name, $this->readContent( $name ) ); - break; - - case "methodparam": - $content .= '<span class="methodparam">'; - break; - } - } - $content .= "</div>"; - return $content; - - } - - protected function transformFromMap( $open, $name ) { - - $tag = $this->map[ $name ]; - if($open) { - return sprintf( '<%s class="%s">', $tag, $name ); - } - return "</$tag>"; - - } - - public function format_listing_hyperlink_function( $matches ) { - - $link = str_replace( '_', '-', $matches[ 1 ] ); - $link = "function${link}.html"; - return '<a class="phpfunc" href="'.$link.'">'.$matches[ 1 ].'</a></span>'.$matches[ 2 ]; - - } - - public function highlight_php_code( $str ) { /* copy&paste from livedocs */ - - if ( is_array( $str ) ) { - $str = $str[ 0 ]; - } - - $tmp = str_replace( - array( - ' ', - '<font color="', // for PHP 4 - '<span style="color: ', // for PHP 5.0.0RC1 - '</font>', - "\n ", - ' ' - ), - array( - ' ', - '<span class="', - '<span class="', - '</span>', - "\n ", - ' ' - ), - highlight_string( $str, TRUE ) - ); - - $tmp = preg_replace_callback( '{([\w_]+)\s*</span>(\s*<span\s+class="keyword">\s*\()}m', - array( $this, 'format_listing_hyperlink_function' ), $tmp ); - return sprintf( '<div class="phpcode">%s</div>', $tmp ); - } + /* TODO: Move the logic to PhDFormat? */ + /* NOTE: This is not a full implementation, just a proof-of-concept */ + public function format_table($open, $name) { + if ($open) { + return '<table border="5">'; + } + return "</table>\n"; + } + public function format_tgroup($open, $name) { + if ($open) { + $this->TABLE_COLS = $this->readAttribute("cols"); + $this->COLSPEC = array(); + return "<colgroup>\n"; + } + return "</colgroup>\n"; + } + public function format_colspec($open, $name) { + if ($open) { + $colname = $this->readAttribute("colname"); + if ($colnum = $this->readAttribute("colnum")) { + $this->COLSPEC[$colnum] = $colname; + } else { + $count = count($this->COLSPEC); + $this->COLSPEC[$count] = $colname; + } + return "<col />"; // Probably throw in couple of width and align attributes + } + /* noop */ + } + public function format_thead($open, $name) { + if ($open) { + return "<thead>"; + } + return "</thread>\n"; + } + public function format_tbody($open, $name) { + if ($open) { + return "<tbody>"; + } + return "</tbody>"; + } + public function format_row($open, $name) { + if ($open) { + return "<tr>\n"; + } + return "</tr>\n"; + } + public function format_thead_entry($open, $name) { + if ($open) { + if ($start = $this->readAttribute("namest")) { + $from = array_search($start, $this->COLSPEC); + $end = $this->readAttribute("nameend"); + $to = array_search($end, $this->COLSPEC); + return sprintf('<th colspan="%d">', $end-$to); + } + return '<th>'; + } + return '</th>'; + } + public function format_tfoot_entry($open, $name) { + return $this->format_thead_entry($open, $name); + } + public function format_tbody_entry($open, $name) { + if ($open) { + $colspan = 1; + $rows = 1; + if ($start = $this->readAttribute("namest")) { + $from = array_search($start, $this->COLSPEC); + $end = $this->readAttribute("nameend"); + $to = array_search($end, $this->COLSPEC); + $colspan = $to-$from+1; + } + if ($morerows = $this->readAttribute("morerows")) { + $rows += $morerows; + } + return sprintf('<td colspan="%d" rowspan="%d">', $colspan, $rows); + } + return "</td>"; + } } @@ -198,4 +384,4 @@ * vim600: sw=4 ts=4 fdm=syntax syntax=php et * vim<600: sw=4 ts=4 */ -?> + http://cvs.php.net/viewvc.cgi/phd/mktoc.php?view=markup&rev=1.1 Index: phd/mktoc.php +++ phd/mktoc.php <?php /* $Id: mktoc.php,v 1.1 2007/08/05 14:49:55 bjori Exp $ */ $r = new PhDReader("/home/bjori/php/doc/.manual.xml"); $FILENAMES = $IDs = $IDMap = array(); $CURRENT_FILENAME = $LAST_CHUNK = ""; $PARENTS = array(-1 => ""); $lastid = 0; /* someone really needs to fix this messed up logic */ while($r->read()) { if (!($id = $r->getID())) { $name = $r->name; if (in_array($name, array("refname", "titleabbrev")) && empty($IDs[$lastid]["sdesc"])) { switch($name) { case "refname": $IDs[$lastid]["sdesc"] = trim($r->readContent($name)); continue 2; case "titleabbrev": $IDs[$lastid]["sdesc"] = trim($r->readContent($name)); continue 2; } } else if (in_array($name, array("title", "refpurpose")) && empty($IDs[$lastid]["ldesc"])) { switch($name) { case "title": $IDs[$lastid]["ldesc"] = trim($r->readContent($name)); continue 2; case "refpurpose": $IDs[$lastid]["ldesc"] = trim($r->readContent($name)); continue 2; } } continue; } switch($r->isChunk) { case PhDReader::OPEN_CHUNK: $FILENAMES[] = $id; $CURRENT_FILENAME = $id; $PARENTS[$r->depth] = $id; $IDMap[$id] = array("parent" => $PARENTS[$r->depth-1]); break; case PhDReader::CLOSE_CHUNK: $LAST_CHUNK = array_pop($FILENAMES); $CURRENT_FILENAME = end($FILENAMES); $IDMap[$CURRENT_FILENAME][$id] =& $IDMap[$LAST_CHUNK]; continue 2; } if ($r->nodeType != XMLReader::ELEMENT) { continue; } $IDs[$id] = array("filename" => $CURRENT_FILENAME, "sdesc" => null, "ldesc" => null); $lastid = $id; } #print_r($IDs); #var_dump($IDs["funcref"]); /* foreach($IDMap[$IDMap["function.strpos"]["parent"]] as $id => $junk) { if ($id == "parent") { continue; } printf("%s (%s): %s\n", $id, $IDs[$id]["sdesc"], $IDs[$id]["ldesc"]); } */ /* * vim600: sw=4 ts=4 fdm=syntax syntax=php et * vim<600: sw=4 ts=4 */ http://cvs.php.net/viewvc.cgi/phd/include/PhDFormat.class.php?view=markup&rev=1.1 Index: phd/include/PhDFormat.class.php +++ phd/include/PhDFormat.class.php <?php /* $Id: PhDFormat.class.php,v 1.1 2007/08/05 14:49:55 bjori Exp $ */ abstract class PhDFormat { private $reader; private $IDs = array(); private $IDMap = array(); protected $ext = ""; /* abstract */ protected $map = array(); public function __construct(PhDReader $reader, array $IDs, array $IDMap, $ext) { $this->reader = $reader; $this->IDs = $IDs; $this->IDMap = $IDMap; $this->ext = $ext; } final public function getFilename($id) { return isset($this->IDs[$id]) ? $this->IDs[$id]["filename"] : false; } final public function getDescription($id, $long = false) { return $long ? ($this->IDs[$id]["ldesc"] ? $this->IDs[$id]["ldesc"] : $this->IDs[$id]["sdesc"]) : ($this->IDs[$id]["sdesc"] ? $this->IDs[$id]["sdesc"] : $this->IDs[$id]["ldesc"]); } final public function getContainer($id) { return $this->IDMap[$id]; } final public function getParent($id) { return $this->IDMap[$id]["parent"]; } final public function getMap() { return $this->map; } /* PhDReader wrapper functions */ public function getID() { return $this->reader->getID(); } public function readContent($node = null) { return $this->reader->readContent($node); } public function readAttribute($attr) { return $this->reader->readAttribute($attr); } public function readAttributeNs($attr, $ns) { return $this->reader->readAttributeNs($attr, $ns); } public function getAttributes() { return $this->reader->getAttributes(); } public function getNextChild($node) { return $this->reader->readNode($node) ? array("type" => $this->reader->nodeType, "name" => $this->reader->name) : false; } /* abstract functions */ abstract public function transformFromMap($open, $tag, $name); abstract public function CDATA($data); abstract public function __call($func, $args); } /* * vim600: sw=4 ts=4 fdm=syntax syntax=php et * vim<600: sw=4 ts=4 */ http://cvs.php.net/viewvc.cgi/phd/formats/php.php?view=markup&rev=1.1 Index: phd/formats/php.php +++ phd/formats/php.php <?php /* $Id: php.php,v 1.1 2007/08/05 14:49:55 bjori Exp $ */ class PHPPhDFormat extends XHTMLPhDFormat { protected $CURRENT_ID = ""; protected $ext; public function __construct(PhDReader $reader, array $IDs, array $IDMap, $ext = "php") { parent::__construct($reader, $IDs, $IDMap, $ext); } public function format_function($open, $name) { $func = $this->readContent($name); $link = str_replace(array("_", "::", "->"), "-", $func); if (!substr_compare($this->CURRENT_ID, $link, -strlen($link)) || !($filename = PhDFormat::getFilename("function.$link"))) { return sprintf("<b>%s()</b>", $func); } return sprintf('<a href="%s.%s" class="function">%s()</a>', $filename, $this->ext, $func); } public function format_container_chunk($open, $name) { $this->CURRENT_ID = $id = PhDFormat::getID(); if ($open) { return "<div>"; } $chunks = PhDFormat::getContainer($id); $content = ""; if (count($chunks) > 1) { $content = '<ul class="chunklist chunklist_'.$name.'">'; if ($name == "reference") { foreach($chunks as $chunkid => $junk) { if ($chunkid == "parent") { continue; } $content .= sprintf('<li><a href="%s.%s">%s</a> â %s</li>', $chunkid, $this->ext, PhDFormat::getDescription($chunkid, false), PhDFormat::getDescription($chunkid, true)); } } else { foreach($chunks as $chunkid => $junk) { if ($chunkid == "parent") { continue; } $content .= sprintf('<li><a href="%s.%s">%s</a></li>', $chunkid, $this->ext, PhDFormat::getDescription($chunkid, true)); } } $content .= "</ul>\n"; } $content .= "</div>\n"; return $content; } } /* * vim600: sw=4 ts=4 fdm=syntax syntax=php et * vim<600: sw=4 ts=4 */ http://cvs.php.net/viewvc.cgi/phd/themes/phpweb.php?view=markup&rev=1.1 Index: phd/themes/phpweb.php +++ phd/themes/phpweb.php <?php /* $Id: phpweb.php,v 1.1 2007/08/05 14:49:55 bjori Exp $ */ class phpweb extends PHPPhDFormat { protected $streams = array(); protected $writeit = false; protected $CURRENT_ID = ""; public function writeChunk($id, $stream) { rewind($stream); file_put_contents("cache/$id.php", $this->header($id)); file_put_contents("cache/$id.php", $stream, FILE_APPEND); file_put_contents("cache/$id.php", $this->footer($id), FILE_APPEND); } public function appendData($data, $isChunk) { switch($isChunk) { case PhDReader::CLOSE_CHUNK: $id = $this->CURRENT_ID; $stream = array_pop($this->streams); $retval = fwrite($stream, $data); $this->writeChunk($id, $stream); fclose($stream); return $retval; break; case PhDReader::OPEN_CHUNK: $this->streams[] = fopen("php://temp/maxmemory", "r+"); default: $stream = end($this->streams); $retval = fwrite($stream, $data); return $retval; } } public function header($id) { $toc = ""; $parent = PhDFormat::getParent($id); foreach(PhDFormat::getContainer($parent) as $k => $v) { if ($k == "parent") { continue; } $toc .= sprintf("array('%s.php', '%s'),\n", $k, addslashes(PhDFormat::getDescription($k, false))); } /* Yes. This is scary. I know. */ return '<?php include_once $_SERVER[\'DOCUMENT_ROOT\'] . \'/include/shared-manual.inc\'; manual_setup( array( "home" => array("index.php", "PHP Manual"), "head" => array("UTF-8", "en"), "this" => array("'.$id.'.php", "'.addslashes(PhDFormat::getDescription($id)).'"), "prev" => array("function.previous.php", "prevous"), "next" => array("function.next.php", "next"), "up" => array("'.$this->getFilename($parent).'.'.$this->ext.'", "'.addslashes(PhDFormat::getDescription($parent, true)). '"), "toc" => array('.$toc.'), ) ); manual_header(); ?> '; } public function footer($id) { return "<?php manual_footer(); ?>"; } } /* * vim600: sw=4 ts=4 fdm=syntax syntax=php et * vim<600: sw=4 ts=4 */