\n"; - /** phpdoc.inc */ - include("phpDocumentor/phpdoc.inc"); - echo "\n"; - echo "
- Help - | -- use this to find directories and files which can be used below - - -printMenu(); -?> - | -
- Joshua Eichorn jeichorn@phpdoc.org
- Juan Pablo Morales ju-moral@uniandes.edu.co
- Gregory Beaver cellog@users.sourceforge.net
-
- If you have any problems with phpDocumentor, please visit the website: phpdocu.sourceforge.net and - submit a bug -
- - --Last modified: $Date: 2005/10/17 18:15:16 $ -Revision: $Revision: 1.1 $ -- - - - - + + + * @author Joshua Eichorn
+ * array( + * parent => array( + * parentfile => array( + * child => childfile + * ) + * ) + * )+ * @var array + */ + var $definitechild; + /** + * array of parsed classes organized by the name of the file that contains + * the class. + * + * Format:
+ * array( + * filename => array( + * classname => {@link parserClass} + * ) + * )+ * @var array + */ + var $classesbyfile = array(); + /** + * array of file names organized by classes that are in the file. + * + * This structure is designed to handle name conflicts. Two files can + * contain classes with the same name, and this array will record both + * filenames to help control linking and inheritance errors + * + * Format:
+ * array( + * classname => array( + * name of file containing classname, + * name of file 2 containing classname, + * ... + * ) + * )+ * @var array + */ + var $classesbynamefile = array(); + /** + * array of parsed methods organized by the file that contains them. + * + * Format:
+ * array( + * filename => array( + * classname => array( + * {@link parserMethod} 1, + * {@link parserMethod} 2, + * ... + * ) + * ) + * )+ * @var array + */ + var $methodsbyfile = array(); + /** + * array of parsed vars organized by the file that contains them. + * + * Format:
+ * array( + * filename => array( + * classname => array( + * {@link parserVar} 1, + * {@link parserVar} 2, + * ... + * ) + * ) + * )+ * @var array + */ + var $varsbyfile = array(); + /** + * array of parsed class constants organized by the file that contains them. + * + * Format:
+ * array( + * filename => array( + * classname => array( + * {@link parserConst} 1, + * {@link parserConst} 2, + * ... + * ) + * ) + * )+ * @var array + */ + var $constsbyfile = array(); + /** + * keeps track of extend declarations by file, used to find inheritance + * + * Format:
+ * array( + * filename => array( + * classname => parentclassname + * ) + * )+ * @var array + */ + var $extendsbyfile = array(); + /** + * Keeps track of child classes by file. + * Since phpDocumentor can document collections of files that contain name + * conflicts (PHP would give a fatal error), it + * is impossible to assume a class that declares "extends foo" necessarily + * extends the class foo in file X. It could be an + * extended class of class foo in file Y. Because of this, phpDocumentor + * relies on packaging to resolve the name conflict + * This array keeps track of the packages of a child class + * + * Format:
+ * array( + * parentclassname => array( + * filename => array( + * childclassname => array( + * packagename, + * packagename + * ) + * ) + * ) + * )+ * @var array + */ + var $classchildrenbyfile = array(); + /** + * Keeps track of class packages found in a file. + * This is used in {@link getParentClass()} to determine the number of + * packages in a file, in order to resolve inheritance issues + * Format:
+ * array( + * filename => array( + * packagename1, + * packagename2, + * ... + * ) + * )+ * @var array + */ + var $classpackagebyfile = array(); + /** + * a tree of class inheritance by name. + * + * Format:
+ * array( + * childname => parentname, + * childname1 => parentname1, + * rootname => 0, + * ... + * )+ * @var array + * @see Converter::generateSortedClassTreeFromClass() + */ + var $classparents = array(); + /** + * Keeps track of package and subpackage for each class name, organized + * by package + * + * Format:
+ * array( + * classname => array( + * path => array( + * package, + * subpackage + * ), + * path2 => array( + * package, + * subpackage + * ), + * ... + * ) + * )+ * @var array + */ + var $classpathpackages = array(); + /** + * used to delete duplicates in the same package to avoid documentation errors + * + * Specifically used in {@link Converter::checkKillClass()} + */ + var $killclass = array(); + /** + * array of methods by package and class + * + * format:
+ * array(packagename => + * array(classname => + * array(methodname1 => {@link parserMethod} class, + * methodname2 => {@link parserMethod} class,...) + * ) + * ) + * )+ * @var array + * @see Converter + */ + var $methods = array(); + + /** + * array of class variables by package and class + * + * format:
+ * array(packagename => + * array(classname => + * array(variablename1 => {@link parserVar} class, + * variablename2 => {@link parserVar} class,... + * ) + * ) + * )+ * @var array + * @see Converter + */ + var $vars = array(); + + /** + * array of class variables by package and class + * + * format:
+ * array(packagename => + * array(classname => + * array(constname1 => {@link parserConst} class, + * constname2 => {@link parserConst} class,... + * ) + * ) + * )+ * @var array + * @see Converter + */ + var $consts = array(); + /** + * Reverse class_packages_by_file, used to prevent duplicates + * @var array Format: array(packagename => 1) + */ + var $revcpbf = array(); + /** + * All classes with no parents (no extends clause) are tracked in this array + * by the file that contains them. + * + * Format:
+ * array( + * classname => array( + * name of file1 that contains root classname, + * name of file2 that contains root classname, + * ... + * ) + * )+ * @var array + */ + var $roots = array(); + /** + * All classes with a parent that was not parsed are included in this array + * + * Format:
+ * array( + * classname => array( + * name of file1 that contains root classname, + * name of file2 that contains root classname, + * ... + * ) + * )+ * @var array + */ + var $specialRoots = array(); + + /** + * array of all files that contain classes with the same name + * @var array Format: (classname => array(path1, path2,...)) + */ + var $potentialclassconflicts = array(); + + /** + * array of all inter-package name conflicts of classes + * + * This array allows documentation of PHP namespace conflicts that would + * occur should a user try to include these files in the same file + * @var array Format: (classname => array(path1, path2,...)) + */ + var $classconflicts = array(); + /**#@-*/ + /** + * While parsing, add a class to the list of parsed classes + * + * sets up the {@link $classesbyfile, $classesbynamefile, $extendsbyfile}, + * {@link $classchildrenbyfile, $roots} arrays, and sets {@link $curclass} + * + * @param parserClass &$element element is a {@link parserClass} + * + * @return void + * @uses addPackageToFile() marks the current class's package as being + * present in a file + */ + function addClass(&$element) + { + $this->curclass = $element->getName(); + $element->curfile = $this->curfile; + if (isset($this->classesbyfile[$this->curfile][$this->curclass])) { + addWarning(PDERROR_ELEMENT_IGNORED, + 'class', $this->curclass, $this->curfile); + $this->curclass = false; + return; + } + $this-> + classesbyfile + [$this->curfile][$this->curclass] + = $element; + $this-> + classesbynamefile[$this->curclass][] + = $this->curfile; + $this-> + extendsbyfile[$this->curfile][$this->curclass] + = $element->getExtends(); + $this-> + classchildrenbyfile[$element->getExtends()] + [$this->curfile][$this->curclass][] + = $element->docblock->package; + if ($element->docblock->getExplicitPackage()) + $this->addPackageToFile($element->docblock->package); + if (!$element->getExtends()) { + $this->roots[$this->curclass][] = $this->curfile; + } + } + + /** + * While parsing, add a method to the list of parsed methods + * + * sets up the {@link $methodsbyfile} array using {@link $curfile} and + * {@link $curclass} + * + * @param parserMethod &$element element is a {@link parserMethod} + * + * @return void + */ + function addMethod(&$element) + { + if (!$this->curclass) return; + $this->methodsbyfile[$this->curfile][$this->curclass][] = $element; + } + + /** + * While parsing, add a variable to the list of parsed variables + * + * sets up the {@link $varsbyfile} array using {@link $curfile} + * and {@link $curclass} + * + * @param parserVar &$element element is a {@link parserVar} + * + * @return void + */ + function addVar(&$element) + { + if (!$this->curclass) return; + $this->varsbyfile[$this->curfile][$this->curclass][] = $element; + } + + /** + * While parsing, add a variable to the list of parsed variables + * + * sets up the {@link $constsbyfile} array using {@link $curfile} + * and {@link $curclass} + * + * @param parserConst &$element element is a {@link parserConst} + * + * @return void + */ + function addConst(&$element) + { + if (!$this->curclass) return; + $this->constsbyfile[$this->curfile][$this->curclass][] = $element; + } + + /** + * Prepare to parse a new file + * + * sets {@link $curfile} to $file and {@link $curclass} + * to false (no class being parsed) + * + * @param string $file file currently being parsed + * + * @return void + */ + function nextFile($file) + { + $this->curfile = $file; + $this->curclass = false; + } + + /** + * Mark a package as being used in a class + * + * {@source} + * + * @param string $package package name + * + * @return void + */ + function addPackageToFile($package) + { + if (!isset($this->revcpbf[$this->curfile][$package])) + $this->classpackagebyfile[$this->curfile][] = $package; + $this->revcpbf[$this->curfile][$package] = 1; + } + + /** + * Find the parent class of $class, and set up structures to note this fact + * + * Modifies the {@link parserClass} element in {@link $classesbyfile} to use + * the parent's package, and inherit methods/vars + * + * @param string $class child class to find parent class + * @param string $file file child class is located in + * + * @return void + * @uses $definitechild if a match is made between a parent class and parameter + * $class in file $file, then definitechild is set here + * @uses getParentClass() to find the parent class + */ + function setClassParent($class,$file) + { + if (is_array($par = $this->getParentClass($class, $file))) { + // (for debugging) + // phpDocumentor_out("$file class $class extends " + // . $par[1] ." file ". $par[0] . "\n"); + + $this->classesbyfile[$file][$class]->setParent($par[1], $par[0], $this); + $this->definitechild[$par[1]][$par[0]][$class] = $file; + } else { + $this->classesbyfile[$file][$class]->setParentNoClass($par); + } + } + + /** + * Main processing engine for setting up class inheritance. + * + * This function uses {@link $roots} to traverse the inheritance tree via + * {@link processChild()} and returns the data structures + * phpDocumentor_IntermediateParser needs to convert parsed data + * to output using {@link phpDocumentor_IntermediateParser::Convert()} + * + * @param phpDocumentor_IntermediateParser &$render the renderer object + * + * @return void + * @uses processChild() set up inheritance + * @todo CS Cleanup - rename to "inherit" for CamelCaps naming standard + */ + function Inherit(&$render) + { + phpDocumentor_out("\nProcessing Class Inheritance\n\n"); + flush(); + phpDocumentor_out("\nProcessing Root Trees\n\n"); + flush(); + foreach ($this->roots as $class => $files) { + for ($i=0; $i
Parsing => Intermediate Parsing organization => Conversion to output+ * + * A Converter takes output from the {@link phpDocumentor_IntermediateParser} and + * converts it to output. With version 1.2, phpDocumentor includes a variety + * of output converters: + *
+ * array(package => + * array(subpackage => + * array(path => + * array(class => + * array({@link abstractLink} descendant 1, ... + * ) + * ) + * ) + * )+ * @see formatLeftIndex() + */ + var $class_contents = array(); + /** + * controls processing of elements marked private with @access private + * + * defaults to false. Set with command-line --parseprivate or -pp + * @var bool + */ + var $parseprivate; + /** + * controls display of progress information while parsing. + * + * defaults to false. Set to true for cron jobs or other situations where no visual output is necessary + * @var bool + */ + var $quietmode; + + /** + * directory that output is sent to. -t command-line sets this. + * @tutorial phpDocumentor.howto.pkg#using.command-line.target + */ + var $targetDir = ''; + + /** + * Directory that the template is in, relative to phpDocumentor root directory + * @var string + */ + var $templateDir = ''; + + /** + * Directory that the smarty templates are in + * @var string + */ + var $smarty_dir = ''; + + /** + * Name of the template, from last part of -o + * @tutorial phpDocumentor.howto.pkg#using.command-line.output + * @var string + */ + var $templateName = ''; + + /** + * full path of the current file being converted + */ + var $curfile; + + /** + * All class information, organized by path, and by package + * @var Classes + */ + var $classes; + + /** + * Flag used to help converters determine whether to do special source highlighting + * @var boolean + */ + var $highlightingSource = false; + + /** + * Hierarchy of packages + * + * Every package that contains classes may have parent or child classes + * in other packages. In other words, this code is legal: + * + *
+ * /**
+ * * @package one
+ * * /
+ * class one {}
+ *
+ * /**
+ * * @package two
+ * * /
+ * class two extends one {}
+ *
+ *
+ * In this case, package one is a parent of package two
+ * @var array
+ * @see phpDocumentor_IntermediateParser::$package_parents
+ */
+ var $package_parents;
+
+ /**
+ * Packages associated with categories
+ *
+ * Used by the XML:DocBook/peardoc2 converter, and available to others, to
+ * group many packages into categories
+ * @see phpDocumentor_IntermediateParser::$packagecategories
+ * @var array
+ */
+ var $packagecategories;
+
+ /**
+ * All packages encountered in parsing
+ * @var array
+ * @see phpDocumentor_IntermediateParser::$all_packages
+ */
+ var $all_packages;
+
+ /**
+ * A list of files that have had source code generated
+ * @var array
+ */
+ var $sourcePaths = array();
+
+ /**
+ * Controls which of the one-element-only indexes are generated.
+ *
+ * Generation of these indexes for large packages is time-consuming. This is an optimization feature. An
+ * example of how to use this is in {@link HTMLframesConverter::$leftindex}, and in {@link HTMLframesConverter::formatLeftIndex()}.
+ * These indexes are intended for use as navigational aids through documentation, but can be used for anything by converters.
+ * @see $class_elements, $page_elements, $function_elements, $define_elements, $global_elements
+ * @see formatLeftIndex()
+ * @var array
+ */
+ var $leftindex = array('classes' => true, 'pages' => true, 'functions' => true, 'defines' => true, 'globals' => true);
+
+ /** @access private */
+ var $killclass = false;
+ /**
+ * @var string
+ * @see phpDocumentor_IntermediateParser::$title
+ */
+ var $title = 'Generated Documentation';
+
+ /**
+ * Options for each template, parsed from the options.ini file in the template base directory
+ * @tutorial phpDocumentor/tutorials.pkg#conversion.ppage
+ * @var array
+ */
+ var $template_options;
+
+ /**
+ * Tutorials and Extended Documentation parsed from a tutorials/package[/subpackage] directory
+ * @tutorial tutorials.pkg
+ * @access private
+ */
+ var $tutorials = array();
+
+ /**
+ * tree-format structure of tutorials and their child tutorials, if any
+ * @var array
+ * @access private
+ */
+ var $tutorial_tree = false;
+
+ /**
+ * list of tutorials that have already been processed. Used by @link _setupTutorialTree()
+ * @var array
+ * @access private
+ */
+ var $processed_tutorials;
+
+ /**
+ * List of all @todo tags and a link to the element with the @todo
+ *
+ * Format: array(package => array(link to element, array(todo {@link parserTag},...)),...)
+ * @tutorial tags.todo.pkg
+ * @var array
+ */
+ var $todoList = array();
+
+ /**
+ * Directory where compiled templates go - will be deleted on exit
+ *
+ * @var string
+ * @access private
+ */
+ var $_compiledDir = array();
+
+ /**
+ * Initialize Converter data structures
+ * @param array {@link $all_packages} value
+ * @param array {@link $package_parents} value
+ * @param Classes {@link $classes} value
+ * @param ProceduralPages {@link $proceduralpages} value
+ * @param array {@link $package_output} value
+ * @param boolean {@link $parseprivate} value
+ * @param boolean {@link $quietmode} value
+ * @param string {@link $targetDir} value
+ * @param string {@link $templateDir} value
+ * @param string (@link $title} value
+ */
+ function Converter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $template, $title)
+ {
+ $this->all_packages = $allp;
+ $this->package_parents = $packp;
+ $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
+ $this->proceduralpages = &$procpages;
+ $this->package_output = $po;
+ if (is_array($po))
+ {
+ $a = $po[0];
+ $this->all_packages = array_flip($po);
+ $this->all_packages[$a] = 1;
+ }
+ $this->parseprivate = $pp;
+ $this->quietmode = $qm;
+ $this->classes = &$classes;
+ $this->roots = $classes->getRoots($this->processSpecialRoots);
+ $this->title = $title;
+ $this->setTemplateDir($template);
+ $this->setTargetdir($targetDir);
+ }
+
+ /**
+ * Called by IntermediateParser after creation
+ * @access private
+ */
+ function setTutorials($tutorials)
+ {
+ $this->tutorials = $tutorials;
+ }
+
+ /**
+ * @param pkg|cls|proc the tutorial type to search for
+ * @param tutorial name
+ * @param string package name
+ * @param string subpackage name, if any
+ * @return false|parserTutorial if the tutorial exists, return it
+ */
+ function hasTutorial($type, $name, $package, $subpackage = '')
+ {
+ if (isset($this->tutorials[$package][$subpackage][$type][$name . '.' . $type]))
+ return $this->tutorials[$package][$subpackage][$type][$name . '.' . $type];
+ return false;
+ }
+
+ /**
+ * Called by {@link walk()} while converting, when the last class element
+ * has been parsed.
+ *
+ * A Converter can use this method in any way it pleases. HTMLframesConverter
+ * uses it to complete the template for the class and to output its
+ * documentation
+ * @see HTMLframesConverter::endClass()
+ * @abstract
+ */
+ function endClass()
+ {
+ }
+
+ /**
+ * Called by {@link walk()} while converting, when the last procedural page
+ * element has been parsed.
+ *
+ * A Converter can use this method in any way it pleases. HTMLframesConverter
+ * uses it to complete the template for the procedural page and to output its
+ * documentation
+ * @see HTMLframesConverter::endClass()
+ * @abstract
+ */
+ function endPage()
+ {
+ }
+
+ /**
+ * Called by {@link walk()} while converting.
+ *
+ * This method is intended to be the place that {@link $pkg_elements} is
+ * formatted for output.
+ * @see HTMLframesConverter::formatPkgIndex()
+ * @abstract
+ */
+ function formatPkgIndex()
+ {
+ }
+
+ /**
+ * Called by {@link walk()} while converting.
+ *
+ * This method is intended to be the place that {@link $elements} is
+ * formatted for output.
+ * @see HTMLframesConverter::formatIndex()
+ * @abstract
+ */
+ function formatIndex()
+ {
+ }
+
+ /**
+ * Called by {@link walk()} while converting.
+ *
+ * This method is intended to be the place that any of
+ * {@link $class_elements, $function_elements, $page_elements},
+ * {@link $define_elements}, and {@link $global_elements} is formatted for
+ * output, depending on the value of {@link $leftindex}
+ * @see HTMLframesConverter::formatLeftIndex()
+ * @abstract
+ */
+ function formatLeftIndex()
+ {
+ }
+
+ /**
+ * Called by {@link parserSourceInlineTag::stringConvert()} to allow
+ * converters to format the source code the way they'd like.
+ *
+ * default returns it unchanged (html with xhtml tags)
+ * @param string output from highlight_string() - use this function to
+ * reformat the returned data for Converter-specific output
+ * @return string
+ * @deprecated in favor of tokenizer-based highlighting. This will be
+ * removed for 2.0
+ */
+ function unmangle($sourcecode)
+ {
+ return $sourcecode;
+ }
+
+ /**
+ * Initialize highlight caching
+ */
+ function startHighlight()
+ {
+ $this->_highlightCache = array(false, false);
+ $this->_appendHighlight = '';
+ }
+
+ function getHighlightState()
+ {
+ return $this->_highlightCache;
+ }
+
+ function _setHighlightCache($type, $token)
+ {
+ $test = ($this->_highlightCache[0] === $type && $this->_highlightCache[1] == $token);
+ if (!$test) {
+ $this->_appendHighlight = $this->flushHighlightCache();
+ } else {
+ $this->_appendHighlight = '';
+ }
+ $this->_highlightCache = array($type, $token);
+ return $test;
+ }
+
+ /**
+ * Return the close text for the current token
+ * @return string
+ */
+ function flushHighlightCache()
+ {
+ $hc = $this->_highlightCache;
+ $this->_highlightCache = array(false, false);
+ if ($hc[0]) {
+ if (!isset($this->template_options[$hc[0]]['/'.$hc[1]])) {
+ return '';
+ }
+ return $this->template_options[$hc[0]]['/'.$hc[1]];
+ }
+ return '';
+ }
+
+ /**
+ * Used to allow converters to format the source code the way they'd like.
+ *
+ * default returns it unchanged. Mainly used by the {@link HighlightParser}
+ * {@internal
+ * The method takes information from options.ini, the template options
+ * file, specifically the [highlightSourceTokens] and [highlightSource]
+ * sections, and uses them to enclose tokens.
+ *
+ * {@source}}}
+ * @param integer token value from {@link PHP_MANUAL#tokenizer tokenizer constants}
+ * @param string contents of token
+ * @param boolean whether the contents are preformatted or need modification
+ * @return string
+ */
+ function highlightSource($token, $word, $preformatted = false)
+ {
+ if ($token !== false)
+ {
+ if (!$preformatted) $word = $this->postProcess($word);
+ if (isset($this->template_options['highlightSourceTokens'][token_name($token)]))
+ {
+ if ($this->_setHighlightCache('highlightSourceTokens', token_name($token))) {
+ return $word;
+ }
+ $e = $this->_appendHighlight;
+ return $e . $this->template_options['highlightSourceTokens'][token_name($token)] . $word;
+ } else
+ {
+ $this->_setHighlightCache(false, false);
+ $e = $this->_appendHighlight;
+ return $e . $word;
+ }
+ } else
+ {
+ if (isset($this->template_options['highlightSource'][$word]))
+ {
+ $newword = ($preformatted ? $word : $this->postProcess($word));
+ if ($this->_setHighlightCache('highlightSource', $word)) {
+ return $newword;
+ }
+ $e = $this->_appendHighlight;
+ return $e . $this->template_options['highlightSource'][$word] . $newword;
+ } else
+ {
+ $this->_setHighlightCache(false, false);
+ $e = $this->_appendHighlight;
+ return $e . ($preformatted ? $word : $this->postProcess($word));
+ }
+ }
+ }
+
+ /**
+ * Used to allow converters to format the source code of DocBlocks the way
+ * they'd like.
+ *
+ * default returns it unchanged. Mainly used by the {@link HighlightParser}
+ * {@internal
+ * The method takes information from options.ini, the template options
+ * file, specifically the [highlightDocBlockSourceTokens] section, and uses
+ * it to enclose tokens.
+ *
+ * {@source}}}
+ * @param string name of docblock token type
+ * @param string contents of token
+ * @param boolean whether the contents are preformatted or need modification
+ * @return string
+ */
+ function highlightDocBlockSource($token, $word, $preformatted = false)
+ {
+ if (empty($word)) {
+ $this->_setHighlightCache(false, false);
+ $e = $this->_appendHighlight;
+ return $e . $word;
+ }
+ if (isset($this->template_options['highlightDocBlockSourceTokens'][$token]))
+ {
+ if (!$preformatted) $word = $this->postProcess($word);
+ if ($this->_setHighlightCache('highlightDocBlockSourceTokens', $token)) {
+ return $word;
+ }
+ $e = $this->_appendHighlight;
+ return $e . $this->template_options['highlightDocBlockSourceTokens'][$token] . $word;
+ } else {
+ $this->_setHighlightCache(false, false);
+ $e = $this->_appendHighlight;
+ return $e . ($preformatted ? $word : $this->postProcess($word));
+ }
+ }
+
+ /**
+ * Used to allow converters to format the source code of Tutorial XML the way
+ * they'd like.
+ *
+ * default returns it unchanged. Mainly used by the {@link HighlightParser}
+ * {@internal
+ * The method takes information from options.ini, the template options
+ * file, specifically the [highlightDocBlockSourceTokens] section, and uses
+ * it to enclose tokens.
+ *
+ * {@source}}}
+ * @param string name of docblock token type
+ * @param string contents of token
+ * @param boolean whether the contents are preformatted or need modification
+ * @return string
+ */
+ function highlightTutorialSource($token, $word, $preformatted = false)
+ {
+ if (empty($word)) {
+ $this->_setHighlightCache(false, false);
+ $e = $this->_appendHighlight;
+ return $e . $word;
+ }
+ if (isset($this->template_options['highlightTutorialSourceTokens'][$token]))
+ {
+ if (!$preformatted) $word = $this->postProcess($word);
+ if ($this->_setHighlightCache('highlightTutorialSourceTokens', $token)) {
+ return $word;
+ }
+ $e = $this->_appendHighlight;
+ return $e . $this->template_options['highlightTutorialSourceTokens'][$token] . $word;
+ } else {
+ $this->_setHighlightCache(false, false);
+ $e = $this->_appendHighlight;
+ return $e . ($preformatted ? $word : $this->postProcess($word));
+ }
+ }
+
+ /**
+ * Called by {@link parserReturnTag::Convert()} to allow converters to
+ * change type names to desired formatting
+ *
+ * Used by {@link XMLDocBookConverter::type_adjust()} to change true and
+ * false to the peardoc2 values
+ * @param string
+ * @return string
+ */
+ function type_adjust($typename)
+ {
+ return $typename;
+ }
+
+ /**
+ * Used to convert the {@}example} inline tag in a docblock.
+ *
+ * By default, this just wraps ProgramExample
+ * @see XMLDocBookpeardoc2Converter::exampleProgramExample
+ * @param string
+ * @param boolean true if this is to highlight a tutorial > tag in a docblock
+ * @param string
+ * @param boolean true if this is to highlight a tutorial
+ * @return string
+ */
+ function ProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/,
+ $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/)
+ {
+ $this->highlightingSource = true;
+ if (tokenizer_ext)
+ {
+ $e = $example;
+ if (!is_array($example))
+ {
+ $obj = new phpDocumentorTWordParser;
+ $obj->setup($example);
+ $e = $obj->getFileSource();
+ $bOpenTagFound = false;
+ foreach ($e as $ke => $ee)
+ {
+ foreach ($ee as $kee => $eee)
+ {
+ if ((int) $e[$ke][$kee][0] == T_OPEN_TAG)
+ {
+ $bOpenTagFound = true;
+ }
+ }
+ }
+ if (!$bOpenTagFound) {
+ $example = "setup($example);
+ $e = $obj->getFileSource();
+ unset($e[0]);
+ $e = array_values($e);
+ }
+ unset($obj);
+ }
+ $saveclass = $this->class;
+ $parser = new phpDocumentor_HighlightParser;
+ if (!isset($inlinesourceparse))
+ {
+ $example = $parser->parse($e, $this, true); // force php mode
+ } else
+ {
+ if (isset($filesourcepath))
+ {
+ $example = $parser->parse($e, $this, $inlinesourceparse, $class, $linenum, $filesourcepath);
+ } elseif (isset($linenum))
+ {
+ $example = $parser->parse($e, $this, $inlinesourceparse, $class, $linenum);
+ } elseif (isset($class))
+ {
+ $example = $parser->parse($e, $this, $inlinesourceparse, $class);
+ } else
+ {
+ $example = $parser->parse($e, $this, $inlinesourceparse);
+ }
+ }
+ $this->class = $saveclass;
+ } else
+ {
+ $example = $this->postProcess($example);
+ }
+ $this->highlightingSource = false;
+
+ if ($tutorial)
+ {
+ return $example;
+ }
+
+ if (!isset($this->template_options['desctranslate'])) return $example;
+ if (!isset($this->template_options['desctranslate']['code'])) return $example;
+ $example = $this->template_options['desctranslate']['code'] . $example;
+ if (!isset($this->template_options['desctranslate']['/code'])) return $example;
+ return $example . $this->template_options['desctranslate']['/code'];
+ }
+
+ /**
+ * @param string
+ */
+ function TutorialExample($example)
+ {
+ $this->highlightingSource = true;
+ $parse = new phpDocumentor_TutorialHighlightParser;
+ $x = $parse->parse($example, $this);
+ $this->highlightingSource = false;
+ return $x;
+ }
+
+ /**
+ * Used to convert the contents of <> in a docblock
+ * @param string
+ * @return string
+ */
+ function ListItem($item)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $item;
+ if (!isset($this->template_options['desctranslate']['li'])) return $item;
+ $item = $this->template_options['desctranslate']['li'] . $item;
+ if (!isset($this->template_options['desctranslate']['/li'])) return $item;
+ return $item . $this->template_options['desctranslate']['/li'];
+ }
+
+ /**
+ * Used to convert the contents of <> or <> in a docblock
+ * @param string
+ * @return string
+ */
+ function EncloseList($list,$ordered)
+ {
+ $listname = ($ordered ? 'ol' : 'ul');
+ if (!isset($this->template_options['desctranslate'])) return $list;
+ if (!isset($this->template_options['desctranslate'][$listname])) return $list;
+ $list = $this->template_options['desctranslate'][$listname] . $list;
+ if (!isset($this->template_options['desctranslate']['/'.$listname])) return $list;
+ return $list . $this->template_options['desctranslate']['/'.$listname];
+ }
+
+ /**
+ * Used to convert the contents of <
> in a docblock
+ * @param string
+ * @return string
+ */
+ function PreserveWhiteSpace($string)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $string;
+ if (!isset($this->template_options['desctranslate']['pre'])) return $string;
+ $string = $this->template_options['desctranslate']['pre'] . $string;
+ if (!isset($this->template_options['desctranslate']['/pre'])) return $string;
+ return $string . $this->template_options['desctranslate']['/pre'];
+ }
+
+ /**
+ * Used to enclose a paragraph in a docblock
+ * @param string
+ * @return string
+ */
+ function EncloseParagraph($para)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $para;
+ if (!isset($this->template_options['desctranslate']['p'])) return $para;
+ $para = $this->template_options['desctranslate']['p'] . $para;
+ if (!isset($this->template_options['desctranslate']['/p'])) return $para;
+ return $para . $this->template_options['desctranslate']['/p'];
+ }
+
+ /**
+ * Used to convert the contents of <> in a docblock
+ * @param string
+ * @return string
+ */
+ function Bolden($para)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $para;
+ if (!isset($this->template_options['desctranslate']['b'])) return $para;
+ $para = $this->template_options['desctranslate']['b'] . $para;
+ if (!isset($this->template_options['desctranslate']['/b'])) return $para;
+ return $para . $this->template_options['desctranslate']['/b'];
+ }
+
+ /**
+ * Used to convert the contents of <> in a docblock
+ * @param string
+ * @return string
+ */
+ function Italicize($para)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $para;
+ if (!isset($this->template_options['desctranslate']['i'])) return $para;
+ $para = $this->template_options['desctranslate']['i'] . $para;
+ if (!isset($this->template_options['desctranslate']['/i'])) return $para;
+ return $para . $this->template_options['desctranslate']['/i'];
+ }
+
+ /**
+ * Used to convert the contents of <> in a docblock
+ * @param string
+ * @return string
+ */
+ function Varize($para)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $para;
+ if (!isset($this->template_options['desctranslate']['var'])) return $para;
+ $para = $this->template_options['desctranslate']['var'] . $para;
+ if (!isset($this->template_options['desctranslate']['/var'])) return $para;
+ return $para . $this->template_options['desctranslate']['/var'];
+ }
+
+ /**
+ * Used to convert the contents of <> in a docblock
+ * @param string
+ * @return string
+ */
+ function Kbdize($para)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $para;
+ if (!isset($this->template_options['desctranslate']['kbd'])) return $para;
+ $para = $this->template_options['desctranslate']['kbd'] . $para;
+ if (!isset($this->template_options['desctranslate']['/kbd'])) return $para;
+ return $para . $this->template_options['desctranslate']['/kbd'];
+ }
+
+ /**
+ * Used to convert the contents of <> in a docblock
+ * @param string
+ * @return string
+ */
+ function Sampize($para)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $para;
+ if (!isset($this->template_options['desctranslate']['samp'])) return $para;
+ $para = $this->template_options['desctranslate']['samp'] . $para;
+ if (!isset($this->template_options['desctranslate']['/samp'])) return $para;
+ return $para . $this->template_options['desctranslate']['/samp'];
+ }
+
+ /**
+ * Used to convert <
> in a docblock
+ * @param string
+ * @return string
+ */
+ function Br($para)
+ {
+ if (!isset($this->template_options['desctranslate'])) return $para;
+ if (!isset($this->template_options['desctranslate']['br'])) return $para;
+ $para = $this->template_options['desctranslate']['br'] . $para;
+ return $para;
+ }
+
+ /**
+ * This version does nothing
+ *
+ * Perform necessary post-processing of string data. For example, the HTML
+ * Converters should escape < and > to become < and >
+ * @return string
+ */
+ function postProcess($text)
+ {
+ return $text;
+ }
+
+ /**
+ * Creates a table of contents for a {@}toc} inline tag in a tutorial
+ *
+ * This function should return a formatted table of contents. By default, it
+ * does nothing, it is up to the converter to format the TOC
+ * @abstract
+ * @return string table of contents formatted for use in the current output format
+ * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...)
+ */
+ function formatTutorialTOC($toc)
+ {
+ return '';
+ }
+
+ /**
+ * Write out the formatted source code for a php file
+ *
+ * This function provides the primary functionality for the
+ * {@tutorial tags.filesource.pkg} tag.
+ * @param string full path to the file
+ * @param string fully highlighted/linked source code of the file
+ * @abstract
+ */
+ function writeSource($filepath, $source)
+ {
+ debug($source);
+ return;
+ }
+
+ /**
+ * Write out the formatted source code for an example php file
+ *
+ * This function provides the primary functionality for the
+ * {@tutorial tags.example.pkg} tag.
+ * @param string example title
+ * @param string example filename (no path)
+ * @param string fully highlighted/linked source code of the file
+ * @abstract
+ */
+ function writeExample($title, $path, $source)
+ {
+ return;
+ }
+
+ /** Translate the path info into a unique file name for the highlighted
+ * source code.
+ * @param string $pathinfo
+ * @return string
+ */
+ function getFileSourceName($path)
+ {
+ global $_phpDocumentor_options;
+ $pathinfo = $this->proceduralpages->getPathInfo($path, $this);
+ $pathinfo['source_loc'] = str_replace($_phpDocumentor_options['Program_Root'].'/','',$pathinfo['source_loc']);
+ $pathinfo['source_loc'] = str_replace('/','_',$pathinfo['source_loc']);
+ return "fsource_{$pathinfo['package']}_{$pathinfo['subpackage']}_{$pathinfo['source_loc']}";
+ }
+
+ /** Return the fixed path to the source-code file folder.
+ * @param string $base Path is relative to this folder
+ * @return string
+ */
+ function getFileSourcePath($base)
+ {
+ if (substr($base, strlen($base) - 1) != PATH_DELIMITER) {
+ $base .= PATH_DELIMITER;
+ }
+ return $base . '__filesource';
+ }
+
+ /** Return the path to the current
+ * @param string $pathinfo
+ * @return string
+ */
+ function getCurrentPageURL()
+ {
+ return '{$srcdir}' . PATH_DELIMITER . $this->page_dir;
+ }
+
+ /**
+ * @return string an output-format dependent link to phpxref-style highlighted
+ * source code
+ * @abstract
+ */
+ function getSourceLink($path)
+ {
+ return '';
+ }
+
+ /**
+ * @return string Link to the current page being parsed.
+ * Should return {@link $curname} and a converter-specific extension.
+ * @abstract
+ */
+ function getCurrentPageLink()
+ {
+ }
+
+ /**
+ * Return a line of highlighted source code with formatted line number
+ *
+ * If the $path is a full path, then an anchor to the line number will be
+ * added as well
+ * @param integer line number
+ * @param string highlighted source code line
+ * @param false|string full path to @filesource file this line is a part of,
+ * if this is a single line from a complete file.
+ * @return string formatted source code line with line number
+ */
+ function sourceLine($linenumber, $line, $path = false)
+ {
+ if ($path)
+ {
+ return $this->getSourceAnchor($path, $linenumber) .
+ $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
+ } else
+ {
+ return $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
+ }
+ }
+
+ /**
+ * Determine whether an element's file has generated source code, used for
+ * linking to line numbers of source.
+ *
+ * Wrapper for {@link $sourcePaths} in this version
+ *
+ * {@internal since file paths get stored with most/all slashes
+ * set to forward slash '/', we need to doublecheck that
+ * we're not given a backslashed path to search for...
+ * if we are, it's likely that it was originally stored
+ * with a forward slash. Further, I'm not convinced it's safe
+ * to just check the {@link PHPDOCUMENTOR_WINDOWS} flag, so I'm checking
+ * specifically for backslashes intead.}}
+ *
+ * @param string full path to the source code file
+ * @return boolean
+ */
+ function hasSourceCode($path)
+ {
+ return isset($this->sourcePaths[$path]);
+ if (strpos($path, '\\') > -1) {
+ $modifiedPath = str_replace('\\', '/', $path);
+ return isset($this->sourcePaths[$modifiedPath]);
+ } else {
+ return isset($this->sourcePaths[$path]);
+ }
+ }
+
+ /**
+ * Mark a file as having had source code highlighted
+ * @param string full path of source file
+ */
+ function setSourcePaths($path)
+ {
+ $this->sourcePaths[$path] = true;
+ }
+
+ /**
+ * Used to translate an XML DocBook entity like ” from a tutorial by
+ * reading the options.ini file for the template.
+ * @param string entity name
+ */
+ function TranslateEntity($name)
+ {
+ if (!isset($this->template_options['ppage']))
+ {
+ if (!$this->template_options['preservedocbooktags'])
+ return '';
+ else
+ return '&'.$name.';';
+ }
+ if (isset($this->template_options['ppage']['&'.$name.';']))
+ {
+ return $this->template_options['ppage']['&'.$name.';'];
+ } else
+ {
+ if (!$this->template_options['preservedocbooktags'])
+ return '';
+ else
+ return '&'.$name.';';
+ }
+ }
+
+ /**
+ * Used to translate an XML DocBook tag from a tutorial by reading the
+ * options.ini file for the template.
+ * @param string tag name
+ * @param string any attributes Format: array(name => value)
+ * @param string the tag contents, if any
+ * @param string the tag contents, if any, unpost-processed
+ * @return string
+ */
+ function TranslateTag($name,$attr,$cdata,$unconvertedcdata)
+ {
+ if (!isset($this->template_options['ppage']))
+ {
+ if (!$this->template_options['preservedocbooktags'])
+ return $cdata;
+ else
+ return '<'.$name.$this->AttrToString($name,$attr,true).'>'.$cdata.''.$name.'>'."\n";
+ }
+ // make sure this template transforms the tag into something
+ if (isset($this->template_options['ppage'][$name]))
+ {
+ // test for global attribute transforms like $attr$role = class, changing
+ // all role="*" attributes to class="*" in html, for example
+ foreach($attr as $att => $val)
+ {
+ if (isset($this->template_options['$attr$'.$att]))
+ {
+ $new = '';
+ if (!isset($this->template_options['$attr$'.$att]['close']))
+ {
+ $new .= '<'.$this->template_options['$attr$'.$att]['open'];
+ if (isset($this->template_options['$attr$'.$att]['cdata!']))
+ {
+ if (isset($this->template_options['$attr$'.$att]['separateall']))
+ $new .= $this->template_options['$attr$'.$att]['separator'];
+ else
+ $new .= ' ';
+ $new .= $this->template_options['$attr$'.$att]['$'.$att];
+ $new .= $this->template_options['$attr$'.$att]['separator'];
+ if ($this->template_options['$attr$'.$att]['quotevalues']) $val = '"'.$val.'"';
+ $new .= $val.'>';
+ } else
+ {
+ $new .= '>'.$val;
+ }
+ $new .= ''.$this->template_options['$attr$'.$att]['open'].'>';
+ } else
+ {
+ $new .= $this->template_options['$attr$'.$att]['open'] . $val . $this->template_options['$attr$'.$att]['close'];
+ }
+ unset($attr[$att]);
+ $cdata = $new . $cdata;
+ }
+ }
+
+ if (!isset($this->template_options['ppage']['/'.$name]))
+ {// if the close tag isn't specified, we put opening and closing tags around it, with translated attributes
+ if (isset($this->template_options['ppage'][$name.'/']))
+ $cdata = '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'/>' . $cdata;
+ else
+ $cdata = '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'>' . $cdata .
+ ''.$this->template_options['ppage'][$name].'>';
+ } else
+ { // if close tag is specified, use the open and close as literal
+ if ($name == 'programlisting' && isset($attr['role']) &&
+ ($attr['role'] == 'php' || $attr['role'] == 'tutorial' || $attr['role'] == 'html'))
+ { // highlight PHP source
+// var_dump($unconvertedcdata, $cdata);exit;
+ if ($attr['role'] == 'php') {
+ $cdata = $this->ProgramExample($unconvertedcdata, true);
+ } elseif ($attr['role'] == 'tutorial') {
+ $cdata = $this->TutorialExample($unconvertedcdata);
+ } elseif ($attr['role'] == 'html') {
+ $cdata = $unconvertedcdata;
+ }
+ } else
+ {// normal case below
+ $cdata = $this->template_options['ppage'][$name].$this->AttrToString($name,$attr). $cdata .$this->template_options['ppage']['/'.$name];
+ }
+ }
+ return $cdata;
+ } else
+ {
+ if ($this->template_options['preservedocbooktags'])
+ {
+ return '<'.$name.$this->AttrToString($name,$attr,true).'>' . $cdata .
+ ''.$name.'>'."\n";
+ } else
+ {
+ return $cdata;
+ }
+ }
+ }
+
+ /**
+ * Convert the attribute of a Tutorial docbook tag's attribute list
+ * to a string based on the template options.ini
+ * @param string tag name
+ * @param attribute array
+ * @param boolean if true, returns attrname="value"...
+ * @return string
+ */
+ function AttrToString($tag,$attr,$unmodified = false)
+ {
+ $ret = '';
+ if ($unmodified)
+ {
+ $ret = ' ';
+ foreach($attr as $n => $v)
+ {
+ $ret .= $n.' = "'.$v.'"';
+ }
+ return $ret;
+ }
+ // no_attr tells us to ignore all attributes
+ if (isset($this->template_options['no_attr'])) return $ret;
+ // tagname! tells us to ignore all attributes for this tag
+ if (isset($this->template_options['ppage'][$tag.'!'])) return $ret;
+ if (count($attr)) $ret = ' ';
+ // pass 1, check to see if any attributes add together
+ $same = array();
+ foreach($attr as $n => $v)
+ {
+ if (isset($this->template_options['ppage'][$tag.'->'.$n]))
+ {
+ $same[$this->template_options['ppage'][$tag.'->'.$n]][] = $n;
+ }
+ }
+ foreach($attr as $n => $v)
+ {
+ if (isset($this->template_options['ppage'][$tag.'->'.$n]))
+ {
+ if (count($same[$this->template_options['ppage'][$tag.'->'.$n]]) == 1)
+ { // only 1 attribute translated for this one
+ // this is useful for equivalent value names
+ if (isset($this->template_options['ppage'][$tag.'->'.$n.'+'.$v])) $v = $this->template_options['ppage'][$tag.'->'.$n.'+'.$v];
+ } else
+ { // more than 1 attribute combines to make the new attribute
+ $teststrtemp = array();
+ foreach($same[$this->template_options['ppage'][$tag.'->'.$n]] as $oldattr)
+ {
+ $teststrtemp[] = $oldattr.'+'.$attr[$oldattr];
+ }
+ $teststrs = array();
+ $num = count($same[$this->template_options['ppage'][$tag.'->'.$n]]);
+ for($i=0;$i<$num;$i++)
+ {
+ $started = false;
+ $a = '';
+ for($j=$i;!$started || $j != $i;$j = ($j + $i) % $num)
+ {
+ if (!empty($a)) $a .= '|';
+ $a .= $teststrtemp[$j];
+ }
+ $teststrs[$i] = $a;
+ }
+ $done = false;
+ foreach($teststrs as $test)
+ {
+ if ($done) break;
+ if (isset($this->template_options['ppage'][$tag.'->'.$test]))
+ {
+ $done = true;
+ $v = $this->template_options['ppage'][$tag.'->'.$test];
+ }
+ }
+ }
+ $ret .= $this->template_options['ppage'][$tag.'->'.$n].' = "'.$v.'"';
+ } else
+ {
+ if (!isset($this->template_options['ppage'][$tag.'!'.$n]))
+ {
+ if (isset($this->template_options['ppage']['$attr$'.$n]))
+ $ret .= $this->template_options['ppage']['$attr$'.$n].' = "'.$v.'"';
+ else
+ $ret .= $n.' = "'.$v.'"';
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Convert the title of a Tutorial docbook tag section
+ * to a string based on the template options.ini
+ * @param string tag name
+ * @param array
+ * @param string title text
+ * @param string
+ * @return string
+ */
+ function ConvertTitle($tag,$attr,$title,$cdata)
+ {
+ if (!isset($this->template_options[$tag.'_title'])) return array($attr,$cdata);
+ if (isset($this->template_options[$tag.'_title']['tag_attr']))
+ {
+ $attr[$this->template_options[$tag.'_title']['tag_attr']] = urlencode($cdata);
+ $cdata = '';
+ } elseif(isset($this->template_options[$tag.'_title']['cdata_start']))
+ {
+ $cdata = $this->template_options[$tag.'_title']['open'] . $title .
+ $this->template_options[$tag.'_title']['close'] . $cdata;
+ } else $cdata = $title.$cdata;
+ return array($attr,$cdata);
+ }
+
+ /**
+ * Return a converter-specific id to distinguish tutorials and their
+ * sections
+ *
+ * Used by {@}id}
+ * @return string
+ */
+ function getTutorialId($package,$subpackage,$tutorial,$id)
+ {
+ return $package.$subpackage.$tutorial.$id;
+ }
+
+ /**
+ * Create the {@link $elements, $pkg_elements} and {@link $links} arrays
+ * @access private
+ * @todo version 2.0 - faulty package_output logic should be removed
+ *
+ * in this version, if the parent file isn't in the package, all
+ * the procedural elements are simply shunted to another package!
+ */
+ function _createPkgElements(&$pages)
+ {
+ if (empty($this->elements))
+ {
+ $this->elements = array();
+ $this->pkg_elements = array();
+ $this->links = array();
+ phpDocumentor_out('Building indexes...');
+ flush();
+ foreach($pages as $j => $flub)
+ {
+ $this->package = $pages[$j]->parent->package;
+ $this->subpackage = $pages[$j]->parent->subpackage;
+ $this->class = false;
+ $this->curfile = $pages[$j]->parent->getFile();
+ $this->curname = $this->getPageName($pages[$j]->parent);
+ $this->curpath = $pages[$j]->parent->getPath();
+ $use = true;
+ if ($this->package_output)
+ {
+ if (in_array($this->package,$this->package_output))
+ {
+ $this->addElement($pages[$j]->parent,$pages[$j]);
+ } else
+ {
+ if (count($pages[$j]->classelements))
+ {
+ list(,$pages[$j]->parent->package) = each($this->package_output);
+ reset($this->package_output);
+ $pages[$j]->parent->subpackage = '';
+ $this->addElement($pages[$j]->parent,$pages[$j]);
+ } else
+ {
+ unset($pages[$j]);
+ continue;
+ }
+ }
+ } else
+ {
+ $this->addElement($pages[$j]->parent,$pages[$j]);
+ }
+ if ($use)
+ for($i=0; $ielements); $i++)
+ {
+ $pages[$j]->elements[$i]->docblock->package = $this->package;
+ $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage;
+ $this->proceduralpages->replaceElement($pages[$j]->elements[$i]);
+ $this->addElement($pages[$j]->elements[$i]);
+ }
+ for($i=0; $iclasselements); $i++)
+ {
+ if ($this->class)
+ {
+ if ($pages[$j]->classelements[$i]->type == 'class')
+ {
+ if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
+ $this->package = $pages[$j]->classelements[$i]->docblock->package;
+ if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
+ $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
+ $this->class = $pages[$j]->classelements[$i]->name;
+ } else
+ {
+ if ($this->killclass) continue;
+ // force all contained elements to have parent package/subpackage
+ $pages[$j]->classelements[$i]->docblock->package = $this->package;
+ $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage;
+ }
+ }
+ if ($pages[$j]->classelements[$i]->type == 'class')
+ {
+ if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
+ $this->package = $pages[$j]->classelements[$i]->docblock->package;
+ if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
+ $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
+ $this->class = $pages[$j]->classelements[$i]->name;
+ }
+ if (!$this->killclass) $this->addElement($pages[$j]->classelements[$i]);
+ }
+ }
+ phpDocumentor_out("done\n");
+ flush();
+ }
+ $this->sortIndexes();
+ $this->sortTodos();
+ if ($this->sort_page_contents_by_type) $this->sortPageContentsByElementType($pages);
+ }
+
+ /**
+ * Process the {@link $tutorials} array
+ *
+ * Using the tutorialname.ext.ini files, this method sets up tutorial
+ * hierarchy. There is some minimal error checking to make sure that no
+ * tutorial links to itself, even two levels deep as in tute->next->tute.
+ *
+ * If all tests pass, it creates the hierarchy
+ * @uses generateTutorialOrder()
+ * @uses _setupTutorialTree()
+ * @access private
+ */
+ function _processTutorials()
+ {
+ $parents = $all = array();
+ foreach($this->tutorials as $package => $els)
+ {
+ if ($this->package_output)
+ {
+ if (!in_array($package,$this->package_output))
+ {
+ unset($this->tutorials[$package]);
+ continue;
+ }
+ }
+ if (!isset($this->pkg_elements[$package]))
+ {
+ unset($this->tutorials[$package]);
+ continue;
+ }
+ foreach($els as $subpackage => $els2)
+ {
+ foreach($els2 as $type => $tutorials)
+ {
+ foreach($tutorials as $tutorial)
+ {
+ if ($tutorial->ini)
+ {
+ if (isset($tutorial->ini['Linked Tutorials']))
+ {
+ foreach($tutorial->ini['Linked Tutorials'] as $child)
+ {
+ $sub = (empty($tutorial->subpackage) ? '' : $tutorial->subpackage . '/');
+ $kid = $tutorial->package . '/' . $sub . $child . '.' . $tutorial->tutorial_type;
+ // parent includes self as a linked tutorial?
+ $kidlink = $this->getTutorialLink($kid,false,false,array($tutorial->package));
+ if (is_object($kidlink) && $this->returnSee($kidlink) == $tutorial->getLink($this))
+ { // bad!
+ addErrorDie(PDERROR_TUTORIAL_IS_OWN_CHILD,$tutorial->name,$tutorial->name.'.ini');
+ }
+ }
+ $parents[] = $tutorial;
+ }
+ }
+ $all[$package][$subpackage][$type][] = $tutorial;
+ }
+ }
+ }
+ }
+ // loop error-checking, use this to eliminate possibility of accidentally linking to a parent as a child
+ $testlinks = array();
+ foreach($parents as $parent)
+ {
+ $testlinks[$parent->name]['links'][] = $parent->getLink($this);
+ $testlinks[$parent->name]['name'][$parent->getLink($this)] = $parent->name;
+ }
+ // generate the order of tutorials, and link them together
+ foreach($parents as $parent)
+ {
+ foreach($parent->ini['Linked Tutorials'] as $child)
+ {
+ $sub = (empty($parent->subpackage) ? '' : $parent->subpackage . '/');
+ $kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type;
+ // child tutorials must be in the same package AND subpackage
+ // AND have the same extension as the parent, makes things clearer for both ends
+ if (in_array($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))),$testlinks[$parent->name]['links']))
+ addErrorDie(PDERROR_TUTORIAL_IS_OWN_GRANDPA,$testlinks[$parent->name][$this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package)))],$kid->name,$testlinks[$parent->name][$this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package)))],$kid->name.'.ini');
+ if ($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))) == $kid)
+ {
+ addWarning(PDERROR_CHILD_TUTORIAL_NOT_FOUND, $child . '.' . $parent->tutorial_type, $parent->name .'.ini',$parent->package, $parent->subpackage);
+ }
+ }
+ }
+ $new = $tree = $roots = array();
+ // build a list of all 'root' tutorials (tutorials without parents).
+ foreach($parents as $i => $parent)
+ {
+ if (! $parent->isChildOf($parents)) {
+ $roots[] = $parent;
+ }
+ }
+ $parents = $roots;
+ // add the parents and all child tutorials in order to the list of tutorials to process
+ foreach($parents as $parent)
+ {
+ $this->generateTutorialOrder($parent,$all,$new);
+ }
+ if (count($all))
+ {
+ // add the leftover tutorials
+ foreach($all as $package => $els)
+ {
+ foreach($els as $subpackage => $els2)
+ {
+ foreach($els2 as $type => $tutorials)
+ {
+ foreach($tutorials as $tutorial)
+ {
+ $new[$package][$subpackage][$type][] = $tutorial;
+ }
+ }
+ }
+ }
+ }
+ // remove the old, unprocessed tutorials, and set it up with the next code
+ $this->tutorials = array();
+ // reset integrity of the tutorial list
+ $prev = false;
+ uksort($new, 'tutorialcmp');
+// debug($this->vardump_tree($new));exit;
+ foreach($new as $package => $els)
+ {
+ foreach($els as $subpackage => $els2)
+ {
+ foreach($els2 as $type => $tutorials)
+ {
+ foreach($tutorials as $tutorial)
+ {
+ if ($prev)
+ {
+ $this->tutorials[$prevpackage][$prevsubpackage][$prevtype][$prevname]->setNext($tutorial,$this);
+ $tutorial->setPrev($prev,$this);
+ }
+ $this->tutorials[$package][$subpackage][$type][$tutorial->name] = $tutorial;
+ $prev = $tutorial->getLink($this,true);
+ $prevpackage = $package;
+ $prevsubpackage = $subpackage;
+ $prevtype = $type;
+ $prevname = $tutorial->name;
+ }
+ }
+ }
+ }
+ $this->tutorial_tree = $this->_setupTutorialTree();
+ return $new;
+ }
+
+ /**
+ * called by {@link phpDocumentor_IntermediateParser::Convert()} to traverse
+ * the array of pages and their elements, converting them to the output format
+ *
+ * The walk() method should be flexible enough such that it never needs
+ * modification. walk() sets up all of the indexes, and sorts everything in
+ * logical alphabetical order. It then passes each element individually to
+ * {@link Convert()}, which then passes to the Convert*() methods. A child
+ * Converter need not override any of these unless special functionality must
+ * be added. see {@tutorial Converters/template.vars.cls} for details.
+ * {@internal
+ * walk() first creates all of the indexes {@link $elements, $pkg_elements}
+ * and the left indexes specified by {@link $leftindexes},
+ * and then sorts them by calling {@link sortIndexes()}.
+ *
+ * Next, it converts all README/CHANGELOG/INSTALL-style files, using
+ * {@link Convert_RIC}.
+ *
+ * After this, it
+ * passes all package-level docs to Convert(). Then, it calls the index
+ * sorting functions {@link formatPkgIndex(), formatIndex()} and
+ * {@link formatLeftIndex()}.
+ *
+ * Finally, it converts each procedural page in alphabetical order. This
+ * stage passes elements from the physical file to Convert() in alphabetical
+ * order. First, procedural page elements {@link parserDefine, parserInclude}
+ * {@link parserGlobal}, and {@link parserFunction} are passed to Convert().
+ *
+ * Then, class elements are passed in this order: {@link parserClass}, then
+ * all of the {@link parserVar}s in the class and all of the
+ * {@link parserMethod}s in the class. Classes are in alphabetical order,
+ * and both vars and methods are in alphabetical order.
+ *
+ * Finally, {@link ConvertErrorLog()} is called and the data walk is complete.}}
+ * @param array Format: array(fullpath => {@link parserData} structure with full {@link parserData::$elements}
+ * and {@link parserData::$class_elements}.
+ * @param array Format: array({@link parserPackagePage} 1, {@link parserPackagePage} 2,...)
+ * @uses Converter::_createPkgElements() sets up {@link $elements} and
+ * {@link $pkg_elements} array, as well as {@link $links}
+ */
+ function walk(&$pages,&$package_pages)
+ {
+ if (empty($pages))
+ {
+ die("ERROR: nothing parsed");
+ }
+ $this->_createPkgElements($pages);
+ if (count($this->ric))
+ {
+ phpDocumentor_out("Converting README/INSTALL/CHANGELOG contents...\n");
+ flush();
+ foreach($this->ric as $name => $contents)
+ {
+ phpDocumentor_out("$name...");
+ flush();
+ $this->Convert_RIC($name,$contents);
+ }
+ phpDocumentor_out("\ndone\n");
+ flush();
+ }
+ foreach($package_pages as $i => $perp)
+ {
+ if ($this->package_output)
+ {
+ if (!in_array($package_pages[$i]->package,$this->package_output)) continue;
+ }
+ phpDocumentor_out('Converting package page for package '.$package_pages[$i]->package.'... ');
+ flush();
+ $this->package = $package_pages[$i]->package;
+ $this->subpackage = '';
+ $this->class = false;
+ $this->Convert($package_pages[$i]);
+ phpDocumentor_out("done\n");
+ flush();
+ }
+ phpDocumentor_out("Converting tutorials/extended docs\n");
+ flush();
+ // get tutorials into the order they will display, and set next/prev links
+ $new = $this->_processTutorials();
+ foreach($this->tutorials as $package => $els)
+ {
+ foreach($els as $subpackage => $els2)
+ {
+ foreach($els2 as $type => $tutorials)
+ {
+ foreach($tutorials as $tutorial)
+ {
+ switch ($type)
+ {
+ case 'pkg' :
+ $a = '';
+ if ($tutorial->ini)
+ $a .= 'Top-level ';
+ if (!empty($tutorial->subpackage))
+ $a .= 'Sub-';
+ $ptext = "Converting ${a}Package-level tutorial ".$tutorial->name.'...';
+ break;
+ case 'cls' :
+ $a = '';
+ if ($tutorial->ini)
+ $a .= 'Top-level ';
+ $ptext = "Converting ${a}Class-level tutorial " . $tutorial->name ." and associating...";
+ $link = Converter::getClassLink(str_replace('.cls','',$tutorial->name), $tutorial->package);
+ if (is_object($link))
+ {
+ if ($this->sort_absolutely_everything)
+ {
+ $addend = 'unsuccessful ';
+ if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name]))
+ {
+ $this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name][0]->addTutorial($tutorial,$this);
+ $addend = 'success ';
+ }
+ } else
+ {
+ $addend = 'unsuccessful ';
+ if (!isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)]) && !isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)][$tutorial->path]))
+ {
+ foreach($pages as $j => $inf)
+ {
+ foreach($inf->classelements as $i => $class)
+ {
+ if ($class->type == 'class' && $class->name == str_replace('.cls','',$tutorial->name) && $class->path == $link->path)
+ {
+ $pages[$j]->classelements[$i]->addTutorial($tutorial,$this);
+ $addend = 'success ';
+ }
+ }
+ }
+ }
+ }
+ $ptext .= $addend;
+ } else $ptext .= "unsuccessful ";
+ break;
+ case 'proc' :
+ $a = '';
+ if ($tutorial->ini)
+ $a .= 'Top-level ';
+ $ptext = "Converting ${a}Procedural-level tutorial ".$tutorial->name." and associating...";
+ $link = Converter::getPageLink(str_replace('.proc','',$tutorial->name), $tutorial->package);
+ if (is_object($link))
+ {
+ $addend = 'unsuccessful ';
+ if ($this->sort_absolutely_everything)
+ {
+ if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path]))
+ {
+ $this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path][0]->addTutorial($tutorial,$this);
+ $addend = "success ";
+ }
+ } else
+ {
+ foreach($pages as $j => $info)
+ {
+ if ($j == $link->path)
+ {
+ $pages[$j]->addTutorial($tutorial,$this);
+ $addend = "success ";
+ }
+ }
+ }
+ $ptext .= $addend;
+ } else $ptext .= "unsuccessful ";
+ break;
+ }
+ phpDocumentor_out($ptext);
+ flush();
+ $this->package = $tutorial->package;
+ $this->subpackage = $tutorial->subpackage;
+ $this->Convert($tutorial);
+ phpDocumentor_out("done\n");
+ flush();
+ }
+ }
+ }
+ }
+ phpDocumentor_out("Formatting Package Indexes...");
+ flush();
+ $this->formatPkgIndex();
+ phpDocumentor_out("done\n");
+ flush();
+ phpDocumentor_out("Formatting Index...");
+ flush();
+ $this->formatIndex();
+ phpDocumentor_out("done\n\n");
+ flush();
+ phpDocumentor_out("Formatting Left Quick Index...");
+ flush();
+ $this->formatLeftIndex();
+ phpDocumentor_out("done\n\n");
+ flush();
+ if ($this->sort_absolutely_everything) return $this->walk_everything();
+ foreach($pages as $j => $flub)
+ {
+ phpDocumentor_out('Converting '.$pages[$j]->parent->getPath());
+ flush();
+ $this->package = $pages[$j]->parent->package;
+ $this->subpackage = $pages[$j]->parent->subpackage;
+ $this->class = false;
+ $this->curfile = $pages[$j]->parent->getFile();
+ $this->curname = $this->getPageName($pages[$j]->parent);
+ $this->curpath = $pages[$j]->parent->getPath();
+ $use = true;
+ if ($this->package_output)
+ {
+ if (in_array($this->package,$this->package_output))
+ {
+ $this->Convert($pages[$j]);
+ } else
+ {
+ $use = false;
+ }
+ } else
+ {
+ $this->Convert($pages[$j]);
+ }
+ phpDocumentor_out(" Procedural Page Elements...");
+ flush();
+ if ($use)
+ for($i=0; $ielements); $i++)
+ {
+ $a = $pages[$j]->elements[$i]->docblock->getKeyword('access');
+ if (is_object($a)) $a = $a->getString();
+ if (!$this->parseprivate && ($a == 'private'))
+ continue;
+// phpDocumentor_out(" ".$pages[$j]->elements[$i]->name."\n");
+ $pages[$j]->elements[$i]->docblock->package = $this->package;
+ $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage;
+ $this->Convert($pages[$j]->elements[$i]);
+ }
+ phpDocumentor_out(" Classes...");
+ $this->class = false;
+ flush();
+ for($i=0; $iclasselements); $i++)
+ {
+ if ($this->class)
+ {
+ if ($pages[$j]->classelements[$i]->type == 'class')
+ {
+ if (!$this->killclass) $this->endClass();
+ $this->killclass = false;
+ if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
+ $this->package = $pages[$j]->classelements[$i]->docblock->package;
+ if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
+ $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
+ $this->class = $pages[$j]->classelements[$i]->name;
+ } else
+ {
+ $a = $pages[$j]->classelements[$i]->docblock->getKeyword('access');
+ if (is_object($a)) $a = $a->getString();
+ if (!$this->parseprivate && ($a == 'private'))
+ continue;
+ if ($this->killclass) continue;
+ // force all contained elements to have parent package/subpackage
+ $pages[$j]->classelements[$i]->docblock->package = $this->package;
+ $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage;
+ }
+ }
+ if ($pages[$j]->classelements[$i]->type == 'class')
+ {
+ $this->killclass = false;
+ if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
+ $this->package = $pages[$j]->classelements[$i]->docblock->package;
+ if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
+ $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
+ $this->class = $pages[$j]->classelements[$i]->name;
+ }
+ if ($this->killclass) continue;
+// phpDocumentor_out(" ".$pages[$j]->classelements[$i]->name."\n");
+ $this->Convert($pages[$j]->classelements[$i]);
+ }
+ if (count($pages[$j]->classelements) && !$this->killclass) $this->endClass();
+ phpDocumentor_out(" done\n");
+ flush();
+ $this->endPage();
+ }
+ phpDocumentor_out("\nConverting @todo List...");
+ flush();
+ if (count($this->todoList))
+ {
+ $this->ConvertTodoList();
+ }
+ phpDocumentor_out("done\n");
+ flush();
+ phpDocumentor_out("\nConverting Error Log...");
+ flush();
+ $this->ConvertErrorLog();
+ phpDocumentor_out("done\n");
+ flush();
+ }
+
+
+ /**
+ * Get a tree structure representing the hierarchy of tutorials
+ *
+ * Returns an array in format:
+ *
+ * array('tutorial' => {@link parserTutorial},
+ * 'kids' => array( // child tutorials
+ * array('tutorial' => child {@link parserTutorial},
+ * 'kids' => array(...)
+ * )
+ * )
+ * )
+ *
+ * @param parserTutorial|array
+ * @tutorial tutorials.pkg
+ * @return array
+ */
+ function getTutorialTree($tutorial)
+ {
+ if (is_object($tutorial))
+ {
+ $path = $this->_tutorial_path($tutorial,$tutorial,$tutorial);
+ if (isset($this->tutorial_tree[$path])) {
+ $tutorial = $this->tutorial_tree[$path];
+ } else {
+ return false;
+ }
+ }
+ $tree = array();
+ if (isset($tutorial['tutorial']))
+ {
+ $tree['tutorial'] = $tutorial['tutorial'];
+ if (isset($tutorial['child']))
+ {
+ foreach($tutorial['child'] as $a => $b)
+ {
+ $btut = $b['tutorial'];
+ $res = array(
+ 'tutorial' => $this->tutorials
+ [$btut->package][$btut->subpackage]
+ [$btut->tutorial_type][$btut->name]
+ );
+ if (isset($b['child']))
+ {
+ $tempres = Converter::getTutorialTree($b);
+ $res['kids'] = $tempres['kids'];
+ }
+ $tree['kids'][] = $res;
+ }
+ }
+ }
+ return $tree;
+ }
+
+ /**
+ * Remove tutorials one by one from $all, and transfer them into $new in the
+ * order they should be parsed
+ * @param parserTutorial
+ * @param array
+ * @param array
+ * @access private
+ */
+ function generateTutorialOrder($parent,&$all,&$new)
+ {
+ // remove from the list of tutorials to process
+ foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $t)
+ {
+ if ($t->name == $parent->name) {
+ unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
+ }
+ }
+ // add to the new ordered list of tutorials
+ $x = &$new[$parent->package][$parent->subpackage][$parent->tutorial_type];
+ if (!is_object($x[count($x) - 1]) || $x[count($x) - 1]->name != $parent->name)
+ { // only add if the parent isn't also a child
+ $new[$parent->package][$parent->subpackage][$parent->tutorial_type][] = $parent;
+ // add a new branch to the tree
+ }
+ // process all child tutorials, and insert them in order
+// debug("processing parent ".$parent->name);
+ if ($parent->ini)
+ {
+ foreach($parent->ini['Linked Tutorials'] as $child)
+ {
+ $sub = (empty($parent->subpackage) ? '' : $parent->subpackage . '/');
+ $kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type;
+ $_klink = $this->getTutorialLink($kid,false,false,array($parent->package));
+ if (is_object($_klink)) {
+ $klink = $this->returnSee($_klink);
+ } else {
+ $klink = false;
+ }
+ // remove the child from the list of remaining tutorials
+ foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $tute)
+ {
+ if ($klink && $tute->getLink($this) == $klink)
+ {
+ // set up parent, next and prev links
+ $tute->setParent($parent, $this);
+ // remove the child from the list of tutorials to process
+ foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $t)
+ {
+ if ($t->name == $tute->name)
+ unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
+ }
+ // add to the new ordered list of tutorials
+ $new[$parent->package][$parent->subpackage][$parent->tutorial_type][] = $tute;
+ if ($tute->ini)
+ {
+ // add all the child's child tutorials to the list
+ $this->generateTutorialOrder($tute,$all,$new);
+ }
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ /** Returns the path to this tutorial as a string
+ * @param parserTutorial $pkg
+ * @param parserTutorial $subpkg
+ * @param parserTutorial $namepkg
+ * @return string */
+ function _tutorial_path($pkg, $subpkg = 0, $namepkg = 0)
+ {
+ if (!$subpkg) {
+ $subpkg = $pkg;
+ }
+ if (!$namepkg) {
+ $namepkg = $pkg;
+ }
+ $subpackagename = ($subpkg->subpackage ? '/' . $subpkg->subpackage : '');
+ return $pkg->package . $subpackagename . '/' . $namepkg->name;
+ }
+
+
+ /**
+ * Creates a tree structure of tutorials
+ *
+ * Format:
+ *
+ * array('package/subpackage/tutorial1.ext' =>
+ * array('tutorial' => {@link parserTutorial},
+ * 'child' =>
+ * array('package/subpackage/child1tutorial.ext' => ...,
+ * 'package/subpackage/child2tutorial.ext' => ...,
+ * ...
+ * )
+ * 'package/subpackage/tutorial2.ext' => ...,
+ * ...
+ * )
+ *
+ * @return array the tutorial tree
+ * @access private
+ */
+ function _setupTutorialTree($parent = false)
+ {
+ if (! isset($this->processed_tutorials)) {
+ $this->processed_tutorials = array();
+ }
+ $tree = array();
+ if (!$parent)
+ {
+ foreach($this->tutorials as $package => $s)
+ {
+ foreach($s as $subpackage => $t)
+ {
+ foreach($t as $type => $n)
+ {
+ foreach($n as $name => $tutorial)
+ {
+ if ($tutorial->parent) {
+ continue;
+ }
+
+ $child_path = $this->_tutorial_path($tutorial,$tutorial,$tutorial);
+ if (isset($this->processed_tutorials[$child_path])) {
+ continue;
+ }
+ $this->processed_tutorials[$child_path] = $tutorial;
+ //debug("parent ".$tutorial->name);
+ $ret = $this->_setupTutorialTree($tutorial);
+ if (!count($tree)) {
+ $tree = $ret;
+ } else {
+ $tree = array_merge($tree,$ret);
+ }
+ }
+ }
+ }
+ }
+ return $tree;
+ }
+ $parent_path = $this->_tutorial_path($parent);
+ $tree[$parent_path]['tutorial'] = $parent;
+ // process all child tutorials, and insert them in order
+ if ($parent->ini)
+ {
+ foreach($parent->ini['Linked Tutorials'] as $child)
+ {
+ if (isset($this->tutorials[$parent->package][$parent->subpackage]
+ [$parent->tutorial_type][$child . '.' .
+ $parent->tutorial_type])) {
+ // remove the child from the list of remaining tutorials
+ $tute = $this->tutorials[$parent->package][$parent->subpackage]
+ [$parent->tutorial_type][$child . '.' .
+ $parent->tutorial_type];
+ } else {
+ $tute = false;
+ }
+
+ if (!$tute) {
+ continue;
+ }
+ $child_path = $this->_tutorial_path($parent,$parent,$tute);
+ if (isset($this->processed_tutorials[$child_path])) {
+ continue;
+ }
+ $this->processed_tutorials[$child_path] = $tute;
+ if ($tute->name != $child . '.' . $parent->tutorial_type) {
+ continue;
+ }
+ //echo "Adding [$child_path] to [$parent_path]
";
+ $tree[$parent_path]['child'][$this->_tutorial_path($parent,$parent,$tute)]['tutorial']
+ = $tute;
+ if (!$tute->ini) {
+ continue;
+ }
+ // add all the child's child tutorials to the list
+ if (!isset($tree[$parent_path]['child'])) {
+ $tree[$parent_path]['child'] = $this->_setupTutorialTree($tute);
+ } else {
+ $tree[$parent_path]['child'] = array_merge($tree[$parent_path]['child'],
+ $this->_setupTutorialTree($tute));
+ }
+ }
+ }
+ return $tree;
+ }
+
+ /**
+ * Debugging function for dumping {@link $tutorial_tree}
+ * @return string
+ */
+ function vardump_tree($tree,$indent='')
+ {
+ if (phpDocumentor_get_class($tree) == 'parsertutorial') return $tree->name.' extends '.($tree->parent? $tree->parent->name : 'nothing');
+ $a = '';
+ foreach($tree as $ind => $stuff)
+ {
+ $x = $this->vardump_tree($stuff,"$indent ");
+ $a .= $indent.'['.$ind." => \n ".$indent.$x."]\n";
+ }
+ return substr($a,0,strlen($a) - 1);
+ }
+
+ /**
+ * @access private
+ */
+ function sort_package_elements($a,$b)
+ {
+ if (($a->type == $b->type) && (isset($a->isConstructor) && $a->isConstructor)) return -1;
+ if (($a->type == $b->type) && (isset($b->isConstructor) && $b->isConstructor)) return 1;
+ if ($a->type == $b->type) return strnatcasecmp($a->name,$b->name);
+ if ($a->type == 'class') return -1;
+ if ($b->type == 'class') return 1;
+ if ($a->type == 'const') return -1;
+ if ($b->type == 'const') return 1;
+ if ($a->type == 'var') return -1;
+ if ($b->type == 'var') return 1;
+ if ($a->type == 'page') return -1;
+ if ($b->type == 'page') return 1;
+ if ($a->type == 'include') return -1;
+ if ($b->type == 'include') return 1;
+ if ($a->type == 'define') return -1;
+ if ($b->type == 'define') return 1;
+ if ($a->type == 'global') return -1;
+ if ($b->type == 'global') return 1;
+ if ($a->type == 'function') return -1;
+ if ($b->type == 'function') return 1;
+ }
+
+ /**
+ * @access private
+ */
+ function defpackagesort($a,$b)
+ {
+ if ($a == $GLOBALS['phpDocumentor_DefaultPackageName']) return -1;
+ if ($b == $GLOBALS['phpDocumentor_DefaultPackageName']) return 0;
+ return strnatcasecmp($a,$b);
+ }
+
+ /**
+ * @access private
+ */
+ function Pc_sort($a,$b)
+ {
+ return strnatcasecmp(key($a),key($b));
+ }
+
+ /**
+ * walk over elements by package rather than page
+ *
+ * This method is designed for converters like the PDF converter that need
+ * everything passed in alphabetical order by package/subpackage and by
+ * procedural and then class information
+ * @see PDFdefaultConverter
+ * @see walk()
+ */
+ function walk_everything()
+ {
+ global $hooser;
+ $hooser = false;
+ uksort($this->package_elements,array($this,'defpackagesort'));
+ foreach($this->package_elements as $package => $r)
+ {
+ if ($this->package_output)
+ {
+ if (!in_array($this->package,$this->package_output))
+ {
+ unset($this->package_elements[$package]);
+ continue;
+ }
+ }
+ uksort($this->package_elements[$package],'strnatcasecmp');
+ }
+ foreach($this->package_elements as $package => $r)
+ {
+ foreach($this->package_elements[$package] as $subpackage => $r)
+ {
+ if (isset($r['page']))
+ {
+ uksort($r['page'],'strnatcasecmp');
+ foreach($r['page'] as $page => $oo)
+ {
+ usort($this->package_elements[$package][$subpackage]['page'][$page],array($this,'sort_package_elements'));
+ }
+ }
+ if (isset($r['class']))
+ {
+ uksort($r['class'],'strnatcasecmp');
+ foreach($r['class'] as $page => $oo)
+ {
+ usort($r['class'][$page],array($this,'sort_package_elements'));
+ }
+ }
+ $this->package_elements[$package][$subpackage] = $r;
+ }
+ }
+ foreach($this->package_elements as $package => $s)
+ {
+ $notyet = false;
+ foreach($s as $subpackage => $r)
+ {
+ $this->package = $package;
+ $this->subpackage = $subpackage;
+ if (isset($r['page']))
+ {
+ $this->class = false;
+ foreach($r['page'] as $page => $elements)
+ {
+ if (is_array($elements))
+ {
+ foreach($elements as $element)
+ {
+ if ($element->type == 'page')
+ {
+ phpDocumentor_out('Converting '.$element->parent->getPath());
+ flush();
+ $this->curfile = $element->parent->getFile();
+ $this->curname = $this->getPageName($element->parent);
+ $this->curpath = $element->parent->getPath();
+ $notyet = true;
+ } else
+ {
+ // force all contained elements to have parent package/subpackage
+ $element->docblock->package = $this->package;
+ $element->docblock->subpackage = $this->subpackage;
+ $a = $element->docblock->getKeyword('access');
+ if (is_object($a)) $a = $a->getString();
+ if (!$this->parseprivate && ($a == 'private'))
+ continue;
+ }
+ if ($notyet)
+ {
+ phpDocumentor_out(" Procedural Page Elements...");
+ flush();
+ $notyet = false;
+ }
+ $this->Convert($element);
+ }
+ }
+ $this->endPage();
+ phpDocumentor_out("done\n");
+ flush();
+ }
+ }
+ $start_classes = true;
+ if (isset($r['class']))
+ {
+ foreach($r['class'] as $class => $elements)
+ {
+ foreach($elements as $element)
+ {
+ if ($element->type == 'class')
+ {
+ if (!$start_classes)
+ {
+ if (count($elements) && !$this->killclass) $this->endClass();
+ phpDocumentor_out("done\n");
+ flush();
+ }
+ $start_classes = false;
+ $this->class = $element->getName();
+ $this->killclass = false;
+ if ($this->checkKillClass($element->getName(),$element->getPath())) continue;
+ if (!$this->killclass)
+ {
+ phpDocumentor_out('Converting '.$this->class."...");
+ flush();
+ $notyet = true;
+ }
+ } else
+ {
+ if ($notyet)
+ {
+ phpDocumentor_out("Variables/methods/Class constants...\n");
+ flush();
+ $notyet = false;
+ }
+ $a = $element->docblock->getKeyword('access');
+ if (is_object($a)) $a = $a->getString();
+ if (!$this->parseprivate && ($a == 'private'))
+ continue;
+ if ($this->killclass) continue;
+ // force all contained elements to have parent package/subpackage
+ $element->docblock->package = $this->package;
+ $element->docblock->subpackage = $this->subpackage;
+ }
+ if ($this->killclass) continue;
+ $this->Convert($element);
+ }
+ }
+ if (count($elements) && !$this->killclass) $this->endClass();
+ phpDocumentor_out("done\n");
+ flush();
+ } // if isset($r['class'])
+ } // foreach($s
+ } // foreach($this->package_elements)
+ phpDocumentor_out("\nConverting @todo List...");
+ flush();
+ if (count($this->todoList))
+ {
+ $this->ConvertTodoList();
+ }
+ phpDocumentor_out("done\n");
+ flush();
+ phpDocumentor_out("\nConverting Error Log...");
+ flush();
+ $this->ConvertErrorLog();
+ phpDocumentor_out("done\n");
+ flush();
+ }
+
+ /**
+ * Convert the phpDocumentor parsing/conversion error log
+ * @abstract
+ */
+ function ConvertErrorLog()
+ {
+ }
+
+ /**
+ * Convert the list of all @todo tags
+ * @abstract
+ */
+ function ConvertTodoList()
+ {
+ }
+
+ /**
+ * Sorts the @todo list - do not override or modify this function
+ * @access private
+ * @uses _sortTodos passed to {@link usort()} to sort the todo list
+ */
+ function sortTodos()
+ {
+ phpDocumentor_out("\nSorting @todo list...");
+ flush();
+ foreach($this->todoList as $package => $r) {
+ usort($this->todoList[$package], array('Converter', '_sortTodoPackage'));
+ foreach ($r as $a => $sub) {
+ if (is_array($this->todoList[$package][$a][1])) {
+ usort($this->todoList[$package][$a][1],array('Converter', '_sortTodos'));
+ }
+ }
+ }
+ phpDocumentor_out("done\n");
+ }
+
+ /** @access private */
+ function _sortTodoPackage($a, $b)
+ {
+ return strnatcasecmp($a[0]->name, $b[0]->name);
+ }
+
+ /** @access private */
+ function _sortTodos($a, $b)
+ {
+ if (!is_object($a)) {
+ var_dump($a);
+ }
+ return strnatcasecmp($a->getString(), $b->getString());
+ }
+
+ /**
+ * Sorts all indexes - do not override or modify this function
+ * @uses $leftindex based on the value of leftindex, sorts link arrays
+ * @uses $class_elements sorts with {@link compareLink}
+ * @uses $page_elements sorts with {@link compareLink}
+ * @uses $define_elements sorts with {@link compareLink}
+ * @uses $global_elements sorts with {@link compareLink}
+ * @uses $function_elements sorts with {@link compareLink}
+ * @uses $elements sorts with {@link elementCmp}
+ * @uses $pkg_elements sorts with {@link elementCmp} after sorting by
+ * package/subpackage alphabetically
+ * @access private
+ */
+ function sortIndexes()
+ {
+ phpDocumentor_out("\nSorting Indexes...");
+ flush();
+ uksort($this->elements,'strnatcasecmp');
+ if ($this->leftindex['classes'])
+ {
+ foreach($this->class_elements as $package => $o1)
+ {
+ foreach($o1 as $subpackage => $links)
+ {
+ usort($this->class_elements[$package][$subpackage],array($this,'compareLink'));
+ }
+ }
+ }
+ if ($this->leftindex['pages'])
+ {
+ foreach($this->page_elements as $package => $o1)
+ {
+ uksort($this->page_elements[$package],'strnatcasecmp');
+ foreach($o1 as $subpackage => $links)
+ {
+ usort($this->page_elements[$package][$subpackage],array($this,'compareLink'));
+ }
+ }
+ }
+ if ($this->leftindex['defines'])
+ {
+ foreach($this->define_elements as $package => $o1)
+ {
+ uksort($this->define_elements[$package],'strnatcasecmp');
+ foreach($o1 as $subpackage => $links)
+ {
+ usort($this->define_elements[$package][$subpackage],array($this,'compareLink'));
+ }
+ }
+ }
+ if ($this->leftindex['globals'])
+ {
+ foreach($this->global_elements as $package => $o1)
+ {
+ uksort($this->global_elements[$package],'strnatcasecmp');
+ foreach($o1 as $subpackage => $links)
+ {
+ usort($this->global_elements[$package][$subpackage],array($this,'compareLink'));
+ }
+ }
+ }
+ if ($this->leftindex['functions'])
+ {
+ foreach($this->function_elements as $package => $o1)
+ {
+ uksort($this->function_elements[$package],'strnatcasecmp');
+ foreach($o1 as $subpackage => $links)
+ {
+ usort($this->function_elements[$package][$subpackage],array($this,'compareLink'));
+ }
+ }
+ }
+ foreach($this->elements as $letter => $nothuing)
+ {
+ uasort($this->elements[$letter],array($this,"elementCmp"));
+ }
+ foreach($this->pkg_elements as $package => $els)
+ {
+ uksort($this->pkg_elements[$package],'strnatcasecmp');
+ foreach($this->pkg_elements[$package] as $subpackage => $els)
+ {
+ if (empty($els)) continue;
+ uksort($this->pkg_elements[$package][$subpackage],'strnatcasecmp');
+ foreach($els as $letter => $yuh)
+ {
+ usort($this->pkg_elements[$package][$subpackage][$letter],array($this,"elementCmp"));
+ }
+ }
+ }
+ phpDocumentor_out("done\n");
+ flush();
+ }
+
+ /**
+ * sorts {@link $page_contents} by element type as well as alphabetically
+ * @see $sort_page_contents_by_element_type
+ */
+ function sortPageContentsByElementType(&$pages)
+ {
+ foreach($this->page_contents as $package => $els)
+ {
+ foreach($this->page_contents[$package] as $subpackage => $els)
+ {
+ if (empty($els)) continue;
+ foreach($this->page_contents[$package][$subpackage] as $path => $stuff)
+ {
+ if (!count($pages[$path]->elements)) continue;
+ usort($pages[$path]->elements,array($this,'eltypecmp'));
+ usort($this->page_contents[$package][$subpackage][$path],array($this,'eltypecmp'));
+ if (isset($this->page_contents[$package][$subpackage][$path][0]))
+ $this->page_contents[$package][$subpackage][$path]['###main'] = $this->page_contents[$package][$subpackage][$path][0];
+ unset($this->page_contents[$package][$subpackage][$path][0]);
+ }
+ }
+ }
+ }
+
+ /**
+ * @access private
+ * @see Converter::sortIndexes()
+ */
+ function compareLink($a, $b)
+ {
+ return strnatcasecmp($a->name,$b->name);
+ }
+
+ /**
+ * @access private
+ * @see Converter::sortPageContentsByElementType()
+ */
+ function eltypecmp($a, $b)
+ {
+ if ($a->type == 'page') return -1;
+ if ($b->type == 'page') return 1;
+ return strnatcasecmp($a->type.$a->name,$b->type.$b->name);
+ }
+
+ /**
+ * does a nat case sort on the specified second level value of the array
+ *
+ * @param mixed $a
+ * @param mixed $b
+ * @return int
+ * @access private
+ */
+ function elementCmp ($a, $b)
+ {
+ return strnatcasecmp($a->getName(), $b->getName());
+ }
+
+ /**
+ * Used to stop conversion of @ignored or private @access classes
+ * @uses $killclass sets killclass based on the value of {@link Classes::$killclass}
+ * and {@link $package_output}
+ * @access private
+ */
+ function checkKillClass($class, $path)
+ {
+ $this->killclass = false;
+ if (isset($this->classes->killclass[$class]) && isset($this->classes->killclass[$class][$path])) $this->killclass = true;
+ if ($this->package_output)
+ {
+ $a = $this->classes->getClass($class, $path);
+ if (!in_array($a->docblock->package,$this->package_output)) $this->killclass = true;
+ }
+ if (PHPDOCUMENTOR_DEBUG && $this->killclass) debug("$class $path killed");
+ return $this->killclass;
+ }
+
+ /**
+ * @param abstractLink descendant of abstractLink
+ * @param array|parserTag list of @todos|@todo tag
+ * @access private
+ */
+ function addTodoLink($link, $todos)
+ {
+ $this->todoList[$link->package][] = array($link, $todos);
+ }
+
+ /**
+ * Adds all elements to the {@link $elements, $pkg_elements, $links},
+ * {@link $linkswithfile} and left indexes - Do not modify or override
+ * @access private
+ * @param parserBase any documentable element descendant of parserBase
+ * except parserTutorial
+ * @param false|parserPage only used to add a {@link parserPage} if the
+ * $element passed is a parserPage
+ * @staticvar string path of current page, used for {@link $page_contents} setup
+ */
+ function addElement(&$element,$pageel=false)
+ {
+ static $curpath = '';
+ if ($this->package_output)
+ {
+ if (!in_array($this->package, $this->package_output)) return;
+ }
+ if ($pageel && phpDocumentor_get_class($pageel) == 'parserdata')
+ {
+ if (isset($pageel->docblock) && phpDocumentor_get_class($pageel->docblock) == 'parserdocblock')
+ {
+ $a = $pageel->docblock->getKeyword('todo');
+ if ($a)
+ {
+ $this->addTodoLink($this->addLink($element),$a);
+ }
+ }
+ }
+ if (isset($element->docblock))
+ {
+ $a = $element->docblock->getKeyword('access');
+ if (is_object($a)) $a = $a->getString();
+ if (!$this->parseprivate && ($a == 'private'))
+ return;
+ $a = $element->docblock->getKeyword('todo');
+ if ($a)
+ {
+ if ($element->type != 'include') {
+ $this->addTodoLink($this->addLink($element),$a);
+ } else {
+ addWarning(PDERROR_NOTODO_INCLUDE, $element->getLineNumber(),
+ $element->getPath());
+ }
+ }
+ }
+ $startPositionOfElementName = 0; // which character of the element name actually starts its textual name
+ switch($element->type)
+ {
+ case 'page' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->package][$element->subpackage]['page'][$element->getPath()][] = $pageel;
+ }
+ $link = $this->addLink($element);
+ $curpath = $element->getPath();
+ if ($this->leftindex['pages'])
+ $this->page_elements[$element->package][$element->subpackage][] = $link;
+ $this->page_contents[$element->package][$element->subpackage][$curpath]['###main'] = $link;
+ break;
+ case 'class' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
+ }
+ $link = $this->addLink($element);
+ if ($this->leftindex['classes'])
+ $this->class_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
+ $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class]['###main'] = $link;
+ break;
+ case 'include' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
+ }
+ $link = $this->addLink($element);
+ break;
+ case 'define' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
+ }
+ $link = $this->addLink($element);
+ if ($this->leftindex['defines'])
+ $this->define_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
+ $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link;
+ break;
+ case 'global' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
+ }
+ $link = $this->addLink($element);
+ $startPositionOfElementName = 1; // lose the leading "$" character
+ if ($this->leftindex['globals'])
+ $this->global_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
+ $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link;
+ break;
+ case 'var' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
+ }
+ $link = $this->addLink($element);
+ $startPositionOfElementName = 1; // lose the leading "$" character
+ $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link;
+ break;
+ case 'const' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
+ }
+ $link = $this->addLink($element);
+ $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link;
+ break;
+ case 'method' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
+ }
+ $link = $this->addLink($element);
+ $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link;
+ break;
+ case 'function' :
+ if ($this->sort_absolutely_everything)
+ {
+ $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
+ }
+ $link = $this->addLink($element);
+ if ($this->leftindex['functions'])
+ $this->function_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
+ $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link;
+ break;
+ default :
+ break;
+ }
+ if ($element->getType() != 'include')
+ {
+ if ($element->getType() == 'var' || $element->getType() == 'method'|| $element->getType() == 'const')
+ {
+ $this->links[$this->package][$this->subpackage][$element->getType()][$element->class][$element->getName()] = $link;
+ $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->class][$element->getName()] = $link;
+ } else
+ {
+ if ($element->type == 'page')
+ {
+ $this->links[$this->package][$this->subpackage][$element->getType()][$element->getFile()] = $link;
+ $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getFile()] = $link;
+ } else
+ {
+ $this->links[$this->package][$this->subpackage][$element->getType()][$element->getName()] = $link;
+ $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getName()] = $link;
+ }
+ }
+ }
+ if ($element->type == 'page')
+ {
+ $this->elements[substr(strtolower($element->getFile()),$startPositionOfElementName,1)][] = $element;
+ $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getFile()),$startPositionOfElementName,1)][] = $element;
+ } else
+ {
+ $this->elements[substr(strtolower($element->getName()),$startPositionOfElementName,1)][] = $element;
+ $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getName()),$startPositionOfElementName,1)][] = $element;
+ }
+ }
+
+ /**
+ * returns an abstract link to element. Do not modify or override
+ *
+ * This method should only be called in process of Conversion, unless
+ * $element is a parserPage, or $page is set to true, and $element is
+ * not a parserPage
+ * @return abstractLink abstractLink descendant
+ * @access private
+ * @param parserElement element to add a new link (descended from
+ * {@link abstractLink})to the {@link $links} array
+ * @param string classname for elements that are class-based (this may be
+ * deprecated in the future, as the classname
+ * should be contained within the element. if $element is a
+ * page, this parameter is a package name
+ * @param string subpackage name for page elements
+ */
+ function addLink(&$element,$page = false)
+ {
+ if ($page)
+ {
+ // create a fake parserPage to extract the fileAlias for this link
+ $fakepage = new parserPage;
+ $fakepage->setPath($element->getPath());
+ $fakepage->setFile(basename($element->getPath()));
+ $this->curname = $this->getPageName($fakepage);
+ }
+ switch($element->type)
+ {
+ case 'function':
+ $x = new functionLink;
+ $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
+ return $x;
+ break;
+ case 'define':
+ $x = new defineLink;
+ $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
+ return $x;
+ break;
+ case 'global':
+ $x = new globalLink;
+ $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
+ return $x;
+ break;
+ case 'class':
+ $x = new classLink;
+ $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
+ return $x;
+ break;
+ case 'method':
+ $x = new methodLink;
+ $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
+ return $x;
+ break;
+ case 'var':
+ $x = new varLink;
+ $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
+ return $x;
+ break;
+ case 'const':
+ $x = new constLink;
+ $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
+ return $x;
+ break;
+ case 'page':
+ $x = new pageLink;
+ $x->addLink($element->getPath(),$this->getPageName($element),$element->file,$element->package, $element->subpackage, $element->category);
+ return $x;
+ break;
+ }
+ }
+
+ /**
+ * Return a tree of all classes that extend this class
+ *
+ * The data structure returned is designed for a non-recursive algorithm,
+ * and is somewhat complex.
+ * In most cases, the array returned is:
+ *
+ *
+ * array('#root' =>
+ * array('link' => {@link classLink} to $class,
+ * 'parent' => false,
+ * 'children' => array(array('class' => 'childclass1',
+ * 'package' => 'child1package'),
+ * array('class' => 'childclass2',
+ * 'package' => 'child2package'),...
+ * )
+ * ),
+ * 'child1package#childclass1' =>
+ * array('link' => {@link classLink} to childclass1,
+ * 'parent' => '#root',
+ * 'children' => array(array('class' => 'kidclass',
+ * 'package' => 'kidpackage'),...
+ * )
+ * ),
+ * 'kidpackage#kidclass' =>
+ * array('link' => {@link classLink} to kidclass,
+ * 'parent' => 'child1package#childclass1',
+ * 'children' => array() // no children
+ * ),
+ * ....
+ * )
+ *
+ *
+ * To describe this format using language, every class in the tree has an
+ * entry in the first level of the array. The index for all child
+ * classes that extend the root class is childpackage#childclassname.
+ * Each entry in the array has 3 elements: link, parent, and children.
+ *
+ * - link - a {@link classLink} to the current class
+ * - parent - a {@link classLink} to the class's parent, or false (except for one special case described below)
+ * - children - an array of arrays, each entry has a 'class' and 'package' index to the child class,
+ * used to find the entry in the big array
+ *
+ *
+ * special cases are when the #root class has a parent in another package,
+ * or when the #root class extends a class not found
+ * by phpDocumentor. In the first case, parent will be a
+ * classLink to the parent class. In the second, parent will be the
+ * extends clause, as in:
+ *
+ * class X extends Y
+ * {
+ * ...
+ * }
+ *
+ * in this case, the #root entry will be array('link' => classLink to X, 'parent' => 'Y', children => array(...))
+ *
+ * The fastest way to design a method to process the array returned
+ * is to copy HTMLframesConverter::getRootTree() into
+ * your converter and to modify the html to whatever output format you are going to use
+ * @see HTMLframesConverter::getRootTree()
+ * @param string class name
+ * @param string
+ * @param string
+ * @return array Format: see docs
+ */
+ function getSortedClassTreeFromClass($class,$package,$subpackage)
+ {
+ $my_tree = array();
+ $root = $this->classes->getClassByPackage($class,$package);
+ if (!$root) return false;
+ $class_children = $this->classes->getDefiniteChildren($class,$root->curfile);
+ if (!$class_children)
+ {
+ // special case: parent class is found, but is not part of this package, class has no children
+ if (is_array($root->parent))
+ {
+ $x = $root->getParent($this);
+ if ($x->docblock->package != $package)
+ {
+ $v = Converter::getClassLink($root->getName(),$package,$root->getPath());
+ return array('#root' => array('link' => $v,'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()), 'children' => array()));
+ }
+ } else
+ { // class has normal situation, no children
+ if (is_string($root->getParent($this)))
+ return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => $root->getExtends(),'children' => array()));
+ else
+ return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => false, 'children' => array()));
+ }
+ }
+ // special case: parent class is found, but is not part of this package, class has children
+ if (is_array($root->parent))
+ {
+ $x = $root->getParent($this);
+ if ($x->docblock->package != $package)
+ {
+ $v = Converter::getClassLink($root->getName(),$package,$root->getPath());
+ $my_tree = array('#root' => array('link' => $v, 'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()), 'children' => array()));
+ } else
+ {
+ }
+ } else
+ $my_tree = array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => false, 'children' => array()));
+ // location of tree walker
+ $cur = '#root';
+ $lastcur = array(array(false,0));
+ $childpos = 0;
+ if (isset($class_children))
+ {
+ do
+ {
+ if (!$class_children)
+ {
+ list($cur, $childpos) = array_pop($lastcur);
+ if (isset($my_tree[$cur]['children'][$childpos + 1]))
+ {
+ array_push($lastcur, array($cur, $childpos + 1));
+ $par = $cur;
+ $cur = $my_tree[$cur]['children'][$childpos + 1];
+ $x = $this->classes->getClassByPackage($cur['class'],$cur['package']);
+ $childpos = 0;
+ $cur = $cur['package'] . '#' . $cur['class'];
+ $my_tree[$cur]['link'] = Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
+ $my_tree[$cur]['parent'] = $par;
+ $my_tree[$cur]['children'] = array();
+ $class_children = $this->classes->getDefiniteChildren($x->getName(), $x->curfile);
+ continue;
+ } else
+ {
+ $class_children = false;
+ continue;
+ }
+ }
+ foreach($class_children as $chileclass => $chilefile)
+ {
+ $ch = $this->classes->getClass($chileclass,$chilefile);
+ $my_tree[$cur]['children'][] = array('class' => $ch->getName(), 'package' => $ch->docblock->package);
+ }
+ usort($my_tree[$cur]['children'],'rootcmp');
+ if (isset($my_tree[$cur]['children'][$childpos]))
+ {
+ array_push($lastcur, array($cur, $childpos));
+ $par = $cur;
+ $cur = $my_tree[$cur]['children'][$childpos];
+ $x = $this->classes->getClassByPackage($cur['class'],$cur['package']);
+ $cur = $cur['package'] . '#' . $cur['class'];
+ $my_tree[$cur]['link'] = Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
+ $my_tree[$cur]['parent'] = $par;
+ $my_tree[$cur]['children'] = array();
+ $childpos = 0;
+ $class_children = $this->classes->getDefiniteChildren($x->getName(), $x->curfile);
+ } else
+ {
+ list($cur, $childpos) = array_pop($lastcur);
+ }
+ } while ($cur);
+ }
+ return $my_tree;
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this class exists in package $package and subpackage $subpackage
+ * @param string $expr class name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedClass($expr,$package,$subpackage,$file=false)
+ {
+ if ($file)
+ return isset($this->linkswithfile[$package][$subpackage]['class'][$file][$expr]);
+ return isset($this->links[$package][$subpackage]['class'][$expr]);
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this function exists in package $package and subpackage $subpackage
+ * @param string $expr function name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedFunction($expr,$package,$subpackage,$file=false)
+ {
+ if ($file)
+ return isset($this->linkswithfile[$package][$subpackage]['function'][$file][$expr]);
+ return isset($this->links[$package][$subpackage]['function'][$expr]);
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this define exists in package $package and subpackage $subpackage
+ * @param string $expr define name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedDefine($expr,$package,$subpackage,$file=false)
+ {
+ if ($file)
+ return isset($this->linkswithfile[$package][$subpackage]['define'][$file][$expr]);
+ return isset($this->links[$package][$subpackage]['define'][$expr]);
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this define exists in package $package and subpackage $subpackage
+ * @param string $expr define name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedGlobal($expr,$package,$subpackage,$file=false)
+ {
+ if ($file)
+ return isset($this->linkswithfile[$package][$subpackage]['global'][$file][$expr]);
+ return isset($this->links[$package][$subpackage]['global'][$expr]);
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this procedural page exists in package $package and subpackage $subpackage
+ * @param string $expr procedural page name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedPage($expr,$package,$subpackage,$path=false)
+ {
+ if ($path)
+ return isset($this->linkswithfile[$package][$subpackage]['page'][$path][$expr]);
+ return isset($this->links[$package][$subpackage]['page'][$expr]);
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
+ * @param string $expr method name
+ * @param string $class class name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedMethod($expr,$package,$subpackage,$class,$file=false)
+ {
+ if ($file)
+ return isset($this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr]);
+ return isset($this->links[$package][$subpackage]['method'][$class][$expr]);
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
+ * @param string $expr var name
+ * @param string $class class name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedVar($expr,$package,$subpackage,$class,$file=false)
+ {
+ if ($file)
+ return isset($this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr]);
+ return isset($this->links[$package][$subpackage]['var'][$class][$expr]);
+ }
+
+ /**
+ * do not override
+ * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
+ * @param string $expr constant name
+ * @param string $class class name
+ * @param string $package package to search in
+ * @param string $subpackage subpackage to search in
+ * @access private
+ */
+ function isLinkedConst($expr,$package,$subpackage,$class,$file=false)
+ {
+ if ($file)
+ return isset($this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr]);
+ return isset($this->links[$package][$subpackage]['const'][$class][$expr]);
+ }
+
+ /**
+ * return false or a {@link classLink} to $expr
+ * @param string $expr class name
+ * @param string $package package name
+ * @return mixed returns a {@link classLink} or false if the element is not found in package $package
+ * @see classLink
+ */
+ function getClassLink($expr,$package,$file=false, $text = false)
+ {
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedClass($expr,$package,$subpackage,$file))
+ {
+ if ($file)
+ {
+ return $this->linkswithfile[$package][$subpackage]['class'][$file][$expr];
+ }
+ return $this->links[$package][$subpackage]['class'][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return false or a {@link functionLink} to $expr
+ * @param string $expr function name
+ * @param string $package package name
+ * @return mixed returns a {@link functionLink} or false if the element is not found in package $package
+ * @see functionLink
+ */
+ function getFunctionLink($expr,$package,$file=false, $text = false)
+ {
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedFunction($expr,$package,$subpackage,$file))
+ {
+ if ($file)
+ {
+ return $this->linkswithfile[$package][$subpackage]['function'][$file][$expr];
+ }
+ return $this->links[$package][$subpackage]['function'][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return false or a {@link defineLink} to $expr
+ * @param string $expr constant name
+ * @param string $package package name
+ * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
+ * @see defineLink
+ */
+ function getDefineLink($expr,$package,$file=false, $text = false)
+ {
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedDefine($expr,$package,$subpackage,$file))
+ {
+ if ($file)
+ {
+ return $this->linkswithfile[$package][$subpackage]['define'][$file][$expr];
+ }
+ return $this->links[$package][$subpackage]['define'][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return false or a {@link globalLink} to $expr
+ * @param string $expr global variable name (with leading $)
+ * @param string $package package name
+ * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
+ * @see defineLink
+ */
+ function getGlobalLink($expr,$package,$file=false, $text = false)
+ {
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedGlobal($expr,$package,$subpackage,$file))
+ {
+ if ($file)
+ {
+ return $this->linkswithfile[$package][$subpackage]['global'][$file][$expr];
+ }
+ return $this->links[$package][$subpackage]['global'][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return false or a {@link pageLink} to $expr
+ * @param string $expr procedural page name
+ * @param string $package package name
+ * @return mixed returns a {@link pageLink} or false if the element is not found in package $package
+ * @see pageLink
+ */
+ function getPageLink($expr,$package,$path = false, $text = false, $packages = false)
+ {
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedPage($expr,$package,$subpackage,$path))
+ {
+ if ($path)
+ {
+ return $this->linkswithfile[$package][$subpackage]['page'][$path][$expr];
+ }
+ return $this->links[$package][$subpackage]['page'][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return false or a {@link methodLink} to $expr in $class
+ * @param string $expr method name
+ * @param string $class class name
+ * @param string $package package name
+ * @return mixed returns a {@link methodLink} or false if the element is not found in package $package, class $class
+ * @see methodLink
+ */
+ function getMethodLink($expr,$class,$package,$file=false, $text = false)
+ {
+ $expr = trim($expr);
+ $class = trim($class);
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedMethod($expr,$package,$subpackage,$class,$file))
+ {
+ if ($file)
+ {
+ return $this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr];
+ }
+ return $this->links[$package][$subpackage]['method'][$class][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return false or a {@link varLink} to $expr in $class
+ * @param string $expr var name
+ * @param string $class class name
+ * @param string $package package name
+ * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
+ * @see varLink
+ */
+ function getVarLink($expr,$class,$package,$file=false, $text = false)
+ {
+ $expr = trim($expr);
+ $class = trim($class);
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedVar($expr,$package,$subpackage,$class,$file))
+ {
+ if ($file)
+ {
+ return $this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr];
+ }
+ return $this->links[$package][$subpackage]['var'][$class][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * return false or a {@link constLink} to $expr in $class
+ * @param string $expr constant name
+ * @param string $class class name
+ * @param string $package package name
+ * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
+ * @see constLink
+ */
+ function getConstLink($expr,$class,$package,$file=false, $text = false)
+ {
+ $expr = trim($expr);
+ $class = trim($class);
+ if (!isset($this->links[$package])) return false;
+ foreach($this->links[$package] as $subpackage => $notused)
+ {
+ if ($this->isLinkedConst($expr,$package,$subpackage,$class,$file))
+ {
+ if ($file)
+ {
+ return $this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr];
+ }
+ return $this->links[$package][$subpackage]['const'][$class][$expr];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * The meat of the @tutorial tag and inline {@}tutorial} tag
+ *
+ * Take a string and return an abstract link to the tutorial it represents.
+ * Since tutorial naming literally works like the underlying filesystem, the
+ * way to reference the tutorial is similar. Tutorials are located in a
+ * subdirectory of any directory parsed, which is named 'tutorials/' (we
+ * try to make things simple when we can :). They are further organized by
+ * package and subpackage as:
+ *
+ * tutorials/package/subpackage
+ *
+ * and the files are named *.cls, *.pkg, or *.proc, and so a link to a tutorial
+ * named file.cls can be referenced (depending on context) as any of:
+ *
+ *
+ * * @tutorial package/subpackage/file.cls
+ * * @tutorial package/file.cls
+ * * @tutorial file.cls
+ *
+ *
+ * The first case will only be needed if file.cls exists in both the current
+ * package, in anotherpackage/file.cls and in anotherpackage/subpackage/file.cls
+ * and you wish to reference the one in anotherpackage/subpackage.
+ * The second case is only needed if you wish to reference file.cls in another
+ * package and it is unique in that package. the third will link to the first
+ * file.cls it finds using this search method:
+ *
+ *
+ * - current package/subpackage
+ * - all other subpackages of current package
+ * - parent package, if this package has classes that extend classes in
+ * another package
+ * - all other packages
+ *
+ * @return tutorialLink|string returns either a link, or the original text, if not found
+ * @param string the original expression
+ * @param string package to look in first
+ * @param string subpackage to look in first
+ * @param array array of package names to search in if not found in parent packages.
+ * This is used to limit the search, phpDocumentor automatically searches
+ * all packages
+ * @since 1.2
+ */
+ function getTutorialLink($expr, $package = false, $subpackage = false, $packages = false)
+ {
+ // is $expr a comma-delimited list?
+ if (strpos($expr,','))
+ {
+ $a = explode(',',$expr);
+ $b = array();
+ for($i=0;$ipackage;
+ if (!$subpackage) $subpackage = $this->subpackage;
+ if (!isset($this->all_packages[$package])) return $expr;
+ elseif (isset($packages[$package])) unset($packages[$package]);
+ $ext = pathinfo($expr, PATHINFO_EXTENSION);
+ if (isset($this->tutorials[$package][$subpackage][$ext][$expr]))
+ {
+ $a = $this->tutorials[$package][$subpackage][$ext][$expr];
+ $link = new tutorialLink;
+ $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this,$subsection));
+ return $link;
+ }
+ do
+ {
+ if (!is_array($packages))
+ {
+ $packages = $this->all_packages;
+ if (isset($packages[$package])) unset($packages[$package]);
+ }
+ if (isset($this->tutorials[$package]))
+ {
+ if (isset($this->tutorials[$package][$subpackage][$ext][$expr]))
+ {
+ $a = $this->tutorials[$package][$subpackage][$ext][$expr];
+ $link = new tutorialLink;
+ $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this));
+ return $link;
+ } else
+ {
+ foreach($this->tutorials[$package] as $subpackage => $stuff)
+ {
+ if (isset($stuff[$ext][$expr]))
+ {
+ $a = $stuff[$ext][$expr];
+ $link = new tutorialLink;
+ $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this));
+ return $link;
+ }
+ }
+ }
+ }
+ // try other packages
+ // look in parent package first, if found
+ if (isset($this->package_parents[$package]))
+ {
+ $p1 = $package;
+ $package = $this->package_parents[$package];
+ } else
+ {
+ // no parent package, so start with the first one that's left
+ list($package,) = @each($packages);
+ }
+ if ($package)
+ {
+ if (isset($packages[$package])) unset($packages[$package]);
+ }
+ } while (count($packages) || $package);
+ addWarning(PDERROR_TUTORIAL_NOT_FOUND,$expr);
+ return $expr;
+ }
+
+ /**
+ * The meat of the @see tag and inline {@}link} tag
+ *
+ * $expr is a string with many allowable formats:
+ *
+ * - proceduralpagename.ext
+ * - constant_name
+ * - classname::function()
+ * - classname::constantname
(new 1.2.4)
+ * - classname::$variablename
+ * - classname
+ * - object classname
+ * - function functionname()
+ * - global $globalvarname
+ * - packagename#expr where expr is any of the above
+ *
+ *
+ * New in version 1.1, you can explicitly specify a package to link to that
+ * is different from the current package. Use the # operator
+ * to specify a new package, as in tests#bug-540368.php (which should appear
+ * as a link like: "{@link tests#bug-540368.php}"). This
+ * example links to the procedural page bug-540368.php in package
+ * tests. Also, the "function" operator is now used to specifically
+ * link to a function instead of a method in the current class.
+ *
+ *
+ * class myclass
+ * {
+ * // from inside the class definition, use "function conflict()" to refer to procedural function "conflict()"
+ * function conflict()
+ * {
+ * }
+ * }
+ *
+ * function conflict()
+ * {
+ * }
+ *
+ *
+ * If classname:: is not present, and the see tag is in a documentation
+ * block within a class, then the function uses the classname to
+ * search for $expr as a function or variable within classname, or any of its parent classes.
+ * given an $expr without '$', '::' or '()' getLink first searches for
+ * classes, procedural pages, constants, global variables, and then searches for
+ * methods and variables within the default class, and finally for any function
+ *
+ * @param string $expr expression to search for a link
+ * @param string $package package to start searching in
+ * @param array $packages list of all packages to search in
+ * @return mixed getLink returns a descendant of {@link abstractLink} if it finds a link, otherwise it returns a string
+ * @see getPageLink(), getDefineLink(), getVarLink(), getFunctionLink(), getClassLink()
+ * @see pageLink, functionLink, defineLink, classLink, methodLink, varLink
+ */
+ function &getLink($expr, $package = false, $packages = false)
+ {
+ // is $expr a comma-delimited list?
+ if (strpos($expr,','))
+ {
+ $a = explode(',',$expr);
+ $b = array();
+ for($i=0;$i_getLink($expr, $package, $packages);
+ return $a;
+ }
+
+ /**
+ * @access private
+ */
+ function &_getLink($expr, $package = false, $packages = false)
+ {
+ if (!$package) $package = $this->package;
+ //
+ if (!isset($this->all_packages[$package])) return $expr;
+ elseif (isset($packages[$package])) unset($packages[$package]);
+ $links = &$this->links;
+ $class = $this->class;
+ if (strpos($expr,'function ') === 0)
+ { // asking for a function, not a method
+ if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test;
+ else return $expr;
+ }
+ if (strpos($expr,'global ') === 0)
+ { // asking for a global variable
+ if ($test = Converter::getGlobalLink(str_replace('global ','',$expr), $package)) return $test;
+ else return $expr;
+ }
+ if (strpos($expr,'object ') === 0)
+ { // asking for a class
+ if ($test = Converter::getClassLink(str_replace('object ','',$expr), $package)) return $test;
+ else return $expr;
+ }
+ if (strpos($expr,'constant ') === 0)
+ { // asking for a class
+ if ($test = Converter::getDefineLink(str_replace('constant ','',$expr), $package)) return $test;
+ else return $expr;
+ }
+ // are we in a class?
+ if ($class)
+ {
+ // is $expr simply a word? see if it is the class
+ if (trim($expr) == $class)
+ {
+ if ($test = Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test;
+ }
+ // if not, check to see if it is a method or variable of this class tree
+ if (!strpos($expr,'::'))
+ {
+ // if get is neither get() nor $get, assume get is a function, add () to make get()
+ if (strpos($expr,'$') !== 0 && !strpos($expr,'()')) //$get = $get.'()';
+ {
+ if ($a = $this->getLinkMethod($expr,$class,$package)) return $a;
+ if ($a = $this->getLinkConst($expr,$class,$package)) return $a;
+ if ($a = $this->getLinkVar('$'.$expr,$class,$package)) return $a;
+ }
+ if (strpos($expr,'()')) if ($a = $this->getLinkMethod($expr,$class,$package)) return $a;
+ if (is_numeric(strpos($expr,'$'))) if ($a = $this->getLinkVar($expr,$class,$package)) return $a;
+ }
+ }
+ if ($test = Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test;
+ if ($test = Converter::getPageLink(trim($expr),$package)) return $test;
+ if ($test = Converter::getDefineLink(trim($expr),$package)) return $test;
+ if ($test = Converter::getGlobalLink(trim($expr),$package)) return $test;
+// if (strpos($expr,'.'))
+ // package specified
+
+ if (!is_array($packages))
+ {
+ $packages = $this->all_packages;
+ }
+ do
+ {
+ if (isset($packages[$package])) unset($packages[$package]);
+ if ($test = Converter::getClassLink(str_replace('object ','',$expr),$package)) return $test;
+ if ($test = Converter::getPageLink($expr,$package)) return $test;
+ if ($test = Converter::getDefineLink($expr,$package)) return $test;
+ if ($test = Converter::getGlobalLink($expr,$package)) return $test;
+ // is $expr in class::method() or class::$variable format?
+ if (strpos($expr,'function ') === 0)
+ { // asking for a function, not a method
+ if ($test = Converter::getFunctionLink(str_replace('function','',str_replace('()','',$expr)), $package)) return $test;
+ else return $expr;
+ }
+ $test = $this->_getDoubleColon($expr, $package, $packages, $class, $links);
+ if (!is_string($test)) return $test;
+ if (strpos($test, 'parent::') === 0) return $test;
+ // $expr does not have ::
+ if (is_numeric(@strpos('$',$expr)))
+ {
+ // default to current class, whose name is contained in $this->render->parent
+ if ($test = Converter::getVarLink($expr, $class, $package)) return $test;
+ }
+ // $expr is a function? (non-method)
+ if (@strpos($expr,'()'))
+ {
+ // otherwise, see if it is a method
+ if ($class)
+ {
+ if ($test = Converter::getMethodLink(str_replace('()','',$expr), $class, $package)) return $test;
+ }
+ // extract the function name, use it to retrieve the file that the function is in
+ // $page = $this->func_page[str_replace('function ','',str_replace('()','',$expr))];
+ // return the link
+ if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test;
+ }
+ // $expr is just a word. First, test to see if it is a function of the current package
+ if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test;
+ // try other packages
+ // look in parent package first, if found
+ if (isset($this->package_parents[$package]) && in_array($this->package_parents[$package], $packages))
+ {
+ $p1 = $package;
+ $package = $this->package_parents[$package];
+ if ($package)
+ {
+ if (isset($packages[$package])) unset($packages[$package]);
+ }
+ continue;
+ }
+ // no parent package, so start with the first one that's left
+ $package = @array_shift(@array_keys($packages));
+ if ($package && isset($packages[$package]))
+ {
+ unset($packages[$package]);
+ }
+ } while (count($packages) || $package);
+ $funcs = get_defined_functions();
+ // feature 564991, link to php manual
+ if (in_array(str_replace(array('(',')'),array('',''),$expr),$funcs['internal']))
+ {
+ $return = 'http://www.php.net/'.str_replace(array('(',')'),array('',''),$expr);
+ return $return;
+ }
+ // no links found
+ return $expr;
+ }
+
+ /**
+ * Split up getLink to make it easier to debug
+ * @access private
+ */
+ function _getDoubleColon(&$expr, &$package, &$packages, $class, $links)
+ {
+ if (@strpos($expr,'::'))
+ {
+ $class_method = explode('::',$expr);
+ if ($class_method[0] == 'parent')
+ {
+ // can only have parent in the same package as the class! subtle bug
+ $package = $this->package;
+ $packages = array();
+ $cl = $this->classes->getClassByPackage($class,$package);
+ if (!$cl)
+ { // this is possible if an example file has parent::method()
+ return $expr;
+ }
+ $par = $cl->getParent($this);
+ $phpparent = false;
+ if (is_object($par))
+ {
+ $package = $par->docblock->package;
+ $phpparent = $par->getName();
+ } else
+ {
+ addWarning(PDERROR_CLASS_PARENT_NOT_FOUND,$class,$package,$class_method[1]);
+ return $expr;
+ }
+ if ($phpparent) $class_method[0] = $phpparent;
+ }
+ if (strpos($class_method[1],'()'))
+ {
+ // strip everything but the function name, return a link
+ if ($test = Converter::getMethodLink(str_replace('()','',$class_method[1]), $class_method[0], $package)) return $test;
+ }
+ if ($test = Converter::getVarLink($class_method[1], $class_method[0], $package)) return $test;
+ if ($test = Converter::getConstLink($class_method[1], $class_method[0], $package)) return $test;
+ }
+ return $expr;
+ }
+
+ /**
+ * cycle through parent classes to retrieve a link to a method
+ * do not use or override, used by getLink
+ * @access private
+ */
+ function &getLinkMethod($expr, $class, $package)
+ {
+ $links = &$this->links;
+ do
+ {
+ // is $expr in class::method() or class::$variable format?
+ if (@strpos($expr,'::'))
+ {
+ $class_method = explode('::',$expr);
+ if ($class_method[0] == 'parent')
+ {
+ $cl = $this->classes->getClassByPackage($class,$package);
+ $par = $cl->getParent($this);
+ $phpparent = false;
+ if (is_object($par))
+ {
+ $package = $par->docblock->package;
+ $phpparent = $par->getName();
+ } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
+ if ($phpparent) $class_method[0] = $phpparent;
+ } else
+ {
+ $cl = $this->classes->getClassByPackage($class,$package);
+ }
+ if (strpos($class_method[1],'()'))
+ {
+ // strip everything but the function name, return a link
+ if ($test = Converter::getMethodLink(str_replace('function ','',str_replace('()','',$class_method[1])), $class_method[0], $package)) return $test;
+ }
+ }
+ if ($test = Converter::getMethodLink(str_replace('()','',$expr), $class, $package)) return $test;
+ $cl = $this->classes->getClassByPackage($class,$package);
+ if ($cl)
+ {
+ $par = $cl->getParent($this);
+ if (is_object($par))
+ {
+ $package = $par->docblock->package;
+ $class = $par->getName();
+ } else $class = $par;
+ } else $class = false;
+ } while ($class);
+ // no links found
+ $flag = false;
+ return $flag;
+ }
+
+ /**
+ * cycle through parent classes to retrieve a link to a var
+ * do not use or override, used by getLink
+ * @access private
+ */
+ function &getLinkVar($expr, $class, $package)
+ {
+ $links = &$this->links;
+ do
+ {
+ // is $expr in class::method() or class::$variable format?
+ if (@strpos($expr,'::'))
+ {
+ $class_method = explode('::',$expr);
+ if ($class_method[0] == 'parent')
+ {
+ $cl = $this->classes->getClassByPackage($class,$package);
+ $phpparent = false;
+ $par = $cl->getParent($this);
+ if (is_object($par))
+ {
+ $package = $par->docblock->package;
+ $phpparent = $par->getName();
+ } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
+ if ($phpparent) $class_method[0] = $phpparent;
+ } else
+ {
+ $cl = $this->classes->getClassByPackage($class,$package);
+ }
+ if ($test = Converter::getVarLink($class_method[1], $class_method[0], $package)) return $test;
+ if ($test = Converter::getVarLink('$'.$class_method[1], $class_method[0], $package)) return $test;
+ }
+ if ($test = Converter::getVarLink($expr, $class, $package)) return $test;
+ if ($test = Converter::getVarLink('$'.$expr, $class, $package)) return $test;
+ $cl = $this->classes->getClassByPackage($class,$package);
+ if ($cl)
+ {
+ $par = $cl->getParent($this);
+ if (is_object($par))
+ {
+ $package = $par->docblock->package;
+ $class = $par->getName();
+ } else $class = $par;
+ } else $class = false;
+ } while ($class);
+ // no links found
+ $class = false;
+ return $class;
+ }
+
+ /**
+ * cycle through parent classes to retrieve a link to a class constant
+ * do not use or override, used by getLink
+ * @access private
+ * @since 1.2.4
+ */
+ function &getLinkConst($expr, $class, $package)
+ {
+ $links = &$this->links;
+ do
+ {
+ // is $expr in class::method() or class::$variable format?
+ if (@strpos($expr,'::'))
+ {
+ $class_method = explode('::',$expr);
+ if ($class_method[0] == 'parent')
+ {
+ $cl = $this->classes->getClassByPackage($class,$package);
+ $phpparent = false;
+ $par = $cl->getParent($this);
+ if (is_object($par))
+ {
+ $package = $par->docblock->package;
+ $phpparent = $par->getName();
+ } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
+ if ($phpparent) $class_method[0] = $phpparent;
+ } else
+ {
+ $cl = $this->classes->getClassByPackage($class,$package);
+ }
+ if ($test = Converter::getConstLink($class_method[1], $class_method[0], $package)) return $test;
+ }
+ if ($test = Converter::getConstLink($expr, $class, $package)) return $test;
+ $cl = $this->classes->getClassByPackage($class,$package);
+ if ($cl)
+ {
+ $par = $cl->getParent($this);
+ if (is_object($par))
+ {
+ $package = $par->docblock->package;
+ $class = $par->getName();
+ } else $class = $par;
+ } else $class = false;
+ } while ($class);
+ // no links found
+ $flag = false;
+ return $flag;
+ }
+
+ /**
+ * take URL $link and text $text and return a link in the format needed for the Converter
+ * @param string URL
+ * @param string text to display
+ * @return string link to $link
+ * @abstract
+ */
+ function returnLink($link,$text)
+ {
+ }
+
+ /**
+ * take {@link abstractLink} descendant and text $eltext and return a link
+ * in the format needed for the Converter
+ * @param abstractLink
+ * @param string
+ * @return string link to $element
+ * @abstract
+ */
+ function returnSee(&$link, $eltext = false)
+ {
+ }
+
+ /**
+ * take {@link abstractLink} descendant and text $eltext and return a
+ * unique ID in the format needed for the Converter
+ * @param abstractLink
+ * @return string unique identifier of $element
+ * @abstract
+ */
+ function getId(&$link)
+ {
+ }
+
+ /**
+ * Convert README/INSTALL/CHANGELOG file contents to output format
+ * @param README|INSTALL|CHANGELOG
+ * @param string contents of the file
+ * @abstract
+ */
+ function Convert_RIC($name, $contents)
+ {
+ }
+
+ /**
+ * Convert all elements to output format
+ *
+ * This will call ConvertXxx where Xxx is {@link ucfirst}($element->type).
+ * It is expected that a child converter defines a handler for every
+ * element type, even if that handler does nothing. phpDocumentor will
+ * terminate with an error if a handler doesn't exist.
+ * {@internal
+ * Since 1.2.0 beta 3, this function has been moved from child converters
+ * to the parent, because it doesn't really make sense to put it in the
+ * child converter, and we can add error handling.
+ *
+ * {@source}}}
+ * @throws {@link PDERROR_NO_CONVERT_HANDLER}
+ * @param mixed {@link parserElement} descendant or {@link parserPackagePage} or {@link parserData}
+ */
+ function Convert(&$element)
+ {
+ $handler = 'convert'.ucfirst($element->type);
+ if (method_exists($this,$handler))
+ {
+ $this->$handler($element);
+ } else
+ {
+ addErrorDie(PDERROR_NO_CONVERTER_HANDLER,$element->type,$handler,phpDocumentor_get_class($this));
+ }
+ }
+ /**#@+
+ * Conversion Handlers
+ *
+ * All of the convert* handlers set up template variables for the Smarty
+ * template.{@internal In addition, the {@link newSmarty()} method is
+ * called to retrieve the global Smarty template}}
+ */
+ /**
+ * Default Tutorial Handler
+ *
+ * Sets up the tutorial template, and its prev/next/parent links
+ * {@internal
+ * Retrieves the title using {@link parserTutorial::getTitle()} and uses the
+ * {@link parserTutorial::prev, parserTutorial::next, parserTutorial::parent}
+ * links to set up those links.}}
+ * @param parserTutorial
+ */
+ function &convertTutorial(&$element)
+ {
+ $this->package = $element->package;
+ $this->subpackage = $element->subpackage;
+ $x = $element->Convert($this);
+ $template = &$this->newSmarty();
+ $template->assign('contents',$x);
+ $template->assign('title',$element->getTitle($this));
+ $template->assign('nav',$element->parent || $element->prev || $element->next);
+ if ($element->parent)
+ {
+ $template->assign('up',$this->getId($element->parent));
+ $template->assign('uptitle',$element->parent->title);
+ }
+ if ($element->prev)
+ {
+ $template->assign('prev',$this->getId($element->prev));
+ $template->assign('prevtitle',$element->prev->title);
+ }
+ if ($element->next)
+ {
+ $template->assign('next',$this->getId($element->next));
+ $template->assign('nexttitle',$element->next->title);
+ }
+ return $template;
+ }
+ /**
+ * Default Class Handler
+ *
+ * Sets up the class template.
+ * {@internal special methods
+ * {@link generateChildClassList(), generateFormattedClassTree()},
+ * {@link getFormattedConflicts, getFormattedInheritedMethods},
+ * and {@link getFormattedInheritedVars} are called to complete vital
+ * template setup.}}
+ */
+ function convertClass(&$element)
+ {
+ $this->class = $element->getName();
+ $this->class_data = &$this->newSmarty();
+ $this->class_data->assign("class_name",$element->getName());
+ $this->class_data->assign("vars",array());
+ $this->class_data->assign("methods",array());
+ $this->class_data->assign("consts",array());
+ $this->class_data->assign("is_interface", $element->isInterface());
+ $this->class_data->assign("implements", $this->getFormattedImplements($element));
+ $this->class_data->assign("package",$element->docblock->package);
+ $this->class_data->assign("line_number",$element->getLineNumber());
+ $this->class_data->assign("source_location",$element->getSourceLocation($this));
+ $this->class_data->assign("page_link",$this->getCurrentPageLink());
+ $docblock = $this->prepareDocBlock($element, false);
+ $this->class_data->assign("sdesc",$docblock['sdesc']);
+ $this->class_data->assign("desc",$docblock['desc']);
+ $this->class_data->assign("access", $docblock['access']);
+ $this->class_data->assign("abstract", $docblock['abstract']);
+ $this->class_data->assign("tags",$docblock['tags']);
+ $this->class_data->assign("api_tags",$docblock['api_tags']);
+ $this->class_data->assign("info_tags",$docblock['info_tags']);
+ $this->class_data->assign("utags",$docblock['utags']);
+ $this->class_data->assign( "prop_tags", $docblock['property_tags'] );
+ if ($this->hasSourceCode($element->getPath())) {
+ $this->class_data->assign("class_slink",$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true));
+ }
+
+ else
+ $this->class_data->assign("class_slink",false);
+ $this->class_data->assign("children", $this->generateChildClassList($element));
+ $this->class_data->assign("class_tree", $this->generateFormattedClassTree($element));
+ $this->class_data->assign("conflicts", $this->getFormattedConflicts($element,"classes"));
+ $inherited_methods = $this->getFormattedInheritedMethods($element);
+ if (!empty($inherited_methods))
+ {
+ $this->class_data->assign("imethods",$inherited_methods);
+ } else
+ {
+ $this->class_data->assign("imethods",false);
+ }
+ $inherited_vars = $this->getFormattedInheritedVars($element);
+ if (!empty($inherited_vars))
+ {
+ $this->class_data->assign("ivars",$inherited_vars);
+ } else
+ {
+ $this->class_data->assign("ivars",false);
+ }
+ $inherited_consts = $this->getFormattedInheritedConsts($element);
+ if (!empty($inherited_consts))
+ {
+ $this->class_data->assign("iconsts",$inherited_consts);
+ } else
+ {
+ $this->class_data->assign("iconsts",false);
+ }
+ }
+
+
+ /**
+ * Converts method for template output
+ *
+ * This function must be called by a child converter with any extra
+ * template variables needed in the parameter $addition
+ * @param parserMethod
+ */
+ function convertMethod(&$element, $additions = array())
+ {
+ $fname = $element->getName();
+ $docblock = $this->prepareDocBlock($element);
+ $returntype = 'void';
+ if ($element->isConstructor) $returntype = $element->class;
+ if ($element->docblock->return)
+ {
+ $a = $element->docblock->return->Convert($this);
+ $returntype = $element->docblock->return->converted_returnType;
+ }
+ $params = $param_i = array();
+ if (count($element->docblock->params))
+ foreach($element->docblock->params as $param => $val)
+ {
+ $a = $val->Convert($this);
+ $params[] = $param_i[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
+ }
+
+ if ($element->docblock->hasaccess) {
+ $acc = $docblock['access'];
+ } else {
+ $acc = 'public';
+ }
+
+ if ($this->hasSourceCode($element->getPath()))
+ $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
+ $this->class_data->append('methods',array_merge(
+ array('sdesc' => $docblock['sdesc'],
+ 'desc' => $docblock['desc'],
+ 'static' => $docblock['static'],
+ 'abstract' => $docblock['abstract'],
+ 'tags' => $docblock['tags'],
+ 'api_tags' => $docblock['api_tags'],
+ 'see_tags' => $docblock['see_tags'],
+ 'info_tags_sorted' => $docblock['info_tags_sorted'],
+ 'info_tags' => $docblock['info_tags'],
+ 'utags' => $docblock['utags'],
+ 'constructor' => $element->isConstructor,
+ 'access' => $acc,
+ 'function_name' => $fname,
+ 'function_return' => $returntype,
+ 'function_call' => $element->getFunctionCall(),
+ 'ifunction_call' => $element->getIntricateFunctionCall($this, $param_i),
+ 'descmethod' => $this->getFormattedDescMethods($element),
+ 'method_overrides' => $this->getFormattedOverrides($element),
+ 'method_implements' => $this->getFormattedMethodImplements($element),
+ 'line_number' => $element->getLineNumber(),
+ 'id' => $this->getId($element),
+ 'params' => $params),
+ $additions));
+ }
+
+ /**
+ * Converts class variables for template output.
+ *
+ * This function must be called by a child converter with any extra
+ * template variables needed in the parameter $addition
+ * @param parserVar
+ */
+ function convertVar(&$element, $additions = array())
+ {
+ $docblock = $this->prepareDocBlock($element);
+ $b = 'mixed';
+
+ if ($element->docblock->hasaccess)
+ $acc = $element->docblock->tags['access'][0]->value;
+ else
+ $acc = 'public';
+
+ if ($element->docblock->var)
+ {
+ $b = $element->docblock->var->converted_returnType;
+ }
+ if ($this->hasSourceCode($element->getPath()))
+ $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
+ $this->class_data->append('vars',array_merge(
+ array('sdesc' => $docblock['sdesc'],
+ 'desc' => $docblock['desc'],
+ 'static' => $docblock['static'],
+ 'abstract' => $docblock['abstract'],
+ 'utags' => $docblock['utags'],
+ 'tags' => $docblock['tags'],
+ 'api_tags' => $docblock['api_tags'],
+ 'info_tags' => $docblock['info_tags'],
+ 'var_name' => $element->getName(),
+ 'has_default' => strlen($element->getValue()),
+ 'var_default' => $this->postProcess($element->getValue()),
+ 'var_type' => $b,
+ 'access' => $acc,
+ 'line_number' => $element->getLineNumber(),
+ 'descvar' => $this->getFormattedDescVars($element),
+ 'var_overrides' => $this->getFormattedOverrides($element),
+ 'id' => $this->getId($element)),
+ $additions));
+ }
+
+ /**
+ * Converts class constants for template output.
+ *
+ * This function must be called by a child converter with any extra
+ * template variables needed in the parameter $addition
+ * @param parserConst
+ */
+ function convertConst(&$element, $additions = array())
+ {
+ $docblock = $this->prepareDocBlock($element);
+
+ if ($element->docblock->hasaccess)
+ $acc = $element->docblock->tags['access'][0]->value;
+ else
+ $acc = 'public';
+
+ if ($this->hasSourceCode($element->getPath()))
+ $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
+ $this->class_data->append('consts',array_merge(
+ array('sdesc' => $docblock['sdesc'],
+ 'desc' => $docblock['desc'],
+ 'access' => $docblock['access'],
+ 'abstract' => $docblock['abstract'],
+ 'utags' => $docblock['utags'],
+ 'tags' => $docblock['tags'],
+ 'api_tags' => $docblock['api_tags'],
+ 'info_tags' => $docblock['info_tags'],
+ 'const_name' => $element->getName(),
+ 'const_value' => $this->postProcess($element->getValue()),
+ 'access' => $acc,
+ 'line_number' => $element->getLineNumber(),
+ 'id' => $this->getId($element)),
+ $additions));
+ }
+
+ /**
+ * Default Page Handler
+ *
+ * {@internal In addition to setting up the smarty template with {@link newSmarty()},
+ * this class uses {@link getSourceLocation()} and {@link getClassesOnPage()}
+ * to set template variables. Also used is {@link getPageName()}, to get
+ * a Converter-specific name for the page.}}
+ * @param parserPage
+ */
+ function convertPage(&$element)
+ {
+ $this->page_data = &$this->newSmarty(true);
+ $this->page = $this->getPageName($element->parent);
+ $this->path = $element->parent->getPath();
+ $this->curpage = &$element->parent;
+ $this->page_data->assign("source_location",$element->parent->getSourceLocation($this));
+ $this->page_data->assign("functions",array());
+ $this->page_data->assign("includes",array());
+ $this->page_data->assign("defines",array());
+ $this->page_data->assign("globals",array());
+ $this->page_data->assign("classes",$this->getClassesOnPage($element));
+ $this->page_data->assign("hasclasses",$element->hasClasses());
+ $this->page_data->assign("hasinterfaces",$element->hasInterfaces());
+ $this->page_data->assign("name", $element->parent->getFile());
+ if ($t = $element->getTutorial())
+ {
+ $this->page_data->assign("tutorial",$this->returnSee($t));
+ } else
+ {
+ $this->page_data->assign("tutorial",false);
+ }
+ if ($element->docblock)
+ {
+ $docblock = $this->prepareDocBlock($element, false);
+ $this->page_data->assign("sdesc",$docblock['sdesc']);
+ $this->page_data->assign("desc",$docblock['desc']);
+ $this->page_data->assign("tags",$docblock['tags']);
+ $this->page_data->assign("api_tags",$docblock['api_tags']);
+ $this->page_data->assign("info_tags",$docblock['info_tags']);
+ $this->page_data->assign("utags",$docblock['utags']);
+ }
+ }
+
+ /**
+ * Converts global variables for template output
+ *
+ * This function must be called by a child converter with any extra
+ * template variables needed in the parameter $addition
+ * {@internal
+ * In addition to using {@link prepareDocBlock()}, this method also
+ * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}
+ * @param parserGlobal
+ * @uses postProcess() on global_value template value, makes it displayable
+ * @param array any additional template variables should be in this array
+ */
+ function convertGlobal(&$element, $addition = array())
+ {
+ $docblock = $this->prepareDocBlock($element);
+ $value = $this->getGlobalValue($element->getValue());
+ if ($this->hasSourceCode($element->getPath()))
+ $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
+ $this->page_data->append('globals',array_merge(
+ array('sdesc' => $docblock['sdesc'],
+ 'desc' => $docblock['desc'],
+ 'tags' => $docblock['tags'],
+ 'api_tags' => $docblock['api_tags'],
+ 'info_tags' => $docblock['info_tags'],
+ 'utags' => $docblock['utags'],
+ 'global_name' => $element->getName(),
+ 'global_type' => $element->getDataType($this),
+ 'global_value' => $value,
+ 'line_number' => $element->getLineNumber(),
+ 'global_conflicts' => $this->getFormattedConflicts($element,"global variables"),
+ 'id' => $this->getId($element)),
+ $addition));
+ }
+
+ /**
+ * Converts defines for template output
+ *
+ * This function must be called by a child converter with any extra
+ * template variables needed in the parameter $addition
+ * {@internal
+ * In addition to using {@link prepareDocBlock()}, this method also
+ * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}
+ * @param parserDefine
+ * @uses postProcess() on define_value template value, makes it displayable
+ * @param array any additional template variables should be in this array
+ */
+ function convertDefine(&$element, $addition = array())
+ {
+ $docblock = $this->prepareDocBlock($element);
+ if ($this->hasSourceCode($element->getPath()))
+ $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
+ $this->page_data->append('defines',array_merge(
+ array('sdesc' => $docblock['sdesc'],
+ 'desc' => $docblock['desc'],
+ 'tags' => $docblock['tags'],
+ 'api_tags' => $docblock['api_tags'],
+ 'info_tags' => $docblock['info_tags'],
+ 'utags' => $docblock['utags'],
+ 'define_name' => $element->getName(),
+ 'line_number' => $element->getLineNumber(),
+ 'define_value' => $this->postProcess($element->getValue()),
+ 'define_conflicts' => $this->getFormattedConflicts($element,"defines"),
+ 'id' => $this->getId($element)),
+ $addition));
+ }
+
+
+ /**
+ * Converts includes for template output
+ *
+ * This function must be called by a child converter with any extra
+ * template variables needed in the parameter $addition
+ * @see prepareDocBlock()
+ * @param parserInclude
+ */
+ function convertInclude(&$element, $addition = array())
+ {
+ $docblock = $this->prepareDocBlock($element);
+ $per = $this->getIncludeValue($element->getValue(), $element->getPath());
+
+ if ($this->hasSourceCode($element->getPath()))
+ $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
+ $this->page_data->append('includes',array_merge(
+ array('sdesc' => $docblock['sdesc'],
+ 'desc' => $docblock['desc'],
+ 'tags' => $docblock['tags'],
+ 'api_tags' => $docblock['api_tags'],
+ 'info_tags' => $docblock['info_tags'],
+ 'utags' => $docblock['utags'],
+ 'include_name' => $element->getName(),
+ 'line_number' => $element->getLineNumber(),
+ 'include_value' => $per),
+ $addition));
+ }
+
+ /**
+ * Converts function for template output
+ *
+ * This function must be called by a child converter with any extra
+ * template variables needed in the parameter $addition
+ * @see prepareDocBlock()
+ * @param parserFunction
+ */
+ function convertFunction(&$element, $addition = array())
+ {
+ $docblock = $this->prepareDocBlock($element);
+ $fname = $element->getName();
+ $params = $param_i = array();
+ if (count($element->docblock->params))
+ foreach($element->docblock->params as $param => $val)
+ {
+ $a = $val->Convert($this);
+ $params[] = $param_i[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
+ }
+ $returntype = 'void';
+ if ($element->docblock->return)
+ {
+ $a = $element->docblock->return->Convert($this);
+ $returntype = $element->docblock->return->converted_returnType;
+ }
+
+ if ($this->hasSourceCode($element->getPath()))
+ $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
+ $this->page_data->append('functions',array_merge(
+ array('sdesc' => $docblock['sdesc'],
+ 'desc' => $docblock['desc'],
+ 'tags' => $docblock['tags'],
+ 'api_tags' => $docblock['api_tags'],
+ 'info_tags' => $docblock['info_tags'],
+ 'utags' => $docblock['utags'],
+ 'function_name' => $fname,
+ 'function_return' => $returntype,
+ 'function_conflicts' => $this->getFormattedConflicts($element,"functions"),
+ 'ifunction_call' => $element->getIntricateFunctionCall($this, $param_i),
+ 'function_call' => $element->getFunctionCall(),
+ 'line_number' => $element->getLineNumber(),
+ 'id' => $this->getId($element),
+ 'params' => $params),
+ $addition));
+ }
+ /**#@-*/
+
+ /**
+ * convert the element's DocBlock for output
+ *
+ * This function converts all tags and descriptions for output
+ * @param mixed any descendant of {@link parserElement}, or {@link parserData}
+ * @param array used to translate tagnames into other tags
+ * @param boolean set to false for pages and classes, the only elements allowed to specify @package
+ * @return array
+ *
+ * Format:
+ *
+ * array('sdesc' => DocBlock summary
+ * 'desc' => DocBlock detailed description
+ * 'tags' => array('keyword' => tagname, 'data' => tag description)
+ * known tags
+ * 'api_tags' => array('keyword' => tagname, 'data' => tag description)
+ * known api documentation tags
+ * 'info_tags' => array('keyword' => tagname, 'data' => tag description)
+ * known informational tags
+ * [ 'utags' => array('keyword' => tagname, 'data' => tag description
+ * unknown tags ]
+ * [ 'vartype' => type from @var/@return tag ]
+ * [ 'var_descrip' => description from @var/@return tag ]
+ * )
+ *
+ */
+ function prepareDocBlock(&$element, $names = array(),$nopackage = true)
+ {
+ $tagses = $element->docblock->listTags();
+ $tags = $ret = $api_tags = $info_tags = array();
+ $api_tags_arr = array("abstract", "access", "deprecated", "example", "filesource",
+ "global", "internal", "name", "return", "see",
+ "property", "property-read", "property-write", "method",
+ "staticvar", "usedby", "uses", "var");
+ if (!$nopackage)
+ {
+ $tags[] = array('keyword' => 'package','data' => $element->docblock->package);
+ if (!empty($element->docblock->subpackage)) $tags[] = array('keyword' => 'subpackage','data' => $element->docblock->subpackage);
+ }
+ if ($element->docblock->var)
+ {
+ $a = $element->docblock->var->Convert($this);
+ $ret['vartype'] = $element->docblock->var->converted_returnType;
+ if (!empty($a))
+ {
+ $tags[] = array('keyword' => 'var', 'data' => $a);
+ $ret["var_descrip"] = $a;
+ }
+ }
+ if ($element->docblock->return)
+ {
+ $a = $element->docblock->return->Convert($this);
+ $ret['vartype'] = $element->docblock->return->converted_returnType;
+ if (!empty($a))
+ {
+ $tags[] = $api_tags[] = array('keyword' => 'return', 'data' => $a);
+ $ret["var_descrip"] = $a;
+ }
+ }
+ if ($element->docblock->funcglobals)
+ foreach($element->docblock->funcglobals as $global => $val)
+ {
+ if ($a = $this->getGlobalLink($global,$element->docblock->package))
+ {
+ $global = $a;
+ }
+ $b = Converter::getLink($val[0]);
+ if (is_object($b) && phpDocumentor_get_class($b) == 'classlink')
+ {
+ $val[0] = $this->returnSee($b);
+ }
+ $tags[] = $api_tags[] = array('keyword' => 'global','data' => $val[0].' '.$global.': '.$val[1]->Convert($this));
+ }
+ if ($element->docblock->statics)
+ foreach($element->docblock->statics as $static => $val)
+ {
+ $a = $val->Convert($this);
+ $tags[] = $api_tags[] = array('keyword' => 'staticvar','data' => $val->converted_returnType.' '.$static.': '.$a);
+ }
+ $property_tags = array();
+ foreach ( $element->docblock->properties as $prop_name => $val )
+ {
+ $a = $val->Convert( $this );
+ if ( !empty( $a ) )
+ {
+ $tags[] = $api_tags[] = array( 'keyword' => $val->keyword ,
+ 'data' => $val->converted_returnType . ' ' . $prop_name . ': ' . $a );
+ $prop['prop_name'] = $prop_name;
+ $prop['access'] = $val->keyword == 'property-read' ? 'read' :
+ ( $val->keyword == 'property-write' ? 'write' : 'read/write' );
+ $prop['prop_type'] = $val->converted_returnType;
+ $prop['sdesc'] = $a;
+ $property_tags[ $prop_name ] = $prop;
+ }
+ }
+ ksort( $property_tags, SORT_STRING );
+ $property_tags = array_values( $property_tags );
+ $info_tags_sorted = array();
+ $ret['static'] = false;
+ foreach($tagses as $tag)
+ {
+ if (isset($names[$tag->keyword])) $tag->keyword = $names[$tag->keyword];
+ if ($tag->keyword == 'static') {
+ $ret['static'] = true;
+ continue;
+ }
+ if ($tag->keyword)
+ $tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
+ if (in_array($tag->keyword, $api_tags_arr)) {
+ $api_tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
+ } else {
+ $info_tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
+ @list( $className, $desc ) = explode( " ", $tag->Convert($this), 2 );
+ $info_tags_sorted[ $tag->keyword ][] = array( 'keyword' => $className, 'data' => $desc );
+ }
+ }
+ $utags = array();
+ foreach($element->docblock->unknown_tags as $keyword => $tag)
+ {
+ foreach($tag as $t)
+ $utags[] = array('keyword' => $keyword, 'data' => $t->Convert($this));
+ }
+ $ret['abstract'] = false;
+ $ret['access'] = 'public';
+ $see_tags = array();
+ foreach($tags as $tag)
+ {
+ if ($tag['keyword'] == 'access') {
+ $ret['access'] = $tag['data'];
+ }
+ if ($tag['keyword'] == 'abstract') {
+ $ret['abstract'] = true;
+ }
+ if ($tag['keyword'] == 'see' || $tag['keyword'] == 'uses' ||
+ $tag['keyword'] == 'usedby') {
+ $see_tags[] = $tag['data'];
+ }
+ }
+ $ret['sdesc'] = $element->docblock->getSDesc($this);
+ $ret['desc'] = $element->docblock->getDesc($this);
+ $ret['tags'] = $tags;
+ $ret['see_tags'] = $see_tags;
+ $ret['info_tags_sorted'] = $info_tags_sorted;
+ $ret['api_tags'] = $api_tags;
+ $ret['info_tags'] = $info_tags;
+ $ret['utags'] = $utags;
+ $ret['property_tags'] = $property_tags;
+ return $ret;
+ }
+
+ /**
+ * gets a list of all classes declared on a procedural page represented by
+ * $element, a {@link parserData} class
+ * @param parserData &$element
+ * @return array links to each classes documentation
+ *
+ * Format:
+ *
+ * array('name' => class name,
+ * 'sdesc' => summary of the class
+ * 'link' => link to the class's documentation)
+ *
+ */
+ function getClassesOnPage(&$element)
+ {
+ global $_phpDocumentor_setting;
+ $a = $element->getClasses($this);
+ $classes = array();
+ foreach($a as $package => $clas)
+ {
+ if (!empty($_phpDocumentor_setting['packageoutput']))
+ {
+ $packages = explode(',',$_phpDocumentor_setting['packageoutput']);
+ if (!in_array($package, $packages)) continue;
+ }
+ for($i=0; $iparseprivate || ! ($clas[$i]->docblock && $clas[$i]->docblock->hasaccess && $clas[$i]->docblock->tags['access'][0]->value == 'private'))
+ {
+ $sdesc = '';
+ $r = array();
+ $sdesc = $clas[$i]->docblock->getSDesc($this);
+ if ($clas[$i]->docblock->hasaccess)
+ $r['access'] = $clas[$i]->docblock->tags['access'][0]->value;
+ else
+ $r['access'] = 'public';
+ if (isset ($clas[$i]->docblock->tags['abstract']))
+ $r['abstract'] = TRUE;
+ else
+ $r['abstract'] = FALSE;
+ $r['name'] = $clas[$i]->getName();
+ $r['sdesc'] = $sdesc;
+ $r['link'] = $this->getClassLink($clas[$i]->getName(),$package,$clas[$i]->getPath());
+ $classes[] = $r;
+ }
+ }
+ }
+ return $classes;
+ }
+
+ /**
+ * returns an array containing the class inheritance tree from the root
+ * object to the class.
+ *
+ * This method must be overridden, or phpDocumentor will halt with a fatal
+ * error
+ * @return string Converter-specific class tree for an individual class
+ * @param parserClass class variable
+ * @abstract
+ */
+
+ function generateFormattedClassTree($class)
+ {
+ addErrorDie(PDERROR_CONVERTER_OVR_GFCT,phpDocumentor_get_class($this));
+ }
+
+ /**
+ * returns an array containing the class inheritance tree from the root
+ * object to the class.
+ *
+ * This method must be overridden, or phpDocumentor will halt with a fatal
+ * error
+ * @return string Converter-specific class tree for an individual class
+ * @param parserClass class variable
+ * @abstract
+ */
+
+ function getFormattedImplements($el)
+ {
+ $ret = array();
+ foreach ($el->getImplements() as $interface)
+ {
+ $link = $this->getLink($interface);
+ if ($link && is_object($link)) {
+ $ret[] = $this->returnSee($link);
+ } else {
+ if (class_exists('ReflectionClass')) {
+ if (interface_exists($interface)) {
+ $inter = new ReflectionClass($interface);
+ if ($inter->isInternal()) {
+ $ret[] = $interface . ' (internal interface)';
+ } else {
+ $ret[] = $interface;
+ }
+ }
+ } else {
+ $ret[] = $interface;
+ }
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * @param mixed {@link parserClass, parserFunction, parserDefine} or
+ * {@link parserGlobal}
+ * @param string type to display. either 'class','function','define'
+ * or 'global variable'
+ * @return array links to conflicting elements, or empty array
+ * @uses parserClass::getConflicts()
+ * @uses parserFunction::getConflicts()
+ * @uses parserDefine::getConflicts()
+ * @uses parserGlobal::getConflicts()
+ */
+ function getFormattedConflicts(&$element,$type)
+ {
+ $conflicts = $element->getConflicts($this);
+ $r = array();
+ if (!$conflicts) return false;
+ foreach($conflicts as $package => $class)
+ {
+ $r[] = $class->getLink($this,$class->docblock->package);
+ }
+ if (!empty($r)) $r = array('conflicttype' => $type, 'conflicts' => $r);
+ return $r;
+ }
+
+ /**
+ * Get a list of methods in child classes that override this method
+ * @return array empty array or array(array('link'=>link to method,
+ * 'sdesc'=>short description of the method),...)
+ * @uses parserMethod::getOverridingMethods()
+ * @param parserMethod
+ */
+ function getFormattedDescMethods(&$element)
+ {
+ $meths = $element->getOverridingMethods($this);
+ $r = array();
+ for($i=0; $igetLink($this);
+ $ms['sdesc'] = $meths[$i]->docblock->getSDesc($this);
+ $r[] = $ms;
+ }
+ return $r;
+ }
+
+ /**
+ * Get a list of vars in child classes that override this var
+ * @return array empty array or array('link'=>link to var,
+ * 'sdesc'=>short description of the method
+ * @uses parserVar::getOverridingVars()
+ * @param parserVar
+ */
+ function getFormattedDescVars(&$element)
+ {
+ $vars = $element->getOverridingVars($this);
+ $r = array();
+ for($i=0; $igetLink($this);
+ $vs['sdesc'] = $vars[$i]->docblock->getSDesc($this);
+ $r[] = $vs;
+ }
+ return $r;
+ }
+
+ /**
+ * Get the method this method overrides, if any
+ * @return array|false array('link'=>link to overridden method,
+ * 'sdesc'=>short description
+ * @see parserMethod::getOverrides()
+ * @param parserMethod
+ */
+ function getFormattedOverrides(&$element)
+ {
+ $ovr = $element->getOverrides($this);
+ if (!$ovr) return false;
+ $sdesc = $ovr->docblock->getSDesc($this);
+ $name = method_exists($ovr, 'getFunctionCall') ? $ovr->getFunctionCall() : $ovr->getName();
+ $link = ($link = $ovr->getLink($this)) ? $link : $ovr->getClass() . '::' . $name;
+ return array('link' => $link,'sdesc' => $sdesc);
+ }
+
+ /**
+ * Get the method this method(s) implemented from an interface, if any
+ * @return array|false array('link'=>link to implemented method,
+ * 'sdesc'=>short description
+ * @uses parserMethod::getImplements()
+ * @param parserMethod
+ */
+ function getFormattedMethodImplements(&$element)
+ {
+ $ovr = $element->getImplements($this);
+ if (!$ovr) return false;
+ $ret = array();
+ foreach ($ovr as $impl) {
+ $sdesc = $impl->docblock->getSDesc($this);
+ $name = $impl->getName();
+ $link = ($link = $impl->getLink($this)) ? $link : $impl->getClass() . '::' . $name;
+ $ret[] = array('link' => $link,'sdesc' => $sdesc);
+ }
+ return $ret;
+ }
+
+ /**
+ * returns a list of child classes
+ *
+ * @param parserClass class variable
+ * @uses parserClass::getChildClassList()
+ */
+
+ function generateChildClassList($class)
+ {
+ $kids = $class->getChildClassList($this);
+ $list = array();
+ if (count($kids))
+ {
+ for($i=0; $igetLink($this);
+ $lt['sdesc'] = $kids[$i]->docblock->getSDesc($this);
+
+ if ($kids[$i]->docblock->hasaccess)
+ $lt['access'] = $kids[$i]->docblock->tags['access'][0]->value;
+ else
+ $lt['access'] = 'public';
+
+ $lt['abstract'] = isset ($kids[$i]->docblock->tags['abstract'][0]);
+
+ $list[] = $lt;
+ }
+ } else return false;
+ return $list;
+ }
+
+ /**
+ * Return template-enabled list of inherited variables
+ *
+ * uses parserVar helper function getInheritedVars and generates a
+ * template-enabled list using getClassLink()
+ * @param parserVar $child class var
+ * @see getClassLink(), parserVar::getInheritedVars()
+ * @return array Format:
+ *
+ * array(
+ * array('parent_class' => link to parent class's documentation,
+ * 'ivars' =>
+ * array(
+ * array('name' => inherited variable name,
+ * 'link' => link to inherited variable's documentation,
+ * 'default' => default value of inherited variable,
+ * 'sdesc' => summary of inherited variable),
+ * ...),
+ * ...)
+ *
+ */
+
+ function getFormattedInheritedVars($child)
+ {
+ $package = $child->docblock->package;
+ $subpackage = $child->docblock->subpackage;
+ $ivars = $child->getInheritedVars($this);
+ $results = array();
+ if (!count($ivars)) return $results;
+ foreach($ivars as $parent => $vars)
+ {
+ $file = $vars['file'];
+ $vars = $vars['vars'];
+ $par = $this->classes->getClass($parent,$file);
+ if ($par) {
+ $package = $par->docblock->package;
+ }
+ usort($vars,array($this,"sortVar"));
+ $result['parent_class'] = $this->getClassLink($parent, $package);
+ if (!$result['parent_class']) {
+ $result['parent_class'] = $parent . ' (Internal Class)';
+ }
+ foreach($vars as $var)
+ {
+ $info = array();
+
+ if ($var->docblock->hasaccess) {
+ $info['access'] = $var->docblock->tags['access'][0]->value;
+ } else {
+ $info['access'] = 'public';
+ }
+
+ $info['abstract'] = isset ($var->docblock->tags['abstract'][0]);
+
+ $info['name'] = $var->getName();
+ $info['link'] = $var->getLink($this);
+ if (!$info['link']) {
+ $info['link'] = $info['name'];
+ }
+ $info['default'] = $this->postProcess($var->getValue());
+ if ($var->docblock)
+ $info['sdesc'] = $var->docblock->getSDesc($this);
+ $result["ivars"][] = $info;
+ }
+ $results[] = $result;
+ $result = array();
+ }
+ return $results;
+ }
+
+ /**
+ * Return template-enabled list of inherited methods
+ *
+ * uses parserMethod helper function getInheritedMethods and generates a
+ * template-enabled list using getClassLink()
+ * @param parserMethod $child class method
+ * @see getClassLink(), parserMethod::getInheritedMethods()
+ * @return array Format:
+ *
+ * array(
+ * array('parent_class' => link to parent class's documentation,
+ * 'ivars' =>
+ * array(
+ * array('name' => inherited variable name,
+ * 'link' => link to inherited variable's documentation,
+ * 'function_call' => {@link parserMethod::getIntricateFunctionCall()}
+ * returned array,
+ * 'sdesc' => summary of inherited variable),
+ * ...),
+ * ...)
+ *
+ */
+
+ function getFormattedInheritedMethods($child)
+ {
+ $package = $child->docblock->package;
+ $subpackage = $child->docblock->subpackage;
+ $imethods = $child->getInheritedMethods($this);
+ $results = array();
+ if (!count($imethods)) return $results;
+ foreach($imethods as $parent => $methods)
+ {
+ $file = $methods['file'];
+ $methods = $methods['methods'];
+ $par = $this->classes->getClass($parent,$file);
+ if ($par) {
+ $package = $par->docblock->package;
+ }
+ usort($methods,array($this,"sortMethod"));
+ $result['parent_class'] = $this->getClassLink($parent,$package);
+ if (!$result['parent_class']) {
+ $result['parent_class'] = $parent . ' (Internal Class)';
+ }
+ foreach($methods as $method)
+ {
+ $info = array();
+
+ if ($method->docblock->hasaccess) {
+ $info['access'] = $method->docblock->tags['access'][0]->value;
+ } else {
+ $info['access'] = 'public';
+ }
+ $info['abstract'] = isset ($method->docblock->tags['abstract'][0]);
+
+ if ($method->isConstructor) $info['constructor'] = 1;
+ $returntype = 'void';
+ if ($method->isConstructor) {
+ $returntype = $method->getClass();
+ }
+ if ($method->docblock->return) {
+ $a = $method->docblock->return->Convert($this);
+ $returntype = $method->docblock->return->converted_returnType;
+ }
+ $info['function_return'] = $returntype;
+ $info['static'] = isset ($method->docblock->tags['static'][0]);
+ $info['link'] = $method->getLink($this);
+ if (!$info['link']) {
+ $info['link'] = $method->getFunctionCall();
+ }
+ $info['name'] = $method->getName();
+ if ($method->docblock)
+ $info['sdesc'] = $method->docblock->getSDesc($this);
+ $params = array();
+ if (count($method->docblock->params))
+ foreach($method->docblock->params as $param => $val)
+ {
+ $a = $val->Convert($this);
+ $params[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
+ }
+
+ $info['function_call'] = $method->getIntricateFunctionCall($this,$params);
+ $result["imethods"][] = $info;
+ }
+ $results[] = $result;
+ $result = array();
+ }
+ return $results;
+ }
+
+ /**
+ * Return template-enabled list of inherited class constants
+ *
+ * uses parserConst helper function getInheritedConsts and generates a
+ * template-enabled list using getClassLink()
+ * @param parserConst $child class constant
+ * @see getClassLink(), parserMethod::getInheritedConsts()
+ * @return array Format:
+ *
+ * array(
+ * array('parent_class' => link to parent class's documentation,
+ * 'ivars' =>
+ * array(
+ * array('name' => inherited constant name,
+ * 'link' => link to inherited constant's documentation,
+ * 'value' => constant value,
+ * 'sdesc' => summary of inherited constant),
+ * ...),
+ * ...)
+ *
+ */
+
+ function getFormattedInheritedConsts($child)
+ {
+ $package = $child->docblock->package;
+ $subpackage = $child->docblock->subpackage;
+ $ivars = $child->getInheritedConsts($this);
+ $results = array();
+ if (!count($ivars)) return $results;
+ foreach($ivars as $parent => $vars)
+ {
+ $file = $vars['file'];
+ $vars = $vars['consts'];
+ $par = $this->classes->getClass($parent,$file);
+ if ($par) {
+ $package = $par->docblock->package;
+ }
+ usort($vars,array($this,"sortVar"));
+ $result['parent_class'] = $this->getClassLink($parent,$package);
+ if (!$result['parent_class']) {
+ $result['parent_class'] = $parent . ' (Internal Class)';
+ }
+ foreach($vars as $var)
+ {
+ $info = array();
+
+ if ($var->docblock->hasaccess) {
+ $info['access'] = $var->docblock->tags['access'][0]->value;
+ } else {
+ $info['access'] = 'public';
+ }
+ $info['name'] = $var->getName();
+ $info['link'] = $var->getLink($this);
+ if (!$info['link']) {
+ $info['link'] = $info['name'] . ' = ' . $var->getValue();
+ }
+ $info['value'] = $this->postProcess($var->getValue());
+ if ($var->docblock)
+ $info['sdesc'] = $var->docblock->getSDesc($this);
+ $result["iconsts"][] = $info;
+ }
+ $results[] = $result;
+ $result = array();
+ }
+ return $results;
+ }
+
+ /**
+ * Return a Smarty template object to operate with
+ *
+ * This returns a Smarty template with pre-initialized variables for use.
+ * If the method "SmartyInit()" exists, it is called.
+ * @return Smarty
+ */
+ function &newSmarty()
+ {
+ $templ = new Smarty;
+ $templ->use_sub_dirs = false;
+ $templ->template_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'templates');
+ $templatename = get_class($this) . $this->templateName;
+ if (!file_exists($this->targetDir . DIRECTORY_SEPARATOR . md5($templatename))) {
+ // we'll delete this on finishing conversion
+ $this->_compiledDir[$this->targetDir . DIRECTORY_SEPARATOR . md5($templatename)] = 1;
+ mkdir($this->targetDir . DIRECTORY_SEPARATOR . md5($templatename),0775);
+ }
+ $templ->compile_dir = realpath($this->targetDir . PATH_DELIMITER . md5($templatename));
+ $templ->config_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'configs');
+ $templ->assign("date",date("r",time()));
+ $templ->assign("maintitle",$this->title);
+ $templ->assign("package",$this->package);
+ $templ->assign("phpdocversion",PHPDOCUMENTOR_VER);
+ $templ->assign("phpdocwebsite",PHPDOCUMENTOR_WEBSITE);
+ $templ->assign("subpackage",$this->subpackage);
+ if (method_exists($this,'SmartyInit')) return $this->SmartyInit($templ);
+ return $templ;
+ }
+
+ /**
+ * Finish up parsing/cleanup directories
+ */
+ function cleanup()
+ {
+ foreach ($this->_compiledDir as $dir => $one) {
+ $this->_rmdir($dir);
+ }
+ }
+
+ /**
+ * Completely remove a directory and its contents
+ *
+ * @param string $directory
+ */
+ function _rmdir($directory)
+ {
+ $handle = @opendir($directory);
+ if ($handle) {
+ while (false !== ($file = readdir($handle))) {
+ if ($file == '.' || $file == '..') {
+ continue;
+ }
+ if (is_dir($directory . DIRECTORY_SEPARATOR . $file)) {
+ $this->_rmdir($directory . DIRECTORY_SEPARATOR . $file);
+ }
+ @unlink($directory . DIRECTORY_SEPARATOR . $file);
+ }
+ closedir($handle);
+ @rmdir($directory);
+ }
+ }
+
+ /**
+ * do all necessary output
+ * @see Converter
+ * @abstract
+ */
+ function Output($title)
+ {
+ phpDocumentor_out("WARNING: Generic Converter::Output was used, no output will be generated");
+ }
+
+ /**
+ * Set the template directory with a different template base directory
+ * @tutorial phpDocumentor.howto.pkg#using.command-line.templatebase
+ * @param string template base directory
+ * @param string template name
+ */
+ function setTemplateBase($base, $dir)
+ {
+ // remove trailing /'s from the base path, if any
+ $base = str_replace('\\','/',$base);
+ while ($base{strlen($base) - 1} == '/') $base = substr($base,0,strlen($base) - 1);
+ $this->templateName = substr($dir,0,strlen($dir) - 1);
+ $this->templateDir = $base . "/Converters/" . $this->outputformat . "/" . $this->name . "/templates/" . $dir;
+ if (!is_dir($this->templateDir))
+ {
+ addErrorDie(PDERROR_TEMPLATEDIR_DOESNT_EXIST, $this->templateDir);
+ }
+
+ $this->smarty_dir = $this->templateDir;
+ if (file_exists($this->templateDir . PATH_DELIMITER . 'options.ini'))
+ {
+ // retrieve template options, allow array creation
+ $this->template_options = phpDocumentor_parse_ini_file($this->templateDir . PATH_DELIMITER . 'options.ini',true);
+ }
+ }
+
+ /**
+ * sets the template directory based on the {@link $outputformat} and {@link $name}
+ * Also sets {@link $templateName} to the $dir parameter
+ * @param string subdirectory
+ */
+ function setTemplateDir($dir)
+ {
+ if ('@DATA-DIR@' != '@'.'DATA-DIR@') {
+ $templateBase = str_replace('\\', '/', '@DATA-DIR@/PhpDocumentor/phpDocumentor');
+ } else {
+ $templateBase = str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . '/phpDocumentor';
+ }
+ $this->setTemplateBase($templateBase, $dir);
+ }
+
+ /**
+ * Get the absolute path to the converter's base directory
+ * @return string
+ */
+ function getConverterDir()
+ {
+ if ('@DATA-DIR@' != '@' . 'DATA-DIR@') {
+ return str_replace('\\', '/', "@DATA-DIR@/PhpDocumentor/phpDocumentor/Converters/") . $this->outputformat . "/" . $this->name;
+ } else {
+ return str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) ."/phpDocumentor/Converters/" . $this->outputformat . "/" . $this->name;
+ }
+ }
+
+ /**
+ * Parse a global variable's default value for class initialization.
+ *
+ * If a global variable's default value is "new class" as in:
+ *
+ * $globalvar = new Parser
+ *
+ * This method will document it not as "new Parser" but instead as
+ * "new {@link Parser}". For examples, see {@link phpdoc.inc}.
+ * Many global variables are classes, and phpDocumentor links to their
+ * documentation
+ * @return string default global variable value with link to class if
+ * it's "new Class"
+ * @param string default value of a global variable.
+ */
+ function getGlobalValue($value)
+ {
+ if (strpos($value,'new') === 0)
+ {
+ preg_match('/new([^(]*)((?:.|\r|\n)*)/',$value,$newval);
+ if (isset($newval[1]))
+ {
+ $a = Converter::getLink(trim($newval[1]));
+ if (!isset($newval[2])) $newval[2] = '';
+ if ($a && phpDocumentor_get_class($a) == 'classlink') $value = 'new '.$this->returnSee($a) .
+ $this->postProcess($newval[2]);
+ }
+ return $value;
+ }
+ return $this->postProcess($value);
+ }
+
+ /**
+ * Parse an include's file to see if it is a file documented in this project
+ *
+ * Although not very smart yet, this method will try to look for the
+ * included file file.ext:
+ *
+ *
+ * include ("file.ext");
+ *
+ *
+ * If it finds it, it will return a link to the file's documentation. As of
+ * 1.2.0rc1, phpDocumentor is smarty enough to find these cases:
+ *
+ * - absolute path to file
+ * - ./file.ext or ../file.ext
+ * - relpath/to/file.ext if relpath is a subdirectory of the base parse
+ * directory
+ *
+ * For examples, see {@link Setup.inc.php} includes.
+ * Every include auto-links to the documentation for the file that is included
+ * @return string included file with link to docs for file, if found
+ * @param string file included by include statement.
+ * @param string path of file that has the include statement
+ */
+ function getIncludeValue($value, $ipath)
+ {
+ preg_match('/"([^"\']*\.[^"\']*)"/',$value,$match);
+ if (!isset($match[1]))
+ preg_match('/\'([^"\']*\.[^"\']*)\'/',$value,$match);
+ if (isset($match[1]))
+ {
+ $fancy_per = $this->proceduralpages->pathMatchesParsedFile($match[1],$ipath);
+ if ($fancy_per)
+ {
+ $link = $this->addLink($fancy_per);
+ if (is_object($link) && phpDocumentor_get_class($link) == 'pagelink' &&
+ isset($this->all_packages[$link->package]))
+ {
+ $value = $this->returnSee($link,$value);
+ }
+ } else
+ {
+ $per = Converter::getLink($match[1]);
+ if (is_object($per) && phpDocumentor_get_class($per) == 'pagelink')
+ $value = $this->returnSee($per);
+ }
+ }
+ return $value;
+ }
+
+ /**
+ * Recursively creates all subdirectories that don't exist in the $dir path
+ * @param string $dir
+ */
+ function createParentDir($dir)
+ {
+ if (empty($dir)) return;
+ $tmp = explode(SMART_PATH_DELIMITER,$dir);
+ array_pop($tmp);
+ $parent = implode(SMART_PATH_DELIMITER,$tmp);
+ if ($parent != '' && !file_exists($parent))
+ {
+ $test = @mkdir($parent,0775);
+ if (!$test)
+ {
+ $this->createParentDir($parent);
+ $test = @mkdir($parent,0775);
+ phpDocumentor_out("Creating Parent Directory $parent\n");
+ } else
+ {
+ phpDocumentor_out("Creating Parent Directory $parent\n");
+ }
+ }
+ }
+
+ /**
+ * Sets the output directory for generated documentation
+ *
+ * As of 1.3.0RC6, this also sets the compiled templates directory inside
+ * the target directory
+ * @param string $dir the output directory
+ */
+ function setTargetDir($dir)
+ {
+ if (strlen($dir) > 0)
+ {
+ $this->targetDir = $dir;
+ // if directory does exist create it, this should have more error checking in the future
+ if (!file_exists($dir))
+ {
+ $tmp = str_replace(array("/","\\"),SMART_PATH_DELIMITER,$dir);
+ if (substr($tmp,-1) == SMART_PATH_DELIMITER)
+ {
+ $tmp = substr($tmp,0,(strlen($tmp)-1));
+ }
+ $this->createParentDir($tmp);
+ phpDocumentor_out("Creating Directory $dir\n");
+ mkdir($dir,0775);
+ } elseif (!is_dir($dir))
+ {
+ echo "Output path: '$dir' is not a directory\n";
+ die();
+ }
+ } else {
+ echo "a target directory must be specified\n try phpdoc -h\n";
+ die();
+ }
+ }
+
+ /**
+ * Writes a file to target dir
+ * @param string
+ * @param string
+ * @param boolean true if the data is binary and not text
+ */
+ function writeFile($file,$data,$binary = false)
+ {
+ if (!file_exists($this->targetDir))
+ {
+ mkdir($this->targetDir,0775);
+ }
+ $string = '';
+ if ($binary) $string = 'binary file ';
+ phpDocumentor_out(" Writing $string".$this->targetDir . PATH_DELIMITER . $file . "\n");
+ flush();
+ $write = 'w';
+ if ($binary) $write = 'wb';
+ $fp = fopen($this->targetDir . PATH_DELIMITER . $file,$write);
+ set_file_buffer( $fp, 0 );
+ fwrite($fp,$data,strlen($data));
+ fclose($fp);
+ }
+
+ /**
+ * Copies a file from the template directory to the target directory
+ * thanks to Robert Hoffmann for this fix
+ * @param string
+ */
+ function copyFile($file, $subdir = '')
+ {
+ if (!file_exists($this->targetDir))
+ {
+ mkdir($this->targetDir,0775);
+ }
+ copy($this->templateDir . $subdir . PATH_DELIMITER . $file, $this->targetDir . PATH_DELIMITER . $file);
+ }
+
+ /**
+ * Return parserStringWithInlineTags::Convert() cache state
+ * @see parserStringWithInlineTags::Convert()
+ * @abstract
+ */
+ function getState()
+ {
+ return true;
+ }
+
+ /**
+ * Compare parserStringWithInlineTags::Convert() cache state to $state
+ * @param mixed
+ * @see parserStringWithInlineTags::Convert()
+ * @abstract
+ */
+ function checkState($state)
+ {
+ return true;
+ }
+
+}
+
+/**
+ * @access private
+ * @see Converter::getSortedClassTreeFromClass()
+ */
+function rootcmp($a, $b)
+{
+ return strnatcasecmp($a['class'],$b['class']);
+}
+
+/**
+ * @access private
+ * @global string used to make the first tutorials converted the default package tutorials
+ */
+function tutorialcmp($a, $b)
+{
+ global $phpDocumentor_DefaultPackageName;
+ if ($a == $phpDocumentor_DefaultPackageName) return -1;
+ if ($b == $phpDocumentor_DefaultPackageName) return 1;
+ return strnatcasecmp($a, $b);
+}
+
+/**
+ * smart htmlentities, doesn't entity the allowed tags list
+ * Since version 1.1, this function uses htmlspecialchars instead of
+ * htmlentities, for international support
+ * This function has been replaced by functionality in {@link ParserDescCleanup.inc}
+ * @param string $s
+ * @return string browser-displayable page
+ * @deprecated As of v1.2, No longer needed, as valid tags are parsed out of the source,
+ * and everything else is {@link Converter::postProcess()} handled
+ */
+function adv_htmlentities($s)
+{
+ return;
+ global $phpDocumentor___html,$_phpDocumentor_html_allowed;
+ $result = htmlspecialchars($s);
+ $entities = array_flip(get_html_translation_table(HTML_SPECIALCHARS));
+ $result = strtr($result,$phpDocumentor___html);
+ $matches = array();
+ preg_match_all('/(<img.*>)/U',$result,$matches);
+ for($i=0;$igetName();
+ return '_'.$element->parent->getName();
+ }
+}
+?>
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/CHMdefaultConverter.inc b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/CHMdefaultConverter.inc
new file mode 100755
index 00000000..b9679a27
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/CHMdefaultConverter.inc
@@ -0,0 +1,1899 @@
+
+ * @author Greg Beaver
+ * @copyright 2000-2006 Joshua Eichorn, Gregory Beaver
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @version CVS: $Id: CHMdefaultConverter.inc 234145 2007-04-19 20:20:57Z ashnazg $
+ * @filesource
+ * @link http://www.phpdoc.org
+ * @link http://pear.php.net/PhpDocumentor
+ * @since 1.0rc1
+ */
+/**
+ * Generates files that MS HTML Help Worshop can use to create a MS Windows
+ * compiled help file (CHM)
+ *
+ * The free MS HTML Help compiler takes the project file (phpdoc.hhp) and reads
+ * the table of contents file specified in the project (which is always contents.hhc
+ * in phpDocumentor). When the converter reaches stable state, it will also
+ * output an index file index.hhk. The free download for MS HTML Help Workshop
+ * is available below
+ * @link http://www.microsoft.com/downloads/release.asp?releaseid=33071 MS HTML Help Workshop download
+ * @package Converters
+ * @subpackage CHMdefault
+ * @author Greg Beaver
+ * @since 1.0rc1
+ * @version $Revision: 234145 $
+ */
+class CHMdefaultConverter extends Converter
+{
+ /**
+ * CHMdefaultConverter wants elements sorted by type as well as alphabetically
+ * @see Converter::$sort_page_contents_by_type
+ * @var boolean
+ */
+ var $sort_page_contents_by_type = true;
+ /** @var string */
+ var $outputformat = 'CHM';
+ /** @var string */
+ var $name = 'default';
+ /**
+ * indexes of elements by package that need to be generated
+ * @var array
+ */
+ var $leftindex = array('classes' => true, 'pages' => true, 'functions' => true, 'defines' => false, 'globals' => false);
+
+ /**
+ * output directory for the current procedural page being processed
+ * @var string
+ */
+ var $page_dir;
+
+ /**
+ * target directory passed on the command-line.
+ * {@link $targetDir} is malleable, always adding package/ and package/subpackage/ subdirectories onto it.
+ * @var string
+ */
+ var $base_dir;
+
+ /**
+ * output directory for the current class being processed
+ * @var string
+ */
+ var $class_dir;
+
+ /**
+ * array of converted package page names.
+ * Used to link to the package page in the left index
+ * @var array Format: array(package => 1)
+ */
+ var $package_pages = array();
+
+ /**
+ * controls formatting of parser informative output
+ *
+ * Converter prints:
+ * "Converting /path/to/file.php... Procedural Page Elements... Classes..."
+ * Since CHMdefaultConverter outputs files while converting, it needs to send a \n to start a new line. However, if there
+ * is more than one class, output is messy, with multiple \n's just between class file output. This variable prevents that
+ * and is purely cosmetic
+ * @var boolean
+ */
+ var $juststarted = false;
+
+ /**
+ * contains all of the template procedural page element loop data needed for the current template
+ * @var array
+ */
+ var $current;
+
+ /**
+ * contains all of the template class element loop data needed for the current template
+ * @var array
+ */
+ var $currentclass;
+ var $wrote = false;
+ var $ric_set = array();
+ /**
+ * Table of Contents entry for index.hhk
+ * @var array
+ */
+ var $KLinks = array();
+
+ /**
+ * sets {@link $base_dir} to $targetDir
+ * @see Converter()
+ */
+ function CHMdefaultConverter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $templateDir, $title)
+ {
+ Converter::Converter($allp, $packp, $classes, $procpages,$po, $pp, $qm, $targetDir, $templateDir, $title);
+ $this->base_dir = $targetDir;
+ }
+
+ /**
+ * @deprecated in favor of PHP 4.3.0+ tokenizer-based source highlighting
+ */
+ function unmangle($sourcecode)
+ {
+ $sourcecode = str_replace('','',$sourcecode);
+ $sourcecode = str_replace('
','
',$sourcecode);
+ $sourcecode = str_replace('
',"\n",$sourcecode);
+ $sourcecode = str_replace(' ',' ',$sourcecode);
+ $sourcecode = str_replace('<','<',$sourcecode);
+ $sourcecode = str_replace('>','>',$sourcecode);
+ $sourcecode = str_replace('&','&',$sourcecode);
+ return $sourcecode;
+ }
+
+ /**
+ * @param string full path to the source file
+ * @param string fully highlighted source code
+ */
+ function writeSource($path, $value)
+ {
+ $templ = &$this->newSmarty();
+ $pathinfo = $this->proceduralpages->getPathInfo($path, $this);
+ $templ->assign('source',$value);
+ $templ->assign('package',$pathinfo['package']);
+ $templ->assign('subpackage',$pathinfo['subpackage']);
+ $templ->assign('name',$pathinfo['name']);
+ $templ->assign('source_loc',$pathinfo['source_loc']);
+ $templ->assign('docs',$pathinfo['docs']);
+ $templ->assign("subdir",'../');
+ $templ->register_outputfilter('CHMdefault_outputfilter');
+ $this->setTargetDir($this->getFileSourcePath($this->base_dir));
+ $this->addSourceTOC($pathinfo['name'],$this->getFileSourceName($path),$pathinfo['package'],$pathinfo['subpackage'], true);
+ phpDocumentor_out("\n");
+ $this->setSourcePaths($path);
+ $this->writefile($this->getFileSourceName($path).'.html',$templ->fetch('filesource.tpl'));
+ }
+
+ function writeExample($title, $path, $source)
+ {
+ $templ = &$this->newSmarty();
+ $templ->assign('source',$source);
+ if (empty($title))
+ {
+ $title = 'example';
+ addWarning(PDERROR_EMPTY_EXAMPLE_TITLE, $path, $title);
+ }
+ $templ->assign('title',$title);
+ $templ->assign('file',$path);
+ $templ->assign("subdir",'../');
+ $templ->register_outputfilter('CHMdefault_outputfilter');
+ $pathinfo = $this->proceduralpages->getPathInfo($path, $this);
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . '__examplesource');
+ $this->addSourceTOC($title,'exsource_'.$path,$pathinfo['package'],$pathinfo['subpackage'], false);
+ phpDocumentor_out("\n");
+ $this->writefile('exsource_'.$path.'.html',$templ->fetch('examplesource.tpl'));
+ }
+
+ function getExampleLink($path, $title)
+ {
+ return $this->returnLink('{$subdir}__examplesource' . PATH_DELIMITER . 'exsource_'.$path.'.html',$title);
+ }
+
+ function getSourceLink($path)
+ {
+ return $this->returnLink('{$subdir}__filesource/' .
+ $this->getFileSourceName($path).'.html','Source Code for this file');
+ }
+
+ /**
+ * Retrieve a Converter-specific anchor to a segment of a source code file
+ * parsed via a {@tutorial tags.filesource.pkg} tag.
+ * @param string full path to source file
+ * @param string name of anchor
+ * @param string link text, if this is a link
+ * @param boolean returns either a link or a destination based on this
+ * parameter
+ * @return string link to an anchor, or the anchor
+ */
+ function getSourceAnchor($sourcefile,$anchor,$text = '',$link = false)
+ {
+ if ($link) {
+ return $this->returnLink('{$subdir}__filesource/' .
+ $this->getFileSourceName($sourcefile) . '.html#a' . $anchor, $text);
+ } else {
+ return '';
+ }
+ }
+
+
+ /**
+ * Return a line of highlighted source code with formatted line number
+ *
+ * If the $path is a full path, then an anchor to the line number will be
+ * added as well
+ * @param integer line number
+ * @param string highlighted source code line
+ * @param false|string full path to @filesource file this line is a part of,
+ * if this is a single line from a complete file.
+ * @return string formatted source code line with line number
+ */
+ function sourceLine($linenumber, $line, $path = false)
+ {
+ $extra = '';
+ if (strlen(str_replace("\n", '', $line)) == 0) {
+ $extra = ' ';
+ }
+ if ($path)
+ {
+ return '- ' . $this->getSourceAnchor($path, $linenumber) .
+ str_replace("\n",'',$line) . $extra .
+ "
\n";
+ } else
+ {
+ return '- ' . str_replace("\n",'',$line) .
+ "$extra
\n";
+ }
+ }
+
+ /**
+ * Used to convert the <> tag in a docblock
+ * @param string
+ * @param boolean
+ * @return string
+ */
+ function ProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/,
+ $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/)
+ {
+ return $this->PreserveWhiteSpace(parent::ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath));
+ }
+
+ /**
+ * @param string
+ */
+ function TutorialExample($example)
+ {
+ $trans = $this->template_options['desctranslate'];
+ $this->template_options['desctranslate'] = array();
+ $example = '' . parent::TutorialExample($example)
+ .'
';
+ $this->template_options['desctranslate'] = $trans;
+ if (!isset($this->template_options['desctranslate'])) return $example;
+ if (!isset($this->template_options['desctranslate']['code'])) return $example;
+ $example = $this->template_options['desctranslate']['code'] . $example;
+ if (!isset($this->template_options['desctranslate']['/code'])) return $example;
+ return $example . $this->template_options['desctranslate']['/code'];
+ }
+
+ function getCurrentPageLink()
+ {
+ return $this->curname . '.html';
+ }
+
+ /**
+ * Uses htmlspecialchars() on the input
+ */
+ function postProcess($text)
+ {
+ if ($this->highlightingSource) {
+ return str_replace(array(' ',"\t"), array(' ', ' '),
+ htmlspecialchars($text));
+ }
+ return htmlspecialchars($text);
+ }
+
+ /**
+ * Use the template tutorial_toc.tpl to generate a table of contents for HTML
+ * @return string table of contents formatted for use in the current output format
+ * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...)
+ */
+ function formatTutorialTOC($toc)
+ {
+ $template = &$this->newSmarty();
+ $template->assign('toc',$toc);
+ return $template->fetch('tutorial_toc.tpl');
+ }
+
+ function &SmartyInit(&$templ)
+ {
+ if (!isset($this->package_index))
+ foreach($this->all_packages as $key => $val)
+ {
+ if (isset($this->pkg_elements[$key]))
+ {
+ if (!isset($start)) $start = $key;
+ $this->package_index[] = array('link' => "li_$key.html", 'title' => $key);
+ }
+ }
+ $templ->assign("packageindex",$this->package_index);
+ $templ->assign("subdir",'');
+ return $templ;
+ }
+
+
+ /**
+ * Writes out the template file of {@link $class_data} and unsets the template to save memory
+ * @see registerCurrentClass()
+ * @see parent::endClass()
+ */
+ function endClass()
+ {
+ $a = '../';
+ if (!empty($this->subpackage)) $a .= '../';
+ if ($this->juststarted)
+ {
+ $this->juststarted = false;
+ phpDocumentor_out("\n");
+ flush();
+ }
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir);
+ $this->class_data->assign("subdir",$a);
+ $this->class_data->register_outputfilter('CHMdefault_outputfilter');
+ $this->addTOC($this->class,$this->class,$this->package,$this->subpackage, true);
+ $this->writefile($this->class . '.html',$this->class_data->fetch('class.tpl'));
+ unset($this->class_data);
+ }
+
+ /**
+ * Writes out the template file of {@link $page_data} and unsets the template to save memory
+ * @see registerCurrent()
+ * @see parent::endPage()
+ */
+ function endPage()
+ {
+ $this->package = $this->curpage->package;
+ $this->subpackage = $this->curpage->subpackage;
+ $a = '../';
+ if (!empty($this->subpackage)) $a .= '../';
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir);
+ $this->page_data->assign("package",$this->package);
+ $this->page_data->assign("subdir",$a);
+ $this->page_data->register_outputfilter('CHMdefault_outputfilter');
+ $this->addTOC($this->curpage->file,$this->page,$this->package,$this->subpackage);
+ $this->writefile($this->page . '.html',$this->page_data->fetch('page.tpl'));
+ unset($this->page_data);
+ }
+
+ /**
+ * @param string
+ * @param string
+ * @return string <a href="'.$link.'">'.$text.''.$text.'';
+ }
+
+ /**
+ * CHMdefaultConverter chooses to format both package indexes and the complete index here
+ *
+ * This function formats output for the elementindex.html and pkgelementindex.html template files. It then
+ * writes them to the target directory
+ * @see generateElementIndex(), generatePkgElementIndex()
+ */
+ function formatPkgIndex()
+ {
+ list($package_indexes,$packages,$mletters) = $this->generatePkgElementIndexes();
+ for($i=0;$inewSmarty();
+ $this->package = $package_indexes[$i]['package'];
+ $this->subpackage = '';
+ $template->assign("index",$package_indexes[$i]['pindex']);
+ $template->assign("package",$package_indexes[$i]['package']);
+ $template->assign("letters",$mletters[$package_indexes[$i]['package']]);
+ $template->assign("title","Package ".$package_indexes[$i]['package']." Element Index");
+ $template->assign("subdir",'../');
+ $template->register_outputfilter('CHMdefault_outputfilter');
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $package_indexes[$i]['package']);
+ $this->addTOC($package_indexes[$i]['package']." Alphabetical Index",'elementindex_'.$package_indexes[$i]['package'],$package_indexes[$i]['package'],'');
+ $this->writefile('elementindex_'.$package_indexes[$i]['package'].'.html',$template->fetch('pkgelementindex.tpl'));
+ }
+ phpDocumentor_out("\n");
+ flush();
+ }
+
+ /**
+ * CHMdefaultConverter uses this function to format template index.html and packages.html
+ *
+ * This function generates the package list from {@link $all_packages}, eliminating any
+ * packages that don't have any entries in their package index (no files at all, due to @ignore
+ * or other factors). Then it uses the default package name as the first package index to display.
+ * It sets the right pane to be either a blank file with instructions on making package-level docs,
+ * or the package-level docs for the default package.
+ * @global string Used to set the starting package to display
+ */
+ function formatIndex()
+ {
+ global $phpDocumentor_DefaultPackageName;
+ list($elindex,$mletters) = $this->generateElementIndex();
+ $template = &$this->newSmarty();
+ $template->assign("index",$elindex);
+ $template->assign("letters",$mletters);
+ $template->assign("title","Element Index");
+ $template->assign("date",date("r",time()));
+ $template->register_outputfilter('CHMdefault_outputfilter');
+ phpDocumentor_out("\n");
+ flush();
+ $this->setTargetDir($this->base_dir);
+ $this->addTOC("Alphabetical Index Of All Elements",'elementindex',"Index",'');
+ $this->writefile('elementindex.html',$template->fetch('elementindex.tpl'));
+ usort($this->package_index,"CHMdefault_pindexcmp");
+ $index = &$this->newSmarty();
+ foreach($this->all_packages as $key => $val)
+ {
+ if (isset($this->pkg_elements[$key]))
+ {
+ if (!isset($start)) $start = $key;
+ if (!isset($this->package_pages[$key])) $this->writeNewPPage($key);
+ }
+ }
+ $this->setTargetDir($this->base_dir);
+ // Created index.html
+ if (isset($this->pkg_elements[$phpDocumentor_DefaultPackageName])) $start = $phpDocumentor_DefaultPackageName;
+ $this->package = $start;
+ $this->subpackage = '';
+ $setalready = false;
+ if (isset($this->tutorials[$start]['']['pkg']))
+ {
+ foreach($this->tutorials[$start]['']['pkg'] as $tute)
+ {
+ if ($tute->name == $start . '.pkg')
+ {
+ $setalready = true;
+ $this->addTOC("Start page",$start.'/tutorial_'.$tute->name,"Index",'');
+ }
+ }
+ }
+ if (!$setalready)
+ {
+ if (isset($this->package_pages[$start]))
+ {
+ $this->addTOC("Start page",'package_'.$start,"Index",'');
+ }
+ else
+ {
+ $index->assign("blank","blank");
+ $blank = &$this->newSmarty();
+ $blank->assign('package',$phpDocumentor_DefaultPackageName);
+ $this->addTOC("Start page",'blank',"Index",'');
+ $this->writefile("blank.html",$blank->fetch('blank.tpl'));
+ Converter::writefile('index.html',$blank->fetch('tutorial.tpl'));
+ }
+ }
+ phpDocumentor_out("\n");
+ flush();
+
+ unset($index);
+ }
+
+ function writeNewPPage($key)
+ {
+ return;
+ $template = &$this->newSmarty();
+ $this->package = $key;
+ $this->subpackage = '';
+ $template->assign("date",date("r",time()));
+ $template->assign("title",$this->title);
+ $template->assign("package",$key);
+ $template->register_outputfilter('CHMdefault_outputfilter');
+ phpDocumentor_out("\n");
+ flush();
+ $this->setTargetDir($this->base_dir);
+
+ $this->addTOC("$key Index","li_$key",$key,'');
+ $this->writefile("li_$key.html",$template->fetch('index.tpl'));
+ unset($template);
+ }
+
+ /**
+ * Generate indexes for li_package.html and classtree output files
+ *
+ * This function generates the li_package.html files from the template file left.html. It does this by
+ * iterating through each of the $page_elements, $class_elements and $function_elements arrays to retrieve
+ * the pre-sorted {@link abstractLink} descendants needed for index generation. Conversion of these links to
+ * text is done by {@link returnSee()}. The {@link $local} parameter is set to false to ensure that paths are correct.
+ *
+ * Then it uses {@link generateFormattedClassTrees()} to create class trees from the template file classtrees.html. Output
+ * filename is classtrees_packagename.html. This function also unsets {@link $elements} and {@link $pkg_elements} to free
+ * up the considerable memory these two class vars use
+ * @see $page_elements, $class_elements, $function_elements
+ */
+ function formatLeftIndex()
+ {
+ phpDocumentor_out("\n");
+ flush();
+ $this->setTargetDir($this->base_dir);
+ if (0)//!isset($this->left))
+ {
+ debug("Nothing parsed, check the command-line");
+ die();
+ }
+ foreach($this->all_packages as $package => $rest)
+ {
+ if (!isset($this->pkg_elements[$package])) continue;
+
+ // Create class tree page
+ $template = &$this->newSmarty();
+ $template->assign("classtrees",$this->generateFormattedClassTrees($package));
+ $template->assign("package",$package);
+ $template->assign("date",date("r",time()));
+ $template->register_outputfilter('CHMdefault_outputfilter');
+ $this->addTOC("$package Class Trees","classtrees_$package",$package,'');
+ $this->writefile("classtrees_$package.html",$template->fetch('classtrees.tpl'));
+ phpDocumentor_out("\n");
+ flush();
+ }
+ // free up considerable memory
+ unset($this->elements);
+ unset($this->pkg_elements);
+ }
+
+ /**
+ * This function takes an {@link abstractLink} descendant and returns an html link
+ *
+ * @param abstractLink a descendant of abstractlink should be passed, and never text
+ * @param string text to display in the link
+ * @param boolean this parameter is not used, and is deprecated
+ * @param boolean determines whether the returned text is enclosed in an tag
+ */
+ function returnSee(&$element, $eltext = false, $with_a = true)
+ {
+ if (!$element) return false;
+ if (!$with_a) return $this->getId($element, false);
+ if (!$eltext)
+ {
+ $eltext = '';
+ switch($element->type)
+ {
+ case 'tutorial' :
+ $eltext = strip_tags($element->title);
+ break;
+ case 'method' :
+ case 'var' :
+ case 'const' :
+ $eltext .= $element->class.'::';
+ case 'page' :
+ case 'define' :
+ case 'class' :
+ case 'function' :
+ case 'global' :
+ default :
+ $eltext .= $element->name;
+ if ($element->type == 'function' || $element->type == 'method') $eltext .= '()';
+ break;
+ }
+ }
+ return ''.$eltext.'';
+ }
+
+ function getId($element, $fullpath = true)
+ {
+ if (phpDocumentor_get_class($element) == 'parserdata')
+ {
+ $element = $this->addLink($element->parent);
+ $elp = $element->parent;
+ } elseif (is_a($element, 'parserbase'))
+ {
+ $elp = $element;
+ $element = $this->addLink($element);
+ }
+ $c = '';
+ if (!empty($element->subpackage))
+ {
+ $c = '/'.$element->subpackage;
+ }
+ $b = '{$subdir}';
+ switch ($element->type)
+ {
+ case 'page' :
+ if ($fullpath)
+ return $b.$element->package.$c.'/'.$element->fileAlias.'.html';
+ return 'top';
+ break;
+ case 'define' :
+ case 'global' :
+ case 'function' :
+ if ($fullpath)
+ return $b.$element->package.$c.'/'.$element->fileAlias.'.html#'.$element->type.$element->name;
+ return $element->type.$element->name;
+ break;
+ case 'class' :
+ if ($fullpath)
+ return $b.$element->package.$c.'/'.$element->name.'.html';
+ return 'top';
+ break;
+ case 'method' :
+ case 'var' :
+ case 'const' :
+ if ($fullpath)
+ return $b.$element->package.$c.'/'.$element->class.'.html#'.$element->type.$element->name;
+ return $element->type.$element->name;
+ break;
+ case 'tutorial' :
+ $d = '';
+ if ($element->section)
+ {
+ $d = '#'.$element->section;
+ }
+ return $b.$element->package.$c.'/tutorial_'.$element->name.'.html'.$d;
+ }
+ }
+
+ function ConvertTodoList()
+ {
+ $todolist = array();
+ foreach($this->todoList as $package => $alltodos)
+ {
+ foreach($alltodos as $todos)
+ {
+ $converted = array();
+ $converted['link'] = $this->returnSee($todos[0]);
+ if (!is_array($todos[1]))
+ {
+ $converted['todos'][] = $todos[1]->Convert($this);
+ } else
+ {
+ foreach($todos[1] as $todo)
+ {
+ $converted['todos'][] = $todo->Convert($this);
+ }
+ }
+ $todolist[$package][] = $converted;
+ }
+ }
+ $templ = &$this->newSmarty();
+ $templ->assign('todos',$todolist);
+ $templ->register_outputfilter('CHMdefault_outputfilter');
+ $this->setTargetDir($this->base_dir);
+ $this->addTOC('Todo List','todolist','Index','',false,true);
+ $this->addKLink('Todo List', 'todolist', '', 'Development');
+ $this->writefile('todolist.html',$templ->fetch('todolist.tpl'));
+ }
+
+ /**
+ * Convert README/INSTALL/CHANGELOG file contents to output format
+ * @param README|INSTALL|CHANGELOG
+ * @param string contents of the file
+ */
+ function Convert_RIC($name, $contents)
+ {
+ $template = &$this->newSmarty();
+ $template->assign('contents',$contents);
+ $template->assign('name',$name);
+ $this->setTargetDir($this->base_dir);
+ $this->addTOC($name,'ric_'.$name,'Index','',false,true);
+ $this->addKLink($name, 'ric_'.$name, '', 'Development');
+ $this->writefile('ric_'.$name . '.html',$template->fetch('ric.tpl'));
+ $this->ric_set[$name] = true;
+ }
+
+ /**
+ * Create errors.html template file output
+ *
+ * This method takes all parsing errors and warnings and spits them out ordered by file and line number.
+ * @global ErrorTracker We'll be using it's output facility
+ */
+ function ConvertErrorLog()
+ {
+ global $phpDocumentor_errors;
+ $allfiles = array();
+ $files = array();
+ $warnings = $phpDocumentor_errors->returnWarnings();
+ $errors = $phpDocumentor_errors->returnErrors();
+ $template = &$this->newSmarty();
+ foreach($warnings as $warning)
+ {
+ $file = '##none';
+ $linenum = 'Warning';
+ if ($warning->file)
+ {
+ $file = $warning->file;
+ $allfiles[$file] = 1;
+ $linenum .= ' on line '.$warning->linenum;
+ }
+ $files[$file]['warnings'][] = array('name' => $linenum, 'listing' => $warning->data);
+ }
+ foreach($errors as $error)
+ {
+ $file = '##none';
+ $linenum = 'Error';
+ if ($error->file)
+ {
+ $file = $error->file;
+ $allfiles[$file] = 1;
+ $linenum .= ' on line '.$error->linenum;
+ }
+ $files[$file]['errors'][] = array('name' => $linenum, 'listing' => $error->data);
+ }
+ $i=1;
+ $af = array();
+ foreach($allfiles as $file => $num)
+ {
+ $af[$i++] = $file;
+ }
+ $allfiles = $af;
+ usort($allfiles,'strnatcasecmp');
+ $allfiles[0] = "Post-parsing";
+ foreach($allfiles as $i => $a)
+ {
+ $allfiles[$i] = array('file' => $a);
+ }
+ $out = array();
+ foreach($files as $file => $data)
+ {
+ if ($file == '##none') $file = 'Post-parsing';
+ $out[$file] = $data;
+ }
+ $template->assign("files",$allfiles);
+ $template->assign("all",$out);
+ $template->assign("title","phpDocumentor Parser Errors and Warnings");
+ $this->setTargetDir($this->base_dir);
+ $this->writefile("errors.html",$template->fetch('errors.tpl'));
+ unset($template);
+ phpDocumentor_out("\n\nTo view errors and warnings, look at ".$this->base_dir. PATH_DELIMITER . "errors.html\n");
+ flush();
+ }
+
+ function getCData($value)
+ {
+ return ''.htmlentities($value).'
';
+ }
+
+ function getTutorialId($package,$subpackage,$tutorial,$id)
+ {
+ return $id;
+ }
+
+ /**
+ * Converts package page and sets its package as used in {@link $package_pages}
+ * @param parserPackagePage
+ */
+ function convertPackagepage(&$element)
+ {
+ phpDocumentor_out("\n");
+ flush();
+ $this->package = $element->package;
+ $this->subpackage = '';
+ $contents = $element->Convert($this);
+ $this->package_pages[$element->package] = str_replace('{$subdir}','../',$contents);
+ phpDocumentor_out("\n");
+ flush();
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $element->package);
+ $this->addTOC($element->package." Tutorial",'package_'.$element->package,$element->package,'');
+ $this->writeFile('package_'.$element->package.'.html',str_replace('{$subdir}','../',$contents));
+ $this->setTargetDir($this->base_dir);
+ Converter::writefile('index.html',str_replace('{$subdir}','',$contents));
+ $this->addKLink($element->package." Tutorial", 'package_'.$element->package, '', 'Tutorials');
+ }
+
+ /**
+ * @param parserTutorial
+ */
+ function convertTutorial(&$element)
+ {
+ phpDocumentor_out("\n");
+ flush();
+ $template = &parent::convertTutorial($element);
+ $a = '../';
+ if ($element->subpackage) $a .= '../';
+ $template->assign('subdir',$a);
+ $template->register_outputfilter('CHMdefault_outputfilter');
+ $contents = $template->fetch('tutorial.tpl');
+ if ($element->package == $GLOBALS['phpDocumentor_DefaultPackageName'] && empty($element->subpackage) && ($element->name == $element->package . '.pkg'))
+ {
+ $template->assign('subdir','');
+ $this->setTargetDir($this->base_dir);
+ Converter::writefile('index.html',$template->fetch('tutorial.tpl'));
+ }
+ $a = '';
+ if ($element->subpackage) $a = PATH_DELIMITER . $element->subpackage;
+ phpDocumentor_out("\n");
+ flush();
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $element->package . $a);
+ $this->addTOC($a = strip_tags($element->getTitle($this)), 'tutorial_'.$element->name,
+ $element->package, $element->subpackage, false, true);
+ $this->writeFile('tutorial_'.$element->name.'.html',$contents);
+ $this->addKLink($element->getTitle($this), $element->package . $a . PATH_DELIMITER . 'tutorial_'.$element->name,
+ '', 'Tutorials');
+ }
+
+ /**
+ * Converts class for template output
+ * @see prepareDocBlock(), generateChildClassList(), generateFormattedClassTree(), getFormattedConflicts()
+ * @see getFormattedInheritedMethods(), getFormattedInheritedVars()
+ * @param parserClass
+ */
+ function convertClass(&$element)
+ {
+ parent::convertClass($element);
+ $this->class_dir = $element->docblock->package;
+ if (!empty($element->docblock->subpackage)) $this->class_dir .= PATH_DELIMITER . $element->docblock->subpackage;
+ $a = '../';
+ if ($element->docblock->subpackage != '') $a = "../$a";
+
+ $this->class_data->assign('subdir',$a);
+ $this->class_data->assign("title","Docs For Class " . $element->getName());
+ $this->class_data->assign("page",$element->getName() . '.html');
+ $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER . $this->class, '', 'Classes');
+ }
+
+
+ /**
+ * Converts class variables for template output
+ * @see prepareDocBlock(), getFormattedConflicts()
+ * @param parserDefine
+ */
+ function convertVar(&$element)
+ {
+ parent::convertVar($element, array('var_dest' => $this->getId($element,false)));
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir);
+ $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER .$this->class, $this->getId($element,false), $element->class.' Properties');
+ }
+
+ /**
+ * Converts class constants for template output
+ * @see prepareDocBlock(), getFormattedConflicts()
+ * @param parserDefine
+ */
+ function convertConst(&$element)
+ {
+ parent::convertConst($element, array('const_dest' => $this->getId($element,false)));
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir);
+ $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER .$this->class, $this->getId($element,false), $element->class.' Constants');
+ }
+
+ /**
+ * Converts class methods for template output
+ * @see prepareDocBlock(), getFormattedConflicts()
+ * @param parserDefine
+ */
+ function convertMethod(&$element)
+ {
+ parent::convertMethod($element, array('method_dest' => $this->getId($element,false)));
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->class_dir);
+ $this->addKLink($element->name, $this->class_dir . PATH_DELIMITER .$this->class, $this->getId($element,false), $element->class.' Methods');
+ }
+
+ /**
+ * Converts function for template output
+ * @see prepareDocBlock(), parserFunction::getFunctionCall(), getFormattedConflicts()
+ * @param parserFunction
+ */
+ function convertFunction(&$element)
+ {
+ $funcloc = $this->getId($this->addLink($element));
+ parent::convertFunction($element,array('function_dest' => $this->getId($element,false)));
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir);
+ $this->addKLink($element->name, $this->page_dir . PATH_DELIMITER . $this->page, $this->getId($element,false), 'Functions');
+ }
+
+ /**
+ * Converts include elements for template output
+ * @see prepareDocBlock()
+ * @param parserInclude
+ */
+ function convertInclude(&$element)
+ {
+ parent::convertInclude($element, array('include_file' => '_'.strtr($element->getValue(),array('"' => '', "'" => '','.' => '_'))));
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir);
+ $this->addKLink(str_replace('"', '', $element->getValue()), $this->page_dir . PATH_DELIMITER . $this->page, '', ucfirst($element->name));
+ }
+
+ /**
+ * Converts defines for template output
+ * @see prepareDocBlock(), getFormattedConflicts()
+ * @param parserDefine
+ */
+ function convertDefine(&$element)
+ {
+ parent::convertDefine($element, array('define_link' => $this->getId($element,false)));
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir);
+ $this->addKLink($element->name, $this->page_dir . PATH_DELIMITER . $this->page, $this->getId($element,false), 'Constants');
+ }
+
+ /**
+ * Converts global variables for template output
+ * @param parserGlobal
+ */
+ function convertGlobal(&$element)
+ {
+ parent::convertGlobal($element, array('global_link' => $this->getId($element,false)));
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir);
+ $this->addKLink($element->name, $this->page_dir . PATH_DELIMITER . $this->page, $this->getId($element,false), 'Global Variables');
+ }
+
+ /**
+ * converts procedural pages for template output
+ * @see prepareDocBlock(), getClassesOnPage()
+ * @param parserData
+ */
+ function convertPage(&$element)
+ {
+ parent::convertPage($element);
+ $this->juststarted = true;
+ $this->page_dir = $element->parent->package;
+ if (!empty($element->parent->subpackage)) $this->page_dir .= PATH_DELIMITER . $element->parent->subpackage;
+ // registering stuff on the template
+ $this->page_data->assign("page",$this->getPageName($element) . '.html');
+ $this->page_data->assign("title","Docs for page ".$element->parent->getFile());
+ $this->setTargetDir($this->base_dir . PATH_DELIMITER . $this->page_dir);
+ $this->addKLink($element->parent->file, $this->page_dir . PATH_DELIMITER . $this->page, '', 'Files');
+ }
+
+ function getPageName(&$element)
+ {
+ if (phpDocumentor_get_class($element) == 'parserpage') return '_'.$element->getName();
+ return '_'.$element->parent->getName();
+ }
+
+ /**
+ * returns an array containing the class inheritance tree from the root object to the class
+ *
+ * @param parserClass class variable
+ * @return array Format: array(root,child,child,child,...,$class)
+ * @uses parserClass::getParentClassTree()
+ */
+
+ function generateFormattedClassTree($class)
+ {
+ $tree = $class->getParentClassTree($this);
+ $out = '';
+ if (count($tree) - 1)
+ {
+ $result = array($class->getName());
+ $parent = $tree[$class->getName()];
+ $distance[] = '';
+ while ($parent)
+ {
+ $x = $parent;
+ if (is_object($parent))
+ {
+ $subpackage = $parent->docblock->subpackage;
+ $package = $parent->docblock->package;
+ $x = $parent;
+ $x = $parent->getLink($this);
+ if (!$x) $x = $parent->getName();
+ }
+ $result[] =
+ $x;
+ $distance[] =
+ "\n%s|\n" .
+ "%s--";
+ if (is_object($parent))
+ $parent = $tree[$parent->getName()];
+ elseif (isset($tree[$parent]))
+ $parent = $tree[$parent];
+ }
+ $nbsp = ' ';
+ for($i=count($result) - 1;$i>=0;$i--)
+ {
+ $my_nbsp = '';
+ for($j=0;$jarray_reverse($result),'distance'=>array_reverse($distance));
+ } else
+ {
+ return array('classes'=>$class->getName(),'distance'=>array(''));
+ }
+ }
+
+ /** @access private */
+ function sortVar($a, $b)
+ {
+ return strnatcasecmp($a->getName(),$b->getName());
+ }
+
+ /** @access private */
+ function sortMethod($a, $b)
+ {
+ if ($a->isConstructor) return -1;
+ if ($b->isConstructor) return 1;
+ return strnatcasecmp($a->getName(),$b->getName());
+ }
+
+ /**
+ * returns a template-enabled array of class trees
+ *
+ * @param string $package package to generate a class tree for
+ * @see $roots, HTMLConverter::getRootTree()
+ */
+ function generateFormattedClassTrees($package)
+ {
+ if (!isset($this->roots['normal'][$package]) &&
+ !isset($this->roots['special'][$package])) {
+ return array();
+ }
+ $trees = array();
+ if (isset($this->roots['normal'][$package])) {
+ $roots = $this->roots['normal'][$package];
+ for($i=0;$iclasses->getClassByPackage($roots[$i], $package);
+ if ($root && $root->isInterface()) {
+ continue;
+ }
+ $trees[] = array('class' => $roots[$i],'class_tree' => "\n".$this->getRootTree($this->getSortedClassTreeFromClass($roots[$i],$package,''),$package)."
\n");
+ }
+ }
+ if (isset($this->roots['special'][$package])) {
+ $roots = $this->roots['special'][$package];
+ foreach ($roots as $parent => $classes) {
+ $thistree = '';
+ foreach ($classes as $classinfo) {
+ $root = $this->classes->getClassByPackage($classinfo, $package);
+ if ($root && $root->isInterface()) {
+ continue;
+ }
+ $thistree .=
+ $this->getRootTree(
+ $this->getSortedClassTreeFromClass(
+ $classinfo,
+ $package,
+ ''),
+ $package,
+ true);
+ }
+ if (!$thistree) {
+ continue;
+ }
+ $trees[] = array(
+ 'class' => $parent,
+ 'class_tree' => "\n" . $thistree . "
\n"
+ );
+ }
+ }
+ return $trees;
+ }
+
+ /**
+ * returns a template-enabled array of interface inheritance trees
+ *
+ * @param string $package package to generate a class tree for
+ * @see $roots, HTMLConverter::getRootTree()
+ */
+ function generateFormattedInterfaceTrees($package)
+ {
+ if (!isset($this->roots['normal'][$package]) &&
+ !isset($this->roots['special'][$package])) {
+ return array();
+ }
+ $trees = array();
+ if (isset($this->roots['normal'][$package])) {
+ $roots = $this->roots['normal'][$package];
+ for($i=0;$iclasses->getClassByPackage($roots[$i], $package);
+ if ($root && !$root->isInterface()) {
+ continue;
+ }
+ $trees[] = array('class' => $roots[$i],'class_tree' => "\n".$this->getRootTree($this->getSortedClassTreeFromClass($roots[$i],$package,''),$package)."
\n");
+ }
+ }
+ if (isset($this->roots['special'][$package])) {
+ $roots = $this->roots['special'][$package];
+ foreach ($roots as $parent => $classes) {
+ $thistree = '';
+ foreach ($classes as $classinfo) {
+ $root = $this->classes->getClassByPackage($classinfo, $package);
+ if ($root && !$root->isInterface()) {
+ continue;
+ }
+ $thistree .=
+ $this->getRootTree(
+ $this->getSortedClassTreeFromClass(
+ $classinfo,
+ $package,
+ ''),
+ $package,
+ true);
+ }
+ if (!$thistree) {
+ continue;
+ }
+ $trees[] = array(
+ 'class' => $parent,
+ 'class_tree' => "\n" . $thistree . "
\n"
+ );
+ }
+ }
+ return $trees;
+ }
+
+ /**
+ * return formatted class tree for the Class Trees page
+ *
+ * @param array $tree output from {@link getSortedClassTreeFromClass()}
+ * @param string $package package
+ * @param boolean $nounknownparent if true, an object's parent will not be checked
+ * @see Classes::$definitechild, generateFormattedClassTrees()
+ * @return string
+ */
+ function getRootTree($tree, $package, $noparent = false)
+ {
+ if (!$tree) return '';
+ $my_tree = '';
+ $cur = '#root';
+ $lastcur = array(false);
+ $kids = array();
+ $dopar = false;
+ if (!$noparent && $tree[$cur]['parent'])
+ {
+ $dopar = true;
+ if (!is_object($tree[$cur]['parent']))
+ {
+// debug("parent ".$tree[$cur]['parent']." not found");
+ $my_tree .= '- ' . $tree[$cur]['parent'] .'
';
+ }
+ else
+ {
+// debug("parent ".$this->returnSee($tree[$cur]['parent'])." in other package");
+ $my_tree .= '- ' . $this->returnSee($tree[$cur]['parent']);
+ if ($tree[$cur]['parent']->package != $package) $my_tree .= ' (Different package)
';
+ }
+ }
+ do
+ {
+// fancy_debug($cur,$lastcur,$kids);
+ if (count($tree[$cur]['children']))
+ {
+// debug("$cur has children");
+ if (!isset($kids[$cur]))
+ {
+// debug("set $cur kids");
+ $kids[$cur] = 1;
+ $my_tree .= '- '.$this->returnSee($tree[$cur]['link']);
+ $my_tree .= '
'."\n";
+ }
+ array_push($lastcur,$cur);
+ list(,$cur) = each($tree[$cur]['children']);
+// var_dump('listed',$cur);
+ if ($cur)
+ {
+ $cur = $cur['package'] . '#' . $cur['class'];
+// debug("set cur to child $cur");
+// $my_tree .= '- '.$this->returnSee($tree[$cur]['link']);
+ continue;
+ } else
+ {
+// debug("end of children for $cur");
+ $cur = array_pop($lastcur);
+ $cur = array_pop($lastcur);
+ $my_tree .= '
'."\n";
+ if ($dopar && ($cur == '#root' || !$cur)) $my_tree .= '
';
+ }
+ } else
+ {
+// debug("$cur has no children");
+ $my_tree .= '- '.$this->returnSee($tree[$cur]['link'])."
";
+ if ($dopar && $cur == '#root') $my_tree .= '
';
+ $cur = array_pop($lastcur);
+ }
+ } while ($cur);
+ return $my_tree;
+ }
+ /**
+ * Generate indexing information for given element
+ *
+ * @param parserElement descendant of parserElement
+ * @see generateElementIndex()
+ * @return array
+ */
+ function getIndexInformation($elt)
+ {
+ $Result['type'] = $elt->type;
+ $Result['file_name'] = $elt->file;
+ $Result['path'] = $elt->getPath();
+
+ if (isset($elt->docblock))
+ {
+ $Result['description'] = $elt->docblock->getSDesc($this);
+
+ if ($elt->docblock->hasaccess)
+ $Result['access'] = $elt->docblock->tags['access'][0]->value;
+ else
+ $Result['access'] = 'public';
+
+ $Result['abstract'] = isset ($elt->docblock->tags['abstract'][0]);
+ }
+ else
+ $Result['description'] = '';
+
+ $aa = $Result['description'];
+ if (!empty($aa)) $aa = "
$aa";
+
+ switch($elt->type)
+ {
+ case 'class':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Class';
+ $Result['link'] = $this->getClassLink($elt->getName(),
+ $elt->docblock->package,
+ $elt->getPath(),
+ $elt->getName());
+ $Result['listing'] = 'in file '.$elt->file.', class '.$Result['link']."$aa";
+ break;
+ case 'define':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Constant';
+ $Result['link'] = $this->getDefineLink($elt->getName(),
+ $elt->docblock->package,
+ $elt->getPath(),
+ $elt->getName());
+ $Result['listing'] = 'in file '.$elt->file.', constant '.$Result['link']."$aa";
+ break;
+ case 'global':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Global';
+ $Result['link'] = $this->getGlobalLink($elt->getName(),
+ $elt->docblock->package,
+ $elt->getPath(),
+ $elt->getName());
+ $Result['listing'] = 'in file '.$elt->file.', global variable '.$Result['link']."$aa";
+ break;
+ case 'function':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Function';
+ $Result['link'] = $this->getFunctionLink($elt->getName(),
+ $elt->docblock->package,
+ $elt->getPath(),
+ $elt->getName().'()');
+ $Result['listing'] = 'in file '.$elt->file.', function '.$Result['link']."$aa";
+ break;
+ case 'method':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Method';
+ $Result['link'] = $this->getMethodLink($elt->getName(),
+ $elt->class,
+ $elt->docblock->package,
+ $elt->getPath(),
+ $elt->class.'::'.$elt->getName().'()'
+ );
+ if ($elt->isConstructor) $Result['constructor'] = 1;
+ $Result['listing'] = 'in file '.$elt->file.', method '.$Result['link']."$aa";
+ break;
+ case 'var':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Variable';
+ $Result['link'] = $this->getVarLink($elt->getName(),
+ $elt->class,
+ $elt->docblock->package,
+ $elt->getPath(),
+ $elt->class.'::'.$elt->getName());
+ $Result['listing'] = 'in file '.$elt->file.', variable '.$Result['link']."$aa";
+ break;
+ case 'const':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Variable';
+ $Result['link'] = $this->getConstLink($elt->getName(),
+ $elt->class,
+ $elt->docblock->package,
+ $elt->getPath(),
+ $elt->class.'::'.$elt->getName());
+ $Result['listing'] = 'in file '.$elt->file.', class constant '.$Result['link']."$aa";
+ break;
+ case 'page':
+ $Result['name'] = $elt->getFile();
+ $Result['title'] = 'Page';
+ $Result['link'] = $this->getPageLink($elt->getFile(),
+ $elt->package,
+ $elt->getPath(),
+ $elt->getFile());
+ $Result['listing'] = 'procedural page '.$Result['link'];
+ break;
+ case 'include':
+ $Result['name'] = $elt->getName();
+ $Result['title'] = 'Include';
+ $Result['link'] = $elt->getValue();
+ $Result['listing'] = 'include '.$Result['name'];
+ break;
+ }
+
+ return $Result;
+ }
+ /**
+ * Generate alphabetical index of all elements
+ *
+ * @see $elements, walk()
+ */
+ function generateElementIndex()
+ {
+ $elementindex = array();
+ $letters = array();
+ $used = array();
+ foreach($this->elements as $letter => $nutoh)
+ {
+ foreach($this->elements[$letter] as $i => $yuh)
+ {
+ if ($this->elements[$letter][$i]->type != 'include')
+ {
+ if (!isset($used[$letter]))
+ {
+ $letters[]['letter'] = $letter;
+ $elindex['letter'] = $letter;
+ $used[$letter] = 1;
+ }
+
+ $elindex['index'][] = $this->getIndexInformation($this->elements[$letter][$i]);
+ }
+ }
+ if (isset($elindex['index']))
+ {
+ $elementindex[] = $elindex;
+ } else
+ {
+ unset($letters[count($letters) - 1]);
+ }
+ $elindex = array();
+ }
+ return array($elementindex,$letters);
+ }
+
+ function setTemplateDir($dir)
+ {
+ Converter::setTemplateDir($dir);
+ $this->smarty_dir = $this->templateDir;
+ }
+
+ function copyMediaRecursively($media,$targetdir,$subdir = '')
+ {
+ $versionControlDirectories = array ('CVS', 'media/CVS', 'media\\CVS', '.svn', 'media/.svn', 'media\\.svn');
+ if (!is_array($media)) {
+ return;
+ }
+ foreach($media as $dir => $files)
+ {
+ if ($dir === '/')
+ {
+ $this->copyMediaRecursively($files,$targetdir);
+ } else
+ {
+ if (!is_numeric($dir))
+ {
+ if (in_array($dir, $versionControlDirectories))
+ {
+ // skip it entirely
+ }
+ else
+ {
+ // create the subdir
+ phpDocumentor_out("creating $targetdir" . PATH_DELIMITER . "$dir\n");
+ Converter::setTargetDir($targetdir . PATH_DELIMITER . $dir);
+ if (!empty($subdir))
+ {
+ $subdir .= PATH_DELIMITER;
+ }
+ $this->copyMediaRecursively($files,"$targetdir/$dir",$subdir . $dir);
+ }
+ }
+ else
+ {
+ // copy the file
+ phpDocumentor_out("copying $targetdir" . PATH_DELIMITER . $files['file']."\n");
+ $this->copyFile($files['file'],$subdir);
+ }
+ }
+ }
+ }
+
+ /**
+ * calls the converter setTargetDir, and then copies any template images and the stylesheet if they haven't been copied
+ * @see Converter::setTargetDir()
+ */
+ function setTargetDir($dir)
+ {
+ Converter::setTargetDir($dir);
+ if ($this->wrote) return;
+ $this->wrote = true;
+ $template_images = array();
+ $stylesheets = array();
+ $tdir = $dir;
+ $dir = $this->templateDir;
+ $this->templateDir = $this->templateDir.'templates/';
+ $info = new Io;
+ $this->copyMediaRecursively($info->getDirTree($this->templateDir.'media',$this->templateDir),$tdir);
+ }
+
+ /**
+ * Generate alphabetical index of all elements by package and subpackage
+ *
+ * @param string $package name of a package
+ * @see $pkg_elements, walk(), generatePkgElementIndexes()
+ */
+ function generatePkgElementIndex($package)
+ {
+// var_dump($this->pkg_elements[$package]);
+ $elementindex = array();
+ $letters = array();
+ $letterind = array();
+ $used = array();
+ $subp = '';
+ foreach($this->pkg_elements[$package] as $subpackage => $els)
+ {
+ if (empty($els)) continue;
+ if (!empty($subpackage)) $subp = " (subpackage: $subpackage)"; else $subp = '';
+ foreach($els as $letter => $yuh)
+ {
+ foreach($els[$letter] as $i => $yuh)
+ {
+ if ($els[$letter][$i]->type != 'include')
+ {
+ if (!isset($used[$letter]))
+ {
+ $letters[]['letter'] = $letter;
+ $letterind[$letter] = count($letters) - 1;
+ $used[$letter] = 1;
+ }
+ $elindex[$letter]['letter'] = $letter;
+
+ $elindex[$letter]['index'][] = $this->getIndexInformation($els[$letter][$i]);
+ }
+ }
+ }
+ }
+ ksort($elindex);
+ usort($letters,'CHMdefault_lettersort');
+ if (isset($elindex))
+ {
+ while(list($letter,$tempel) = each($elindex))
+ {
+ if (!isset($tempel))
+ {
+ unset($letters[$letterind[$tempel['letter']]]);
+ } else
+ $elementindex[] = $tempel;
+ }
+ } else $letters = array();
+ return array($elementindex,$letters);
+ }
+
+ /**
+ *
+ * @see generatePkgElementIndex()
+ */
+ function generatePkgElementIndexes()
+ {
+ $packages = array();
+ $package_names = array();
+ $pkg = array();
+ $letters = array();
+ foreach($this->pkg_elements as $package => $trash)
+ {
+ $pkgs['package'] = $package;
+ $pkg['package'] = $package;
+ list($pkg['pindex'],$letters[$package]) = $this->generatePkgElementIndex($package);
+ if (count($pkg['pindex']))
+ {
+ $packages[] = $pkg;
+ $package_names[] = $pkgs;
+ }
+ unset($pkgs);
+ unset($pkg);
+ }
+ foreach($packages as $i => $package)
+ {
+ $pnames = array();
+ for($j=0;$jreturnSee($a, $text, $with_a);
+ }
+
+ /**
+ * @param string name of function
+ * @param string package name
+ * @param string full path to look in (used in index generation)
+ * @param boolean deprecated
+ * @param boolean return just the URL, or enclose it in an html a tag
+ * @return mixed false if not found, or an html a link to the function's documentation
+ * @see parent::getFunctionLink()
+ */
+ function getFunctionLink($expr,$package, $file = false,$text = false)
+ {
+ $a = Converter::getFunctionLink($expr,$package,$file);
+ if (!$a) return false;
+ return $this->returnSee($a, $text);
+ }
+
+ /**
+ * @param string name of define
+ * @param string package name
+ * @param string full path to look in (used in index generation)
+ * @param boolean deprecated
+ * @param boolean return just the URL, or enclose it in an html a tag
+ * @return mixed false if not found, or an html a link to the define's documentation
+ * @see parent::getDefineLink()
+ */
+ function getDefineLink($expr,$package, $file = false,$text = false)
+ {
+ $a = Converter::getDefineLink($expr,$package,$file);
+ if (!$a) return false;
+ return $this->returnSee($a, $text);
+ }
+
+ /**
+ * @param string name of global variable
+ * @param string package name
+ * @param string full path to look in (used in index generation)
+ * @param boolean deprecated
+ * @param boolean return just the URL, or enclose it in an html a tag
+ * @return mixed false if not found, or an html a link to the global variable's documentation
+ * @see parent::getGlobalLink()
+ */
+ function getGlobalLink($expr,$package, $file = false,$text = false)
+ {
+ $a = Converter::getGlobalLink($expr,$package,$file);
+ if (!$a) return false;
+ return $this->returnSee($a, $text);
+ }
+
+ /**
+ * @param string name of procedural page
+ * @param string package name
+ * @param string full path to look in (used in index generation)
+ * @param boolean deprecated
+ * @param boolean return just the URL, or enclose it in an html a tag
+ * @return mixed false if not found, or an html a link to the procedural page's documentation
+ * @see parent::getPageLink()
+ */
+ function getPageLink($expr,$package, $path = false,$text = false)
+ {
+ $a = Converter::getPageLink($expr,$package,$path);
+ if (!$a) return false;
+ return $this->returnSee($a, $text);
+ }
+
+ /**
+ * @param string name of method
+ * @param string class containing method
+ * @param string package name
+ * @param string full path to look in (used in index generation)
+ * @param boolean deprecated
+ * @param boolean return just the URL, or enclose it in an html a tag
+ * @return mixed false if not found, or an html a link to the method's documentation
+ * @see parent::getMethodLink()
+ */
+ function getMethodLink($expr,$class,$package, $file = false,$text = false)
+ {
+ $a = Converter::getMethodLink($expr,$class,$package,$file);
+ if (!$a) return false;
+ return $this->returnSee($a, $text);
+ }
+
+ /**
+ * @param string name of var
+ * @param string class containing var
+ * @param string package name
+ * @param string full path to look in (used in index generation)
+ * @param boolean deprecated
+ * @param boolean return just the URL, or enclose it in an html a tag
+ * @return mixed false if not found, or an html a link to the var's documentation
+ * @see parent::getVarLink()
+ */
+ function getVarLink($expr,$class,$package, $file = false,$text = false)
+ {
+ $a = Converter::getVarLink($expr,$class,$package,$file);
+ if (!$a) return false;
+ return $this->returnSee($a, $text);
+ }
+
+ /**
+ * @param string name of class constant
+ * @param string class containing class constant
+ * @param string package name
+ * @param string full path to look in (used in index generation)
+ * @param boolean deprecated
+ * @param boolean return just the URL, or enclose it in an html a tag
+ * @return mixed false if not found, or an html a link to the var's documentation
+ * @see parent::getVarLink()
+ */
+ function getConstLink($expr,$class,$package, $file = false,$text = false)
+ {
+ $a = Converter::getConstLink($expr,$class,$package,$file);
+ if (!$a) return false;
+ return $this->returnSee($a, $text);
+ }
+
+ /**
+ * does a nat case sort on the specified second level value of the array
+ *
+ * @param mixed $a
+ * @param mixed $b
+ * @return int
+ */
+ function rcNatCmp ($a, $b)
+ {
+ $aa = strtoupper($a[$this->rcnatcmpkey]);
+ $bb = strtoupper($b[$this->rcnatcmpkey]);
+
+ return strnatcasecmp($aa, $bb);
+ }
+
+ /**
+ * does a nat case sort on the specified second level value of the array.
+ * this one puts constructors first
+ *
+ * @param mixed $a
+ * @param mixed $b
+ * @return int
+ */
+ function rcNatCmp1 ($a, $b)
+ {
+ $aa = strtoupper($a[$this->rcnatcmpkey]);
+ $bb = strtoupper($b[$this->rcnatcmpkey]);
+
+ if (strpos($aa,'CONSTRUCTOR') === 0)
+ {
+ return -1;
+ }
+ if (strpos($bb,'CONSTRUCTOR') === 0)
+ {
+ return 1;
+ }
+ if (strpos($aa,strtoupper($this->class)) === 0)
+ {
+ return -1;
+ }
+ if (strpos($bb,strtoupper($this->class)) === 0)
+ {
+ return -1;
+ }
+ return strnatcasecmp($aa, $bb);
+ }
+
+ /**
+ * Write a file to disk, and add it to the {@link $hhp_files} list of files
+ * to include in the generated CHM
+ *
+ * {@source}
+ */
+ function writefile($file,$contents)
+ {
+ $this->addHHP($this->targetDir . PATH_DELIMITER . $file);
+ Converter::writefile($file,$contents);
+ }
+
+ /**
+ * @uses $hhp_files creates the array by adding parameter $file
+ */
+ function addHHP($file)
+ {
+ $file = str_replace($this->base_dir . PATH_DELIMITER, '', $file);
+ $file = str_replace('\\',PATH_DELIMITER,$file);
+ $file = str_replace('//',PATH_DELIMITER,$file);
+ $file = str_replace(PATH_DELIMITER,'\\',$file);
+ $this->hhp_files[]['name'] = $file;
+ }
+
+ function generateTOC()
+ {
+ $comppack = '';
+ $templ = &$this->newSmarty();
+ foreach($this->TOC as $package => $TOC1)
+ {
+ $comp_subs = '';
+ $comp_subs1 = false;
+ foreach($TOC1 as $subpackage => $types)
+ {
+ $comp_types = '';
+ foreach($types as $type => $files)
+ {
+ $comp = '';
+ $templ1 = &$this->newSmarty();
+ $templ1->assign('entry', array());
+ foreach($files as $file)
+ {
+ // use book icon for classes
+ if ($type == 'Classes') {
+ $templ1->append('entry', array('paramname' => $file[0],'outputfile' => $file[1],'isclass' => 1));
+ } else {
+ $templ1->append('entry', array('paramname' => $file[0],'outputfile' => $file[1]));
+ }
+ }
+ $templ = &$this->newSmarty();
+ $templ->assign('tocsubentries',$templ1->fetch('tocentry.tpl'));
+ $templ->assign('entry', array(array('paramname' => $type)));
+ $comp_types .= $templ->fetch('tocentry.tpl');
+ }
+ if (!empty($subpackage))
+ {
+ $templ = &$this->newSmarty();
+ $templ->assign('tocsubentries',$comp_types);
+ $templ->assign('entry', array(array('paramname' => $subpackage)));
+ $comp_subs .= $templ->fetch('tocentry.tpl');
+ } else
+ {
+ $comp_subs1 = $comp_types;
+ }
+ }
+ if ($comp_subs1)
+ $templ->assign('tocsubentries',$comp_subs1);
+ if (!empty($comp_subs))
+ $templ->assign('entry', array(array('paramname' => $package, 'tocsubentries' => $comp_subs)));
+ else
+ $templ->assign('entry', array(array('paramname' => $package)));
+ $comppack .= $templ->fetch('tocentry.tpl');
+ }
+ return $comppack;
+ }
+
+ function addSourceTOC($name, $file, $package, $subpackage, $source = false)
+ {
+ $file = str_replace($this->base_dir . PATH_DELIMITER, '', $this->targetDir)
+ . PATH_DELIMITER . $file . '.html';
+ $file = str_replace('\\',PATH_DELIMITER,$file);
+ $file = str_replace('//',PATH_DELIMITER,$file);
+ $file = str_replace(PATH_DELIMITER,'\\',$file);
+ $sub = $source ? 'Source Code' : 'Examples';
+ $this->TOC[$package][$subpackage][$sub][] = array($name, $file);
+ }
+
+ function addTOC($name,$file,$package,$subpackage,$class = false,$tutorial = false)
+ {
+ $file = str_replace($this->base_dir . PATH_DELIMITER, '', $this->targetDir . PATH_DELIMITER)
+ . $file . '.html';
+ $file = str_replace('\\',PATH_DELIMITER,$file);
+ $file = str_replace('//',PATH_DELIMITER,$file);
+ $file = str_replace(PATH_DELIMITER,'\\',$file);
+ $file = str_replace($this->base_dir . '\\', '', $file);
+ $sub = $class ? 'Classes' : 'Files';
+ if ($tutorial) $sub = 'Manual';
+ $this->TOC[$package][$subpackage][$sub][] = array($name,$file);
+ }
+
+ /**
+ * Add an item to the index.hhk file
+ * @param string $name index entry name
+ * @param string $file filename containing index
+ * @param string $bookmark html anchor of location in file, if any
+ * @param string $group group this entry with a string
+ * @uses $KLinks tracks the index
+ * @author Andrew Eddie
+ */
+ function addKLink($name, $file, $bookmark='', $group='')
+ {
+ $file = $file . '.html';
+ $file = str_replace('\\',PATH_DELIMITER,$file);
+ $file = str_replace('//',PATH_DELIMITER,$file);
+ $file = str_replace(PATH_DELIMITER,'\\',$file);
+// debug("added $name, $file, $bookmark, $group ");
+ $link = $file;
+ $link .= $bookmark ? "#$bookmark" :'';
+ if ($group) {
+ $this->KLinks[$group]['grouplink'] = $file;
+ $this->KLinks[$group][] = array($name,$link);
+ }
+ $this->KLinks[] = array($name,$link);
+ }
+
+ /**
+ * Get the table of contents for index.hhk
+ * @return string contents of tocentry.tpl generated from $KLinks
+ * @author Andrew Eddie
+ */
+ function generateKLinks()
+ {
+ $templ = &$this->newSmarty();
+ $templ->assign('entry', array());
+ foreach($this->KLinks as $group=>$link)
+ {
+ if (isset($link['grouplink'])) {
+ $templg = &$this->newSmarty();
+ $templg->assign('entry', array());
+ foreach($link as $k=>$sublink)
+ {
+ if ($k != 'grouplink') {
+ $templg->append('entry', array('paramname' => $sublink[0],'outputfile' => $sublink[1]));
+ }
+ }
+ $templ->append('entry', array('paramname' => $group, 'outputfile' => $link['grouplink'], 'tocsubentries' => $templg->fetch('tocentry.tpl') ));
+ } else {
+ $templ->append('entry', array('paramname' => $link[0],'outputfile' => $link[1]));
+ }
+ }
+ return $templ->fetch('tocentry.tpl');
+ }
+
+ /**
+ * Create the phpdoc.hhp, contents.hhc files needed by MS HTML Help Compiler
+ * to create a CHM file
+ *
+ * The output function generates the table of contents (contents.hhc)
+ * and file list (phpdoc.hhp) files used to create a .CHM by the
+ * free MS HTML Help compiler.
+ * {@internal
+ * Using {@link $hhp_files}, a list of all separate .html files
+ * is created in CHM format, and written to phpdoc.hhp. This list was
+ * generated by {@link writefile}.
+ *
+ * Next, a call to the table of contents:
+ *
+ * {@source 12 2}
+ *
+ * finishes things off}}
+ * @todo use to directly call html help compiler hhc.exe
+ * @link http://www.microsoft.com/downloads/release.asp?releaseid=33071
+ * @uses generateTOC() assigns to the toc template variable
+ */
+ function Output()
+ {
+ $templ = &$this->newSmarty();
+ $templ->assign('files',$this->hhp_files);
+ $this->setTargetDir($this->base_dir);
+ Converter::writefile('phpdoc.hhp',$templ->fetch('hhp.tpl'));
+ $templ = &$this->newSmarty();
+ $templ->assign('toc',$this->generateTOC());
+ Converter::writefile('contents.hhc',$templ->fetch('contents.hhc.tpl'));
+ $templ->assign('klinks',$this->generateKLinks());
+ Converter::writefile('index.hhk',$templ->fetch('index.hhk.tpl'));
+ phpDocumentor_out("NOTE: to create the documentation.chm file, you must now run Microsoft Help Workshop on phpdoc.hhp\n");
+ phpDocumentor_out("To get the free Microsoft Help Workshop, browse to: http://go.microsoft.com/fwlink/?LinkId=14188\n");
+ flush();
+ }
+}
+
+/**
+ * @access private
+ * @global string name of the package to set as the first package
+ */
+function CHMdefault_pindexcmp($a, $b)
+{
+ global $phpDocumentor_DefaultPackageName;
+ if ($a['title'] == $phpDocumentor_DefaultPackageName) return -1;
+ if ($b['title'] == $phpDocumentor_DefaultPackageName) return 1;
+ return strnatcasecmp($a['title'],$b['title']);
+}
+
+/** @access private */
+function CHMdefault_lettersort($a, $b)
+{
+ return strnatcasecmp($a['letter'],$b['letter']);
+}
+
+/** @access private */
+function CHMdefault_outputfilter($src, &$smarty)
+{
+ return str_replace('{$subdir}',$smarty->_tpl_vars['subdir'],$src);
+}
+?>
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/options.ini b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/options.ini
new file mode 100755
index 00000000..cae1952d
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/options.ini
@@ -0,0 +1,507 @@
+preservedocbooktags = false
+
+;; used to highlight the {@source} inline tag, @filesource tag, and @example tag
+[highlightSourceTokens]
+;; format:
+;; T_CONSTANTNAME = open
+;; /T_CONSTANTNAME = close
+T_ABSTRACT =
+/T_ABSTRACT =
+T_CLONE =
+/T_CLONE =
+T_HALT_COMPILER =
+/T_HALT_COMPILER =
+T_PUBLIC =
+/T_PUBLIC =
+T_PRIVATE =
+/T_PRIVATE =
+T_PROTECTED =
+/T_PROTECTED =
+T_FINAL =
+/T_FINAL =
+T_IMPLEMENTS =
+/T_IMPLEMENTS =
+T_CLASS =
+/T_CLASS =
+T_INTERFACE =
+/T_INTERFACE =
+T_INCLUDE =
+/T_INCLUDE =
+T_INCLUDE_ONCE =
+/T_INCLUDE_ONCE =
+T_REQUIRE_ONCE =
+/T_REQUIRE_ONCE =
+T_FUNCTION =
+/T_FUNCTION =
+T_VARIABLE =
+/T_VARIABLE =
+T_CONSTANT_ENCAPSED_STRING =
+/T_CONSTANT_ENCAPSED_STRING =
+T_COMMENT =
+/T_COMMENT =
+T_OBJECT_OPERATOR =
+/T_OBJECT_OPERATOR =
+T_RETURN =
+/T_RETURN =
+T_STATIC =
+/T_STATIC =
+T_SWITCH =
+/T_SWITCH =
+T_IF =
+/T_IF =
+T_FOREACH =
+/T_FOREACH =
+T_FOR =
+/T_FOR =
+T_VAR =
+/T_VAR =
+T_EXTENDS =
+/T_EXTENDS =
+T_RETURN =
+/T_RETURN =
+T_GLOBAL =
+/T_GLOBAL =
+T_DOUBLE_COLON =
+/T_DOUBLE_COLON =
+T_OBJECT_OPERATOR =
+/T_OBJECT_OPERATOR =
+T_OPEN_TAG =
+/T_OPEN_TAG =
+T_CLOSE_TAG =
+/T_CLOSE_TAG =
+
+[highlightSource]
+;; this is for highlighting things that aren't tokens like "&"
+;; format:
+;; word = open
+;; /word = close
+@ =
+/@ =
+& =
+/& =
+[ =
+/[ =
+] =
+/] =
+! =
+/! =
+";" =
+/; =
+( =
+/( =
+) =
+/) =
+, =
+/, =
+{ =
+/{ =
+} =
+/} =
+""" =
+/" =
+
+[highlightDocBlockSourceTokens]
+;; this is for docblock tokens, using by phpDocumentor_HighlightParser
+;; tagphptype is for "string" in @param string description, for example
+docblock =
+/docblock =
+tagphptype =
+/tagphptype =
+tagvarname =
+/tagvarname =
+coretag =
+/coretag =
+tag =
+/tag =
+inlinetag =
+/inlinetag =
+internal =
+/internal =
+closetemplate =
+/closetemplate =
+docblocktemplate =
+/docblocktemplate =
+
+[highlightTutorialSourceTokens]
+;; this is for XML DocBook-based tutorials, highlighted by phpDocumentor_TutorialHighlightParser
+;;
+opentag =
+/opentag =
+;;
+closetag =
+/closetag =
+;;
+attribute =
+/attribute =
+;;
+attributevalue =
+/attributevalue =
+;; &entity;
+entity =
+/entity =
+;;
+comment =
+/comment =
+;; {@inline tag}
+itag =
+/itag =
+
+;; used for translation of html in DocBlocks
+[desctranslate]
+ul =
+/ul =
+ol =
+/ol =
+li = -
+/li =
+code =
+/code =
+var =
+/var =
+samp =
+/samp =
+kbd =
+/kbd =
+pre =
+/pre =
+p =
+/p =
+b =
+/b =
+i =
+/i =
+br =
+
+[ppage]
+;; this is the DocBook package page translation section. All DocBook tags
+;; that have a corresponding html tag must be listed here
+;;
+;; examples:
+;; 1)
+;; tagname = newtagname
+;;
+;; This is the simplest case, where all attributes will be added into the
+;; starting tag and the ending tag will be html/xml style
+;; becomes and
+;; becomes
+;;
+;;
+;; 2)
+;; tagname = newtagname
+;; tagname->attr = newattrname
+;;
+;; in this case, everything will be like the first case, except tags like:
+;; will become
+;;
+;;
+;; 3)
+;; tagname = newtagname
+;; tagname->attr = newattrname
+;; tagname->attr+value = newvalue
+;;
+;; in this case, the value is also translated to another. This can be useful
+;; for instances such as focus="middle" changing to align="center" or something
+;; of that nature.
+;; will become
+;;
+;;
+;; 4)
+;; tagname = newtagname
+;; tagname->attr1 = newattrname
+;; tagname->attr2 = newattrname
+;; tagname->attr1+value|attr2+value = newvalue
+;;
+;; in this case, two attributes combine to make one new attribute, and the combined
+;; value is translated into a new value
+;; will become
+;;
+;;
+;; 5)
+;; tagname = newtagname
+;; tagname!attr = dummy
+;;
+;; here, the attribute will be ignored. dummy is not used and may be any value
+;; will become
+;;
+;;
+;; 6)
+;; tagname = newtagname
+;; tagname! = dummy
+;;
+;; here, all attributes will be ignored. dummy is not used and may be any value
+;; will become
+;;
+;;
+;; 7)
+;; tagname = newtagname
+;; tagname/ = 1
+;;
+;; here, the tag will be translated as a single tag with no closing tag, and all
+;; attributes
+;; {text text} will become
+;;
+;;
+;; 8)
+;; tagname =
+;; /tagname = closetagtext
+;;
+;; in this case, the text will be inserted exactly as entered for
+;; and closetagtext for
+;; will become
+;; closetagtext
+;;
+;; 9)
+;; $attr$my_attribute = newattrname
+;;
+;; tagname = newtagname
+;;
+;; in this case, all occurences of my_attribute in any tag will be changed to
+;; newattrname. This is useful for changing things like role="php" to
+;; class="php," for example. Note that the text "$attr$" MUST be on the line
+;; start for phpDocumentor to recognize it.
+;;
+;; 10)
+;; &entity; = translation text
+;; " = "
+;; " = """
+;; < = <
+;;
+;; Use this to control translation of entities to their appropriate values
+
+ =
+" = "
+” = ”
+“ = “
+& = &
+< = <
+> = >
+© = ©
+
+$attr$role = class
+
+abbrev = abbr
+
+blockquote = blockquote
+
+arg = span
+arg->choice = class
+
+author = by
+/author =
+author! = 0
+
+authorblurb = blockquote
+
+authorgroup = Authors:
+/authorgroup =
+authorgroup! = 0
+
+caution = Caution
+/caution =
+caution! = 0
+
+command =
+/command =
+
+cmdsynopsis =
+/cmdsynopsis =
+
+copyright =
+/copyright =
+
+emphasis = strong
+
+example =
+/example =
+example! = 0
+
+function =
+/function = ()
+
+formalpara = p
+
+graphic = img
+graphic->fileref = src
+graphic/ =
+
+important = u
+
+informalequation = blockquote
+
+informalexample = pre
+
+inlineequation = em
+
+itemizedlist = ul
+
+listitem = li
+
+literal = code
+
+literallayout = pre
+
+option = " "
+/option =
+
+orderedlist = ol
+
+para = p
+
+programlisting =
+/programlisting =
+programlisting! = 0
+
+refentry = div
+
+refnamediv =
+/refnamediv =
+refnamediv! = 0
+
+refname = h1
+
+refpurpose =
+/refpurpose =
+
+refsynopsisdiv =
+/refsynopsisdiv =
+refsynopsisdiv! = 0
+
+refsect1 = span
+
+refsect2 =
+/refsect2 =
+
+refsect3 =
+/refsect3 =
+
+releaseinfo = (
+/releaseinfo = )
+
+simpara =
+/simpara =
+simpara! = 0
+
+subscript = sub
+
+superscript = super
+
+table = table
+
+table->colsep = rules
+table->rowsep = rules
+table->colsep+1|rowsep+1 = all
+table->colsep+1|rowsep+0 = cols
+table->colsep+0|rowsep+1 = rows
+
+table->frame = frame
+table->frame+all = border
+table->frame+none = void
+table->frame+sides = vsides
+table->frame+top = above
+table->frame+topbot = hsides
+
+thead = thead
+
+tfoot = tfoot
+
+tbody = tbody
+
+colspec = col
+
+tgroup = colgroup
+tgroup/ = 1
+tgroup->cols = span
+
+row = tr
+
+entry = td
+entry->morerows = colspan
+entry->morerows+1 = 2
+entry->morerows+2 = 3
+entry->morerows+3 = 4
+entry->morerows+4 = 5
+entry->morerows+5 = 6
+entry->morerows+6 = 7
+entry->morerows+7 = 8
+entry->morerows+8 = 9
+entry->morerows+9 = 10
+entry->morerows+10 = 11
+;; add more if you need more colspans
+
+warning =
+/warning =
+warning! = 0
+
+;; now begins the attributes that should be tags in cdata
+[$attr$id]
+open = a
+;close = /a
+cdata! = true
+quotevalues = true
+separator = "="
+;separateall = true
+$id = name
+
+;; now begins the sections that deal with
+[refsynopsisdiv_title]
+;tag_attr = true
+;attr_name = title
+cdata_start = true
+;cdata_end = true
+open =
+close =
+
+[refsect1_title]
+;tag_attr = true
+;attr_name = title
+cdata_start = true
+;cdata_end = true
+open =
+close =
+
+[refsect2_title]
+;tag_attr = true
+;attr_name = title
+cdata_start = true
+;cdata_end = true
+open =
+close =
+
+[refsect3_title]
+;tag_attr = true
+;attr_name = title
+cdata_start = true
+;cdata_end = true
+open =
+close =
+
+[para_title]
+;tag_attr = true
+;attr_name = title
+cdata_start = true
+;cdata_end = true
+open =
+close =
+
+[formalpara_title]
+;tag_attr = true
+;attr_name = title
+cdata_start = true
+;cdata_end = true
+open =
+close =
+
+[example_title]
+;tag_attr = true
+;attr_name = title
+;cdata_start = true
+cdata_end = true
+open =
+close =
+
+[table_title]
+;tag_attr = true
+;attr_name = true
+cdata_start = true
+open =
+close =
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/basicindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/basicindex.tpl
new file mode 100755
index 00000000..29a27593
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/basicindex.tpl
@@ -0,0 +1,21 @@
+{section name=letter loop=$letters}
+ {$letters[letter].letter}
+{/section}
+
+{section name=index loop=$index}
+
+top
+
+
+
+ {$index[index].letter}
+
+
+
+
+ {section name=contents loop=$index[index].index}
+ {$index[index].index[contents].name} {$index[index].index[contents].listing}
+ {/section}
+{/section}
+
+
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/blank.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/blank.tpl
new file mode 100755
index 00000000..6a05f27e
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/blank.tpl
@@ -0,0 +1,13 @@
+
+
+ {$maintitle}
+
+
+
+
+{$maintitle}
+Welcome to {$package}!
+
+This documentation was generated by phpDocumentor v{$phpdocversion}
+
+
\ No newline at end of file
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/class.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/class.tpl
new file mode 100755
index 00000000..93cd4f27
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/class.tpl
@@ -0,0 +1,94 @@
+{include file="header.tpl" eltype="class" hasel=true contents=$classcontents}
+
+
+ {if $is_interface}Interface{else}Class{/if} {$class_name}
+
+
+[line {if $class_slink}{$class_slink}{else}{$line_number}{/if}]
+
+{section name=tree loop=$class_tree.classes}{$class_tree.classes[tree]}{$class_tree.distance[tree]}{/section}
+
+{if $tutorial}
+Class Tutorial: {$tutorial}
+{/if}
+{if $children}
+Classes extended from {$class_name}:
+ {section name=kids loop=$children}
+
+ - {$children[kids].link}
+ - {$children[kids].sdesc}
+
+ {/section}
+{/if}
+{if $conflicts.conflict_type}Conflicts with classes:
+ {section name=me loop=$conflicts.conflicts}
+ {$conflicts.conflicts[me]}
+ {/section}
+
+{/if}
+Location: {$source_location}
+
+{include file="docblock.tpl" type="class" sdesc=$sdesc desc=$desc}
+
+{include file="var.tpl" show="summary"}
+
+{include file="const.tpl" show="summary"}
+
+
+
+Inherited Class Constant Summary
+
+{section name=iconsts loop=$iconsts}
+Inherited From Class {$iconsts[iconsts].parent_class}
+
+ {section name=iconsts2 loop=$iconsts[iconsts].iconsts}
+
+ {$iconsts[iconsts].iconsts[iconsts2].link}
= {$iconsts[iconsts].iconsts[iconsts2].value}
+
+ {$iconsts[iconsts].iconsts[iconsts2].sdesc}
+ {/section}
+
+
+{/section}
+
+
+
+Inherited Class Variable Summary
+
+{section name=ivars loop=$ivars}
+Inherited From Class {$ivars[ivars].parent_class}
+
+ {section name=ivars2 loop=$ivars[ivars].ivars}
+
+ {$ivars[ivars].ivars[ivars2].link}
= {$ivars[ivars].ivars[ivars2].default}
+
+ {$ivars[ivars].ivars[ivars2].sdesc}
+ {/section}
+
+
+{/section}
+
+
+{include file="method.tpl" show="summary"}
+
+
+Inherited Method Summary
+
+{section name=imethods loop=$imethods}
+Inherited From Class {$imethods[imethods].parent_class}
+
+ {section name=im2 loop=$imethods[imethods].imethods}
+
+ {$imethods[imethods].imethods[im2].link}
+ {$imethods[imethods].imethods[im2].sdesc}
+ {/section}
+
+{/section}
+
+{include file="method.tpl"}
+
+{include file="var.tpl"}
+
+{include file="const.tpl"}
+
+{include file="footer.tpl"}
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classleft.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classleft.tpl
new file mode 100755
index 00000000..65d60118
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classleft.tpl
@@ -0,0 +1,8 @@
+{foreach key=subpackage item=files from=$classleftindex}
+ {if $subpackage != ""}{$subpackage}
{/if}
+ {section name=files loop=$files}
+ {if $files[files].link != ''}{/if}
+ {$files[files].title}
+ {if $files[files].link != ''}{/if}
+ {/section}
+{/foreach}
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classtrees.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classtrees.tpl
new file mode 100755
index 00000000..6308aba9
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/classtrees.tpl
@@ -0,0 +1,12 @@
+{capture name="title"}Class Trees for Package {$package}{/capture}
+{include file="header.tpl" title=$smarty.capture.title}
+
+
+
+ {$smarty.capture.title}
+
+{section name=classtrees loop=$classtrees}
+Root class {$classtrees[classtrees].class}
+{$classtrees[classtrees].class_tree}
+{/section}
+{include file="footer.tpl"}
\ No newline at end of file
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/const.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/const.tpl
new file mode 100644
index 00000000..720a71b5
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/const.tpl
@@ -0,0 +1,29 @@
+{if $show=="summary"}
+
+
+Class Constant Summary
+
+
+ {section name=consts loop=$consts}
+
+ {$consts[consts].const_name}
= {$consts[consts].const_value|replace:"\n":"
\n"|replace:" ":" "|replace:"\t":" "}
+
+ {$consts[consts].sdesc}
+ {/section}
+
+{else}
+
+
+
+
+Class Constant Detail
+
+
+{section name=consts loop=$consts}
+
+- {$consts[consts].const_name} =
{$consts[consts].const_value|replace:"\n":"
\n"|replace:" ":" "|replace:"\t":" "}
[line {if $consts[consts].slink}{$consts[consts].slink}{else}{$consts[consts].line_number}{/if}]
+{include file="docblock.tpl" sdesc=$consts[consts].sdesc desc=$consts[consts].desc tags=$consts[consts].tags}
+
+{/section}
+
+{/if}
\ No newline at end of file
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/contents.hhc.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/contents.hhc.tpl
new file mode 100755
index 00000000..44938319
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/contents.hhc.tpl
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+{$toc}
+
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/define.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/define.tpl
new file mode 100755
index 00000000..4a3a64e9
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/define.tpl
@@ -0,0 +1,33 @@
+{if $summary}
+
+
+Constant Summary
+
+
+ {section name=def loop=$defines}
+ {$defines[def].define_name}
= {$defines[def].define_value}
+
{$defines[def].sdesc}
+ {/section}
+
+{else}
+
+
+
+Constant Detail
+
+
+ {section name=def loop=$defines}
+
+ - {$defines[def].define_name} =
{$defines[def].define_value}
[line {if $defines[def].slink}{$defines[def].slink}{else}{$defines[def].line_number}{/if}]
+ {if $defines[def].define_conflicts.conflict_type}
+ Conflicts with defines:
+ {section name=me loop=$defines[def].define_conflicts.conflicts}
+ {$defines[def].define_conflicts.conflicts[me]}
+ {/section}
+
+ {/if}
+
+ {include file="docblock.tpl" sdesc=$defines[def].sdesc desc=$defines[def].desc tags=$defines[def].tags}
+ {/section}
+
+{/if}
\ No newline at end of file
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/docblock.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/docblock.tpl
new file mode 100755
index 00000000..ef621b9b
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/docblock.tpl
@@ -0,0 +1,31 @@
+
+{if $function}
+ {if $params}
+ Parameters
+ {section name=params loop=$params}
+ {$params[params].var}
+ {$params[params].data}
+ {/section}
+ {/if}
+{/if}
+{section name=tags loop=$tags}
+{if $tags[tags].keyword == 'return'}
+ Returns
+ {$tags[tags].data}
+{/if}
+{/section}
+{if $sdesc || $desc}
+Remarks
+{/if}
+{if $sdesc}
+{$sdesc}
+{/if}
+{if $desc}
+{$desc}
+{/if}
+{section name=tags loop=$tags}
+{if $tags[tags].keyword != 'return'}
+ {$tags[tags].keyword}
+ {$tags[tags].data}
+{/if}
+{/section}
\ No newline at end of file
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/elementindex.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/elementindex.tpl
new file mode 100755
index 00000000..755f33c7
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/elementindex.tpl
@@ -0,0 +1,9 @@
+{include file="header.tpl" noleftindex=true}
+
+Index of All Elements
+Indexes by package:
+{section name=p loop=$packageindex}
+{$packageindex[p].title}
+{/section}
+{include file="basicindex.tpl" indexname="elementindex"}
+{include file="footer.tpl"}
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/errors.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/errors.tpl
new file mode 100755
index 00000000..0f526584
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/errors.tpl
@@ -0,0 +1,21 @@
+{include file="header.tpl" noleftindex=true}
+{section name=files loop=$files}
+{$files[files].file}
+{/section}
+{foreach key=file item=issues from=$all}
+
+{$file}
+{if count($issues.warnings)}
+Warnings:
+{section name=warnings loop=$issues.warnings}
+{$issues.warnings[warnings].name} - {$issues.warnings[warnings].listing}
+{/section}
+{/if}
+{if count($issues.errors)}
+Errors:
+{section name=errors loop=$issues.errors}
+{$issues.errors[errors].name} - {$issues.errors[errors].listing}
+{/section}
+{/if}
+{/foreach}
+{include file="footer.tpl"}
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/fileleft.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/fileleft.tpl
new file mode 100755
index 00000000..45bcf945
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/fileleft.tpl
@@ -0,0 +1,8 @@
+{foreach key=subpackage item=files from=$fileleftindex}
+ {if $subpackage != ""}subpackage {$subpackage}
{/if}
+ {section name=files loop=$files}
+ {if $files[files].link != ''}{/if}
+ {$files[files].title}
+ {if $files[files].link != ''}{/if}
+ {/section}
+{/foreach}
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/filesource.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/filesource.tpl
new file mode 100755
index 00000000..55c826b9
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/filesource.tpl
@@ -0,0 +1,6 @@
+{capture name="tutle"}File Source for {$name}{/capture}
+{include file="header.tpl" title=$smarty.capture.tutle}
+Source for file {$name}
+Documentation is available at {$docs}
+{$source}
+{include file="footer.tpl"}
\ No newline at end of file
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/footer.tpl b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/footer.tpl
new file mode 100755
index 00000000..157bb1cd
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/Converters/CHM/default/templates/default/templates/footer.tpl
@@ -0,0 +1,8 @@
+{if !$index}
+
+
+ Documentation generated on {$date} by phpDocumentor {$phpdocversion}
+
+{/if}
+