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: Converter.inc,v 1.39 2007/12/19 02:16:49 ashnazg Exp $
  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: Converter.inc,v 1.39 2007/12/19 02:16:49 ashnazg Exp $
  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.      * Options for each template, parsed from the options.ini file in the template base directory
  396.      * @tutorial phpDocumentor/tutorials.pkg#conversion.ppage
  397.      * @var array 
  398.      */
  399.     var $template_options;
  400.  
  401.     /**
  402.      * Tutorials and Extended Documentation parsed from a tutorials/package[/subpackage] directory
  403.      * @tutorial tutorials.pkg
  404.      * @access private
  405.      */
  406.     var $tutorials = array();
  407.  
  408.     /**
  409.      * tree-format structure of tutorials and their child tutorials, if any
  410.      * @var array 
  411.      * @access private
  412.      */
  413.     var $tutorial_tree = false;
  414.  
  415.     /**
  416.      * list of tutorials that have already been processed. Used by @link _setupTutorialTree()
  417.      * @var array 
  418.      * @access private
  419.      */
  420.     var $processed_tutorials;
  421.  
  422.     /**
  423.      * List of all @todo tags and a link to the element with the @todo
  424.      *
  425.      * Format: array(package => array(link to element, array(todo {@link parserTag},...)),...)
  426.      * @tutorial tags.todo.pkg
  427.      * @var array 
  428.      */
  429.     var $todoList = array();
  430.  
  431.     /**
  432.      * Directory where compiled templates go - will be deleted on exit
  433.      *
  434.      * @var string 
  435.      * @access private
  436.      */
  437.      var $_compiledDir = array();
  438.  
  439.     /**
  440.      * Initialize Converter data structures
  441.      * @param array {@link $all_packages} value
  442.      * @param array {@link $package_parents} value
  443.      * @param Classes {@link $classes} value
  444.      * @param ProceduralPages {@link $proceduralpages} value
  445.      * @param array {@link $package_output} value
  446.      * @param boolean {@link $parseprivate} value
  447.      * @param boolean {@link $quietmode} value
  448.      * @param string {@link $targetDir} value
  449.      * @param string {@link $templateDir} value
  450.      * @param string (@link $title} value
  451.      */
  452.     function Converter(&$allp&$packp&$classes&$procpages$po$pp$qm$targetDir$template$title)
  453.     {
  454.         $this->all_packages = $allp;
  455.         $this->package_parents = $packp;
  456.         $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
  457.         $this->proceduralpages &$procpages;
  458.         $this->package_output = $po;
  459.         if (is_array($po))
  460.         {
  461.             $a $po[0];
  462.             $this->all_packages = array_flip($po);
  463.             $this->all_packages[$a= 1;
  464.         }
  465.         $this->parseprivate = $pp;
  466.         $this->quietmode = $qm;
  467.         $this->classes = &$classes;
  468.         $this->roots $classes->getRoots($this->processSpecialRoots);
  469.         $this->title = $title;
  470.         $this->setTemplateDir($template);
  471.         $this->setTargetdir($targetDir);
  472.     }
  473.  
  474.     /**
  475.      * Called by IntermediateParser after creation
  476.      * @access private
  477.      */
  478.     function setTutorials($tutorials)
  479.     {
  480.         $this->tutorials $tutorials;
  481.     }
  482.  
  483.     /**
  484.      * @param pkg|cls|procthe tutorial type to search for
  485.      * @param tutorial name
  486.      * @param string package name
  487.      * @param string subpackage name, if any
  488.      * @return false|parserTutorialif the tutorial exists, return it
  489.      */
  490.     function hasTutorial($type$name$package$subpackage '')
  491.     {
  492.         if (isset($this->tutorials[$package][$subpackage][$type][$name '.' $type]))
  493.             return $this->tutorials[$package][$subpackage][$type][$name '.' $type];
  494.         return false;
  495.     }
  496.  
  497.     /**
  498.      * Called by {@link walk()} while converting, when the last class element
  499.      * has been parsed.
  500.      *
  501.      * A Converter can use this method in any way it pleases. HTMLframesConverter
  502.      * uses it to complete the template for the class and to output its
  503.      * documentation
  504.      * @see HTMLframesConverter::endClass()
  505.      * @abstract
  506.      */
  507.     function endClass()
  508.     {
  509.     }
  510.  
  511.     /**
  512.     * Called by {@link walk()} while converting, when the last procedural page
  513.     * element has been parsed.
  514.     *
  515.     * A Converter can use this method in any way it pleases. HTMLframesConverter
  516.     * uses it to complete the template for the procedural page and to output its
  517.     * documentation
  518.     * @see HTMLframesConverter::endClass()
  519.     * @abstract
  520.     */
  521.     function endPage()
  522.     {
  523.     }
  524.  
  525.     /**
  526.     * Called by {@link walk()} while converting.
  527.     *
  528.     * This method is intended to be the place that {@link $pkg_elements} is
  529.     * formatted for output.
  530.     * @see HTMLframesConverter::formatPkgIndex()
  531.     * @abstract
  532.     */
  533.     function formatPkgIndex()
  534.     {
  535.     }
  536.  
  537.     /**
  538.     * Called by {@link walk()} while converting.
  539.     *
  540.     * This method is intended to be the place that {@link $elements} is
  541.     * formatted for output.
  542.     * @see HTMLframesConverter::formatIndex()
  543.     * @abstract
  544.     */
  545.     function formatIndex()
  546.     {
  547.     }
  548.  
  549.     /**
  550.     * Called by {@link walk()} while converting.
  551.     *
  552.     * This method is intended to be the place that any of
  553.     * {@link $class_elements, $function_elements, $page_elements},
  554.     * {@link $define_elements}, and {@link $global_elements} is formatted for
  555.     * output, depending on the value of {@link $leftindex}
  556.     * @see HTMLframesConverter::formatLeftIndex()
  557.     * @abstract
  558.     */
  559.     function formatLeftIndex()
  560.     {
  561.     }
  562.  
  563.     /**
  564.      * Called by {@link parserSourceInlineTag::stringConvert()} to allow
  565.      * converters to format the source code the way they'd like.
  566.      *
  567.      * default returns it unchanged (html with xhtml tags)
  568.      * @param string output from highlight_string() - use this function to
  569.      *  reformat the returned data for Converter-specific output
  570.      * @return string 
  571.      * @deprecated in favor of tokenizer-based highlighting.  This will be
  572.      *              removed for 2.0
  573.      */
  574.     function unmangle($sourcecode)
  575.     {
  576.         return $sourcecode;
  577.     }
  578.  
  579.     /**
  580.      * Initialize highlight caching
  581.      */
  582.     function startHighlight()
  583.     {
  584.         $this->_highlightCache = array(falsefalse);
  585.         $this->_appendHighlight '';
  586.     }
  587.  
  588.     function getHighlightState()
  589.     {
  590.         return $this->_highlightCache;
  591.     }
  592.  
  593.     function _setHighlightCache($type$token)
  594.     {
  595.         $test ($this->_highlightCache[0=== $type && $this->_highlightCache[1== $token);
  596.         if (!$test{
  597.             $this->_appendHighlight $this->flushHighlightCache();
  598.         else {
  599.             $this->_appendHighlight '';
  600.         }
  601.         $this->_highlightCache = array($type$token);
  602.         return $test;
  603.     }
  604.  
  605.     /**
  606.      * Return the close text for the current token
  607.      * @return string 
  608.      */
  609.     function flushHighlightCache()
  610.     {
  611.         $hc $this->_highlightCache;
  612.         $this->_highlightCache = array(falsefalse);
  613.         if ($hc[0]{
  614.             if (!isset($this->template_options[$hc[0]]['/'.$hc[1]])) {
  615.                 return '';
  616.             }
  617.             return $this->template_options[$hc[0]]['/'.$hc[1]];
  618.         }
  619.         return '';
  620.     }
  621.  
  622.     /**
  623.      * Used to allow converters to format the source code the way they'd like.
  624.      *
  625.      * default returns it unchanged.  Mainly used by the {@link HighlightParser}
  626.      * {@internal 
  627.      * The method takes information from options.ini, the template options
  628.      * file, specifically the [highlightSourceTokens] and [highlightSource]
  629.      * sections, and uses them to enclose tokens.
  630.      *
  631.      * {@source } }
  632.      * @param integer token value from {@link PHP_MANUAL#tokenizer tokenizer constants}
  633.      * @param string contents of token
  634.      * @param boolean whether the contents are preformatted or need modification
  635.      * @return string 
  636.      */
  637.     function highlightSource($token$word$preformatted = false)
  638.     {
  639.         if ($token !== false)
  640.         {
  641.             if (!$preformatted$word $this->postProcess($word);
  642.             if (isset($this->template_options['highlightSourceTokens'][token_name($token)]))
  643.             {
  644.                 if ($this->_setHighlightCache('highlightSourceTokens'token_name($token))) {
  645.                     return $word;
  646.                 }
  647.                 $e $this->_appendHighlight;
  648.                 return $e $this->template_options['highlightSourceTokens'][token_name($token)$word;
  649.             else
  650.             {
  651.                 $this->_setHighlightCache(falsefalse);
  652.                 $e $this->_appendHighlight;
  653.                 return $e $word;
  654.             }
  655.         else
  656.         {
  657.             if (isset($this->template_options['highlightSource'][$word]))
  658.             {
  659.                 $newword ($preformatted $word $this->postProcess($word));
  660.                 if ($this->_setHighlightCache('highlightSource'$word)) {
  661.                     return $newword;
  662.                 }
  663.                 $e $this->_appendHighlight;
  664.                 return $e $this->template_options['highlightSource'][$word$newword;
  665.             else
  666.             {
  667.                 $this->_setHighlightCache(falsefalse);
  668.                 $e $this->_appendHighlight;
  669.                 return $e ($preformatted $word $this->postProcess($word));
  670.             }
  671.         }
  672.     }
  673.  
  674.     /**
  675.      * Used to allow converters to format the source code of DocBlocks the way
  676.      * they'd like.
  677.      *
  678.      * default returns it unchanged.  Mainly used by the {@link HighlightParser}
  679.      * {@internal 
  680.      * The method takes information from options.ini, the template options
  681.      * file, specifically the [highlightDocBlockSourceTokens] section, and uses
  682.      * it to enclose tokens.
  683.      *
  684.      * {@source } }
  685.      * @param string name of docblock token type
  686.      * @param string contents of token
  687.      * @param boolean whether the contents are preformatted or need modification
  688.      * @return string 
  689.      */
  690.     function highlightDocBlockSource($token$word$preformatted = false)
  691.     {
  692.         if (empty($word)) {
  693.             $this->_setHighlightCache(falsefalse);
  694.             $e $this->_appendHighlight;
  695.             return $e $word;
  696.         }
  697.         if (isset($this->template_options['highlightDocBlockSourceTokens'][$token]))
  698.         {
  699.             if (!$preformatted$word $this->postProcess($word);
  700.             if ($this->_setHighlightCache('highlightDocBlockSourceTokens'$token)) {
  701.                 return $word;
  702.             }
  703.             $e $this->_appendHighlight;
  704.             return $e $this->template_options['highlightDocBlockSourceTokens'][$token$word;
  705.         else {
  706.             $this->_setHighlightCache(falsefalse);
  707.             $e $this->_appendHighlight;
  708.             return $e ($preformatted $word $this->postProcess($word));
  709.         }
  710.     }
  711.  
  712.     /**
  713.      * Used to allow converters to format the source code of Tutorial XML the way
  714.      * they'd like.
  715.      *
  716.      * default returns it unchanged.  Mainly used by the {@link HighlightParser}
  717.      * {@internal 
  718.      * The method takes information from options.ini, the template options
  719.      * file, specifically the [highlightDocBlockSourceTokens] section, and uses
  720.      * it to enclose tokens.
  721.      *
  722.      * {@source } }
  723.      * @param string name of docblock token type
  724.      * @param string contents of token
  725.      * @param boolean whether the contents are preformatted or need modification
  726.      * @return string 
  727.      */
  728.     function highlightTutorialSource($token$word$preformatted = false)
  729.     {
  730.         if (empty($word)) {
  731.             $this->_setHighlightCache(falsefalse);
  732.             $e $this->_appendHighlight;
  733.             return $e $word;
  734.         }
  735.         if (isset($this->template_options['highlightTutorialSourceTokens'][$token]))
  736.         {
  737.             if (!$preformatted$word $this->postProcess($word);
  738.             if ($this->_setHighlightCache('highlightTutorialSourceTokens'$token)) {
  739.                 return $word;
  740.             }
  741.             $e $this->_appendHighlight;
  742.             return $e $this->template_options['highlightTutorialSourceTokens'][$token$word;
  743.         else {
  744.             $this->_setHighlightCache(falsefalse);
  745.             $e $this->_appendHighlight;
  746.             return $e ($preformatted $word $this->postProcess($word));
  747.         }
  748.     }
  749.  
  750.     /**
  751.      * Called by {@link parserReturnTag::Convert()} to allow converters to
  752.      * change type names to desired formatting
  753.      *
  754.      * Used by {@link XMLDocBookConverter::type_adjust()} to change true and
  755.      * false to the peardoc2 values
  756.      * @param string 
  757.      * @return string 
  758.      */
  759.     function type_adjust($typename)
  760.     {
  761.         return $typename;
  762.     }
  763.  
  764.     /**
  765.      * Used to convert the {@}example} inline tag in a docblock.
  766.      *
  767.      * By default, this just wraps ProgramExample
  768.      * @see XMLDocBookpeardoc2Converter::exampleProgramExample
  769.      * @param string 
  770.      * @param boolean true if this is to highlight a tutorial <programlisting>
  771.      * @return string 
  772.      */
  773.     function exampleProgramExample($example$tutorial = false$inlinesourceparse = null/*false*/,
  774.                             $class = null/*false*/$linenum = null/*false*/$filesourcepath = null/*false*/)
  775.     {
  776.         return $this->ProgramExample($example$tutorial$inlinesourceparse$class$linenum$filesourcepath);
  777.     }
  778.  
  779.     /**
  780.      * Used to convert the <<code>> tag in a docblock
  781.      * @param string 
  782.      * @param boolean true if this is to highlight a tutorial <programlisting>
  783.      * @return string 
  784.      */
  785.     function ProgramExample($example$tutorial = false$inlinesourceparse = null/*false*/,
  786.                             $class = null/*false*/$linenum = null/*false*/$filesourcepath = null/*false*/)
  787.     {
  788.         $this->highlightingSource = true;
  789.         if (tokenizer_ext)
  790.         {
  791.             $e $example;
  792.             if (!is_array($example))
  793.             {
  794.                 $obj = new phpDocumentorTWordParser;
  795.                 $obj->setup($example);
  796.                 $e $obj->getFileSource();
  797.                 $bOpenTagFound = false;
  798.                 foreach ($e as $ke => $ee)
  799.                 {
  800.                     foreach ($ee as $kee => $eee)
  801.                     {
  802.                         if ((int) $e[$ke][$kee][0== T_OPEN_TAG)
  803.                         {
  804.                             $bOpenTagFound = true;
  805.                         }
  806.                     }
  807.                 }
  808.                 if (!$bOpenTagFound{
  809.                     $example "<?php\n".$example;
  810.                     $obj->setup($example);
  811.                     $e $obj->getFileSource();
  812.                     unset($e[0]);
  813.                     $e array_values($e);
  814.                 }
  815.                 unset($obj);
  816.             }
  817.             $saveclass $this->class;
  818.             $parser = new phpDocumentor_HighlightParser;
  819.             if (!isset($inlinesourceparse))
  820.             {
  821.                 $example $parser->parse($e$thistrue)// force php mode
  822.             else
  823.             {
  824.                 if (isset($filesourcepath))
  825.                 {
  826.                     $example $parser->parse($e$this$inlinesourceparse$class$linenum$filesourcepath);
  827.                 elseif (isset($linenum))
  828.                 {
  829.                     $example $parser->parse($e$this$inlinesourceparse$class$linenum);
  830.                 elseif (isset($class))
  831.                 {
  832.                     $example $parser->parse($e$this$inlinesourceparse$class);
  833.                 else
  834.                 {
  835.                     $example $parser->parse($e$this$inlinesourceparse);
  836.                 }
  837.             }
  838.             $this->class = $saveclass;
  839.         else
  840.         {
  841.             $example $this->postProcess($example);
  842.         }
  843.         $this->highlightingSource = false;
  844.  
  845.         if ($tutorial)
  846.         {
  847.             return $example;
  848.         }
  849.  
  850.         if (!isset($this->template_options['desctranslate'])) return $example;
  851.         if (!isset($this->template_options['desctranslate']['code'])) return $example;
  852.         $example $this->template_options['desctranslate']['code'$example;
  853.         if (!isset($this->template_options['desctranslate']['/code'])) return $example;
  854.         return $example $this->template_options['desctranslate']['/code'];
  855.     }
  856.  
  857.     /**
  858.      * @param string 
  859.      */
  860.     function TutorialExample($example)
  861.     {
  862.         $this->highlightingSource = true;
  863.         $parse = new phpDocumentor_TutorialHighlightParser;
  864.         $x $parse->parse($example$this);
  865.         $this->highlightingSource = false;
  866.         return $x;
  867.     }
  868.  
  869.     /**
  870.      * Used to convert the contents of <<li>> in a docblock
  871.      * @param string 
  872.      * @return string 
  873.      */
  874.     function ListItem($item)
  875.     {
  876.         if (!isset($this->template_options['desctranslate'])) return $item;
  877.         if (!isset($this->template_options['desctranslate']['li'])) return $item;
  878.         $item $this->template_options['desctranslate']['li'$item;
  879.         if (!isset($this->template_options['desctranslate']['/li'])) return $item;
  880.         return $item $this->template_options['desctranslate']['/li'];
  881.     }
  882.  
  883.     /**
  884.      * Used to convert the contents of <<ol>> or <<ul>> in a docblock
  885.      * @param string 
  886.      * @return string 
  887.      */
  888.     function EncloseList($list,$ordered)
  889.     {
  890.         $listname ($ordered 'ol' 'ul');
  891.         if (!isset($this->template_options['desctranslate'])) return $list;
  892.         if (!isset($this->template_options['desctranslate'][$listname])) return $list;
  893.         $list $this->template_options['desctranslate'][$listname$list;
  894.         if (!isset($this->template_options['desctranslate']['/'.$listname])) return $list;
  895.         return $list $this->template_options['desctranslate']['/'.$listname];
  896.     }
  897.  
  898.     /**
  899.      * Used to convert the contents of <<pre>> in a docblock
  900.      * @param string 
  901.      * @return string 
  902.      */
  903.     function PreserveWhiteSpace($string)
  904.     {
  905.         if (!isset($this->template_options['desctranslate'])) return $string;
  906.         if (!isset($this->template_options['desctranslate']['pre'])) return $string;
  907.         $string $this->template_options['desctranslate']['pre'$string;
  908.         if (!isset($this->template_options['desctranslate']['/pre'])) return $string;
  909.         return $string $this->template_options['desctranslate']['/pre'];
  910.     }
  911.  
  912.     /**
  913.      * Used to enclose a paragraph in a docblock
  914.      * @param string 
  915.      * @return string 
  916.      */
  917.     function EncloseParagraph($para)
  918.     {
  919.         if (!isset($this->template_options['desctranslate'])) return $para;
  920.         if (!isset($this->template_options['desctranslate']['p'])) return $para;
  921.         $para $this->template_options['desctranslate']['p'$para;
  922.         if (!isset($this->template_options['desctranslate']['/p'])) return $para;
  923.         return $para $this->template_options['desctranslate']['/p'];
  924.     }
  925.  
  926.     /**
  927.      * Used to convert the contents of <<b>> in a docblock
  928.      * @param string 
  929.      * @return string 
  930.      */
  931.     function Bolden($para)
  932.     {
  933.         if (!isset($this->template_options['desctranslate'])) return $para;
  934.         if (!isset($this->template_options['desctranslate']['b'])) return $para;
  935.         $para $this->template_options['desctranslate']['b'$para;
  936.         if (!isset($this->template_options['desctranslate']['/b'])) return $para;
  937.         return $para $this->template_options['desctranslate']['/b'];
  938.     }
  939.  
  940.     /**
  941.      * Used to convert the contents of <<i>> in a docblock
  942.      * @param string 
  943.      * @return string 
  944.      */
  945.     function Italicize($para)
  946.     {
  947.         if (!isset($this->template_options['desctranslate'])) return $para;
  948.         if (!isset($this->template_options['desctranslate']['i'])) return $para;
  949.         $para $this->template_options['desctranslate']['i'$para;
  950.         if (!isset($this->template_options['desctranslate']['/i'])) return $para;
  951.         return $para $this->template_options['desctranslate']['/i'];
  952.     }
  953.  
  954.     /**
  955.      * Used to convert the contents of <<var>> in a docblock
  956.      * @param string 
  957.      * @return string 
  958.      */
  959.     function Varize($para)
  960.     {
  961.         if (!isset($this->template_options['desctranslate'])) return $para;
  962.         if (!isset($this->template_options['desctranslate']['var'])) return $para;
  963.         $para $this->template_options['desctranslate']['var'$para;
  964.         if (!isset($this->template_options['desctranslate']['/var'])) return $para;
  965.         return $para $this->template_options['desctranslate']['/var'];
  966.     }
  967.  
  968.     /**
  969.      * Used to convert the contents of <<kbd>> in a docblock
  970.      * @param string 
  971.      * @return string 
  972.      */
  973.     function Kbdize($para)
  974.     {
  975.         if (!isset($this->template_options['desctranslate'])) return $para;
  976.         if (!isset($this->template_options['desctranslate']['kbd'])) return $para;
  977.         $para $this->template_options['desctranslate']['kbd'$para;
  978.         if (!isset($this->template_options['desctranslate']['/kbd'])) return $para;
  979.         return $para $this->template_options['desctranslate']['/kbd'];
  980.     }
  981.  
  982.     /**
  983.      * Used to convert the contents of <<samp>> in a docblock
  984.      * @param string 
  985.      * @return string 
  986.      */
  987.     function Sampize($para)
  988.     {
  989.         if (!isset($this->template_options['desctranslate'])) return $para;
  990.         if (!isset($this->template_options['desctranslate']['samp'])) return $para;
  991.         $para $this->template_options['desctranslate']['samp'$para;
  992.         if (!isset($this->template_options['desctranslate']['/samp'])) return $para;
  993.         return $para $this->template_options['desctranslate']['/samp'];
  994.     }
  995.  
  996.     /**
  997.      * Used to convert <<br>> in a docblock
  998.      * @param string 
  999.      * @return string 
  1000.      */
  1001.     function Br($para)
  1002.     {
  1003.         if (!isset($this->template_options['desctranslate'])) return $para;
  1004.         if (!isset($this->template_options['desctranslate']['br'])) return $para;
  1005.         $para $this->template_options['desctranslate']['br'$para;
  1006.         return $para;
  1007.     }
  1008.  
  1009.     /**
  1010.      * This version does nothing
  1011.      *
  1012.      * Perform necessary post-processing of string data.  For example, the HTML
  1013.      * Converters should escape < and > to become &lt; and &gt;
  1014.      * @return string 
  1015.      */
  1016.     function postProcess($text)
  1017.     {
  1018.         return $text;
  1019.     }
  1020.  
  1021.     /**
  1022.      * Creates a table of contents for a {@}toc} inline tag in a tutorial
  1023.      *
  1024.      * This function should return a formatted table of contents.  By default, it
  1025.      * does nothing, it is up to the converter to format the TOC
  1026.      * @abstract
  1027.      * @return string table of contents formatted for use in the current output format
  1028.      * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...)
  1029.      */
  1030.     function formatTutorialTOC($toc)
  1031.     {
  1032.         return '';
  1033.     }
  1034.  
  1035.     /**
  1036.      * Write out the formatted source code for a php file
  1037.      *
  1038.      * This function provides the primary functionality for the
  1039.      * {@tutorial tags.filesource.pkg} tag.
  1040.      * @param string full path to the file
  1041.      * @param string fully highlighted/linked source code of the file
  1042.      * @abstract
  1043.      */
  1044.     function writeSource($filepath$source)
  1045.     {
  1046.         debug($source);
  1047.         return;
  1048.     }
  1049.  
  1050.     /**
  1051.      * Write out the formatted source code for an example php file
  1052.      *
  1053.      * This function provides the primary functionality for the
  1054.      * {@tutorial tags.example.pkg} tag.
  1055.      * @param string example title
  1056.      * @param string example filename (no path)
  1057.      * @param string fully highlighted/linked source code of the file
  1058.      * @abstract
  1059.      */
  1060.     function writeExample($title$path$source)
  1061.     {
  1062.         return;
  1063.     }
  1064.  
  1065.     /** Translate the path info into a unique file name for the highlighted
  1066.      * source code.
  1067.      * @param string $pathinfo 
  1068.      * @return string 
  1069.      */
  1070.     function getFileSourceName($path)
  1071.     {
  1072.         global $_phpDocumentor_options;
  1073.         $pathinfo $this->proceduralpages->getPathInfo($path$this);
  1074.         $pathinfo['source_loc'str_replace($_phpDocumentor_options['Program_Root'].'/','',$pathinfo['source_loc']);
  1075.         $pathinfo['source_loc'str_replace('/','_',$pathinfo['source_loc']);
  1076.         return "fsource_{$pathinfo['package']}_{$pathinfo['subpackage']}_{$pathinfo['source_loc']}";
  1077.     }
  1078.  
  1079.     /** Return the fixed path to the source-code file folder.
  1080.      * @param string $base Path is relative to this folder
  1081.      * @return string 
  1082.      */
  1083.     function getFileSourcePath($base)
  1084.     {
  1085.         if (substr($basestrlen($base- 1!= PATH_DELIMITER{
  1086.             $base .= PATH_DELIMITER;
  1087.         }
  1088.         return $base '__filesource';
  1089.     }
  1090.  
  1091.     /** Return the path to the current
  1092.      * @param string $pathinfo 
  1093.      * @return string 
  1094.      */
  1095.     function getCurrentPageURL()
  1096.     {
  1097.         return '{$srcdir}' PATH_DELIMITER . $this->page_dir;
  1098.     }
  1099.  
  1100.     /**
  1101.      * @return string an output-format dependent link to phpxref-style highlighted
  1102.      *  source code
  1103.      * @abstract
  1104.      */
  1105.     function getSourceLink($path)
  1106.     {
  1107.         return '';
  1108.     }
  1109.  
  1110.     /**
  1111.      * @return string Link to the current page being parsed.
  1112.      *  Should return {@link $curname} and a converter-specific extension.
  1113.      * @abstract
  1114.      */
  1115.     function getCurrentPageLink()
  1116.     {
  1117.     }
  1118.  
  1119.     /**
  1120.      * Return a line of highlighted source code with formatted line number
  1121.      *
  1122.      * If the $path is a full path, then an anchor to the line number will be
  1123.      * added as well
  1124.      * @param integer line number
  1125.      * @param string highlighted source code line
  1126.      * @param false|stringfull path to @filesource file this line is a part of,
  1127.      *         if this is a single line from a complete file.
  1128.      * @return string formatted source code line with line number
  1129.      */
  1130.     function sourceLine($linenumber$line$path = false)
  1131.     {
  1132.         if ($path)
  1133.         {
  1134.             return $this->getSourceAnchor($path$linenumber.
  1135.                    $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
  1136.         else
  1137.         {
  1138.             return $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
  1139.         }
  1140.     }
  1141.  
  1142.     /**
  1143.      * Determine whether an element's file has generated source code, used for
  1144.      * linking to line numbers of source.
  1145.      *
  1146.      * Wrapper for {@link $sourcePaths} in this version
  1147.      * 
  1148.      * {@internal since file paths get stored with most/all slashes
  1149.      * set to forward slash '/', we need to doublecheck that
  1150.      * we're not given a backslashed path to search for...
  1151.      * if we are, it's likely that it was originally stored
  1152.      * with a forward slash.  Further, I'm not convinced it's safe
  1153.      * to just check the {@link PHPDOCUMENTOR_WINDOWS} flag, so I'm checking
  1154.      * specifically for backslashes intead.}}}
  1155.      * 
  1156.      * @param string full path to the source code file
  1157.      * @return boolean 
  1158.      */
  1159.     function hasSourceCode($path)
  1160.     {
  1161.         return isset($this->sourcePaths[$path]);
  1162.         if (strpos($path'\\'> -1{
  1163.             $modifiedPath str_replace('\\''/'$path);
  1164.             return isset($this->sourcePaths[$modifiedPath]);
  1165.         else {
  1166.             return isset($this->sourcePaths[$path]);
  1167.         }
  1168.     }
  1169.  
  1170.     /**
  1171.      * Mark a file as having had source code highlighted
  1172.      * @param string full path of source file
  1173.      */
  1174.     function setSourcePaths($path)
  1175.     {
  1176.         $this->sourcePaths[$path= true;
  1177.     }
  1178.  
  1179.     /**
  1180.      * Used to translate an XML DocBook entity like &rdquo; from a tutorial by
  1181.      * reading the options.ini file for the template.
  1182.      * @param string entity name
  1183.      */
  1184.     function TranslateEntity($name)
  1185.     {
  1186.         if (!isset($this->template_options['ppage']))
  1187.         {
  1188.             if (!$this->template_options['preservedocbooktags'])
  1189.             return '';
  1190.             else
  1191.             return '&'.$name.';';
  1192.         }
  1193.         if (isset($this->template_options['ppage']['&'.$name.';']))
  1194.         {
  1195.             return $this->template_options['ppage']['&'.$name.';'];
  1196.         else
  1197.         {
  1198.             if (!$this->template_options['preservedocbooktags'])
  1199.             return '';
  1200.             else
  1201.             return '&'.$name.';';
  1202.         }
  1203.     }
  1204.  
  1205.     /**
  1206.      * Used to translate an XML DocBook tag from a tutorial by reading the
  1207.      * options.ini file for the template.
  1208.      * @param string tag name
  1209.      * @param string any attributes Format: array(name => value)
  1210.      * @param string the tag contents, if any
  1211.      * @param string the tag contents, if any, unpost-processed
  1212.      * @return string 
  1213.      */
  1214.     function TranslateTag($name,$attr,$cdata,$unconvertedcdata)
  1215.     {
  1216.         if (!isset($this->template_options['ppage']))
  1217.         {
  1218.             if (!$this->template_options['preservedocbooktags'])
  1219.             return $cdata;
  1220.             else
  1221.             return '<'.$name.$this->AttrToString($name,$attr,true).'>'.$cdata.'</'.$name.'>'."\n";
  1222.         }
  1223.         // make sure this template transforms the tag into something
  1224.         if (isset($this->template_options['ppage'][$name]))
  1225.         {
  1226.             // test for global attribute transforms like $attr$role = class, changing
  1227.             // all role="*" attributes to class="*" in html, for example
  1228.             foreach($attr as $att => $val)
  1229.             {
  1230.                 if (isset($this->template_options['$attr$'.$att]))
  1231.                 {
  1232.                     $new '';
  1233.                     if (!isset($this->template_options['$attr$'.$att]['close']))
  1234.                     {
  1235.                         $new .= '<'.$this->template_options['$attr$'.$att]['open'];
  1236.                         if (isset($this->template_options['$attr$'.$att]['cdata!']))
  1237.                         {
  1238.                             if (isset($this->template_options['$attr$'.$att]['separateall']))
  1239.                             $new .= $this->template_options['$attr$'.$att]['separator'];
  1240.                             else
  1241.                             $new .= ' ';
  1242.                             $new .= $this->template_options['$attr$'.$att]['$'.$att];
  1243.                             $new .= $this->template_options['$attr$'.$att]['separator'];
  1244.                             if ($this->template_options['$attr$'.$att]['quotevalues']$val '"'.$val.'"';
  1245.                             $new .= $val.'>';
  1246.                         else
  1247.                         {
  1248.                             $new .= '>'.$val;
  1249.                         }
  1250.                         $new .= '</'.$this->template_options['$attr$'.$att]['open'].'>';
  1251.                     else
  1252.                     {
  1253.                         $new .= $this->template_options['$attr$'.$att]['open'$val $this->template_options['$attr$'.$att]['close'];
  1254.                     }
  1255.                     unset($attr[$att]);
  1256.                     $cdata $new $cdata;
  1257.                 }
  1258.             }
  1259.  
  1260.             if (!isset($this->template_options['ppage']['/'.$name]))
  1261.             {// if the close tag isn't specified, we put opening and closing tags around it, with translated attributes
  1262.                 if (isset($this->template_options['ppage'][$name.'/']))
  1263.                 $cdata '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'/>' $cdata;
  1264.                 else
  1265.                 $cdata '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'>' $cdata .
  1266.                          '</'.$this->template_options['ppage'][$name].'>';
  1267.             else
  1268.             // if close tag is specified, use the open and close as literal
  1269.                 if ($name == 'programlisting' && isset($attr['role']&&
  1270.                       ($attr['role'== 'php' || $attr['role'== 'tutorial' || $attr['role'== 'html'))
  1271.                 // highlight PHP source
  1272. //                    var_dump($unconvertedcdata, $cdata);exit;
  1273.                     if ($attr['role'== 'php'{
  1274.                         $cdata $this->ProgramExample($unconvertedcdatatrue);
  1275.                     elseif ($attr['role'== 'tutorial'{
  1276.                         $cdata $this->TutorialExample($unconvertedcdata);
  1277.                     elseif ($attr['role'== 'html'{
  1278.                         $cdata $unconvertedcdata;
  1279.                     }
  1280.                 else
  1281.                 {// normal case below
  1282.                     $cdata $this->template_options['ppage'][$name].$this->AttrToString($name,$attr)$cdata .$this->template_options['ppage']['/'.$name];
  1283.                 }
  1284.             }
  1285.             return $cdata;
  1286.         else
  1287.         {
  1288.             if ($this->template_options['preservedocbooktags'])
  1289.             {
  1290.                 return '<'.$name.$this->AttrToString($name,$attr,true).'>' $cdata .
  1291.                          '</'.$name.'>'."\n";
  1292.             else
  1293.             {
  1294.                 return $cdata;
  1295.             }
  1296.         }
  1297.     }
  1298.  
  1299.     /**
  1300.      * Convert the attribute of a Tutorial docbook tag's attribute list
  1301.      * to a string based on the template options.ini
  1302.      * @param string tag name
  1303.      * @param attribute array
  1304.      * @param boolean if true, returns attrname="value"...
  1305.      * @return string 
  1306.      */
  1307.     function AttrToString($tag,$attr,$unmodified = false)
  1308.     {
  1309.         $ret '';
  1310.         if ($unmodified)
  1311.         {
  1312.             $ret ' ';
  1313.             foreach($attr as $n => $v)
  1314.             {
  1315.                 $ret .= $n.' = "'.$v.'"';
  1316.             }
  1317.             return $ret;
  1318.         }
  1319.         // no_attr tells us to ignore all attributes
  1320.         if (isset($this->template_options['no_attr'])) return $ret;
  1321.         // tagname! tells us to ignore all attributes for this tag
  1322.         if (isset($this->template_options['ppage'][$tag.'!'])) return $ret;
  1323.         if (count($attr)) $ret ' ';
  1324.         // pass 1, check to see if any attributes add together
  1325.         $same = array();
  1326.         foreach($attr as $n => $v)
  1327.         {
  1328.             if (isset($this->template_options['ppage'][$tag.'->'.$n]))
  1329.             {
  1330.                 $same[$this->template_options['ppage'][$tag.'->'.$n]][$n;
  1331.             }
  1332.         }
  1333.         foreach($attr as $n => $v)
  1334.         {
  1335.             if (isset($this->template_options['ppage'][$tag.'->'.$n]))
  1336.             {
  1337.                 if (count($same[$this->template_options['ppage'][$tag.'->'.$n]]== 1)
  1338.                 // only 1 attribute translated for this one
  1339.                     // this is useful for equivalent value names
  1340.                     if (isset($this->template_options['ppage'][$tag.'->'.$n.'+'.$v])) $v $this->template_options['ppage'][$tag.'->'.$n.'+'.$v];
  1341.                 else
  1342.                 // more than 1 attribute combines to make the new attribute
  1343.                     $teststrtemp = array();
  1344.                     foreach($same[$this->template_options['ppage'][$tag.'->'.$n]] as $oldattr)
  1345.                     {
  1346.                         $teststrtemp[$oldattr.'+'.$attr[$oldattr];
  1347.                     }
  1348.                     $teststrs = array();
  1349.                     $num count($same[$this->template_options['ppage'][$tag.'->'.$n]]);
  1350.                     for($i=0;$i<$num;$i++)
  1351.                     {
  1352.                         $started = false;
  1353.                         $a '';
  1354.                         for($j=$i;!$started || $j != $i;$j ($j $i$num)
  1355.                         {
  1356.                             if (!empty($a)) $a .= '|';
  1357.                             $a .= $teststrtemp[$j];
  1358.                         }
  1359.                         $teststrs[$i$a;
  1360.                     }
  1361.                     $done = false;
  1362.                     foreach($teststrs as $test)
  1363.                     {
  1364.                         if ($donebreak;
  1365.                         if (isset($this->template_options['ppage'][$tag.'->'.$test]))
  1366.                         {
  1367.                             $done = true;
  1368.                             $v $this->template_options['ppage'][$tag.'->'.$test];
  1369.                         }
  1370.                     }
  1371.                 }
  1372.                 $ret .= $this->template_options['ppage'][$tag.'->'.$n].' = "'.$v.'"';
  1373.             else
  1374.             {
  1375.                 if (!isset($this->template_options['ppage'][$tag.'!'.$n]))
  1376.                 {
  1377.                     if (isset($this->template_options['ppage']['$attr$'.$n]))
  1378.                     $ret .= $this->template_options['ppage']['$attr$'.$n].' = "'.$v.'"';
  1379.                     else
  1380.                     $ret .= $n.' = "'.$v.'"';
  1381.                 }
  1382.             }
  1383.         }
  1384.         return $ret;
  1385.     }
  1386.  
  1387.     /**
  1388.      * Convert the title of a Tutorial docbook tag section
  1389.      * to a string based on the template options.ini
  1390.      * @param string tag name
  1391.      * @param array 
  1392.      * @param string title text
  1393.      * @param string 
  1394.      * @return string 
  1395.      */
  1396.     function ConvertTitle($tag,$attr,$title,$cdata)
  1397.     {
  1398.         if (!isset($this->template_options[$tag.'_title'])) return array($attr,$cdata);
  1399.         if (isset($this->template_options[$tag.'_title']['tag_attr']))
  1400.         {
  1401.             $attr[$this->template_options[$tag.'_title']['tag_attr']] urlencode($cdata);
  1402.             $cdata '';
  1403.         elseif(isset($this->template_options[$tag.'_title']['cdata_start']))
  1404.         {
  1405.             $cdata $this->template_options[$tag.'_title']['open'$title .
  1406.                      $this->template_options[$tag.'_title']['close'$cdata;
  1407.         else $cdata $title.$cdata;
  1408.         return array($attr,$cdata);
  1409.     }
  1410.  
  1411.     /**
  1412.      * Return a converter-specific id to distinguish tutorials and their
  1413.      * sections
  1414.      *
  1415.      * Used by {@}id}
  1416.      * @return string 
  1417.      */
  1418.     function getTutorialId($package,$subpackage,$tutorial,$id)
  1419.     {
  1420.         return $package.$subpackage.$tutorial.$id;
  1421.     }
  1422.  
  1423.     /**
  1424.      * Create the {@link $elements, $pkg_elements} and {@link $links} arrays
  1425.      * @access private
  1426.      * @todo version 2.0 - faulty package_output logic should be removed
  1427.      *
  1428.      *        in this version, if the parent file isn't in the package, all
  1429.      *        the procedural elements are simply shunted to another package!
  1430.      */
  1431.     function _createPkgElements(&$pages)
  1432.     {
  1433.         if (empty($this->elements))
  1434.         {
  1435.             $this->elements = array();
  1436.             $this->pkg_elements = array();
  1437.             $this->links = array();
  1438.             phpDocumentor_out('Building indexes...');
  1439.             flush();
  1440.             foreach($pages as $j => $flub)
  1441.             {
  1442.                 $this->package = $pages[$j]->parent->package;
  1443.                 $this->subpackage = $pages[$j]->parent->subpackage;
  1444.                 $this->class = false;
  1445.                 $this->curfile = $pages[$j]->parent->getFile();
  1446.                 $this->curname $this->getPageName($pages[$j]->parent);
  1447.                 $this->curpath $pages[$j]->parent->getPath();
  1448.                 $use = true;
  1449.                 if ($this->package_output)
  1450.                 {
  1451.                     if (in_array($this->package,$this->package_output))
  1452.                     {
  1453.                         $this->addElement($pages[$j]->parent,$pages[$j]);
  1454.                     else
  1455.                     {
  1456.                         if (count($pages[$j]->classelements))
  1457.                         {
  1458.                             list(,$pages[$j]->parent->packageeach($this->package_output);
  1459.                             reset($this->package_output);
  1460.                             $pages[$j]->parent->subpackage = '';
  1461.                             $this->addElement($pages[$j]->parent,$pages[$j]);
  1462.                         else
  1463.                         {
  1464.                             unset($pages[$j]);
  1465.                             continue;
  1466.                         }
  1467.                     }
  1468.                 else
  1469.                 {
  1470.                     $this->addElement($pages[$j]->parent,$pages[$j]);
  1471.                 }
  1472.                 if ($use)
  1473.                 for($i=0; $i<count($pages[$j]->elements)$i++)
  1474.                 {
  1475.                     $pages[$j]->elements[$i]->docblock->package = $this->package;
  1476.                     $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage;
  1477.                     $this->proceduralpages->replaceElement($pages[$j]->elements[$i]);
  1478.                     $this->addElement($pages[$j]->elements[$i]);
  1479.                 }
  1480.                 for($i=0; $i<count($pages[$j]->classelements)$i++)
  1481.                 {
  1482.                     if ($this->class)
  1483.                     {
  1484.                         if ($pages[$j]->classelements[$i]->type == 'class')
  1485.                         {
  1486.                             if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1487.                             $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1488.                             if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1489.                             $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1490.                             $this->class = $pages[$j]->classelements[$i]->name;
  1491.                         else
  1492.                         {
  1493.                             if ($this->killclasscontinue;
  1494.                             // force all contained elements to have parent package/subpackage
  1495.                             $pages[$j]->classelements[$i]->docblock->package = $this->package;
  1496.                             $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage;
  1497.                         }
  1498.                     }
  1499.                     if ($pages[$j]->classelements[$i]->type == 'class')
  1500.                     {
  1501.                         if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1502.                         $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1503.                         if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1504.                         $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1505.                         $this->class = $pages[$j]->classelements[$i]->name;
  1506.                     }
  1507.                     if (!$this->killclass$this->addElement($pages[$j]->classelements[$i]);
  1508.                 }
  1509.             }
  1510.             phpDocumentor_out("done\n");
  1511.             flush();
  1512.         }
  1513.         $this->sortIndexes();
  1514.         $this->sortTodos();
  1515.         if ($this->sort_page_contents_by_type$this->sortPageContentsByElementType($pages);
  1516.     }
  1517.  
  1518.     /**
  1519.      * Process the {@link $tutorials} array
  1520.      *
  1521.      * Using the tutorialname.ext.ini files, this method sets up tutorial
  1522.      * hierarchy.  There is some minimal error checking to make sure that no
  1523.      * tutorial links to itself, even two levels deep as in tute->next->tute.
  1524.      *
  1525.      * If all tests pass, it creates the hierarchy
  1526.      * @uses generateTutorialOrder()
  1527.      * @uses _setupTutorialTree()
  1528.      * @access private
  1529.      */
  1530.     function _processTutorials()
  1531.     {
  1532.         $parents $all = array();
  1533.         foreach($this->tutorials as $package => $els)
  1534.         {
  1535.             if ($this->package_output)
  1536.             {
  1537.                 if (!in_array($package,$this->package_output))
  1538.                 {
  1539.                     unset($this->tutorials[$package]);
  1540.                     continue;
  1541.                 }
  1542.             }
  1543.             if (!isset($this->pkg_elements[$package]))
  1544.             {
  1545.                 unset($this->tutorials[$package]);
  1546.                 continue;
  1547.             }
  1548.             foreach($els as $subpackage => $els2)
  1549.             {
  1550.                 foreach($els2 as $type => $tutorials)
  1551.                 {
  1552.                     foreach($tutorials as $tutorial)
  1553.                     {
  1554.                         if ($tutorial->ini)
  1555.                         {
  1556.                             if (isset($tutorial->ini['Linked Tutorials']))
  1557.                             {
  1558.                                 foreach($tutorial->ini['Linked Tutorials'as $child)
  1559.                                 {
  1560.                                     $sub (empty($tutorial->subpackage'' $tutorial->subpackage . '/');
  1561.                                     $kid $tutorial->package . '/' $sub $child '.' $tutorial->tutorial_type;
  1562.                                     // parent includes self as a linked tutorial?
  1563.                                     $kidlink $this->getTutorialLink($kid,false,false,array($tutorial->package));
  1564.                                     if (is_object($kidlink&& $this->returnSee($kidlink== $tutorial->getLink($this))
  1565.                                     // bad!
  1566.                                         addErrorDie(PDERROR_TUTORIAL_IS_OWN_CHILD,$tutorial->name,$tutorial->name.'.ini');
  1567.                                     }
  1568.                                 }
  1569.                                 $parents[$tutorial;
  1570.                             }
  1571.                         }
  1572.                         $all[$package][$subpackage][$type][$tutorial;
  1573.                     }
  1574.                 }
  1575.             }
  1576.         }
  1577.         // loop error-checking, use this to eliminate possibility of accidentally linking to a parent as a child
  1578.         $testlinks = array();
  1579.         foreach($parents as $parent)
  1580.         {
  1581.             $testlinks[$parent->name]['links'][$parent->getLink($this);
  1582.             $testlinks[$parent->name]['name'][$parent->getLink($this)$parent->name;
  1583.         }
  1584.         // generate the order of tutorials, and link them together
  1585.         foreach($parents as $parent)
  1586.         {
  1587.             foreach($parent->ini['Linked Tutorials'as $child)
  1588.             {
  1589.                 $sub (empty($parent->subpackage'' $parent->subpackage . '/');
  1590.                 $kid $parent->package . '/' $sub $child '.' $parent->tutorial_type;
  1591.                 // child tutorials must be in the same package AND subpackage
  1592.                 // AND have the same extension as the parent, makes things clearer for both ends
  1593.                 if (in_array($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))),$testlinks[$parent->name]['links']))
  1594.                     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');
  1595.                 if ($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))) == $kid)
  1596.                 {
  1597.                     addWarning(PDERROR_CHILD_TUTORIAL_NOT_FOUND$child '.' $parent->tutorial_type$parent->name .'.ini',$parent->package$parent->subpackage);
  1598.                 }
  1599.             }
  1600.         }
  1601.         $new $tree $roots = array();
  1602.         // build a list of all 'root' tutorials (tutorials without parents).
  1603.         foreach($parents as $i => $parent)
  1604.         {
  1605.             if ($parent->isChildOf($parents)) {
  1606.                 $roots[$parent;
  1607.             }
  1608.         }
  1609.         $parents $roots;
  1610.         // add the parents and all child tutorials in order to the list of tutorials to process
  1611.         foreach($parents as $parent)
  1612.         {
  1613.             $this->generateTutorialOrder($parent,$all,$new);
  1614.         }
  1615.         if (count($all))
  1616.         {
  1617.             // add the leftover tutorials
  1618.             foreach($all as $package => $els)
  1619.             {
  1620.                 foreach($els as $subpackage => $els2)
  1621.                 {
  1622.                     foreach($els2 as $type => $tutorials)
  1623.                     {
  1624.                         foreach($tutorials as $tutorial)
  1625.                         {
  1626.                             $new[$package][$subpackage][$type][$tutorial;
  1627.                         }
  1628.                     }
  1629.                 }
  1630.             }
  1631.         }
  1632.         // remove the old, unprocessed tutorials, and set it up with the next code
  1633.         $this->tutorials = array();
  1634.         // reset integrity of the tutorial list
  1635.         $prev = false;
  1636.         uksort($new'tutorialcmp');
  1637. //        debug($this->vardump_tree($new));exit;
  1638.         foreach($new as $package => $els)
  1639.         {
  1640.             foreach($els as $subpackage => $els2)
  1641.             {
  1642.                 foreach($els2 as $type => $tutorials)
  1643.                 {
  1644.                     foreach($tutorials as $tutorial)
  1645.                     {
  1646.                         if ($prev)
  1647.                         {
  1648.                             $this->tutorials[$prevpackage][$prevsubpackage][$prevtype][$prevname]->setNext($tutorial,$this);
  1649.                             $tutorial->setPrev($prev,$this);
  1650.                         }
  1651.                         $this->tutorials[$package][$subpackage][$type][$tutorial->name$tutorial;
  1652.                         $prev $tutorial->getLink($this,true);
  1653.                         $prevpackage $package;
  1654.                         $prevsubpackage $subpackage;
  1655.                         $prevtype $type;
  1656.                         $prevname $tutorial->name;
  1657.                     }
  1658.                 }
  1659.             }
  1660.         }
  1661.         $this->tutorial_tree $this->_setupTutorialTree();
  1662.         return $new;
  1663.     }
  1664.  
  1665.     /**
  1666.     * called by {@link phpDocumentor_IntermediateParser::Convert()} to traverse
  1667.     * the array of pages and their elements, converting them to the output format
  1668.     *
  1669.     * The walk() method should be flexible enough such that it never needs
  1670.     * modification.  walk() sets up all of the indexes, and sorts everything in
  1671.     * logical alphabetical order.  It then passes each element individually to
  1672.     * {@link Convert()}, which then passes to the Convert*() methods.  A child
  1673.     * Converter need not override any of these unless special functionality must
  1674.     * be added. see {@tutorial Converters/template.vars.cls} for details.
  1675.     * {@internal 
  1676.     * walk() first creates all of the indexes {@link $elements, $pkg_elements}
  1677.     * and the left indexes specified by {@link $leftindexes},
  1678.     * and then sorts them by calling {@link sortIndexes()}.
  1679.     *
  1680.     * Next, it converts all README/CHANGELOG/INSTALL-style files, using
  1681.     * {@link Convert_RIC}.
  1682.     *
  1683.     * After this, it
  1684.     * passes all package-level docs to Convert().  Then, it calls the index
  1685.     * sorting functions {@link formatPkgIndex(), formatIndex()} and
  1686.     * {@link formatLeftIndex()}.
  1687.     *
  1688.     * Finally, it converts each procedural page in alphabetical order.  This
  1689.     * stage passes elements from the physical file to Convert() in alphabetical
  1690.     * order.  First, procedural page elements {@link parserDefine, parserInclude}
  1691.     * {@link parserGlobal}, and {@link parserFunction} are passed to Convert().
  1692.     *
  1693.     * Then, class elements are passed in this order: {@link parserClass}, then
  1694.     * all of the {@link parserVar}s in the class and all of the
  1695.     * {@link parserMethod}s in the class.  Classes are in alphabetical order,
  1696.     * and both vars and methods are in alphabetical order.
  1697.     *
  1698.     * Finally, {@link ConvertErrorLog()} is called and the data walk is complete.}}}
  1699.     * @param array Format: array(fullpath => {@link parserData} structure with full {@link parserData::$elements}
  1700.     *                                          and {@link parserData::$class_elements}.
  1701.     * @param array Format: array({@link parserPackagePage} 1, {@link parserPackagePage} 2,...)
  1702.     * @uses Converter::_createPkgElements() sets up {@link $elements} and
  1703.     *        {@link $pkg_elements} array, as well as {@link $links}
  1704.     */
  1705.     function walk(&$pages,&$package_pages)
  1706.     {
  1707.         if (empty($pages))
  1708.         {
  1709.             die("<b>ERROR</b>: nothing parsed");
  1710.         }
  1711.         $this->_createPkgElements($pages);
  1712.         if (count($this->ric))
  1713.         {
  1714.             phpDocumentor_out("Converting README/INSTALL/CHANGELOG contents...\n");
  1715.             flush();
  1716.             foreach($this->ric as $name => $contents)
  1717.             {
  1718.                 phpDocumentor_out("$name...");
  1719.                 flush();
  1720.                 $this->Convert_RIC($name,$contents);
  1721.             }
  1722.             phpDocumentor_out("\ndone\n");
  1723.             flush();
  1724.         }
  1725.         foreach($package_pages as $i => $perp)
  1726.         {
  1727.             if ($this->package_output)
  1728.             {
  1729.                 if (!in_array($package_pages[$i]->package,$this->package_output)) continue;
  1730.             }
  1731.             phpDocumentor_out('Converting package page for package '.$package_pages[$i]->package.'... ');
  1732.             flush();
  1733.             $this->package = $package_pages[$i]->package;
  1734.             $this->subpackage = '';
  1735.             $this->class = false;
  1736.             $this->Convert($package_pages[$i]);
  1737.             phpDocumentor_out("done\n");
  1738.             flush();
  1739.         }
  1740.         phpDocumentor_out("Converting tutorials/extended docs\n");
  1741.         flush();
  1742.         // get tutorials into the order they will display, and set next/prev links
  1743.         $new $this->_processTutorials();
  1744.         foreach($this->tutorials as $package => $els)
  1745.         {
  1746.             foreach($els as $subpackage => $els2)
  1747.             {
  1748.                 foreach($els2 as $type => $tutorials)
  1749.                 {
  1750.                     foreach($tutorials as $tutorial)
  1751.                     {
  1752.                         switch ($type)
  1753.                         {
  1754.                             case 'pkg' :
  1755.                                 $a '';
  1756.                                 if ($tutorial->ini)
  1757.                                 $a .= 'Top-level ';
  1758.                                 if (!empty($tutorial->subpackage))
  1759.                                 $a .= 'Sub-';
  1760.                                 $ptext = "Converting ${a}Package-level tutorial ".$tutorial->name.'...';
  1761.                             break;
  1762.                             case 'cls' :
  1763.                                 $a '';
  1764.                                 if ($tutorial->ini)
  1765.                                 $a .= 'Top-level ';
  1766.                                 $ptext = "Converting ${a}Class-level tutorial " . $tutorial->name ." and associating...";
  1767.                                 $link Converter::getClassLink(str_replace('.cls','',$tutorial->name)$tutorial->package);
  1768.                                 if (is_object($link))
  1769.                                 {
  1770.                                     if ($this->sort_absolutely_everything)
  1771.                                     {
  1772.                                         $addend 'unsuccessful ';
  1773.                                         if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name]))
  1774.                                         {
  1775.                                             $this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name][0]->addTutorial($tutorial,$this);
  1776.                                             $addend 'success ';
  1777.                                         }
  1778.                                     else
  1779.                                     {
  1780.                                         $addend 'unsuccessful ';
  1781.                                         if (!isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)]&& !isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)][$tutorial->path]))
  1782.                                         {
  1783.                                             foreach($pages as $j => $inf)
  1784.                                             {
  1785.                                                 foreach($inf->classelements as $i => $class)
  1786.                                                 {
  1787.                                                     if ($class->type == 'class' && $class->name == str_replace('.cls','',$tutorial->name&& $class->path == $link->path)
  1788.                                                     {
  1789.                                                         $pages[$j]->classelements[$i]->addTutorial($tutorial,$this);
  1790.                                                         $addend 'success ';
  1791.                                                     }
  1792.                                                 }
  1793.                                             }
  1794.                                         }
  1795.                                     }
  1796.                                     $ptext .= $addend;
  1797.                                 else $ptext .= "unsuccessful ";
  1798.                             break;
  1799.                             case 'proc' :
  1800.                                 $a '';
  1801.                                 if ($tutorial->ini)
  1802.                                 $a .= 'Top-level ';
  1803.                                 $ptext = "Converting ${a}Procedural-level tutorial ".$tutorial->name." and associating...";
  1804.                                 $link Converter::getPageLink(str_replace('.proc','',$tutorial->name)$tutorial->package);
  1805.                                 if (is_object($link))
  1806.                                 {
  1807.                                     $addend 'unsuccessful ';
  1808.                                     if ($this->sort_absolutely_everything)
  1809.                                     {
  1810.                                         if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path]))
  1811.                                         {
  1812.                                             $this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path][0]->addTutorial($tutorial,$this);
  1813.                                             $addend "success ";
  1814.                                         }
  1815.                                     else
  1816.                                     {
  1817.                                         foreach($pages as $j => $info)
  1818.                                         {
  1819.                                             if ($j == $link->path)
  1820.                                             {
  1821.                                                 $pages[$j]->addTutorial($tutorial,$this);
  1822.                                                 $addend "success ";
  1823.                                             }
  1824.                                         }
  1825.                                     }
  1826.                                     $ptext .= $addend;
  1827.                                 else $ptext .= "unsuccessful ";
  1828.                             break;
  1829.                         }
  1830.                         phpDocumentor_out($ptext);
  1831.                         flush();
  1832.                         $this->package = $tutorial->package;
  1833.                         $this->subpackage = $tutorial->subpackage;
  1834.                         $this->Convert($tutorial);
  1835.                         phpDocumentor_out("done\n");
  1836.                         flush();
  1837.                     }
  1838.                 }
  1839.             }
  1840.         }
  1841.         phpDocumentor_out("Formatting Package Indexes...");
  1842.         flush();
  1843.         $this->formatPkgIndex();
  1844.         phpDocumentor_out("done\n");
  1845.         flush();
  1846.         phpDocumentor_out("Formatting Index...");
  1847.         flush();
  1848.         $this->formatIndex();
  1849.         phpDocumentor_out("done\n\n");
  1850.         flush();
  1851.         phpDocumentor_out("Formatting Left Quick Index...");
  1852.         flush();
  1853.         $this->formatLeftIndex();
  1854.         phpDocumentor_out("done\n\n");
  1855.         flush();
  1856.         if ($this->sort_absolutely_everythingreturn $this->walk_everything();
  1857.         foreach($pages as $j => $flub)
  1858.         {
  1859.             phpDocumentor_out('Converting '.$pages[$j]->parent->getPath());
  1860.             flush();
  1861.             $this->package = $pages[$j]->parent->package;
  1862.             $this->subpackage = $pages[$j]->parent->subpackage;
  1863.             $this->class = false;
  1864.             $this->curfile = $pages[$j]->parent->getFile();
  1865.             $this->curname $this->getPageName($pages[$j]->parent);
  1866.             $this->curpath $pages[$j]->parent->getPath();
  1867.             $use = true;
  1868.             if ($this->package_output)
  1869.             {
  1870.                 if (in_array($this->package,$this->package_output))
  1871.                 {
  1872.                     $this->Convert($pages[$j]);
  1873.                 else
  1874.                 {
  1875.                     $use = false;
  1876.                 }
  1877.             else
  1878.             {
  1879.                 $this->Convert($pages[$j]);
  1880.             }
  1881.             phpDocumentor_out(" Procedural Page Elements...");
  1882.             flush();
  1883.             if ($use)
  1884.             for($i=0; $i<count($pages[$j]->elements)$i++)
  1885.             {
  1886.                 $a $pages[$j]->elements[$i]->docblock->getKeyword('access');
  1887.                 if (is_object($a)) $a $a->getString();
  1888.                 if (!$this->parseprivate && ($a == 'private'))
  1889.                     continue;
  1890. //                phpDocumentor_out("    ".$pages[$j]->elements[$i]->name."\n");
  1891.                 $pages[$j]->elements[$i]->docblock->package = $this->package;
  1892.                 $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage;
  1893.                 $this->Convert($pages[$j]->elements[$i]);
  1894.             }
  1895.             phpDocumentor_out(" Classes...");
  1896.             $this->class = false;
  1897.             flush();
  1898.             for($i=0; $i<count($pages[$j]->classelements)$i++)
  1899.             {
  1900.                 if ($this->class)
  1901.                 {
  1902.                     if ($pages[$j]->classelements[$i]->type == 'class')
  1903.                     {
  1904.                         if (!$this->killclass$this->endClass();
  1905.                         $this->killclass = false;
  1906.                         if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1907.                         $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1908.                         if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1909.                         $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1910.                         $this->class = $pages[$j]->classelements[$i]->name;
  1911.                     else
  1912.                     {
  1913.                         $a $pages[$j]->classelements[$i]->docblock->getKeyword('access');
  1914.                         if (is_object($a)) $a $a->getString();
  1915.                         if (!$this->parseprivate && ($a == 'private'))
  1916.                             continue;
  1917.                         if ($this->killclasscontinue;
  1918.                         // force all contained elements to have parent package/subpackage
  1919.                         $pages[$j]->classelements[$i]->docblock->package = $this->package;
  1920.                         $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage;
  1921.                     }
  1922.                 }
  1923.                 if ($pages[$j]->classelements[$i]->type == 'class')
  1924.                 {
  1925.                     $this->killclass = false;
  1926.                     if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1927.                     $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1928.                     if ($this->package_outputif (!in_array($this->package,$this->package_output)) continue;
  1929.                     $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1930.                     $this->class = $pages[$j]->classelements[$i]->name;
  1931.                 }
  1932.                 if ($this->killclasscontinue;
  1933. //                phpDocumentor_out("    ".$pages[$j]->classelements[$i]->name."\n");
  1934.                 $this->Convert($pages[$j]->classelements[$i]);
  1935.             }
  1936.             if (count($pages[$j]->classelements&& !$this->killclass$this->endClass();
  1937.             phpDocumentor_out(" done\n");
  1938.             flush();
  1939.             $this->endPage();
  1940.         }
  1941.         phpDocumentor_out("\nConverting @todo List...");
  1942.         flush();
  1943.         if (count($this->todoList))
  1944.         {
  1945.             $this->ConvertTodoList();
  1946.         }
  1947.         phpDocumentor_out("done\n");
  1948.         flush();
  1949.         phpDocumentor_out("\nConverting Error Log...");
  1950.         flush();
  1951.         $this->ConvertErrorLog();
  1952.         phpDocumentor_out("done\n");
  1953.         flush();
  1954.     }
  1955.  
  1956.  
  1957.     /**
  1958.      * Get a tree structure representing the hierarchy of tutorials
  1959.      *
  1960.      * Returns an array in format:
  1961.      * <pre>
  1962.      * array('tutorial' => {@link parserTutorial},
  1963.      *       'kids' => array( // child tutorials
  1964.      *                   array('tutorial' => child {@link parserTutorial},
  1965.      *                         'kids' => array(...)
  1966.      *                        )
  1967.      *                      )
  1968.      *      )
  1969.      * </pre>
  1970.      * @param parserTutorial|array
  1971.      * @tutorial tutorials.pkg
  1972.      * @return array 
  1973.      */
  1974.     function getTutorialTree($tutorial)
  1975.     {
  1976.         if (is_object($tutorial))
  1977.         {
  1978.             $path $this->_tutorial_path($tutorial,$tutorial,$tutorial);
  1979.             if (isset($this->tutorial_tree[$path])) {
  1980.                 $tutorial $this->tutorial_tree[$path];
  1981.             else {
  1982.                 return false;
  1983.             }
  1984.         }
  1985.         $tree = array();
  1986.         if (isset($tutorial['tutorial']))
  1987.         {
  1988.             $tree['tutorial'$tutorial['tutorial'];
  1989.             if (isset($tutorial['child']))
  1990.             {
  1991.                 foreach($tutorial['child'as $a => $b)
  1992.                 {
  1993.                     $btut $b['tutorial'];
  1994.                     $res['tutorial'$this->tutorials[$btut->package][$btut->subpackage][$btut->tutorial_type][$btut->name];
  1995.                     if (isset($b['child']))
  1996.                     {
  1997.                          $tempres Converter::getTutorialTree($b);
  1998.                          $res['kids'$tempres['kids'];
  1999.                     }
  2000.                     $tree['kids'][$res;
  2001.                 }
  2002.             }
  2003.         }
  2004.         return $tree;
  2005.     }
  2006.  
  2007.     /**
  2008.      * Remove tutorials one by one from $all, and transfer them into $new in the
  2009.      * order they should be parsed
  2010.      * @param parserTutorial 
  2011.      * @param array 
  2012.      * @param array 
  2013.      * @access private
  2014.      */
  2015.     function generateTutorialOrder($parent,&$all,&$new)
  2016.     {
  2017.         // remove from the list of tutorials to process
  2018.         foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_typeas $ind => $t)
  2019.         {
  2020.             if ($t->name == $parent->name{
  2021.                 unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
  2022.             }
  2023.         }
  2024.         // add to the new ordered list of tutorials
  2025.         $x &$new[$parent->package][$parent->subpackage][$parent->tutorial_type];
  2026.         if (!is_object($x[count($x- 1]|| $x[count($x- 1]->name != $parent->name)
  2027.         // only add if the parent isn't also a child
  2028.             $new[$parent->package][$parent->subpackage][$parent->tutorial_type][$parent;
  2029.             // add a new branch to the tree
  2030.         }
  2031.         // process all child tutorials, and insert them in order
  2032. //        debug("processing parent ".$parent->name);
  2033.         if ($parent->ini)
  2034.         {
  2035.             foreach($parent->ini['Linked Tutorials'as $child)
  2036.             {
  2037.                 $sub (empty($parent->subpackage'' $parent->subpackage . '/');
  2038.                 $kid $parent->package . '/' $sub $child '.' $parent->tutorial_type;
  2039.                 $_klink $this->getTutorialLink($kid,false,false,array($parent->package));
  2040.                 if (is_object($_klink)) {
  2041.                     $klink $this->returnSee($_klink);
  2042.                 else {
  2043.                     $klink = false;
  2044.                 }
  2045.                 // remove the child from the list of remaining tutorials
  2046.                 foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_typeas $ind => $tute)
  2047.                 {
  2048.                     if ($klink && $tute->getLink($this== $klink)
  2049.                     {
  2050.                         // set up parent, next and prev links
  2051.                         $tute->setParent($parent$this);
  2052.                         // remove the child from the list of tutorials to process
  2053.                         foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_typeas $ind => $t)
  2054.                         {
  2055.                             if ($t->name == $tute->name)
  2056.                             unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
  2057.                         }
  2058.                         // add to the new ordered list of tutorials
  2059.                         $new[$parent->package][$parent->subpackage][$parent->tutorial_type][$tute;
  2060.                         if ($tute->ini)
  2061.                         {
  2062.                             // add all the child's child tutorials to the list
  2063.                             $this->generateTutorialOrder($tute,$all,$new);
  2064.                         }
  2065.                     }
  2066.                 }
  2067.             }
  2068.         }
  2069.         return;
  2070.     }
  2071.  
  2072.         /** Returns the path to this tutorial as a string
  2073.          * @param parserTutorial $pkg 
  2074.          * @param parserTutorial $subpkg 
  2075.          * @param parserTutorial $namepkg 
  2076.          * @return string */
  2077.         function _tutorial_path($pkg$subpkg = 0$namepkg = 0)
  2078.         {
  2079.             if (!$subpkg{
  2080.                 $subpkg $pkg;
  2081.             }
  2082.             if (!$namepkg{
  2083.                 $namepkg $pkg;
  2084.             }
  2085.             $subpackagename ($subpkg->subpackage ? '/' $subpkg->subpackage : '');
  2086.             return $pkg->package . $subpackagename '/' $namepkg->name;
  2087.         }
  2088.  
  2089.  
  2090.     /**
  2091.      * Creates a tree structure of tutorials
  2092.      *
  2093.      * Format:
  2094.      * <pre>
  2095.      * array('package/subpackage/tutorial1.ext' =>
  2096.      *          array('tutorial' => {@link parserTutorial},
  2097.      *                'child'    =>
  2098.      *                    array('package/subpackage/child1tutorial.ext' => ...,
  2099.      *                          'package/subpackage/child2tutorial.ext' => ...,
  2100.      *                          ...
  2101.      *                         )
  2102.      *       'package/subpackage/tutorial2.ext' => ...,
  2103.      *       ...
  2104.      *       )
  2105.      * </pre>
  2106.      * @return array the tutorial tree
  2107.      * @access private
  2108.      */
  2109.     function _setupTutorialTree($parent = false)
  2110.     {
  2111.         if (isset($this->processed_tutorials)) {
  2112.             $this->processed_tutorials = array();
  2113.         }
  2114.         $tree = array();
  2115.         if (!$parent)
  2116.         {
  2117.             foreach($this->tutorials as $package => $s)
  2118.             {
  2119.                 foreach($s as $subpackage => $t)
  2120.                 {
  2121.                     foreach($t as $type => $n)
  2122.                     {
  2123.                         foreach($n as $name => $tutorial)
  2124.                         {
  2125.                             if ($tutorial->parent{
  2126.                                 continue;
  2127.                             }
  2128.                             
  2129.                             $child_path $this->_tutorial_path($tutorial,$tutorial,$tutorial);
  2130.                             if (isset($this->processed_tutorials[$child_path])) {
  2131.                                 continue;
  2132.                             }
  2133.                             $this->processed_tutorials[$child_path$tutorial;
  2134.                             //debug("parent ".$tutorial->name);
  2135.                             $ret $this->_setupTutorialTree($tutorial);
  2136.                             if (!count($tree)) {
  2137.                                 $tree $ret;
  2138.                             else {
  2139.                                 $tree array_merge($tree,$ret);
  2140.                             }
  2141.                         }
  2142.                     }
  2143.                 }
  2144.             }
  2145.             return $tree;
  2146.         }
  2147.         $parent_path $this->_tutorial_path($parent);
  2148.         $tree[$parent_path]['tutorial'$parent;
  2149.         // process all child tutorials, and insert them in order
  2150.         if ($parent->ini)
  2151.         {
  2152.             foreach($parent->ini['Linked Tutorials'as $child)
  2153.             {
  2154.                 if (isset($this->tutorials[$parent->package][$parent->subpackage]
  2155.                                           [$parent->tutorial_type][$child '.' .
  2156.                                            $parent->tutorial_type])) {
  2157.                     // remove the child from the list of remaining tutorials
  2158.                     $tute $this->tutorials[$parent->package][$parent->subpackage]
  2159.                                             [$parent->tutorial_type][$child '.' .
  2160.                                              $parent->tutorial_type];
  2161.                 else {
  2162.                     $tute = false;
  2163.                 }
  2164.  
  2165.                 if (!$tute{
  2166.                     continue;
  2167.                 }
  2168.                 $child_path $this->_tutorial_path($parent,$parent,$tute);
  2169.                 if (isset($this->processed_tutorials[$child_path])) {
  2170.                     continue;
  2171.                 }
  2172.                 $this->processed_tutorials[$child_path$tute;
  2173.                 if ($tute->name != $child '.' $parent->tutorial_type{
  2174.                     continue;
  2175.                 }
  2176.                 //echo "Adding [$child_path] to [$parent_path]<br>";
  2177.                 $tree[$parent_path]['child'][$this->_tutorial_path($parent,$parent,$tute)]['tutorial']
  2178.                     = $tute;
  2179.                 if (!$tute->ini{
  2180.                     continue;
  2181.                 }
  2182.                 // add all the child's child tutorials to the list
  2183.                 if (!isset($tree[$parent_path]['child'])) {
  2184.                     $tree[$parent_path]['child'$this->_setupTutorialTree($tute);
  2185.                 else {
  2186.                     $tree[$parent_path]['child'array_merge($tree[$parent_path]['child'],
  2187.                         $this->_setupTutorialTree($tute));
  2188.                 }
  2189.             }
  2190.         }
  2191.         return $tree;
  2192.     }
  2193.  
  2194.     /**
  2195.      * Debugging function for dumping {@link $tutorial_tree}
  2196.      * @return string 
  2197.      */
  2198.     function vardump_tree($tree,$indent='')
  2199.     {
  2200.         if (phpDocumentor_get_class($tree== 'parsertutorial'return $tree->name.' extends '.($tree->parent? $tree->parent->name : 'nothing');
  2201.         $a '';
  2202.         foreach($tree as $ind => $stuff)
  2203.         {
  2204.             $x $this->vardump_tree($stuff,"$indent   ");
  2205.             $a .= $indent.'['.$ind." => \n   ".$indent.$x."]\n";
  2206.         }
  2207.         return substr($a,0,strlen($a- 1);
  2208.     }
  2209.  
  2210.     /**
  2211.      * @access private
  2212.      */
  2213.     function sort_package_elements($a,$b)
  2214.     {
  2215.         if (($a->type == $b->type&& (isset($a->isConstructor&& $a->isConstructor)) return -1;
  2216.         if (($a->type == $b->type&& (isset($b->isConstructor&& $b->isConstructor)) return 1;
  2217.         if ($a->type == $b->typereturn strnatcasecmp($a->name,$b->name);
  2218.         if ($a->type == 'class'return -1;
  2219.         if ($b->type == 'class'return 1;
  2220.         if ($a->type == 'const'return -1;
  2221.         if ($b->type == 'const'return 1;
  2222.         if ($a->type == 'var'return -1;
  2223.         if ($b->type == 'var'return 1;
  2224.         if ($a->type == 'page'return -1;
  2225.         if ($b->type == 'page'return 1;
  2226.         if ($a->type == 'include'return -1;
  2227.         if ($b->type == 'include'return 1;
  2228.         if ($a->type == 'define'return -1;
  2229.         if ($b->type == 'define'return 1;
  2230.         if ($a->type == 'global'return -1;
  2231.         if ($b->type == 'global'return 1;
  2232.         if ($a->type == 'function'return -1;
  2233.         if ($b->type == 'function'return 1;
  2234.     }
  2235.  
  2236.     /**
  2237.      * @access private
  2238.      */
  2239.     function defpackagesort($a,$b)
  2240.     {
  2241.         if ($a == $GLOBALS['phpDocumentor_DefaultPackageName']return -1;
  2242.         if ($b == $GLOBALS['phpDocumentor_DefaultPackageName']return 0;
  2243.         return strnatcasecmp($a,$b);
  2244.     }
  2245.  
  2246.     /**
  2247.      * @access private
  2248.      */
  2249.     function Pc_sort($a,$b)
  2250.     {
  2251.         return strnatcasecmp(key($a),key($b));
  2252.     }
  2253.  
  2254.     /**
  2255.      * walk over elements by package rather than page
  2256.      *
  2257.      * This method is designed for converters like the PDF converter that need
  2258.      * everything passed in alphabetical order by package/subpackage and by
  2259.      * procedural and then class information
  2260.      * @see PDFdefaultConverter
  2261.      * @see walk()
  2262.      */
  2263.     function walk_everything()
  2264.     {
  2265.         global $hooser;
  2266.         $hooser = false;
  2267.         uksort($this->package_elements,array($this,'defpackagesort'));
  2268.         foreach($this->package_elements as $package => $r)
  2269.         {
  2270.             if ($this->package_output)
  2271.             {
  2272.                 if (!in_array($this->package,$this->package_output))
  2273.                 {
  2274.                     unset($this->package_elements[$package]);
  2275.                     continue;
  2276.                 }
  2277.             }
  2278.             uksort($this->package_elements[$package],'strnatcasecmp');
  2279.         }
  2280.         foreach($this->package_elements as $package => $r)
  2281.         {
  2282.             foreach($this->package_elements[$packageas $subpackage => $r)
  2283.             {
  2284.                 if (isset($r['page']))
  2285.                 {
  2286.                     uksort($r['page'],'strnatcasecmp');
  2287.                     foreach($r['page'as $page => $oo)
  2288.                     {
  2289.                         usort($this->package_elements[$package][$subpackage]['page'][$page],array($this,'sort_package_elements'));
  2290.                     }
  2291.                 }
  2292.                 if (isset($r['class']))
  2293.                 {
  2294.                     uksort($r['class'],'strnatcasecmp');
  2295.                     foreach($r['class'as $page => $oo)
  2296.                     {
  2297.                         usort($r['class'][$page],array($this,'sort_package_elements'));
  2298.                     }
  2299.                 }
  2300.                 $this->package_elements[$package][$subpackage$r;
  2301.             }
  2302.         }
  2303.         foreach($this->package_elements as $package => $s)
  2304.         {
  2305.             $notyet = false;
  2306.             foreach($s as $subpackage => $r)
  2307.             {
  2308.                 $this->package = $package;
  2309.                 $this->subpackage = $subpackage;
  2310.                 if (isset($r['page']))
  2311.                 {
  2312.                     $this->class = false;
  2313.                     foreach($r['page'as $page => $elements)
  2314.                     {
  2315.                         if (is_array($elements))
  2316.                         {
  2317.                             foreach($elements as $element)
  2318.                             {
  2319.                                 if ($element->type == 'page')
  2320.                                 {
  2321.                                     phpDocumentor_out('Converting '.$element->parent->getPath());
  2322.                                     flush();
  2323.                                     $this->curfile = $element->parent->getFile();
  2324.                                     $this->curname $this->getPageName($element->parent);
  2325.                                     $this->curpath $element->parent->getPath();
  2326.                                     $notyet = true;
  2327.                                 else
  2328.                                 {
  2329.                                     // force all contained elements to have parent package/subpackage
  2330.                                     $element->docblock->package = $this->package;
  2331.                                     $element->docblock->subpackage = $this->subpackage;
  2332.                                     $a $element->docblock->getKeyword('access');
  2333.                                     if (is_object($a)) $a $a->getString();
  2334.                                     if (!$this->parseprivate && ($a == 'private'))
  2335.                                         continue;
  2336.                                 }
  2337.                                 if ($notyet)
  2338.                                 {
  2339.                                     phpDocumentor_out(" Procedural Page Elements...");
  2340.                                     flush();
  2341.                                     $notyet = false;
  2342.                                 }
  2343.                                 $this->Convert($element);
  2344.                             }
  2345.                         }
  2346.                         $this->endPage();
  2347.                         phpDocumentor_out("done\n");
  2348.                         flush();
  2349.                     }
  2350.                 }
  2351.                 $start_classes = true;
  2352.                 if (isset($r['class']))
  2353.                 {
  2354.                     foreach($r['class'as $class => $elements)
  2355.                     {
  2356.                         foreach($elements as $element)
  2357.                         {
  2358.                             if ($element->type == 'class')
  2359.                             {
  2360.                                 if (!$start_classes)
  2361.                                 {
  2362.                                     if (count($elements&& !$this->killclass$this->endClass();
  2363.                                     phpDocumentor_out("done\n");
  2364.                                     flush();
  2365.                                 }
  2366.                                 $start_classes = false;
  2367.                                 $this->class = $element->getName();
  2368.                                 $this->killclass = false;
  2369.                                 if ($this->checkKillClass($element->getName(),$element->getPath())) continue;
  2370.                                 if (!$this->killclass)
  2371.                                 {
  2372.                                     phpDocumentor_out('Converting '.$this->class."...");
  2373.                                     flush();
  2374.                                     $notyet = true;
  2375.                                 }
  2376.                             else
  2377.                             {
  2378.                                 if ($notyet)
  2379.                                 {
  2380.                                     phpDocumentor_out("Variables/methods/Class constants...\n");
  2381.                                     flush();
  2382.                                     $notyet = false;
  2383.                                 }
  2384.                                 $a $element->docblock->getKeyword('access');
  2385.                                 if (is_object($a)) $a $a->getString();
  2386.                                 if (!$this->parseprivate && ($a == 'private'))
  2387.                                     continue;
  2388.                                 if ($this->killclasscontinue;
  2389.                                 // force all contained elements to have parent package/subpackage
  2390.                                 $element->docblock->package = $this->package;
  2391.                                 $element->docblock->subpackage = $this->subpackage;
  2392.                             }
  2393.                             if ($this->killclasscontinue;
  2394.                             $this->Convert($element);
  2395.                         }
  2396.                     }
  2397.                     if (count($elements&& !$this->killclass$this->endClass();
  2398.                     phpDocumentor_out("done\n");
  2399.                     flush();
  2400.                 // if isset($r['class'])
  2401.             // foreach($s
  2402.         // foreach($this->package_elements)
  2403.         phpDocumentor_out("\nConverting @todo List...");
  2404.         flush();
  2405.         if (count($this->todoList))
  2406.         {
  2407.             $this->ConvertTodoList();
  2408.         }
  2409.         phpDocumentor_out("done\n");
  2410.         flush();
  2411.         phpDocumentor_out("\nConverting Error Log...");
  2412.         flush();
  2413.         $this->ConvertErrorLog();
  2414.         phpDocumentor_out("done\n");
  2415.         flush();
  2416.     }
  2417.  
  2418.     /**
  2419.      * Convert the phpDocumentor parsing/conversion error log
  2420.      * @abstract
  2421.      */
  2422.     function ConvertErrorLog()
  2423.     {
  2424.     }
  2425.  
  2426.     /**
  2427.      * Convert the list of all @todo tags
  2428.      * @abstract
  2429.      */
  2430.     function ConvertTodoList()
  2431.     {
  2432.     }
  2433.  
  2434.     /**
  2435.      * Sorts the @todo list - do not override or modify this function
  2436.      * @access private
  2437.      * @uses _sortTodos passed to {@link usort()} to sort the todo list
  2438.      */
  2439.     function sortTodos()
  2440.     {
  2441.         phpDocumentor_out("\nSorting @todo list...");
  2442.         flush();
  2443.         foreach($this->todoList as $package => $r{
  2444.             usort($this->todoList[$package]array('Converter''_sortTodoPackage'));
  2445.             foreach ($r as $a => $sub{
  2446.                 if (is_array($this->todoList[$package][$a][1])) {
  2447.                     usort($this->todoList[$package][$a][1],array('Converter''_sortTodos'));
  2448.                 }
  2449.             }
  2450.         }
  2451.         phpDocumentor_out("done\n");
  2452.     }
  2453.  
  2454.     /** @access private */
  2455.     function _sortTodoPackage($a$b)
  2456.     {
  2457.         return strnatcasecmp($a[0]->name$b[0]->name);
  2458.     }
  2459.  
  2460.     /** @access private */
  2461.     function _sortTodos($a$b)
  2462.     {
  2463.         if (!is_object($a)) {
  2464.             var_dump($a);
  2465.         }
  2466.         return strnatcasecmp($a->getString()$b->getString());
  2467.     }
  2468.  
  2469.     /**
  2470.      * Sorts all indexes - do not override or modify this function
  2471.      * @uses $leftindex based on the value of leftindex, sorts link arrays
  2472.      * @uses $class_elements sorts with {@link compareLink}
  2473.      * @uses $page_elements sorts with {@link compareLink}
  2474.      * @uses $define_elements sorts with {@link compareLink}
  2475.      * @uses $global_elements sorts with {@link compareLink}
  2476.      * @uses $function_elements sorts with {@link compareLink}
  2477.      * @uses $elements sorts with {@link elementCmp}
  2478.      * @uses $pkg_elements sorts with {@link elementCmp} after sorting by
  2479.      *                      package/subpackage alphabetically
  2480.      * @access private
  2481.      */
  2482.     function sortIndexes()
  2483.     {
  2484.         phpDocumentor_out("\nSorting Indexes...");
  2485.         flush();
  2486.         uksort($this->elements,'strnatcasecmp');
  2487.         if ($this->leftindex['classes'])
  2488.         {
  2489.             foreach($this->class_elements as $package => $o1)
  2490.             {
  2491.                 foreach($o1 as $subpackage => $links)
  2492.                 {
  2493.                     usort($this->class_elements[$package][$subpackage],array($this,'compareLink'));
  2494.                 }
  2495.             }
  2496.         }
  2497.         if ($this->leftindex['pages'])
  2498.         {
  2499.             foreach($this->page_elements as $package => $o1)
  2500.             {
  2501.                 uksort($this->page_elements[$package],'strnatcasecmp');
  2502.                 foreach($o1 as $subpackage => $links)
  2503.                 {
  2504.                     usort($this->page_elements[$package][$subpackage],array($this,'compareLink'));
  2505.                 }
  2506.             }
  2507.         }
  2508.         if ($this->leftindex['defines'])
  2509.         {
  2510.             foreach($this->define_elements as $package => $o1)
  2511.             {
  2512.                 uksort($this->define_elements[$package],'strnatcasecmp');
  2513.                 foreach($o1 as $subpackage => $links)
  2514.                 {
  2515.                     usort($this->define_elements[$package][$subpackage],array($this,'compareLink'));
  2516.                 }
  2517.             }
  2518.         }
  2519.         if ($this->leftindex['globals'])
  2520.         {
  2521.             foreach($this->global_elements as $package => $o1)
  2522.             {
  2523.                 uksort($this->global_elements[$package],'strnatcasecmp');
  2524.                 foreach($o1 as $subpackage => $links)
  2525.                 {
  2526.                     usort($this->global_elements[$package][$subpackage],array($this,'compareLink'));
  2527.                 }
  2528.             }
  2529.         }
  2530.         if ($this->leftindex['functions'])
  2531.         {
  2532.             foreach($this->function_elements as $package => $o1)
  2533.             {
  2534.                 uksort($this->function_elements[$package],'strnatcasecmp');
  2535.                 foreach($o1 as $subpackage => $links)
  2536.                 {
  2537.                     usort($this->function_elements[$package][$subpackage],array($this,'compareLink'));
  2538.                 }
  2539.             }
  2540.         }
  2541.         foreach($this->elements as $letter => $nothuing)
  2542.         {
  2543.             uasort($this->elements[$letter],array($this,"elementCmp"));
  2544.         }
  2545.         foreach($this->pkg_elements as $package => $els)
  2546.         {
  2547.             uksort($this->pkg_elements[$package],'strnatcasecmp');
  2548.             foreach($this->pkg_elements[$packageas $subpackage => $els)
  2549.             {
  2550.                 if (empty($els)) continue;
  2551.                 uksort($this->pkg_elements[$package][$subpackage],'strnatcasecmp');
  2552.                 foreach($els as $letter => $yuh)
  2553.                 {
  2554.                     usort($this->pkg_elements[$package][$subpackage][$letter],array($this,"elementCmp"));
  2555.                 }
  2556.             }
  2557.         }
  2558.         phpDocumentor_out("done\n");
  2559.         flush();
  2560.     }
  2561.  
  2562.     /**
  2563.      * sorts {@link $page_contents} by element type as well as alphabetically
  2564.      * @see $sort_page_contents_by_element_type
  2565.      */
  2566.     function sortPageContentsByElementType(&$pages)
  2567.     {
  2568.         foreach($this->page_contents as $package => $els)
  2569.         {
  2570.             foreach($this->page_contents[$packageas $subpackage => $els)
  2571.             {
  2572.                 if (empty($els)) continue;
  2573.                 foreach($this->page_contents[$package][$subpackageas $path => $stuff)
  2574.                 {
  2575.                     if (!count($pages[$path]->elements)) continue;
  2576.                     usort($pages[$path]->elements,array($this,'eltypecmp'));
  2577.                     usort($this->page_contents[$package][$subpackage][$path],array($this,'eltypecmp'));
  2578.                     if (isset($this->page_contents[$package][$subpackage][$path][0]))
  2579.                     $this->page_contents[$package][$subpackage][$path]['###main'$this->page_contents[$package][$subpackage][$path][0];
  2580.                     unset($this->page_contents[$package][$subpackage][$path][0]);
  2581.                 }
  2582.             }
  2583.         }
  2584.     }
  2585.  
  2586.     /**
  2587.      * @access private
  2588.      * @see Converter::sortIndexes()
  2589.      */
  2590.     function compareLink($a$b)
  2591.     {
  2592.          return strnatcasecmp($a->name,$b->name);
  2593.     }
  2594.  
  2595.     /**
  2596.      * @access private
  2597.      * @see Converter::sortPageContentsByElementType()
  2598.      */
  2599.     function eltypecmp($a$b)
  2600.     {
  2601.         if ($a->type == 'page'return -1;
  2602.         if ($b->type == 'page'return 1;
  2603.          return strnatcasecmp($a->type.$a->name,$b->type.$b->name);
  2604.     }
  2605.  
  2606.     /**
  2607.      * does a nat case sort on the specified second level value of the array
  2608.      *
  2609.      * @param    mixed    $a 
  2610.      * @param    mixed    $b 
  2611.      * @return    int 
  2612.      * @access private
  2613.      */
  2614.     function elementCmp ($a$b)
  2615.     {
  2616.         return strnatcasecmp($a->getName()$b->getName());
  2617.     }
  2618.  
  2619.     /**
  2620.      * Used to stop conversion of @ignored or private @access classes
  2621.      * @uses $killclass sets killclass based on the value of {@link Classes::$killclass}
  2622.      *        and {@link $package_output}
  2623.      * @access private
  2624.      */
  2625.     function checkKillClass($class$path)
  2626.     {
  2627.         $this->killclass = false;
  2628.         if (isset($this->classes->killclass[$class]&& isset($this->classes->killclass[$class][$path])) $this->killclass = true;
  2629.         if ($this->package_output)
  2630.         {
  2631.             $a $this->classes->getClass($class$path);
  2632.             if (!in_array($a->docblock->package,$this->package_output)) $this->killclass = true;
  2633.         }
  2634.         if (PHPDOCUMENTOR_DEBUG && $this->killclassdebug("$class $path killed");
  2635.         return $this->killclass;
  2636.     }
  2637.  
  2638.     /**
  2639.      * @param abstractLink descendant of abstractLink
  2640.      * @param array|parserTaglist of @todos|@todo tag
  2641.      * @access private
  2642.      */
  2643.     function addTodoLink($link$todos)
  2644.     {
  2645.         $this->todoList[$link->package][= array($link$todos);
  2646.     }
  2647.  
  2648.     /**
  2649.      * Adds all elements to the {@link $elements, $pkg_elements, $links},
  2650.      * {@link $linkswithfile} and left indexes - Do not modify or override
  2651.      * @access private
  2652.      * @param parserBase any documentable element descendant of parserBase
  2653.      *                    except parserTutorial
  2654.      * @param false|parserPageonly used to add a {@link parserPage} if the
  2655.      *                          $element passed is a parserPage
  2656.      * @staticvar string path of current page, used for {@link $page_contents} setup
  2657.      */
  2658.     function addElement(&$element,$pageel=false)
  2659.     {
  2660.         static $curpath '';
  2661.         if ($this->package_output)
  2662.         {
  2663.             if (!in_array($this->package$this->package_output)) return;
  2664.         }
  2665.         if ($pageel && phpDocumentor_get_class($pageel== 'parserdata')
  2666.         {
  2667.             if (isset($pageel->docblock&& phpDocumentor_get_class($pageel->docblock== 'parserdocblock')
  2668.             {
  2669.                 $a $pageel->docblock->getKeyword('todo');
  2670.                 if ($a)
  2671.                 {
  2672.                     $this->addTodoLink($this->addLink($element),$a);
  2673.                 }
  2674.             }
  2675.         }
  2676.         if (isset($element->docblock))
  2677.         {
  2678.             $a $element->docblock->getKeyword('access');
  2679.             if (is_object($a)) $a $a->getString();
  2680.             if (!$this->parseprivate && ($a == 'private'))
  2681.                 return;
  2682.             $a $element->docblock->getKeyword('todo');
  2683.             if ($a)
  2684.             {
  2685.                 if ($element->type != 'include'{
  2686.                     $this->addTodoLink($this->addLink($element),$a);
  2687.                 else {
  2688.                     addWarning(PDERROR_NOTODO_INCLUDE$element->getLineNumber(),
  2689.                         $element->getPath());
  2690.                 }
  2691.             }
  2692.         }
  2693.         $startPositionOfElementName = 0;    // which character of the element name actually starts its textual name
  2694.         switch($element->type)
  2695.         {
  2696.             case 'page' :
  2697.                 if ($this->sort_absolutely_everything)
  2698.                 {
  2699.                     $this->package_elements[$element->package][$element->subpackage]['page'][$element->getPath()][$pageel;
  2700.                 }
  2701.                 $link $this->addLink($element);
  2702.                 $curpath $element->getPath();
  2703.                 if ($this->leftindex['pages'])
  2704.                 $this->page_elements[$element->package][$element->subpackage][$link;
  2705.                 $this->page_contents[$element->package][$element->subpackage][$curpath]['###main'$link;
  2706.             break;
  2707.             case 'class' :
  2708.                 if ($this->sort_absolutely_everything)
  2709.                 {
  2710.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2711.                 }
  2712.                 $link $this->addLink($element);
  2713.                 if ($this->leftindex['classes'])
  2714.                 $this->class_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2715.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class]['###main'$link;
  2716.             break;
  2717.             case 'include' :
  2718.                 if ($this->sort_absolutely_everything)
  2719.                 {
  2720.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2721.                 }
  2722.                 $link $this->addLink($element);
  2723.             break;
  2724.             case 'define' :
  2725.                 if ($this->sort_absolutely_everything)
  2726.                 {
  2727.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2728.                 }
  2729.                 $link $this->addLink($element);
  2730.                 if ($this->leftindex['defines'])
  2731.                 $this->define_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2732.                 $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][$link;
  2733.             break;
  2734.             case 'global' :
  2735.                 if ($this->sort_absolutely_everything)
  2736.                 {
  2737.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2738.                 }
  2739.                 $link $this->addLink($element);
  2740.                 $startPositionOfElementName = 1;    // lose the leading "$" character
  2741.                 if ($this->leftindex['globals'])
  2742.                 $this->global_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2743.                 $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][$link;
  2744.             break;
  2745.             case 'var' :
  2746.                 if ($this->sort_absolutely_everything)
  2747.                 {
  2748.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2749.                 }
  2750.                 $link $this->addLink($element);
  2751.                 $startPositionOfElementName = 1;    // lose the leading "$" character
  2752.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][$link;
  2753.             break;
  2754.             case 'const' :
  2755.                 if ($this->sort_absolutely_everything)
  2756.                 {
  2757.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2758.                 }
  2759.                 $link $this->addLink($element);
  2760.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][$link;
  2761.             break;
  2762.             case 'method' :
  2763.                 if ($this->sort_absolutely_everything)
  2764.                 {
  2765.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][$element;
  2766.                 }
  2767.                 $link $this->addLink($element);
  2768.                 $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][$link;
  2769.             break;
  2770.             case 'function' :
  2771.                 if ($this->sort_absolutely_everything)
  2772.                 {
  2773.                     $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][$element;
  2774.                 }
  2775.                 $link $this->addLink($element);
  2776.                 if ($this->leftindex['functions'])
  2777.                 $this->function_elements[$element->docblock->package][$element->docblock->subpackage][$link;
  2778.                 $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][$link;
  2779.             break;
  2780.             default :
  2781.             break;
  2782.         }
  2783.         if ($element->getType(!= 'include')
  2784.         {
  2785.             if ($element->getType(== 'var' || $element->getType(== 'method'|| $element->getType(== 'const')
  2786.             {
  2787.                 $this->links[$this->package][$this->subpackage][$element->getType()][$element->class][$element->getName()$link;
  2788.                 $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->class][$element->getName()$link;
  2789.             else
  2790.             {
  2791.                 if ($element->type == 'page')
  2792.                 {
  2793.                     $this->links[$this->package][$this->subpackage][$element->getType()][$element->getFile()$link;
  2794.                     $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getFile()$link;
  2795.                 else
  2796.                 {
  2797.                     $this->links[$this->package][$this->subpackage][$element->getType()][$element->getName()$link;
  2798.                     $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getName()$link;
  2799.                 }
  2800.             }
  2801.         }
  2802.         if ($element->type == 'page')
  2803.         {
  2804.             $this->elements[substr(strtolower($element->getFile()),$startPositionOfElementName,1)][$element;
  2805.             $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getFile()),$startPositionOfElementName,1)][$element;
  2806.         else
  2807.         {
  2808.             $this->elements[substr(strtolower($element->getName()),$startPositionOfElementName,1)][$element;
  2809.             $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getName()),$startPositionOfElementName,1)][$element;
  2810.         }
  2811.     }
  2812.  
  2813.     /**
  2814.      * returns an abstract link to element.  Do not modify or override
  2815.      *
  2816.      * This method should only be called in process of Conversion, unless
  2817.      * $element is a parserPage, or $page is set to true, and $element is
  2818.      * not a parserPage
  2819.      * @return abstractLink abstractLink descendant
  2820.      * @access private
  2821.      * @param parserElement element to add a new link (descended from
  2822.      *                       {@link abstractLink})to the {@link $links} array
  2823.      * @param string classname for elements that are class-based (this may be
  2824.      *                deprecated in the future, as the classname
  2825.      *                should be contained within the element.  if $element is a
  2826.      *                page, this parameter is a package name
  2827.      * @param string subpackage name for page elements
  2828.      */
  2829.     function addLink(&$element,$page = false)
  2830.     {
  2831.         if ($page)
  2832.         {
  2833.             // create a fake parserPage to extract the fileAlias for this link
  2834.             $fakepage = new parserPage;
  2835.             $fakepage->setPath($element->getPath());
  2836.             $fakepage->setFile(basename($element->getPath()));
  2837.             $this->curname = $this->getPageName($fakepage);
  2838.         }
  2839.         switch($element->type)
  2840.         {
  2841.             case 'function':
  2842.                 $x = new functionLink;
  2843.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2844.                 return $x;
  2845.             break;
  2846.             case 'define':
  2847.                 $x = new defineLink;
  2848.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2849.                 return $x;
  2850.             break;
  2851.             case 'global':
  2852.                 $x = new globalLink;
  2853.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2854.                 return $x;
  2855.             break;
  2856.             case 'class':
  2857.                 $x = new classLink;
  2858.                 $x->addLink($element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2859.                 return $x;
  2860.             break;
  2861.             case 'method':
  2862.                 $x = new methodLink;
  2863.                 $x->addLink($this->class$element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2864.                 return $x;
  2865.             break;
  2866.             case 'var':
  2867.                 $x = new varLink;
  2868.                 $x->addLink($this->class$element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2869.                 return $x;
  2870.             break;
  2871.             case 'const':
  2872.                 $x = new constLink;
  2873.                 $x->addLink($this->class$element->getPath()$this->curname$element->name$element->docblock->package$element->docblock->subpackage$element->docblock->category);
  2874.                 return $x;
  2875.             break;
  2876.             case 'page':
  2877.                 $x = new pageLink;
  2878.                 $x->addLink($element->getPath(),$this->getPageName($element),$element->file,$element->package$element->subpackage$element->category);
  2879.                 return $x;
  2880.             break;
  2881.         }
  2882.     }
  2883.  
  2884.     /**
  2885.      * Return a tree of all classes that extend this class
  2886.      *
  2887.      * The data structure returned is designed for a non-recursive algorithm,
  2888.      * and is somewhat complex.
  2889.      * In most cases, the array returned is:
  2890.      *
  2891.      * <pre>
  2892.      * array('#root' =>
  2893.      *         array('link' => {@link classLink} to $class,
  2894.      *               'parent' => false,
  2895.      *               'children' => array(array('class' => 'childclass1',
  2896.      *                                         'package' => 'child1package'),
  2897.      *                                    array('class' => 'childclass2',
  2898.      *                                         'package' => 'child2package'),...
  2899.      *                                  )
  2900.      *               ),
  2901.      *       'child1package#childclass1' =>
  2902.      *         array('link' => {@link classLink} to childclass1,
  2903.      *               'parent' => '#root',
  2904.      *               'children' => array(array('class' => 'kidclass',
  2905.      *                                         'package' => 'kidpackage'),...
  2906.      *                                  )
  2907.      *              ),
  2908.      *       'kidpackage#kidclass' =>
  2909.      *         array('link' => {@link classLink} to kidclass,
  2910.      *               'parent' => 'child1package#childclass1',
  2911.      *               'children' => array() // no children
  2912.      *              ),
  2913.      *      ....
  2914.      *      )
  2915.      *</pre>
  2916.      *
  2917.      * To describe this format using language, every class in the tree has an
  2918.      * entry in the first level of the array.  The index for all child
  2919.      * classes that extend the root class is childpackage#childclassname.
  2920.      * Each entry in the array has 3 elements: link, parent, and children.
  2921.      * <ul>
  2922.      *  <li>link - a {@link classLink} to the current class</li>
  2923.      *  <li>parent - a {@link classLink} to the class's parent, or false (except for one special case described below)</li>
  2924.      *  <li>children - an array of arrays, each entry has a 'class' and 'package' index to the child class,
  2925.      * used to find the entry in the big array</li>
  2926.      * </ul>
  2927.      *
  2928.      * special cases are when the #root class has a parent in another package,
  2929.      * or when the #root class extends a class not found
  2930.      * by phpDocumentor.  In the first case, parent will be a
  2931.      * classLink to the parent class.  In the second, parent will be the
  2932.      * extends clause, as in:
  2933.      * <code>
  2934.      * class X extends Y
  2935.      * {
  2936.      * ...
  2937.      * }
  2938.      * </code>
  2939.      * in this case, the #root entry will be array('link' => classLink to X, 'parent' => 'Y', children => array(...))
  2940.      *
  2941.      * The fastest way to design a method to process the array returned
  2942.      * is to copy HTMLframesConverter::getRootTree() into
  2943.      * your converter and to modify the html to whatever output format you are going to use
  2944.      * @see HTMLframesConverter::getRootTree()
  2945.      * @param string class name
  2946.      * @param string 
  2947.      * @param string 
  2948.      * @return array Format: see docs
  2949.      */
  2950.     function getSortedClassTreeFromClass($class,$package,$subpackage)
  2951.     {
  2952.         $my_tree = array();
  2953.         $root $this->classes->getClassByPackage($class,$package);
  2954.         if (!$rootreturn false;
  2955.         $class_children $this->classes->getDefiniteChildren($class,$root->curfile);
  2956.         if (!$class_children)
  2957.         {
  2958.             // special case: parent class is found, but is not part of this package, class has no children
  2959.             if (is_array($root->parent))
  2960.             {
  2961.                 $x $root->getParent($this);
  2962.                 if ($x->docblock->package != $package)
  2963.                 {
  2964.                     $v Converter::getClassLink($root->getName(),$package,$root->getPath());
  2965.                     return array('#root' => array('link' => $v,'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath())'children' => array()));
  2966.                 }
  2967.             else
  2968.             // class has normal situation, no children
  2969.                 if (is_string($root->getParent($this)))
  2970.                 return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath())'parent' => $root->getExtends(),'children' => array()));
  2971.                 else
  2972.                 return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath())'parent' => false'children' => array()));
  2973.             }
  2974.         }
  2975.         // special case: parent class is found, but is not part of this package, class has children
  2976.         if (is_array($root->parent))
  2977.         {
  2978.             $x $root->getParent($this);
  2979.             if ($x->docblock->package != $package)
  2980.             {
  2981.                 $v Converter::getClassLink($root->getName(),$package,$root->getPath());
  2982.                 $my_tree = array('#root' => array('link' => $v'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath())'children' => array()));
  2983.             else
  2984.             {
  2985.             }
  2986.         else
  2987.         $my_tree = array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath())'parent' => false'children' => array()));
  2988.         // location of tree walker
  2989.         $cur '#root';
  2990.         $lastcur = array(array(false,0));
  2991.         $childpos = 0;
  2992.         if (isset($class_children))
  2993.         {
  2994.             do
  2995.             {
  2996.                 if (!$class_children)
  2997.                 {
  2998.                     list($cur$childposarray_pop($lastcur);
  2999.                     if (isset($my_tree[$cur]['children'][$childpos + 1]))
  3000.                     {
  3001.                         array_push($lastcurarray($cur$childpos + 1));
  3002.                         $par $cur;
  3003.                         $cur $my_tree[$cur]['children'][$childpos + 1];
  3004.                         $x $this->classes->getClassByPackage($cur['class'],$cur['package']);
  3005.                         $childpos = 0;
  3006.                         $cur $cur['package''#' $cur['class'];
  3007.                         $my_tree[$cur]['link'Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
  3008.                         $my_tree[$cur]['parent'$par;
  3009.                         $my_tree[$cur]['children'= array();
  3010.                         $class_children $this->classes->getDefiniteChildren($x->getName()$x->curfile);
  3011.                         continue;
  3012.                     else
  3013.                     {
  3014.                         $class_children = false;
  3015.                         continue;
  3016.                     }
  3017.                 }
  3018.                 foreach($class_children as $chileclass => $chilefile)
  3019.                 {
  3020.                     $ch $this->classes->getClass($chileclass,$chilefile);
  3021.                     $my_tree[$cur]['children'][= array('class' => $ch->getName()'package' => $ch->docblock->package);
  3022.                 }
  3023.                 usort($my_tree[$cur]['children'],'rootcmp');
  3024.                 if (isset($my_tree[$cur]['children'][$childpos]))
  3025.                 {
  3026.                     array_push($lastcurarray($cur$childpos));
  3027.                     $par $cur;
  3028.                     $cur $my_tree[$cur]['children'][$childpos];
  3029.                     $x $this->classes->getClassByPackage($cur['class'],$cur['package']);
  3030.                     $cur $cur['package''#' $cur['class'];
  3031.                     $my_tree[$cur]['link'Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
  3032.                     $my_tree[$cur]['parent'$par;
  3033.                     $my_tree[$cur]['children'= array();
  3034.                     $childpos = 0;
  3035.                     $class_children $this->classes->getDefiniteChildren($x->getName()$x->curfile);
  3036.                 else
  3037.                 {
  3038.                     list($cur$childposarray_pop($lastcur);
  3039.                 }
  3040.             while ($cur);
  3041.         }
  3042.         return $my_tree;
  3043.     }
  3044.  
  3045.     /**
  3046.      * do not override
  3047.      * @return bool true if a link to this class exists in package $package and subpackage $subpackage
  3048.      * @param string $expr class name
  3049.      * @param string $package package to search in
  3050.      * @param string $subpackage subpackage to search in
  3051.      * @access private
  3052.      */
  3053.     function isLinkedClass($expr,$package,$subpackage,$file=false)
  3054.     {
  3055.         if ($file)
  3056.         return isset($this->linkswithfile[$package][$subpackage]['class'][$file][$expr]);
  3057.         return isset($this->links[$package][$subpackage]['class'][$expr]);
  3058.     }
  3059.  
  3060.     /**
  3061.      * do not override
  3062.      * @return bool true if a link to this function exists in package $package and subpackage $subpackage
  3063.      * @param string $expr function name
  3064.      * @param string $package package to search in
  3065.      * @param string $subpackage subpackage to search in
  3066.      * @access private
  3067.      */
  3068.     function isLinkedFunction($expr,$package,$subpackage,$file=false)
  3069.     {
  3070.         if ($file)
  3071.         return isset($this->linkswithfile[$package][$subpackage]['function'][$file][$expr]);
  3072.         return isset($this->links[$package][$subpackage]['function'][$expr]);
  3073.     }
  3074.  
  3075.     /**
  3076.      * do not override
  3077.      * @return bool true if a link to this define exists in package $package and subpackage $subpackage
  3078.      * @param string $expr define name
  3079.      * @param string $package package to search in
  3080.      * @param string $subpackage subpackage to search in
  3081.      * @access private
  3082.      */
  3083.     function isLinkedDefine($expr,$package,$subpackage,$file=false)
  3084.     {
  3085.         if ($file)
  3086.         return isset($this->linkswithfile[$package][$subpackage]['define'][$file][$expr]);
  3087.         return isset($this->links[$package][$subpackage]['define'][$expr]);
  3088.     }
  3089.  
  3090.     /**
  3091.      * do not override
  3092.      * @return bool true if a link to this define exists in package $package and subpackage $subpackage
  3093.      * @param string $expr define name
  3094.      * @param string $package package to search in
  3095.      * @param string $subpackage subpackage to search in
  3096.      * @access private
  3097.      */
  3098.     function isLinkedGlobal($expr,$package,$subpackage,$file=false)
  3099.     {
  3100.         if ($file)
  3101.         return isset($this->linkswithfile[$package][$subpackage]['global'][$file][$expr]);
  3102.         return isset($this->links[$package][$subpackage]['global'][$expr]);
  3103.     }
  3104.  
  3105.     /**
  3106.      * do not override
  3107.      * @return bool true if a link to this procedural page exists in package $package and subpackage $subpackage
  3108.      * @param string $expr procedural page name
  3109.      * @param string $package package to search in
  3110.      * @param string $subpackage subpackage to search in
  3111.      * @access private
  3112.      */
  3113.     function isLinkedPage($expr,$package,$subpackage,$path=false)
  3114.     {
  3115.         if ($path)
  3116.         return isset($this->linkswithfile[$package][$subpackage]['page'][$path][$expr]);
  3117.         return isset($this->links[$package][$subpackage]['page'][$expr]);
  3118.     }
  3119.  
  3120.     /**
  3121.      * do not override
  3122.      * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
  3123.      * @param string $expr method name
  3124.      * @param string $class class name
  3125.      * @param string $package package to search in
  3126.      * @param string $subpackage subpackage to search in
  3127.      * @access private
  3128.      */
  3129.     function isLinkedMethod($expr,$package,$subpackage,$class,$file=false)
  3130.     {
  3131.         if ($file)
  3132.         return isset($this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr]);
  3133.         return isset($this->links[$package][$subpackage]['method'][$class][$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 var 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 isLinkedVar($expr,$package,$subpackage,$class,$file=false)
  3146.     {
  3147.         if ($file)
  3148.         return isset($this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr]);
  3149.         return isset($this->links[$package][$subpackage]['var'][$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 constant 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 isLinkedConst($expr,$package,$subpackage,$class,$file=false)
  3162.     {
  3163.         if ($file)
  3164.         return isset($this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr]);
  3165.         return isset($this->links[$package][$subpackage]['const'][$class][$expr]);
  3166.     }
  3167.  
  3168.     /**
  3169.      * return false or a {@link classLink} to $expr
  3170.      * @param string $expr class name
  3171.      * @param string $package package name
  3172.      * @return mixed returns a {@link classLink} or false if the element is not found in package $package
  3173.      * @see classLink
  3174.      */
  3175.     function getClassLink($expr,$package,$file=false$text = false)
  3176.     {
  3177.         if (!isset($this->links[$package])) return false;
  3178.         foreach($this->links[$packageas $subpackage => $notused)
  3179.         {
  3180.             if ($this->isLinkedClass($expr,$package,$subpackage,$file))
  3181.             {
  3182.                 if ($file)
  3183.                 {
  3184.                     return $this->linkswithfile[$package][$subpackage]['class'][$file][$expr];
  3185.                 }
  3186.                 return $this->links[$package][$subpackage]['class'][$expr];
  3187.             }
  3188.         }
  3189.         return false;
  3190.     }
  3191.  
  3192.     /**
  3193.      * return false or a {@link functionLink} to $expr
  3194.      * @param string $expr function name
  3195.      * @param string $package package name
  3196.      * @return mixed returns a {@link functionLink} or false if the element is not found in package $package
  3197.      * @see functionLink
  3198.      */
  3199.     function getFunctionLink($expr,$package,$file=false$text = false)
  3200.     {
  3201.         if (!isset($this->links[$package])) return false;
  3202.         foreach($this->links[$packageas $subpackage => $notused)
  3203.         {
  3204.             if ($this->isLinkedFunction($expr,$package,$subpackage,$file))
  3205.             {
  3206.                 if ($file)
  3207.                 {
  3208.                     return $this->linkswithfile[$package][$subpackage]['function'][$file][$expr];
  3209.                 }
  3210.                 return $this->links[$package][$subpackage]['function'][$expr];
  3211.             }
  3212.         }
  3213.         return false;
  3214.     }
  3215.  
  3216.     /**
  3217.      * return false or a {@link defineLink} to $expr
  3218.      * @param string $expr constant name
  3219.      * @param string $package package name
  3220.      * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
  3221.      * @see defineLink
  3222.      */
  3223.     function getDefineLink($expr,$package,$file=false$text = false)
  3224.     {
  3225.         if (!isset($this->links[$package])) return false;
  3226.         foreach($this->links[$packageas $subpackage => $notused)
  3227.         {
  3228.             if ($this->isLinkedDefine($expr,$package,$subpackage,$file))
  3229.             {
  3230.                 if ($file)
  3231.                 {
  3232.                     return $this->linkswithfile[$package][$subpackage]['define'][$file][$expr];
  3233.                 }
  3234.                 return $this->links[$package][$subpackage]['define'][$expr];
  3235.             }
  3236.         }
  3237.         return false;
  3238.     }
  3239.  
  3240.     /**
  3241.      * return false or a {@link globalLink} to $expr
  3242.      * @param string $expr global variable name (with leading $)
  3243.      * @param string $package package name
  3244.      * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
  3245.      * @see defineLink
  3246.      */
  3247.     function getGlobalLink($expr,$package,$file=false$text = false)
  3248.     {
  3249.         if (!isset($this->links[$package])) return false;
  3250.         foreach($this->links[$packageas $subpackage => $notused)
  3251.         {
  3252.             if ($this->isLinkedGlobal($expr,$package,$subpackage,$file))
  3253.             {
  3254.                 if ($file)
  3255.                 {
  3256.                     return $this->linkswithfile[$package][$subpackage]['global'][$file][$expr];
  3257.                 }
  3258.                 return $this->links[$package][$subpackage]['global'][$expr];
  3259.             }
  3260.         }
  3261.         return false;
  3262.     }
  3263.  
  3264.     /**
  3265.      * return false or a {@link pageLink} to $expr
  3266.      * @param string $expr procedural page name
  3267.      * @param string $package package name
  3268.      * @return mixed returns a {@link pageLink} or false if the element is not found in package $package
  3269.      * @see pageLink
  3270.      */
  3271.     function getPageLink($expr,$package,$path = false$text = false$packages = false)
  3272.     {
  3273.         if (!isset($this->links[$package])) return false;
  3274.         foreach($this->links[$packageas $subpackage => $notused)
  3275.         {
  3276.             if ($this->isLinkedPage($expr,$package,$subpackage,$path))
  3277.             {
  3278.                 if ($path)
  3279.                 {
  3280.                     return $this->linkswithfile[$package][$subpackage]['page'][$path][$expr];
  3281.                 }
  3282.                 return $this->links[$package][$subpackage]['page'][$expr];
  3283.             }
  3284.         }
  3285.         return false;
  3286.     }
  3287.  
  3288.     /**
  3289.      * return false or a {@link methodLink} to $expr in $class
  3290.      * @param string $expr method name
  3291.      * @param string $class class name
  3292.      * @param string $package package name
  3293.      * @return mixed returns a {@link methodLink} or false if the element is not found in package $package, class $class
  3294.      * @see methodLink
  3295.      */
  3296.     function getMethodLink($expr,$class,$package,$file=false$text = false)
  3297.     {
  3298.         $expr trim($expr);
  3299.         $class trim($class);
  3300.         if (!isset($this->links[$package])) return false;
  3301.         foreach($this->links[$packageas $subpackage => $notused)
  3302.         {
  3303.             if ($this->isLinkedMethod($expr,$package,$subpackage,$class,$file))
  3304.             {
  3305.                 if ($file)
  3306.                 {
  3307.                     return $this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr];
  3308.                 }
  3309.                 return $this->links[$package][$subpackage]['method'][$class][$expr];
  3310.             }
  3311.         }
  3312.         return false;
  3313.     }
  3314.  
  3315.     /**
  3316.      * return false or a {@link varLink} to $expr in $class
  3317.      * @param string $expr var name
  3318.      * @param string $class class name
  3319.      * @param string $package package name
  3320.      * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
  3321.      * @see varLink
  3322.      */
  3323.     function getVarLink($expr,$class,$package,$file=false$text = false)
  3324.     {
  3325.         $expr trim($expr);
  3326.         $class trim($class);
  3327.         if (!isset($this->links[$package])) return false;
  3328.         foreach($this->links[$packageas $subpackage => $notused)
  3329.         {
  3330.             if ($this->isLinkedVar($expr,$package,$subpackage,$class,$file))
  3331.             {
  3332.                 if ($file)
  3333.                 {
  3334.                     return $this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr];
  3335.                 }
  3336.                 return $this->links[$package][$subpackage]['var'][$class][$expr];
  3337.             }
  3338.         }
  3339.         return false;
  3340.     }
  3341.  
  3342.     /**
  3343.      * return false or a {@link constLink} to $expr in $class
  3344.      * @param string $expr constant name
  3345.      * @param string $class class name
  3346.      * @param string $package package name
  3347.      * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
  3348.      * @see constLink
  3349.      */
  3350.     function getConstLink($expr,$class,$package,$file=false$text = false)
  3351.     {
  3352.         $expr trim($expr);
  3353.         $class trim($class);
  3354.         if (!isset($this->links[$package])) return false;
  3355.         foreach($this->links[$packageas $subpackage => $notused)
  3356.         {
  3357.             if ($this->isLinkedConst($expr,$package,$subpackage,$class,$file))
  3358.             {
  3359.                 if ($file)
  3360.                 {
  3361.                     return $this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr];
  3362.                 }
  3363.                 return $this->links[$package][$subpackage]['const'][$class][$expr];
  3364.             }
  3365.         }
  3366.         return false;
  3367.     }
  3368.  
  3369.     /**
  3370.      * The meat of the @tutorial tag and inline {@}tutorial} tag
  3371.      *
  3372.      * Take a string and return an abstract link to the tutorial it represents.
  3373.      * Since tutorial naming literally works like the underlying filesystem, the
  3374.      * way to reference the tutorial is similar.  Tutorials are located in a
  3375.      * subdirectory of any directory parsed, which is named 'tutorials/' (we
  3376.      * try to make things simple when we can :).  They are further organized by
  3377.      * package and subpackage as:
  3378.      *
  3379.      * tutorials/package/subpackage
  3380.      *
  3381.      * and the files are named *.cls, *.pkg, or *.proc, and so a link to a tutorial
  3382.      * named file.cls can be referenced (depending on context) as any of:
  3383.      *
  3384.      * <code>
  3385.      * * @tutorial package/subpackage/file.cls
  3386.      * * @tutorial package/file.cls
  3387.      * * @tutorial file.cls
  3388.      * </code>
  3389.      *
  3390.      * The first case will only be needed if file.cls exists in both the current
  3391.      * package, in anotherpackage/file.cls and in anotherpackage/subpackage/file.cls
  3392.      * and you wish to reference the one in anotherpackage/subpackage.
  3393.      * The second case is only needed if you wish to reference file.cls in another
  3394.      * package and it is unique in that package. the third will link to the first
  3395.      * file.cls it finds using this search method:
  3396.      *
  3397.      * <ol>
  3398.      *    <li>current package/subpackage</li>
  3399.      *    <li>all other subpackages of current package</li>
  3400.      *    <li>parent package, if this package has classes that extend classes in
  3401.      *    another package</li>
  3402.      *    <li>all other packages</li>
  3403.      * </ol>
  3404.      * @return tutorialLink|stringreturns either a link, or the original text, if not found
  3405.      * @param string the original expression
  3406.      * @param string package to look in first
  3407.      * @param string subpackage to look in first
  3408.      * @param array array of package names to search in if not found in parent packages.
  3409.      *               This is used to limit the search, phpDocumentor automatically searches
  3410.      *               all packages
  3411.      * @since 1.2
  3412.      */
  3413.     function getTutorialLink($expr$package = false$subpackage = false$packages = false)
  3414.     {
  3415.         // is $expr a comma-delimited list?
  3416.         if (strpos($expr,','))
  3417.         {
  3418.             $a explode(',',$expr);
  3419.             $b = array();
  3420.             for($i=0;$i<count($a);$i++)
  3421.             {
  3422.                 // if so return each component with a link
  3423.                 $b[Converter::getTutorialLink(trim($a[$i]));
  3424.             }
  3425.             return $b;
  3426.         }
  3427.         $subsection '';
  3428.         if (strpos($expr,'#'))
  3429.         {
  3430.             $a explode('#',$expr);
  3431.             $org $expr;
  3432.             $expr $a[0];
  3433.             $subsection $a[1];
  3434.         }
  3435.         if (strpos($expr,'/'))
  3436.         {
  3437.             $a explode('/',$expr);
  3438.             if (count($a== 3)
  3439.             {
  3440.                 return Converter::getTutorialLink($a[2],$a[0],$a[1],array());
  3441.             }
  3442.             if (count($a== 2)
  3443.             {
  3444.                 return Converter::getTutorialLink($a[1],$a[0],false,array());
  3445.             }
  3446.         }
  3447.         if (!$package$package $this->package;
  3448.         if (!$subpackage$subpackage $this->subpackage;
  3449.         if (!isset($this->all_packages[$package])) return $expr;
  3450.         elseif (isset($packages[$package])) unset($packages[$package]);
  3451.         $ext pathinfo($exprPATHINFO_EXTENSION);
  3452.         if (isset($this->tutorials[$package][$subpackage][$ext][$expr]))
  3453.         {
  3454.             $a $this->tutorials[$package][$subpackage][$ext][$expr];
  3455.             $link = new tutorialLink;
  3456.             $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this,$subsection));
  3457.             return $link;
  3458.         }
  3459.         do
  3460.         {
  3461.             if (!is_array($packages))
  3462.             {
  3463.                 $packages $this->all_packages;
  3464.                 if (isset($packages[$package])) unset($packages[$package]);
  3465.             }
  3466.             if (isset($this->tutorials[$package]))
  3467.             {
  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));
  3473.                     return $link;
  3474.                 else
  3475.                 {
  3476.                     foreach($this->tutorials[$packageas $subpackage => $stuff)
  3477.                     {
  3478.                         if (isset($stuff[$ext][$expr]))
  3479.                         {
  3480.                             $a $stuff[$ext][$expr];
  3481.                             $link = new tutorialLink;
  3482.                             $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this));
  3483.                             return $link;
  3484.                         }
  3485.                     }
  3486.                 }
  3487.             }
  3488.             // try other packages
  3489.             // look in parent package first, if found
  3490.             if (isset($this->package_parents[$package]))
  3491.             {
  3492.                 $p1 $package;
  3493.                 $package $this->package_parents[$package];
  3494.             else
  3495.             {
  3496.                 // no parent package, so start with the first one that's left
  3497.                 list($package,@each($packages);
  3498.             }
  3499.             if ($package)
  3500.             {
  3501.                 if (isset($packages[$package])) unset($packages[$package]);
  3502.             }
  3503.         while (count($packages|| $package);
  3504.         addWarning(PDERROR_TUTORIAL_NOT_FOUND,$expr);
  3505.         return $expr;
  3506.     }
  3507.  
  3508.     /**
  3509.      * The meat of the @see tag and inline {@}link} tag
  3510.      *
  3511.      * $expr is a string with many allowable formats:
  3512.      * <ol>
  3513.      *  <li>proceduralpagename.ext</li>
  3514.      *  <li>constant_name</li>
  3515.      *  <li>classname::function()</li>
  3516.      *  <li>classname::constantname</li> (new 1.2.4)
  3517.      *  <li>classname::$variablename</li>
  3518.      *  <li>classname</li>
  3519.      *  <li>object classname</li>
  3520.      *  <li>function functionname()</li>
  3521.      *  <li>global $globalvarname</li>
  3522.      *  <li>packagename#expr where expr is any of the above</li>
  3523.      * </ol>
  3524.      *
  3525.      * New in version 1.1, you can explicitly specify a package to link to that
  3526.      * is different from the current package.  Use the # operator
  3527.      * to specify a new package, as in tests#bug-540368.php (which should appear
  3528.      * as a link like: "{@link tests#bug-540368.php}").  This
  3529.      * example links to the procedural page bug-540368.php in package
  3530.      * tests.  Also, the "function" operator is now used to specifically
  3531.      * link to a function instead of a method in the current class.
  3532.      *
  3533.      * <code>
  3534.      * class myclass
  3535.      * {
  3536.      *  // from inside the class definition, use "function conflict()" to refer to procedural function "conflict()"
  3537.      *    function conflict()
  3538.      *    {
  3539.      *    }
  3540.      * }
  3541.      *
  3542.      * function conflict()
  3543.      * {
  3544.      * }
  3545.      * </code>
  3546.      *
  3547.      * If classname:: is not present, and the see tag is in a documentation
  3548.      * block within a class, then the function uses the classname to
  3549.      * search for $expr as a function or variable within classname, or any of its parent classes.
  3550.      * given an $expr without '$', '::' or '()' getLink first searches for
  3551.      * classes, procedural pages, constants, global variables, and then searches for
  3552.      * methods and variables within the default class, and finally for any function
  3553.      *
  3554.      * @param string $expr expression to search for a link
  3555.      * @param string $package package to start searching in
  3556.      * @param array $packages list of all packages to search in
  3557.      * @return mixed getLink returns a descendant of {@link abstractLink} if it finds a link, otherwise it returns a string
  3558.      * @see getPageLink(), getDefineLink(), getVarLink(), getFunctionLink(), getClassLink()
  3559.      * @see pageLink, functionLink, defineLink, classLink, methodLink, varLink
  3560.      */
  3561.     function &getLink($expr$package = false$packages = false)
  3562.     {
  3563.         // is $expr a comma-delimited list?
  3564.         if (strpos($expr,','))
  3565.         {
  3566.             $a explode(',',$expr);
  3567.             $b = array();
  3568.             for($i=0;$i<count($a);$i++)
  3569.             {
  3570.                 // if so return each component with a link
  3571.                 $b[Converter::getLink(trim($a[$i]));
  3572.             }
  3573.             return $b;
  3574.         }
  3575.         if (strpos($expr,'#'))
  3576.         {
  3577.             $a explode('#',$expr);
  3578.             if (count($a== 2)
  3579.             // can have exactly 1 package override, otherwise it's ignored
  3580.                 // feature 564991, link to php manual
  3581.                 if ($a[0== 'PHP_MANUAL'{
  3582.                     $s 'http://www.php.net/'.$a[1];
  3583.                     return $s;
  3584.                 }
  3585.                 $s &Converter::getLink($a[1],$a[0],array());
  3586.                 return $s;
  3587.             }
  3588.         }
  3589.         $a &$this->_getLink($expr$package$packages);
  3590.         return $a;
  3591.     }
  3592.  
  3593.     /**
  3594.      * @access private
  3595.      */
  3596.     function &_getLink($expr$package = false$packages = false)
  3597.     {
  3598.         if (!$package$package $this->package;
  3599.         //
  3600.         if (!isset($this->all_packages[$package])) return $expr;
  3601.         elseif (isset($packages[$package])) unset($packages[$package]);
  3602.         $links &$this->links;
  3603.         $class $this->class;
  3604.         if (strpos($expr,'function '=== 0)
  3605.         // asking for a function, not a method
  3606.             if ($test Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr))$package)) return $test;
  3607.             else return $expr;
  3608.         }
  3609.         if (strpos($expr,'global '=== 0)
  3610.         // asking for a global variable
  3611.             if ($test Converter::getGlobalLink(str_replace('global ','',$expr)$package)) return $test;
  3612.             else return $expr;
  3613.         }
  3614.         if (strpos($expr,'object '=== 0)
  3615.         // asking for a class
  3616.             if ($test Converter::getClassLink(str_replace('object ','',$expr)$package)) return $test;
  3617.             else return $expr;
  3618.         }
  3619.         if (strpos($expr,'constant '=== 0)
  3620.         // asking for a class
  3621.             if ($test Converter::getDefineLink(str_replace('constant ','',$expr)$package)) return $test;
  3622.             else return $expr;
  3623.         }
  3624.         // are we in a class?
  3625.         if ($class)
  3626.         {
  3627.             // is $expr simply a word? see if it is the class
  3628.             if (trim($expr== $class)
  3629.             {
  3630.                 if ($test Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test;
  3631.             }
  3632.             // if not, check to see if it is a method or variable of this class tree
  3633.             if (!strpos($expr,'::'))
  3634.             {
  3635.                 // if get is neither get() nor $get, assume get is a function, add () to make get()
  3636.                 if (strpos($expr,'$'!== 0 && !strpos($expr,'()')) //$get = $get.'()';
  3637.                 {
  3638.                     if ($a $this->getLinkMethod($expr,$class,$package)) return $a;
  3639.                     if ($a $this->getLinkConst($expr,$class,$package)) return $a;
  3640.                     if ($a $this->getLinkVar('$'.$expr,$class,$package)) return $a;
  3641.                 }
  3642.                 if (strpos($expr,'()')) if ($a $this->getLinkMethod($expr,$class,$package)) return $a;
  3643.                 if (is_numeric(strpos($expr,'$'))) if ($a $this->getLinkVar($expr,$class,$package)) return $a;
  3644.             }
  3645.         }
  3646.         if ($test Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test;
  3647.         if ($test Converter::getPageLink(trim($expr),$package)) return $test;
  3648.         if ($test Converter::getDefineLink(trim($expr),$package)) return $test;
  3649.         if ($test Converter::getGlobalLink(trim($expr),$package)) return $test;
  3650. //        if (strpos($expr,'.'))
  3651.         // package specified
  3652.  
  3653.         if (!is_array($packages))
  3654.         {
  3655.             $packages $this->all_packages;
  3656.         }
  3657.         do
  3658.         {
  3659.             if (isset($packages[$package])) unset($packages[$package]);
  3660.             if ($test Converter::getClassLink(str_replace('object ','',$expr),$package)) return $test;
  3661.             if ($test Converter::getPageLink($expr,$package)) return $test;
  3662.             if ($test Converter::getDefineLink($expr,$package)) return $test;
  3663.             if ($test Converter::getGlobalLink($expr,$package)) return $test;
  3664.             // is $expr in class::method() or class::$variable format?
  3665.             if (strpos($expr,'function '=== 0)
  3666.             // asking for a function, not a method
  3667.                 if ($test Converter::getFunctionLink(str_replace('function','',str_replace('()','',$expr))$package)) return $test;
  3668.                 else return $expr;
  3669.             }
  3670.             $test $this->_getDoubleColon($expr$package$packages$class$links);
  3671.             if (!is_string($test)) return $test;
  3672.             if (strpos($test'parent::'=== 0return $test;
  3673.             // $expr does not have ::
  3674.             if (is_numeric(@strpos('$',$expr)))
  3675.             {
  3676.                 // default to current class, whose name is contained in $this->render->parent
  3677.                 if ($test Converter::getVarLink($expr$class$package)) return $test;
  3678.             }
  3679.             // $expr is a function? (non-method)
  3680.             if (@strpos($expr,'()'))
  3681.             {
  3682.                 // otherwise, see if it is a method
  3683.                 if ($class)
  3684.                 {
  3685.                     if ($test Converter::getMethodLink(str_replace('()','',$expr)$class$package)) return $test;
  3686.                 }
  3687.                 // extract the function name, use it to retrieve the file that the function is in
  3688.     //            $page = $this->func_page[str_replace('function ','',str_replace('()','',$expr))];
  3689.                 // return the link
  3690.                 if ($test Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr))$package)) return $test;
  3691.             }
  3692.             // $expr is just a word.  First, test to see if it is a function of the current package
  3693.             if ($test Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr))$package)) return $test;
  3694.             // try other packages
  3695.             // look in parent package first, if found
  3696.             if (isset($this->package_parents[$package]&& in_array($this->package_parents[$package]$packages))
  3697.             {
  3698.                 $p1 $package;
  3699.                 $package $this->package_parents[$package];
  3700.                 if ($package)
  3701.                 {
  3702.                     if (isset($packages[$package])) unset($packages[$package]);
  3703.                 }
  3704.                 continue;
  3705.             }
  3706.             // no parent package, so start with the first one that's left
  3707.             $package @array_shift(@array_keys($packages));
  3708.             if ($package && isset($packages[$package]))
  3709.             {
  3710.                 unset($packages[$package]);
  3711.             }
  3712.         while (count($packages|| $package);
  3713.         $funcs get_defined_functions();
  3714.         // feature 564991, link to php manual
  3715.         if (in_array(str_replace(array('(',')'),array('',''),$expr),$funcs['internal']))
  3716.         {
  3717.             $return 'http://www.php.net/'.str_replace(array('(',')'),array('',''),$expr);
  3718.             return $return;
  3719.         }
  3720.         // no links found
  3721.         return $expr;
  3722.     }
  3723.  
  3724.     /**
  3725.      * Split up getLink to make it easier to debug
  3726.      * @access private
  3727.      */
  3728.     function _getDoubleColon(&$expr&$package&$packages$class$links)
  3729.     {
  3730.         if (@strpos($expr,'::'))
  3731.         {
  3732.             $class_method explode('::',$expr);
  3733.             if ($class_method[0== 'parent')
  3734.             {
  3735.                 // can only have parent in the same package as the class!  subtle bug
  3736.                 $package $this->package;
  3737.                 $packages = array();
  3738.                 $cl $this->classes->getClassByPackage($class,$package);
  3739.                 if (!$cl)
  3740.                 // this is possible if an example file has parent::method()
  3741.                     return $expr;
  3742.                 }
  3743.                 $par $cl->getParent($this);
  3744.                 $phpparent = false;
  3745.                 if (is_object($par))
  3746.                 {
  3747.                     $package $par->docblock->package;
  3748.                     $phpparent $par->getName();
  3749.                 else
  3750.                 {
  3751.                     addWarning(PDERROR_CLASS_PARENT_NOT_FOUND,$class,$package,$class_method[1]);
  3752.                     return $expr;
  3753.                 }
  3754.                 if ($phpparent$class_method[0$phpparent;
  3755.             }
  3756.             if (strpos($class_method[1],'()'))
  3757.             {
  3758.                 // strip everything but the function name, return a link
  3759.                 if ($test Converter::getMethodLink(str_replace('()','',$class_method[1])$class_method[0]$package)) return $test;
  3760.             }
  3761.             if ($test Converter::getVarLink($class_method[1]$class_method[0]$package)) return $test;
  3762.             if ($test Converter::getConstLink($class_method[1]$class_method[0]$package)) return $test;
  3763.         }
  3764.         return $expr;
  3765.     }
  3766.  
  3767.     /**
  3768.      * cycle through parent classes to retrieve a link to a method
  3769.      * do not use or override, used by getLink
  3770.      * @access private
  3771.      */
  3772.     function &getLinkMethod($expr$class$package)
  3773.     {
  3774.         $links &$this->links;
  3775.         do
  3776.         {
  3777.             // is $expr in class::method() or class::$variable format?
  3778.             if (@strpos($expr,'::'))
  3779.             {
  3780.                 $class_method explode('::',$expr);
  3781.                 if ($class_method[0== 'parent')
  3782.                 {
  3783.                     $cl $this->classes->getClassByPackage($class,$package);
  3784.                     $par $cl->getParent($this);
  3785.                     $phpparent = false;
  3786.                     if (is_object($par))
  3787.                     {
  3788.                         $package $par->docblock->package;
  3789.                         $phpparent $par->getName();
  3790.                     else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
  3791.                     if ($phpparent$class_method[0$phpparent;
  3792.                 else
  3793.                 {
  3794.                     $cl $this->classes->getClassByPackage($class,$package);
  3795.                 }
  3796.                 if (strpos($class_method[1],'()'))
  3797.                 {
  3798.                     // strip everything but the function name, return a link
  3799.                     if ($test Converter::getMethodLink(str_replace('function ','',str_replace('()','',$class_method[1]))$class_method[0]$package)) return $test;
  3800.                 }
  3801.             }
  3802.             if ($test Converter::getMethodLink(str_replace('()','',$expr)$class$package)) return $test;
  3803.             $cl $this->classes->getClassByPackage($class,$package);
  3804.             if ($cl)
  3805.             {
  3806.                 $par $cl->getParent($this);
  3807.                 if (is_object($par))
  3808.                 {
  3809.                     $package $par->docblock->package;
  3810.                     $class $par->getName();
  3811.                 else $class $par;
  3812.             else $class = false;
  3813.         while ($class);
  3814.         // no links found
  3815.         $flag = false;
  3816.         return $flag;
  3817.     }
  3818.  
  3819.     /**
  3820.      * cycle through parent classes to retrieve a link to a var
  3821.      * do not use or override, used by getLink
  3822.      * @access private
  3823.      */
  3824.     function &getLinkVar($expr$class$package)
  3825.     {
  3826.         $links &$this->links;
  3827.         do
  3828.         {
  3829.             // is $expr in class::method() or class::$variable format?
  3830.             if (@strpos($expr,'::'))
  3831.             {
  3832.                 $class_method explode('::',$expr);
  3833.                 if ($class_method[0== 'parent')
  3834.                 {
  3835.                     $cl $this->classes->getClassByPackage($class,$package);
  3836.                     $phpparent = false;
  3837.                     $par $cl->getParent($this);
  3838.                     if (is_object($par))
  3839.                     {
  3840.                         $package $par->docblock->package;
  3841.                         $phpparent $par->getName();
  3842.                     else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
  3843.                     if ($phpparent$class_method[0$phpparent;
  3844.                 else
  3845.                 {
  3846.                     $cl $this->classes->getClassByPackage($class,$package);
  3847.                 }
  3848.                 if ($test Converter::getVarLink($class_method[1]$class_method[0]$package)) return $test;
  3849.                 if ($test Converter::getVarLink('$'.$class_method[1]$class_method[0]$package)) return $test;
  3850.             }
  3851.             if ($test Converter::getVarLink($expr$class$package)) return $test;
  3852.             if ($test Converter::getVarLink('$'.$expr$class$package)) return $test;
  3853.             $cl $this->classes->getClassByPackage($class,$package);
  3854.             if ($cl)
  3855.             {
  3856.                 $par $cl->getParent($this);
  3857.                 if (is_object($par))
  3858.                 {
  3859.                     $package $par->docblock->package;
  3860.                     $class $par->getName();
  3861.                 else $class $par;
  3862.             else $class = false;
  3863.         while ($class);
  3864.         // no links found
  3865.         $class = false;
  3866.         return $class;
  3867.     }
  3868.  
  3869.     /**
  3870.      * cycle through parent classes to retrieve a link to a class constant
  3871.      * do not use or override, used by getLink
  3872.      * @access private
  3873.      * @since 1.2.4
  3874.      */
  3875.     function &getLinkConst($expr$class$package)
  3876.     {
  3877.         $links &$this->links;
  3878.         do
  3879.         {
  3880.             // is $expr in class::method() or class::$variable format?
  3881.             if (@strpos($expr,'::'))
  3882.             {
  3883.                 $class_method explode('::',$expr);
  3884.                 if ($class_method[0== 'parent')
  3885.                 {
  3886.                     $cl $this->classes->getClassByPackage($class,$package);
  3887.                     $phpparent = false;
  3888.                     $par $cl->getParent($this);
  3889.                     if (is_object($par))
  3890.                     {
  3891.                         $package $par->docblock->package;
  3892.                         $phpparent $par->getName();
  3893.                     else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
  3894.                     if ($phpparent$class_method[0$phpparent;
  3895.                 else
  3896.                 {
  3897.                     $cl $this->classes->getClassByPackage($class,$package);
  3898.                 }
  3899.                 if ($test Converter::getConstLink($class_method[1]$class_method[0]$package)) return $test;
  3900.             }
  3901.             if ($test Converter::getConstLink($expr$class$package)) return $test;
  3902.             $cl $this->classes->getClassByPackage($class,$package);
  3903.             if ($cl)
  3904.             {
  3905.                 $par $cl->getParent($this);
  3906.                 if (is_object($par))
  3907.                 {
  3908.                     $package $par->docblock->package;
  3909.                     $class $par->getName();
  3910.                 else $class $par;
  3911.             else $class = false;
  3912.         while ($class);
  3913.         // no links found
  3914.         $flag = false;
  3915.         return $flag;
  3916.     }
  3917.  
  3918.     /**
  3919.      * take URL $link and text $text and return a link in the format needed for the Converter
  3920.      * @param string URL
  3921.      * @param string text to display
  3922.      * @return string link to $link
  3923.      * @abstract
  3924.      */
  3925.     function returnLink($link,$text)
  3926.     {
  3927.     }
  3928.  
  3929.     /**
  3930.      * take {@link abstractLink} descendant and text $eltext and return a link
  3931.      * in the format needed for the Converter
  3932.      * @param abstractLink 
  3933.      * @param string 
  3934.      * @return string link to $element
  3935.      * @abstract
  3936.      */
  3937.     function returnSee(&$link$eltext = false)
  3938.     {
  3939.     }
  3940.  
  3941.     /**
  3942.      * take {@link abstractLink} descendant and text $eltext and return a
  3943.      * unique ID in the format needed for the Converter
  3944.      * @param abstractLink 
  3945.      * @return string unique identifier of $element
  3946.      * @abstract
  3947.      */
  3948.     function getId(&$link)
  3949.     {
  3950.     }
  3951.  
  3952.     /**
  3953.      * Convert README/INSTALL/CHANGELOG file contents to output format
  3954.      * @param README|INSTALL|CHANGELOG
  3955.      * @param string contents of the file
  3956.      * @abstract
  3957.      */
  3958.     function Convert_RIC($name$contents)
  3959.     {
  3960.     }
  3961.  
  3962.     /**
  3963.      * Convert all elements to output format
  3964.      *
  3965.      * This will call ConvertXxx where Xxx is {@link ucfirst}($element->type).
  3966.      * It is expected that a child converter defines a handler for every
  3967.      * element type, even if that handler does nothing.  phpDocumentor will
  3968.      * terminate with an error if a handler doesn't exist.
  3969.      * {@internal 
  3970.      * Since 1.2.0 beta 3, this function has been moved from child converters
  3971.      * to the parent, because it doesn't really make sense to put it in the
  3972.      * child converter, and we can add error handling.
  3973.      *
  3974.      * {@source } }
  3975.      * @throws {@link PDERROR_NO_CONVERT_HANDLER}
  3976.      * @param mixed {@link parserElement} descendant or {@link parserPackagePage} or {@link parserData}
  3977.      */
  3978.     function Convert(&$element)
  3979.     {
  3980.         $handler 'convert'.ucfirst($element->type);
  3981.         if (method_exists($this,$handler))
  3982.         {
  3983.             $this->$handler($element);
  3984.         else
  3985.         {
  3986.             addErrorDie(PDERROR_NO_CONVERTER_HANDLER,$element->type,$handler,phpDocumentor_get_class($this));
  3987.         }
  3988.     }
  3989.     /**#@+
  3990.      * Conversion Handlers
  3991.      *
  3992.      * All of the convert* handlers set up template variables for the Smarty
  3993.      * template.{@internal  In addition, the {@link newSmarty()} method is
  3994.      * called to retrieve the global Smarty template}}
  3995.      */
  3996.     /**
  3997.      * Default Tutorial Handler
  3998.      *
  3999.      * Sets up the tutorial template, and its prev/next/parent links
  4000.      * {@internal 
  4001.      * Retrieves the title using {@link parserTutorial::getTitle()} and uses the
  4002.      * {@link parserTutorial::prev, parserTutorial::next, parserTutorial::parent}
  4003.      * links to set up those links.}}}
  4004.      * @param parserTutorial 
  4005.      */
  4006.     function &convertTutorial(&$element)
  4007.     {
  4008.         $this->package = $element->package;
  4009.         $this->subpackage = $element->subpackage;
  4010.         $x $element->Convert($this);
  4011.         $template &$this->newSmarty();
  4012.         $template->assign('contents',$x);
  4013.         $template->assign('title',$element->getTitle($this));
  4014.         $template->assign('nav',$element->parent || $element->prev || $element->next);
  4015.         if ($element->parent)
  4016.         {
  4017.             $template->assign('up',$this->getId($element->parent));
  4018.             $template->assign('uptitle',$element->parent->title);
  4019.         }
  4020.         if ($element->prev)
  4021.         {
  4022.             $template->assign('prev',$this->getId($element->prev));
  4023.             $template->assign('prevtitle',$element->prev->title);
  4024.         }
  4025.         if ($element->next)
  4026.         {
  4027.             $template->assign('next',$this->getId($element->next));
  4028.             $template->assign('nexttitle',$element->next->title);
  4029.         }
  4030.         return $template;
  4031.     }
  4032.     /**
  4033.      * Default Class Handler
  4034.      *
  4035.      * Sets up the class template.
  4036.      * {@internal special methods
  4037.      * {@link generateChildClassList(), generateFormattedClassTree()},
  4038.      * {@link getFormattedConflicts, getFormattedInheritedMethods},
  4039.      * and {@link getFormattedInheritedVars} are called to complete vital
  4040.      * template setup.}}}
  4041.      */
  4042.     function convertClass(&$element)
  4043.     {
  4044.         $this->class = $element->getName();
  4045.         $this->class_data = &$this->newSmarty();
  4046.         $this->class_data->assign("class_name",$element->getName());
  4047.         $this->class_data->assign("vars",array());
  4048.         $this->class_data->assign("methods",array());
  4049.         $this->class_data->assign("consts",array());
  4050.         $this->class_data->assign("is_interface"$element->isInterface());
  4051.         $this->class_data->assign("implements"$this->getFormattedImplements($element));
  4052.         $this->class_data->assign("package",$element->docblock->package);
  4053.         $this->class_data->assign("line_number",$element->getLineNumber());
  4054.         $this->class_data->assign("source_location",$element->getSourceLocation($this));
  4055.                 $this->class_data->assign("page_link",$this->getCurrentPageLink());
  4056.         $docblock $this->prepareDocBlock($elementfalse);
  4057.         $this->class_data->assign("sdesc",$docblock['sdesc']);
  4058.         $this->class_data->assign("desc",$docblock['desc']);
  4059.                 $this->class_data->assign("access"$docblock['access']);
  4060.                 $this->class_data->assign("abstract"$docblock['abstract']);
  4061.         $this->class_data->assign("tags",$docblock['tags']);
  4062.         $this->class_data->assign("api_tags",$docblock['api_tags']);
  4063.         $this->class_data->assign("info_tags",$docblock['info_tags']);
  4064.         $this->class_data->assign("utags",$docblock['utags']);
  4065.         $this->class_data->assign"prop_tags"$docblock['property_tags');
  4066.         if ($this->hasSourceCode($element->getPath())) {
  4067.         $this->class_data->assign("class_slink",$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true));
  4068.         }
  4069.  
  4070.         else
  4071.         $this->class_data->assign("class_slink",false);
  4072.         $this->class_data->assign("children"$this->generateChildClassList($element));
  4073.         $this->class_data->assign("class_tree"$this->generateFormattedClassTree($element));
  4074.         $this->class_data->assign("conflicts"$this->getFormattedConflicts($element,"classes"));
  4075.         $inherited_methods $this->getFormattedInheritedMethods($element);
  4076.         if (!empty($inherited_methods))
  4077.         {
  4078.             $this->class_data->assign("imethods",$inherited_methods);
  4079.         else
  4080.         {
  4081.             $this->class_data->assign("imethods",false);
  4082.         }
  4083.         $inherited_vars $this->getFormattedInheritedVars($element);
  4084.         if (!empty($inherited_vars))
  4085.         {
  4086.             $this->class_data->assign("ivars",$inherited_vars);
  4087.         else
  4088.         {
  4089.             $this->class_data->assign("ivars",false);
  4090.         }
  4091.         $inherited_consts $this->getFormattedInheritedConsts($element);
  4092.         if (!empty($inherited_consts))
  4093.         {
  4094.             $this->class_data->assign("iconsts",$inherited_consts);
  4095.         else
  4096.         {
  4097.             $this->class_data->assign("iconsts",false);
  4098.         }
  4099.     }
  4100.  
  4101.  
  4102.     /**
  4103.      * Converts method for template output
  4104.      *
  4105.      * This function must be called by a child converter with any extra
  4106.      * template variables needed in the parameter $addition
  4107.      * @param parserMethod 
  4108.      */
  4109.     function convertMethod(&$element$additions = array())
  4110.     {
  4111.         $fname $element->getName();
  4112.         $docblock $this->prepareDocBlock($element);
  4113.         $returntype 'void';
  4114.         if ($element->isConstructor$returntype $element->class;
  4115.         if ($element->docblock->return)
  4116.         {
  4117.             $a $element->docblock->return->Convert($this);
  4118.             $returntype $element->docblock->return->converted_returnType;
  4119.         }
  4120.         $params $param_i = array();
  4121.         if (count($element->docblock->params))
  4122.         foreach($element->docblock->params as $param => $val)
  4123.         {
  4124.             $a $val->Convert($this);
  4125.             $params[$param_i[$param= array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
  4126.         }
  4127.  
  4128.         if ($element->docblock->hasaccess{
  4129.             $acc $docblock['access'];
  4130.         else {
  4131.             $acc 'public';
  4132.         }
  4133.  
  4134.         if ($this->hasSourceCode($element->getPath()))
  4135.         $additions["slink"$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4136.         $this->class_data->append('methods',array_merge(
  4137.                                              array('sdesc' => $docblock['sdesc'],
  4138.                                                    'desc' => $docblock['desc'],
  4139.                                                    'static' => $docblock['static'],
  4140.                                                    'abstract' => $docblock['abstract'],
  4141.                                                    'tags' => $docblock['tags'],
  4142.                                                    'api_tags' => $docblock['api_tags'],
  4143.                                                    'see_tags' => $docblock['see_tags'],
  4144.                                                    'info_tags_sorted' => $docblock['info_tags_sorted'],
  4145.                                                    'info_tags' => $docblock['info_tags'],
  4146.                                                    'utags' => $docblock['utags'],
  4147.                                                    'constructor' => $element->isConstructor,
  4148.                                                    'access' => $acc,
  4149.                                                    'function_name'     => $fname,
  4150.                                                    'function_return'    => $returntype,
  4151.                                                    'function_call'     => $element->getFunctionCall(),
  4152.                                                    'ifunction_call'     => $element->getIntricateFunctionCall($this$param_i),
  4153.                                                    'descmethod'    => $this->getFormattedDescMethods($element),
  4154.                                                    'method_overrides'    => $this->getFormattedOverrides($element),
  4155.                                                    'method_implements'    => $this->getFormattedMethodImplements($element),
  4156.                                                    'line_number' => $element->getLineNumber(),
  4157.                                                    'id' => $this->getId($element),
  4158.                                                    'params' => $params),
  4159.                                              $additions));
  4160.     }
  4161.  
  4162.     /**
  4163.      * Converts class variables for template output.
  4164.      *
  4165.      * This function must be called by a child converter with any extra
  4166.      * template variables needed in the parameter $addition
  4167.      * @param parserVar 
  4168.      */
  4169.     function convertVar(&$element$additions = array())
  4170.     {
  4171.         $docblock $this->prepareDocBlock($element);
  4172.         $b 'mixed';
  4173.  
  4174.         if ($element->docblock->hasaccess)
  4175.             $acc $element->docblock->tags['access'][0]->value;
  4176.         else
  4177.             $acc 'public';
  4178.  
  4179.         if ($element->docblock->var)
  4180.         {
  4181.             $b $element->docblock->var->converted_returnType;
  4182.         }
  4183.         if ($this->hasSourceCode($element->getPath()))
  4184.         $additions["slink"$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4185.         $this->class_data->append('vars',array_merge(
  4186.                                           array('sdesc' => $docblock['sdesc'],
  4187.                                                 'desc' => $docblock['desc'],
  4188.                                                 'static' => $docblock['static'],
  4189.                                                 'abstract' => $docblock['abstract'],
  4190.                                                 'utags' => $docblock['utags'],
  4191.                                                 'tags' => $docblock['tags'],
  4192.                                                 'api_tags' => $docblock['api_tags'],
  4193.                                                 'info_tags' => $docblock['info_tags'],
  4194.                                                 'var_name' => $element->getName(),
  4195.                                                 'has_default' => strlen($element->getValue()),
  4196.                                                 'var_default' => $this->postProcess($element->getValue()),
  4197.                                                 'var_type' => $b,
  4198.                                                 'access' => $acc,
  4199.                                                 'line_number' => $element->getLineNumber(),
  4200.                                                 'descvar'    => $this->getFormattedDescVars($element),
  4201.                                                 'var_overrides' => $this->getFormattedOverrides($element),
  4202.                                                 'id' => $this->getId($element)),
  4203.                                           $additions));
  4204.     }
  4205.  
  4206.     /**
  4207.      * Converts class constants for template output.
  4208.      *
  4209.      * This function must be called by a child converter with any extra
  4210.      * template variables needed in the parameter $addition
  4211.      * @param parserConst 
  4212.      */
  4213.     function convertConst(&$element$additions = array())
  4214.     {
  4215.         $docblock $this->prepareDocBlock($element);
  4216.  
  4217.         if ($element->docblock->hasaccess)
  4218.             $acc $element->docblock->tags['access'][0]->value;
  4219.         else
  4220.             $acc 'public';
  4221.  
  4222.         if ($this->hasSourceCode($element->getPath()))
  4223.         $additions["slink"$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4224.         $this->class_data->append('consts',array_merge(
  4225.                                           array('sdesc' => $docblock['sdesc'],
  4226.                                                 'desc' => $docblock['desc'],
  4227.                                                 'access' => $docblock['access'],
  4228.                                                 'abstract' => $docblock['abstract'],
  4229.                                                 'utags' => $docblock['utags'],
  4230.                                                 'tags' => $docblock['tags'],
  4231.                                                 'api_tags' => $docblock['api_tags'],
  4232.                                                 'info_tags' => $docblock['info_tags'],
  4233.                                                 'const_name' => $element->getName(),
  4234.                                                 'const_value' => $this->postProcess($element->getValue()),
  4235.                                                 'access' => $acc,
  4236.                                                 'line_number' => $element->getLineNumber(),
  4237.                                                 'id' => $this->getId($element)),
  4238.                                           $additions));
  4239.     }
  4240.  
  4241.     /**
  4242.      * Default Page Handler
  4243.      *
  4244.      * {@internal In addition to setting up the smarty template with {@link newSmarty()},
  4245.      * this class uses {@link getSourceLocation()} and {@link getClassesOnPage()}
  4246.      * to set template variables.  Also used is {@link getPageName()}, to get
  4247.      * a Converter-specific name for the page.}}}
  4248.      * @param parserPage 
  4249.      */
  4250.     function convertPage(&$element)
  4251.     {
  4252.         $this->page_data = &$this->newSmarty(true);
  4253.         $this->page = $this->getPageName($element->parent);
  4254.         $this->path = $element->parent->getPath();
  4255.         $this->curpage = &$element->parent;
  4256.         $this->page_data->assign("source_location",$element->parent->getSourceLocation($this));
  4257.         $this->page_data->assign("functions",array());
  4258.         $this->page_data->assign("includes",array());
  4259.         $this->page_data->assign("defines",array());
  4260.         $this->page_data->assign("globals",array());
  4261.         $this->page_data->assign("classes",$this->getClassesOnPage($element));
  4262.         $this->page_data->assign("hasclasses",$element->hasClasses());
  4263.         $this->page_data->assign("hasinterfaces",$element->hasInterfaces());
  4264.         $this->page_data->assign("name"$element->parent->getFile());
  4265.         if ($t $element->getTutorial())
  4266.         {
  4267.             $this->page_data->assign("tutorial",$this->returnSee($t));
  4268.         else
  4269.         {
  4270.             $this->page_data->assign("tutorial",false);
  4271.         }
  4272.         if ($element->docblock)
  4273.         {
  4274.             $docblock $this->prepareDocBlock($elementfalse);
  4275.             $this->page_data->assign("sdesc",$docblock['sdesc']);
  4276.             $this->page_data->assign("desc",$docblock['desc']);
  4277.             $this->page_data->assign("tags",$docblock['tags']);
  4278.             $this->page_data->assign("api_tags",$docblock['api_tags']);
  4279.             $this->page_data->assign("info_tags",$docblock['info_tags']);
  4280.             $this->page_data->assign("utags",$docblock['utags']);
  4281.         }
  4282.     }
  4283.  
  4284.     /**
  4285.      * Converts global variables for template output
  4286.      *
  4287.      * This function must be called by a child converter with any extra
  4288.      * template variables needed in the parameter $addition
  4289.      * {@internal 
  4290.      * In addition to using {@link prepareDocBlock()}, this method also
  4291.      * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}}
  4292.      * @param parserGlobal 
  4293.      * @uses postProcess() on global_value template value, makes it displayable
  4294.      * @param array any additional template variables should be in this array
  4295.      */
  4296.     function convertGlobal(&$element$addition = array())
  4297.     {
  4298.         $docblock $this->prepareDocBlock($element);
  4299.         $value $this->getGlobalValue($element->getValue());
  4300.         if ($this->hasSourceCode($element->getPath()))
  4301.         $addition["slink"$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4302.         $this->page_data->append('globals',array_merge(
  4303.                                             array('sdesc' => $docblock['sdesc'],
  4304.                                                   'desc' => $docblock['desc'],
  4305.                                                   'tags' => $docblock['tags'],
  4306.                                                   'api_tags' => $docblock['api_tags'],
  4307.                                                   'info_tags' => $docblock['info_tags'],
  4308.                                                   'utags' => $docblock['utags'],
  4309.                                                   'global_name'     => $element->getName(),
  4310.                                                   'global_type' => $element->getDataType($this),
  4311.                                                   'global_value'    => $value,
  4312.                                                   'line_number' => $element->getLineNumber(),
  4313.                                                   'global_conflicts'    => $this->getFormattedConflicts($element,"global variables"),
  4314.                                                   'id' => $this->getId($element)),
  4315.                                             $addition));
  4316.     }
  4317.  
  4318.     /**
  4319.      * Converts defines for template output
  4320.      *
  4321.      * This function must be called by a child converter with any extra
  4322.      * template variables needed in the parameter $addition
  4323.      * {@internal 
  4324.      * In addition to using {@link prepareDocBlock()}, this method also
  4325.      * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}}
  4326.      * @param parserDefine 
  4327.      * @uses postProcess() on define_value template value, makes it displayable
  4328.      * @param array any additional template variables should be in this array
  4329.      */
  4330.     function convertDefine(&$element$addition = array())
  4331.     {
  4332.         $docblock $this->prepareDocBlock($element);
  4333.         if ($this->hasSourceCode($element->getPath()))
  4334.         $addition["slink"$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4335.         $this->page_data->append('defines',array_merge(
  4336.                                             array('sdesc' => $docblock['sdesc'],
  4337.                                                   'desc' => $docblock['desc'],
  4338.                                                   'tags' => $docblock['tags'],
  4339.                                                   'api_tags' => $docblock['api_tags'],
  4340.                                                   'info_tags' => $docblock['info_tags'],
  4341.                                                   'utags' => $docblock['utags'],
  4342.                                                   'define_name'     => $element->getName(),
  4343.                                                   'line_number' => $element->getLineNumber(),
  4344.                                                   'define_value'    => $this->postProcess($element->getValue()),
  4345.                                                   'define_conflicts'    => $this->getFormattedConflicts($element,"defines"),
  4346.                                                   'id' => $this->getId($element)),
  4347.                                             $addition));
  4348.     }
  4349.  
  4350.  
  4351.     /**
  4352.      * Converts includes for template output
  4353.      *
  4354.      * This function must be called by a child converter with any extra
  4355.      * template variables needed in the parameter $addition
  4356.      * @see prepareDocBlock()
  4357.      * @param parserInclude 
  4358.      */
  4359.     function convertInclude(&$element$addition = array())
  4360.     {
  4361.         $docblock $this->prepareDocBlock($element);
  4362.         $per $this->getIncludeValue($element->getValue()$element->getPath());
  4363.  
  4364.         if ($this->hasSourceCode($element->getPath()))
  4365.         $addition["slink"$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4366.         $this->page_data->append('includes',array_merge(
  4367.                                              array('sdesc' => $docblock['sdesc'],
  4368.                                                    'desc' => $docblock['desc'],
  4369.                                                    'tags' => $docblock['tags'],
  4370.                                                    'api_tags' => $docblock['api_tags'],
  4371.                                                    'info_tags' => $docblock['info_tags'],
  4372.                                                    'utags' => $docblock['utags'],
  4373.                                                    'include_name'     => $element->getName(),
  4374.                                                    'line_number' => $element->getLineNumber(),
  4375.                                                    'include_value'    => $per),
  4376.                                              $addition));
  4377.     }
  4378.  
  4379.     /**
  4380.      * Converts function for template output
  4381.      *
  4382.      * This function must be called by a child converter with any extra
  4383.      * template variables needed in the parameter $addition
  4384.      * @see prepareDocBlock()
  4385.      * @param parserFunction 
  4386.      */
  4387.     function convertFunction(&$element$addition = array())
  4388.     {
  4389.         $docblock $this->prepareDocBlock($element);
  4390.         $fname $element->getName();
  4391.         $params $param_i = array();
  4392.         if (count($element->docblock->params))
  4393.         foreach($element->docblock->params as $param => $val)
  4394.         {
  4395.             $a $val->Convert($this);
  4396.             $params[$param_i[$param= array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
  4397.         }
  4398.         $returntype 'void';
  4399.         if ($element->docblock->return)
  4400.         {
  4401.             $a $element->docblock->return->Convert($this);
  4402.             $returntype $element->docblock->return->converted_returnType;
  4403.         }
  4404.  
  4405.         if ($this->hasSourceCode($element->getPath()))
  4406.         $addition["slink"$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4407.         $this->page_data->append('functions',array_merge(
  4408.                                               array('sdesc' => $docblock['sdesc'],
  4409.                                                     'desc' => $docblock['desc'],
  4410.                                                     'tags' => $docblock['tags'],
  4411.                                                     'api_tags' => $docblock['api_tags'],
  4412.                                                     'info_tags' => $docblock['info_tags'],
  4413.                                                     'utags' => $docblock['utags'],
  4414.                                                     'function_name'     => $fname,
  4415.                                                     'function_return'    => $returntype,
  4416.                                                     'function_conflicts'    => $this->getFormattedConflicts($element,"functions"),
  4417.                                                     'ifunction_call'     => $element->getIntricateFunctionCall($this$param_i),
  4418.                                                     'function_call'     => $element->getFunctionCall(),
  4419.                                                     'line_number' => $element->getLineNumber(),
  4420.                                                     'id' => $this->getId($element),
  4421.                                                     'params' => $params),
  4422.                                               $addition));
  4423.     }
  4424.     /**#@-*/
  4425.  
  4426.     /**
  4427.      * convert the element's DocBlock for output
  4428.      *
  4429.      * This function converts all tags and descriptions for output
  4430.      * @param mixed any descendant of {@link parserElement}, or {@link parserData}
  4431.      * @param array used to translate tagnames into other tags
  4432.      * @param boolean set to false for pages and classes, the only elements allowed to specify @package
  4433.      * @return array 
  4434.      *
  4435.      *  Format:
  4436.      *  <pre>
  4437.      *  array('sdesc' => DocBlock summary
  4438.      *        'desc' => DocBlock detailed description
  4439.      *        'tags' => array('keyword' => tagname, 'data' => tag description)
  4440.      *                  known tags
  4441.      *        'api_tags' => array('keyword' => tagname, 'data' => tag description)
  4442.      *                  known api documentation tags
  4443.      *        'info_tags' => array('keyword' => tagname, 'data' => tag description)
  4444.      *                  known informational tags
  4445.      *      [ 'utags' => array('keyword' => tagname, 'data' => tag description
  4446.      *                  unknown tags ]
  4447.      *      [ 'vartype' => type from @var/@return tag ]
  4448.      *      [ 'var_descrip' => description from @var/@return tag ]
  4449.      *       )
  4450.      *  </pre>
  4451.      */
  4452.     function prepareDocBlock(&$element$names = array(),$nopackage = true)
  4453.     {
  4454.         $tagses $element->docblock->listTags();
  4455.         $tags $ret $api_tags $info_tags = array();
  4456.         $api_tags_arr = array("abstract""access""deprecated""example""filesource",
  4457.                              "global""internal""name""return""see",
  4458.                              "property""property-read""property-write""method",
  4459.                              "staticvar""usedby""uses""var");
  4460.         if (!$nopackage)
  4461.         {
  4462.             $tags[= array('keyword' => 'package','data' => $element->docblock->package);
  4463.             if (!empty($element->docblock->subpackage)) $tags[= array('keyword' => 'subpackage','data' => $element->docblock->subpackage);
  4464.         }
  4465.         if ($element->docblock->var)
  4466.         {
  4467.             $a $element->docblock->var->Convert($this);
  4468.             $ret['vartype'$element->docblock->var->converted_returnType;
  4469.             if (!empty($a))
  4470.             {
  4471.                 $tags[= array('keyword' => 'var''data' => $a);
  4472.                 $ret["var_descrip"$a;
  4473.             }
  4474.         }
  4475.         if ($element->docblock->return)
  4476.         {
  4477.             $a $element->docblock->return->Convert($this);
  4478.             $ret['vartype'$element->docblock->return->converted_returnType;
  4479.             if (!empty($a))
  4480.             {
  4481.                 $tags[$api_tags[= array('keyword' => 'return''data' => $a);
  4482.                 $ret["var_descrip"$a;
  4483.             }
  4484.         }
  4485.         if ($element->docblock->funcglobals)
  4486.         foreach($element->docblock->funcglobals as $global => $val)
  4487.         {
  4488.             if ($a $this->getGlobalLink($global,$element->docblock->package))
  4489.             {
  4490.                 $global $a;
  4491.             }
  4492.             $b Converter::getLink($val[0]);
  4493.             if (is_object($b&& phpDocumentor_get_class($b== 'classlink')
  4494.             {
  4495.                 $val[0$this->returnSee($b);
  4496.             }
  4497.             $tags[$api_tags[= array('keyword' => 'global','data' => $val[0].' '.$global.': '.$val[1]->Convert($this));
  4498.         }
  4499.         if ($element->docblock->statics)
  4500.         foreach($element->docblock->statics as $static => $val)
  4501.         {
  4502.             $a $val->Convert($this);
  4503.             $tags[$api_tags[= array('keyword' => 'staticvar','data' => $val->converted_returnType.' '.$static.': '.$a);
  4504.         }
  4505.         $property_tags = array();
  4506.         foreach $element->docblock->properties as $prop_name => $val )
  4507.         {
  4508.             $a $val->Convert$this );
  4509.             if !empty$a ) )
  4510.             {
  4511.                 $tags[$api_tags[= array'keyword' => $val->keyword ,
  4512.                                                'data' => $val->converted_returnType  . ' ' $prop_name ': ' $a );
  4513.                 $prop['prop_name'$prop_name;
  4514.                 $prop['access'$val->keyword == 'property-read' 'read' :
  4515.                                     $val->keyword == 'property-write' 'write' 'read/write' );
  4516.                 $prop['prop_type'$val->converted_returnType;
  4517.                 $prop['sdesc'$a;
  4518.                 $property_tags$prop_name $prop;
  4519.             }
  4520.         }
  4521.         ksort$property_tagsSORT_STRING );
  4522.         $property_tags array_values$property_tags );
  4523.         $info_tags_sorted = array();
  4524.         $ret['static'= false;
  4525.         foreach($tagses as $tag)
  4526.         {
  4527.             if (isset($names[$tag->keyword])) $tag->keyword = $names[$tag->keyword];
  4528.             if ($tag->keyword == 'static'{
  4529.                 $ret['static'= true;
  4530.                 continue;
  4531.             }
  4532.             if ($tag->keyword)
  4533.                 $tags[= array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
  4534.             if (in_array($tag->keyword$api_tags_arr)) {
  4535.                 $api_tags[= array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
  4536.             else {
  4537.                 $info_tags[= array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
  4538.                 @list$className$desc explode" "$tag->Convert($this));
  4539.                 $info_tags_sorted$tag->keyword ][= array'keyword' => $className'data' => $desc );
  4540.             }
  4541.         }
  4542.         $utags = array();
  4543.         foreach($element->docblock->unknown_tags as $keyword => $tag)
  4544.         {
  4545.             foreach($tag as $t)
  4546.             $utags[= array('keyword' => $keyword'data' => $t->Convert($this));
  4547.         }
  4548.         $ret['abstract'= false;
  4549.         $ret['access''public';
  4550.         $see_tags = array();
  4551.         foreach($tags as $tag)
  4552.         {
  4553.             if ($tag['keyword'== 'access'{
  4554.                 $ret['access'$tag['data'];
  4555.             }
  4556.             if ($tag['keyword'== 'abstract'{
  4557.                 $ret['abstract'= true;
  4558.             }
  4559.             if ($tag['keyword'== 'see' || $tag['keyword'== 'uses' ||
  4560.                   $tag['keyword'== 'usedby'{
  4561.                 $see_tags[$tag['data'];
  4562.             }
  4563.         }
  4564.         $ret['sdesc'$element->docblock->getSDesc($this);
  4565.         $ret['desc'$element->docblock->getDesc($this);
  4566.         $ret['tags'$tags;
  4567.         $ret['see_tags'$see_tags;
  4568.         $ret['info_tags_sorted'$info_tags_sorted;
  4569.         $ret['api_tags'$api_tags;
  4570.         $ret['info_tags'$info_tags;
  4571.         $ret['utags'$utags;
  4572.         $ret['property_tags'$property_tags;
  4573.         return $ret;
  4574.     }
  4575.  
  4576.     /**
  4577.      * gets a list of all classes declared on a procedural page represented by
  4578.      * $element, a {@link parserData} class
  4579.      * @param parserData &$element 
  4580.      * @return array links to each classes documentation
  4581.      *
  4582.      *  Format:
  4583.      *  <pre>
  4584.      *  array('name' => class name,
  4585.      *        'sdesc' => summary of the class
  4586.      *        'link' => link to the class's documentation)
  4587.      *  </pre>
  4588.      */
  4589.     function getClassesOnPage(&$element)
  4590.     {
  4591.         global $_phpDocumentor_setting;
  4592.         $a $element->getClasses($this);
  4593.         $classes = array();
  4594.         foreach($a as $package => $clas)
  4595.         {
  4596.             if (!empty($_phpDocumentor_setting['packageoutput']))
  4597.             {
  4598.                 $packages explode(',',$_phpDocumentor_setting['packageoutput']);
  4599.                 if (!in_array($package$packages)) continue;
  4600.             }
  4601.             for($i=0; $i<count($clas)$i++)
  4602.             {
  4603.                 if ($this->parseprivate || ($clas[$i]->docblock && $clas[$i]->docblock->hasaccess && $clas[$i]->docblock->tags['access'][0]->value == 'private'))
  4604.                 {
  4605.                     $sdesc '';
  4606.                     $r = array();
  4607.                     $sdesc $clas[$i]->docblock->getSDesc($this);
  4608.                     if ($clas[$i]->docblock->hasaccess)
  4609.                                             $r['access'$clas[$i]->docblock->tags['access'][0]->value;
  4610.                     else
  4611.                                             $r['access''public';
  4612.                                         if (isset ($clas[$i]->docblock->tags['abstract']))
  4613.                                             $r['abstract'= TRUE;
  4614.                                         else
  4615.                                             $r['abstract'= FALSE;
  4616.                     $r['name'$clas[$i]->getName();
  4617.                     $r['sdesc'$sdesc;
  4618.                     $r['link'$this->getClassLink($clas[$i]->getName(),$package,$clas[$i]->getPath());
  4619.                     $classes[$r;
  4620.                 }
  4621.             }
  4622.         }
  4623.         return $classes;
  4624.     }
  4625.  
  4626.     /**
  4627.      * returns an array containing the class inheritance tree from the root
  4628.      * object to the class.
  4629.      *
  4630.      * This method must be overridden, or phpDocumentor will halt with a fatal
  4631.      * error
  4632.      * @return string Converter-specific class tree for an individual class
  4633.      * @param parserClass    class variable
  4634.      * @abstract
  4635.      */
  4636.  
  4637.     function generateFormattedClassTree($class)
  4638.     {
  4639.     }
  4640.  
  4641.     /**
  4642.      * returns an array containing the class inheritance tree from the root
  4643.      * object to the class.
  4644.      *
  4645.      * This method must be overridden, or phpDocumentor will halt with a fatal
  4646.      * error
  4647.      * @return string Converter-specific class tree for an individual class
  4648.      * @param parserClass    class variable
  4649.      * @abstract
  4650.      */
  4651.  
  4652.     function getFormattedImplements($el)
  4653.     {
  4654.         $ret = array();
  4655.         foreach ($el->getImplements(as $interface)
  4656.         {
  4657.             $link $this->getLink($interface);
  4658.             if ($link && is_object($link)) {
  4659.                 $ret[$this->returnSee($link);
  4660.             else {
  4661.                 if (class_exists('ReflectionClass')) {
  4662.                     if (interface_exists($interface)) {
  4663.                         $inter = new ReflectionClass($interface);
  4664.                         if ($inter->isInternal()) {
  4665.                             $ret[$interface ' (internal interface)';
  4666.                         else {
  4667.                             $ret[$interface;
  4668.                         }
  4669.                     }
  4670.                 else {
  4671.                     $ret[$interface;
  4672.                 }
  4673.             }
  4674.         }
  4675.         return $ret;
  4676.     }
  4677.  
  4678.     /**
  4679.      * @param mixed {@link parserClass, parserFunction, parserDefine} or
  4680.      *  {@link parserGlobal}
  4681.      * @param string type to display.  either 'class','function','define'
  4682.      *                or 'global variable'
  4683.      * @return array links to conflicting elements, or empty array
  4684.      * @uses parserClass::getConflicts()
  4685.      * @uses parserFunction::getConflicts()
  4686.      * @uses parserDefine::getConflicts()
  4687.      * @uses parserGlobal::getConflicts()
  4688.      */
  4689.     function getFormattedConflicts(&$element,$type)
  4690.     {
  4691.         $conflicts $element->getConflicts($this);
  4692.         $r = array();
  4693.         if (!$conflictsreturn false;
  4694.         foreach($conflicts as $package => $class)
  4695.         {
  4696.             $r[$class->getLink($this,$class->docblock->package);
  4697.         }
  4698.         if (!empty($r)) $r = array('conflicttype' => $type'conflicts' => $r);
  4699.         return $r;
  4700.     }
  4701.  
  4702.     /**
  4703.      * Get a list of methods in child classes that override this method
  4704.      * @return array empty array or array(array('link'=>link to method,
  4705.      *  'sdesc'=>short description of the method),...)
  4706.      * @uses parserMethod::getOverridingMethods()
  4707.      * @param parserMethod 
  4708.      */
  4709.     function getFormattedDescMethods(&$element)
  4710.     {
  4711.         $meths $element->getOverridingMethods($this);
  4712.         $r = array();
  4713.         for($i=0; $i<count($meths)$i++)
  4714.         {
  4715.             $ms = array();
  4716.             $ms['link'$meths[$i]->getLink($this);
  4717.             $ms['sdesc'$meths[$i]->docblock->getSDesc($this);
  4718.             $r[$ms;
  4719.         }
  4720.         return $r;
  4721.     }
  4722.  
  4723.     /**
  4724.      * Get a list of vars in child classes that override this var
  4725.      * @return array empty array or array('link'=>link to var,
  4726.      *  'sdesc'=>short description of the method
  4727.      * @uses parserVar::getOverridingVars()
  4728.      * @param parserVar 
  4729.      */
  4730.     function getFormattedDescVars(&$element)
  4731.     {
  4732.         $vars $element->getOverridingVars($this);
  4733.         $r = array();
  4734.         for($i=0; $i<count($vars)$i++)
  4735.         {
  4736.             $vs = array();
  4737.             $vs['link'$vars[$i]->getLink($this);
  4738.             $vs['sdesc'$vars[$i]->docblock->getSDesc($this);
  4739.             $r[$vs;
  4740.         }
  4741.         return $r;
  4742.     }
  4743.  
  4744.     /**
  4745.      * Get the method this method overrides, if any
  4746.      * @return array|falsearray('link'=>link to overridden method,
  4747.      *  'sdesc'=>short description
  4748.      * @see parserMethod::getOverrides()
  4749.      * @param parserMethod 
  4750.      */
  4751.     function getFormattedOverrides(&$element)
  4752.     {
  4753.         $ovr $element->getOverrides($this);
  4754.         if (!$ovrreturn false;
  4755.         $sdesc $ovr->docblock->getSDesc($this);
  4756.         $name method_exists($ovr'getFunctionCall'$ovr->getFunctionCall($ovr->getName();
  4757.         $link ($link $ovr->getLink($this)) $link $ovr->getClass('::' $name;
  4758.         return array('link' => $link,'sdesc' => $sdesc);
  4759.     }
  4760.  
  4761.     /**
  4762.      * Get the method this method(s) implemented from an interface, if any
  4763.      * @return array|falsearray('link'=>link to implemented method,
  4764.      *  'sdesc'=>short description
  4765.      * @uses parserMethod::getImplements()
  4766.      * @param parserMethod 
  4767.      */
  4768.     function getFormattedMethodImplements(&$element)
  4769.     {
  4770.         $ovr $element->getImplements($this);
  4771.         if (!$ovrreturn false;
  4772.         $ret = array();
  4773.         foreach ($ovr as $impl{
  4774.             $sdesc $impl->docblock->getSDesc($this);
  4775.             $name $impl->getName();
  4776.             $link ($link $impl->getLink($this)) $link $impl->getClass('::' $name;
  4777.             $ret[= array('link' => $link,'sdesc' => $sdesc);
  4778.         }
  4779.         return $ret;
  4780.     }
  4781.  
  4782.     /**
  4783.      * returns a list of child classes
  4784.      *
  4785.      * @param parserClass class variable
  4786.      * @uses parserClass::getChildClassList()
  4787.      */
  4788.  
  4789.     function generateChildClassList($class)
  4790.     {
  4791.         $kids $class->getChildClassList($this);
  4792.         $list = array();
  4793.         if (count($kids))
  4794.         {
  4795.             for($i=0; $i<count($kids)$i++)
  4796.             {
  4797.                 $lt['link'$kids[$i]->getLink($this);
  4798.                 $lt['sdesc'$kids[$i]->docblock->getSDesc($this);
  4799.  
  4800.                                 if ($kids[$i]->docblock->hasaccess)
  4801.                                     $lt['access'$kids[$i]->docblock->tags['access'][0]->value;
  4802.                                 else
  4803.                                     $lt['access''public';
  4804.  
  4805.                                 $lt['abstract'= isset ($kids[$i]->docblock->tags['abstract'][0]);
  4806.  
  4807.                 $list[$lt;
  4808.             }
  4809.         else return false;
  4810.         return $list;
  4811.     }
  4812.  
  4813.     /**
  4814.      * Return template-enabled list of inherited variables
  4815.      *
  4816.      * uses parserVar helper function getInheritedVars and generates a
  4817.      * template-enabled list using getClassLink()
  4818.      * @param parserVar $child class var
  4819.      * @see getClassLink(), parserVar::getInheritedVars()
  4820.      * @return array Format:
  4821.      *  <pre>
  4822.      *  array(
  4823.      *    array('parent_class' => link to parent class's documentation,
  4824.      *          'ivars' =>
  4825.      *             array(
  4826.      *               array('name' => inherited variable name,
  4827.      *                     'link' => link to inherited variable's documentation,
  4828.      *                     'default' => default value of inherited variable,
  4829.      *                     'sdesc' => summary of inherited variable),
  4830.      *               ...),
  4831.      *    ...)
  4832.      *  </pre>
  4833.      */
  4834.  
  4835.     function getFormattedInheritedVars($child)
  4836.     {
  4837.         $package $child->docblock->package;
  4838.         $subpackage $child->docblock->subpackage;
  4839.         $ivars $child->getInheritedVars($this);
  4840.         $results = array();
  4841.         if (!count($ivars)) return $results;
  4842.         foreach($ivars as $parent => $vars)
  4843.         {
  4844.             $file $vars['file'];
  4845.             $vars $vars['vars'];
  4846.             $par $this->classes->getClass($parent,$file);
  4847.             if ($par{
  4848.                 $package $par->docblock->package;
  4849.             }
  4850.             usort($vars,array($this,"sortVar"));
  4851.             $result['parent_class'$this->getClassLink($parent$package);
  4852.             if (!$result['parent_class']{
  4853.                 $result['parent_class'$parent ' (Internal Class)';
  4854.             }
  4855.             foreach($vars as $var)
  4856.             {
  4857.                 $info = array();
  4858.  
  4859.                 if ($var->docblock->hasaccess{
  4860.                     $info['access'$var->docblock->tags['access'][0]->value;
  4861.                 else {
  4862.                     $info['access''public';
  4863.                 }
  4864.  
  4865.                 $info['abstract'= isset ($var->docblock->tags['abstract'][0]);
  4866.  
  4867.                 $info['name'$var->getName();
  4868.                 $info['link'$var->getLink($this);
  4869.                 if (!$info['link']{
  4870.                     $info['link'$info['name'];
  4871.                 }
  4872.                 $info['default'$this->postProcess($var->getValue());
  4873.                 if ($var->docblock)
  4874.                 $info['sdesc'$var->docblock->getSDesc($this);
  4875.                 $result["ivars"][$info;
  4876.             }
  4877.             $results[$result;
  4878.             $result = array();
  4879.         }
  4880.         return $results;
  4881.     }
  4882.  
  4883.     /**
  4884.      * Return template-enabled list of inherited methods
  4885.      *
  4886.      * uses parserMethod helper function getInheritedMethods and generates a
  4887.      * template-enabled list using getClassLink()
  4888.      * @param parserMethod $child class method
  4889.      * @see getClassLink(), parserMethod::getInheritedMethods()
  4890.      * @return array Format:
  4891.      *  <pre>
  4892.      *  array(
  4893.      *    array('parent_class' => link to parent class's documentation,
  4894.      *          'ivars' =>
  4895.      *             array(
  4896.      *               array('name' => inherited variable name,
  4897.      *                     'link' => link to inherited variable's documentation,
  4898.      *                     'function_call' => {@link parserMethod::getIntricateFunctionCall()}
  4899.      *                                        returned array,
  4900.      *                     'sdesc' => summary of inherited variable),
  4901.      *               ...),
  4902.      *    ...)
  4903.      *  </pre>
  4904.      */
  4905.  
  4906.     function getFormattedInheritedMethods($child)
  4907.     {
  4908.         $package $child->docblock->package;
  4909.         $subpackage $child->docblock->subpackage;
  4910.         $imethods $child->getInheritedMethods($this);
  4911.         $results = array();
  4912.         if (!count($imethods)) return $results;
  4913.         foreach($imethods as $parent => $methods)
  4914.         {
  4915.             $file $methods['file'];
  4916.             $methods $methods['methods'];
  4917.             $par $this->classes->getClass($parent,$file);
  4918.             if ($par{
  4919.                 $package $par->docblock->package;
  4920.             }
  4921.             usort($methods,array($this,"sortMethod"));
  4922.             $result['parent_class'$this->getClassLink($parent,$package);
  4923.             if (!$result['parent_class']{
  4924.                 $result['parent_class'$parent ' (Internal Class)';
  4925.             }
  4926.             foreach($methods as $method)
  4927.             {
  4928.                 $info = array();
  4929.  
  4930.                 if ($method->docblock->hasaccess{
  4931.                     $info['access'$method->docblock->tags['access'][0]->value;
  4932.                 else {
  4933.                     $info['access''public';
  4934.                 }
  4935.                 $info['abstract'= isset ($method->docblock->tags['abstract'][0]);
  4936.  
  4937.                 if ($method->isConstructor$info['constructor'= 1;
  4938.                 $returntype 'void';
  4939.                 if ($method->isConstructor{
  4940.                     $returntype $method->getClass();
  4941.                 }
  4942.                 if ($method->docblock->return{
  4943.                     $a $method->docblock->return->Convert($this);
  4944.                     $returntype $method->docblock->return->converted_returnType;
  4945.                 }
  4946.                 $info['function_return'$returntype;
  4947.                 $info['static'= isset ($method->docblock->tags['static'][0]);
  4948.                 $info['link'$method->getLink($this);
  4949.                 if (!$info['link']{
  4950.                     $info['link'$method->getFunctionCall();
  4951.                 }
  4952.                 $info['name'$method->getName();
  4953.                 if ($method->docblock)
  4954.                 $info['sdesc'$method->docblock->getSDesc($this);
  4955.                 $params = array();
  4956.                 if (count($method->docblock->params))
  4957.                 foreach($method->docblock->params as $param => $val)
  4958.                 {
  4959.                     $a $val->Convert($this);
  4960.                     $params[$param= array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
  4961.                 }
  4962.  
  4963.                 $info['function_call'$method->getIntricateFunctionCall($this,$params);
  4964.                 $result["imethods"][$info;
  4965.             }
  4966.             $results[$result;
  4967.             $result = array();
  4968.         }
  4969.         return $results;
  4970.     }
  4971.  
  4972.     /**
  4973.      * Return template-enabled list of inherited class constants
  4974.      *
  4975.      * uses parserConst helper function getInheritedConsts and generates a
  4976.      * template-enabled list using getClassLink()
  4977.      * @param parserConst $child class constant
  4978.      * @see getClassLink(), parserMethod::getInheritedConsts()
  4979.      * @return array Format:
  4980.      *  <pre>
  4981.      *  array(
  4982.      *    array('parent_class' => link to parent class's documentation,
  4983.      *          'ivars' =>
  4984.      *             array(
  4985.      *               array('name' => inherited constant name,
  4986.      *                     'link' => link to inherited constant's documentation,
  4987.      *                     'value' => constant value,
  4988.      *                     'sdesc' => summary of inherited constant),
  4989.      *               ...),
  4990.      *    ...)
  4991.      *  </pre>
  4992.      */
  4993.  
  4994.     function getFormattedInheritedConsts($child)
  4995.     {
  4996.         $package $child->docblock->package;
  4997.         $subpackage $child->docblock->subpackage;
  4998.         $ivars $child->getInheritedConsts($this);
  4999.         $results = array();
  5000.         if (!count($ivars)) return $results;
  5001.         foreach($ivars as $parent => $vars)
  5002.         {
  5003.             $file $vars['file'];
  5004.             $vars $vars['consts'];
  5005.             $par $this->classes->getClass($parent,$file);
  5006.             if ($par{
  5007.                 $package $par->docblock->package;
  5008.             }
  5009.             usort($vars,array($this,"sortVar"));
  5010.             $result['parent_class'$this->getClassLink($parent,$package);
  5011.             if (!$result['parent_class']{
  5012.                 $result['parent_class'$parent ' (Internal Class)';
  5013.             }
  5014.             foreach($vars as $var)
  5015.             {
  5016.                 $info = array();
  5017.  
  5018.                 if ($var->docblock->hasaccess{
  5019.                     $info['access'$var->docblock->tags['access'][0]->value;
  5020.                 else {
  5021.                     $info['access''public';
  5022.                 }
  5023.                 $info['name'$var->getName();
  5024.                 $info['link'$var->getLink($this);
  5025.                 if (!$info['link']{
  5026.                     $info['link'$info['name'' = ' $var->getValue();
  5027.                 }
  5028.                 $info['value'$this->postProcess($var->getValue());
  5029.                 if ($var->docblock)
  5030.                 $info['sdesc'$var->docblock->getSDesc($this);
  5031.                 $result["iconsts"][$info;
  5032.             }
  5033.             $results[$result;
  5034.             $result = array();
  5035.         }
  5036.         return $results;
  5037.     }
  5038.  
  5039.     /**
  5040.      * Return a Smarty template object to operate with
  5041.      *
  5042.      * This returns a Smarty template with pre-initialized variables for use.
  5043.      * If the method "SmartyInit()" exists, it is called.
  5044.      * @return Smarty 
  5045.      */
  5046.     function &newSmarty()
  5047.     {
  5048.         $templ = new Smarty;
  5049.         $templ->use_sub_dirs = false;
  5050.         $templ->template_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'templates');
  5051.         $templatename get_class($this$this->templateName;
  5052.         if (!file_exists($this->targetDir . DIRECTORY_SEPARATOR . md5($templatename))) {
  5053.             // we'll delete this on finishing conversion
  5054.             $this->_compiledDir[$this->targetDir . DIRECTORY_SEPARATOR . md5($templatename)= 1;
  5055.             mkdir($this->targetDir . DIRECTORY_SEPARATOR . md5($templatename),0775);
  5056.         }
  5057.         $templ->compile_dir = realpath($this->targetDir . PATH_DELIMITER . md5($templatename));
  5058.         $templ->config_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'configs');
  5059.         $templ->assign("date",date("r",time()));
  5060.         $templ->assign("maintitle",$this->title);
  5061.         $templ->assign("package",$this->package);
  5062.         $templ->assign("phpdocversion",PHPDOCUMENTOR_VER);
  5063.         $templ->assign("phpdocwebsite",PHPDOCUMENTOR_WEBSITE);
  5064.         $templ->assign("subpackage",$this->subpackage);
  5065.         if (method_exists($this,'SmartyInit')) return $this->SmartyInit($templ);
  5066.         return $templ;
  5067.     }
  5068.  
  5069.     /**
  5070.      * Finish up parsing/cleanup directories
  5071.      */
  5072.     function cleanup()
  5073.     {
  5074.         foreach ($this->_compiledDir as $dir => $one{
  5075.             $this->_rmdir($dir);
  5076.         }
  5077.     }
  5078.  
  5079.     /**
  5080.      * Completely remove a directory and its contents
  5081.      *
  5082.      * @param string $directory 
  5083.      */
  5084.     function _rmdir($directory)
  5085.     {
  5086.         $handle @opendir($directory);
  5087.         if ($handle{
  5088.             while (false !== ($file readdir($handle))) {
  5089.                 if ($file == '.' || $file == '..'{
  5090.                     continue;
  5091.                 }
  5092.                 if (is_dir($directory . DIRECTORY_SEPARATOR . $file)) {
  5093.                     $this->_rmdir($directory . DIRECTORY_SEPARATOR . $file);
  5094.                 }
  5095.                 @unlink($directory . DIRECTORY_SEPARATOR . $file);
  5096.             }
  5097.             closedir($handle);
  5098.             @rmdir($directory);
  5099.         }
  5100.     }
  5101.  
  5102.     /**
  5103.      * do all necessary output
  5104.      * @see Converter
  5105.      * @abstract
  5106.      */
  5107.     function Output($title)
  5108.     {
  5109.         phpDocumentor_out("WARNING: Generic Converter::Output was used, no output will be generated");
  5110.     }
  5111.  
  5112.     /**
  5113.      * Set the template directory with a different template base directory
  5114.      * @tutorial phpDocumentor.howto.pkg#using.command-line.templatebase
  5115.      * @param string template base directory
  5116.      * @param string template name
  5117.      */
  5118.     function setTemplateBase($base$dir)
  5119.     {
  5120.         // remove trailing /'s from the base path, if any
  5121.         $base str_replace('\\','/',$base);
  5122.         while ($base{strlen($base- 1== '/'$base substr($base,0,strlen($base- 1);
  5123.         $this->templateName = substr($dir,0,strlen($dir- 1);
  5124.         $this->templateDir =  $base "/Converters/" $this->outputformat . "/" $this->name . "/templates/" $dir;
  5125.         if (!is_dir($this->templateDir))
  5126.         {
  5127.             addErrorDie(PDERROR_TEMPLATEDIR_DOESNT_EXIST$this->templateDir);
  5128.         }
  5129.  
  5130.         $this->smarty_dir = $this->templateDir;
  5131.         if (file_exists($this->templateDir . PATH_DELIMITER . 'options.ini'))
  5132.         {
  5133.             // retrieve template options, allow array creation
  5134.             $this->template_options = phpDocumentor_parse_ini_file($this->templateDir . PATH_DELIMITER . 'options.ini',true);
  5135.         }
  5136.     }
  5137.  
  5138.     /**
  5139.      * sets the template directory based on the {@link $outputformat} and {@link $name}
  5140.      * Also sets {@link $templateName} to the $dir parameter
  5141.      * @param string subdirectory
  5142.      */
  5143.     function setTemplateDir($dir)
  5144.     {
  5145.         if ('@DATA-DIR@' != '@'.'DATA-DIR@'{
  5146.             $templateBase str_replace('\\''/''@DATA-DIR@/PhpDocumentor/phpDocumentor');
  5147.         else {
  5148.             $templateBase str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']'/phpDocumentor';
  5149.         }
  5150.         $this->setTemplateBase($templateBase$dir);
  5151.     }
  5152.  
  5153.     /**
  5154.      * Get the absolute path to the converter's base directory
  5155.      * @return string 
  5156.      */
  5157.     function getConverterDir()
  5158.     {
  5159.         if ('@DATA-DIR@' != '@' 'DATA-DIR@'{
  5160.             return str_replace('\\''/'"@DATA-DIR@/PhpDocumentor/phpDocumentor/Converters/"$this->outputformat . "/" $this->name;
  5161.         else {
  5162.             return str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']."/phpDocumentor/Converters/" $this->outputformat . "/" $this->name;
  5163.         }
  5164.     }
  5165.  
  5166.     /**
  5167.      * Parse a global variable's default value for class initialization.
  5168.      *
  5169.      * If a global variable's default value is "new class" as in:
  5170.      * <code>
  5171.      * $globalvar = new Parser
  5172.      * </code>
  5173.      * This method will document it not as "new Parser" but instead as
  5174.      * "new {@link Parser}".    For examples, see {@link phpdoc.inc}.
  5175.      * Many global variables are classes, and phpDocumentor links to their
  5176.      * documentation
  5177.      * @return string default global variable value with link to class if
  5178.      *                 it's "new Class"
  5179.      * @param string default value of a global variable.
  5180.      */
  5181.     function getGlobalValue($value)
  5182.     {
  5183.         if (strpos($value,'new'=== 0)
  5184.         {
  5185.             preg_match('/new([^(]*)((?:.|\r|\n)*)/',$value,$newval);
  5186.             if (isset($newval[1]))
  5187.             {
  5188.                 $a Converter::getLink(trim($newval[1]));
  5189.                 if (!isset($newval[2])) $newval[2'';
  5190.                 if ($a && phpDocumentor_get_class($a== 'classlink'$value 'new '.$this->returnSee($a.
  5191.                     $this->postProcess($newval[2]);
  5192.             }
  5193.             return $value;
  5194.         }
  5195.         return $this->postProcess($value);
  5196.     }
  5197.  
  5198.     /**
  5199.      * Parse an include's file to see if it is a file documented in this project
  5200.      *
  5201.      * Although not very smart yet, this method will try to look for the
  5202.      * included file file.ext:
  5203.      *
  5204.      * <code>
  5205.      * include ("file.ext");
  5206.      * </code>
  5207.      *
  5208.      * If it finds it, it will return a link to the file's documentation.  As of
  5209.      * 1.2.0rc1, phpDocumentor is smarty enough to find these cases:
  5210.      * <ul>
  5211.      *  <li>absolute path to file</li>
  5212.      *  <li>./file.ext or ../file.ext</li>
  5213.      *  <li>relpath/to/file.ext if relpath is a subdirectory of the base parse
  5214.      *      directory</li>
  5215.      * </ul>
  5216.      * For examples, see {@link Setup.inc.php} includes.
  5217.      * Every include auto-links to the documentation for the file that is included
  5218.      * @return string included file with link to docs for file, if found
  5219.      * @param string file included by include statement.
  5220.      * @param string path of file that has the include statement
  5221.      */
  5222.     function getIncludeValue($value$ipath)
  5223.     {
  5224.         preg_match('/"([^"\']*\.[^"\']*)"/',$value,$match);
  5225.         if (!isset($match[1]))
  5226.         preg_match('/\'([^"\']*\.[^"\']*)\'/',$value,$match);
  5227.         if (isset($match[1]))
  5228.         {
  5229.             $fancy_per $this->proceduralpages->pathMatchesParsedFile($match[1],$ipath);
  5230.             if ($fancy_per)
  5231.             {
  5232.                 $link $this->addLink($fancy_per);
  5233.                 if (is_object($link&& phpDocumentor_get_class($link== 'pagelink' &&
  5234.                     isset($this->all_packages[$link->package]))
  5235.                 {
  5236.                     $value $this->returnSee($link,$value);
  5237.                 }
  5238.             else
  5239.             {
  5240.                 $per Converter::getLink($match[1]);
  5241.                 if (is_object($per&& phpDocumentor_get_class($per== 'pagelink')
  5242.                 $value $this->returnSee($per);
  5243.             }
  5244.         }
  5245.         return $value;
  5246.     }
  5247.  
  5248.     /**
  5249.      * Recursively creates all subdirectories that don't exist in the $dir path
  5250.      * @param string $dir 
  5251.      */
  5252.     function createParentDir($dir)
  5253.     {
  5254.         if (empty($dir)) return;
  5255.         $tmp explode(SMART_PATH_DELIMITER,$dir);
  5256.         array_pop($tmp);
  5257.         $parent implode(SMART_PATH_DELIMITER,$tmp);
  5258.         if ($parent != '' && !file_exists($parent))
  5259.         {
  5260.             $test @mkdir($parent,0775);
  5261.             if (!$test)
  5262.             {
  5263.                 $this->createParentDir($parent);
  5264.                 $test @mkdir($parent,0775);
  5265.                 phpDocumentor_out("Creating Parent Directory $parent\n");
  5266.             else
  5267.             {
  5268.                 phpDocumentor_out("Creating Parent Directory $parent\n");
  5269.             }
  5270.         }
  5271.     }
  5272.  
  5273.     /**
  5274.      * Sets the output directory for generated documentation
  5275.      * 
  5276.      * As of 1.3.0RC6, this also sets the compiled templates directory inside
  5277.      * the target directory
  5278.      * @param string $dir the output directory
  5279.      */
  5280.     function setTargetDir($dir)
  5281.     {
  5282.         if (strlen($dir> 0)
  5283.         {
  5284.             $this->targetDir = $dir;
  5285.             // if directory does exist create it, this should have more error checking in the future
  5286.             if (!file_exists($dir))
  5287.             {
  5288.                 $tmp str_replace(array("/","\\"),SMART_PATH_DELIMITER,$dir);
  5289.                 if (substr($tmp,-1== SMART_PATH_DELIMITER)
  5290.                 {
  5291.                     $tmp substr($tmp,0,(strlen($tmp)-1));
  5292.                 }
  5293.                 $this->createParentDir($tmp);
  5294.                 phpDocumentor_out("Creating Directory $dir\n");
  5295.                 mkdir($dir,0775);
  5296.             elseif (!is_dir($dir))
  5297.             {
  5298.                 echo "Output path: '$dir' is not a directory\n";
  5299.                 die();
  5300.             }
  5301.         else {
  5302.             echo "a target directory must be specified\n try phpdoc -h\n";
  5303.             die();
  5304.         }
  5305.     }
  5306.  
  5307.     /**
  5308.      * Writes a file to target dir
  5309.      * @param string 
  5310.      * @param string 
  5311.      * @param boolean true if the data is binary and not text
  5312.      */
  5313.     function writeFile($file,$data,$binary = false)
  5314.     {
  5315.         if (!file_exists($this->targetDir))
  5316.         {
  5317.             mkdir($this->targetDir,0775);
  5318.         }
  5319.         $string '';
  5320.         if ($binary$string 'binary file ';
  5321.         phpDocumentor_out("    Writing $string".$this->targetDir . PATH_DELIMITER . $file "\n");
  5322.         flush();
  5323.         $write 'w';
  5324.         if ($binary$write 'wb';
  5325.         $fp fopen($this->targetDir . PATH_DELIMITER . $file,$write);
  5326.         set_file_buffer$fp);
  5327.         fwrite($fp,$data,strlen($data));
  5328.         fclose($fp);
  5329.     }
  5330.  
  5331.     /**
  5332.      * Copies a file from the template directory to the target directory
  5333.      * thanks to Robert Hoffmann for this fix
  5334.      * @param string 
  5335.      */
  5336.     function copyFile($file$subdir '')
  5337.     {
  5338.         if (!file_exists($this->targetDir))
  5339.         {
  5340.             mkdir($this->targetDir,0775);
  5341.         }
  5342.         copy($this->templateDir . $subdir  PATH_DELIMITER . $file$this->targetDir . PATH_DELIMITER . $file);
  5343.     }
  5344.  
  5345.     /**
  5346.      * Return parserStringWithInlineTags::Convert() cache state
  5347.      * @see parserStringWithInlineTags::Convert()
  5348.      * @abstract
  5349.      */
  5350.     function getState()
  5351.     {
  5352.         return true;
  5353.     }
  5354.  
  5355.     /**
  5356.      * Compare parserStringWithInlineTags::Convert() cache state to $state
  5357.      * @param mixed 
  5358.      * @see parserStringWithInlineTags::Convert()
  5359.      * @abstract
  5360.      */
  5361.     function checkState($state)
  5362.     {
  5363.         return true;
  5364.     }
  5365.  
  5366. }
  5367.  
  5368. /**
  5369.  * @access private
  5370.  * @see Converter::getSortedClassTreeFromClass()
  5371.  */
  5372. function rootcmp($a$b)
  5373. {
  5374.     return strnatcasecmp($a['class'],$b['class']);
  5375. }
  5376.  
  5377. /**
  5378.  * @access private
  5379.  * @global string used to make the first tutorials converted the default package tutorials
  5380.  */
  5381. function tutorialcmp($a$b)
  5382. {
  5383.     global $phpDocumentor_DefaultPackageName;
  5384.     if ($a == $phpDocumentor_DefaultPackageNamereturn -1;
  5385.     if ($b == $phpDocumentor_DefaultPackageNamereturn 1;
  5386.     return strnatcasecmp($a$b);
  5387. }
  5388.  
  5389. /**
  5390.  * smart htmlentities, doesn't entity the allowed tags list
  5391.  * Since version 1.1, this function uses htmlspecialchars instead of
  5392.  * htmlentities, for international support
  5393.  * This function has been replaced by functionality in {@link ParserDescCleanup.inc}
  5394.  * @param string $s 
  5395.  * @return string browser-displayable page
  5396.  * @deprecated As of v1.2, No longer needed, as valid tags are parsed out of the source,
  5397.  *    and everything else is {@link Converter::postProcess()} handled
  5398.  */
  5399. function adv_htmlentities($s)
  5400. {
  5401.     return;
  5402.     global $phpDocumentor___html,$_phpDocumentor_html_allowed;
  5403.     $result htmlspecialchars($s);
  5404.     $entities array_flip(get_html_translation_table(HTML_SPECIALCHARS));
  5405.     $result strtr($result,$phpDocumentor___html);
  5406.     $matches = array();
  5407.     preg_match_all('/(&lt;img.*&gt;)/U',$result,$matches);
  5408.     for($i=0;$i<count($matches[1]);$i++)
  5409.     {
  5410.         $result str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5411.     }
  5412.     preg_match_all('/(&lt;font.*&gt;)/U',$result,$matches);
  5413.     for($i=0;$i<count($matches[1]);$i++)
  5414.     {
  5415.         $result str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5416.     }
  5417.     preg_match_all('/(&lt;ol.*&gt;)/U',$result,$matches);
  5418.     for($i=0;$i<count($matches[1]);$i++)
  5419.     {
  5420.         $result str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5421.     }
  5422.     preg_match_all('/(&lt;ul.*&gt;)/U',$result,$matches);
  5423.     for($i=0;$i<count($matches[1]);$i++)
  5424.     {
  5425.         $result str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5426.     }
  5427.     preg_match_all('/(&lt;li.*&gt;)/U',$result,$matches);
  5428.     for($i=0;$i<count($matches[1]);$i++)
  5429.     {
  5430.         $result str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5431.     }
  5432.     preg_match_all('/(&lt;a .*&gt;)/U',$result,$matches);
  5433.     for($i=0;$i<count($matches[1]);$i++)
  5434.     {
  5435.         $result str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5436.     }
  5437.     return $result;
  5438. }
  5439.  
  5440. /**
  5441.  * Used solely for setting up the @uses list
  5442.  * @package ignore
  5443.  * @ignore
  5444.  */
  5445. class __dummyConverter extends Converter
  5446. {
  5447.     function setTemplateDir(){}
  5448.     function setTargetDir(){}
  5449.     function getPageName(&$element)
  5450.     {
  5451.         if (phpDocumentor_get_class($element== 'parserpage'return '_'.$element->getName();
  5452.         return '_'.$element->parent->getName();
  5453.     }
  5454. }
  5455. ?>

Documentation generated on Mon, 11 Mar 2019 15:18:56 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.