home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / IntermediateParser.inc < prev    next >
Encoding:
Text File  |  2004-03-24  |  69.5 KB  |  1,758 lines

  1. <?php
  2. //
  3. // +------------------------------------------------------------------------+
  4. // | phpDocumentor                                                          |
  5. // +------------------------------------------------------------------------+
  6. // | Copyright (c) 2000-2003 Joshua Eichorn, Gregory Beaver                 |
  7. // | Email         jeichorn@phpdoc.org, cellog@phpdoc.org                   |
  8. // | Web           http://www.phpdoc.org                                    |
  9. // | Mirror        http://phpdocu.sourceforge.net/                          |
  10. // | PEAR          http://pear.php.net/package-info.php?pacid=137           |
  11. // +------------------------------------------------------------------------+
  12. // | This source file is subject to version 3.00 of the PHP License,        |
  13. // | that is available at http://www.php.net/license/3_0.txt.               |
  14. // | If you did not receive a copy of the PHP license and are unable to     |
  15. // | obtain it through the world-wide-web, please send a note to            |
  16. // | license@php.net so we can mail you a copy immediately.                 |
  17. // +------------------------------------------------------------------------+
  18. //
  19.  
  20. /** The phpDocumentor_IntermediateParser Class
  21.  *
  22.  *  The Intermediary Data Parser (intermediate between Parse and Converter)
  23.  *
  24.  *  @author Gregory Beaver
  25.  *  @version $Revision: 1.1.2.4 $
  26.  *  @copyright 2002 Gregory Beaver
  27.  *  @package     phpDocumentor
  28.  */
  29. /** The phpDocumentor_IntermediateParser Class
  30.  *
  31.  * This class performs the work of organizing raw data from the parser in the
  32.  * format of descendants of the {@link parserElement} class.  This is also where
  33.  * processing of package pages occurs, in
  34.  * {@link phpDocumentor_IntermediateParser::handleClass()} for class-level
  35.  * packages and {@link phpDocumentor_IntermediateParser::handleDocBlock()} for
  36.  * page-level packages.
  37.  *
  38.  * Most of the work of this parser goes to matching up
  39.  * DocBlocks with the elements that they are documenting.  Since DocBlocks are
  40.  * passed before the element they document, the last DocBlock is stored in
  41.  * {@link phpDocumentor_IntermediateParser::$last} and then placed into the
  42.  * $docblock parameter of the parserElement
  43.  * descendant object.
  44.  *  @author Gregory Beaver
  45.  *  @version $Id: pear-IntermediateParser.inc,v 1.1.2.4 2003/08/13 20:23:45 CelloG Exp $
  46.  *  @copyright 2002 Gregory Beaver
  47.  *  @package     phpDocumentor
  48.  */
  49. class phpDocumentor_IntermediateParser
  50. {
  51.     /**
  52.      * @var parserDocBlock
  53.      */
  54.     var $last;
  55.     
  56.     /**
  57.      * type of the last parser Element handled
  58.      *
  59.      * This is used in handleDocBlock to determine whether a DocBlock is a
  60.      * page-level DocBlock in conjunction with the {@link parserData::$clean}
  61.      * var.  A page-level DocBlock is alwaysthe first DocBlock in a file, and
  62.      * must be followed by another DocBlock.  The first test is handled by
  63.      * parserData::$clean, which is set to false on the first encounter of an
  64.      * element, and the second test is handled by this variable, which must be
  65.      * equal to "docblock"
  66.      * @see handleDocBlock()
  67.      * @var string
  68.      */
  69.     var $lasttype = '';
  70.     
  71.     /**
  72.      * Name of the class currently being parsed.
  73.      * It is only used (and only valid) when phpDocumentor_IntermediateParser is
  74.      * parsing a class
  75.      * @var string
  76.      */
  77.     var $cur_class = '';
  78.     
  79.     /**
  80.      * type of the current parser Element being handled
  81.      * 
  82.      * This is used by {@link HandleEvent()} to set the {@link $lasttype} var,
  83.      * which is used to detect page-level DocBlocks
  84.      * @var string
  85.      */
  86.     var $type = '';
  87.     
  88.     /**
  89.      * set in {@link Setup.inc.php} to the value of the parseprivate commandline
  90.      * option.  If this option is true, elements with an @access private tag
  91.      * will be parsed and displayed
  92.      * @tutorial phpDocumentor.howto.pkg#using.command-line.parseprivate
  93.      * @var boolean
  94.      */
  95.     var $parsePrivate = false;
  96.     
  97.     /**
  98.      * this variable is used to prevent parsing of elements with an @ignore tag
  99.      * @see $packageoutput
  100.      * @see $parsePrivate
  101.      */
  102.     var $private_class = false;
  103.     
  104.     /**
  105.      * used to set the output directory
  106.      * @see setTargetDir()
  107.      */
  108.     var $targetDir;
  109.     
  110.     /**
  111.      * used to set the template base directory
  112.      * @see setTemplateBase()
  113.      */
  114.     var $templateBase;
  115.     
  116.     /**
  117.      * array of parsed package pages
  118.      *
  119.      * used by {@link Convert()} to convert all package pages into output
  120.      * @var array
  121.      */
  122.     var $package_pages = array();
  123.     
  124.     /**
  125.      * @var array array of all {@link parserData} containing page information
  126.      */
  127.     var $pages = array();
  128.     /**
  129.      * Put away a page that has been @ignored or @access private if
  130.      * !{@link $parsePrivate}
  131.      *
  132.      * When a page has @access private in its DocBlock, it is placed here
  133.      * instead of in {@link $pages}, to allow for proper Class parsing.  Since
  134.      * classes and pages are parsed as if they were separate, this array allows
  135.      * public classes on private pages to retrieve information needed about the
  136.      * page that holds the class and to {@link addPageIfNecessary()} to the
  137.      * $pages array
  138.      * @var array
  139.      */
  140.     var $privatepages = array();
  141.     /**
  142.      * Keeps track of packages of classes that have parent classes in another
  143.      * package.  Used in automatic linking.
  144.      *
  145.      * This array is updated by {@link addPackageParent()}, which is called in
  146.      * {@link Classes::processChild()} to keep track of classes that descend
  147.      * from classes in different packages.  In other words, if class foo is in
  148.      * package one, and class bar is in package two, an entry
  149.      * $package_parents['two'] = 'one' will be made.
  150.      * @var array Format: packagename => parentpackagename
  151.      * @see Converter::getLink()
  152.      */
  153.     var $package_parents = array();
  154.     
  155.     /**
  156.      * Used to determine the category for tutorials.
  157.      *
  158.      * <b>WARNING:</b> If more than one category exists, the last category
  159.      * encountered will overwrite the previous and will raise a big warning
  160.      * @var array Format: packagename => categoryname
  161.      */
  162.     var $packagecategories = array();
  163.     
  164.     /**
  165.      * list of all packages encountered while documenting.  Used in automatic
  166.      * linking.
  167.      * 
  168.      * Converter::getLink() first checks if an ambiguous link is found in the
  169.      * current package.  If not, it then checks in parent packages, and if still
  170.      * not found, uses this array to check in the rest of the packages before
  171.      * giving up
  172.      * @var array Format: array(packagename => 1, packagename => 1,...)
  173.      * @see Converter::getLink()
  174.      */
  175.     var $all_packages = array();
  176.     
  177.     /**
  178.      * array of packages to parser and output documentation for, if not all
  179.      * packages should be documented
  180.      *
  181.      * Format:<br />
  182.      * array(package1,package2,...)<br />
  183.      * or false if not set
  184.      *
  185.      * Use this option to limit output similar to ignoring files.  If you have
  186.      * some temporary files that you don't want to specify by name but don't
  187.      * want included in output, set a package name for all the elements in your
  188.      * project, and set packageoutput to that name.  the default package will be
  189.      * ignored.  Parsing speed does not improve.  If you want to ignore files
  190.      * for speed reasons, use the ignore command-line option
  191.      * @tutorial phpDocumentor.howto.pkg#using.command-line.packageoutput
  192.      * @see Io
  193.      * @var false|array
  194.      */
  195.     var $packageoutput = false;
  196.     
  197.     /**
  198.      * the functions which handle output from the {@link Parser}
  199.      * @see handleEvent(), handleDocBlock(), handlePage(), handleClass()
  200.      * @see handleDefine(), handleFunction(), handleMethod(), handleVar()
  201.      * @see handlePackagePage(), handleInclude(), handleTutorial()
  202.      */
  203.     var $event_handlers = array(
  204.             'docblock' => 'handleDocBlock',
  205.             'page' => 'handlePage',
  206.             'class' => 'handleClass',
  207.             'define' => 'handleDefine',
  208.             'function' => 'handleFunction',
  209.             'method' => 'handleMethod',
  210.             'var' => 'handleVar',
  211.             'packagepage' => 'handlePackagePage',
  212.             'include' => 'handleInclude',
  213.             'global' => 'handleGlobal',
  214.             'tutorial' => 'handleTutorial',
  215.             );
  216.     
  217.     /**
  218.      * $data contains parsed structures for the current page being parsed
  219.      *
  220.      * In version 1.1+, $data is only used to store the current page information.
  221.      * All handling of documented elements is handled by the
  222.      * {@link ProceduralPages} and {@link Classes} classes.
  223.      * @var parserData
  224.      */
  225.     var $data;
  226.     
  227.     /**
  228.      * set in {@link Setup.inc.php} to the value of the quitemode commandline
  229.      * option.
  230.      *
  231.      * If this option is true, informative output while parsing will not be
  232.      * displayed (documentation is unaffected)
  233.      * @var boolean
  234.      * @tutorial phpDocumentor.howto.pkg#using.command-line.quiet
  235.      */
  236.     var $quietMode = false;
  237.     
  238.     /**
  239.      * used to keep track of inheritance at the smartest level possible for a
  240.      * dumb computer
  241.      * @var Classes
  242.      */
  243.     var $classes = false;
  244.     
  245.     /**
  246.      * used to keep track of all elements in a procedural page.  Handles name
  247.      * conflicts with elegance
  248.      * @since 1.1
  249.      * @var ProceduralPages
  250.      */
  251.     var $proceduralpages = false;
  252.     
  253.     /**
  254.      * an array of template names indexed by converter name
  255.      *
  256.      * For example, if the default HTMLframesConverter is using the DOM/l0l33t
  257.      * template, the array will be
  258.      * <code>$converters['frames'] = 'DOM/l0l33t'</code>
  259.      * @var array Format: array(Convertername1 => templatename)
  260.      * @see Converter
  261.      */
  262.     var $converters = false;
  263.     /** 
  264.      * @var string Title of generated documentation, passed to Converters
  265.      */
  266.     var $title = '';
  267.     
  268.     var $uses = array();
  269.  
  270.     var $db_template;
  271.     
  272.     /**
  273.      * Stores parsed CHANGELOG/INSTALL/README files
  274.      * @var array Format: array(CHANGELOG => contents,
  275.      *                          INSTALL => contents,
  276.      *                          README => contents)
  277.      */
  278.     var $ric = array();
  279.     
  280.     /**
  281.      * Flag used to determine whether the last docblock
  282.      * was a page-level docblock.
  283.      * @var boolean
  284.      * @access private
  285.      */
  286.     var $_lastDocBlockWasPageLevel = false;
  287.     
  288.     /**
  289.      * Flag used to determine whether the Page-level
  290.      * DocBlock was declared in old or new style
  291.      * @var boolean
  292.      * @access private
  293.      */
  294.     var $_oldPageLevel = false;
  295.  
  296.     /**
  297.      * sets up basic data structures
  298.      * @param string Title of generated documentation, passed to Converters
  299.      * @see $title, $data, $classes, $proceduralpages
  300.      */
  301.     function phpDocumentor_IntermediateParser($title='Generated Documentation')
  302.     {
  303.         $this->title = $title;
  304.         $this->data = new parserData;
  305.         $this->classes = new Classes;
  306.         $this->proceduralpages = new ProceduralPages;
  307.     }
  308.     
  309.     /**
  310.      * Retrieve the relative path.  If the path contains "pear/" it will
  311.      * be used as the base, otherwise the Program_Root string will be used.
  312.      * @global array uses 'Program_Root' option to replace it with '' for
  313.      *               retrieving the source location of a file
  314.      * @param string path to file
  315.      * @return string
  316.      * @see $sourceLocation
  317.      * @access private
  318.      */
  319.     function _getSourceLocation($sl, $sourceloc)
  320.     {
  321.         global $_phpDocumentor_options;
  322.         if (empty($sl)) return false;
  323.         $sl = str_replace('\\','/',$sl);
  324.         if (strpos($sl,'pear/'))
  325.         {
  326.             $sl = substr($sl,strpos($sl,'pear/') + 5);
  327.             if (dirname($sl) == '.')
  328.             {
  329.                 return 'PEAR';
  330.             }
  331.             return dirname($sl);
  332.         } else
  333.         {
  334.             if (strpos(str_replace($_phpDocumentor_options['Program_Root'] . PATH_DELIMITER,'',$sourceloc),PATH_DELIMITER) === false)
  335.                 return '';
  336.             return dirname(str_replace($_phpDocumentor_options['Program_Root'] . PATH_DELIMITER,'',$sourceloc));
  337.         }
  338.     }
  339.     
  340.     /**
  341.      * Guess the package/subpackage based on subdirectory if the --pear option
  342.      *
  343.      * A file in pear/dir/file.php will be in package "dir."  A file in
  344.      * pear/dir/subdir/file.php will be in package "dir," subpackage "subdir."
  345.      * @param string full path of file
  346.      * @param template-ready source location Program_Root/dir/file.php
  347.      * @global array uses the 'pear' option to determine whether to guess based
  348.      *               on subdirectory
  349.      * @tutorial phpDocumentor.howto.pkg#using.command-line.pear
  350.      */
  351.     function _guessPackage($path, $sourceloc)
  352.     {
  353.         global $_phpDocumentor_setting;
  354.         if ($_phpDocumentor_setting['pear'])
  355.         {
  356.             $subpath = explode(PATH_DELIMITER, $this->_getSourceLocation($path, $sourceloc));
  357.             if (!empty($subpath[0]))
  358.             { // can only have package and subpackage in this version
  359.                 $package = $subpath[0];
  360.                 $subpackage = '';
  361.                 if (isset($subpath[1])) $subpackage = $subpath[1];
  362.                 return array($package,$subpackage);
  363.             } else return array($this->package, $this->subpackage);
  364.         } else return array($this->package, $this->subpackage);
  365.     }
  366.     
  367.     /**
  368.      * handles post-parsing of include/require/include_once/include_once
  369.      *
  370.      * This function sets {@link $data}->clean to false to tell the
  371.      * phpDocumentor_IntermediateParser that a page-level DocBlock can't be
  372.      * found after this point on this page.  It then sets the package
  373.      * to be the same as the page, and adds itself to the
  374.      * {@link ProceduralPages} class
  375.      * @param integer $event Event number from {@link Parser.inc}
  376.      * @param parserInclude $data
  377.      */
  378.     function handleInclude($event,$data)
  379.     {
  380.         if ($this->_lastDocBlockWasPageLevel)
  381.         {
  382.             addWarning(PDERROR_DOCBLOCK_CONFLICT, $data->getName(), $data->getFile());
  383.             if (!$this->_oldPageLevel)
  384.             {
  385.                 unset($this->last);
  386.             }
  387.         }
  388.         $this->_lastDocBlockWasPageLevel =
  389.         $this->data->clean = false;
  390.         // page was @ignored
  391.         if ($this->private_page)
  392.         {
  393.             unset($this->last);
  394.             return;
  395.         }
  396.         if (empty($this->last))
  397.         {
  398.             if (isset($this->db_template))
  399.             // use the docblock template
  400.             $this->last = $this->db_template;
  401.             else
  402.             // we don't have a docblock, create an empty one to get rid of errors
  403.             $this->last = new parserDocblock();
  404.         }
  405. //        $this->last->setLineNumber($data->getLineNumber());
  406.         if ($this->last->getKeyword('ignore'))
  407.         {
  408.             $this->last = false;
  409.             return;
  410. //            addWarning(PDERROR_IGNORE_TAG_IGNORED,'include',$data->getName().'('.$data->getValue().')');
  411.         }
  412.  
  413.         $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'include');
  414.         $data->setDocBlock($this->last);
  415.         $this->proceduralpages->addInclude($data);
  416.         $this->last = false;
  417.     }
  418.     
  419.     /**
  420.      * handles post-parsing of global variables
  421.      *
  422.      * This function sets {@link $data}->clean to false to tell the
  423.      * phpDocumentor_IntermediateParser that a page-level DocBlock can't be
  424.      * found after this point on this page.  It then sets the package
  425.      * to be the same as the page, and adds itself to the
  426.      * {@link ProceduralPages} class
  427.      * @param integer $event Event number from {@link Parser.inc}
  428.      * @param parserGlobal $data
  429.      */
  430.     function handleGlobal($event,$data)
  431.     {
  432.         if ($this->_lastDocBlockWasPageLevel)
  433.         {
  434.             addWarning(PDERROR_DOCBLOCK_CONFLICT, 'global variable', $data->getName());
  435.             if (!$this->_oldPageLevel)
  436.             {
  437.                 unset($this->last);
  438.             }
  439.         }
  440.         $this->_lastDocBlockWasPageLevel =
  441.         $this->data->clean = false;
  442.         if ($this->private_page)
  443.         {
  444.             unset($this->last);
  445.             return;
  446.         }
  447.         if (empty($this->last))
  448.         {
  449.             if (isset($this->db_template))
  450.             // use the docblock template
  451.             $this->last = $this->db_template;
  452.             else
  453.             // we don't have a docblock, create an empty one to get rid of errors
  454.             $this->last = new parserDocblock();
  455.         }
  456. //        $this->last->setLineNumber($data->getLineNumber());
  457.         if ($this->last->getKeyword('ignore'))
  458.         {
  459.             addWarning(PDERROR_IGNORE_TAG_IGNORED,'global variable - just don\'t document the',$data->getName());
  460.             $this->last = false;
  461.             return;
  462.         }
  463.         $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'global');
  464.         $data->setDocBlock($this->last);
  465.         if ($data->docblock->getKeyword('name'))
  466.         {
  467.             $a = $data->docblock->getKeyword('name');
  468.             $data->setName($a->value);
  469.         }
  470.         $this->proceduralpages->addGlobal($data);
  471.         $this->last = false;
  472.     }
  473.     
  474.     /**
  475.      * handles post-parsing of Package-level documentation pages.
  476.      *
  477.      * sets the {@link $package_pages}[$data->package] to $data
  478.      * @param integer $event Event number from {@link Parser.inc}
  479.      * @param parserPackagePage $data
  480.      */
  481.     function handlePackagePage($event,$data)
  482.     {
  483.         $this->package_pages[$data->package] = &$data;
  484.         $this->last = false;
  485.     }
  486.     
  487.     /**
  488.      * handle post-parsing of Tutorials.
  489.      *
  490.      * This adds the parsed tutorial to the tutorial tree
  491.      * @uses $tutorials sets the value of tutorials to parameter $data
  492.      * @param integer $event Event Number
  493.      * @param parserTutorial $data
  494.      * @since 1.2
  495.      */
  496.     function handleTutorial($event,$data)
  497.     {
  498.         if (isset($this->packagecategories[$data->package]))
  499.         {
  500.             $data->category = $this->packagecategories[$data->package];
  501.         } else
  502.         {
  503.             $data->category = $GLOBALS['phpDocumentor_DefaultCategoryName'];
  504.         }
  505.         $this->tutorials[$data->package][$data->subpackage][$data->tutorial_type][$data->name] = $data;
  506.     }
  507.     
  508.     /**
  509.      * handles post-parsing of class vars
  510.      *
  511.      * This function sets up a @var tag if none is found, and aligns $data's
  512.      * $path var and packages to match the parent object
  513.      * @param integer $event Event number from {@link Parser.inc}
  514.      * @param parserVar $data
  515.      */
  516.     function handleVar($event,$data)
  517.     {
  518.         global $_phpDocumentor_setting;
  519.         if ($this->private_class)
  520.         {
  521.             unset($this->last);
  522.             return;
  523.         }
  524.         if (empty($this->last))
  525.         {
  526.             if (isset($this->db_template))
  527.             // use the docblock template
  528.             $this->last = $this->db_template;
  529.             else
  530.             // we don't have a docblock, create an empty one to get rid of errors
  531.             $this->last = new parserDocblock();
  532.         }
  533. //        $this->last->setLineNumber($data->getLineNumber());
  534.         $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'var');
  535.  
  536.         if ($this->last->getKeyword('ignore'))
  537.         {
  538.             $this->last = false;
  539.             return;
  540. //            addWarning(PDERROR_IGNORE_TAG_IGNORED,'var',$this->cur_class.'::'.$data->getName());
  541.         }
  542.         if (!$this->last->var)
  543.         {
  544.             $this->last->addVar('mixed',new parserStringWithInlineTags);
  545.         }
  546.         
  547.         if ($_phpDocumentor_setting['pear'])
  548.         {
  549.             if (strpos($data->getName(), '_') == 1 && !$this->last->getKeyword('access'))
  550.             {
  551.                 addWarning(PDERROR_PRIVATE_ASSUMED,'class variable',$data->class.'::'.$data->getName());
  552.                 $this->last->addKeyword('access','private');
  553.                 $data->setDocBlock($this->last);
  554.             }
  555.         }
  556.         $data->setDocBlock($this->last);
  557.         $data->path = $this->data->parent->path;
  558.         $this->classes->addVar($data);
  559.         $this->last = false;
  560.     }
  561.     
  562.     /**
  563.      * handles post-parsing of class methods
  564.      *
  565.      * This function first aligns $data's path and package to match the parent
  566.      * object, and also aligns the docblock's @param, @global, and @staticvar
  567.      * tags with the information parsed from the method source code.  It also
  568.      * checks to see if the method is a constructor and sets the $isConstructor
  569.      * flag.  If source code has been parsed by a {@}source} tag, the source is
  570.      * added to its docblock
  571.      *
  572.      * Finally, it adds the method to the {@link Classes} class.
  573.      * @param integer $event Event number from {@link Parser.inc}
  574.      * @param parserMethod $data
  575.      */
  576.     function handleMethod($event,$data)
  577.     {
  578.         global $_phpDocumentor_setting;
  579.         if ($this->private_class)
  580.         {
  581.             unset($this->last);
  582.             return;
  583.         }
  584.  
  585.         if (empty($this->last))
  586.         {
  587.             if (isset($this->db_template))
  588.             // use the docblock template
  589.             $this->last = $this->db_template;
  590.             else
  591.             // we don't have a docblock, create an empty one to get rid of errors
  592.             $this->last = new parserDocblock();
  593.         }
  594. //        $this->last->setLineNumber($data->getLineNumber());
  595.         if ($this->last->getKeyword('ignore'))
  596.         {
  597.             $this->last = false;
  598.             return;
  599. //            addWarning(PDERROR_IGNORE_TAG_IGNORED,'method',$this->cur_class.'::'.$data->getName());
  600.         }
  601.         $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'method');
  602.         if ($data->hasSource())
  603.         {
  604.             $this->last->setSource($data->getSource(), $data->getClass());
  605.         }
  606.         foreach($data->listParams() as $param)
  607.         {
  608.             $update_params[] = $param[0];
  609.         }
  610.         foreach($data->listGlobals() as $param)
  611.         {
  612.             $update_globals[] = $param[1];
  613.         }
  614.         foreach($data->listStatics() as $param)
  615.         {
  616.             $update_statics[] = $param[0];
  617.         }
  618.         if (isset($update_params))
  619.         $this->last->updateParams($update_params);
  620.         if (isset($update_globals))
  621.         $this->last->updateGlobals($update_globals);
  622.         if (isset($update_statics))
  623.         $this->last->updateStatics($update_statics);
  624.         unset($update_params);
  625.         unset($update_globals);
  626.         unset($update_statics);
  627.  
  628.         if ($data->getName() == $this->cur_class) $data->setConstructor();
  629.  
  630.         if ($_phpDocumentor_setting['pear'])
  631.         {
  632.             if (strpos($data->getName(), '_') === 0 && substr($data->getName(), 1) == $data->class)
  633.             { // is destructor
  634.                 $data->setDestructor();
  635.             } elseif (strpos($data->getName(), '_') === 0 && !$this->last->getKeyword('access'))
  636.             {
  637.                 addWarning(PDERROR_PRIVATE_ASSUMED,'method',$data->class.'::'.$data->getName().'()');
  638.                 $this->last->addKeyword('access','private');
  639.                 $data->setDocBlock($this->last);
  640.             }
  641.         }
  642.         $data->setDocBlock($this->last);
  643.         $data->path = $this->data->parent->path;
  644.         $this->classes->addMethod($data);
  645.         $this->last = false;
  646.     }
  647.  
  648.     /**
  649.      * handles post-parsing of functions
  650.      *
  651.      * This function sets {@link $data}->clean to false to tell the
  652.      * phpDocumentor_IntermediateParser that a page-level DocBlock can't be
  653.      * found after this point on this page.  It then sets the package to be the
  654.      * same as the page, aligns the docblock's @param, @global, and @staticvar
  655.      * tags with the information parsed from the function source code.
  656.      *
  657.      * If source code has been parsed by a {@}source} tag, the source is added
  658.      * to its docblock, and then the parserFunction adds itself to the
  659.      * {@link ProceduralPages} class
  660.      * @param integer $event Event number from {@link Parser.inc}
  661.      * @param parserFunction $data
  662.      */
  663.     function handleFunction($event,$data)
  664.     {
  665.         if ($this->_lastDocBlockWasPageLevel)
  666.         {
  667.             addWarning(PDERROR_DOCBLOCK_CONFLICT, 'function', $data->getName());
  668.             if (!$this->_oldPageLevel)
  669.             {
  670.                 unset($this->last);
  671.             }
  672.         }
  673.         $this->_lastDocBlockWasPageLevel =
  674.         $this->data->clean = false;
  675.         if ($this->private_page)
  676.         {
  677.             unset($this->last);
  678.             return;
  679.         }
  680.  
  681.         if (empty($this->last))
  682.         {
  683.             if (isset($this->db_template))
  684.             // use the docblock template
  685.             $this->last = $this->db_template;
  686.             else
  687.             // we don't have a docblock, create an empty one to get rid of errors
  688.             $this->last = new parserDocblock();
  689.         }
  690. //        $this->last->setLineNumber($data->getLineNumber());
  691.         if ($this->last->getKeyword('ignore'))
  692.         {
  693.             unset($this->last);
  694.             return;
  695.         }
  696.         $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'function');
  697.  
  698.         foreach($data->listParams() as $param)
  699.         {
  700.             $update_params[] = $param[0];
  701.         }
  702.         foreach($data->listGlobals() as $param)
  703.         {
  704.             $update_globals[] = $param[1];
  705.         }
  706.         foreach($data->listStatics() as $param)
  707.         {
  708.             $update_statics[] = $param[0];
  709.         }
  710.         if (isset($update_params))
  711.         $this->last->updateParams($update_params);
  712.         if (isset($update_globals))
  713.         $this->last->updateGlobals($update_globals);
  714.         if (isset($update_statics))
  715.         $this->last->updateStatics($update_statics);
  716.         unset($update_params);
  717.         unset($update_globals);
  718.         unset($update_statics);
  719.  
  720.         if ($data->hasSource())
  721.         {
  722.             $this->last->setSource($data->getSource());
  723.         }
  724.         if (count($this->last->params) == 1 && !count($data->listParams()))
  725.         {
  726.             // if the function has no parameters, and 1 @param, add it to the list as optional, default value is description from @param
  727.             $pars = $this->last->listParams();
  728.             $data->addParam($pars[0]['var'],$pars[0]['data']->getString());
  729.         }
  730.         $data->setDocBlock($this->last);
  731.         $this->proceduralpages->addFunction($data);
  732.         $this->last = false;
  733.     }
  734.     
  735.     /**
  736.      * handles post-parsing of defines
  737.      *
  738.      * This function sets {@link $data}->clean to false to tell the
  739.      * phpDocumentor_IntermediateParser that a page-level DocBlock can't be
  740.      * found after this point on this page.  It then sets the package to be the
  741.      * same as the page and adds itself to the {@link ProceduralPages} class
  742.      * @param integer $event Event number from {@link Parser.inc}
  743.      * @param parserDefine $data
  744.      */
  745.     function handleDefine($event,$data)
  746.     {
  747.         if ($this->_lastDocBlockWasPageLevel)
  748.         {
  749.             addWarning(PDERROR_DOCBLOCK_CONFLICT, 'define', $data->getName());
  750.             if (!$this->_oldPageLevel)
  751.             {
  752.                 unset($this->last);
  753.             }
  754.         }
  755.         $this->_lastDocBlockWasPageLevel =
  756.         $this->data->clean = false;
  757.         if ($this->private_page)
  758.         {
  759.             unset($this->last);
  760.             return;
  761.         }
  762.         if (empty($this->last))
  763.         {
  764.             if (isset($this->db_template))
  765.             // use the docblock template
  766.             $this->last = $this->db_template;
  767.             else
  768.             // we don't have a docblock, create an empty one to get rid of errors
  769.             $this->last = new parserDocblock();
  770.         }
  771. //        $this->last->setLineNumber($data->getLineNumber());
  772.         if ($this->last->getKeyword('ignore'))
  773.         {
  774.             unset($this->last);
  775.             return;
  776.         }
  777.  
  778.         $this->last->overridePackage($this->category,$this->package,$this->subpackage,$data->getName(),'define');
  779.         $data->setDocBlock($this->last);
  780.         $this->proceduralpages->addDefine($data);
  781.         $this->last = false;
  782.     }
  783.     
  784.     /**
  785.      * handles post-parsing of classes
  786.      *
  787.      * This function sets {@link $data}->clean to false to tell the
  788.      * phpDocumentor_IntermediateParser that a page-level DocBlock can't be
  789.      * found after this point on this page.  It sets {@link $cur_class} to its
  790.      * name, and if an @ignore tag is found in the DocBlock, it sets
  791.      * {@link $private_class} to true, to prevent post-parsing of any of the
  792.      * class's vars or methods.  Then it checks for the existence of a package
  793.      * page for the class's package
  794.      * @param integer $event Event number from {@link Parser.inc}
  795.      * @param parserClass $data
  796.      */
  797.     function handleClass($event,$data)
  798.     {
  799.         if ($this->_lastDocBlockWasPageLevel)
  800.         {
  801.             if (!$this->_oldPageLevel)
  802.             {
  803.                 addWarning(PDERROR_DOCBLOCK_GOES_CLASS, $data->getName());
  804.                 $doc = new parserDocBlock;
  805.                 $doc->category = $this->category;
  806.                 $doc->package = $this->package;
  807.                 $doc->subpackage = $this->subpackage;
  808.                 $this->data->setDocBlock($doc);
  809.                 unset($doc);
  810.             }
  811.         }
  812.         $this->_lastDocBlockWasPageLevel =
  813.         $this->data->clean = false;
  814.         if (empty($this->last))
  815.         {
  816.             if (isset($this->db_template))
  817.             // use the docblock template
  818.             $this->last = $this->db_template;
  819.             else
  820.             // we don't have a docblock, create an empty one to get rid of errors
  821.             $this->last = new parserDocblock();
  822.             list($this->last->package, $this->last->subpackage) = $this->_guessPackage($this->data->parent->path, $this->data->parent->getSourceLocation('dummy'));
  823.             addWarning(PDERROR_NO_PACKAGE_TAG,'class',$data->getName(),$this->last->package);
  824.         } else
  825.         {
  826.             if (!$this->last->getExplicitPackage())
  827.             {
  828.                 list($this->last->package, $this->last->subpackage) = $this->_guessPackage($this->data->parent->path, $this->data->parent->getSourceLocation('dummy'));
  829.                 addWarning(PDERROR_NO_PACKAGE_TAG,'class',$data->getName(),$this->last->package);
  830.             } else
  831.             {
  832.                 if (isset($this->packagecategories[$this->package])
  833.                     && $this->packagecategories[$this->package] != $this->category)
  834.                     addWarning(PDERROR_PACKAGECAT_SET,$this->package,
  835.                                 $this->packagecategories[$this->package],
  836.                                 $this->category);
  837.                 $this->packagecategories[$this->package] = $this->category;
  838.             }
  839.         }
  840.         
  841. //        $this->last->setLineNumber($data->getLineNumber());
  842.         $data->setDocBlock($this->last);
  843.         $this->cur_class = $name = $data->getName();
  844.         if ($this->last->getKeyword('ignore'))
  845.         {
  846.             $this->private_class = true;
  847.             unset($this->last);
  848.             return;
  849.         }
  850.         $data->path = $this->data->parent->path;
  851.         $this->classes->addClass($data);
  852.         $this->private_class = false;
  853.         if ($this->last->package)
  854.         {
  855.             $this->parsePackagePage($this->last->package, $this->data->parent->getPath());
  856.         }
  857.         $this->last = false;
  858.     }
  859.     
  860.     /**
  861.      * handles post-parsing of procedural pages
  862.      *
  863.      * this event is called at the start of a new page, before the Parser knows
  864.      * whether the page will contain any procedural pages or not
  865.      * @param integer $event Event number from {@link Parser.inc}
  866.      * @param parserPage $data
  867.      */
  868.     function handlePage($event,$data)
  869.     {
  870.         $type = 'page';
  871.         $this->private_page = false;
  872.         $this->data = new parserData;
  873.         $data->category = $this->category = $GLOBALS['phpDocumentor_DefaultCategoryName'];
  874.         $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
  875.         $this->subpackage = '';
  876.         $this->proceduralpages->addPage($data);
  877.         $this->data->setParent($data);
  878.         $this->pages[$data->getPath()] = $this->data;
  879.         $this->classes->nextFile($data->getPath());
  880.         $this->packageoutput = $data->getPackageOutput();
  881.     }
  882.     
  883.     /**
  884.      * handles post-parsing of DocBlocks
  885.      *
  886.      * This function sets {@link $last} to the DocBlock represented by $data, to
  887.      * allow the next documentable element passed to
  888.      * phpDocumentor_IntermediateParser to link the DocBlock into its $docblock
  889.      * property.  This function also checks for two special cases of DocBlocks:
  890.      * <ol>
  891.      *    <li>First DocBlock in the file contains a @package tag</li>
  892.      *    <li>First DocBlock in the file is immediately followed by another
  893.      *        DocBlock</li>
  894.      * </ol>
  895.      * In both cases, the function extracts this tag and uses it as the
  896.      * page-level package.  If the @package tag is in the DocBlock of an
  897.      * element (function, global variable, whatever) that isn't a page-level
  898.      * DocBlock, a warning will be raised to notify the author that a @package
  899.      * tag belongs in a page-level DocBlock.
  900.      *
  901.      * <b>New</b> in version 1.2.2, if the first DocBlock in a file contains
  902.      * a @package tag, it is a page-level DocBlock.
  903.      *
  904.      * If the DocBlock is page-level, it is processed with
  905.      * {@link _processPageLevelDocBlock}
  906.      *
  907.      * Finally, the function replaces the old parserPage in
  908.      * {@link parserData::$data}->parent with the new one containing information
  909.      * from the DocBlock by calling {@link addPage()}, and checks for
  910.      * package-level docs.
  911.      * @param integer $event Event number from {@link Parser.inc}
  912.      * @param parserDocBlock $data
  913.      */
  914.     function handleDocBlock($event,$data)
  915.     {
  916.         $type = 'docblock';
  917.         $data->postProcess();
  918.         // Zend desc support
  919.         if ($tdesc = $data->getKeyword('desc'))
  920.         {
  921.             $data->setShortDesc($tdesc);
  922.             unset($data->tags['desc']);
  923.         }
  924.         $this->_lastDocBlockWasPageLevel = false;
  925.         // 1st docblock in file, check for @package
  926.         if ($this->data->isClean() && !isset($this->last))
  927.         {
  928.             if ($data->getExplicitPackage())
  929.             {
  930.                 // new with 1.2.2:
  931.                 // if the first docblock in a file
  932.                 // contains a @package tag, then it is
  933.                 // a page-level docblock
  934.                 $this->_processPageLevelDocBlock($data);
  935.                 $this->_lastDocBlockWasPageLevel = true;
  936.                 $this->all_packages[$data->package] = 1;
  937.                 $this->last = $data;
  938.                 return;
  939.             }
  940.             $doc = new parserDocBlock;
  941.             $doc->category = $this->category;
  942.             $doc->package = $this->package;
  943.             $doc->subpackage = $this->subpackage;
  944.             $this->data->setDocBlock($doc);
  945.             $this->proceduralpages->addPagePackage($this->data->parent->getPath(),$this->package,$this->subpackage);
  946.             unset($doc);
  947.         }
  948.         // 2nd docblock in a row, and it's at the top of the file, page-level docblock
  949.         if ($this->lasttype == "docblock" && $this->data->isClean())
  950.         {
  951.             $this->_processPageLevelDocBlock($this->last);
  952.             $this->_oldPageLevel = true;
  953.             $this->_lastDocBlockWasPageLevel = false;
  954.         }
  955.         $this->all_packages[$data->package] = 1;
  956.         $this->last = $data;
  957.     }
  958.     
  959.     /**
  960.      * Process a Page-level DocBlock
  961.      *
  962.      * First, it checks for an @ignore tag,
  963.      * and if found, calls {@link ProceduralPages::ignorePage()}.  An @ignore
  964.      * tag in a page-level DocBlock will ignore all functions, defines, global
  965.      * variables, and includes.  It will not ignore classes!  The function next
  966.      * checks for an @access private, and if --parseprivate is off, performs the
  967.      * same actions as @ignore, raising a warning for the unsuspecting user.
  968.      * Next, it checks for the @name tag, which is used to rename the page.
  969.      * This is also a PEAR compatibility issue, and may not be very useful in
  970.      * the long run.  Documentation is best when it refers to real entities in
  971.      * the package, and not to aliases.
  972.      * @access private
  973.      */
  974.     function _processPageLevelDocBlock($data)
  975.     {
  976.         global $_phpDocumentor_setting;
  977.         // can only have 1 package-level docblock, others are ignored
  978.         if (!$this->data->isClean())
  979.         {
  980.             return;
  981.         }
  982.         $this->data->clean = false;
  983.         $this->data->explicitDocBlock();
  984.         $data->canSource();
  985.         if ($_phpDocumentor_setting['sourcecode'])
  986.         {
  987.             $data->addFileSource($this->data->parent->path, $this->data->parent->source);
  988.         }
  989.         if (!$data->getExplicitPackage())
  990.         {
  991.             list($data->package,$data->subpackage) = $this->_guessPackage($this->data->parent->getPath(), $this->data->parent->getSourceLocation('dummy'));
  992.             addWarning(PDERROR_NO_PACKAGE_TAG,'file',$this->data->parent->getPath(),$this->last->package);
  993.         }
  994.         if (isset($this->packagecategories[$this->package])
  995.             && $this->packagecategories[$this->package] != $this->category)
  996.             addWarning(PDERROR_PACKAGECAT_SET,$this->package,
  997.                         $this->packagecategories[$this->package],
  998.                         $data->category);
  999.         $this->packagecategories[$this->package] = $data->category;
  1000.         $this->category = $this->data->parent->category = $data->category;
  1001.         $this->packagecategories[$this->package] = $this->category;
  1002.         $this->subpackage = $this->data->parent->subpackage = $data->subpackage;
  1003.         if ($data->getKeyword('ignore'))
  1004.         {
  1005.             $this->proceduralpages->ignorePage($this->data->parent);
  1006.             $this->private_page = true;
  1007.             unset($this->last);
  1008.             $this->privatepages[$this->data->parent->getPath()] = $this->data;
  1009.             unset($this->pages[$this->data->parent->getPath()]);
  1010.             return;
  1011.         }
  1012.         $this->data->setDocBlock($data);
  1013.         $this->package = $this->data->parent->package = $data->package;
  1014.         $this->subpackage = $this->data->parent->subpackage = $data->subpackage;
  1015.         $this->proceduralpages->addPagePackage($this->data->parent->getPath(),$this->package,$this->subpackage);
  1016.         if ($access = $data->getKeyword('access'))
  1017.         {
  1018.             if (($access->getString() == 'private') && (!$this->parsePrivate))
  1019.             {
  1020.                 addWarning(PDERROR_PARSEPRIVATE, $this->data->parent->getPath());
  1021.                 $this->proceduralpages->ignorePage($this->data->parent);
  1022.                 $this->private_page = true;
  1023.                 unset($this->last);
  1024.                 $this->privatepages[$this->data->parent->getPath()] = $this->data;
  1025.                 unset($this->pages[$this->data->parent->getPath()]);
  1026.                 return;
  1027.             }
  1028.         }
  1029.         if ($data->getKeyword('name'))
  1030.         {
  1031.             $a = $data->getKeyword('name');
  1032.             $this->data->parent->setFile($a->value);
  1033.             $this->proceduralpages->setName($a->value);
  1034.         }
  1035.         $this->addPage($this->data->parent, $this->data->parent->getPath());
  1036.         if ($this->package)
  1037.         {
  1038.             $this->parsePackagePage($this->package, $this->data->parent->getPath());
  1039.         }
  1040.     }
  1041.     
  1042.     /**
  1043.      * Backward-compatibility only, use the new tutorials for more power
  1044.      * @tutorial tutorials.pkg
  1045.      * @param string package name of package file to parse
  1046.      * @param string directory of file that contains package name
  1047.      */
  1048.     function parsePackagePage($package, $path)
  1049.     {
  1050.         if (!isset($this->package_pages[$package]))
  1051.         {
  1052.             if (file_exists(dirname($path) . SMART_PATH_DELIMITER . $package . '.html'))
  1053.             {
  1054.                 if ($this->quietMode === false)
  1055.                 {
  1056.                     phpDocumentor_out("Reading package-level file ".$package . '.html');
  1057.                           flush();
  1058.                 }
  1059.                 $fp = fopen(dirname($path) . SMART_PATH_DELIMITER . $package . '.html',"r");
  1060.                 $ret = fread($fp,filesize(dirname($path) . SMART_PATH_DELIMITER . $package . '.html'));
  1061.                 fclose($fp);
  1062.                 unset($fp);
  1063.                 if ($this->quietMode === false)
  1064.                 {
  1065.                     phpDocumentor_out(" -- Parsing File\n");
  1066.                           flush();
  1067.                 }
  1068.                 $pageParser = new ppageParser;
  1069.                 $tempp = $this->package;
  1070.                 $lp = $this->last;
  1071.                 $pageParser->subscribe('*',$this);
  1072.                 $pageParser->parse($ret,false,$package);
  1073.                 $this->package = $tempp;
  1074.                 $this->last = $lp;
  1075.                 unset($tempp);
  1076.                 unset($pageParser);
  1077.             }
  1078.         }
  1079.     }
  1080.     
  1081.     /**
  1082.      * called via {@link Parser::parse()} and Parser's inherited method
  1083.      * {@link Publisher::publishEvent()}
  1084.      *
  1085.      * $event is one of the PHPDOC constants from Parser.inc.  If it is not
  1086.      * PHPDOCUMENTOR_EVENT_NEWSTATE, then a function name is retrieved from the
  1087.      * {@link $event_handlers} array and called to handle the $data
  1088.      * @param integer $event event number from {@link Parser.inc}
  1089.      * @param mixed $data if $event is {@link PHPDOCUMENTOR_EVENT_NEWSTATE}, $data is a {@link PHP_DOC_EVENT_END_PAGE} or {@link STATE_END_CLASS},
  1090.      *                    otherwise $data is either a {@link parserDocBlock}, {@link parserPage} or descendant of {@link parserElement}
  1091.      * @global array we use 'sourcecode' to determine whether to highlight the source
  1092.      *               of the current file if it has no file-level docblock
  1093.      */
  1094.     function HandleEvent($event,$data)
  1095.     {
  1096.         global $_phpDocumentor_setting;
  1097.         global $phpDocumentor_DefaultPackageName, $phpDocumentor_DefaultCategoryName;
  1098.         if (empty($this->packagecategories))
  1099.         $this->packagecategories[$phpDocumentor_DefaultPackageName] = $phpDocumentor_DefaultCategoryName;
  1100.         if ($event == PHPDOCUMENTOR_EVENT_NEWSTATE)
  1101.         {
  1102.             if ($data == STATE_END_CLASS)
  1103.             {
  1104.             } elseif ($data == PHPDOCUMENTOR_EVENT_END_PAGE)
  1105.             {
  1106.                 if (!$this->private_page)
  1107.                 {
  1108.                     $this->all_packages[$this->package] = 1;
  1109.                     if (!$this->data->hasExplicitDocBlock())
  1110.                     {
  1111.                         $doc = $this->data->docblock;
  1112.                         if (!$this->data->docblock)
  1113.                         {
  1114.                             $doc = new parserDocBlock;
  1115.                         }
  1116.                         if ($_phpDocumentor_setting['sourcecode'])
  1117.                         {
  1118.                             $doc->canSource();
  1119.                             $doc->addFileSource($this->data->parent->path, $this->data->parent->source);
  1120.                         }
  1121.                         list($doc->package,$doc->subpackage) = $this->_guessPackage($this->data->parent->getPath(), $this->data->parent->getSourceLocation('dummy'));
  1122.                         addWarning(PDERROR_NO_PAGE_LEVELDOCBLOCK,$this->data->parent->getPath());
  1123.                         $this->data->setDocBlock($doc);
  1124.                         $this->proceduralpages->addPage($this->data->parent,$doc->package,$doc->subpackage);
  1125.                     }
  1126.                     $this->pages[$this->data->parent->getPath()] = $this->data;
  1127.                 }
  1128.                 $this->private_page = false;
  1129.                 $this->private_class = false;
  1130.                 if (isset($this->db_template))
  1131.                 {
  1132.                     addWarning(PDERROR_DB_TEMPLATE_UNTERMINATED);
  1133.                 }
  1134.                 unset($this->db_template);
  1135.                 unset($this->last);
  1136.             } elseif ($data == PHPDOCUMENTOR_EVENT_END_DOCBLOCK_TEMPLATE)
  1137.             {
  1138.                 unset($this->db_template);
  1139.             }
  1140.             //echo $this->state_lookup[$data] . "\n";
  1141.             //echo $data."\n";
  1142.         } 
  1143.          else 
  1144.         {
  1145.             if ($event == PHPDOCUMENTOR_EVENT_README_INSTALL_CHANGELOG)
  1146.             {
  1147.                 $this->ric[$data[0]] = $data[1];
  1148.                 return;
  1149.             }
  1150.             if ($event == PHPDOCUMENTOR_EVENT_DOCBLOCK_TEMPLATE)
  1151.             {
  1152.                 $data->postProcess();
  1153.                 $this->db_template = $data;
  1154.                 // 2nd docblock in a row, and it's at the top of the file, page-level docblock
  1155.                 if ($this->type == "docblock" && $this->data->isClean())
  1156.                 {
  1157.                     // can only have 1 package-level docblock, others are ignored
  1158.                     $this->data->clean = false;
  1159.                     if ($this->last->getKeyword('ignore'))
  1160.                     {
  1161.                         $this->proceduralpages->ignorePage($this->data->parent);
  1162.                         $this->private_page = true;
  1163.                         unset($this->last);
  1164.                         $this->privatepages[$this->data->parent->getPath()] = $this->data;
  1165.                         unset($this->pages[$this->data->parent->getPath()]);
  1166.                         return;
  1167.                     }
  1168.                     $this->data->setDocBlock($this->last);
  1169.                     $this->package = $this->data->parent->package = $this->last->package;
  1170.                     $this->subpackage = $this->data->parent->subpackage = $this->last->subpackage;
  1171.                     $this->proceduralpages->addPagePackage($this->data->parent->getPath(),$this->package,$this->subpackage);
  1172.                     if ($access = $this->last->getKeyword('access'))
  1173.                     {
  1174.                         if (($access->getString() == 'private') && (!$this->parsePrivate))
  1175.                         {
  1176.                             addWarning(PDERROR_PARSEPRIVATE, $this->data->parent->getPath());
  1177.                             $this->proceduralpages->ignorePage($this->data->parent);
  1178.                             $this->private_page = true;
  1179.                             unset($this->last);
  1180.                             $this->privatepages[$this->data->parent->getPath()] = $this->data;
  1181.                             unset($this->pages[$this->data->parent->getPath()]);
  1182.                             return;
  1183.                         }
  1184.                     }
  1185.                     if ($this->last->getKeyword('name'))
  1186.                     {
  1187.                         $a = $this->last->getKeyword('name');
  1188.                         $this->data->parent->setFile($a->value);
  1189.                         $this->proceduralpages->setName($a->value);
  1190.                     }
  1191.                     $this->addPage($this->data->parent, $this->data->parent->getPath());
  1192.                     if ($this->package)
  1193.                     {
  1194.                         $this->parsePackagePage($this->package, $this->data->parent->getPath());
  1195.                     }
  1196.                 }
  1197.                 unset($this->last);
  1198.             } else
  1199.             {
  1200.                 $this->lasttype = $this->type;
  1201.                 $type = $data->getType();
  1202. //                fancy_debug($type,$data);
  1203.                 if (($type != 'page') && ($type != 'docblock') && ($type != 'packagepage') && ($type != 'tutorial'))
  1204.                 {
  1205.                     $data->setFile($this->data->parent->getFile());
  1206.                 }
  1207.                 $this->type = $type;
  1208.                 //echo $type . "\n";
  1209.                 
  1210.                 if (isset($this->event_handlers[$type]))
  1211.                 {
  1212.                     $handle = $this->event_handlers[$type];
  1213.                     $this->$handle($event,$data);
  1214.                 }
  1215.             } 
  1216.         }
  1217.     }
  1218.     
  1219.     /**
  1220.      * Replaces the {@link parserPage} represented by $this->pages[$path] with
  1221.      * $page
  1222.      *
  1223.      * Called by {@link addPageIfNecessary(), handleDocBlock()} and
  1224.      * {@link ProceduralPages::setupPages()}, this method first checks to see if
  1225.      * the page has been added.  If not, it assumes that the page has either
  1226.      * been @ignored or set with @access private with --parseprivate off, and
  1227.      * returns {@link addPrivatePage()}.  Otherwise, it sets the pages[$path] to
  1228.      * be the parserPage $page and sets the package and subpackage to that of
  1229.      * $page
  1230.      * @see $pages
  1231.      * @param parserPage
  1232.      * @param string full path to the file
  1233.      */
  1234.     function addPage($page, $path)
  1235.     {
  1236.         if (!isset($this->pages[$path])) return $this->addPrivatePage($page, $path);
  1237.         $this->pages[$path]->setParent($page);
  1238.         if ($page->package != $GLOBALS['phpDocumentor_DefaultPackageName'])
  1239.         {
  1240.             if (!$this->pages[$path]->docblock)
  1241.             {
  1242.                 $docblock = new parserDocBlock;
  1243.                 $docblock->package = $page->package;
  1244.                 $docblock->subpackage = $page->subpackage;
  1245.                 $this->pages[$path]->docblock = $docblock;
  1246.             } else
  1247.             {
  1248.                 $this->pages[$path]->docblock->package = $page->package;
  1249.                 $this->pages[$path]->docblock->subpackage = $page->subpackage;
  1250.             }
  1251.         }
  1252.     }
  1253.     
  1254.     /**
  1255.      * add a new {@link parserPage} to the $pages array if none is found
  1256.      *
  1257.      * This method is used when a page has been @ignored or marked with @access
  1258.      * private, and a public class is in the page (a class with no @access
  1259.      * private in its DocBlock).  The method first creates a new page in the
  1260.      * {@link $pages} array and then copies path information, and calls
  1261.      * {@link addPage()} to set up packages
  1262.      * @param string full path of page
  1263.      */
  1264.     function addPageIfNecessary($path, &$class)
  1265.     {
  1266.         global $_phpDocumentor_setting;
  1267.         if (!$this->parsePrivate)
  1268.         {
  1269.             if (!isset($this->pages[$path]))
  1270.             {
  1271.                 $this->pages[$path] = new parserData;
  1272.                 $this->pages[$path]->docblock = new parserDocBlock;
  1273.                 $this->pages[$path]->docblock->package = $this->privatepages[$path]->docblock->package;
  1274.                 $this->pages[$path]->docblock->subpackage = $this->privatepages[$path]->docblock->subpackage;
  1275.                 $par = $this->privatepages[$path]->parent;
  1276.                 $this->pages[$path]->setParent($par);
  1277.                 $this->proceduralpages->addPage($par);
  1278.             }
  1279.         }
  1280.         if (isset($_phpDocumentor_setting['packageoutput']))
  1281.             $packages = explode(',',$_phpDocumentor_setting['packageoutput']);
  1282.         if (isset($_phpDocumentor_setting['packageoutput']) &&
  1283.             $this->pages[$path]->parent->package != $class->docblock->package &&
  1284.             !in_array($this->pages[$path]->parent->package,$packages))
  1285.         {
  1286.             $this->pages[$path]->parent->package = $class->docblock->package;
  1287.             $this->addPage($this->pages[$path]->parent, $path);
  1288.             $this->proceduralpages->addPage($this->pages[$path]->parent);
  1289.         }
  1290.     }
  1291.     
  1292.     /**
  1293.      * Adds a {@link parserPage} element to the {@link parserData} element in
  1294.      * $this->privatepages[$path]
  1295.      *
  1296.      * Performs a similar function to addPage, but adds to the
  1297.      * {@link $privatePages} array
  1298.      * @param parserPage $page
  1299.      * @param string $path full path to the page
  1300.      * @see addPage()
  1301.      */
  1302.     function addPrivatePage($page, $path)
  1303.     {
  1304.         $this->privatepages[$path]->setParent($page);
  1305.         if ($page->package != $GLOBALS['phpDocumentor_DefaultPackageName'])
  1306.         {
  1307.             if (!$this->privatepages[$path]->docblock)
  1308.             {
  1309.                 $docblock = new parserDocBlock;
  1310.                 $docblock->package = $page->package;
  1311.                 $docblock->subpackage = $page->subpackage;
  1312.                 $this->privatepages[$path]->docblock = $docblock;
  1313.             } else
  1314.             {
  1315.                 $this->privatepages[$path]->docblock->package = $page->package;
  1316.                 $this->privatepages[$path]->docblock->subpackage = $page->subpackage;
  1317.             }
  1318.         }
  1319.     }
  1320.     
  1321.     /**
  1322.      * adds a processed descendant of {@link parserElement} to the {@link $pages}
  1323.      * array or {@link $privatepages} array
  1324.      *
  1325.      * This function expects the page to exist in either $pages or $privatepages.  It calls the
  1326.      * {@link parserData::addElement()} method to add $element to the page.
  1327.      * @param parserElement $element this will actually be a descendant of parserElement
  1328.      * @param string $path
  1329.      */
  1330.     function addElementToPage($element, $path)
  1331.     {
  1332.         if (isset($this->privatepages[$path]))
  1333.         {
  1334.             if (isset($this->pages[$path]))
  1335.             {
  1336.                 if ($element->type == 'class' || $element->type == 'method' || $element->type == 'var')
  1337.                 {
  1338.                     $this->pages[$path]->addElement($element);
  1339.                 } else
  1340.                 $this->privatepages[$path]->addElement($element);
  1341.             } else
  1342.             $this->privatepages[$path]->addElement($element);
  1343.         } else
  1344.         {
  1345.             if (isset($this->pages[$path]))
  1346.             {
  1347.                 $this->pages[$path]->addElement($element);
  1348.             }
  1349.         }
  1350.     }
  1351.     
  1352.     /**
  1353.      * Add all the @uses tags from $element to the $uses array so that @usedby
  1354.      * virtual tags can be added
  1355.      * @uses parserUsesTag::getSeeElement() used to initialize {@link $uses}
  1356.      * @uses parserUsesTag::getDescription() used to initialize {@link $uses}
  1357.      * @param parserElement descendant of parserElement
  1358.      * @param string full path to the file 
  1359.      */
  1360.     function addUses($element, $path)
  1361.     {
  1362.         if ($element->type == 'page')
  1363.         {
  1364.             $element = $this->pages[$element->path];
  1365.         }
  1366.         if (!$this->parsePrivate && $element->docblock->hasaccess)
  1367.         {
  1368.             $a =  $element->docblock->getKeyword('access');
  1369.             if ($a->getString() == 'private') return;
  1370.         }
  1371.         if (isset($this->privatepages[$path]))
  1372.         {
  1373.             if (isset($this->pages[$path]))
  1374.             {
  1375. //                if ($element->type == 'function' || $element->type == 'method')
  1376.                 {
  1377.                     $uses = $element->docblock->getKeyword('uses');
  1378.                     if ($uses)
  1379.                     {
  1380.                         if (!is_array($uses)) $uses = array($uses);
  1381.                         foreach($uses as $use)
  1382.                         {
  1383.                             $el = $use->getSeeElement();
  1384.                             $description = $use->getDescription();
  1385.                             $this->uses[$el][] = array($element, $description);
  1386.                         }
  1387.                     }
  1388.                 }
  1389.             }
  1390.         } else
  1391.         {
  1392.             if (isset($this->pages[$path]))
  1393.             {
  1394. //                if ($element->type == 'function' || $element->type == 'method')
  1395.                 {
  1396.                     $uses = $element->docblock->getKeyword('uses');
  1397.                     if ($uses)
  1398.                     {
  1399.                         if (!is_array($uses)) $uses = array($uses);
  1400.                         foreach($uses as $use)
  1401.                         {
  1402.                             $el = $use->getSeeElement();
  1403.                             $description = $use->getDescription();
  1404.                             $this->uses[$el][] = array($element, $description);
  1405.                         }
  1406.                     }
  1407.                 }
  1408.             }
  1409.         }
  1410.     }
  1411.     
  1412.     /**
  1413.      * Add a {@link parserUsedByTag} link to every element referred to by @uses
  1414.      * @param Converter temporary converter used to retrieve abstract links
  1415.      * @uses phpDocumentor_IntermediateParser::addUses() indirectly, as
  1416.      *       addUses() sets up $uses, which is iterated over here
  1417.      * @uses $pages sets up all @usedby tags from here
  1418.      * @access private
  1419.      */
  1420.     function _setupUsesList(&$converter)
  1421.     {
  1422.         ob_start();
  1423.         $converter->_createPkgElements($this->pages);
  1424.         ob_end_clean();
  1425.         foreach($this->uses as $link => $elements)
  1426.         {
  1427.             foreach($elements as $element)
  1428.             {
  1429.                 if ($element[0]->type == 'method' || $element[0]->type == 'var')
  1430.                 {
  1431.                     $converter->class = $element[0]->getClass();
  1432.                 }
  1433.                 if ($element[0]->type == 'class')
  1434.                 {
  1435.                     $converter->class = $element[0]->getName();
  1436.                 }
  1437.                 $reallink = $converter->getLink($link,$element[0]->docblock->package);
  1438.                 if (is_object($reallink))
  1439.                 {
  1440.                     // add a used by tag to the docblock of the destination
  1441.                     switch(get_class($reallink))
  1442.                     {
  1443.                         case 'pagelink' :
  1444.                         case 'functionlink' :
  1445.                         case 'definelink' :
  1446.                         case 'globallink' :
  1447.                         if (isset($this->pages[$reallink->path]))
  1448.                         {
  1449.                             for ($i=0;$i<count($this->pages[$reallink->path]->elements);$i++)
  1450.                             {
  1451.                                 if ($this->pages[$reallink->path]->elements[$i]->type == str_replace('link','',get_class($reallink)) && $this->pages[$reallink->path]->elements[$i]->getName() == $reallink->name)
  1452.                                 {
  1453.                                     $this->pages[$reallink->path]->elements[$i]->docblock->addUsedBy($element[0]->getLink($converter,false,true), $element[1]);
  1454. //                                   debug('added @usedby to '.str_replace('link','',get_class($reallink)).' '.$reallink->name);
  1455.                                 }
  1456.                             }
  1457.                         }
  1458.                         break;
  1459.                         case 'classlink' :
  1460.                         case 'methodlink' :
  1461.                         case 'varlink' :
  1462.                         if (isset($this->pages[$reallink->path]))
  1463.                         {
  1464.                             for ($i=0;$i<count($this->pages[$reallink->path]->classelements);$i++)
  1465.                             {
  1466.                                 if ($this->pages[$reallink->path]->classelements[$i]->type == str_replace('link','',get_class($reallink)) && $this->pages[$reallink->path]->classelements[$i]->getName() == $reallink->name)
  1467.                                 {
  1468.                                     $this->pages[$reallink->path]->classelements[$i]->docblock->addUsedBy($element[0]->getLink($converter,false,true), $element[1]);
  1469. //                                   debug('added @usedby to '.str_replace('link','',get_class($reallink)).' '.$reallink->name);
  1470.                                 }
  1471.                             }
  1472.                         }
  1473.                         break;
  1474.                     }
  1475.                 }
  1476.             }
  1477.         }
  1478.     }
  1479.     
  1480.     /**
  1481.      * Interface to the Converter
  1482.      *
  1483.      * This function simply passes {@link $pages} and {@link package_pages} to
  1484.      * the walk() method, and then calls the Output() method.  Note that
  1485.      * Output() is not required to do anything, and in fact doesn't in
  1486.      * HTMLframesConverter.
  1487.      * @uses Converter::walk() passes {@link $pages} and {@link $package_pages}
  1488.      * @uses Converter::Output()
  1489.      */
  1490.     function Convert($title, $converter)
  1491.     {
  1492.         $converter->walk($this->pages, $this->package_pages);
  1493.         $converter->Output($title);
  1494.     }
  1495.     
  1496.     /**
  1497.      * Clean up classes
  1498.      *
  1499.      * {@source}
  1500.      * @access private
  1501.      * @uses Classes::Inherit() passes $this
  1502.      */
  1503.     function fixClasses()
  1504.     {
  1505.         $this->classes->Inherit($this);
  1506.     }
  1507.     
  1508.     /**
  1509.      * Clean up Procedural Pages
  1510.      * {@source}
  1511.      * @access private
  1512.      * @uses ProceduralPages::setupPages() passes $this
  1513.      */
  1514.     function fixProcPages()
  1515.     {
  1516.         $this->proceduralpages->setupPages($this);
  1517.     }
  1518.     
  1519.     /**
  1520.      * If the parent class of $class is in a different package, adds it to the
  1521.      * {@link $package_parents} array
  1522.      * @param parserClass &$class
  1523.      */
  1524.     function addPackageParent(&$class)
  1525.     {
  1526.         if (!is_array($class->parent)) return;
  1527.         $par = $this->classes->getClass($class->parent[1], $class->parent[0]);
  1528.         if ($class->docblock->package == $par->docblock->package) return;
  1529.         $this->package_parents[$class->docblock->package] = $par->docblock->package;
  1530.         if (!isset($this->package_parents[$par->docblock->package]) || !$this->package_parents[$par->docblock->package]) $this->package_parents[$par->docblock->package] = false;
  1531.     }
  1532.     
  1533.     /**
  1534.      * Add a converter name to use to the list of converters
  1535.      *
  1536.      * Sets up the {@link $converters} array.
  1537.      * {@internal
  1538.      * First, the Converter's file is included, and then, if successful,
  1539.      * the converter classname is tested for existance.  If all is good,
  1540.      * then the templates are added to the list of converters/templates to use}}
  1541.      * @param string $output output format (HTML, PDF, XML).  Must be all caps
  1542.      * @param string $name Converter name (frames, for example, is the name of
  1543.      *                     HTMLframesConverter)
  1544.      * @param string $template template to use, should be a relative path to the
  1545.      *                         templates dir (like DOM/default)
  1546.      */
  1547.     function addConverter($output,$name,$template)
  1548.     {
  1549.         if (strpos($name,PATH_DELIMITER))
  1550.         {
  1551.             $parent = explode(PATH_DELIMITER,$name);
  1552.             $parent = $parent[0];
  1553.             $filename = 'PhpDocumentor/phpDocumentor/Converters' .
  1554.                 PATH_DELIMITER . $output . PATH_DELIMITER . $parent . PATH_DELIMITER . $output . $parent . "Converter" . ".inc";
  1555.             if (Io::isIncludeable($filename))
  1556.             {
  1557.                 include_once($filename);
  1558.             }
  1559.             if (!class_exists($output . $parent . 'Converter'))
  1560.             {
  1561.                 addError(PDERROR_CONVERTER_NOT_FOUND,"parent Converter ".$output . $parent . "Converter of child Converter ".$output . str_replace(PATH_DELIMITER,'',$name) . "Converter");
  1562.             }
  1563.         }
  1564.         $filename = 'PhpDocumentor/phpDocumentor/Converters' .
  1565.              PATH_DELIMITER . $output . PATH_DELIMITER . $name . PATH_DELIMITER . $output .
  1566.              str_replace(PATH_DELIMITER, '', $name) . "Converter" . ".inc";
  1567.         if (Io::isIncludeable($filename))
  1568.         {
  1569.             include_once($filename);
  1570.         } else {
  1571.             var_dump($filename);
  1572.         }
  1573.         if (class_exists($output . str_replace(PATH_DELIMITER,'',$name) . 'Converter'))
  1574.         {
  1575.             $this->converters[$output][$output . str_replace(PATH_DELIMITER,'',$name) . "Converter"][] = $template;
  1576.         } else
  1577.         {
  1578.             addError(PDERROR_CONVERTER_NOT_FOUND,$output . str_replace(PATH_DELIMITER,'',$name) . "Converter");
  1579.         }
  1580.     }
  1581.  
  1582.     /**
  1583.      * does a natural case sort on two {@link parserElement} descendants
  1584.      *
  1585.      * @param    mixed    $a
  1586.      * @param    mixed    $b
  1587.      * @return    int
  1588.      * @see        generateElementIndex()
  1589.      */
  1590.     function elementCmp ($a, $b)
  1591.     {
  1592.         return strnatcasecmp($a->getName(), $b->getName());
  1593.     }
  1594.     
  1595.     /**
  1596.      * does a natural case sort on two class elements (either
  1597.      * {@link parserClass, parserMethod} or {@link parserVar}
  1598.      *
  1599.      * @param    mixed    $a
  1600.      * @param    mixed    $b
  1601.      * @return    int
  1602.      * @see        generateElementIndex()
  1603.      */
  1604.     function ClasselementCmp ($a, $b)
  1605.     {
  1606.         if (get_class($a) == 'parserclass') $atest = $a->name; else $atest = $a->class;
  1607.         if (get_class($b) == 'parserclass') $btest = $b->name; else $btest = $b->class;
  1608.         
  1609.         if(($c = strnatcasecmp($atest, $btest)) != 0) return $c;
  1610.         if ((get_class($a) == 'parservar') || (get_class($a) == 'parsermethod')) $atest .= $a->name;
  1611.         if ((get_class($b) == 'parservar') || (get_class($b) == 'parsermethod')) $btest .= $b->name;
  1612.         if (get_class($a) == 'parsermethod' && get_class($b) == 'parsermethod')
  1613.         {
  1614.             if ($a->isConstructor) return -1;
  1615.             if ($b->isConstructor) return 1;
  1616.             if ($a->isDestructor) return -1;
  1617.             if ($b->isDestructor) return 1;
  1618.         }
  1619.         return strnatcasecmp($atest,$btest);
  1620.     }
  1621.     
  1622.     /**
  1623.      * call this method once parsing has completed.
  1624.      *
  1625.      * This method calls the private methods fixClasses and fixProcPages, both
  1626.      * of which adjust inheritance and package information based on complicated
  1627.      * post-parsing rules described in {@link ProceduralPages::setupPages()}
  1628.      * and {@link Classes::Inherit()}.  Then, it sorts elements of the $pages
  1629.      * array and calls Convert for each Converter in the $converters array
  1630.      * @see $converters
  1631.      * @see $pages
  1632.      * @see Convert()
  1633.      */
  1634.     function Output ($title = "Generated Documentation")
  1635.     {
  1636.         $GLOBALS['phpDocumentor_errors']->curfile = false;
  1637.         $this->fixClasses();
  1638.         $this->fixProcPages();
  1639. //        var_dump($this->uses);
  1640. //        exit;
  1641.         phpDocumentor_out("\nSorting page elements...");
  1642.         flush();
  1643.         uasort($this->pages,'pagesort');
  1644.         foreach($this->pages as $i => $page)
  1645.         {
  1646.             usort($this->pages[$i]->elements,array($this,'elementCmp'));
  1647.             usort($this->pages[$i]->classelements,array($this,'ClasselementCmp'));
  1648.         }
  1649.         phpDocumentor_out("done\n");
  1650.         flush();
  1651.         $complicatedout = false;
  1652.         if (is_array($this->converters))
  1653.         {
  1654.             if (count($this->converters) > 1)
  1655.             {
  1656.                 $complicatedout = true;
  1657.             }
  1658.             phpDocumentor_out("Formatting @uses list...");
  1659.             flush();
  1660.             $a = new __dummyConverter($this->all_packages, $this->package_parents, $this->classes, $this->proceduralpages, $this->packageoutput, $this->parsePrivate, $this->quietMode, $this->targetDir , '', $this->title);
  1661.             $this->_setupUsesList($a);
  1662.             unset($a);
  1663.             phpDocumentor_out("done\n\n");
  1664.             flush();
  1665.             foreach($this->converters as $converter => $blah)
  1666.             {
  1667.                 if (is_array($blah))
  1668.                 {
  1669.                     if (count($blah) > 1)
  1670.                     {
  1671.                         $complicatedout = true;
  1672.                     }
  1673.                     foreach($blah as $converter => $templates)
  1674.                     {
  1675.                         foreach($templates as $template)
  1676.                         {
  1677.                             $extraout = '';
  1678.                             if ($complicatedout)
  1679.                             {
  1680.                                 $extraout = SMART_PATH_DELIMITER . $converter;
  1681.                             }
  1682.                             if (count($templates) > 1)
  1683.                             {
  1684.                                 $extraout .= SMART_PATH_DELIMITER . str_replace(PATH_DELIMITER, SMART_PATH_DELIMITER, substr($template,0,strlen($template) - 1));
  1685.                             }
  1686.                             $a = new $converter($this->all_packages, $this->package_parents, $this->classes, $this->proceduralpages, $this->packageoutput, $this->parsePrivate, $this->quietMode, $this->targetDir . $extraout, $template, $this->title);
  1687.                             if (isset($this->templateBase))
  1688.                             {
  1689.                                 $a->setTemplateBase($this->templateBase, $template);
  1690.                             }
  1691.                             $a->ric = $this->ric;
  1692.                             $a->packagecategories = $this->packagecategories;
  1693.                             if (isset($this->tutorials)) $a->setTutorials($this->tutorials);
  1694.                             $this->Convert($title, $a);
  1695.                             unset($a);
  1696.                         }
  1697.                     }
  1698.                 }
  1699.             }
  1700.         } else
  1701.         {
  1702.             addErrorDie(PDERROR_NO_CONVERTERS);
  1703.         }
  1704.     }
  1705.  
  1706.     /**
  1707.      * Sets the output directory
  1708.      *
  1709.      * @param string $dir the output directory
  1710.      */
  1711.     function setTargetDir($dir)
  1712.     {
  1713.         $this->targetDir = $dir;
  1714.     }
  1715.  
  1716.     /**
  1717.      * Sets the template base directory
  1718.      *
  1719.      * @param string $dir the template base directory
  1720.      * @tutorial phpDocumentor.howto.pkg#using.command-line.templatebase
  1721.      */
  1722.     function setTemplateBase($dir)
  1723.     {
  1724.         $this->templateBase = $dir;
  1725.     }
  1726.  
  1727.     /**
  1728.      * set parsing information output mode (quiet or verbose)
  1729.      *
  1730.      * If set to false, no parsing information (parsing /php/file/thisfile.php,
  1731.      * Converting etc.) will be displayed.
  1732.      * Useful for cron jobs
  1733.      * @param    bool $quietMode
  1734.      */
  1735.     function setQuietMode($quietMode)
  1736.     {
  1737.         $this->quietMode = $quietMode;
  1738.     }
  1739.     
  1740.     /**
  1741.      * set display of elements marked with @access private
  1742.      *
  1743.      * If set to true, elements will be displayed
  1744.      * @param    bool $parse
  1745.      */
  1746.     function setParsePrivate($parse)
  1747.     {
  1748.         $this->parsePrivate = $parse;
  1749.     }
  1750. }
  1751.  
  1752. /** @access private */
  1753. function pagesort($a, $b)
  1754. {
  1755.     return strnatcasecmp($a->parent->file,$b->parent->file);
  1756. }
  1757. ?>
  1758.