changed git call from https to git readonly
[atutor.git] / mods / phpdoc2 / PhpDocumentor / phpDocumentor / ParserDocBlock.inc
1 <?php\r
2 /**\r
3  * DocBlock Parser Classes\r
4  * \r
5  * phpDocumentor :: automatic documentation generator\r
6  * \r
7  * PHP versions 4 and 5\r
8  *\r
9  * Copyright (c) 2002-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    phpDocumentor\r
29  * @subpackage ParserDocBlock\r
30  * @author     Gregory Beaver <cellog@php.net>\r
31  * @copyright  2002-2006 Gregory Beaver\r
32  * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL\r
33  * @version    CVS: $Id: ParserDocBlock.inc,v 1.12 2007/04/19 20:20:57 ashnazg Exp $\r
34  * @link       http://www.phpdoc.org\r
35  * @link       http://pear.php.net/PhpDocumentor\r
36  * @see        Parser, WordParser\r
37  * @since      1.0rc1\r
38  */\r
39 /**\r
40  * represents a short or long description in a DocBlock ({@link parserDocBlock})\r
41  * @package phpDocumentor\r
42  * @subpackage ParserDocBlock\r
43  * @author Greg Beaver <cellog@php.net>\r
44  * @since 1.0rc1\r
45  * @version $Id: ParserDocBlock.inc,v 1.12 2007/04/19 20:20:57 ashnazg Exp $\r
46  */\r
47 class parserDesc extends parserStringWithInlineTags\r
48 {\r
49     /**\r
50      * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah'\r
51      * always '_desc'\r
52      * @var string\r
53      */\r
54     var $type = '_desc';\r
55     \r
56     /**\r
57      * @param mixed like {@link parserStringWithInlineTags::add()}, this can be a string or parserInlineTag, but it can also be a\r
58      *              parserStringWithInlineTags, and the contents will be merged\r
59      */\r
60     function add($stringOrClass)\r
61     {\r
62         if (is_object($stringOrClass))\r
63         {\r
64             if (phpDocumentor_get_class($stringOrClass) == 'parserstringwithinlinetags' ||\r
65                 phpDocumentor_get_class($stringOrClass) == 'parserdesc')\r
66             {\r
67                 for($i=0;$i<count($stringOrClass->value);$i++)\r
68                 {\r
69                     parserStringWithInlineTags::add($stringOrClass->value[$i]);\r
70                 }\r
71             } else\r
72             {\r
73                 parserStringWithInlineTags::add($stringOrClass);\r
74             }\r
75         } else return parserStringWithInlineTags::add($stringOrClass);\r
76     }\r
77     \r
78     /**\r
79      * @return boolean whether this desc has an {@}inheritdoc} inline tag\r
80      */\r
81     function hasInheritDoc()\r
82     {\r
83         for($i=0;$i<count($this->value);$i++)\r
84         {\r
85             if (phpDocumentor_get_class($this->value[$i])=='parserinheritdocinlinetag') return true;\r
86         }\r
87     }\r
88     \r
89     /**\r
90      * @return boolean whether this desc has an {@}source} inline tag\r
91      */\r
92     function hasSource()\r
93     {\r
94         for($i=0;$i<count($this->value);$i++)\r
95         {\r
96             if (phpDocumentor_get_class($this->value[$i])=='parsersourceinlinetag') return true;\r
97         }\r
98     }\r
99     \r
100     /**\r
101      * replaces {@}inheritdoc} with the contents of the parent DocBlock\r
102      * @param parserDesc parent parserDesc, used to retrieve the description\r
103      */\r
104     function replaceInheritDoc($desc)\r
105     {\r
106         $value = $this->value;\r
107         $this->value = array();\r
108         for($i=0;$i<count($value);$i++)\r
109         {\r
110             if (phpDocumentor_get_class($value[$i])=='parserinheritdocinlinetag')\r
111             {\r
112                 for($j=0;$j<count($desc->value);$j++)\r
113                 {\r
114                     $this->add($desc->value[$j]);\r
115                 }\r
116             } else $this->add($value[$i]);\r
117         }\r
118     }\r
119 }\r
120 \r
121 /**\r
122  * Represents a docblock and its components, {@link $desc}, {@link $sdesc}, {@link $tags}, and also {@link $params} for functions\r
123  * @package phpDocumentor\r
124  * @subpackage ParserDocBlock\r
125  * @author Greg Beaver <cellog@php.net>\r
126  * @since 1.0rc1\r
127  * @version $Id: ParserDocBlock.inc,v 1.12 2007/04/19 20:20:57 ashnazg Exp $\r
128  */\r
129 class parserDocBlock\r
130 {\r
131     /**\r
132      * @var parserDesc\r
133      */\r
134     var $desc = false;\r
135     /**\r
136      * @var array array of {@link parserDesc}s\r
137      */\r
138     var $processed_desc = false;\r
139     /**\r
140      * @var array array of {@link parserDesc}s\r
141      */\r
142     var $processed_sdesc = false;\r
143     /**\r
144      * @var parserDesc\r
145      */\r
146     var $sdesc = false;\r
147     /**\r
148      * Line number in the source on which this docblock begins\r
149      * @since 1.2\r
150      * @var false|integer\r
151      */\r
152     var $linenumber = false;\r
153     /**\r
154      * Line number in the source on which this docblock ends\r
155      * @since 1.2\r
156      * @var false|integer\r
157      */\r
158     var $endlinenumber = false;\r
159     /**\r
160      * array of {@link parserTag}s\r
161      * @var array\r
162      */\r
163     var $tags = array();\r
164     /**\r
165      * array of unrecognized {@link parserTag}s\r
166      * @var array\r
167      */\r
168     var $unknown_tags = array();\r
169     /**\r
170      * array of param data.\r
171      * Format:\r
172      * array(index of param in function parameter list -OR- parameter name =>\r
173      *         parserStringWithInlineTags,...)\r
174      * @var array\r
175      */\r
176     var $params = array();\r
177     /**\r
178      * array of global variable data.\r
179      * Format:\r
180      * array(index of global variable in @global tag list -OR- global variable name =>\r
181      *         array(datatype,parserStringWithInlineTags),...)\r
182      * @var array\r
183      */\r
184     var $funcglobals = array();\r
185     \r
186     /**\r
187      * array of static variable data.\r
188      * Format:\r
189      * array(index of static variable in @global tag list -OR- static variable name =>\r
190      *         {@link parserStaticvarTag},...)\r
191      * @var array\r
192      */\r
193     var $statics = array();\r
194     /**\r
195      * array of {@link parserPropertyTag}, {@link parserPropertyReadTag}, {@link parserPropertyWriteTag}, {@link parserMethodTag} magic tags\r
196      */\r
197     var $properties = array();\r
198     /**\r
199      * This is either a {@link parserReturnTag} or false if no return tag is present\r
200      * @var mixed\r
201      */\r
202     var $return = false;\r
203     /**\r
204      * This is either a {@link parserVarTag} or false if no var tag is present\r
205      * @var mixed\r
206      */\r
207     var $var = false;\r
208     /**\r
209      * fix for bug 591396\r
210      * @var boolean\r
211      */\r
212     var $explicitpackage = false;\r
213     /**\r
214      * fix for bug 708559\r
215      * @var boolean\r
216      */\r
217     var $explicitcategory = false;\r
218     /** @var string */\r
219     var $category;\r
220     /** @var string */\r
221     var $package = 'default';\r
222     /** @var string */\r
223     var $subpackage = '';\r
224     /**\r
225      * whether this DocBlock has an @access tag\r
226      * @var boolean */\r
227     var $hasaccess = false;\r
228     /**\r
229      * whether this DocBlock has a @name tag\r
230      * @var boolean */\r
231     var $hasname = false;\r
232     /**\r
233      * description of package parsed from @package tag\r
234      * Unused in this version\r
235      * @var string\r
236      */\r
237     var $packagedescrip = '';\r
238     /**\r
239      * description of subpackage parsed from @package tag\r
240      * Unused in this version\r
241      * @var string\r
242      */\r
243     var $subpackagedescrip = '';\r
244     /**\r
245      * Determines whether a DocBlock can legally have a {@}source} tag\r
246      * @tutorial tags.inlinesource.pkg\r
247      * @var boolean\r
248      * @access private\r
249      */\r
250     var $_canSource = false;\r
251     \r
252     /**\r
253      * sets package to default\r
254      * @global string default package name\r
255      */\r
256     function parserDocBlock()\r
257     {\r
258         global $phpDocumentor_DefaultPackageName;\r
259         $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];\r
260         $this->category = $GLOBALS['phpDocumentor_DefaultCategoryName'];\r
261     }\r
262     \r
263     /**\r
264      * Sets the starting line number for the DocBlock\r
265      * @param integer\r
266      */\r
267     function setLineNumber($number)\r
268     {\r
269         $this->linenumber = $number;\r
270     }\r
271     \r
272     /**\r
273      * Retrieve starting line number\r
274      * @return integer\r
275      */\r
276     function getLineNumber()\r
277     {\r
278         return $this->linenumber;\r
279     }\r
280     \r
281     /**\r
282      * Sets the ending line number for the DocBlock\r
283      * @param integer\r
284      */\r
285     function setEndLineNumber($number)\r
286     {\r
287         $this->endlinenumber = $number;\r
288     }\r
289     \r
290     /**\r
291      * Retrieve ending line number\r
292      * @return integer\r
293      */\r
294     function getEndLineNumber()\r
295     {\r
296         return $this->endlinenumber;\r
297     }\r
298     \r
299     /**\r
300      * Parse out any html tags from doc comments, and make them into\r
301      * abstract structures\r
302      * @uses parserDescParser::parse()\r
303      */\r
304     function postProcess()\r
305     {\r
306         if ($this->sdesc)\r
307         {\r
308             $parser = new parserDescParser;\r
309             $parser->subscribe('*',$this);\r
310             if ($this->desc) $parser->parse($this->desc->value);\r
311             $parser->parse($this->sdesc->value,true);\r
312         }\r
313     }\r
314     \r
315     /**\r
316      * Tells the DocBlock it can have a @filesource tag\r
317      *\r
318      * Only page-level DocBlocks may have a @filesource tag\r
319      */\r
320     function canSource()\r
321     {\r
322         $this->_canSource = true;\r
323     }\r
324     \r
325     /**\r
326      * Tells the DocBlock it can't have a @filesource tag\r
327      *\r
328      * Only page-level DocBlocks may have a @filesource tag\r
329      */\r
330     function cantSource()\r
331     {\r
332         $this->_canSource = false;\r
333     }\r
334     \r
335     /**\r
336      * Indirectly called after parsing by {@link postProcess}\r
337      *\r
338      * @param integer either 1 for long desc or 2 for short desc\r
339      * @param array data organized into paragraphs.  Each entry is a {@link parserStringWithInlineTags}\r
340      * @uses $processed_desc sets to the array passed from {@link parserDescParser::parse()}\r
341      * @uses $processed_sdesc sets to the array passed from {@link parserDescParser::parse()}\r
342      * @access private\r
343      */\r
344     function HandleEvent($event,$data)\r
345     {\r
346         if ($event == 1)\r
347         $this->processed_desc = $data;\r
348         else\r
349         $this->processed_sdesc = $data;\r
350     }\r
351     \r
352     /**\r
353      * @param array\r
354      */\r
355     function updateModifiers($modifiers)\r
356     {\r
357         if (is_array($modifiers) && count($modifiers))\r
358         {\r
359             foreach ($modifiers as $modifier)\r
360             {\r
361                 switch ($modifier)\r
362                 {\r
363                     case 'private' :\r
364                     case 'public' :\r
365                     case 'protected' :\r
366                         unset($this->tags['access']);\r
367                         $x = new parserAccessTag($modifier);\r
368                         if ($x->isvalid)\r
369                         {\r
370                             $this->hasaccess = true;\r
371                             $this->tags['access'][] = $x;\r
372                         }\r
373                     break;\r
374                     case 'static' :\r
375                     case 'abstract' :\r
376                         unset($this->tags[$modifier]);\r
377                         $this->addKeyword($modifier, '');\r
378                     break;\r
379                 }\r
380             }\r
381         }\r
382     }\r
383     \r
384     /**\r
385      * Set the short description of the DocBlock\r
386      *\r
387      * Setting the short description is possible by passing in one of three\r
388      * possible parameters:\r
389      * <ul>\r
390      *  <li>another DocBlock's short description</li>\r
391      *  <li>another DocBlock, the short description will be extracted</li>\r
392      *  <li>a Zend Studio-compatible @desc tag</li>\r
393      * </ul>\r
394      * @param parserDesc|parserDocBlock|parserTag sets {@link $sdesc}\r
395      */\r
396     function setShortDesc($desc)\r
397     {\r
398         if (phpDocumentor_get_class($desc) == 'parsertag')\r
399         {\r
400             $this->sdesc = new parserDesc;\r
401             $this->processed_sdesc = $desc->value;\r
402             return;\r
403         }\r
404         if (phpDocumentor_get_class($desc) == 'parserdesc') {\r
405             $this->sdesc = $desc;\r
406         } else\r
407         {\r
408             $this->sdesc = $desc->sdesc;\r
409             $this->processed_sdesc = $desc->processed_sdesc;\r
410         }\r
411         \r
412         if ($this->sdesc && $this->sdesc->hasSource())\r
413         {\r
414             addWarning(PDERROR_SOURCE_TAG_IGNORED,$this->sdesc->getString());\r
415         }\r
416     }\r
417     \r
418     /**\r
419      * Passes to {@link parserStringWithInlineTags::setSource()}\r
420      *\r
421      * After passing, it calls {@link postProcess()} to set up the new\r
422      * source\r
423      * @param string|array tokenized highlight-ready source code\r
424      * @param false|string name of class if this is a method source\r
425      */\r
426     function setSource($source, $class = false)\r
427     {\r
428         if ($this->desc)\r
429         {\r
430             $this->desc->setSource($source, $class);\r
431             $this->postProcess();\r
432         }\r
433     }\r
434     \r
435     /**\r
436      * @param parserDesc|parserDocBlock sets {@link $desc}\r
437      */\r
438     function setDesc($desc)\r
439     {\r
440         if (phpDocumentor_get_class($desc) == 'parserdesc')\r
441         $this->desc = $desc;\r
442         else\r
443         {\r
444             $this->desc = $desc->desc;\r
445             $this->processed_desc = $desc->processed_desc;\r
446         }\r
447     }\r
448     \r
449     /**\r
450      * Wrapper for {@link parserDesc::hasInheritDoc()}\r
451      * @return boolean\r
452      */\r
453     function hasInheritDoc()\r
454     {\r
455         if (!$this->desc) return false;\r
456         return $this->desc->hasInheritDoc();\r
457     }\r
458     \r
459     /**\r
460      * Wrapper for {@link parserDesc::replaceInheritDoc()}\r
461      *\r
462      * Also replaces {@}inheritdoc} in the {@link $processed_desc}\r
463      * @param parserDesc\r
464      */\r
465     function replaceInheritDoc($desc)\r
466     {\r
467         if (!$this->desc) return false;\r
468         $this->desc->replaceInheritDoc($desc->desc);\r
469         $this->postProcess();\r
470     }\r
471     \r
472     /**\r
473      * @param Converter takes {@link $sdesc} and converts it to a string and returns it if present, otherwise returns ''\r
474      * @return string\r
475      */\r
476     function getSDesc(&$converter)\r
477     {\r
478         if ($this->sdesc && $this->processed_sdesc)\r
479         {\r
480             $result = '';\r
481             foreach($this->processed_sdesc as $desc)\r
482             {\r
483                 if (count($desc->value))\r
484                 $result .= $desc->Convert($converter);\r
485             }\r
486             return $result;\r
487         } else\r
488         {\r
489 //            var_dump($this->desc,$this->processed_desc);\r
490         }\r
491         return '';\r
492     }\r
493     \r
494     /**\r
495      * @param Converter takes {@link $desc} and converts it to a string and returns it if present, otherwise returns ''\r
496      * @return string\r
497      */\r
498     function getDesc(&$converter)\r
499     {\r
500         if ($this->desc && $this->processed_desc)\r
501         {\r
502             $result = '';\r
503             foreach($this->processed_desc as $desc)\r
504             {\r
505                 if (count($desc->value))\r
506                 $result .= $converter->EncloseParagraph($desc->Convert($converter));\r
507             }\r
508             return $result;\r
509         } else\r
510         {\r
511 //            var_dump($this->desc,$this->processed_desc);\r
512         }\r
513         return '';\r
514     }\r
515     \r
516     /**\r
517      * @param string $paramVar if empty, param is indexed in the order received and set using {@link changeParam()}\r
518      * @param parserStringWithInlineTags $value\r
519      */\r
520     function addParam($paramVar, $paramType, $value)\r
521     {\r
522         if (empty($paramVar))\r
523         $this->params[count($this->params)] = new parserParamTag($paramType,$value);\r
524         else\r
525         $this->params[$paramVar] = new parserParamTag($paramType,$value);\r
526     }\r
527 \r
528     function resetParams()\r
529     {\r
530         $this->params = array();\r
531     }\r
532     /**\r
533      * @param integer $index index of parameter in the {@link $params} array\r
534      * @param string $name name of the parameter to set in the $params array\r
535      * @param string|null $type type of the parameter\r
536      */\r
537     function changeParam($index, $name, $type)\r
538     {\r
539         if ($name === $index) {\r
540             return;\r
541         }\r
542         $this->params[$name] = $this->params[$index];\r
543         unset($this->params[$index]);\r
544     }\r
545     \r
546     /**\r
547      * replaces nameless parameters in the {@link $params} array with their names\r
548      * add @param tags for params in the function with no entry\r
549      * @param array $params Format: array(parameter key =>\r
550      *                      array(0 => parameter name[,1 => default value][,2 => type hint]),...)\r
551      */\r
552     function updateParams($params)\r
553     {\r
554         $countparams = array_values($params);\r
555         reset($params);\r
556         for($i=0;$i<count($countparams);$i++, next($params))\r
557         {\r
558             if (isset($this->params[$i]))\r
559             {\r
560                 $info = current($params);\r
561                 $type = isset($info[2]) ? $info[2] : null;\r
562                 $this->changeParam($i, key($params), $type);\r
563                 $params[key($params)] = false;\r
564             }\r
565         }\r
566         $blank = new parserStringWithInlineTags;\r
567         foreach ($params as $key => $info) {\r
568             if (!$info) {\r
569                 continue;\r
570             }\r
571             $type = isset($info[2]) ? $info[2] : null;\r
572             if (!isset($this->params[$info[0]])) {\r
573                 $this->addParam($info[0], $type, $blank);\r
574             }\r
575         }\r
576         reset($params);\r
577         \r
578         if (isset($this->tags))\r
579         unset($this->tags['param']);\r
580     }\r
581     \r
582     /**\r
583      * Used to insert DocBlock Template tags into a docblock\r
584      * @param parserTag tag\r
585      * @global array used to determine whether to add ignored tags, or not\r
586      */\r
587     function addTag($tag)\r
588     {\r
589         global $_phpDocumentor_setting;\r
590         if (phpDocumentor_setup::checkIgnoreTag($tag->keyword)) return;\r
591         $value = $tag->value;\r
592         if (is_array($value)) $value = $value[0];\r
593         if ($tag->keyword == 'uses')\r
594         {\r
595             $this->addUses($value, $tag->_description);\r
596         } else\r
597         {\r
598             $this->addKeyword($tag->keyword, $value);\r
599         }\r
600     }\r
601 \r
602     /**\r
603      * @param string $keyword tag name\r
604      * @param parserStringWithInlineTags $value the contents of the tag\r
605      * @global array used to determine whether to add the @internal tag or not\r
606      */\r
607     function addKeyword($keyword, $value)\r
608     {\r
609         global $_phpDocumentor_setting;\r
610         $keyword = trim($keyword);\r
611         if (phpDocumentor_setup::checkIgnoreTag($keyword)) return;\r
612         // don't add the tag at all if it was specified to ignore it with --ignore-tags\r
613         if ($keyword == 'package' || $keyword == 'subpackage' || $keyword == 'category') return $this->addPackage($keyword, $value);\r
614         if ($keyword == 'access') return $this->addAccess($value);\r
615         if ($keyword == 'link') return $this->addLink($value);\r
616         if ($keyword == 'see' || $keyword == 'tutorial') return $this->addSee($keyword,$value);\r
617         if ($keyword == 'uses') return $this->addUses($keyword, $value);\r
618         if ($keyword == 'name') return $this->addName($value);\r
619         if (!in_array($keyword,$GLOBALS['_phpDocumentor_tags_allowed']))\r
620         $this->addUnknownTag($keyword,$value);\r
621         else\r
622         {\r
623         if ($keyword == 'internal' && (!isset($_phpDocumentor_setting['parseprivate']) || $_phpDocumentor_setting['parseprivate'] == 'off')) return;\r
624             if (!isset($this->tags[$keyword])) {\r
625                 $this->tags[$keyword] = array();\r
626             }\r
627             $ptag = 'parserTag';\r
628             if (class_exists('parser'.$keyword.'tag'))\r
629                 $ptag = 'parser'.ucfirst($keyword).'Tag';\r
630             array_unshift($this->tags[$keyword], new $ptag($keyword, $value));\r
631         }\r
632     }\r
633     \r
634     /**\r
635      * adds an @example tag\r
636      * @param string contents of the tag\r
637      * @param string path to the file containing this tag\r
638      */\r
639     function addExample($value, $path)\r
640     {\r
641         $this->tags['example'][] = new parserExampleTag($value, $path);\r
642     }\r
643     \r
644     /**\r
645      * adds an unknown tag to the {@link $unknown_tags} array for use by custom converters\r
646      * @param string tag name\r
647      * @param string tag value\r
648      */\r
649     function addUnknownTag($keyword, $value)\r
650     {\r
651         addWarning(PDERROR_UNKNOWN_TAG,$keyword);\r
652         $this->unknown_tags[$keyword][] = new parserTag($keyword, $value);\r
653     }\r
654     \r
655     /**\r
656      * set the element's package to the passed values.  Used in {@link phpDocumentor_IntermediateParser} to align package of\r
657      * elements inside a class or procedural page to the package of the class/procedural page\r
658      * @param string\r
659      * @param string\r
660      * @param string\r
661      * @param string element name\r
662      * @param string element type (include, define, var, method, global, function, const)\r
663      */\r
664     function overridePackage($category, $package,$subpackage,$elname,$type)\r
665     {\r
666         if ($this->package != $GLOBALS['phpDocumentor_DefaultPackageName'])\r
667         {\r
668             addError(PDERROR_OVERRIDDEN_PACKAGE_TAGS,$elname,$type,$this->package);\r
669             $this->explicitpackage = false;\r
670         }\r
671         if (!empty($this->subpackage))\r
672         addError(PDERROR_OVERRIDDEN_SUBPACKAGE_TAGS,$type,$elname,$this->subpackage);\r
673         $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];\r
674         $this->subpackage = '';\r
675         $this->category = $category;\r
676         $this->addPackage('package',$package);\r
677         $this->addPackage('subpackage',$subpackage);\r
678     }\r
679     \r
680     /**\r
681      * Used if this docblock has a @package tag.\r
682      *\r
683      * phpDocumentor will guess package for DocBlocks that don't have\r
684      * a @package tag\r
685      * @uses $explicitpackage\r
686      */\r
687     function setExplicitPackage()\r
688     {\r
689         $this->explicitpackage = true;\r
690     }\r
691     \r
692     /**\r
693      * If the DocBlock has a @package tag, then this returns true\r
694      * @return boolean\r
695      */\r
696     function getExplicitPackage()\r
697     {\r
698         return $this->explicitpackage;\r
699     }\r
700     \r
701     /**\r
702      * Used if this docblock has a @category tag.\r
703      *\r
704      * phpDocumentor will guess category for DocBlocks that don't have\r
705      * a @category tag\r
706      * @uses $explicitcategory\r
707      */\r
708     function setExplicitCategory()\r
709     {\r
710         $this->explicitcategory = true;\r
711     }\r
712     \r
713     /**\r
714      * If the DocBlock has a @category tag, then this returns true\r
715      * @return boolean\r
716      */\r
717     function getExplicitCategory()\r
718     {\r
719         return $this->explicitcategory;\r
720     }\r
721     \r
722     /**\r
723      * @param string $keyword tag name (either package or subpackage)\r
724      * @param mixed $value either a string or a parserStringWithInlineTags.  Strips all inline tags and use the text as the package\r
725      */\r
726     function addPackage($keyword, $value)\r
727     {\r
728         if ($keyword == 'package')\r
729         {\r
730             if (!$this->explicitpackage)\r
731             {\r
732                 if (!is_string($value))\r
733                 $value = $value->getString();\r
734                 $rest = '';\r
735                 $value = explode(' ',$value);\r
736                 if (count($value) - 1)\r
737                 {\r
738                     $rest = $value;\r
739                     $value = trim($value[0]);\r
740                     unset($rest[0]);\r
741                     $rest = implode($rest,' ');\r
742                 } else\r
743                 {\r
744                     $value = explode("\t",$value[0]);\r
745                     if (count($value) - 1)\r
746                     {\r
747                         $rest = $value;\r
748                         $value = trim($value[0]);\r
749                         unset($rest[0]);\r
750                         $rest = implode($rest,"\t");\r
751                     } else $value = trim($value[0]);\r
752                 }\r
753                 $value = preg_replace('/[^\[\]0-9\-a-zA-Z_\x7f-\xff]/', '-', $value);\r
754                 $this->packagedescrip = $this->package = trim($value);\r
755                 if (!empty($rest)) $this->packagedescrip = $rest;\r
756             } else\r
757             {\r
758                 if (is_string($value))\r
759                 addError(PDERROR_MULTIPLE_PACKAGE_TAGS,$value);\r
760                 else\r
761                 addError(PDERROR_MULTIPLE_PACKAGE_TAGS,$value->getString());\r
762             }\r
763         } elseif ($keyword == 'subpackage')\r
764         {\r
765             if (empty($this->subpackage))\r
766             {\r
767                 if (!is_string($value))\r
768                 $value = $value->getString();\r
769                 $rest = '';\r
770                 $value = explode(' ',$value);\r
771                 if (count($value) - 1)\r
772                 {\r
773                     $rest = $value;\r
774                     $value = $value[0];\r
775                     unset($rest[0]);\r
776                     $rest = implode($rest,' ');\r
777                 } else\r
778                 {\r
779                     $value = explode("\t",$value[0]);\r
780                     if (count($value) - 1)\r
781                     {\r
782                         $rest = $value;\r
783                         $value = $value[0];\r
784                         unset($rest[0]);\r
785                         $rest = implode($rest,"\t");\r
786                     } else $value = $value[0];\r
787                 }\r
788                 if (!empty($value))\r
789                 {\r
790                     $value = preg_replace('/[^\[\]0-9\-a-zA-Z_\x7f-\xff]/', '-', $value);\r
791                 }\r
792                 $this->subpackage = trim($value);\r
793                 if (!empty($rest)) $this->subpackagedescrip = $rest;\r
794             } else\r
795             {\r
796                 if (is_string($value))\r
797                 addError(PDERROR_MULTIPLE_SUBPACKAGE_TAGS,$value);\r
798                 else\r
799                 addError(PDERROR_MULTIPLE_SUBPACKAGE_TAGS,$value->getString());\r
800             }\r
801         } elseif ($keyword == 'category')\r
802         {\r
803             if (!$this->explicitcategory)\r
804             {\r
805                 if (!is_string($value))\r
806                 $value = $value->getString();\r
807                 $value = preg_replace('/[^\[\]0-9\-a-zA-Z_\x7f-\xff]/', '-', $value);\r
808                 $this->category = $value;\r
809             } else\r
810             {\r
811                 if (is_string($value))\r
812                 addError(PDERROR_MULTIPLE_CATEGORY_TAGS,$value);\r
813                 else\r
814                 addError(PDERROR_MULTIPLE_CATEGORY_TAGS,$value->getString());\r
815             }\r
816         }\r
817     }\r
818     \r
819     /**\r
820      * Adds a @name tag to the tag list\r
821      * @param string new name of element\r
822      */\r
823     function addName($value)\r
824     {\r
825         if (is_object($value)) $value = $value->getString();\r
826         if (!$this->hasname)\r
827         {\r
828             $x = new parserNameTag('name',$value);\r
829             $this->hasname = true;\r
830             $this->tags['name'][] = $x;\r
831         } else\r
832         {\r
833             addError(PDERROR_MULTIPLE_NAME_TAGS,$value);\r
834         }\r
835     }\r
836     \r
837     /**\r
838      * @param string if empty, staticvar is indexed in the order received and set using {@link changeStatic()}\r
839      * @param string data type\r
840      * @param parserStringWithInlineTags\r
841      */\r
842     function addStaticVar($staticvar, $type, $descrip)\r
843     {\r
844         if (empty($staticvar))\r
845         $this->statics[] = new parserStaticvarTag($type,$descrip);\r
846         else\r
847         $this->statics[$staticvar] = new parserStaticvarTag($type,$descrip);\r
848     }\r
849     \r
850     /**\r
851      * adds a function declaration of @global to the {@link $funcglobals} array\r
852      * @param string global type\r
853      * @param string description of how the global is used in the function\r
854      */\r
855     function addFuncGlobal($type,$value)\r
856     {\r
857         $this->funcglobals[] = array($type,$value);\r
858     }\r
859     \r
860     /**\r
861      * @param integer $index index of parameter in the {@link $funcglobals} array\r
862      * @param string $name name of the parameter to set in the $funcglobals array\r
863      */\r
864     function changeGlobal($index,$name)\r
865     {\r
866         $this->funcglobals[$name] = $this->funcglobals[$index];\r
867         unset($this->funcglobals[$index]);\r
868     }\r
869 \r
870     /**\r
871      * @param integer $index index of parameter in the {@link $statics} array\r
872      * @param string $name name of the parameter to set in the $statics array\r
873      */\r
874     function changeStatic($index,$name)\r
875     {\r
876         $this->statics[$name] = $this->statics[$index];\r
877         unset($this->statics[$index]);\r
878     }\r
879 \r
880     /**\r
881      * replaces nameless global variables in the {@link $funcglobals} array with their names\r
882      * @param array\r
883      */\r
884     function updateGlobals($funcs)\r
885     {\r
886         for($i=0;$i<count($funcs);$i++)\r
887         {\r
888             if (isset($this->funcglobals[$i]))\r
889             {\r
890                 $this->changeGlobal($i,$funcs[$i]);\r
891             }\r
892         }\r
893     }\r
894 \r
895     /**\r
896      * replaces nameless static variables in the {@link $statics} array with their names\r
897      * @param array\r
898      */\r
899     function updateStatics($funcs)\r
900     {\r
901         for($i=0;$i<count($funcs);$i++)\r
902         {\r
903             if (isset($this->statics[$i]))\r
904             {\r
905                 $this->changeStatic($i,$funcs[$i]);\r
906             }\r
907         }\r
908     }\r
909 \r
910     /**\r
911      * add an @access tag to the {@link tags} array\r
912      * @param string should be either public or private\r
913      */\r
914     function addAccess($value)\r
915     {\r
916         if (is_object($value)) $value = $value->getString();\r
917         $value = strtolower($value);\r
918         if (!$this->hasaccess)\r
919         {\r
920             $x = new parserAccessTag($value);\r
921             if ($x->isvalid)\r
922             {\r
923                 $this->hasaccess = true;\r
924                 $this->tags['access'][] = $x;\r
925             }\r
926         } else\r
927         {\r
928             if (is_string($value))\r
929             addError(PDERROR_MULTIPLE_ACCESS_TAGS,$value);\r
930             else\r
931             addError(PDERROR_MULTIPLE_ACCESS_TAGS,$value->getString());\r
932         }\r
933     }\r
934     \r
935     /**\r
936      * Adds a new @filesource tag to the DocBlock\r
937      * @tutorial tags.filesource.pkg\r
938      * @param string full path to the file\r
939      * @param array tokenized source code, ordered by line number\r
940      */\r
941     function addFileSource($path, $source)\r
942     {\r
943         if (isset($this->tags['filesource'])) return;\r
944         $this->tags['filesource'][] = new parserFileSourceTag($path, $source);\r
945     }\r
946     \r
947     /**\r
948      * creates a {@link parserLinkTag} and adds it to the {@link $tags} array\r
949      * @param string $link\r
950      */\r
951     function addLink($link)\r
952     {\r
953         if (phpDocumentor_setup::checkIgnoreTag('@link')) return;\r
954         $this->tags['link'][] = new parserLinkTag($link);\r
955     }\r
956     \r
957     /**\r
958      * creates a {@link parserLinkTag} and adds it to the {@link $tags} array\r
959      * @param string either see or uses\r
960      * @param string $value\r
961      */\r
962     function addSee($keyword,$value)\r
963     {\r
964         if (phpDocumentor_setup::checkIgnoreTag($keyword)) return;\r
965         $tag = 'parser'.ucfirst($keyword).'Tag';\r
966         $this->tags[$keyword][] = new $tag($value);\r
967     }\r
968     \r
969     /**\r
970      * creates a {@link parserReturnTag} and adds it to the {@link $tags} array\r
971      * @param string $returnType the one-word name of the return type (mixed should be used if more than one type)\r
972      * @param parserStringWithInlineTags $value\r
973      */\r
974     function addReturn($returnType, $value)\r
975     {\r
976         // only take the first one\r
977         if (!$this->return)\r
978         {\r
979             $this->return = new parserReturnTag($returnType, $value);\r
980         } else\r
981         {\r
982             addError(PDERROR_MULTIPLE_RETURN_TAGS,$returnType,$value->getString());\r
983         }\r
984     }\r
985     \r
986     /**\r
987      * creates a {@link parserVarTag} and adds it to the {@link $tags} array\r
988      * @param string $varType the one-word name of the variable type (mixed should be used if more than one type)\r
989      * @param parserStringWithInlineTags $value\r
990      */\r
991     function addVar($varType, $value)\r
992     {\r
993         // only take the first one\r
994         if (!$this->var)\r
995         {\r
996             $this->var = new parserVarTag($varType, $value);\r
997         } else\r
998         {\r
999             addError(PDERROR_MULTIPLE_VAR_TAGS,$varType,$value->getString());\r
1000         }\r
1001     }\r
1002     \r
1003     /**\r
1004      * Adds a virtual @usedby tag to output\r
1005      * @param abstractLink link to the element that has a @uses tag\r
1006      * @param parserStringWithInlinetags description of how the elements uses\r
1007      *                                   this one\r
1008      * @access private\r
1009      */\r
1010     function addUsedBy($link, $descrip)\r
1011     {\r
1012         $this->tags['usedby'][] = new parserUsedByTag($link, $descrip);\r
1013     }\r
1014     \r
1015     /**\r
1016      * Add a @uses tag to the DocBlock\r
1017      * @param string @see-style text, used for {@link Converter::getLink()}\r
1018      * @param parserStringWithInlineTags description of how the used element is\r
1019      *                                   used\r
1020      * @tutorial tags.uses.pkg\r
1021      */\r
1022     function addUses($seeel, $description)\r
1023     {\r
1024         $this->tags['uses'][] = new parserUsesTag($seeel, $description);\r
1025         usort($this->tags['uses'], array($this, '_sortUses'));\r
1026     }\r
1027 \r
1028     /**\r
1029      * Adds a @property(-read or -write) or @method magic tag to the DocBlock\r
1030      */\r
1031     function addProperty( $tagName, $propertyName, $propertyType, $value )\r
1032     {\r
1033         if ( empty( $propertyName ) )\r
1034         {\r
1035             addWarning ( PDERROR_MISSING_PROPERTY_TAG_NAME, $tagName, $tagName, $propertyType, $value->getString() );\r
1036         }\r
1037         else\r
1038         {\r
1039             switch ( $tagName )\r
1040             {\r
1041             case 'property':\r
1042                 $this->properties[ $propertyName ] = new parserPropertyTag( $propertyType, $value );\r
1043                 break;\r
1044             case 'property-read':\r
1045                 $this->properties[ $propertyName ] = new parserPropertyReadTag( $propertyType, $value );\r
1046                 break;\r
1047             case 'property-write':\r
1048                 $this->properties[ $propertyName ] = new parserPropertyWriteTag( $propertyType, $value );\r
1049                 break;\r
1050             case 'method':\r
1051                 $this->properties[ $propertyName ] = new parserMethodTag( $propertyType, $value );\r
1052                 break;\r
1053             }\r
1054         }\r
1055     }\r
1056 \r
1057     /**\r
1058      * Custom sorting function for sorting @uses tags\r
1059      *\r
1060      * @param parserTag $a\r
1061      * @param parserTag $b\r
1062      * @access private\r
1063      * @return int\r
1064      */\r
1065     function _sortUses($a, $b)\r
1066     {\r
1067         return strnatcasecmp($a->getString(), $b->getString());\r
1068     }\r
1069 \r
1070     /**\r
1071      * @param string\r
1072      * @return mixed false if no keyword, unconverted value if one keyword, array of unconverted values if more than one keyword\r
1073      */\r
1074     function getKeyword($keyword)\r
1075     {\r
1076         if ($keyword == 'filesource' && !$this->_canSource) return false;\r
1077         if (isset($this->tags[$keyword]))\r
1078         {\r
1079             if (count($this->tags[$keyword]) == 1)\r
1080             {\r
1081                 return $this->tags[$keyword][0];\r
1082             } else return $this->tags[$keyword];\r
1083         } else return false;\r
1084     }\r
1085     \r
1086     /**\r
1087      * @return array Format: array('var' => tag name, 'data' => unconverted tag value)\r
1088      */\r
1089     function listParams()\r
1090     {\r
1091         if (isset($this->params))\r
1092         {\r
1093             $ret = array();\r
1094             foreach($this->params as $key => $val)\r
1095             {\r
1096                 $ret[] = array("var" => ucfirst($key),"data" => $val);\r
1097             }\r
1098             return $ret;\r
1099         } else {\r
1100             return array();\r
1101         }\r
1102     }\r
1103 \r
1104     /**\r
1105      * @return array Format: array('var' => tag name, 'data' => unconverted tag value)\r
1106      */\r
1107     function listProperties()\r
1108     {\r
1109         $ret = array();\r
1110         if (isset($this->properties))\r
1111         {\r
1112             foreach($this->properties as $key => $val)\r
1113             {\r
1114                 $ret[] = array("var" => ucfirst($key),"data" => $val);\r
1115             }\r
1116         }\r
1117         return $ret;\r
1118     }\r
1119     \r
1120     /**\r
1121      * @param Converter\r
1122      */\r
1123     function listTags()\r
1124     {\r
1125         $tags = array();\r
1126         foreach($this->tags as $keyword => $vals)\r
1127         {\r
1128             if ($keyword == 'filesource' && !$this->_canSource) continue;\r
1129             foreach($vals as $val)\r
1130             {\r
1131                 $tags[] = $val;\r
1132             }\r
1133         }\r
1134         usort($tags,'tagsort');\r
1135         return $tags;\r
1136     }\r
1137     \r
1138     /** @return string always 'docblock' */\r
1139     function getType()\r
1140     {\r
1141         return 'docblock';\r
1142     }\r
1143 }\r
1144 \r
1145 /**\r
1146  * Determines the arbitrary tag rank value for a given tag\r
1147  * @access private\r
1148  */\r
1149 function getTagRanking($tag)\r
1150 {\r
1151     switch(phpDocumentor_get_class($tag))\r
1152     {\r
1153         case 'parserreturntag' :\r
1154             $o = 0;\r
1155             break;\r
1156         case 'parservartag' :\r
1157             $o = 1;\r
1158             break;\r
1159         case 'parsertutorialtag' :\r
1160             $o = 2;\r
1161             break;\r
1162         case 'parserstaticvartag' :\r
1163             $o = 3;\r
1164             break;\r
1165         case 'parserseetag' :\r
1166             $o = 10;\r
1167             break;\r
1168         case 'parserlinktag' :\r
1169             $o = 11;\r
1170             break;\r
1171         case 'parsertag' :\r
1172             switch ($tag->keyword)\r
1173             {\r
1174                 case 'author' :\r
1175                     $o = 4;\r
1176                     break;\r
1177                 case 'version' :\r
1178                     $o = 5;\r
1179                     break;\r
1180                 case 'copyright' :\r
1181                     $o = 6;\r
1182                     break;\r
1183                 case 'deprecated' :\r
1184                 case 'deprec' :\r
1185                     $o = 12;\r
1186                     break;\r
1187                 case 'todo' :\r
1188                 case 'TODO' :\r
1189                     $o = 13;\r
1190                     break;\r
1191                 case 'abstract' :\r
1192                     $o = 14;\r
1193                     break;\r
1194                 default :\r
1195                     $o = 15;\r
1196                     break;\r
1197             }\r
1198             break;\r
1199         case 'parseraccesstag' :\r
1200             $o = 18;\r
1201             break;\r
1202         case 'parsernametag' :\r
1203             $o = 19;\r
1204             break;\r
1205         default :\r
1206             $o = 20;\r
1207             break;\r
1208     }\r
1209     return $o;\r
1210 }\r
1211 \r
1212 /**\r
1213  * Utilizes the getTagRanking method to determine tag sort order of two given tags\r
1214  * @access private\r
1215  */\r
1216 function tagsort($a, $b)\r
1217 {\r
1218     $returnval = 0;\r
1219     $o = getTagRanking($a);\r
1220     $p = getTagRanking($b);\r
1221     if ($o == $p) return 0;\r
1222     if ($o < $p) return -1;\r
1223     if ($o > $p) return 1;\r
1224 }\r
1225 ?>\r