1<?php
2/**
3 * Outputs documentation in XML DocBook format, in the version expected by
4 * pear.php.net's documentation team
5 *
6 * phpDocumentor :: automatic documentation generator
7 *
8 * PHP versions 4 and 5
9 *
10 * Copyright (c) 2002-2006 Gregory Beaver
11 *
12 * LICENSE:
13 *
14 * This library is free software; you can redistribute it
15 * and/or modify it under the terms of the GNU Lesser General
16 * Public License as published by the Free Software Foundation;
17 * either version 2.1 of the License, or (at your option) any
18 * later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 * @package    Converters
30 * @subpackage XMLDocBook
31 * @author     Greg Beaver <cellog@php.net>
32 * @copyright  2002-2006 Gregory Beaver
33 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
34 * @version    CVS: $Id: XMLDocBookpeardoc2Converter.inc 234423 2007-04-24 21:32:15Z ashnazg $
35 * @filesource
36 * @link       http://www.phpdoc.org
37 * @link       http://pear.php.net/PhpDocumentor
38 * @since      1.2
39 */
40/**
41 * XML DocBook converter.
42 * This Converter takes output from the {@link Parser} and converts it to DocBook
43 * output for PEAR documentation.
44 *
45 * This Converter differs from the parent DocBook Converter in that it does not
46 * recognize the possibility of procedural pages or of functions!  All functions
47 * must be defined as static methods for namespace purposes.  In addition, all
48 * constants and global variables for a package are grouped together as per
49 * peardoc2 requirements.  Include statements are not documented.  If you want
50 * to document a normal project, don't use the peardoc2 converter, use the
51 * DocBook converter.
52 * @package Converters
53 * @subpackage XMLDocBook
54 * @author Greg Beaver <cellog@php.net>
55 * @since 1.2
56 * @version $Id: XMLDocBookpeardoc2Converter.inc 234423 2007-04-24 21:32:15Z ashnazg $
57 */
58class XMLDocBookpeardoc2Converter extends Converter
59{
60    /**
61     * This converter knows about the new root tree processing
62     * In order to fix PEAR Bug #6389
63     * @var boolean
64     */
65    var $processSpecialRoots = true;
66    /**
67     * XMLDocBookConverter wants elements sorted by type as well as alphabetically
68     * @see Converter::$sort_page_contents_by_type
69     * @var boolean
70     */
71    var $sort_page_contents_by_type = true;
72    /** @var string */
73    var $outputformat = 'XML';
74    /** @var string */
75    var $name = 'DocBook/peardoc2';
76    /**
77     * indexes of elements by package that need to be generated
78     * @var array
79     */
80    var $leftindex = array('classes' => true, 'pages' => false, 'functions' => false, 'defines' => true, 'globals' => true);
81    /**
82     * whether a @see is going to be in the {@link $base_dir}, or in a package/subpackage subdirectory of $base_dir
83     * @var boolean
84     */
85    var $local = true;
86
87    /**
88     * name of current page being converted
89     * @var string
90     */
91    var $page;
92
93    /**
94     * path of current page being converted
95     * @var string
96     */
97    var $path;
98
99    /**
100     * name of current class being converted
101     * @var string
102     */
103    var $class;
104
105    /**
106     * template for the procedural page currently being processed
107     * @var Template
108     */
109    var $page_data;
110
111    /**
112     * output directory for the current procedural page being processed
113     * @var string
114     */
115    var $page_dir;
116
117    /**
118     * Constants, used for constants.tpl
119     * @var array
120     */
121    var $_peardoc2_constants = false;
122
123    /**
124     * Global Variables, used for globals.tpl
125     * @var array
126     */
127    var $_peardoc2_globals = false;
128
129    /**
130     * target directory passed on the command-line.
131     * {@link $targetDir} is malleable, always adding package/ and package/subpackage/ subdirectories onto it.
132     * @var string
133     */
134    var $base_dir;
135
136    /**
137     * output directory for the current class being processed
138     * @var string
139     */
140    var $class_dir;
141
142    /**
143     * template for the class currently being processed
144     * @var Template
145     */
146    var $class_data;
147
148    /**
149     * array of converted package page names.
150     * Used to link to the package page in the left index
151     * @var array Format: array(package => 1)
152     */
153    var $package_pages = array();
154
155    /**
156     * Contents of the packagename.xml file are stored in this template variable
157     * @var Smarty
158     */
159    var $packagexml;
160    /**
161     * controls formatting of parser informative output
162     *
163     * Converter prints:
164     * "Converting /path/to/file.php... Procedural Page Elements... Classes..."
165     * Since HTMLdefaultConverter outputs files while converting, it needs to send a \n to start a new line.  However, if there
166     * is more than one class, output is messy, with multiple \n's just between class file output.  This variable prevents that
167     * and is purely cosmetic
168     * @var boolean
169     */
170    var $juststarted = false;
171
172    /**
173     * contains all of the template procedural page element loop data needed for the current template
174     * @var array
175     */
176    var $current;
177
178    /**
179     * contains all of the template class element loop data needed for the current template
180     * @var array
181     */
182    var $currentclass;
183
184    /**
185     * Pass elements by package, simplifies generation of package.xml/category.xml
186     */
187    var $sort_absolutely_everything = true;
188    /**
189     * template options.  Currently only 1 recognized option usepear
190     *
191     * usepear tells the getLink() function to return a package link to PEAR and PEAR_ERROR if possible, and to link directly
192     * to the fully-delimited link package#class.method or package#file.method in PEAR style, if possible, even if the
193     * package is not parsed.  This will allow parsing of separate PEAR packages without parsing the entire thing at once!
194     * @var array
195     */
196    var $template_options = array('usepear' => false);
197
198    var $function_data = array();
199    var $method_data = array();
200    var $_write_constants_xml = array();
201    var $_write_globals_xml = array();
202    var $sourceloc = '';
203    /**
204     * peardoc2 Category
205     * @var string
206     */
207    var $category;
208    /**
209     * Used to re-format output so that it's easy for translators to handle
210     *
211     * @var XML_Beautifier|false
212     * @access private
213     */
214    var $_beautifier = false;
215
216    /**
217     * sets {@link $base_dir} to $targetDir
218     * @see Converter()
219     */
220    function XMLDocBookpeardoc2Converter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $templateDir, $title)
221    {
222        if (!class_exists('XML_Beautifier')) {
223            @include_once 'XML/Beautifier.php';
224        }
225        Converter::Converter($allp, $packp, $classes, $procpages,$po, $pp, $qm, $targetDir, $templateDir, $title);
226        if (class_exists('XML_Beautifier')) {
227            require_once 'phpDocumentor/Converters/XML/DocBook/peardoc2/Beautifier.php';
228            $this->_beautifier = new phpDocumentor_peardoc2_XML_Beautifier;
229            $this->_beautifier->setOption('indent', ' ');
230        }
231        $this->base_dir = $targetDir;
232    }
233
234    /**
235     * do that stuff in $template_options
236     */
237    function &getLink($expr, $package = false, $packages = false)
238    {
239        return Converter::getLink($expr, $package, $packages);
240    }
241
242    function unmangle($s,$sourcecode)
243    {
244        return '<programlisting role="php"><![CDATA[
245'.$sourcecode.']]></programlisting>';
246    }
247
248    /**
249     * Writes a file to target dir, beautify any .xml files first
250     * @param string filename
251     * @param string file contents
252     * @param boolean true if the data is binary and not text
253     */
254    function writeFile($file,$data,$binary = false)
255    {
256        if ($this->_beautifier && substr($file, -4) == '.xml') {
257            $ret = $this->_beautifier->formatString($data);
258            if (PEAR::isError($ret)) {
259                addWarning(PDERROR_BEAUTIFYING_FAILED, $ret->getMessage());
260                $ret = $data;
261            }
262            $data = $ret;
263        }
264        return parent::writeFile($file, $data, $binary);
265    }
266
267    /**
268     * Used to convert the {@}example} inline tag in a docblock.
269     *
270     * By default, this just wraps ProgramExample
271     * @see XMLDocBookpeardoc2Converter::exampleProgramExample
272     * @param string
273     * @param boolean true if this is to highlight a tutorial <programlisting>
274     * @return string
275     */
276    function exampleProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/,
277                            $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/)
278    {
279        return '<example><title>Example</title><programlisting role="php"><![CDATA[' .
280         $example . ']]></programlisting></example>';
281        $this->ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath)
282        . '</example>';
283    }
284
285    function writeExample($title, $path, $source)
286    {
287        $this->_save_example = array($title, $source);
288    }
289
290    function getExampleLink($unused, $title)
291    {
292        $source = $this->_save_example[1];
293        return '<para><example><title>' . $title . '</title>' . $source . '</example></para>';
294    }
295
296    function type_adjust($typename)
297    {
298        if (isset($this->template_options['typechanging'][trim($typename)]))
299        return $this->template_options['typechanging'][trim($typename)];
300        $a = $this->getLink($typename);
301        if (is_object($a))
302        {
303            if (phpDocumentor_get_class($a) == 'classlink')
304            return '<classname>'.$typename.'</classname>';
305            if (phpDocumentor_get_class($a) == 'functionlink' || phpDocumentor_get_class($a) == 'methodlink')
306            return '<function>'.$typename.'</function>';
307            if (phpDocumentor_get_class($a) == 'definelink')
308            return '<constant>'.$typename.'</constant>';
309            if (phpDocumentor_get_class($a) == 'varlink')
310            return '<varname>'.$typename.'</varname>';
311        }
312        return $typename;
313    }
314
315    /**
316     * Writes out the template file of {@link $class_data} and unsets the template to save memory
317     * @see registerCurrentClass()
318     * @see parent::endClass()
319     * @todo move class summary into an array to be written out at the end
320     *       of parsing each package
321     */
322    function endClass()
323    {
324        $a = '../';
325        if (!empty($this->subpackage)) $a .= '../';
326        if ($this->juststarted)
327        {
328            $this->juststarted = false;
329            phpDocumentor_out("\n");
330            flush();
331        }
332        foreach($this->method_data as $func)
333        {
334            $func[0]->assign("phpdocversion",PHPDOCUMENTOR_VER);
335            $func[0]->assign("phpdocwebsite",PHPDOCUMENTOR_WEBSITE);
336            $this->setTargetDir($this->base_dir . PATH_DELIMITER . strtolower($this->category) . PATH_DELIMITER . strtolower($this->class_dir . PATH_DELIMITER . str_replace(array('_','.'),array('-','--'),$this->class)));
337            $this->writefile(strtolower($func[1] ). '.xml','<!-- $' . "Revision$ -->\n" . $func[0]->fetch('method.tpl'));
338        }
339        // code below is in packagename.xml handling, see Output()
340/*        $this->setTargetDir($this->base_dir . PATH_DELIMITER . strtolower($this->category) . PATH_DELIMITER . strtolower($this->class_dir));
341        $this->writefile(str_replace(array('_','.'),array('-','--'),strtolower($this->class)) . '.xml',$this->class_data->fetch('class.tpl'));*/
342        unset($this->class_data);
343    }
344
345    function addSummaryToPackageXml($template_output)
346    {
347        $this->packagexml->append('ids',$template_output);
348    }
349
350    /**
351     * @param parserClass|false $element is false if this is the end of all conversion
352     */
353    function flushPackageXml($element)
354    {
355        if (isset($this->packagexml))
356        {
357            if (!$element || $element->docblock->package != $this->package) // finished with package
358            {
359                if (isset($this->_write_constants_xml[$this->category][$this->package]) &&
360                    $this->_write_constants_xml[$this->category][$this->package])
361                {
362                    $this->packagexml->append('ids',
363                        '&package.' .
364                         strtolower($this->category.'.' .
365                         str_replace(array('_','.'),array('-','--'),$this->package).'.constants;'));
366                    $this->_write_constants_xml[$this->category][$this->package] = false;
367                }
368                if (isset($this->_write_globals_xml[$this->category][$this->package]) &&
369                    $this->_write_globals_xml[$this->category][$this->package])
370                {
371                    $this->packagexml->append('ids',
372                            '&package.'.strtolower($this->category.'.' .
373                             str_replace(array('_','.'),array('-','--'),$this->package).'.globals;'));
374                    $this->_write_globals_xml[$this->category][$this->package] = false;
375                }
376                $this->setTargetDir($this->base_dir . PATH_DELIMITER . strtolower($this->category));
377                $this->writefile(str_replace('_','-',strtolower($this->package)).'.xml',
378                    '<!-- $' . "Revision$ -->\n" . $this->packagexml->fetch('package.tpl'));
379                $this->packagexml->clear_all_assign();
380                if ($element) {
381                    $this->packagexml->assign('package',$element->docblock->package);
382                    $this->packagexml->assign('ids',array());
383                    $this->packagexml->assign('id',$this->getId($element, true));
384                }
385            }
386        } else
387        {
388            $this->packagexml = $this->newSmarty();
389            $this->packagexml->assign('package',$element->docblock->package);
390            $this->packagexml->assign('ids',array());
391            $this->packagexml->assign('id',$this->getId($element, true));
392        }
393    }
394
395    /**
396     * @param string
397     * @param string
398     * @return string <ulink url="'.$link.'">'.$text.'</ulink>
399     */
400    function returnLink($link,$text)
401    {
402        return '<ulink url="'.$link.'">'.$text.'</ulink>';
403    }
404
405    function makeLeft()
406    {
407    }
408
409    /**
410     * Does nothing
411     */
412    function formatPkgIndex()
413    {
414    }
415
416    /**
417     * Does nothing
418     */
419    function formatIndex()
420    {
421    }
422
423    /**
424     * Does nothing
425     */
426    function writeNewPPage($key)
427    {
428    }
429
430    /**
431     * Does nothing
432     */
433    function writeSource()
434    {
435    }
436
437    /**
438     * Creates package/lang/categoryname/packagename.xml for each package
439     */
440    function formatLeftIndex()
441    {
442        $this->makeLeft();
443    }
444
445    /**
446     * This function takes an {@link abstractLink} descendant and returns an html link
447     *
448     * @param abstractLink a descendant of abstractlink should be passed, and never text
449     * @param string text to display in the link
450     * @param boolean this parameter is not used, and is deprecated
451     * @param boolean determines whether the returned text is enclosed in an <link> tag
452     */
453    function returnSee(&$element, $eltext = false, $local = true, $with_a = true)
454    {
455        if (!$element) return false;
456        if (!$eltext)
457        {
458            $eltext = '';
459            switch($element->type)
460            {
461                case 'tutorial' :
462                $eltext = $element->title;
463                break;
464                case 'class' :
465                $eltext = '<classname>'.$element->name.'</classname>';
466                break;
467                case 'method' :
468                $eltext .= '<function>';
469                case 'var' :
470                if ($element->type == 'var') $eltext .= '<varname>';
471                $eltext .= $element->class.'::';
472                case 'page' :
473                case 'define' :
474                if ($element->type == 'define')
475                $eltext .= '<constant>';
476                case 'function' :
477                if ($element->type == 'function')
478                $eltext .= '<function>';
479                case 'global' :
480                default :
481                $eltext .= $element->name;
482                if ($element->type == 'function' || $element->type == 'method') $eltext .= '</function>';
483                if ($element->type == 'var') $eltext .= '</varname>';
484                if ($element->type == 'define') $eltext .= '</constant>';
485                break;
486            }
487        } elseif (!is_object($element)) {
488            return false;
489        } elseif ($element->type == 'method')
490        {
491            $eltext = str_replace($element->name . '()', $element->name, $eltext);
492        }
493
494        if ($element->type == 'page' || $element->type == 'function' || $element->type == 'var')
495        { // we ignore all procedural pages, instead, constant, function and
496          // global variable pages are output
497            return $eltext;
498        }
499        if ($element->type == 'class')
500        {
501            return '<link linkend="'.$this->getId($element).'-summary">'.$eltext.'</link>';
502        }
503        return '<link linkend="'.$this->getId($element).'">'.$eltext.'</link>';
504    }
505
506    /**
507     * Get the id value needed to allow linking
508     * @param mixed descendant of parserElement or parserData/parserPage
509     * @param boolean true to return the id for the package page
510     * @see parserElement, parserData, parserPage
511     * @return string the id value for this element type
512     */
513    function getId(&$el, $returnpackage = false)
514    {
515        if (phpDocumentor_get_class($el) == 'parserdata')
516        {
517            $element = $this->addLink($el->parent);
518            $elp = $el->parent;
519        } elseif (!is_a($el,'abstractlink'))
520        {
521            $elp = $el;
522            $element = $this->addLink($el);
523        } else $element = $el;
524        $a = '';
525        if (!empty($element->subpackage))
526        {
527            $a = str_replace(array('_','.'),array('-','--'),$element->subpackage).'.';
528        }
529        if ($returnpackage) return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package));
530        switch ($element->type)
531        {
532            case 'page' :
533            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.'.$a.$element->fileAlias);
534            break;
535            case 'define' :
536            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.constants.details.'.$element->fileAlias);
537            break;
538            case 'global' :
539            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.globals.details.'.$element->fileAlias);
540            break;
541            case 'class' :
542            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.'.$a.str_replace(array('_','.'),array('-','--'),$element->name));
543            break;
544            case 'function' :
545            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.'.$a.$element->fileAlias.'.'.str_replace('_','-',$element->name));
546            break;
547            case 'method' :
548            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.'.$a.str_replace(array('_','.'),array('-','--'),$element->class).'.'.str_replace('_','-',$element->name));
549            break;
550            case 'var' :
551            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.'.$a.str_replace(array('_','.'),array('-','--'),$element->class).'-summary.vars.'.str_replace(array('$','_'),array('var--','-'),$element->name));
552            break;
553            case 'tutorial' :
554            return 'package.'.strtolower($element->category.'.'.str_replace(array('_','.'),array('-','--'),$element->package).'.'.$a.str_replace(array('_','.'),array('-','--'),$element->name)).'-tutorial';
555            break;
556        }
557    }
558
559    /**
560     * Create errors.html template file output
561     *
562     * This method takes all parsing errors and warnings and spits them out ordered by file and line number.
563     * @global ErrorTracker We'll be using it's output facility
564     */
565    function ConvertErrorLog()
566    {
567        global $phpDocumentor_errors;
568        $allfiles = array();
569        $files = array();
570        $warnings = $phpDocumentor_errors->returnWarnings();
571        $errors = $phpDocumentor_errors->returnErrors();
572        $template = &$this->newSmarty();
573        foreach($warnings as $warning)
574        {
575            $file = '##none';
576            $linenum = 'Warning';
577            if ($warning->file)
578            {
579                $file = $warning->file;
580                $allfiles[$file] = 1;
581                $linenum .= ' on line '.$warning->linenum;
582            }
583            $files[$file]['warnings'][] = array('name' => $linenum, 'listing' => $warning->data);
584        }
585        foreach($errors as $error)
586        {
587            $file = '##none';
588            $linenum = 'Error';
589            if ($error->file)
590            {
591                $file = $error->file;
592                $allfiles[$file] = 1;
593                $linenum .= ' on line '.$error->linenum;
594            }
595            $files[$file]['errors'][] = array('name' => $linenum, 'listing' => $error->data);
596        }
597        $i=1;
598        $af = array();
599        foreach($allfiles as $file => $num)
600        {
601            $af[$i++] = $file;
602        }
603        $allfiles = $af;
604        usort($allfiles,'strnatcasecmp');
605        $allfiles[0] = "Post-parsing";
606        foreach($allfiles as $i => $a)
607        {
608            $allfiles[$i] = array('file' => $a);
609        }
610        $out = array();
611        foreach($files as $file => $data)
612        {
613            if ($file == '##none') $file = 'Post-parsing';
614            $out[$file] = $data;
615        }
616        $template->assign("files",$allfiles);
617        $template->assign("all",$out);
618        $template->assign("title","phpDocumentor Parser Errors and Warnings");
619        $this->setTargetDir($this->base_dir);
620        $this->writefile("errors.html",$template->fetch('errors.tpl'));
621        unset($template);
622        phpDocumentor_out("\n\nTo view errors and warnings, look at ".$this->base_dir. PATH_DELIMITER . "errors.html\n");
623        flush();
624    }
625
626    function postProcess($text)
627    {
628        return str_replace("'", '&apos;', htmlentities($text));
629    }
630
631    function prepareDocBlock(&$element, $nopackage = true)
632    {
633        $a = new parserStringWithInlineTags;
634        $a->add('no exceptions thrown');
635        if (!$element->docblock->getKeyword('throws')) $element->docblock->addKeyword('throws',$a);
636        $tags = parent::prepareDocBlock($element,
637                array('staticvar' => 'note','deprec' => 'deprecated',
638                      'abstract' => 'abstract','TODO' => 'note', 'link' => 'see',
639                      'uses' => 'see', 'usedby' => 'see', 'tutorial' => 'see',
640                      'return' => 'returns', 'access' => false), $nopackage);
641        $ret = array();
642        foreach($tags['tags'] as $tag)
643        {
644            if ($tag['keyword'] == 'return')
645            {
646                // hack because stupid Converter isn't doing its job
647                $tag['keyword'] = 'returns';
648            }
649            $ret[$tag['keyword']][] = $tag;
650        }
651        $tags['tags'] = $ret;
652        $tags['sdesc'] = $this->wordwrap($tags['sdesc']);
653        return $tags;
654    }
655
656    function getTutorialId($package,$subpackage,$tutorial,$id,$category)
657    {
658        $subpackage = (empty($subpackage) ? '' : '.'.$subpackage);
659        $id = (empty($id) ? '' : '.'.$id);
660        return 'package.'.strtolower($category.'.'.$package.$subpackage.str_replace(array('_','.'),array('-','--'),$tutorial).$id);
661    }
662
663
664    /**
665     * Retrieve a Converter-specific anchor to a segment of a source code file
666     * parsed via a {@tutorial tags.filesource.pkg} tag.
667     *
668     * NOTE: unused
669     * @param string full path to source file
670     * @param string name of anchor
671     * @param string link text, if this is a link
672     * @param boolean returns either a link or a destination based on this
673     *                parameter
674     * @return string link to an anchor, or the anchor
675     */
676    function getSourceAnchor($sourcefile,$anchor,$text = '',$link = false)
677    {
678        return '';
679    }
680
681    function Br($input)
682    {
683        return "$input\n";
684    }
685
686    function getCData($value)
687    {
688        return '<![CDATA['.$value.']]>';
689    }
690
691    function ProgramExample($listing, $tutorial = false, $inlinesourceparse = null/*false*/,
692                            $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/, $origsource = null)
693    {
694        if ($origsource !== null) {
695            $listing = $origsource;
696        }
697        if (!tokenizer_ext)
698        {
699            $listing = $this->getCData($listing);
700        }
701        return '<programlisting role="php">' . $this->getCData($listing) . '</programlisting>';
702    }
703
704    /**
705     * Does nothing - use tutorials for DocBook
706     * @param parserPackagePage
707     */
708    function convertPackagePage(&$element)
709    {
710    }
711
712    /**
713     * Convert tutorials for output
714     * @param parserTutorial
715     */
716    function convertTutorial(&$element)
717    {
718        $template = &parent::convertTutorial($element);
719        phpDocumentor_out("\n");
720        flush();
721        $x = $element->Convert($this,false);
722        if ($element->ini)
723        { // add child tutorial list to the tutorial through a slight hack :)
724            $subtutorials = '';
725            $b = '';
726            if (!empty($element->subpackage)) $b = '.'.$element->subpackage;
727            foreach($element->ini['Linked Tutorials'] as $child)
728            {
729                $subtutorials .= '      &'.$element->category.'.'.$element->package.$b.'.'.str_replace(array('_','.'),array('-','--'),$child).'-'.$element->tutorial_type."-tutorial;\n";
730            }
731            $x = str_replace('</refsect1></refentry>','</refsect1>
732    <refsect1>
733     <title>Related Docs</title>
734     <para>
735'.$subtutorials.
736'     </para>
737    </refsect1></refentry>',$x);
738        }
739        $template->assign('contents',$x);
740        $contents = $template->fetch('tutorial.tpl');
741        $a = '';
742        if ($element->subpackage) $a = PATH_DELIMITER . $element->subpackage;
743        phpDocumentor_out("\n");
744        flush();
745        $this->setTargetDir($this->base_dir . PATH_DELIMITER . str_replace(array('_','.'),array('-','--'),strtolower($element->category))
746          . PATH_DELIMITER . strtolower(str_replace(array('_','.'),array('-','--'),$element->package) . $a));
747        $this->writeFile(str_replace(array('_','.'),array('-','--'),strtolower($element->name)).'-tutorial.xml',
748            '<!-- $' . "Revision$ -->\n" . $contents);
749    }
750
751    /**
752     * Does nothing in this converter
753     * @param parserVar
754     */
755    function convertVar(&$element)
756    {
757        return;
758        $docblock = $this->prepareDocBlock($element);
759        $b = 'mixed';
760        if ($element->docblock->var)
761        {
762            $b = $element->docblock->var->converted_returnType;
763        }
764//        var_dump($this->getFormattedOverrides($element));
765        if (isset($this->template_options['separatepage']) && $this->template_options['separatepage'])
766        $this->class_summary->append('vars',array('sdesc' => $docblock['sdesc'],
767                                               'desc' => $docblock['desc'],
768                                               'tags' => $docblock['tags'],
769                                               'var_name' => $this->type_adjust($element->getName()),
770                                               'var_default' => htmlspecialchars($element->getValue()),
771                                               'var_type' => $b,
772                                               'var_overrides' => $this->getFormattedOverrides($element),
773                                               'line_number' => $element->getLineNumber(),
774                                               'id' => $this->getId($element)));
775        else
776        $this->class_data->append('vars',array('sdesc' => $docblock['sdesc'],
777                                               'desc' => $docblock['desc'],
778                                               'tags' => $docblock['tags'],
779                                               'var_name' => $this->type_adjust($element->getName()),
780                                               'var_default' => htmlspecialchars($element->getValue()),
781                                               'var_type' => $b,
782                                               'var_overrides' => $this->getFormattedOverrides($element),
783                                               'line_number' => $element->getLineNumber(),
784                                               'id' => $this->getId($element)));
785    }
786
787    /**
788     * Converts class for template output
789     * @param parserClass
790     * @uses flushPackageXml() creates packagename.xml file when all classes in
791     *       a package have been converted
792     */
793    function convertClass(&$element)
794    {
795        $this->flushPackageXml($element);
796        parent::convertClass($element);
797        $docblock = $this->prepareDocBlock($element);
798        $this->method_data = array();
799        $this->class_dir = str_replace(array('_','.'),array('-','--'),$element->docblock->package);
800        $this->package = $element->docblock->package;
801        $this->category = strtolower($element->docblock->category);
802        if (!empty($element->docblock->subpackage)) $this->class_dir .= PATH_DELIMITER . $element->docblock->subpackage;
803        $docblock = $this->prepareDocBlock($element,false);
804        $this->class_data->assign("sdesc",$docblock['sdesc']);
805        $this->class_data->assign("desc",$docblock['desc']);
806        $this->class_data->assign("tags",$docblock['tags']);
807
808        $this->class_data->assign("source_location",$element->getSourceLocation($this,$this->template_options['usepear']));
809        $this->class_data->assign("id",$this->getId($element));
810        $this->class_data->assign("method_ids",array());
811        $this->left[$this->package][] = array('link' => $this->getId($element).'-summary');
812        if ($t = $element->getTutorial())
813        {
814            $this->class_data->append("method_ids",$this->getId($t));
815        }
816
817        if (isset($this->template_options['separatepage']) && $this->template_options['separatepage'])
818        {
819            $this->class_summary = &$this->newSmarty(true);
820            if ($t = $element->getTutorial())
821            {
822                $this->class_summary->assign("tutorial",$this->returnSee($t));
823            }
824
825            $this->class_summary->assign("class_name",$this->type_adjust($element->getName()));
826            $this->class_summary->assign("sdesc",$docblock['sdesc']);
827            $this->class_summary->assign("desc",$docblock['desc']);
828            $this->class_summary->assign("tags",$docblock['tags']);
829            $this->class_summary->assign("vars",array());
830            $this->class_summary->assign("methods",array());
831            $this->class_summary->assign("package",$element->docblock->package);
832
833            $this->class_summary->assign("children", $this->generateChildClassList($element));
834            $this->class_summary->assign("class_tree", $this->generateFormattedClassTree($element));
835            $this->class_summary->assign("conflicts", $this->getFormattedConflicts($element,"classes"));
836
837            $this->class_summary->assign("source_location",$element->getSourceLocation($this,$this->template_options['usepear']));
838            $this->class_summary->assign("id",$this->getId($element).'-summary');
839            $this->class_data->append("method_ids",$this->getId($element).'.'.strtolower(str_replace('_','-',$element->getName())).'-summary');
840            $inherited_methods = $this->getFormattedInheritedMethods($element);
841            if (!empty($inherited_methods))
842            {
843                $this->class_summary->assign("imethods",$inherited_methods);
844            }
845            $inherited_vars = $this->getFormattedInheritedVars($element);
846            // variables are irrelevant in peardoc2
847            if (false)//!empty($inherited_vars))
848            {
849                $this->class_summary->assign("ivars",$inherited_vars);
850            }
851            $this->addSummaryToPackageXml($this->class_summary->fetch('class_summary.tpl'));
852        }
853        $this->sourceloc = $element->getSourceLocation($this,$this->template_options['usepear']);
854    }
855
856    /**
857     * Converts method for template output
858     * @see prepareDocBlock(), parserMethod::getFunctionCall(), getFormattedDescMethods(), getFormattedOverrides()
859     * @param parserMethod
860     */
861    function convertMethod(&$element)
862    {
863        $docblock = $this->prepareDocBlock($element);
864        $returntype = 'void';
865        if ($element->docblock->return)
866        {
867            $a = $element->docblock->return->Convert($this);
868            $returntype = $element->docblock->return->converted_returnType;
869            if ($returntype != $element->docblock->return->returnType)
870            {
871                $returntype = "<replaceable>$returntype</replaceable>";
872            }
873        }
874        $params = array();
875        if (count($element->docblock->params))
876        foreach($element->docblock->params as $param => $val)
877        {
878            $a = $val->Convert($this);
879            $b = explode(' ',$a);
880            $c = '';
881            foreach($b as $blah) {
882                if (!empty($c)) {
883                    $c .= ' ';
884                }
885                $c .= str_replace(array('true', 'false', 'null'), array('&true;', '&false;', '&null;'), $blah);
886            }
887            $params[$param] = array("var" => $param,"datatype" => str_replace(array('true', 'false', 'null'), array('&true;', '&false;', '&null;'),
888                $val->returnType), "cdatatype" => $val->converted_returnType,"data" => $this->wordwrap($c));
889        }
890
891        $call = $element->getIntricateFunctionCall($this, $params);
892        if (isset($call['params']))
893        {
894            foreach($call['params'] as $i => $param)
895            {
896                if (!is_string($call['params'][$i]['default']))
897                {
898                    continue;
899                }
900                $call['params'][$i]['default'] = str_replace(array('true', 'false', 'null'), array('&true;', '&false;', '&null;'), $param['default']);
901            }
902        }
903        $this->packagexml->append('ids','&'.$this->getId($element).';');
904        $this->class_data->append('method_ids',$this->getId($element));
905        $this->class_summary->append('methods',array('id' => $this->getId($element),
906                                                  'sdesc' => $docblock['sdesc'],
907                                                  'desc' => $docblock['desc'],
908                                                  'tags' => $docblock['tags'],
909                                                  'is_constructor' => $element->isConstructor,
910                                                  'function_name' => $element->getName(),
911                                                  'function_return' => $returntype,
912                                                  'function_call' => $call,
913                                                  'descmethod' => $this->getFormattedDescMethods($element),
914                                                  'method_overrides' => $this->getFormattedOverrides($element),
915                                                  'line_number' => $element->getLineNumber(),
916                                                  'params' => $params));
917        $this->method_data[$i = count($this->method_data) - 1][0] = &$this->newSmarty(true);
918        $this->method_data[$i][1] = str_replace(array('_','.'),array('-','--'),$element->getName());
919        $this->method_data[$i][0]->assign('class',$this->class);
920        $this->method_data[$i][0]->assign('source_location',$this->returnSee($this->getLink(basename($this->curpage->getFile())),$this->sourceloc));
921        $this->method_data[$i][0]->assign('sdesc',$docblock['sdesc']);
922        $this->method_data[$i][0]->assign('desc',$docblock['desc']);
923        $this->method_data[$i][0]->assign('tags',$docblock['tags']);
924        $this->method_data[$i][0]->assign('function_name',$element->getName());
925        $this->method_data[$i][0]->assign('function_return',$returntype);
926        $this->method_data[$i][0]->assign('function_call',$call);
927        $this->method_data[$i][0]->assign('descmethod',$this->getFormattedDescMethods($element));
928        $this->method_data[$i][0]->assign('method_overrides',$this->getFormattedOverrides($element));
929        $this->method_data[$i][0]->assign('params',$params);
930        $this->method_data[$i][0]->assign('id',$this->getId($element));
931    }
932
933    /**
934     * Converts function for template output - does nothing in peardoc2!
935     * @param parserFunction
936     */
937    function convertFunction(&$element)
938    {
939/*        parent::convertFunction($element);
940        $docblock = $this->prepareDocBlock($element);
941        $fname = $element->getName();
942        $params = array();
943        if (count($element->docblock->params))
944        foreach($element->docblock->params as $param => $val)
945        {
946            $a = $val->Convert($this);
947            $params[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
948        }
949        $returntype = 'void';
950        if ($element->docblock->return)
951        {
952            $a = $element->docblock->return->Convert($this);
953            $returntype = $element->docblock->return->converted_returnType;
954        }
955
956        $this->page_data->append("function_ids",$this->getId($element));
957        $this->page_summary->append("function_ids",$this->getId($element));
958        $this->page_summary->append('functions',array('id' => $this->getId($element),
959                                                   'sdesc' => $docblock['sdesc'],
960                                                   'desc' => $docblock['desc'],
961                                                   'tags' => $docblock['tags'],
962                                                   'function_name' => $element->getName(),
963                                                   'line_number' => $element->getLineNumber(),
964                                                   'function_return' => $returntype,
965                                                   'function_call' => $element->getIntricateFunctionCall($this,$params),
966                                                   'function_conflicts' => $this->getFormattedConflicts($element,'functions'),
967                                                   'params' => $params));
968        $this->function_data[$i = count($this->function_data) - 1][0] = $this->newSmarty(true);
969        $this->function_data[$i][1] = $element->getName();
970        $this->function_data[$i][0]->assign('sdesc',$docblock['sdesc']);
971        $this->function_data[$i][0]->assign('desc',$docblock['desc']);
972        $this->function_data[$i][0]->assign('tags',$docblock['tags']);
973        $this->function_data[$i][0]->assign('function_name',$fname);
974        $this->function_data[$i][0]->assign('line_number',$element->getLineNumber());
975        $this->function_data[$i][0]->assign('function_return',$returntype);
976        $this->function_data[$i][0]->assign('function_call',$element->getIntricateFunctionCall($this,$params));
977        $this->function_data[$i][0]->assign('function_conflicts',$this->getFormattedConflicts($element,"functions"));
978        $this->function_data[$i][0]->assign('params',$params);
979        $this->function_data[$i][0]->assign('source_location',$this->returnSee($this->getLink(basename($this->curpage->getFile())),$this->sourceloc));
980        $this->function_data[$i][0]->assign('id',$this->getId($element));*/
981    }
982
983    /**
984     * Converts include elements for template output
985     *
986     * Completely ignored by this converter
987     * @param parserInclude
988     */
989    function convertInclude(&$element)
990    {
991/*        parent::convertInclude($element, array('include_file'    => '-'.strtr($element->getValue(),array('"' => '', "'" => '','.' => '-'))));
992        $docblock = $this->prepareDocBlock($element);
993        $per = $this->getIncludeValue($element->getValue(), $element->getPath());
994        $this->page_summary->append('includes',array('sdesc' => $docblock['sdesc'],
995                                                   'desc' => $docblock['desc'],
996                                                  'tags' => $docblock['tags'],
997                                                  'utags' => $docblock['utags'],
998                                                  'include_name'     => $element->getName(),
999                                                  'include_value'    => $per,
1000                                                  'line_number' => $element->getLineNumber(),
1001                                                  'include_file'    => '-'.strtr($element->getValue(),array('"' => '', "'" => '','.' => '-'))));*/
1002    }
1003
1004    /**
1005     * Converts defines for template output
1006     * @see prepareDocBlock(), getFormattedConflicts()
1007     * @param parserDefine
1008     */
1009    function convertDefine(&$element)
1010    {
1011        $docblock = $this->prepareDocBlock($element);
1012        $this->_appendDefines(array('sdesc' => $docblock['sdesc'],
1013                                   'desc' => $docblock['desc'],
1014                                   'tags' => $docblock['tags'],
1015                                   'name'     => $this->postProcess($element->getName()),
1016                                   'value'    => $this->postProcess($element->getValue()),
1017                                   'conflicts'    => $this->getFormattedConflicts($element,"defines"),
1018                                   'line_number' => $element->getLineNumber(),
1019                                   'id' => $this->getId($element)));
1020    }
1021
1022    /**
1023     * Append the constant information to the Smarty information
1024     *
1025     * Uses category, package, and current file to organize constants defined
1026     * in a package for the constants.xml output file
1027     * @param array
1028     * @uses $_peardoc2_constants appends $define to them
1029     * @access private
1030     */
1031    function _appendDefines($define)
1032    {
1033        if (!isset($this->_peardoc2_constants[$this->category][$this->package][$this->sourceloc]))
1034        {
1035            $this->_peardoc2_constants[$this->category][$this->package][$this->sourceloc]['name'] =
1036                $this->sourceloc;
1037            $this->_peardoc2_constants[$this->category][$this->package][$this->sourceloc]['page'] =
1038                $this->page;
1039        }
1040        $this->_write_constants_xml[$this->category][$this->package] = true;
1041        $this->_peardoc2_constants[$this->category][$this->package][$this->sourceloc]['defines'][] = $define;
1042    }
1043
1044    /**
1045     * Converts global variables for template output
1046     * @param parserGlobal
1047     * @see prepareDocBlock(), getFormattedConflicts()
1048     */
1049    function convertGlobal(&$element)
1050    {
1051        $docblock = $this->prepareDocBlock($element);
1052        $value = $this->getGlobalValue($element->getValue());
1053        if ($value == $element->getValue())
1054        {
1055            $value = $this->ProgramExample($value);
1056        } else
1057        {
1058            $value = $this->getGlobalValue('<![CDATA[' .$element->getValue() . ']]>');
1059        }
1060        $this->_appendGlobals(array('sdesc' => $docblock['sdesc'],
1061                                   'desc' => $docblock['desc'],
1062                                   'tags' => $docblock['tags'],
1063                                   'name'     => $this->postProcess($element->getName()),
1064                                   'link'    => $element->getName(),
1065                                   'value'    => $value,
1066                                   'type' => $element->getDataType($this),
1067                                   'line_number' => $element->getLineNumber(),
1068                                   'conflicts'    => $this->getFormattedConflicts($element,"global variables"),
1069                                   'id' => $this->getId($element)));
1070    }
1071
1072    /**
1073     * Append the global variable information to the Smarty information
1074     *
1075     * Uses category, package, and current file to organize globals defined
1076     * in a package for the globals.xml output file
1077     * @param array
1078     * @uses $_peardoc2_globals appends $global to them
1079     * @access private
1080     */
1081    function _appendGlobals($global)
1082    {
1083        if (!isset($this->_peardoc2_globals[$this->category][$this->package][$this->sourceloc]))
1084        {
1085            $this->_peardoc2_globals[$this->category][$this->package][$this->sourceloc]['name'] =
1086                $this->sourceloc;
1087            $this->_peardoc2_globals[$this->category][$this->package][$this->sourceloc]['page'] =
1088                $this->page;
1089        }
1090        $this->_write_globals_xml[$this->category][$this->package] = true;
1091        $this->_peardoc2_globals[$this->category][$this->package][$this->sourceloc]['globals'][] = $global;
1092    }
1093
1094    /**
1095     * converts procedural pages for template output
1096     * @see prepareDocBlock(), getClassesOnPage()
1097     * @param parserData
1098     */
1099    function convertPage(&$element)
1100    {
1101        parent::convertPage($element);
1102        $this->juststarted = true;
1103        $this->page_dir = $element->parent->package;
1104        $this->page = $this->getPageName($element->parent);
1105        $this->category = strtolower($element->parent->category);
1106        $this->sourceloc = $element->parent->getSourceLocation($this,true);
1107        if (!empty($element->parent->subpackage)) $this->page_dir .= PATH_DELIMITER . $element->parent->subpackage;
1108        // registering stuff on the template
1109    }
1110
1111    function getPageName(&$element)
1112    {
1113        return str_replace(array('/','_','.'),array('-','-','---'),$element->getSourceLocation($this,true));
1114    }
1115
1116    /**
1117     * returns an array containing the class inheritance tree from the root object to the class
1118     *
1119     * @param parserClass    class variable
1120     * @return array Format: array(root,child,child,child,...,$class)
1121     * @uses parserClass::getParentClassTree()
1122     */
1123
1124    function generateFormattedClassTree($class)
1125    {
1126        $tree = $class->getParentClassTree($this);
1127        $out = '';
1128        if (count($tree) - 1)
1129        {
1130            $result = array($class->getName());
1131            $parent = $tree[$class->getName()];
1132            while ($parent)
1133            {
1134                if (is_string($parent)) {
1135                    $result[] = $parent;
1136                    break;
1137                }
1138                $subpackage = $parent->docblock->subpackage;
1139                $package = $parent->docblock->package;
1140                $x = $parent;
1141                if (is_object($parent))
1142                $x = $parent->getLink($this);
1143                if (!$x) $x = $parent->getName();
1144                $result[] =
1145                    $x;
1146                if (is_object($parent))
1147                $parent = $tree[$parent->getName()];
1148                elseif (isset($tree[$parent]))
1149                $parent = $tree[$parent];
1150            }
1151            return array_reverse($result);
1152        } else
1153        {
1154            return array($class->getName());
1155        }
1156    }
1157
1158    /**
1159     * returns a list of child classes
1160     *
1161     * @param parserClass class variable
1162     * @uses parserClass::getChildClassList()
1163     */
1164
1165    function generateChildClassList($class)
1166    {
1167        $kids = $class->getChildClassList($this);
1168        $list = array();
1169        if (count($kids))
1170        {
1171            for($i=0; $i<count($kids); $i++)
1172            {
1173                $lt['link'] = '<link linkend="'.$this->getId($kids[$i]) . '-summary">'. $kids[$i]->getName().'</link>';
1174                $lt['sdesc'] = $kids[$i]->docblock->getSDesc($this);
1175                $list[] = $lt;
1176            }
1177        } else return false;
1178        return $list;
1179    }
1180
1181    /** @access private */
1182    function sortVar($a, $b)
1183    {
1184        return strnatcasecmp($a->getName(),$b->getName());
1185    }
1186
1187    /** @access private */
1188    function sortMethod($a, $b)
1189    {
1190        if ($a->isConstructor) return -1;
1191        if ($b->isConstructor) return 1;
1192        return strnatcasecmp($a->getName(),$b->getName());
1193    }
1194
1195    /**
1196     * returns a template-enabled array of class trees
1197     *
1198     * @param    string    $package    package to generate a class tree for
1199     * @see $roots, HTMLConverter::getRootTree()
1200     */
1201    function generateFormattedClassTrees($package)
1202    {
1203        if (!isset($this->roots['normal'][$package]) &&
1204              !isset($this->roots['special'][$package])) {
1205            return array();
1206        }
1207        $trees = array();
1208        if (isset($this->roots['normal'][$package])) {
1209            $roots = $this->roots['normal'][$package];
1210            for($i=0;$i<count($roots);$i++)
1211            {
1212                $root = $this->classes->getClassByPackage($roots[$i], $package);
1213                if ($root && $root->isInterface()) {
1214                    continue;
1215                }
1216                $trees[] = array('class' => $roots[$i],'class_tree' => "<ul>\n".$this->getRootTree($this->getSortedClassTreeFromClass($roots[$i],$package,''),$package)."</ul>\n");
1217            }
1218        }
1219        if (isset($this->roots['special'][$package])) {
1220            $roots = $this->roots['special'][$package];
1221            foreach ($roots as $parent => $classes) {
1222                $thistree = '';
1223                foreach ($classes as $classinfo) {
1224                    $root = $this->classes->getClassByPackage($classinfo, $package);
1225                    if ($root && $root->isInterface()) {
1226                        continue;
1227                    }
1228                    $thistree .=
1229                        $this->getRootTree(
1230                            $this->getSortedClassTreeFromClass(
1231                                $classinfo,
1232                                $package,
1233                                ''),
1234                            $package,
1235                            true);
1236                }
1237                if (!$thistree) {
1238                    continue;
1239                }
1240                $trees[] = array(
1241                    'class' => $parent,
1242                    'class_tree' => "<ul>\n" . $thistree . "</ul>\n"
1243                );
1244            }
1245        }
1246        return $trees;
1247    }
1248
1249    /**
1250     * returns a template-enabled array of interface inheritance trees
1251     *
1252     * @param    string    $package    package to generate a class tree for
1253     * @see $roots, HTMLConverter::getRootTree()
1254     */
1255    function generateFormattedInterfaceTrees($package)
1256    {
1257        if (!isset($this->roots['normal'][$package]) &&
1258              !isset($this->roots['special'][$package])) {
1259            return array();
1260        }
1261        $trees = array();
1262        if (isset($this->roots['normal'][$package])) {
1263            $roots = $this->roots['normal'][$package];
1264            for($i=0;$i<count($roots);$i++)
1265            {
1266                $root = $this->classes->getClassByPackage($roots[$i], $package);
1267                if ($root && !$root->isInterface()) {
1268                    continue;
1269                }
1270                $trees[] = array('class' => $roots[$i],'class_tree' => "<ul>\n".$this->getRootTree($this->getSortedClassTreeFromClass($roots[$i],$package,''),$package)."</ul>\n");
1271            }
1272        }
1273        if (isset($this->roots['special'][$package])) {
1274            $roots = $this->roots['special'][$package];
1275            foreach ($roots as $parent => $classes) {
1276                $thistree = '';
1277                foreach ($classes as $classinfo) {
1278                    $root = $this->classes->getClassByPackage($classinfo, $package);
1279                    if ($root && !$root->isInterface()) {
1280                        continue;
1281                    }
1282                    $thistree .=
1283                        $this->getRootTree(
1284                            $this->getSortedClassTreeFromClass(
1285                                $classinfo,
1286                                $package,
1287                                ''),
1288                            $package,
1289                            true);
1290                }
1291                if (!$thistree) {
1292                    continue;
1293                }
1294                $trees[] = array(
1295                    'class' => $parent,
1296                    'class_tree' => "<ul>\n" . $thistree . "</ul>\n"
1297                );
1298            }
1299        }
1300        return $trees;
1301    }
1302
1303    /**
1304     * return formatted class tree for the Class Trees page
1305     *
1306     * @param array $tree output from {@link getSortedClassTreeFromClass()}
1307     * @param string $package  package
1308     * @param boolean $nounknownparent if true, an object's parent will not be checked
1309     * @see Classes::$definitechild, generateFormattedClassTrees()
1310     * @return string
1311     */
1312    function getRootTree($tree, $package, $noparent = false)
1313    {
1314        if (!$tree) return '';
1315        $my_tree = '';
1316        $cur = '#root';
1317        $lastcur = array(false);
1318        $kids = array();
1319        $dopar = false;
1320        if (!$noparent && $tree[$cur]['parent'])
1321        {
1322            $dopar = true;
1323            if (!is_object($tree[$cur]['parent']))
1324            {
1325//                debug("parent ".$tree[$cur]['parent']." not found");
1326                $my_tree .= '<listitem>' . $tree[$cur]['parent'] .'<itemizedlist>';
1327            }
1328            else
1329            {
1330//                        debug("parent ".$this->returnSee($tree[$cur]['parent'], false, false)." in other package");
1331                $my_tree .= '<listitem>' . $this->returnSee($tree[$cur]['parent'], false, false);
1332                if ($tree[$cur]['parent']->package != $package) $my_tree .= ' <emphasis>(Different package)</emphasis><itemizedlist>';
1333            }
1334        }
1335        do
1336        {
1337//            fancy_debug($cur,$lastcur,$kids);
1338            if (count($tree[$cur]['children']))
1339            {
1340//                debug("$cur has children");
1341                if (!isset($kids[$cur]))
1342                {
1343//                    debug("set $cur kids");
1344                    $kids[$cur] = 1;
1345                    $my_tree .= '<listitem>'.$this->returnSee($tree[$cur]['link'], false, false);
1346                    $my_tree .= '<itemizedlist>'."\n";
1347                }
1348                array_push($lastcur,$cur);
1349                list(,$cur) = each($tree[$cur]['children']);
1350//                var_dump('listed',$cur);
1351                if ($cur)
1352                {
1353                    $cur = $cur['package'] . '#' . $cur['class'];
1354//                    debug("set cur to child $cur");
1355//                    $my_tree .= '<li>'.$this->returnSee($tree[$cur]['link'], false, false);
1356                    continue;
1357                } else
1358                {
1359//                    debug("end of children for $cur");
1360                    $cur = array_pop($lastcur);
1361                    $cur = array_pop($lastcur);
1362                    $my_tree .= '</itemizedlist></listitem>'."\n";
1363                    if ($dopar && ($cur == '#root' || !$cur)) $my_tree .= '</itemizedlist></listitem>';
1364                }
1365            } else
1366            {
1367//                debug("$cur has no children");
1368                $my_tree .= '<listitem>'.$this->returnSee($tree[$cur]['link'], false, false)."</listitem>";
1369                if ($dopar && $cur == '#root') $my_tree .= '</itemizedlist></listitem>';
1370                $cur = array_pop($lastcur);
1371            }
1372        } while ($cur);
1373        return $my_tree;
1374    }
1375    /**
1376     * does nothing
1377     */
1378    function generateElementIndex()
1379    {
1380    }
1381
1382    function setTemplateDir($dir)
1383    {
1384        Converter::setTemplateDir($dir);
1385        $this->smarty_dir = $this->templateDir;
1386    }
1387
1388    /**
1389     * Generate alphabetical index of all elements by package and subpackage
1390     *
1391     * @param string $package name of a package
1392     * @see $pkg_elements, walk(), generatePkgElementIndexes()
1393     */
1394    function generatePkgElementIndex($package)
1395    {
1396    }
1397
1398    /**
1399     *
1400     * @see generatePkgElementIndex()
1401     */
1402    function generatePkgElementIndexes()
1403    {
1404    }
1405
1406    /**
1407     * @param string name of class
1408     * @param string package name
1409     * @param string full path to look in (used in index generation)
1410     * @param boolean deprecated
1411     * @param boolean return just the URL, or enclose it in an html a tag
1412     * @return mixed false if not found, or an html a link to the class's documentation
1413     * @see parent::getClassLink()
1414     */
1415    function getClassLink($expr,$package, $file = false,$text = false, $local = true, $with_a = true)
1416    {
1417        $a = Converter::getClassLink($expr,$package,$file);
1418        if (!$a) return false;
1419        return $this->returnSee($a, $text, $local, $with_a);
1420    }
1421
1422    /**
1423     * @param string name of function
1424     * @param string package name
1425     * @param string full path to look in (used in index generation)
1426     * @param boolean deprecated
1427     * @param boolean return just the URL, or enclose it in an html a tag
1428     * @return mixed false if not found, or an html a link to the function's documentation
1429     * @see parent::getFunctionLink()
1430     */
1431    function getFunctionLink($expr,$package, $file = false,$text = false, $local = true)
1432    {
1433        $a = Converter::getFunctionLink($expr,$package,$file);
1434        if (!$a) return false;
1435        return $this->returnSee($a, $text, $local);
1436    }
1437
1438    /**
1439     * @param string name of define
1440     * @param string package name
1441     * @param string full path to look in (used in index generation)
1442     * @param boolean deprecated
1443     * @param boolean return just the URL, or enclose it in an html a tag
1444     * @return mixed false if not found, or an html a link to the define's documentation
1445     * @see parent::getDefineLink()
1446     */
1447    function getDefineLink($expr,$package, $file = false,$text = false, $local = true)
1448    {
1449        $a = Converter::getDefineLink($expr,$package,$file);
1450        if (!$a) return false;
1451        return $this->returnSee($a, $text, $local);
1452    }
1453
1454    /**
1455     * @param string name of global variable
1456     * @param string package name
1457     * @param string full path to look in (used in index generation)
1458     * @param boolean deprecated
1459     * @param boolean return just the URL, or enclose it in an html a tag
1460     * @return mixed false if not found, or an html a link to the global variable's documentation
1461     * @see parent::getGlobalLink()
1462     */
1463    function getGlobalLink($expr,$package, $file = false,$text = false, $local = true)
1464    {
1465        $a = Converter::getGlobalLink($expr,$package,$file);
1466        if (!$a) return false;
1467        return $this->returnSee($a, $text, $local);
1468    }
1469
1470    /**
1471     * @param string name of procedural page
1472     * @param string package name
1473     * @param string full path to look in (used in index generation)
1474     * @param boolean deprecated
1475     * @param boolean return just the URL, or enclose it in an html a tag
1476     * @return mixed false if not found, or an html a link to the procedural page's documentation
1477     * @see parent::getPageLink()
1478     */
1479    function getPageLink($expr,$package, $path = false,$text = false, $local = true)
1480    {
1481        $a = Converter::getPageLink($expr,$package,$path);
1482        if (!$a) return false;
1483        return $this->returnSee($a, $text, $local);
1484    }
1485
1486    /**
1487     * @param string name of method
1488     * @param string class containing method
1489     * @param string package name
1490     * @param string full path to look in (used in index generation)
1491     * @param boolean deprecated
1492     * @param boolean return just the URL, or enclose it in an html a tag
1493     * @return mixed false if not found, or an html a link to the method's documentation
1494     * @see parent::getMethodLink()
1495     */
1496    function getMethodLink($expr,$class,$package, $file = false,$text = false, $local = true)
1497    {
1498        $a = Converter::getMethodLink($expr,$class,$package,$file);
1499        if (!$a) return false;
1500        return $this->returnSee($a, $text, $local);
1501    }
1502
1503    /**
1504     * @param string name of var
1505     * @param string class containing var
1506     * @param string package name
1507     * @param string full path to look in (used in index generation)
1508     * @param boolean deprecated
1509     * @param boolean return just the URL, or enclose it in an html a tag
1510     * @return mixed false if not found, or an html a link to the var's documentation
1511     * @see parent::getVarLink()
1512     */
1513    function getVarLink($expr,$class,$package, $file = false,$text = false, $local = true)
1514    {
1515        $a = Converter::getVarLink($expr,$class,$package,$file);
1516        if (!$a) return false;
1517        return $this->returnSee($a, $text, $local);
1518    }
1519
1520    /**
1521     * does a nat case sort on the specified second level value of the array
1522     *
1523     * @param    mixed    $a
1524     * @param    mixed    $b
1525     * @return    int
1526     */
1527    function rcNatCmp ($a, $b)
1528    {
1529        $aa = strtoupper($a[$this->rcnatcmpkey]);
1530        $bb = strtoupper($b[$this->rcnatcmpkey]);
1531
1532        return strnatcasecmp($aa, $bb);
1533    }
1534
1535    /**
1536     * does a nat case sort on the specified second level value of the array.
1537     * this one puts constructors first
1538     *
1539     * @param    mixed    $a
1540     * @param    mixed    $b
1541     * @return    int
1542     */
1543    function rcNatCmp1 ($a, $b)
1544    {
1545        $aa = strtoupper($a[$this->rcnatcmpkey]);
1546        $bb = strtoupper($b[$this->rcnatcmpkey]);
1547
1548        if (strpos($aa,'CONSTRUCTOR') === 0)
1549        {
1550            return -1;
1551        }
1552        if (strpos($bb,'CONSTRUCTOR') === 0)
1553        {
1554            return 1;
1555        }
1556        if (strpos($aa,strtoupper($this->class)) === 0)
1557        {
1558            return -1;
1559        }
1560        if (strpos($bb,strtoupper($this->class)) === 0)
1561        {
1562            return -1;
1563        }
1564        return strnatcasecmp($aa, $bb);
1565    }
1566
1567    function wordwrap($string)
1568    {
1569        return wordwrap($string);
1570    }
1571
1572    /**
1573     * Generate the constants.xml, packagename.xml, and globals.xml files
1574     */
1575    function Output()
1576    {
1577        $this->flushPackageXml(false);
1578        $templ = &$this->newSmarty();
1579        $categories = array();
1580        $packages = array_flip($this->all_packages);
1581        foreach($this->packagecategories as $package => $category)
1582        {
1583            $categories[$category]['package.'.$category.'.'.str_replace('_','-',strtolower($package ))] = 1;
1584            if (isset($packages[$package])) unset($packages[$package]);
1585        }
1586        $category = $GLOBALS['phpDocumentor_DefaultCategoryName'];
1587        foreach($packages as $package)
1588        {
1589            $categories[$category]['package.'.$category.'.'.str_replace('_','-',strtolower($package ))] = 1;
1590        }
1591        foreach($categories as $category => $ids)
1592        {
1593            $templ->assign('id','package.'.$category);
1594            $templ->assign('ids',array());
1595            $templ->assign('category',$category);
1596            $this->setTargetDir($this->base_dir);
1597            if (file_exists($this->base_dir . PATH_DELIMITER . strtolower($category ) . '.xml'))
1598            {
1599                $contents = @file($this->base_dir . PATH_DELIMITER . strtolower($category ) . '.xml');
1600                if (is_array($contents))
1601                {
1602                    $found = false;
1603                    foreach($contents as $i => $line)
1604                    {
1605                        $line = trim($line);
1606                        if (strlen($line) && $line{0} == '&')
1607                        {
1608                            $found = $i;
1609                            if (in_array(str_replace(array ('&', ';'), array ('', ''), trim($line )), array_keys($ids )))
1610                            {
1611                                unset($ids[str_replace(array('&', ';'), array('', ''), trim($line))]);
1612                            }
1613                        }
1614                        if ($found !== false && (!strlen($line) || $line{0} != '&'))
1615                        {
1616                            break;
1617                        }
1618                    }
1619                    $newids = array();
1620                    foreach($ids as $id => $unll)
1621                    {
1622                        $newids[] = ' &' . $id . ";\n";
1623                    }
1624                    $newcontents = array_merge(array_slice($contents, 0, $i), $newids);
1625                    $newcontents = array_merge($newcontents, array_slice($contents, $i));
1626                }
1627                $categorycontents = implode($newcontents, '');
1628            } else
1629            {
1630                foreach($ids as $id => $unll)
1631                {
1632                    if (!in_array($id, $templ->_tpl_vars['ids']))
1633                    {
1634                        $templ->append('ids',$id);
1635                    }
1636                }
1637                $categorycontents = '<!-- $' . "Revision$ -->\n" . $templ->fetch('category.tpl');
1638            }
1639            $this->writefile(strtolower($category) . '.xml',
1640                $categorycontents);
1641            phpDocumentor_out("\n");
1642            flush();
1643        }
1644        $my = &$this->newSmarty();
1645        if ($this->_peardoc2_constants)
1646        {
1647            foreach($this->_peardoc2_constants as $category => $r)
1648            {
1649                foreach($r as $package => $s)
1650                {
1651                    $my->assign('id','package.'.strtolower($category.'.'.str_replace('_','-',strtolower($package ))).'.constants');
1652                    $my->assign('package',$package);
1653                    $defines = array();
1654                    foreach($s as $file => $t)
1655                    {
1656                        $arr = array();
1657                        $arr['name'] = $file;
1658                        $arr['page'] = strtolower($t['page']);
1659                        $arr['defines'] = $t['defines'];
1660                        $defines[] = $arr;
1661                    }
1662                    $my->assign('defines',$defines);
1663                    $this->setTargetDir($this->base_dir . PATH_DELIMITER . $category
1664                       . PATH_DELIMITER . strtolower(str_replace('_','-',strtolower($package ))));
1665                    $this->writefile('constants.xml',
1666                        '<!-- $' . "Revision$ -->\n" . $my->fetch('constants.tpl'));
1667                    $my->clear_all_assign();
1668                }
1669            }
1670            $this->_peardoc2_constants = false;
1671        }
1672        if ($this->_peardoc2_globals)
1673        {
1674            foreach($this->_peardoc2_globals as $category => $r)
1675            {
1676                foreach($r as $package => $s)
1677                {
1678                    $my->assign('id','package.'.strtolower($category.'.'.str_replace('_','-',strtolower($package ))).'.globals');
1679                    $my->assign('package',$package);
1680                    $defines = array();
1681                    foreach($s as $file => $t)
1682                    {
1683                        $arr = array();
1684                        $arr['name'] = $file;
1685                        $arr['page'] = strtolower($t['page']);
1686                        $arr['globals'] = $t['globals'];
1687                        $defines[] = $arr;
1688                    }
1689                    $my->assign('globals',$defines);
1690                    $this->setTargetDir($this->base_dir . PATH_DELIMITER . $category
1691                       . PATH_DELIMITER . strtolower(str_replace('_','-',strtolower($package ))));
1692                    $this->writefile('globals.xml',
1693                        '<!-- $' . "Revision$ -->\n" . $my->fetch('globals.tpl'));
1694                    $my->clear_all_assign();
1695                }
1696            }
1697            $this->_peardoc2_globals = false;
1698        }
1699    }
1700}
1701?>
1702