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