phpDocumentor Converters
[ class tree: Converters ] [ index: Converters ] [ all elements ]

Source for file Converter.inc

Documentation is available at Converter.inc

  1. <?php
  2. /**
  3.  * Base class for all Converters
  4.  *
  5.  * phpDocumentor :: automatic documentation generator
  6.  * 
  7.  * PHP versions 4 and 5
  8.  *
  9.  * Copyright (c) 2001-2006 Gregory Beaver
  10.  * 
  11.  * LICENSE:
  12.  * 
  13.  * This library is free software; you can redistribute it
  14.  * and/or modify it under the terms of the GNU Lesser General
  15.  * Public License as published by the Free Software Foundation;
  16.  * either version 2.1 of the License, or (at your option) any
  17.  * later version.
  18.  * 
  19.  * This library is distributed in the hope that it will be useful,
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22.  * Lesser General Public License for more details.
  23.  * 
  24.  * You should have received a copy of the GNU Lesser General Public
  25.  * License along with this library; if not, write to the Free Software
  26.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27.  *
  28.  * @category   documentation
  29.  * @package    Converters
  30.  * @author     Greg Beaver <cellog@php.net>
  31.  * @copyright  2001-2006 Gregory Beaver
  32.  * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
  33.  * @version    CVS: $Id: Converter.inc,v 1.33 2006/10/22 18:54:47 cellog Exp $
  34.  * @filesource
  35.  * @link       http://www.phpdoc.org
  36.  * @link       http://pear.php.net/PhpDocumentor
  37.  * @see        parserDocBlock, parserInclude, parserPage, parserClass
  38.  * @see        parserDefine, parserFunction, parserMethod, parserVar
  39.  * @since      1.0rc1
  40.  */
  41. /**
  42.  * Smarty template files
  43.  */
  44. include_once("phpDocumentor/Smarty-2.6.0/libs/Smarty.class.php");
  45. /**
  46.  * Base class for all output converters.
  47.  *
  48.  * The Converter marks the final stage in phpDocumentor.  phpDocumentor works
  49.  * in this order:
  50.  *
  51.  * <pre>Parsing => Intermediate Parsing organization => Conversion to output</pre>
  52.  *
  53.  * A Converter takes output from the {@link phpDocumentor_IntermediateParser} and
  54.  * converts it to output.  With version 1.2, phpDocumentor includes a variety
  55.  * of output converters:
  56.  * <ul>
  57.  *  <li>{@link HTMLframesConverter}</li>
  58.  *  <li>{@link HTMLSmartyConverter}</li>
  59.  *  <li>{@link PDFdefaultConverter}</li>
  60.  *  <li>{@link CHMdefaultConverter}</li>
  61.  *  <li>{@link CSVdia2codeConverter}</li>
  62.  *  <li>{@link XMLDocBookConverter}</li>
  63.  * </ul>
  64.  * {@internal 
  65.  * The converter takes output directly from {@link phpDocumentor_IntermediateParser}
  66.  * and using {@link walk()} or {@link walk_everything} (depending on the value of
  67.  * {@link $sort_absolutely_everything}) it "walks" over an array of phpDocumentor elements.}}}
  68.  *
  69.  * @package Converters
  70.  * @abstract
  71.  * @author Greg Beaver <cellog@users.sourceforge.net>
  72.  * @since 1.0rc1
  73.  * @version $Id: Converter.inc,v 1.33 2006/10/22 18:54:47 cellog Exp $
  74.  */
  75. class Converter
  76. {
  77.     /**
  78.      * This converter knows about the new root tree processing
  79.      * In order to fix PEAR Bug #6389
  80.      * @var boolean 
  81.      */
  82.     var $processSpecialRoots = false;
  83.     /**
  84.      * output format of this converter
  85.      *
  86.      * in Child converters, this will match the first part of the -o command-line
  87.      * as in -o HTML:frames:default "HTML"
  88.      * @tutorial phpDocumentor.howto.pkg#using.command-line.output
  89.      * @var string 
  90.      */
  91.     var $outputformat = 'Generic';
  92.     /**
  93.      * package name currently being converted
  94.      * @var string 
  95.      */
  96.     var $package = 'default';
  97.     /**
  98.      * subpackage name currently being converted
  99.      * @var string 
  100.      */
  101.     var $subpackage = '';
  102.     /**
  103.      * set to a classname if currently parsing a class, false if not
  104.      * @var string|false
  105.      */
  106.     var $class = false;
  107.     /**#@+
  108.      * @access private
  109.      */
  110.     /**
  111.      * the workhorse of linking.
  112.      *
  113.      * This array is an array of link objects of format:
  114.      * [package][subpackage][eltype][elname] = descendant of {@link abstractLink}
  115.      * eltype can be page|function|define|class|method|var
  116.      * if eltype is method or var, the array format is:
  117.      * [package][subpackage][eltype][class][elname]
  118.      * @var array 
  119.      * @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink
  120.      */
  121.     var $links array();
  122.  
  123.     /**
  124.      * the workhorse of linking, with allowance for support of multiple
  125.      * elements in different files.
  126.      *
  127.      * This array is an array of link objects of format:
  128.      * [package][subpackage][eltype][file][elname] = descendant of {@link abstractLink}
  129.      * eltype can be function|define|class|method|var
  130.      * if eltype is method or var, the array format is:
  131.      * [package][subpackage][eltype][file][class][elname]
  132.      * @var array 
  133.      * @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink
  134.     */
  135.     var $linkswithfile array();
  136.     /**#@-*/
  137.     /**
  138.      * set to value of -po commandline
  139.      * @tutorial phpDocumentor.howto.pkg#using.command-line.packageoutput
  140.      * @var mixed 
  141.      */
  142.     var $package_output;
  143.  
  144.     /**
  145.      * name of current page being converted
  146.      * @var string 
  147.      */
  148.     var $page;
  149.  
  150.     /**
  151.      * path of current page being converted
  152.      * @var string 
  153.      */
  154.     var $path;
  155.  
  156.     /**
  157.      * template for the procedural page currently being processed
  158.      * @var Smarty 
  159.      */
  160.     var $page_data;
  161.  
  162.     /**
  163.      * template for the class currently being processed
  164.      * @var Smarty 
  165.      */
  166.     var $class_data;
  167.  
  168.     /**
  169.      * current procedural page being processed
  170.      * @var parserPage 
  171.      */
  172.     var $curpage;
  173.     /**
  174.      * alphabetical index of all elements sorted by package, subpackage, page,
  175.      * and class.
  176.      * @var array Format: array(package => array(subpackage => array('page'|'class' => array(path|classname => array(element, element,...)))))
  177.      * @uses $sort_absolutely_everything if true, then $package_elements is used,
  178.      *        otherwise, the {@link ParserData::$classelements} and
  179.      *        {@link ParserData::$pageelements} variables are used
  180.      */
  181.     var $package_elements = array();
  182.     /**
  183.      * alphabetical index of all elements
  184.      *
  185.      * @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...))
  186.      * @see formatIndex(), HTMLframesConverter::formatIndex()
  187.      */
  188.     var $elements = array();
  189.     /**
  190.      * alphabetized index of procedural pages by package
  191.      *
  192.      * @see $leftindex
  193.      * @var array Format: array(package => array(subpackage => array({@link pageLink} 1,{@link pageLink} 2,...)
  194.      */
  195.     var $page_elements = array();
  196.     /**
  197.      * alphabetized index of defines by package
  198.      *
  199.      * @see $leftindex
  200.      * @var array Format: array(package => array(subpackage => array({@link defineLink} 1,{@link defineLink} 2,...)
  201.      */
  202.     var $define_elements = array();
  203.     /**
  204.      * alphabetized index of classes by package
  205.      *
  206.      * @see $leftindex
  207.      * @var array Format: array(package => array(subpackage => array({@link classLink} 1,{@link classLink} 2,...)
  208.      */
  209.     var $class_elements = array();
  210.     /**
  211.      * alphabetized index of global variables by package
  212.      *
  213.      * @see $leftindex
  214.      * @var array Format: array(package => array(subpackage => array({@link globalLink} 1,{@link globalLink} 2,...)
  215.      */
  216.     var $global_elements = array();
  217.     /**
  218.      * alphabetized index of functions by package
  219.      *
  220.      * @see $leftindex
  221.      * @var array Format: array(package => array(subpackage => array({@link functionLink} 1,{@link functionLink} 2,...)
  222.      */
  223.     var $function_elements = array();
  224.     /**
  225.      * alphabetical index of all elements, indexed by package/subpackage
  226.      *
  227.      * @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...))
  228.      * @see formatPkgIndex(), HTMLframesConverter::formatPkgIndex()
  229.      */
  230.     var $pkg_elements = array();
  231.  
  232.     /**
  233.      * alphabetical index of all elements on a page by package/subpackage
  234.      *
  235.      * The page itself has a link under ###main
  236.      * @var array Format: array(package => array(subpackage => array(path => array({@link abstractLink} descendant 1, ...)))
  237.      * @see formatLeftIndex()
  238.      */
  239.     var $page_contents = array();
  240.  
  241.     /**
  242.      * This determines whether the {@link $page_contents} array should be sorted by element type as well as alphabetically by name
  243.      * @see sortPageContentsByElementType()
  244.      * @var boolean 
  245.      */
  246.     var $sort_page_contents_by_type = false;
  247.     /**
  248.      * This is used if the content must be passed in the order it should be read, i.e. by package, procedural then classes
  249.      *
  250.      * This fixes bug 637921, and is used by {@link PDFdefaultConverter}
  251.      */
  252.     var $sort_absolutely_everything = false;
  253.     /**
  254.      * alphabetical index of all methods and vars in a class by package/subpackage
  255.      *
  256.      * The class itself has a link under ###main
  257.      * @var array 
  258.      *  Format:<pre>
  259.      *  array(package =>
  260.      *        array(subpackage =>
  261.      *              array(path =>
  262.      *                    array(class =>
  263.      *                          array({@link abstractLink} descendant 1, ...
  264.      *                         )
  265.      *                   )
  266.      *             )
  267.      *       )</pre>
  268.      * @see formatLeftIndex()
  269.      */
  270.     var $class_contents = array();
  271.     /**
  272.      * controls processing of elements marked private with @access private
  273.      *
  274.      * defaults to false.  Set with command-line --parseprivate or -pp
  275.      * @var bool 
  276.      */
  277.     var $parseprivate;
  278.     /**
  279.      * controls display of progress information while parsing.
  280.      *
  281.      * defaults to false.  Set to true for cron jobs or other situations where no visual output is necessary
  282.      * @var bool 
  283.      */
  284.     var $quietmode;
  285.  
  286.     /**
  287.      * directory that output is sent to. -t command-line sets this.
  288.      * @tutorial phpDocumentor.howto.pkg#using.command-line.target
  289.      */
  290.     var $targetDir = '';
  291.  
  292.     /**
  293.      * Directory that the template is in, relative to phpDocumentor root directory
  294.      * @var string 
  295.      */
  296.     var $templateDir = '';
  297.  
  298.     /**
  299.      * Directory that the smarty templates are in
  300.      * @var string 
  301.      */
  302.     var $smarty_dir = '';
  303.  
  304.     /**
  305.      * Name of the template, from last part of -o
  306.      * @tutorial phpDocumentor.howto.pkg#using.command-line.output
  307.      * @var string 
  308.      */
  309.     var $templateName = '';
  310.  
  311.     /**
  312.      * full path of the current file being converted
  313.      */
  314.     var $curfile;
  315.  
  316.     /**
  317.      * All class information, organized by path, and by package
  318.      * @var Classes 
  319.      */
  320.     var $classes;
  321.  
  322.     /**
  323.      * Flag used to help converters determine whether to do special source highlighting
  324.      * @var boolean 
  325.      */
  326.     var $highlightingSource = false;
  327.  
  328.     /**
  329.      * Hierarchy of packages
  330.      *
  331.      * Every package that contains classes may have parent or child classes
  332.      * in other packages.  In other words, this code is legal:
  333.      *
  334.      * <code>
  335.      * /**
  336.      *  * @package one
  337.      *  * /
  338.      * class one {}
  339.      *
  340.      * /**
  341.      *  * @package two
  342.      *  * /
  343.      * class two extends one {}
  344.      * </code>
  345.      *
  346.      * In this case, package one is a parent of package two
  347.      * @var array 
  348.      * @see phpDocumentor_IntermediateParser::$package_parents
  349.      */
  350.     var $package_parents;
  351.  
  352.     /**
  353.      * Packages associated with categories
  354.      *
  355.      * Used by the XML:DocBook/peardoc2 converter, and available to others, to
  356.      * group many packages into categories
  357.      * @see phpDocumentor_IntermediateParser::$packagecategories
  358.      * @var array 
  359.      */
  360.     var $packagecategories;
  361.  
  362.     /**
  363.      * All packages encountered in parsing
  364.      * @var array 
  365.      * @see phpDocumentor_IntermediateParser::$all_packages
  366.      */
  367.     var $all_packages;
  368.  
  369.     /**
  370.      * A list of files that have had source code generated
  371.      * @var array 
  372.      */
  373.     var $sourcePaths = array();
  374.  
  375.     /**
  376.      * Controls which of the one-element-only indexes are generated.
  377.      *
  378.      * Generation of these indexes for large packages is time-consuming.  This is an optimization feature.  An
  379.      * example of how to use this is in {@link HTMLframesConverter::$leftindex}, and in {@link HTMLframesConverter::formatLeftIndex()}.
  380.      * These indexes are intended for use as navigational aids through documentation, but can be used for anything by converters.
  381.      * @see $class_elements, $page_elements, $function_elements, $define_elements, $global_elements
  382.      * @see formatLeftIndex()
  383.      * @var array 
  384.      */
  385.     var $leftindex = array('classes' => true'pages' => true'functions' => true'defines' => true'globals' => true);
  386.  
  387.     /** @access private */
  388.     var $killclass false;
  389.     /**
  390.      * @var string 
  391.      * @see phpDocumentor_IntermediateParser::$title
  392.      */
  393.     var $title = 'Generated Documentation';
  394.  
  395.     /**
  396.      * Options for each template, parsed from the options.ini file in the template base directory
  397.      * @tutorial phpDocumentor/tutorials.pkg#conversion.ppage
  398.      * @var array 
  399.      */
  400.     var $template_options;
  401.  
  402.     /**
  403.      * Tutorials and Extended Documentation parsed from a tutorials/package[/subpackage] directory
  404.      * @tutorial tutorials.pkg
  405.      * @access private
  406.      */
  407.     var $tutorials array();
  408.  
  409.     /**
  410.      * tree-format structure of tutorials and their child tutorials, if any
  411.      * @var array 
  412.      * @access private
  413.      */
  414.     var $tutorial_tree false;
  415.  
  416.     /**
  417.      * list of tutorials that have already been processed. Used by @link _setupTutorialTree()
  418.      * @var array 
  419.      * @access private
  420.      */
  421.     var $processed_tutorials;
  422.  
  423.     /**
  424.      * List of all @todo tags and a link to the element with the @todo
  425.      *
  426.      * Format: array(package => array(link to element, array(todo {@link parserTag},...)),...)
  427.      * @tutorial tags.todo.pkg
  428.      * @var array 
  429.      */
  430.     var $todoList = array();
  431.  
  432.     /**
  433.      * Directory where compiled templates go - will be deleted on exit
  434.      *
  435.      * @var string 
  436.      * @access private
  437.      */
  438.      var $_compiledDir array();
  439.  
  440.     /**
  441.      * Initialize Converter data structures
  442.      * @param array {@link $all_packages} value
  443.      * @param array {@link $package_parents} value
  444.      * @param Classes {@link $classes} value
  445.      * @param ProceduralPages {@link $proceduralpages} value
  446.      * @param array {@link $package_output} value
  447.      * @param boolean {@link $parseprivate} value
  448.      * @param boolean {@link $quietmode} value
  449.      * @param string {@link $targetDir} value
  450.      * @param string {@link $templateDir} value
  451.      * @param string (@link $title} value
  452.      */
  453.     function Converter(&$allp&$packp&$classes&$procpages$po$pp$qm$targetDir$template$title)
  454.     {
  455.         $this->all_packages = $allp;
  456.         $this->package_parents = $packp;
  457.         $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
  458.         $this->proceduralpages &$procpages;
  459.         $this->package_output = $po;
  460.         if (is_array($po))
  461.         {
  462.             $a $po[0];
  463.             $this->all_packages = array_flip($po);
  464.             $this->all_packages[$a1;
  465.         }
  466.         $this->parseprivate = $pp;
  467.         $this->quietmode = $qm;
  468.         $this->classes = &$classes;
  469.         $this->roots $classes->getRoots($this->processSpecialRoots);
  470.         $this->title = $title;
  471.         $this->setTemplateDir($template);
  472.         $this->setTargetdir($targetDir);
  473.     }
  474.  
  475.     /**
  476.      * Called by IntermediateParser after creation
  477.      * @access private
  478.      */
  479.     function setTutorials($tutorials)
  480.     {
  481.         $this->tutorials $tutorials;
  482.     }
  483.  
  484.     /**
  485.      * @param pkg|cls|procthe tutorial type to search for
  486.      * @param tutorial name
  487.      * @param string package name
  488.      * @param string subpackage name, if any
  489.      * @return false|parserTutorialif the tutorial exists, return it
  490.      */
  491.     function hasTutorial($type$name$package$subpackage '')
  492.     {
  493.         if (isset($this->tutorials[$package][$subpackage][$type][$name '.' $type]))
  494.             return $this->tutorials[$package][$subpackage][$type][$name '.' $type];
  495.         return false;
  496.     }
  497.  
  498.     /**
  499.      * Called by {@link walk()} while converting, when the last class element
  500.      * has been parsed.
  501.      *
  502.      * A Converter can use this method in any way it pleases. HTMLframesConverter
  503.      * uses it to complete the template for the class and to output its
  504.      * documentation
  505.      * @see HTMLframesConverter::endClass()
  506.      * @abstract
  507.      */
  508.     function endClass()
  509.     {
  510.     }
  511.  
  512.     /**
  513.     * Called by {@link walk()} while converting, when the last procedural page
  514.     * element has been parsed.
  515.     *
  516.     * A Converter can use this method in any way it pleases. HTMLframesConverter
  517.     * uses it to complete the template for the procedural page and to output its
  518.     * documentation
  519.     * @see HTMLframesConverter::endClass()
  520.     * @abstract
  521.     */
  522.     function endPage()
  523.     {
  524.     }
  525.  
  526.     /**
  527.     * Called by {@link walk()} while converting.
  528.     *
  529.     * This method is intended to be the place that {@link $pkg_elements} is
  530.     * formatted for output.
  531.     * @see HTMLframesConverter::formatPkgIndex()
  532.     * @abstract
  533.     */
  534.     function formatPkgIndex()
  535.     {
  536.     }
  537.  
  538.     /**
  539.     * Called by {@link walk()} while converting.
  540.     *
  541.     * This method is intended to be the place that {@link $elements} is
  542.     * formatted for output.
  543.     * @see HTMLframesConverter::formatIndex()
  544.     * @abstract
  545.     */
  546.     function formatIndex()
  547.     {
  548.     }
  549.  
  550.     /**
  551.     * Called by {@link walk()} while converting.
  552.     *
  553.     * This method is intended to be the place that any of
  554.     * {@link $class_elements, $function_elements, $page_elements},
  555.     * {@link $define_elements}, and {@link $global_elements} is formatted for
  556.     * output, depending on the value of {@link $leftindex}
  557.     * @see HTMLframesConverter::formatLeftIndex()
  558.     * @abstract
  559.     */
  560.     function formatLeftIndex()
  561.     {
  562.     }
  563.  
  564.     /**
  565.      * Called by {@link parserSourceInlineTag::stringConvert()} to allow
  566.      * converters to format the source code the way they'd like.
  567.      *
  568.      * default returns it unchanged (html with xhtml tags)
  569.      * @param string output from highlight_string() - use this function to
  570.      *  reformat the returned data for Converter-specific output
  571.      * @return string 
  572.      * @deprecated in favor of tokenizer-based highlighting.  This will be
  573.      *              removed for 2.0
  574.      */
  575.     function unmangle($sourcecode)
  576.     {
  577.         return $sourcecode;
  578.     }
  579.  
  580.     /**
  581.      * Initialize highlight caching
  582.      */
  583.     function startHighlight()
  584.     {
  585.         $this->_highlightCache array(falsefalse);
  586.         $this->_appendHighlight '';
  587.     }
  588.  
  589.     function getHighlightState()
  590.     {
  591.         return $this->_highlightCache;
  592.     }
  593.  
  594.     function _setHighlightCache($type$token)
  595.     {
  596.         $test ($this->_highlightCache[0=== $type && $this->_highlightCache[1== $token);
  597.         if (!$test{
  598.             $this->_appendHighlight $this->flushHighlightCache();
  599.         else {
  600.             $this->_appendHighlight '';
  601.         }
  602.         $this->_highlightCache array($type$token);
  603.         return $test;
  604.     }
  605.  
  606.     /**
  607.      * Return the close text for the current token
  608.      * @return string 
  609.      */
  610.     function flushHighlightCache()
  611.     {
  612.         $hc $this->_highlightCache;
  613.         $this->_highlightCache array(falsefalse);
  614.         if ($hc[0]{
  615.             if (!isset($this->template_options[$hc[0]]['/'.$hc[1]])) {
  616.                 return '';
  617.             }
  618.             return $this->template_options[$hc[0]]['/'.$hc[1]];
  619.         }
  620.         return '';
  621.     }
  622.  
  623.     /**
  624.      * Used to allow converters to format the source code the way they'd like.
  625.      *
  626.      * default returns it unchanged.  Mainly used by the {@link HighlightParser}
  627.      * {@internal 
  628.      * The method takes information from options.ini, the template options
  629.      * file, specifically the [highlightSourceTokens] and [highlightSource]
  630.      * sections, and uses them to enclose tokens.
  631.      *
  632.      * {@source } }
  633.      * @param integer token value from {@link PHP_MANUAL#tokenizer tokenizer constants}
  634.      * @param string contents of token
  635.      * @param boolean whether the contents are preformatted or need modification
  636.      * @return string 
  637.      */
  638.     function highlightSource($token$word$preformatted false)
  639.     {
  640.         if ($token !== false)
  641.         {
  642.             if (!$preformatted$word $this->postProcess($word);
  643.             if (isset($this->template_options['highlightSourceTokens'][token_name($token)]))
  644.             {
  645.                 if ($this->_setHighlightCache('highlightSourceTokens'token_name($token))) {
  646.                     return $word;
  647.                 }
  648.                 $e $this->_appendHighlight;
  649.                 return $e $this->template_options['highlightSourceTokens'][token_name($token)$word;
  650.             else
  651.             {
  652.                 $this->_setHighlightCache(falsefalse);
  653.                 $e $this->_appendHighlight;
  654.                 return $e $word;
  655.             }
  656.         else
  657.         {
  658.             if (isset($this->template_options['highlightSource'][$word]))
  659.             {
  660.                 $newword ($preformatted $word $this->postProcess($word));
  661.                 if ($this->_setHighlightCache('highlightSource'$word)) {
  662.                     return $newword;
  663.                 }
  664.                 $e $this->_appendHighlight;
  665.                 return $e $this->template_options['highlightSource'][$word$newword;
  666.             else
  667.             {
  668.                 $this->_setHighlightCache(falsefalse);
  669.                 $e $this->_appendHighlight;
  670.                 return $e ($preformatted $word $this->postProcess($word));
  671.             }
  672.         }
  673.     }
  674.  
  675.     /**
  676.      * Used to allow converters to format the source code of DocBlocks the way
  677.      * they'd like.
  678.      *
  679.      * default returns it unchanged.  Mainly used by the {@link HighlightParser}
  680.      * {@internal 
  681.      * The method takes information from options.ini, the template options
  682.      * file, specifically the [highlightDocBlockSourceTokens] section, and uses
  683.      * it to enclose tokens.
  684.      *
  685.      * {@source } }
  686.      * @param string name of docblock token type
  687.      * @param string contents of token
  688.      * @param boolean whether the contents are preformatted or need modification
  689.      * @return string 
  690.      */
  691.     function highlightDocBlockSource($token$word$preformatted false)
  692.     {
  693.         if (empty($word)) {
  694.             $this->_setHighlightCache(falsefalse);
  695.             $e $this->_appendHighlight;
  696.             return $e $word;
  697.         }
  698.         if (isset($this->template_options['highlightDocBlockSourceTokens'][$token]))
  699.         {
  700.             if (!$preformatted$word $this->postProcess($word);
  701.             if ($this->_setHighlightCache('highlightDocBlockSourceTokens'$token)) {
  702.                 return $word;
  703.             }
  704.             $e $this->_appendHighlight;
  705.             return $e $this->template_options['highlightDocBlockSourceTokens'][$token$word;
  706.         else {
  707.             $this->_setHighlightCache(falsefalse);
  708.             $e $this->_appendHighlight;
  709.             return $e ($preformatted $word $this->postProcess($word));
  710.         }
  711.     }
  712.  
  713.     /**
  714.      * Used to allow converters to format the source code of Tutorial XML the way
  715.      * they'd like.
  716.      *
  717.      * default returns it unchanged.  Mainly used by the {@link HighlightParser}
  718.      * {@internal 
  719.      * The method takes information from options.ini, the template options
  720.      * file, specifically the [highlightDocBlockSourceTokens] section, and uses
  721.      * it to enclose tokens.
  722.      *
  723.      * {@source } }
  724.      * @param string name of docblock token type
  725.      * @param string contents of token
  726.      * @param boolean whether the contents are preformatted or need modification
  727.      * @return string 
  728.      */
  729.     function highlightTutorialSource($token$word$preformatted false)
  730.     {
  731.         if (empty($word)) {
  732.             $this->_setHighlightCache(falsefalse);
  733.             $e $this->_appendHighlight;
  734.             return $e $word;
  735.         }
  736.         if (isset($this->template_options['highlightTutorialSourceTokens'][$token]))
  737.         {
  738.             if (!$preformatted$word $this->postProcess($word);
  739.             if ($this->_setHighlightCache('highlightTutorialSourceTokens'$token)) {
  740.                 return $word;
  741.             }
  742.             $e $this->_appendHighlight;
  743.             return $e $this->template_options['highlightTutorialSourceTokens'][$token$word;
  744.         else {
  745.             $this->_setHighlightCache(falsefalse);
  746.             $e $this->_appendHighlight;
  747.             return $e ($preformatted $word $this->postProcess($word));
  748.         }
  749.     }
  750.  
  751.     /**
  752.      * Called by {@link parserReturnTag::Convert()} to allow converters to
  753.      * change type names to desired formatting
  754.      *
  755.      * Used by {@link XMLDocBookConverter::type_adjust()} to change true and
  756.      * false to the peardoc2 values
  757.      * @param string 
  758.      * @return string 
  759.      */
  760.     function type_adjust($typename)
  761.     {
  762.         return $typename;
  763.     }
  764.  
  765.     /**
  766.      * Used to convert the {@}example} inline tag in a docblock.
  767.      *
  768.      * By default, this just wraps ProgramExample
  769.      * @see XMLDocBookpeardoc2Converter::exampleProgramExample
  770.      * @param string 
  771.      * @param boolean true if this is to highlight a tutorial <programlisting>
  772.      * @return string 
  773.      */
  774.     function exampleProgramExample($example$tutorial false$inlinesourceparse null/*false*/,
  775.                             $class null/*false*/$linenum null/*false*/$filesourcepath null/*false*/)
  776.     {
  777.         return $this->ProgramExample($example$tutorial$inlinesourceparse$class$linenum$filesourcepath);
  778.     }
  779.  
  780.     /**
  781.      * Used to convert the <<code>> tag in a docblock
  782.      * @param string 
  783.      * @param boolean true if this is to highlight a tutorial <programlisting>
  784.      * @return string 
  785.      */
  786.     function ProgramExample($example$tutorial false$inlinesourceparse null/*false*/,
  787.                             $class null/*false*/$linenum null/*false*/$filesourcepath null/*false*/)
  788.     {
  789.         $this->highlightingSource = true;
  790.         if (tokenizer_ext)
  791.         {
  792.             $e $example;
  793.             if (!is_array($example))
  794.             {
  795.                 $obj new phpDocumentorTWordParser;
  796.                 $obj->setup($example);
  797.                 $e $obj->getFileSource();
  798.                 $bOpenTagFound false;
  799.                 foreach ($e as $ke => $ee)
  800.                 {
  801.                     foreach ($ee as $kee => $eee)
  802.                     {
  803.                         if ((int) $e[$ke][$kee][0== T_OPEN_TAG)
  804.                         {
  805.                             $bOpenTagFound true;
  806.                         }
  807.                     }
  808.                 }
  809.                 if (!$bOpenTagFound{
  810.                     $example "<?php\n".$example;
  811.                     $obj->setup($example);
  812.                     $e $obj->getFileSource();
  813.                     unset($e[0]);
  814.                     $e array_values($e);
  815.                 }
  816.                 unset($obj);
  817.             }
  818.             $saveclass $this->class;
  819.             $parser new phpDocumentor_HighlightParser;
  820.             if (!isset($inlinesourceparse))
  821.             {
  822.                 $example $parser->parse($e$thistrue)// force php mode
  823.             else
  824.             {
  825.                 if (isset($filesourcepath))
  826.                 {
  827.                     $example $parser->parse($e$this$inlinesourceparse$class$linenum$filesourcepath);
  828.                 elseif (isset($linenum))
  829.                 {
  830.                     $example $parser->parse($e$this$inlinesourceparse$class$linenum);
  831.                 elseif (isset($class))
  832.                 {
  833.                     $example $parser->parse($e$this$inlinesourceparse$class);
  834.                 else
  835.                 {
  836.                     $example $parser->parse($e$this$inlinesourceparse);
  837.                 }
  838.             }
  839.             $this->class = $saveclass;
  840.         else
  841.         {
  842.             $example $this->postProcess($example);
  843.         }
  844.         $this->highlightingSource = false;
  845.  
  846.         if ($tutorial)
  847.         {
  848.             return $example;
  849.         }
  850.  
  851.         if (!isset($this->template_options['desctranslate'])) return $example;
  852.         if (!isset($this->template_options['desctranslate']['code'])) return $example;
  853.         $example $this->template_options['desctranslate']['code'$example;
  854.         if (!isset($this->template_options['desctranslate']['/code'])) return $example;
  855.         return $example $this->template_options['desctranslate']['/code'];
  856.     }
  857.  
  858.     /**
  859.      * @param string 
  860.      */
  861.     function TutorialExample($example)
  862.     {
  863.         $this->highlightingSource = true;
  864.         $parse new phpDocumentor_TutorialHighlightParser;
  865.         $x $parse->parse($example$this);
  866.         $this->highlightingSource = false;
  867.         return $x;
  868.     }
  869.  
  870.     /**
  871.      * Used to convert the contents of <<li>> in a docblock
  872.      * @param string 
  873.      * @return string 
  874.      */
  875.     function ListItem($item)
  876.     {
  877.         if (!isset($this->template_options['desctranslate'])) return $item;
  878.         if (!isset($this->template_options['desctranslate']['li'])) return $item;
  879.         $item $this->template_options['desctranslate']['li'$item;
  880.         if (!isset($this->template_options['desctranslate']['/li'])) return $item;
  881.         return $item $this->template_options['desctranslate']['/li'];
  882.     }
  883.  
  884.     /**
  885.      * Used to convert the contents of <<ol>> or <<ul>> in a docblock
  886.      * @param string 
  887.      * @return string 
  888.      */
  889.     function EncloseList($list,$ordered)
  890.     {
  891.         $listname ($ordered 'ol' 'ul');
  892.         if (!isset($this->template_options['desctranslate'])) return $list;
  893.         if (!isset($this->template_options['desctranslate'][$listname])) return $list;
  894.         $list $this->template_options['desctranslate'][$listname$list;
  895.         if (!isset($this->template_options['desctranslate']['/'.$listname])) return $list;
  896.         return $list $this->template_options['desctranslate']['/'.$listname];
  897.     }
  898.  
  899.     /**
  900.      * Used to convert the contents of <<pre>> in a docblock
  901.      * @param string 
  902.      * @return string 
  903.      */
  904.     function PreserveWhiteSpace($string)
  905.     {
  906.         if (!isset($this->template_options['desctranslate'])) return $string;
  907.         if (!isset($this->template_options['desctranslate']['pre'])) return $string;
  908.         $string $this->template_options['desctranslate']['pre'$string;
  909.         if (!isset($this->template_options['desctranslate']['/pre'])) return $string;
  910.         return $string $this->template_options['desctranslate']['/pre'];
  911.     }
  912.  
  913.     /**
  914.      * Used to enclose a paragraph in a docblock
  915.      * @param string 
  916.      * @return string 
  917.      */
  918.     function EncloseParagraph($para)
  919.     {
  920.         if (!isset($this->template_options['desctranslate'])) return $para;
  921.         if (!isset($this->template_options['desctranslate']['p'])) return $para;
  922.         $para $this->template_options['desctranslate']['p'$para;
  923.         if (!isset($this->template_options['desctranslate']['/p'])) return $para;
  924.         return $para $this->template_options['desctranslate']['/p'];
  925.     }
  926.  
  927.     /**
  928.      * Used to convert the contents of <<b>> in a docblock
  929.      * @param string 
  930.      * @return string 
  931.      */
  932.     function Bolden($para)
  933.     {
  934.         if (!isset($this->template_options['desctranslate'])) return $para;
  935.         if (!isset($this->template_options['desctranslate']['b'])) return $para;
  936.         $para $this->template_options['desctranslate']['b'$para;
  937.         if (!isset($this->template_options['desctranslate']['/b'])) return $para;
  938.         return $para $this->template_options['desctranslate']['/b'];
  939.     }
  940.  
  941.     /**
  942.      * Used to convert the contents of <<i>> in a docblock
  943.      * @param string 
  944.      * @return string 
  945.      */
  946.     function Italicize($para)
  947.     {
  948.         if (!isset($this->template_options['desctranslate'])) return $para;
  949.         if (!isset($this->template_options['desctranslate']['i'])) return $para;
  950.         $para $this->template_options['desctranslate']['i'$para;
  951.         if (!isset($this->template_options['desctranslate']['/i'])) return $para;
  952.         return $para $this->template_options['desctranslate']['/i'];
  953.     }
  954.  
  955.     /**
  956.      * Used to convert the contents of <<var>> in a docblock
  957.      * @param string 
  958.      * @return string 
  959.      */
  960.     function Varize($para)
  961.     {
  962.         if (!isset($this->template_options['desctranslate'])) return $para;
  963.         if (!isset($this->template_options['desctranslate']['var'])) return $para;
  964.         $para $this->template_options['desctranslate']['var'$para;
  965.         if (!isset($this->template_options['desctranslate']['/var'])) return $para;
  966.         return $para $this->template_options['desctranslate']['/var'];
  967.     }
  968.  
  969.     /**
  970.      * Used to convert the contents of <<kbd>> in a docblock
  971.      * @param string 
  972.      * @return string 
  973.      */
  974.     function Kbdize($para)
  975.     {
  976.         if (!isset($this->template_options['desctranslate'])) return $para;
  977.         if (!isset($this->template_options['desctranslate']['kbd'])) return $para;
  978.         $para $this->template_options['desctranslate']['kbd'$para;
  979.         if (!isset($this->template_options['desctranslate']['/kbd'])) return $para;
  980.         return $para $this->template_options['desctranslate']['/kbd'];
  981.     }
  982.  
  983.     /**
  984.      * Used to convert the contents of <<samp>> in a docblock
  985.      * @param string 
  986.      * @return string 
  987.      */
  988.     function Sampize($para)
  989.     {
  990.         if (!isset($this->template_options['desctranslate'])) return $para;
  991.         if (!isset($this->template_options['desctranslate']['samp'])) return $para;
  992.         $para $this->template_options['desctranslate']['samp'$para;
  993.         if (!isset($this->template_options['desctranslate']['/samp'])) return $para;
  994.         return $para $this->template_options['desctranslate']['/samp'];
  995.     }
  996.  
  997.     /**
  998.      * Used to convert <<br>> in a docblock
  999.      * @param string 
  1000.      * @return string 
  1001.      */
  1002.     function Br($para)
  1003.     {
  1004.         if (!isset($this->template_options['desctranslate'])) return $para;
  1005.         if (!isset($this->template_options['desctranslate']['br'])) return $para;
  1006.         $para $this->template_options['desctranslate']['br'$para;
  1007.         return $para;
  1008.     }
  1009.  
  1010.     /**
  1011.      * This version does nothing
  1012.      *
  1013.      * Perform necessary post-processing of string data.  For example, the HTML
  1014.      * Converters should escape < and > to become &lt; and &gt;
  1015.      * @return string 
  1016.      */
  1017.     function postProcess($text)
  1018.     {
  1019.         return $text;
  1020.     }
  1021.  
  1022.     /**
  1023.      * Creates a table of contents for a {@}toc} inline tag in a tutorial
  1024.      *
  1025.      * This function should return a formatted table of contents.  By default, it
  1026.      * does nothing, it is up to the converter to format the TOC
  1027.      * @abstract
  1028.      * @return string table of contents formatted for use in the current output format
  1029.      * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...)
  1030.      */
  1031.     function formatTutorialTOC($toc)
  1032.     {
  1033.         return '';
  1034.     }
  1035.  
  1036.     /**
  1037.      * Write out the formatted source code for a php file
  1038.      *
  1039.      * This function provides the primary functionality for the
  1040.      * {@tutorial tags.filesource.pkg} tag.
  1041.      * @param string full path to the file
  1042.      * @param string fully highlighted/linked source code of the file
  1043.      * @abstract
  1044.      */
  1045.     function writeSource($filepath$source)
  1046.     {
  1047.         debug($source);
  1048.         return;
  1049.     }
  1050.  
  1051.     /**
  1052.      * Write out the formatted source code for an example php file
  1053.      *
  1054.      * This function provides the primary functionality for the
  1055.      * {@tutorial tags.example.pkg} tag.
  1056.      * @param string example title
  1057.      * @param string example filename (no path)
  1058.      * @param string fully highlighted/linked source code of the file
  1059.      * @abstract
  1060.      */
  1061.     function writeExample($title$path$source)
  1062.     {
  1063.         return;
  1064.     }
  1065.  
  1066.     /** Translate the path info into a unique file name for the highlighted
  1067.      * source code.
  1068.      * @param string $pathinfo 
  1069.      * @return string 
  1070.      */
  1071.     function getFileSourceName($path)
  1072.     {
  1073.         global $_phpDocumentor_options;
  1074.         $pathinfo $this->proceduralpages->getPathInfo($path$this);
  1075.         $pathinfo['source_loc'str_replace($_phpDocumentor_options['Program_Root'].'/','',$pathinfo['source_loc']);
  1076.         $pathinfo['source_loc'str_replace('/','_',$pathinfo['source_loc']);
  1077.         return "fsource_{$pathinfo['package']}_{$pathinfo['subpackage']}_{$pathinfo['source_loc']}";
  1078.     }
  1079.  
  1080.     /** Return the fixed path to the source-code file folder.
  1081.      * @param string $base Path is relative to this folder
  1082.      * @return string 
  1083.      */
  1084.     function getFileSourcePath($base)
  1085.     {
  1086.         if (substr($basestrlen($base1!= PATH_DELIMITER{
  1087.             $base .= PATH_DELIMITER;
  1088.         }
  1089.         return $base '__filesource';
  1090.     }
  1091.  
  1092.     /** Return the path to the current
  1093.      * @param string $pathinfo 
  1094.      * @return string 
  1095.      */
  1096.     function getCurrentPageURL()
  1097.     {
  1098.         return '{$srcdir}' PATH_DELIMITER $this->page_dir;
  1099.     }
  1100.  
  1101.     /**
  1102.      * @return string an output-format dependent link to phpxref-style highlighted
  1103.      *  source code
  1104.      * @abstract
  1105.      */
  1106.     function getSourceLink($path)
  1107.     {
  1108.         return '';
  1109.     }
  1110.  
  1111.     /**
  1112.      * @return string Link to the current page being parsed.
  1113.      *  Should return {@link $curname} and a converter-specific extension.
  1114.      * @abstract
  1115.      */
  1116.     function getCurrentPageLink()
  1117.     {
  1118.     }
  1119.  
  1120.     /**
  1121.      * Return a line of highlighted source code with formatted line number
  1122.      *
  1123.      * If the $path is a full path, then an anchor to the line number will be
  1124.      * added as well
  1125.      * @param integer line number
  1126.      * @param string highlighted source code line
  1127.      * @param false|stringfull path to @filesource file this line is a part of,
  1128.      *         if this is a single line from a complete file.
  1129.      * @return string formatted source code line with line number
  1130.      */
  1131.     function sourceLine($linenumber$line$path false)
  1132.     {
  1133.         if ($path)
  1134.         {
  1135.             return $this->getSourceAnchor($path$linenumber.
  1136.                    $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
  1137.         else
  1138.         {
  1139.             return $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
  1140.         }
  1141.     }
  1142.  
  1143.     /**
  1144.      * Determine whether an element's file has generated source code, used for
  1145.      * linking to line numbers of source.
  1146.      *
  1147.      * Wrapper for {@link $sourcePaths} in this version
  1148.      * @param string full path to the source code file
  1149.      * @return boolean 
  1150.      */
  1151.     function hasSourceCode($path)
  1152.     {
  1153.         return isset($this->sourcePaths[$path]);
  1154.     }
  1155.  
  1156.     /**
  1157.      * Mark a file as having had source code highlighted
  1158.      * @param string full path of source file
  1159.      */
  1160.     function setSourcePaths($path)
  1161.     {
  1162.         $this->sourcePaths[$pathtrue;
  1163.     }
  1164.  
  1165.     /**
  1166.      * Used to translate an XML DocBook entity like &rdquo; from a tutorial by
  1167.      * reading the options.ini file for the template.
  1168.      * @param string entity name
  1169.      */
  1170.     function TranslateEntity($name)
  1171.     {
  1172.         if (!isset($this->template_options['ppage']))
  1173.         {
  1174.             if (!$this->template_options['preservedocbooktags'])
  1175.             return '';
  1176.             else
  1177.             return '&'.$name.';';
  1178.         }
  1179.         if (isset($this->template_options['ppage']['&'.$name.';']))
  1180.         {
  1181.             return $this->template_options['ppage']['&'.$name.';'];
  1182.         else
  1183.         {
  1184.             if (!$this->template_options['preservedocbooktags'])
  1185.             return '';
  1186.             else
  1187.             return '&'.$name.';';
  1188.         }
  1189.     }
  1190.  
  1191.     /**
  1192.      * Used to translate an XML DocBook tag from a tutorial by reading the
  1193.      * options.ini file for the template.
  1194.      * @param string tag name
  1195.      * @param string any attributes Format: array(name => value)
  1196.      * @param string the tag contents, if any
  1197.      * @param string the tag contents, if any, unpost-processed
  1198.      * @return string 
  1199.      */
  1200.     function TranslateTag($name,$attr,$cdata,$unconvertedcdata)
  1201.     {
  1202.         if (!isset($this->template_options['ppage']))
  1203.         {
  1204.             if (!$this->template_options['preservedocbooktags'])
  1205.             return $cdata;
  1206.             else
  1207.             return '<'.$name.$this->AttrToString($name,$attr,true).'>'.$cdata.'</'.$name.'>'."\n";
  1208.         }
  1209.         // make sure this template transforms the tag into something
  1210.         if (isset($this->template_options['ppage'][$name]))
  1211.         {
  1212.             // test for global attribute transforms like $attr$role = class, changing
  1213.             // all role="*" attributes to class="*" in html, for example
  1214.             foreach($attr as $att => $val)
  1215.             {
  1216.                 if (isset($this->template_options['$attr$'.$att]))
  1217.                 {
  1218.                     $new '';
  1219.                     if (!isset($this->template_options['$attr$'.$att]['close']))
  1220.                     {
  1221.                         $new .= '<'.$this->template_options['$attr$'.$att]['open'];
  1222.                         if (isset($this->template_options['$attr$'.$att]['cdata!']))
  1223.                         {
  1224.                             if (isset($this->template_options['$attr$'.$att]['separateall']))
  1225.                             $new .= $this->template_options['$attr$'.$att]['separator'];
  1226.                             else
  1227.                             $new .= ' ';
  1228.                             $new .= $this->template_options['$attr$'.$att]['$'.$att];
  1229.                             $new .= $this->template_options['$attr$'.$att]['separator'];
  1230.                             if ($this->template_options['$attr$'.$att]['quotevalues']$val '"'.$val.'"';
  1231.                             $new .= $val.'>';
  1232.                         else
  1233.                         {
  1234.                             $new .= '>'.$val;
  1235.                         }
  1236.                         $new .= '</'.$this->template_options['$attr$'.$att]['open'].'>';
  1237.                     else
  1238.                     {
  1239.                         $new .= $this->template_options['$attr$'.$att]['open'$val $this->template_options['$attr$'.$att]['close'];
  1240.                     }
  1241.                     unset($attr[$att]);
  1242.                     $cdata $new $cdata;
  1243.                 }
  1244.             }
  1245.  
  1246.             if (!isset($this->template_options['ppage']['/'.$name]))
  1247.             {// if the close tag isn't specified, we put opening and closing tags around it, with translated attributes
  1248.                 if (isset($this->template_options['ppage'][$name.'/']))
  1249.                 $cdata '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'/>' $cdata;
  1250.                 else
  1251.                 $cdata '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'>' $cdata .
  1252.                          '</'.$this->template_options['ppage'][$name].'>';
  1253.             else
  1254.             // if close tag is specified, use the open and close as literal
  1255.                 if ($name == 'programlisting' && isset($attr['role']&&
  1256.                       ($attr['role'== 'php' || $attr['role'== 'tutorial' || $attr['role'== 'html'))
  1257.                 // highlight PHP source
  1258. //                    var_dump($unconvertedcdata, $cdata);exit;
  1259.                     if ($attr['role'== 'php'{
  1260.                         $cdata $this->ProgramExample($unconvertedcdatatrue);
  1261.                     elseif ($attr['role'== 'tutorial'{
  1262.                         $cdata $this->TutorialExample($unconvertedcdata);
  1263.                     elseif ($attr['role'== 'html'{
  1264.                         $cdata $unconvertedcdata;
  1265.                     }
  1266.                 else
  1267.                 {// normal case below
  1268.                     $cdata $this->template_options['ppage'][$name].$this->AttrToString($name,$attr)$cdata .$this->template_options['ppage']['/'.$name];
  1269.                 }
  1270.             }
  1271.             return $cdata;
  1272.         else
  1273.         {
  1274.             if ($this->template_options['preservedocbooktags'])
  1275.             {
  1276.                 return '<'.$name.$this->AttrToString($name,$attr,true).'>' $cdata .
  1277.                          '</'.$name.'>'."\n";
  1278.             else
  1279.             {
  1280.                 return $cdata;
  1281.             }
  1282.         }
  1283.     }
  1284.  
  1285.     /**
  1286.      * Convert the attribute of a Tutorial docbook tag's attribute list
  1287.      * to a string based on the template options.ini
  1288.      * @param string tag name
  1289.      * @param attribute array
  1290.      * @param boolean if true, returns attrname="value"...
  1291.      * @return string 
  1292.      */
  1293.     function AttrToString($tag,$attr,$unmodified false)
  1294.     {
  1295.         $ret '';
  1296.         if ($unmodified)
  1297.         {
  1298.             $ret ' ';
  1299.             foreach($attr as $n => $v)
  1300.             {
  1301.                 $ret .= $n.' = "'.$v.'"';
  1302.             }
  1303.             return $ret;
  1304.         }
  1305.         // no_attr tells us to ignore all attributes
  1306.         if (isset($this->template_options['no_attr'])) return $ret;
  1307.         // tagname! tells us to ignore all attributes for this tag
  1308.         if (isset($this->template_options['ppage'][$tag.'!'])) return $ret;
  1309.         if (count($attr)) $ret ' ';
  1310.         // pass 1, check to see if any attributes add together
  1311.         $same array();
  1312.         foreach($attr as $n => $v)
  1313.         {
  1314.             if (isset($this->template_options['ppage'][$tag.'->'.$n]))
  1315.             {
  1316.                 $same[$this->template_options['ppage'][$tag.'->'.$n]][$n;
  1317.             }
  1318.         }
  1319.         foreach($attr as $n => $v)
  1320.         {
  1321.             if (isset($this->template_options['ppage'][$tag.'->'.$n]))
  1322.             {
  1323.                 if (count($same[$this->template_options['ppage'][$tag.'->'.$n]]== 1)
  1324.                 // only 1 attribute translated for this one
  1325.                     // this is useful for equivalent value names
  1326.                     if (isset($this->template_options['ppage'][$tag.'->'.$n.'+'.$v])) $v $this->template_options['ppage'][$tag.'->'.$n.'+'.$v];
  1327.                 else
  1328.                 // more than 1 attribute combines to make the new attribute
  1329.                     $teststrtemp array();
  1330.                     foreach($same[$this->template_options['ppage'][$tag.'->'.$n]] as $oldattr)
  1331.                     {
  1332.                         $teststrtemp[$oldattr.'+'.$attr[$oldattr];
  1333.                     }
  1334.                     $teststrs array();
  1335.                     $num count($same[$this->template_options['ppage'][$tag.'->'.$n]]);
  1336.                     for($i=0;$i<$num;$i++)
  1337.                     {
  1338.                         $started false;
  1339.                         $a '';
  1340.                         for($j=$i;!$started || $j != $i;$j ($j $i$num)
  1341.                         {
  1342.                             if (!empty($a)) $a .= '|';
  1343.                             $a .= $teststrtemp[$j];
  1344.                         }
  1345.                         $teststrs[$i$a;
  1346.                     }
  1347.                     $done false;
  1348.                     foreach($teststrs as $test)
  1349.                     {
  1350.                         if ($donebreak;
  1351.                         if (isset($this->template_options['ppage'][$tag.'->'.$test]))
  1352.                         {
  1353.                             $done true;
  1354.                             $v $this->template_options['ppage'][$tag.'->'.$test];
  1355.                         }
  1356.                     }
  1357.                 }
  1358.                 $ret .= $this->template_options['ppage'][$tag.'->'.$n].' = "'.$v.'"';
  1359.             else
  1360.             {
  1361.                 if (!isset($this->template_options['ppage'][$tag.'!'.$n]))
  1362.                 {
  1363.                     if (isset($this->template_options['ppage']['$attr$'.$n]))
  1364.                     $ret .= $this->template_options['ppage']['$attr$'.$n].' = "'.$v.'"';
  1365.                     else
  1366.                     $ret .= $n.' = "'.$v.'"';
  1367.                 }
  1368.             }
  1369.         }
  1370.         return $ret;
  1371.     }
  1372.  
  1373.     /**
  1374.      * Convert the title of a Tutorial docbook tag section
  1375.      * to a string based on the template options.ini
  1376.      * @param string tag name
  1377.      * @param array 
  1378.      * @param string title text
  1379.      * @param string 
  1380.      * @return string 
  1381.      */
  1382.     function ConvertTitle($tag,$attr,$title,$cdata)
  1383.     {
  1384.         if (!isset($this->template_options[$tag.'_title'])) return array($attr,$title.$cdata);
  1385.         if (isset($this->template_options[$tag.'_title']['tag_attr']))
  1386.         {
  1387.             $attr[$this->template_options[$tag.'_title']['tag_attr']] urlencode($cdata);
  1388.             $cdata '';
  1389.         elseif(isset($this->template_options[$tag.'_title']['cdata_start']))
  1390.         {
  1391.             $cdata $this->template_options[$tag.'_title']['open'$title .
  1392.                      $this->template_options[$tag.'_title']['close'$cdata;
  1393.         else $cdata $title.$cdata;
  1394.         return array($attr,$cdata);
  1395.     }
  1396.  
  1397.     /**
  1398.      * Return a converter-specific id to distinguish tutorials and their
  1399.      * sections
  1400.      *
  1401.      * Used by {@}id}
  1402.      * @return string 
  1403.      */
  1404.     function getTutorialId($package,$subpackage,$tutorial,$id)
  1405.     {
  1406.         return $package.$subpackage.$tutorial.$id;
  1407.     }
  1408.  
  1409.     /**
  1410.      * Create the {@link $elements, $pkg_elements} and {@link $links} arrays
  1411.      * @access private
  1412.      * @todo version 2.0 - faulty package_output logic should be removed
  1413.      *
  1414.      *        in this version, if the parent file isn't in the package, all
  1415.      *        the procedural elements are simply shunted to another package!
  1416.      */
  1417.     function _createPkgElements(&$pages)
  1418.     {
  1419.         if (empty($this->elements))
  1420.         {
  1421.             $this->elements = array();
  1422.             $this->pkg_elements = array();
  1423.             $this->links array();
  1424.             phpDocumentor_out('Building indexes...');
  1425.             flush();
  1426.             foreach($pages as $j => $flub)
  1427.             {
  1428.                 $this->package = $pages[$j]->parent->package;
  1429.                 $this->subpackage = $pages[$j]->parent->subpackage;
  1430.                 $this->class = false;
  1431.                 $this->curfile = $pages[$j]->parent->getFile();
  1432.                 $this->curname $this->getPageName($pages[$j]->parent);
  1433.                 $this->curpath $pages[$j]->parent->getPath();
  1434.                 $use true;
  1435.                 if ($this->package_output)
  1436.                 {
  1437.                     if (in_array($this->package,$this->package_output))
  1438.                     {
  1439.                         $this->addElement($pages[$j]->parent,$pages[$j]);
  1440.                     else
  1441.                     {
  1442.                         if (count($pages[$j]->classelements))
  1443.                         {
  1444.                             list(,$pages[$j]->parent->packageeach($this->package_output);
  1445.                             reset($this->package_output);
  1446.                             $pages[$j]->parent->subpackage '';
  1447.                             $this->addElement($pages[$j]->parent,$pages[$j]);
  1448.                         else
  1449.                         {
  1450.                             unset($pages[$j]);
  1451.                             continue;
  1452.                         }
  1453.                     }
  1454.                 else
  1455.                 {
  1456.                     $this->addElement($pages[$j]->parent,$pages[$j]);
  1457.                 }
  1458.                 if ($use)
  1459.                 for($i=0$i<count($pages[$j]->elements)$i++)
  1460.                 {
  1461.                     $pages[$j]->elements[$i]->docblock->package $this->package;
  1462.                     $pages[$j]->elements[$i]->docblock->subpackage $this->subpackage;
  1463.                     $this->proceduralpages->replaceElement($pages[$j]->elements[$i]);
  1464.                     $this->addElement($pages[$j]->elements[$i]);
  1465.                 }
  1466.                 for($i=0$i<count($pages[$j]->classelements)$i++)
  1467.                 {
  1468.                     if ($this->class)
  1469.                     {
  1470.                         if ($pages[$j]->classelements[$i]->type == 'class')
  1471.                         {
  1472.                             if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1473.                             $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1474.                             if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1475.                             $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1476.                             $this->class = $pages[$j]->classelements[$i]->name;
  1477.                         else
  1478.                         {
  1479.                             if ($this->killclasscontinue;
  1480.                             // force all contained elements to have parent package/subpackage
  1481.                             $pages[$j]->classelements[$i]->docblock->package $this->package;
  1482.                             $pages[$j]->classelements[$i]->docblock->subpackage $this->subpackage;
  1483.                         }
  1484.                     }
  1485.                     if ($pages[$j]->classelements[$i]->type == 'class')
  1486.                     {
  1487.                         if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1488.                         $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1489.                         if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1490.                         $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1491.                         $this->class = $pages[$j]->classelements[$i]->name;
  1492.                     }
  1493.                     if (!$this->killclass$this->addElement($pages[$j]->classelements[$i]);
  1494.                 }
  1495.             }
  1496.             phpDocumentor_out("done\n");
  1497.             flush();
  1498.         }
  1499.         $this->sortIndexes();
  1500.         $this->sortTodos();
  1501.         if ($this->sort_page_contents_by_type$this->sortPageContentsByElementType($pages);
  1502.     }
  1503.  
  1504.     /**
  1505.      * Process the {@link $tutorials} array
  1506.      *
  1507.      * Using the tutorialname.ext.ini files, this method sets up tutorial
  1508.      * hierarchy.  There is some minimal error checking to make sure that no
  1509.      * tutorial links to itself, even two levels deep as in tute->next->tute.
  1510.      *
  1511.      * If all tests pass, it creates the hierarchy
  1512.      * @uses generateTutorialOrder()
  1513.      * @uses _setupTutorialTree()
  1514.      * @access private
  1515.      */
  1516.     function _processTutorials()
  1517.     {
  1518.         $parents $all array();
  1519.         foreach($this->tutorials as $package => $els)
  1520.         {
  1521.             if ($this->package_output)
  1522.             {
  1523.                 if (!in_array($package,$this->package_output))
  1524.                 {
  1525.                     unset($this->tutorials[$package]);
  1526.                     continue;
  1527.                 }
  1528.             }
  1529.             if (!isset($this->pkg_elements[$package]))
  1530.             {
  1531.                 unset($this->tutorials[$package]);
  1532.                 continue;
  1533.             }
  1534.             foreach($els as $subpackage => $els2)
  1535.             {
  1536.                 foreach($els2 as $type => $tutorials)
  1537.                 {
  1538.                     foreach($tutorials as $tutorial)
  1539.                     {
  1540.                         if ($tutorial->ini)
  1541.                         {
  1542.                             if (isset($tutorial->ini['Linked Tutorials']))
  1543.                             {
  1544.                                 foreach($tutorial->ini['Linked Tutorials'as $child)
  1545.                                 {
  1546.                                     $sub (empty($tutorial->subpackage'' $tutorial->subpackage '/');
  1547.                                     $kid $tutorial->package '/' $sub $child '.' $tutorial->tutorial_type;
  1548.                                     // parent includes self as a linked tutorial?
  1549.                                     $kidlink $this->getTutorialLink($kid,false,false,array($tutorial->package));
  1550.                                     if (is_object($kidlink&& $this->returnSee($kidlink== $tutorial->getLink($this))
  1551.                                     // bad!
  1552.                                         addErrorDie(PDERROR_TUTORIAL_IS_OWN_CHILD,$tutorial->name,$tutorial->name.'.ini');
  1553.                                     }
  1554.                                 }
  1555.                                 $parents[$tutorial;
  1556.                             }
  1557.                         }
  1558.                         $all[$package][$subpackage][$type][$tutorial;
  1559.                     }
  1560.                 }
  1561.             }
  1562.         }
  1563.         // loop error-checking, use this to eliminate possibility of accidentally linking to a parent as a child
  1564.         $testlinks array();
  1565.         foreach($parents as $parent)
  1566.         {
  1567.             $testlinks[$parent->name]['links'][$parent->getLink($this);
  1568.             $testlinks[$parent->name]['name'][$parent->getLink($this)$parent->name;
  1569.         }
  1570.         // generate the order of tutorials, and link them together
  1571.         foreach($parents as $parent)
  1572.         {
  1573.             foreach($parent->ini['Linked Tutorials'as $child)
  1574.             {
  1575.                 $sub (empty($parent->subpackage'' $parent->subpackage '/');
  1576.                 $kid $parent->package '/' $sub $child '.' $parent->tutorial_type;
  1577.                 // child tutorials must be in the same package AND subpackage
  1578.                 // AND have the same extension as the parent, makes things clearer for both ends
  1579.                 if (in_array($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))),$testlinks[$parent->name]['links']))
  1580.                     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');
  1581.                 if ($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))) == $kid)
  1582.                 {
  1583.                     addWarning(PDERROR_CHILD_TUTORIAL_NOT_FOUND$child '.' $parent->tutorial_type$parent->name .'.ini',$parent->package$parent->subpackage);
  1584.                 }
  1585.             }
  1586.         }
  1587.         $new $tree $roots array();
  1588.         // build a list of all 'root' tutorials (tutorials without parents).
  1589.         foreach($parents as $i => $parent)
  1590.         {
  1591.             if ($parent->isChildOf($parents)) {
  1592.                 $roots[$parent;
  1593.             }
  1594.         }
  1595.         $parents $roots;
  1596.         // add the parents and all child tutorials in order to the list of tutorials to process
  1597.         foreach($parents as $parent)
  1598.         {
  1599.             $this->generateTutorialOrder($parent,$all,$new);
  1600.         }
  1601.         if (count($all))
  1602.         {
  1603.             // add the leftover tutorials
  1604.             foreach($all as $package => $els)
  1605.             {
  1606.                 foreach($els as $subpackage => $els2)
  1607.                 {
  1608.                     foreach($els2 as $type => $tutorials)
  1609.                     {
  1610.                         foreach($tutorials as $tutorial)
  1611.                         {
  1612.                             $new[$package][$subpackage][$type][$tutorial;
  1613.                         }
  1614.                     }
  1615.                 }
  1616.             }
  1617.         }
  1618.         // remove the old, unprocessed tutorials, and set it up with the next code
  1619.         $this->tutorials array();
  1620.         // reset integrity of the tutorial list
  1621.         $prev false;
  1622.         uksort($new'tutorialcmp');
  1623. //        debug($this->vardump_tree($new));exit;
  1624.         foreach($new as $package => $els)
  1625.         {
  1626.             foreach($els as $subpackage => $els2)
  1627.             {
  1628.                 foreach($els2 as $type => $tutorials)
  1629.                 {
  1630.                     foreach($tutorials as $tutorial)
  1631.                     {
  1632.                         if ($prev)
  1633.                         {
  1634.                             $this->tutorials[$prevpackage][$prevsubpackage][$prevtype][$prevname]->setNext($tutorial,$this);
  1635.                             $tutorial->setPrev($prev,$this);
  1636.                         }
  1637.                         $this->tutorials[$package][$subpackage][$type][$tutorial->name$tutorial;
  1638.                         $prev $tutorial->getLink($this,true);
  1639.                         $prevpackage $package;
  1640.                         $prevsubpackage $subpackage;
  1641.                         $prevtype $type;
  1642.                         $prevname $tutorial->name;
  1643.                     }
  1644.                 }
  1645.             }
  1646.         }
  1647.         $this->tutorial_tree $this->_setupTutorialTree();
  1648.         return $new;
  1649.     }
  1650.  
  1651.     /**
  1652.     * called by {@link phpDocumentor_IntermediateParser::Convert()} to traverse
  1653.     * the array of pages and their elements, converting them to the output format
  1654.     *
  1655.     * The walk() method should be flexible enough such that it never needs
  1656.     * modification.  walk() sets up all of the indexes, and sorts everything in
  1657.     * logical alphabetical order.  It then passes each element individually to
  1658.     * {@link Convert()}, which then passes to the Convert*() methods.  A child
  1659.     * Converter need not override any of these unless special functionality must
  1660.     * be added. see {@tutorial Converters/template.vars.cls} for details.
  1661.     * {@internal 
  1662.     * walk() first creates all of the indexes {@link $elements, $pkg_elements}
  1663.     * and the left indexes specified by {@link $leftindexes},
  1664.     * and then sorts them by calling {@link sortIndexes()}.
  1665.     *
  1666.     * Next, it converts all README/CHANGELOG/INSTALL-style files, using
  1667.     * {@link Convert_RIC}.
  1668.     *
  1669.     * After this, it
  1670.     * passes all package-level docs to Convert().  Then, it calls the index
  1671.     * sorting functions {@link formatPkgIndex(), formatIndex()} and
  1672.     * {@link formatLeftIndex()}.
  1673.     *
  1674.     * Finally, it converts each procedural page in alphabetical order.  This
  1675.     * stage passes elements from the physical file to Convert() in alphabetical
  1676.     * order.  First, procedural page elements {@link parserDefine, parserInclude}
  1677.     * {@link parserGlobal}, and {@link parserFunction} are passed to Convert().
  1678.     *
  1679.     * Then, class elements are passed in this order: {@link parserClass}, then
  1680.     * all of the {@link parserVar}s in the class and all of the
  1681.     * {@link parserMethod}s in the class.  Classes are in alphabetical order,
  1682.     * and both vars and methods are in alphabetical order.
  1683.     *
  1684.     * Finally, {@link ConvertErrorLog()} is called and the data walk is complete.}}}
  1685.     * @param array Format: array(fullpath => {@link parserData} structure with full {@link parserData::$elements}
  1686.     *                                          and {@link parserData::$class_elements}.
  1687.     * @param array Format: array({@link parserPackagePage} 1, {@link parserPackagePage} 2,...)
  1688.     * @uses Converter::_createPkgElements() sets up {@link $elements} and
  1689.     *        {@link $pkg_elements} array, as well as {@link $links}
  1690.     */
  1691.     function walk(&$pages,&$package_pages)
  1692.     {
  1693.         if (empty($pages))
  1694.         {
  1695.             die("<b>ERROR</b>: nothing parsed");
  1696.         }
  1697.         $this->_createPkgElements($pages);
  1698.         if (count($this->ric))
  1699.         {
  1700.             phpDocumentor_out("Converting README/INSTALL/CHANGELOG contents...\n");
  1701.             flush();
  1702.             foreach($this->ric as $name => $contents)
  1703.             {
  1704.                 phpDocumentor_out("$name...");
  1705.                 flush();
  1706.                 $this->Convert_RIC($name,$contents);
  1707.             }
  1708.             phpDocumentor_out("\ndone\n");
  1709.             flush();
  1710.         }
  1711.         foreach($package_pages as $i => $perp)
  1712.         {
  1713.             if ($this->package_output)
  1714.             {
  1715.                 if (!in_array($package_pages[$i]->package,$this->package_output)) continue;
  1716.             }
  1717.             phpDocumentor_out('Converting package page for package '.$package_pages[$i]->package.'... ');
  1718.             flush();
  1719.             $this->package = $package_pages[$i]->package;
  1720.             $this->subpackage = '';
  1721.             $this->class = false;
  1722.             $this->Convert($package_pages[$i]);
  1723.             phpDocumentor_out("done\n");
  1724.             flush();
  1725.         }
  1726.         phpDocumentor_out("Converting tutorials/extended docs\n");
  1727.         flush();
  1728.         // get tutorials into the order they will display, and set next/prev links
  1729.         $new $this->_processTutorials();
  1730.         foreach($this->tutorials as $package => $els)
  1731.         {
  1732.             foreach($els as $subpackage => $els2)
  1733.             {
  1734.                 foreach($els2 as $type => $tutorials)
  1735.                 {
  1736.                     foreach($tutorials as $tutorial)
  1737.                     {
  1738.                         switch ($type)
  1739.                         {
  1740.                             case 'pkg' :
  1741.                                 $a '';
  1742.                                 if ($tutorial->ini)
  1743.                                 $a .= 'Top-level ';
  1744.                                 if (!empty($tutorial->subpackage))
  1745.                                 $a .= 'Sub-';
  1746.                                 $ptext "Converting ${a}Package-level tutorial ".$tutorial->name.'...';
  1747.                             break;
  1748.                             case 'cls' :
  1749.                                 $a '';
  1750.                                 if ($tutorial->ini)
  1751.                                 $a .= 'Top-level ';
  1752.                                 $ptext "Converting ${a}Class-level tutorial $tutorial->name ." and associating...";
  1753.                                 $link Converter::getClassLink(str_replace('.cls','',$tutorial->name)$tutorial->package);
  1754.                                 if (is_object($link))
  1755.                                 {
  1756.                                     if ($this->sort_absolutely_everything)
  1757.                                     {
  1758.                                         $addend 'unsuccessful ';
  1759.                                         if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name]))
  1760.                                         {
  1761.                                             $this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name][0]->addTutorial($tutorial,$this);
  1762.                                             $addend 'success ';
  1763.                                         }
  1764.                                     else
  1765.                                     {
  1766.                                         $addend 'unsuccessful ';
  1767.                                         if (!isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)]&& !isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)][$tutorial->path]))
  1768.                                         {
  1769.                                             foreach($pages as $j => $inf)
  1770.                                             {
  1771.                                                 foreach($inf->classelements as $i => $class)
  1772.                                                 {
  1773.                                                     if ($class->type == 'class' && $class->name == str_replace('.cls','',$tutorial->name&& $class->path == $link->path)
  1774.                                                     {
  1775.                                                         $pages[$j]->classelements[$i]->addTutorial($tutorial,$this);
  1776.                                                         $addend 'success ';
  1777.                                                     }
  1778.                                                 }
  1779.                                             }
  1780.                                         }
  1781.                                     }
  1782.                                     $ptext .= $addend;
  1783.                                 else $ptext .= "unsuccessful ";
  1784.                             break;
  1785.                             case 'proc' :
  1786.                                 $a '';
  1787.                                 if ($tutorial->ini)
  1788.                                 $a .= 'Top-level ';
  1789.                                 $ptext "Converting ${a}Procedural-level tutorial ".$tutorial->name." and associating...";
  1790.                                 $link Converter::getPageLink(str_replace('.proc','',$tutorial->name)$tutorial->package);
  1791.                                 if (is_object($link))
  1792.                                 {
  1793.                                     $addend 'unsuccessful ';
  1794.                                     if ($this->sort_absolutely_everything)
  1795.                                     {
  1796.                                         if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path]))
  1797.                                         {
  1798.                                             $this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path][0]->addTutorial($tutorial,$this);
  1799.                                             $addend "success ";
  1800.                                         }
  1801.                                     else
  1802.                                     {
  1803.                                         foreach($pages as $j => $info)
  1804.                                         {
  1805.                                             if ($j == $link->path)
  1806.                                             {
  1807.                                                 $pages[$j]->addTutorial($tutorial,$this);
  1808.                                                 $addend "success ";
  1809.                                             }
  1810.                                         }
  1811.                                     }
  1812.                                     $ptext .= $addend;
  1813.                                 else $ptext .= "unsuccessful ";
  1814.                             break;
  1815.                         }
  1816.                         phpDocumentor_out($ptext);
  1817.                         flush();
  1818.                         $this->package = $tutorial->package;
  1819.                         $this->subpackage = $tutorial->subpackage;
  1820.                         $this->Convert($tutorial);
  1821.                         phpDocumentor_out("done\n");
  1822.                         flush();
  1823.                     }
  1824.                 }
  1825.             }
  1826.         }
  1827.         phpDocumentor_out("Formatting Package Indexes...");
  1828.         flush();
  1829.         $this->formatPkgIndex();
  1830.         phpDocumentor_out("done\n");
  1831.         flush();
  1832.         phpDocumentor_out("Formatting Index...");
  1833.         flush();
  1834.         $this->formatIndex();
  1835.         phpDocumentor_out("done\n\n");
  1836.         flush();
  1837.         phpDocumentor_out("Formatting Left Quick Index...");
  1838.         flush();
  1839.         $this->formatLeftIndex();
  1840.         phpDocumentor_out("done\n\n");
  1841.         flush();
  1842.         if ($this->sort_absolutely_everythingreturn $this->walk_everything();
  1843.         foreach($pages as $j => $flub)
  1844.         {
  1845.             phpDocumentor_out('Converting '.$pages[$j]->parent->getPath());
  1846.             flush();
  1847.             $this->package = $pages[$j]->parent->package;
  1848.             $this->subpackage = $pages[$j]->parent->subpackage;
  1849.             $this->class = false;
  1850.             $this->curfile = $pages[$j]->parent->getFile();
  1851.             $this->curname $this->getPageName($pages[$j]->parent);
  1852.             $this->curpath $pages[$j]->parent->getPath();
  1853.             $use true;
  1854.             if ($this->package_output)
  1855.             {
  1856.                 if (in_array($this->package,$this->package_output))
  1857.                 {
  1858.                     $this->Convert($pages[$j]);
  1859.                 else
  1860.                 {
  1861.                     $use false;
  1862.                 }
  1863.             else
  1864.             {
  1865.                 $this->Convert($pages[$j]);
  1866.             }
  1867.             phpDocumentor_out(" Procedural Page Elements...");
  1868.             flush();
  1869.             if ($use)
  1870.             for($i=0$i<count($pages[$j]->elements)$i++)
  1871.             {
  1872.                 $a $pages[$j]->elements[$i]->docblock->getKeyword('access');
  1873.                 if (is_object($a)) $a $a->getString();
  1874.                 if (!$this->parseprivate && ($a == 'private'))
  1875.                     continue;
  1876. //                phpDocumentor_out("    ".$pages[$j]->elements[$i]->name."\n");
  1877.                 $pages[$j]->elements[$i]->docblock->package $this->package;
  1878.                 $pages[$j]->elements[$i]->docblock->subpackage $this->subpackage;
  1879.                 $this->Convert($pages[$j]->elements[$i]);
  1880.             }
  1881.             phpDocumentor_out(" Classes...");
  1882.             $this->class = false;
  1883.             flush();
  1884.             for($i=0$i<count($pages[$j]->classelements)$i++)
  1885.             {
  1886.                 if ($this->class)
  1887.                 {
  1888.                     if ($pages[$j]->classelements[$i]->type == 'class')
  1889.                     {
  1890.                         if (!$this->killclass$this->endClass();
  1891.                         $this->killclass false;
  1892.                         if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1893.                         $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1894.                         if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1895.                         $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1896.                         $this->class = $pages[$j]->classelements[$i]->name;
  1897.                     else
  1898.                     {
  1899.                         $a $pages[$j]->classelements[$i]->docblock->getKeyword('access');
  1900.                         if (is_object($a)) $a $a->getString();
  1901.                         if (!$this->parseprivate && ($a == 'private'))
  1902.                             continue;
  1903.                         if ($this->killclasscontinue;
  1904.                         // force all contained elements to have parent package/subpackage
  1905.                         $pages[$j]->classelements[$i]->docblock->package $this->package;
  1906.                         $pages[$j]->classelements[$i]->docblock->subpackage $this->subpackage;
  1907.                     }
  1908.                 }
  1909.                 if ($pages[$j]->classelements[$i]->type == 'class')
  1910.                 {
  1911.                     $this->killclass false;
  1912.                     if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1913.                     $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1914.                     if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1915.                     $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1916.                     $this->class = $pages[$j]->classelements[$i]->name;
  1917.                 }
  1918.                 if ($this->killclasscontinue;
  1919. //                phpDocumentor_out("    ".$pages[$j]->classelements[$i]->name."\n");
  1920.                 $this->Convert($pages[$j]->classelements[$i]);
  1921.             }
  1922.             if (count($pages[$j]->classelements&& !$this->killclass$this->endClass();
  1923.             phpDocumentor_out(" done\n");
  1924.             flush();
  1925.             $this->endPage();
  1926.         }
  1927.         phpDocumentor_out("\nConverting @todo List...");
  1928.         flush();
  1929.         if (count($this->todoList))
  1930.         {
  1931.             $this->ConvertTodoList();
  1932.         }
  1933.         phpDocumentor_out("done\n");
  1934.         flush();
  1935.         phpDocumentor_out("\nConverting Error Log...");
  1936.         flush();
  1937.         $this->ConvertErrorLog();
  1938.         phpDocumentor_out("done\n");
  1939.         flush();
  1940.     }
  1941.  
  1942.  
  1943.     /**
  1944.      * Get a tree structure representing the hierarchy of tutorials
  1945.      *
  1946.      * Returns an array in format:
  1947.      * <pre>
  1948.      * array('tutorial' => {@link parserTutorial},
  1949.      *       'kids' => array( // child tutorials
  1950.      *                   array('tutorial' => child {@link parserTutorial},
  1951.      *                         'kids' => array(...)
  1952.      *                        )
  1953.      *                      )
  1954.      *      )
  1955.      * </pre>
  1956.      * @param parserTutorial|array
  1957.      * @tutorial tutorials.pkg
  1958.      * @return array 
  1959.      */
  1960.     function getTutorialTree($tutorial)
  1961.     {
  1962.         if (is_object($tutorial))
  1963.         {
  1964.             $path $this->_tutorial_path($tutorial,$tutorial,$tutorial);
  1965.             if (isset($this->tutorial_tree[$path])) {
  1966.                 $tutorial $this->tutorial_tree[$path];
  1967.             else {
  1968.                 return false;
  1969.             }
  1970.         }
  1971.         $tree array();
  1972.         if (isset($tutorial['tutorial']))
  1973.         {
  1974.             $tree['tutorial'$tutorial['tutorial'];
  1975.             if (isset($tutorial['child']))
  1976.             {
  1977.                 foreach($tutorial['child'as $a => $b)
  1978.                 {
  1979.                     $btut $b['tutorial'];
  1980.                     $res['tutorial'$this->tutorials[$btut->package][$btut->subpackage][$btut->tutorial_type][$btut->name];
  1981.                     if (isset($b['child']))
  1982.                     {
  1983.                          $tempres Converter::getTutorialTree($b);
  1984.                          $res['kids'$tempres['kids'];
  1985.                     }
  1986.                     $tree['kids'][$res;
  1987.                 }
  1988.             }
  1989.         }
  1990.         return $tree;
  1991.     }
  1992.  
  1993.     /**
  1994.      * Remove tutorials one by one from $all, and transfer them into $new in the
  1995.      * order they should be parsed
  1996.      * @param parserTutorial 
  1997.      * @param array 
  1998.      * @param array 
  1999.      * @access private
  2000.      */
  2001.     function generateTutorialOrder($parent,&$all,&$new)
  2002.     {
  2003.         // remove from the list of tutorials to process
  2004.         foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_typeas $ind => $t)
  2005.         {
  2006.             if ($t->name == $parent->name{
  2007.                 unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
  2008.             }
  2009.         }
  2010.         // add to the new ordered list of tutorials
  2011.         $x &$new[$parent->package][$parent->subpackage][$parent->tutorial_type];
  2012.         if (!is_object($x[count($x1]|| $x[count($x1]->name != $parent->name)
  2013.         // only add if the parent isn't also a child
  2014.             $new[$parent->package][$parent->subpackage][$parent->tutorial_type][$parent;
  2015.             // add a new branch to the tree
  2016.         }
  2017.         // process all child tutorials, and insert them in order
  2018. //        debug("processing parent ".$parent->name);
  2019.         if ($parent->ini)
  2020.         {
  2021.             foreach($parent->ini['Linked Tutorials'as $child)
  2022.             {
  2023.                 $sub (empty($parent->subpackage'' $parent->subpackage '/');
  2024.                 $kid $parent->package '/' $sub $child '.' $parent->tutorial_type;
  2025.                 $_klink $this->getTutorialLink($kid,false,false,array($parent->package));
  2026.                 if (is_object($_klink)) {
  2027.                     $klink $this->returnSee($_klink);
  2028.                 else {
  2029.                     $klink false;
  2030.                 }
  2031.                 // remove the child from the list of remaining tutorials
  2032.                 foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_typeas $ind => $tute)
  2033.                 {
  2034.                     if ($klink && $tute->getLink($this== $klink)
  2035.                     {
  2036.                         // set up parent, next and prev links
  2037.                         $tute->setParent($parent$this);
  2038.                         // remove the child from the list of tutorials to process
  2039.                         foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_typeas $ind => $t)
  2040.                         {
  2041.                             if ($t->name == $tute->name)
  2042.                             unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
  2043.                         }
  2044.                         // add to the new ordered list of tutorials
  2045.                         $new[$parent->package][$parent->subpackage][$parent->tutorial_type][$tute;
  2046.                         if ($tute->ini)
  2047.                         {
  2048.                             // add all the child's child tutorials to the list
  2049.                             $this->generateTutorialOrder($tute,$all,$new);
  2050.                         }
  2051.                     }
  2052.                 }
  2053.             }
  2054.         }
  2055.         return;
  2056.     }
  2057.  
  2058.         /** Returns the path to this tutorial as a string
  2059.          * @param parserTutorial $pkg 
  2060.          * @param parserTutorial $subpkg 
  2061.          * @param parserTutorial $namepkg 
  2062.          * @return string */
  2063.         function _tutorial_path($pkg$subpkg 0$namepkg 0)
  2064.         {
  2065.             if (!$subpkg{
  2066.                 $subpkg $pkg;
  2067.             }
  2068.             if (!$namepkg{
  2069.                 $namepkg $pkg;
  2070.             }
  2071.             $subpackagename ($subpkg->subpackage '/' $subpkg->subpackage '');
  2072.             return $pkg->package $subpackagename '/' $namepkg->name;
  2073.         }
  2074.  
  2075.  
  2076.     /**
  2077.      * Creates a tree structure of tutorials
  2078.      *
  2079.      * Format:
  2080.      * <pre>
  2081.      * array('package/subpackage/tutorial1.ext' =>
  2082.      *          array('tutorial' => {@link parserTutorial},
  2083.      *                'child'    =>
  2084.      *                    array('package/subpackage/child1tutorial.ext' => ...,
  2085.      *                          'package/subpackage/child2tutorial.ext' => ...,
  2086.      *                          ...
  2087.      *                         )
  2088.      *       'package/subpackage/tutorial2.ext' => ...,
  2089.      *       ...
  2090.      *       )
  2091.      * </pre>
  2092.      * @return array the tutorial tree
  2093.      * @access private
  2094.      */
  2095.     function _setupTutorialTree($parent false)
  2096.     {
  2097.         if (isset($this->processed_tutorials)) {
  2098.             $this->processed_tutorials array();
  2099.         }
  2100.         $tree array();
  2101.         if (!$parent)
  2102.         {
  2103.             foreach($this->tutorials as $package => $s)
  2104.             {
  2105.                 foreach($s as $subpackage => $t)
  2106.                 {
  2107.                     foreach($t as $type => $n)
  2108.                     {
  2109.                         foreach($n as $name => $tutorial)
  2110.                         {
  2111.                             if ($tutorial->parent{
  2112.                                 continue;
  2113.                             }
  2114.                             
  2115.                             $child_path $this->_tutorial_path($tutorial,$tutorial,$tutorial);
  2116.                             if (isset($this->processed_tutorials[$child_path])) {
  2117.                                 continue;
  2118.                             }
  2119.                             $this->processed_tutorials[$child_path$tutorial;
  2120.                             //debug("parent ".$tutorial->name);
  2121.                             $ret $this->_setupTutorialTree($tutorial);
  2122.                             if (!count($tree)) {
  2123.                                 $tree $ret;
  2124.                             else {
  2125.                                 $tree array_merge($tree,$ret);
  2126.                             }
  2127.                         }
  2128.                     }
  2129.                 }
  2130.             }
  2131.             return $tree;
  2132.         }
  2133.         $parent_path $this->_tutorial_path($parent);
  2134.         $tree[$parent_path]['tutorial'$parent;
  2135.         // process all child tutorials, and insert them in order
  2136.         if ($parent->ini)
  2137.         {
  2138.             foreach($parent->ini['Linked Tutorials'as $child)
  2139.             {
  2140.                 if (isset($this->tutorials[$parent->package][$parent->subpackage]
  2141.                                           [$parent->tutorial_type][$child '.' .
  2142.                                            $parent->tutorial_type])) {
  2143.                     // remove the child from the list of remaining tutorials
  2144.                     $tute $this->tutorials[$parent->package][$parent->subpackage]
  2145.                                             [$parent->tutorial_type][$child '.' .
  2146.                                              $parent->tutorial_type];
  2147.                 else {
  2148.                     $tute false;
  2149.                 }
  2150.  
  2151.                 if (!$tute{
  2152.                     continue;
  2153.                 }
  2154.                 $child_path $this->_tutorial_path($parent,$parent,$tute);
  2155.                 if (isset($this->processed_tutorials[$child_path])) {
  2156.                     continue;
  2157.                 }
  2158.                 $this->processed_tutorials[$child_path$tute;
  2159.                 if ($tute->name != $child '.' $parent->tutorial_type{
  2160.                     continue;
  2161.                 }
  2162.                 //echo "Adding [$child_path] to [$parent_path]<br>";
  2163.                 $tree[$parent_path]['child'][$this->_tutorial_path($parent,$parent,$tute)]['tutorial']
  2164.                     = $tute;
  2165.                 if (!$tute->ini{
  2166.                     continue;
  2167.                 }
  2168.                 // add all the child's child tutorials to the list
  2169.                 if (!isset($tree[$parent_path]['child'])) {
  2170.                     $tree[$parent_path]['child'$this->_setupTutorialTree($tute);
  2171.                 else {
  2172.                     $tree[$parent_path]['child'array_merge($tree[$parent_path]['child'],
  2173.                         $this->_setupTutorialTree($tute));
  2174.                 }
  2175.             }
  2176.         }
  2177.         return $tree;
  2178.     }
  2179.  
  2180.     /**
  2181.      * Debugging function for dumping {@link $tutorial_tree}
  2182.      * @return string 
  2183.      */
  2184.     function vardump_tree($tree,$indent='')
  2185.     {
  2186.         if (phpDocumentor_get_class($tree== 'parsertutorial'return $tree->name.' extends '.($tree->parent$tree->parent->name 'nothing');
  2187.         $a '';
  2188.         foreach($tree as $ind => $stuff)
  2189.         {
  2190.             $x $this->vardump_tree($stuff,"$indent   ");
  2191.             $a .= $indent.'['.$ind." => \n   ".$indent.$x."]\n";
  2192.         }
  2193.         return substr($a,0,strlen($a1);
  2194.     }
  2195.  
  2196.     /**
  2197.      * @access private
  2198.      */
  2199.     function sort_package_elements($a,$b)
  2200.     {
  2201.         if (($a->type == $b->type&& (isset($a->isConstructor&& $a->isConstructor)) return -1;
  2202.         if (($a->type == $b->type&& (isset($b->isConstructor&& $b->isConstructor)) return 1;
  2203.         if ($a->type == $b->typereturn strnatcasecmp($a->name,$b->name);
  2204.         if ($a->type == 'class'return -1;
  2205.         if ($b->type == 'class'return 1;
  2206.         if ($a->type == 'const'return -1;
  2207.         if ($b->type == 'const'return 1;
  2208.         if ($a->type == 'var'return -1;
  2209.         if ($b->type == 'var'return 1;
  2210.         if ($a->type == 'page'return -1;
  2211.         if ($b->type == 'page'return 1;
  2212.         if ($a->type == 'include'return -1;
  2213.         if ($b->type == 'include'return 1;
  2214.         if ($a->type == 'define'return -1;
  2215.         if ($b->type == 'define'return 1;
  2216.         if ($a->type == 'global'return -1;
  2217.         if ($b->type == 'global'return 1;
  2218.         if ($a->type == 'function'return -1;
  2219.         if ($b->type == 'function'return 1;
  2220.     }
  2221.  
  2222.     /**
  2223.      * @access private
  2224.      */
  2225.     function defpackagesort($a,$b)
  2226.     {
  2227.         if ($a == $GLOBALS['phpDocumentor_DefaultPackageName']return -1;
  2228.         if ($b == $GLOBALS['phpDocumentor_DefaultPackageName']return 0;
  2229.         return strnatcasecmp($a,$b);
  2230.     }
  2231.  
  2232.     /**
  2233.      * @access private
  2234.      */
  2235.     function Pc_sort($a,$b)
  2236.     {
  2237.         return strnatcasecmp(key($a),key($b));
  2238.     }
  2239.  
  2240.     /**
  2241.      * walk over elements by package rather than page
  2242.      *
  2243.      * This method is designed for converters like the PDF converter that need
  2244.      * everything passed in alphabetical order by package/subpackage and by
  2245.      * procedural and then class information
  2246.      * @see PDFdefaultConverter
  2247.      * @see walk()
  2248.      */
  2249.     function walk_everything()
  2250.     {
  2251.         global $hooser;
  2252.         $hooser false;
  2253.         uksort($this->package_elements,array($this,'defpackagesort'));
  2254.         foreach($this->package_elements as $package => $r)
  2255.         {
  2256.             if ($this->package_output)
  2257.             {
  2258.                 if (!in_array($this->package,$this->package_output))
  2259.                 {
  2260.                     unset($this->package_elements[$package]);
  2261.                     continue;
  2262.                 }
  2263.             }
  2264.             uksort($this->package_elements[$package],'strnatcasecmp');
  2265.         }
  2266.         foreach($this->package_elements as $package => $r)
  2267.         {
  2268.             foreach($this->package_elements[$packageas $subpackage => $r)
  2269.             {
  2270.                 if (isset($r['page']))
  2271.                 {
  2272.                     uksort($r['page'],'strnatcasecmp');
  2273.                     foreach($r['page'as $page => $oo)
  2274.                     {
  2275.                         usort($this->package_elements[$package][$subpackage]['page'][$page],array($this,'sort_package_elements'));
  2276.                     }
  2277.                 }
  2278.                 if (isset($r['class']))
  2279.                 {
  2280.                     uksort($r['class'],'strnatcasecmp');
  2281.                     foreach($r['class'as $page => $oo)
  2282.                     {
  2283.                         usort($r['class'][$page],array($this,'sort_package_elements'));
  2284.                     }
  2285.                 }
  2286.                 $this->package_elements[$package][$subpackage$r;
  2287.             }
  2288.         }
  2289.         foreach($this->package_elements as $package => $s)
  2290.         {
  2291.             $notyet false;
  2292.             foreach($s as $subpackage => $r)
  2293.             {
  2294.                 $this->package = $package;
  2295.                 $this->subpackage = $subpackage;
  2296.                 if (isset($r['page']))
  2297.                 {
  2298.                     $this->class = false;
  2299.                     foreach($r['page'as $page => $elements)
  2300.                     {
  2301.                         if (is_array($elements))
  2302.                         {
  2303.                             foreach($elements as $element)
  2304.                             {
  2305.                                 if ($element->type == 'page')
  2306.                                 {
  2307.                                     phpDocumentor_out('Converting '.$element->parent->getPath());
  2308.                                     flush();
  2309.                                     $this->curfile = $element->parent->getFile();
  2310.                                     $this->curname $this->getPageName($element->parent);
  2311.                                     $this->curpath $element->parent->getPath();
  2312.                                     $notyet true;
  2313.                                 else
  2314.                                 {
  2315.                                     // force all contained elements to have parent package/subpackage
  2316.                                     $element->docblock->package $this->package;
  2317.                                     $element->docblock->subpackage $this->subpackage;
  2318.                                     $a $element->docblock->getKeyword('access');
  2319.                                     if (is_object($a)) $a $a->getString();
  2320.                                     if (!$this->parseprivate && ($a == 'private'))
  2321.                                         continue;
  2322.                                 }
  2323.                                 if ($notyet)
  2324.                                 {
  2325.                                     phpDocumentor_out(" Procedural Page Elements...");
  2326.                                     flush();
  2327.                                     $notyet false;
  2328.                                 }
  2329.                                 $this->Convert($element);
  2330.                             }
  2331.                         }
  2332.                         $this->endPage();
  2333.                         phpDocumentor_out("done\n");
  2334.                         flush();
  2335.                     }
  2336.                 }
  2337.                 $start_classes true;
  2338.                 if (isset($r['class']))
  2339.                 {
  2340.                     foreach($r['class'as $class => $elements)
  2341.                     {
  2342.                         foreach($elements as $element)
  2343.                         {
  2344.                             if ($element->type == 'class')
  2345.                             {
  2346.                                 if (!$start_classes)
  2347.                                 {
  2348.                                     if (count($elements&& !$this->killclass$this->endClass();
  2349.                                     phpDocumentor_out("done\n");
  2350.                                     flush();
  2351.                                 }
  2352.                                 $start_classes false;
  2353.                                 $this->class = $element->getName();
  2354.                                 $this->killclass false;
  2355.                                 if ($this->checkKillClass($element->getName(),$element->getPath())) continue;
  2356.                                 if (!$this->killclass)
  2357.                                 {
  2358.                                     phpDocumentor_out('Converting '.$this->class."...");
  2359.                                     flush();
  2360.                                     $notyet true;
  2361.                                 }
  2362.                             else
  2363.                             {
  2364.                                 if ($notyet)
  2365.                                 {
  2366.                                     phpDocumentor_out("Variables/methods/Class constants...\n");
  2367.                                     flush();
  2368.                                     $notyet false;
  2369.                                 }
  2370.                                 $a $element->docblock->getKeyword('access');
  2371.                                 if (is_object($a)) $a $a->getString();
  2372.                                 if (!$this->parseprivate && ($a == 'private'))
  2373.                                     continue;
  2374.                                 if ($this->killclasscontinue;
  2375.                                 // force all contained elements to have parent package/subpackage
  2376.                                 $element->docblock->package $this->package;
  2377.                                 $element->docblock->subpackage $this->subpackage;
  2378.                             }
  2379.                             if ($this->killclasscontinue;
  2380.                             $this->Convert($element);
  2381.                         }
  2382.                     }
  2383.                     if (count($elements&& !$this->killclass$this->endClass();
  2384.                     phpDocumentor_out("done\n");
  2385.                     flush();
  2386.                 // if isset($r['class'])
  2387.             // foreach($s
  2388.         // foreach($this->package_elements)
  2389.         phpDocumentor_out("\nConverting @todo List...");
  2390.         flush();
  2391.         if (count($this->todoList))
  2392.         {
  2393.             $this->ConvertTodoList();
  2394.         }
  2395.         phpDocumentor_out("done\n");
  2396.         flush();
  2397.         phpDocumentor_out("\nConverting Error Log...");
  2398.         flush();
  2399.         $this->ConvertErrorLog();
  2400.         phpDocumentor_out("done\n");
  2401.         flush();
  2402.     }
  2403.  
  2404.     /**
  2405.      * Convert the phpDocumentor parsing/conversion error log
  2406.      * @abstract
  2407.      */
  2408.     function ConvertErrorLog()
  2409.     {
  2410.     }
  2411.  
  2412.     /**
  2413.      * Convert the list of all @todo tags
  2414.      * @abstract
  2415.      */
  2416.     function ConvertTodoList()
  2417.     {
  2418.     }
  2419.  
  2420.     /**
  2421.      * Sorts the @todo list - do not override or modify this function
  2422.      * @access private
  2423.      * @uses _sortTodos passed to {@link usort()} to sort the todo list
  2424.      */
  2425.     function sortTodos()
  2426.     {
  2427.         phpDocumentor_out("\nSorting @todo list...");
  2428.         flush();
  2429.         foreach($this->todoList as $package => $r{
  2430.             usort($this->todoList[$package]array('Converter''_sortTodoPackage'));
  2431.             foreach ($r as $a => $sub{
  2432.                 if (is_array($this->todoList[$package][$a][1])) {
  2433.                     usort($this->todoList[$package][$a][1],array('Converter''_sortTodos'));
  2434.                 }
  2435.             }
  2436.         }
  2437.         phpDocumentor_out("done\n");
  2438.     }
  2439.  
  2440.     /** @access private */
  2441.     function _sortTodoPackage($a$b)
  2442.     {
  2443.         return strnatcasecmp($a[0]->name$b[0]->name);
  2444.     }
  2445.  
  2446.     /** @access private */
  2447.     function _sortTodos($a$b)
  2448.     {
  2449.         if (!is_object($a)) {
  2450.             var_dump($a);
  2451.         }
  2452.         return strnatcasecmp($a->getString()$b->getString());
  2453.     }
  2454.  
  2455.     /**
  2456.      * Sorts all indexes - do not override or modify this function
  2457.      * @uses $leftindex based on the value of leftindex, sorts link arrays
  2458.      * @uses $class_elements sorts with {@link compareLink}
  2459.      * @uses $page_elements sorts with {@link compareLink}
  2460.      * @uses $define_elements sorts with {@link compareLink}
  2461.      * @uses $global_elements sorts with {@link compareLink}
  2462.      * @uses $function_elements sorts with {@link compareLink}
  2463.      * @uses $elements sorts with {@link elementCmp}
  2464.      * @uses $pkg_elements sorts with {@link elementCmp} after sorting by
  2465.      *                      package/subpackage alphabetically
  2466.      * @access private
  2467.      */
  2468.     function sortIndexes()
  2469.     {
  2470.         phpDocumentor_out("\nSorting Indexes...");
  2471.         flush();
  2472.         uksort($this->elements,'strnatcasecmp');
  2473.         if ($this->leftindex['classes'])
  2474.         {
  2475.             foreach($this->class_elements as $package => $o1)
  2476.             {
  2477.                 foreach($o1 as $subpackage => $links)
  2478.                 {
  2479.                     usort($this->class_elements[$package][$subpackage],array($this,'compareLink'));
  2480.                 }
  2481.             }
  2482.         }
  2483.         if ($this->leftindex['pages'])
  2484.         {
  2485.             foreach($this->page_elements as $package => $o1)
  2486.             {
  2487.                 uksort($this->page_elements[$package],'strnatcasecmp');
  2488.                 foreach($o1 as $subpackage => $links)
  2489.                 {
  2490.                     usort($this->page_elements[$package][$subpackage],array($this,'compareLink'));
  2491.                 }
  2492.             }
  2493.         }
  2494.         if ($this->leftindex['defines'])
  2495.         {
  2496.             foreach($this->define_elements as $package => $o1)
  2497.             {
  2498.                 uksort($this->define_elements[$package],'strnatcasecmp');
  2499.                 foreach($o1 as $subpackage => $links)
  2500.                 {
  2501.                     usort($this->define_elements[$package][$subpackage],array($this,'compareLink'));
  2502.                 }
  2503.             }
  2504.         }
  2505.         if ($this->leftindex['globals'])
  2506.         {
  2507.             foreach($this->global_elements as $package => $o1)
  2508.             {
  2509.                 uksort($this->global_elements[$package],'strnatcasecmp');
  2510.                 foreach($o1 as $subpackage => $links)
  2511.                 {
  2512.                     usort($this->global_elements[$package][$subpackage],array($this,'compareLink'));
  2513.                 }
  2514.             }
  2515.         }
  2516.         if ($this->leftindex['functions'])
  2517.         {
  2518.             foreach($this->function_elements as $package => $o1)
  2519.             {
  2520.                 uksort($this->function_elements[$package],'strnatcasecmp');
  2521.                 foreach($o1 as $subpackage => $links)
  2522.                 {
  2523.                     usort($this->function_elements[$package][$subpackage],array($this,'compareLink'));
  2524.                 }
  2525.             }
  2526.         }
  2527.         foreach($this->elements as $letter => $nothuing)
  2528.         {
  2529.             uasort($this->elements[$letter],array($this,"elementCmp"));
  2530.         }
  2531.         foreach($this->pkg_elements as $package => $els)
  2532.         {
  2533.             uksort($this->pkg_elements[$package],'strnatcasecmp');
  2534.             foreach($this->pkg_elements[$packageas $subpackage => $els)
  2535.             {
  2536.                 if (empty($els)) continue;
  2537.                 uksort($this->pkg_elements[$package][$subpackage],'strnatcasecmp');
  2538.                 foreach($els as $letter => $yuh)
  2539.                 {
  2540.                     usort($this->pkg_elements[$package][$subpackage][$letter],array($this,"elementCmp"));
  2541.                 }
  2542.             }
  2543.         }
  2544.         phpDocumentor_out("done\n");
  2545.         flush();
  2546.     }
  2547.  
  2548.     /**
  2549.      * sorts {@link $page_contents} by element type as well as alphabetically
  2550.      * @see $sort_page_contents_by_element_type
  2551.      */
  2552.     function sortPageContentsByElementType(&$pages)
  2553.     {
  2554.         foreach($this->page_contents as $package => $els)
  2555.         {
  2556.             foreach($this->page_contents[$packageas $subpackage => $els)
  2557.             {
  2558.                 if (empty($els)) continue;
  2559.                 foreach($this->page_contents[$package][$subpackageas $path => $stuff)
  2560.                 {
  2561.                     if (!count($pages[$path]->elements)) continue;
  2562.                     usort($pages[$path]->elements,array($this,'eltypecmp'));
  2563.                     usort($this->page_contents[$package][$subpackage][$path],array($this,'eltypecmp'));
  2564.                     if (isset($this->page_contents[$package][$subpackage][$path][0]))
  2565.                     $this->page_contents[$package][$subpackage][$path]['###main'$this->page_contents[$package][$subpackage][$path][0];
  2566.                     unset($this->page_contents[$package][$subpackage][$path][0]);
  2567.                 }
  2568.             }
  2569.         }
  2570.     }
  2571.  
  2572.     /**
  2573.      * @access private
  2574.      * @see Converter::sortIndexes()
  2575.      */
  2576.     function compareLink($a$b)
  2577.     {
  2578.          return strnatcasecmp($a->name,$b->name);
  2579.     }
  2580.  
  2581.     /**
  2582.      * @access private
  2583.      * @see Converter::sortPageContentsByElementType()
  2584.      */
  2585.     function eltypecmp($a$b)
  2586.     {
  2587.         if ($a->type == 'page'return -1;
  2588.         if ($b->type == 'page'return 1;
  2589.          return strnatcasecmp($a->type.$a->name,$b->type.$b->name);
  2590.     }
  2591.  
  2592.     /**
  2593.      * does a nat case sort on the specified second level value of the array
  2594.      *
  2595.      * @param    mixed    $a 
  2596.      * @param    mixed    $b 
  2597.      * @return    int 
  2598.      * @access private
  2599.      */
  2600.     function elementCmp ($a$b)
  2601.     {
  2602.         return strnatcasecmp($a->getName()$b->getName());
  2603.     }
  2604.  
  2605.     /**
  2606.      * Used to stop conversion of @ignored or private @access classes
  2607.      * @uses $killclass sets killclass based on the value of {@link Classes::$killclass}
  2608.      *        and {@link $package_output}
  2609.      * @access private
  2610.      */
  2611.     function checkKillClass($class$path)
  2612.     {
  2613.         $this->killclass false;
  2614.         if (isset($this->classes->killclass[$class]&& isset($this->classes->killclass[$class][$path])) $this->killclass true;
  2615.         if ($this->package_output)
  2616.         {
  2617.             $a $this->classes->getClass($class$path);
  2618.             if (!in_array($a->docblock->package,$this->package_output)) $this->killclass true;
  2619.         }
  2620.         if (PHPDOCUMENTOR_DEBUG && $this->killclassdebug("$class $path killed");
  2621.         return $this->killclass;
  2622.     }
  2623.  
  2624.     /**
  2625.      * @param abstractLink descendant of abstractLink
  2626.      * @param array|parserTaglist of @todos|@todo tag
  2627.      * @access private
  2628.      */
  2629.     function addTodoLink($link$todos)
  2630.     {
  2631.         $this->todoList[$link->package][array($link$todos);
  2632.     }
  2633.  
  2634.     /**
  2635.      * Adds all elements to the {@link $elements, $pkg_elements, $links},
  2636.      * {@link $linkswithfile} and left indexes - Do not modify or override
  2637.      * @access private
  2638.      * @param parserBase any documentable element descendant of parserBase
  2639.      *                    except parserTutorial
  2640.      * @param false|parserPageonly used to add a {@link parserPage} if the
  2641.      *                          $element passed is a parserPage
  2642.      * @staticvar string path of current page, used for {@link $page_contents} setup
  2643.      */
  2644.     function addElement(&$element,$pageel=false)
  2645.     {
  2646.         static $curpath '';
  2647.         if ($this->package_output)
  2648.         {
  2649.             if (!in_array($this->package$this->package_output)) return;
  2650.         }
  2651.         if ($pageel && phpDocumentor_get_class($pageel== 'parserdata')
  2652.         {
  2653.             if (isset($pageel->docblock&& phpDocumentor_get_class($pageel->docblock== 'parserdocblock')
  2654.             {
  2655.                 $a $pageel->docblock->getKeyword('todo');
  2656.                 if ($a)
  2657.                 {
  2658.                     $this->addTodoLink($this->addLink($element),$a);
  2659.                 }
  2660.             }
  2661.         }
  2662.         if (isset($element->docblock))
  2663.         {
  2664.             $a $element->docblock->getKeyword('access');
  2665.             if (is_object($a)) $a $a->getString();
  2666.             if (!$this->parseprivate && ($a == 'private'))
  2667.                 return;
  2668.             $a $element->docblock->getKeyword('todo');
  2669.             if ($a)
  2670.             {
  2671.                 if ($element->type != 'include'{
  2672.                     $this->addTodoLink($this->addLink($element),$a);
  2673.                 else {
  2674.                     addWarning(PDERROR_NOTODO_INCLUDE$element->getLineNumber(),
  2675.                         $element->getPath());
  2676.                 }
  2677.             }
  2678.         }
  2679.         $i 0;
  2680.         switch($element->type)
  2681.         {
  2682.             case 'page' :
  2683.                 if ($this->sort_absolutely_everything)
  2684.                 {
  2685.                     $this->package_elements[$element->package][$element->subpackage]['page'][$element->getPath()][$pageel;
  2686.                 }
  2687.                 $link $this->addLink($element);
  2688.                 $curpath $element->getPath();
  2689.                 if ($this->leftindex['pages'])
  2690.                 $this->page_elements[$element->package][$element->subpackage][$link;
  2691.                 $this->page_contents[$element->package][$element->subpackage][$curpath]['###main'$link;
  2692.             break;
  2693.             case 'class' :
  2694.                 if ($this->sort_absolutely_everything)
  2695.                 {
  2696.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2697.                 }
  2698.                 $link $this->addLink($element);
  2699.                 if ($this->leftindex['classes'])
  2700.                 $this->class_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2701.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class]['###main'$link;
  2702.             break;
  2703.             case 'include' :
  2704.                 if ($this->sort_absolutely_everything)
  2705.                 {
  2706.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2707.                 }
  2708.                 $link $this->addLink($element);
  2709.             break;
  2710.             case 'define' :
  2711.                 if ($this->sort_absolutely_everything)
  2712.                 {
  2713.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2714.                 }
  2715.                 $link $this->addLink($element);
  2716.                 if ($this->leftindex['defines'])
  2717.                 $this->define_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2718.                 $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][$link;
  2719.             break;
  2720.             case 'global' :
  2721.                 if ($this->sort_absolutely_everything)
  2722.                 {
  2723.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2724.                 }
  2725.                 $link $this->addLink($element);
  2726.                 $i++;
  2727.                 if ($this->leftindex['globals'])
  2728.                 $this->global_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2729.                 $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][$link;
  2730.             break;
  2731.             case 'var' :
  2732.                 if ($this->sort_absolutely_everything)
  2733.                 {
  2734.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2735.                 }
  2736.                 $link $this->addLink($element);
  2737.                 $i++;
  2738.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][$link;
  2739.             break;
  2740.             case 'const' :
  2741.                 if ($this->sort_absolutely_everything)
  2742.                 {
  2743.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2744.                 }
  2745.                 $link $this->addLink($element);
  2746.                 $i++;
  2747.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][$link;
  2748.             break;
  2749.             case 'method' :
  2750.                 if ($this->sort_absolutely_everything)
  2751.                 {
  2752.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2753.                 }
  2754.                 $link $this->addLink($element);
  2755.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][$link;
  2756.             break;
  2757.             case 'function' :
  2758.                 if ($this->sort_absolutely_everything)
  2759.                 {
  2760.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2761.                 }
  2762.                 $link $this->addLink($element);
  2763.                 if ($this->leftindex['functions'])
  2764.                 $this->function_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2765.                 $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][$link;
  2766.             break;
  2767.             default :
  2768.             break;
  2769.         }
  2770.         if ($element->getType(!= 'include')
  2771.         {
  2772.             if ($element->getType(== 'var' || $element->getType(== 'method'|| $element->getType(== 'const')
  2773.             {
  2774.                 $this->links[$this->package][$this->subpackage][$element->getType()][$element->class][$element->getName()$link;
  2775.                 $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->class][$element->getName()$link;
  2776.             else
  2777.             {
  2778.                 if ($element->type == 'page')
  2779.                 {
  2780.                     $this->links[$this->package][$this->subpackage][$element->getType()][$element->getFile()$link;
  2781.                     $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getFile()$link;
  2782.                 else
  2783.                 {
  2784.                     $this->links[$this->package][$this->subpackage][$element->getType()][$element->getName()$link;
  2785.                     $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getName()$link;
  2786.                 }
  2787.             }
  2788.         }
  2789.         if ($element->type == 'page')
  2790.         {
  2791.             $this->elements[substr(strtolower($element->getFile()),$i,1)][$element;
  2792.             $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getFile()),$i,1)][$element;
  2793.         else
  2794.         {
  2795.             $this->elements[substr(strtolower($element->getName()),$i,1)][$element;
  2796.             $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getName()),$i,1)][$element;
  2797.         }
  2798.     }
  2799.  
  2800.     /**
  2801.      * returns an abstract link to element.  Do not modify or override
  2802.      *
  2803.      * This method should only be called in process of Conversion, unless
  2804.      * $element is a parserPage, or $page is set to true, and $element is
  2805.      * not a parserPage
  2806.      * @return abstractLink abstractLink descendant
  2807.      * @access private
  2808.      * @param parserElement element to add a new link (descended from
  2809.      *                       {@link abstractLink})to the {@link $links} array
  2810.      * @param string classname for elements that are class-based (this may be
  2811.      *                deprecated in the future, as the classname
  2812.      *                should be contained within the element.  if $element is a
  2813.      *                page, this parameter is a package name
  2814.      * @param string subpackage name for page elements
  2815.      */
  2816.     function addLink(&$element,$page false)
  2817.     {
  2818.         if ($page)
  2819.         {
  2820.             // create a fake parserPage to extract the fileAlias for this link
  2821.             $fakepage new parserPage;
  2822.             $fakepage->setPath($element->getPath());
  2823.             $fakepage->setFile(basename($element->getPath()));
  2824.             $this->curname $this->getPageName($fakepage);
  2825.         }
  2826.         switch($element->type)
  2827.         {
  2828.             case 'function':
  2829.                 $x new functionLink;
  2830.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2831.                 return $x;
  2832.             break;
  2833.             case 'define':
  2834.                 $x new defineLink;
  2835.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2836.                 return $x;
  2837.             break;
  2838.             case 'global':
  2839.                 $x new globalLink;
  2840.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2841.                 return $x;
  2842.             break;
  2843.             case 'class':
  2844.                 $x new classLink;
  2845.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2846.                 return $x;
  2847.             break;
  2848.             case 'method':
  2849.                 $x new methodLink;
  2850.                 $x->addLink($this->class$element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2851.                 return $x;
  2852.             break;
  2853.             case 'var':
  2854.                 $x new varLink;
  2855.                 $x->addLink($this->class$element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2856.                 return $x;
  2857.             break;
  2858.             case 'const':
  2859.                 $x new constLink;
  2860.                 $x->addLink($this->class$element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2861.                 return $x;
  2862.             break;
  2863.             case 'page':
  2864.                 $x new pageLink;
  2865.                 $x->addLink($element->getPath(),$this->getPageName($element),$element->file,$element->package$element->subpackage$element->category);
  2866.                 return $x;
  2867.             break;
  2868.         }
  2869.     }
  2870.  
  2871.     /**
  2872.      * Return a tree of all classes that extend this class
  2873.      *
  2874.      * The data structure returned is designed for a non-recursive algorithm,
  2875.      * and is somewhat complex.
  2876.      * In most cases, the array returned is:
  2877.      *
  2878.      * <pre>
  2879.      * array('#root' =>
  2880.      *         array('link' => {@link classLink} to $class,
  2881.      *               'parent' => false,
  2882.      *               'children' => array(array('class' => 'childclass1',
  2883.      *                                         'package' => 'child1package'),
  2884.      *                                    array('class' => 'childclass2',
  2885.      *                                         'package' => 'child2package'),...
  2886.      *                                  )
  2887.      *               ),
  2888.      *       'child1package#childclass1' =>
  2889.      *         array('link' => {@link classLink} to childclass1,
  2890.      *               'parent' => '#root',
  2891.      *               'children' => array(array('class' => 'kidclass',
  2892.      *                                         'package' => 'kidpackage'),...
  2893.      *                                  )
  2894.      *              ),
  2895.      *       'kidpackage#kidclass' =>
  2896.      *         array('link' => {@link classLink} to kidclass,
  2897.      *               'parent' => 'child1package#childclass1',
  2898.      *               'children' => array() // no children
  2899.      *              ),
  2900.      *      ....
  2901.      *      )
  2902.      *</pre>
  2903.      *
  2904.      * To describe this format using language, every class in the tree has an
  2905.      * entry in the first level of the array.  The index for all child
  2906.      * classes that extend the root class is childpackage#childclassname.
  2907.      * Each entry in the array has 3 elements: link, parent, and children.
  2908.      * <ul>
  2909.      *  <li>link - a {@link classLink} to the current class</li>
  2910.      *  <li>parent - a {@link classLink} to the class's parent, or false (except for one special case described below)</li>
  2911.      *  <li>children - an array of arrays, each entry has a 'class' and 'package' index to the child class,
  2912.      * used to find the entry in the big array</li>
  2913.      * </ul>
  2914.      *
  2915.      * special cases are when the #root class has a parent in another package,
  2916.      * or when the #root class extends a class not found
  2917.      * by phpDocumentor.  In the first case, parent will be a
  2918.      * classLink to the parent class.  In the second, parent will be the
  2919.      * extends clause, as in:
  2920.      * <code>
  2921.      * class X extends Y
  2922.      * {
  2923.      * ...
  2924.      * }
  2925.      * </code>
  2926.      * in this case, the #root entry will be array('link' => classLink to X, 'parent' => 'Y', children => array(...))
  2927.      *
  2928.      * The fastest way to design a method to process the array returned
  2929.      * is to copy HTMLframesConverter::getRootTree() into
  2930.      * your converter and to modify the html to whatever output format you are going to use
  2931.      * @see HTMLframesConverter::getRootTree()
  2932.      * @param string class name
  2933.      * @param string 
  2934.      * @param string 
  2935.      * @return array Format: see docs
  2936.      */
  2937.     function getSortedClassTreeFromClass($class,$package,$subpackage)
  2938.     {
  2939.         $my_tree array();
  2940.         $root $this->classes->getClassByPackage($class,$package);
  2941.         if (!$rootreturn false;
  2942.         $class_children $this->classes->getDefiniteChildren($class,$root->curfile);
  2943.         if (!$class_children)
  2944.         {
  2945.             // special case: parent class is found, but is not part of this package, class has no children
  2946.             if (is_array($root->parent))
  2947.             {
  2948.                 $x $root->getParent($this);
  2949.                 if ($x->docblock->package != $package)
  2950.                 {
  2951.                     $v Converter::getClassLink($root->getName(),$package,$root->getPath());
  2952.                     return array('#root' => array('link' => $v,'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath())'children' => array()));
  2953.                 }
  2954.             else
  2955.             // class has normal situation, no children
  2956.                 if (is_string($root->getParent($this)))
  2957.                 return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath())'parent' => $root->getExtends(),'children' => array()));
  2958.                 else
  2959.                 return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath())'parent' => false'children' => array()));
  2960.             }
  2961.         }
  2962.         // special case: parent class is found, but is not part of this package, class has children
  2963.         if (is_array($root->parent))
  2964.         {
  2965.             $x $root->getParent($this);
  2966.             if ($x->docblock->package != $package)
  2967.             {
  2968.                 $v Converter::getClassLink($root->getName(),$package,$root->getPath());
  2969.                 $my_tree array('#root' => array('link' => $v'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath())'children' => array()));
  2970.             else
  2971.             {
  2972.             }
  2973.         else
  2974.         $my_tree array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath())'parent' => false'children' => array()));
  2975.         // location of tree walker
  2976.         $cur '#root';
  2977.         $lastcur array(array(false,0));
  2978.         $childpos 0;
  2979.         if (isset($class_children))
  2980.         {
  2981.             do
  2982.             {
  2983.                 if (!$class_children)
  2984.                 {
  2985.                     list($cur$childposarray_pop($lastcur);
  2986.                     if (isset($my_tree[$cur]['children'][$childpos 1]))
  2987.                     {
  2988.                         array_push($lastcurarray($cur$childpos 1));
  2989.                         $par $cur;
  2990.                         $cur $my_tree[$cur]['children'][$childpos 1];
  2991.                         $x $this->classes->getClassByPackage($cur['class'],$cur['package']);
  2992.                         $childpos 0;
  2993.                         $cur $cur['package''#' $cur['class'];
  2994.                         $my_tree[$cur]['link'Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
  2995.                         $my_tree[$cur]['parent'$par;
  2996.                         $my_tree[$cur]['children'array();
  2997.                         $class_children $this->classes->getDefiniteChildren($x->getName()$x->curfile);
  2998.                         continue;
  2999.                     else
  3000.                     {
  3001.                         $class_children false;
  3002.                         continue;
  3003.                     }
  3004.                 }
  3005.                 foreach($class_children as $chileclass => $chilefile)
  3006.                 {
  3007.                     $ch $this->classes->getClass($chileclass,$chilefile);
  3008.                     $my_tree[$cur]['children'][array('class' => $ch->getName()'package' => $ch->docblock->package);
  3009.                 }
  3010.                 usort($my_tree[$cur]['children'],'rootcmp');
  3011.                 if (isset($my_tree[$cur]['children'][$childpos]))
  3012.                 {
  3013.                     array_push($lastcurarray($cur$childpos));
  3014.                     $par $cur;
  3015.                     $cur $my_tree[$cur]['children'][$childpos];
  3016.                     $x $this->classes->getClassByPackage($cur['class'],$cur['package']);
  3017.                     $cur $cur['package''#' $cur['class'];
  3018.                     $my_tree[$cur]['link'Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
  3019.                     $my_tree[$cur]['parent'$par;
  3020.                     $my_tree[$cur]['children'array();
  3021.                     $childpos 0;
  3022.                     $class_children $this->classes->getDefiniteChildren($x->getName()$x->curfile);
  3023.                 else
  3024.                 {
  3025.                     list($cur$childposarray_pop($lastcur);
  3026.                 }
  3027.             while ($cur);
  3028.         }
  3029.         return $my_tree;
  3030.     }
  3031.  
  3032.     /**
  3033.      * do not override
  3034.      * @return bool true if a link to this class exists in package $package and subpackage $subpackage
  3035.      * @param string $expr class name
  3036.      * @param string $package package to search in
  3037.      * @param string $subpackage subpackage to search in
  3038.      * @access private
  3039.      */
  3040.     function isLinkedClass($expr,$package,$subpackage,$file=false)
  3041.     {
  3042.         if ($file)
  3043.         return isset($this->linkswithfile[$package][$subpackage]['class'][$file][$expr]);
  3044.         return isset($this->links[$package][$subpackage]['class'][$expr]);
  3045.     }
  3046.  
  3047.     /**
  3048.      * do not override
  3049.      * @return bool true if a link to this function exists in package $package and subpackage $subpackage
  3050.      * @param string $expr function name
  3051.      * @param string $package package to search in
  3052.      * @param string $subpackage subpackage to search in
  3053.      * @access private
  3054.      */
  3055.     function isLinkedFunction($expr,$package,$subpackage,$file=false)
  3056.     {
  3057.         if ($file)
  3058.         return isset($this->linkswithfile[$package][$subpackage]['function'][$file][$expr]);
  3059.         return isset($this->links[$package][$subpackage]['function'][$expr]);
  3060.     }
  3061.  
  3062.     /**
  3063.      * do not override
  3064.      * @return bool true if a link to this define exists in package $package and subpackage $subpackage
  3065.      * @param string $expr define name
  3066.      * @param string $package package to search in
  3067.      * @param string $subpackage subpackage to search in
  3068.      * @access private
  3069.      */
  3070.     function isLinkedDefine($expr,$package,$subpackage,$file=false)
  3071.     {
  3072.         if ($file)
  3073.         return isset($this->linkswithfile[$package][$subpackage]['define'][$file][$expr]);
  3074.         return isset($this->links[$package][$subpackage]['define'][$expr]);
  3075.     }
  3076.  
  3077.     /**
  3078.      * do not override
  3079.      * @return bool true if a link to this define exists in package $package and subpackage $subpackage
  3080.      * @param string $expr define name
  3081.      * @param string $package package to search in
  3082.      * @param string $subpackage subpackage to search in
  3083.      * @access private
  3084.      */
  3085.     function isLinkedGlobal($expr,$package,$subpackage,$file=false)
  3086.     {
  3087.         if ($file)
  3088.         return isset($this->linkswithfile[$package][$subpackage]['global'][$file][$expr]);
  3089.         return isset($this->links[$package][$subpackage]['global'][$expr]);
  3090.     }
  3091.  
  3092.     /**
  3093.      * do not override
  3094.      * @return bool true if a link to this procedural page exists in package $package and subpackage $subpackage
  3095.      * @param string $expr procedural page name
  3096.      * @param string $package package to search in
  3097.      * @param string $subpackage subpackage to search in
  3098.      * @access private
  3099.      */
  3100.     function isLinkedPage($expr,$package,$subpackage,$path=false)
  3101.     {
  3102.         if ($path)
  3103.         return isset($this->linkswithfile[$package][$subpackage]['page'][$path][$expr]);
  3104.         return isset($this->links[$package][$subpackage]['page'][$expr]);
  3105.     }
  3106.  
  3107.     /**
  3108.      * do not override
  3109.      * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
  3110.      * @param string $expr method name
  3111.      * @param string $class class name
  3112.      * @param string $package package to search in
  3113.      * @param string $subpackage subpackage to search in
  3114.      * @access private
  3115.      */
  3116.     function isLinkedMethod($expr,$package,$subpackage,$class,$file=false)
  3117.     {
  3118.         if ($file)
  3119.         return isset($this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr]);
  3120.         return isset($this->links[$package][$subpackage]['method'][$class][$expr]);
  3121.     }
  3122.  
  3123.     /**
  3124.      * do not override
  3125.      * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
  3126.      * @param string $expr var name
  3127.      * @param string $class class name
  3128.      * @param string $package package to search in
  3129.      * @param string $subpackage subpackage to search in
  3130.      * @access private
  3131.      */
  3132.     function isLinkedVar($expr,$package,$subpackage,$class,$file=false)
  3133.     {
  3134.         if ($file)
  3135.         return isset($this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr]);
  3136.         return isset($this->links[$package][$subpackage]['var'][$class][$expr]);
  3137.     }
  3138.  
  3139.     /**
  3140.      * do not override
  3141.      * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
  3142.      * @param string $expr constant name
  3143.      * @param string $class class name
  3144.      * @param string $package package to search in
  3145.      * @param string $subpackage subpackage to search in
  3146.      * @access private
  3147.      */
  3148.     function isLinkedConst($expr,$package,$subpackage,$class,$file=false)
  3149.     {
  3150.         if ($file)
  3151.         return isset($this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr]);
  3152.         return isset($this->links[$package][$subpackage]['const'][$class][$expr]);
  3153.     }
  3154.  
  3155.     /**
  3156.      * return false or a {@link classLink} to $expr
  3157.      * @param string $expr class name
  3158.      * @param string $package package name
  3159.      * @return mixed returns a {@link classLink} or false if the element is not found in package $package
  3160.      * @see classLink
  3161.      */
  3162.     function getClassLink($expr,$package,$file=false$text false)
  3163.     {
  3164.         if (!isset($this->links[$package])) return false;
  3165.         foreach($this->links[$packageas $subpackage => $notused)
  3166.         {
  3167.             if ($this->isLinkedClass($expr,$package,$subpackage,$file))
  3168.             {
  3169.                 if ($file)
  3170.                 {
  3171.                     return $this->linkswithfile[$package][$subpackage]['class'][$file][$expr];
  3172.                 }
  3173.                 return $this->links[$package][$subpackage]['class'][$expr];
  3174.             }
  3175.         }
  3176.         return false;
  3177.     }
  3178.  
  3179.     /**
  3180.      * return false or a {@link functionLink} to $expr
  3181.      * @param string $expr function name
  3182.      * @param string $package package name
  3183.      * @return mixed returns a {@link functionLink} or false if the element is not found in package $package
  3184.      * @see functionLink
  3185.      */
  3186.     function getFunctionLink($expr,$package,$file=false$text false)
  3187.     {
  3188.         if (!isset($this->links[$package])) return false;
  3189.         foreach($this->links[$packageas $subpackage => $notused)
  3190.         {
  3191.             if ($this->isLinkedFunction($expr,$package,$subpackage,$file))
  3192.             {
  3193.                 if ($file)
  3194.                 {
  3195.                     return $this->linkswithfile[$package][$subpackage]['function'][$file][$expr];
  3196.                 }
  3197.                 return $this->links[$package][$subpackage]['function'][$expr];
  3198.             }
  3199.         }
  3200.         return false;
  3201.     }
  3202.  
  3203.     /**
  3204.      * return false or a {@link defineLink} to $expr
  3205.      * @param string $expr constant name
  3206.      * @param string $package package name
  3207.      * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
  3208.      * @see defineLink
  3209.      */
  3210.     function getDefineLink($expr,$package,$file=false$text false)
  3211.     {
  3212.         if (!isset($this->links[$package])) return false;
  3213.         foreach($this->links[$packageas $subpackage => $notused)
  3214.         {
  3215.             if ($this->isLinkedDefine($expr,$package,$subpackage,$file))
  3216.             {
  3217.                 if ($file)
  3218.                 {
  3219.                     return $this->linkswithfile[$package][$subpackage]['define'][$file][$expr];
  3220.                 }
  3221.                 return $this->links[$package][$subpackage]['define'][$expr];
  3222.             }
  3223.         }
  3224.         return false;
  3225.     }
  3226.  
  3227.     /**
  3228.      * return false or a {@link globalLink} to $expr
  3229.      * @param string $expr global variable name (with leading $)
  3230.      * @param string $package package name
  3231.      * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
  3232.      * @see defineLink
  3233.      */
  3234.     function getGlobalLink($expr,$package,$file=false$text false)
  3235.     {
  3236.         if (!isset($this->links[$package])) return false;
  3237.         foreach($this->links[$packageas $subpackage => $notused)
  3238.         {
  3239.             if ($this->isLinkedGlobal($expr,$package,$subpackage,$file))
  3240.             {
  3241.                 if ($file)
  3242.                 {
  3243.                     return $this->linkswithfile[$package][$subpackage]['global'][$file][$expr];
  3244.                 }
  3245.                 return $this->links[$package][$subpackage]['global'][$expr];
  3246.             }
  3247.         }
  3248.         return false;
  3249.     }
  3250.  
  3251.     /**
  3252.      * return false or a {@link pageLink} to $expr
  3253.      * @param string $expr procedural page name
  3254.      * @param string $package package name
  3255.      * @return mixed returns a {@link pageLink} or false if the element is not found in package $package
  3256.      * @see pageLink
  3257.      */
  3258.     function getPageLink($expr,$package,$path false$text false$packages false)
  3259.     {
  3260.         if (!isset($this->links[$package])) return false;
  3261.         foreach($this->links[$packageas $subpackage => $notused)
  3262.         {
  3263.             if ($this->isLinkedPage($expr,$package,$subpackage,$path))
  3264.             {
  3265.                 if ($path)
  3266.                 {
  3267.                     return $this->linkswithfile[$package][$subpackage]['page'][$path][$expr];
  3268.                 }
  3269.                 return $this->links[$package][$subpackage]['page'][$expr];
  3270.             }
  3271.         }
  3272.         return false;
  3273.     }
  3274.  
  3275.     /**
  3276.      * return false or a {@link methodLink} to $expr in $class
  3277.      * @param string $expr method name
  3278.      * @param string $class class name
  3279.      * @param string $package package name
  3280.      * @return mixed returns a {@link methodLink} or false if the element is not found in package $package, class $class
  3281.      * @see methodLink
  3282.      */
  3283.     function getMethodLink($expr,$class,$package,$file=false$text false)
  3284.     {
  3285.         $expr trim($expr);
  3286.         $class trim($class);
  3287.         if (!isset($this->links[$package])) return false;
  3288.         foreach($this->links[$packageas $subpackage => $notused)
  3289.         {
  3290.             if ($this->isLinkedMethod($expr,$package,$subpackage,$class,$file))
  3291.             {
  3292.                 if ($file)
  3293.                 {
  3294.                     return $this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr];
  3295.                 }
  3296.                 return $this->links[$package][$subpackage]['method'][$class][$expr];
  3297.             }
  3298. &