Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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