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 287891 2009-08-30 08:08:00Z ashnazg $
  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 287891 2009-08-30 08:08:00Z ashnazg $
  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[$a1;
  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($base1!= 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[$pathtrue;
  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.