Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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