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