Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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