3 * All abstract representations of inline tags are in this file
\r
5 * phpDocumentor :: automatic documentation generator
\r
7 * PHP versions 4 and 5
\r
9 * Copyright (c) 2002-2006 Gregory Beaver
\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
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
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
28 * @package phpDocumentor
\r
29 * @subpackage InlineTags
\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: InlineTags.inc,v 1.7 2007/04/19 20:20:57 ashnazg Exp $
\r
35 * @link http://www.phpdoc.org
\r
36 * @link http://pear.php.net/PhpDocumentor
\r
37 * @since separate file since 1.2
\r
40 * Use this element to represent an {@}inline tag} like {@}link}
\r
41 * @see parserStringWithInlineTags
\r
42 * @package phpDocumentor
\r
43 * @subpackage InlineTags
\r
44 * @author Greg Beaver <cellog@php.net>
\r
46 * @version $Revision: 1.7 $
\r
47 * @tutorial inlinetags.pkg
\r
49 class parserInlineTag extends parserBase
\r
54 * Type is used by many functions to skip the hassle of
\r
57 * if phpDocumentor_get_class($blah) == 'parserBlah'
\r
59 * always "inlinetag"
\r
62 var $type = 'inlinetag';
\r
64 * the name of the inline tag (like link)
\r
67 var $inlinetype = '';
\r
70 * @param string $type tag type (example: link)
\r
71 * @param string $value tag value (example: what to link to)
\r
73 function parserInlineTag($type,$value)
\r
75 $this->inlinetype = $type;
\r
76 $this->value = trim($value);
\r
80 * @return integer length of the tag
\r
85 if (is_array($this->value))
\r
87 return array_reduce(create_function('$a,$b', 'return $a + strlen($b);')) +
\r
88 count($this->value);
\r
90 return strlen($this->value);
\r
94 * @return string always '', used by {@link Parser::handleDocBlock()} to
\r
95 * calculate the short description of a DocBlock
\r
96 * @see parserStringWithInlineTags::getString()
\r
97 * @see parserStringWithInlineTags::trimmedStrlen()
\r
99 function getString()
\r
106 * represents inline links
\r
107 * @tutorial tags.inlinelink.pkg
\r
108 * @package phpDocumentor
\r
109 * @subpackage InlineTags
\r
110 * @author Greg Beaver <cellog@php.net>
\r
113 class parserLinkInlineTag extends parserInlineTag
\r
116 * text to display in the link, can be different from the link for standard
\r
117 * links like websites
\r
120 var $linktext = '';
\r
123 * @param string $link stored in $value, see {@link parserBase::$value}
\r
124 * @param string $text see {@link $linktext}
\r
126 function parserLinkInlineTag($link,$text)
\r
128 if (strpos($link, ','))
\r
130 $link = explode(',',$link);
\r
131 parserInlineTag::parserInlineTag('link','');
\r
132 $this->value = $link;
\r
135 parserInlineTag::parserInlineTag('link',$link);
\r
137 $this->linktext = trim($text);
\r
141 * @param Converter converter used to change the abstract link into text for
\r
143 * @return false|string returns the converted link or false if not converted
\r
146 function Convert(&$c)
\r
148 if (is_array($this->value))
\r
151 foreach($this->value as $text)
\r
157 $ret .= $this->ConvertPart($c, trim($text));
\r
162 return $this->ConvertPart($c, $this->value);
\r
166 function ConvertPart(&$c, $value)
\r
168 if (strpos($value,'://') || (strpos($value,'mailto:') === 0))
\r
170 if (strpos($value, ' '))
\r
172 $value = explode(' ', $value);
\r
173 $link = array_shift($value);
\r
174 $text = join(' ', $value);
\r
178 $text = $this->linktext;
\r
180 return $c->returnLink($link,htmlspecialchars($text));
\r
183 $savevalue = $value;
\r
185 if (strpos(trim($value),' '))
\r
187 $v = preg_split('/\s/',trim($value));
\r
188 if (in_array(strtolower($v[0]), array('object', 'function')))
\r
190 if (!isset($v[1]) ||
\r
191 (isset($v[1]) && strlen($v[1])
\r
192 && !in_array($v[1]{0}, array('$','&'))
\r
193 && $v[1] != '###commanana####'))
\r
197 $v[0] = $vsave . ' ' . $v[0];
\r
200 $value = $c->getLink($v[0]);
\r
202 $descrip = join($v,' ');
\r
203 $descrip = str_replace('###commanana####', ',', $descrip);
\r
206 $value = $c->getLink($value);
\r
208 if (is_string($value))
\r
211 if (strpos($value,'://'))
\r
214 return $c->returnLink($value,
\r
215 $descrip ? $descrip : str_replace('PHP_MANUAL#','',$value));
\r
219 if (!$descrip) $descrip = $c->type_adjust($savevalue);
\r
220 if (is_object($value)) return $c->returnSee($value, $descrip);
\r
221 /* // getLink parsed a comma-delimited list of linked thingies, add the commas back in
\r
222 if (is_array($value))
\r
225 foreach($value as $i => $bub)
\r
227 if (!empty($a)) $a .= ', ';
\r
228 if (is_string($value[$i]))
\r
231 if (strpos($value[$i],'://'))
\r
234 $a .= $c->returnLink($value[$i],str_replace('PHP_MANUAL#','',$vals[$i]));
\r
238 if (is_object($value[$i])) $a .= $c->returnSee($value[$i],$descrip[$i]);
\r
248 * Represents inline links to external tutorial documentation
\r
249 * @tutorial tags.inlinetutorial.pkg
\r
250 * @package phpDocumentor
\r
251 * @subpackage InlineTags
\r
253 class parserTutorialInlineTag extends parserLinkInlineTag
\r
256 * @param string $link stored in $value, see {@link parserBase::$value}
\r
257 * @param string $text see {@link $linktext}
\r
259 function parserTutorialInlineTag($link,$text)
\r
261 parserInlineTag::parserInlineTag('tutorial',$link);
\r
262 $this->linktext = trim($text);
\r
266 * @param Converter converter used to change the abstract link into text for display
\r
267 * @return mixed returns the converted link or false if not converted successfully
\r
269 function Convert(&$c)
\r
272 if (strpos($this->value,',') === false)
\r
274 if (strpos(trim($this->value),' '))
\r
276 $v = split(' ',trim($this->value));
\r
277 $value = $c->getTutorialLink($v[0]);
\r
279 $descrip = join($v,' ');
\r
280 } else $value = $c->getTutorialLink($this->value);
\r
283 $vals = split(',',$this->value);
\r
284 $descrip = array();
\r
285 foreach($vals as $val)
\r
288 if (strpos($val,' '))
\r
290 $v = split(' ',$val);
\r
291 $value[] = $c->getTutorialLink($v[0]);
\r
293 $descrip[] = join($v,' ');
\r
296 $value[] = $c->getTutorialLink($val);
\r
297 $descrip[] = false;
\r
301 if (is_string($value))
\r
305 if (is_object($value)) return $c->returnSee($value,$descrip);
\r
306 // getLink parsed a comma-delimited list of linked thingies, add the commas back in
\r
307 if (is_array($value))
\r
310 foreach($value as $i => $bub)
\r
312 if (!empty($a)) $a .= ', ';
\r
313 if (is_string($value[$i]))
\r
317 if (is_object($value[$i])) $a .= $c->returnSee($value[$i],$descrip[$i]);
\r
326 * represents inline source tag, used for function/method source
\r
327 * @tutorial tags.inlinesource.pkg
\r
328 * @package phpDocumentor
\r
329 * @subpackage InlineTags
\r
331 class parserSourceInlineTag extends parserInlineTag
\r
337 var $inlinetype = 'source';
\r
339 * First line of source code to display
\r
345 * Last line to display
\r
346 * @var '*'|integer If '*' then the whole source will be used, otherwise
\r
347 * the {@link $start} to $end line numbers will be displayed
\r
351 * tokenized source organized by line numbers for php 4.3.0+, the old
\r
352 * {@}source} tag used a string
\r
353 * @var string|array
\r
355 var $source = false;
\r
356 /**#@+ @access private */
\r
357 /** @var string|false */
\r
361 * @param string format "start [end]" where start and end are line numbers
\r
362 * with the end line number optional
\r
364 function parserSourceInlineTag($value)
\r
366 parserInlineTag::parserInlineTag('source','');
\r
367 preg_match('/^([0-9]+)\W([0-9]*)$/',trim($value), $match);
\r
368 if (!count($match))
\r
370 preg_match('/^([0-9]+)$/',trim($value),$match);
\r
373 $this->start = (int) $match[1];
\r
377 $this->start = (int) $match[1];
\r
378 $this->end = (int) $match[2];
\r
383 * only used to determine blank lines. {@}source} will not be blank,
\r
391 function getString()
\r
393 return '{@source}';
\r
397 * @param string|array source code
\r
398 * @param boolean in php 4.3.0, if this is a method this will be true
\r
399 * @param string class name if this is a method
\r
401 function setSource($source, $class = false)
\r
403 if (is_array($source))
\r
405 $this->_class = $class;
\r
406 $this->source = $source;
\r
409 $source = strstr($source,'function');
\r
410 $pos = strrpos($source,'}');
\r
411 $this->source = substr($source,0,$pos + 1);
\r
416 * @uses stringConvert() in PHP 4.2.3-, this method is used to convert
\r
417 * @uses arrayConvert() in PHP 4.3.0+, this method is used to convert
\r
420 function Convert(&$c)
\r
422 if (is_string($this->source)) return $this->stringConvert($c);
\r
423 return $this->arrayConvert($c);
\r
428 * @uses phpDocumentor_HighlightParser Parses the tokenized source
\r
430 function arrayConvert(&$c)
\r
432 $source = $this->source;
\r
433 if ($this->end != '*')
\r
435 $source = array_slice($this->source,0,$this->end + $this->start - 1);
\r
437 $start = $this->start - 1;
\r
438 if ($start < 0) $start = 0;
\r
439 return $c->ProgramExample($source, true, true, $this->_class, $start);
\r
444 * @uses Converter::unmangle() remove the extraneous stuff from
\r
445 * {@link highlight_string()}
\r
446 * @deprecated in favor of PHP 4.3.0+ {@link arrayConvert()}
\r
448 function stringConvert(&$c)
\r
450 $source = highlight_string('<?php '.$this->source.' ?>', true);
\r
451 $source = '<code>'.substr($source,strlen('<code><font color="#000000">
\r
452 <font color="#0000CC"><?php </font>') - 1);
\r
453 $source = str_replace('} </font><font color="#0000CC">?></font>','}</font></code>',$source);
\r
454 if ($this->start || ($this->end != '*'))
\r
456 $source = explode('<br />',$source);
\r
457 $start = $this->start;
\r
458 if ($this->end != '*')
\r
460 $source = array_slice($source,$start - 1,$this->end - $start + 1);
\r
463 $source = array_slice($source,$start - 1);
\r
465 $source = implode($source,'<br />');
\r
466 if ($start > 0) $source = "<code>$source";
\r
467 if ($this->end != '*') $source = "$source</code>";
\r
469 $source = $c->unmangle($source,$this->source);
\r
475 * Represents the example inline tag, used to display an example file
\r
476 * inside a docblock or tutorial
\r
477 * @tutorial tags.inlineexample.pkg
\r
478 * @package phpDocumentor
\r
479 * @subpackage InlineTags
\r
481 class parserExampleInlineTag extends parserSourceInlineTag
\r
484 * @param string format "filepath[ start [end]]" where start and end are line numbers
\r
485 * with the end line number optional
\r
486 * @param string full path to the current file, used to check relative
\r
487 * directory locations
\r
488 * @param boolean if true, then this is in a tutorial
\r
490 function parserExampleInlineTag($value, $current_path, $isTutorial = false)
\r
492 global $_phpDocumentor_setting;
\r
493 parserInlineTag::parserInlineTag('example','');
\r
495 $tagValue = trim($value);
\r
496 $path = $isAbsPath = $pathOnly = $fileName = $fileExt = $original_path = $title = FALSE;
\r
499 // make sure the format is stuff.ext startline[ endline]
\r
500 if (!preg_match('`(.*)\.(\w*)\s(.*)`', $tagValue, $match))
\r
502 // or format is stuff.ext
\r
503 if (!preg_match('`(.*)\.(\w*)\s*$`', $tagValue, $match))
\r
505 // Murphy: Some funny path was given
\r
506 $original_path = $tagValue; // used for error output
\r
507 break; // try-block
\r
510 if (strlen($match[1]) === 0)
\r
512 // Murphy: Some funny path was given
\r
513 $original_path = $tagValue; // used for error output
\r
514 break; // try-block
\r
516 $fileExt = $match[2];
\r
517 if (isset($match[3]))
\r
519 $lines = explode(' ', trim($match[3]));
\r
520 $this->start = (int) $lines[0];
\r
521 if (isset($lines[1])) {
\r
522 $this->end = (int) $lines[1];
\r
525 $pathTmp = str_replace('\\', '/', $match[1]); // Replace windows '\' the path.
\r
527 // Is there a path and a file or is it just a file?
\r
528 if (strpos($pathTmp,'/') === false)
\r
532 $fileName = $pathTmp .'.'. $fileExt;
\r
535 $splitPos = strrpos($pathTmp,'/'); // split the path on the last directory, find the filename
\r
536 $pathOnly = substr($match[1], 0, $splitPos+1);
\r
537 $fileName = substr($match[1], $splitPos+1) .'.'. $fileExt;
\r
538 // Is the path absolute? (i.e. does it start like an absolute path?)
\r
539 if (('/' === $pathTmp[0]) || preg_match('`^\w*:`i', $pathTmp))
\r
540 { // works for both windows 'C:' and URLs like 'http://'
\r
541 $isAbsPath = true; // Yes
\r
545 $original_path = $pathOnly . $fileName;
\r
547 // Now look for the file starting with abs. path.
\r
550 $tmp = realpath($original_path); // remove any weirdities like /../file.ext
\r
551 if ($tmp && is_file($tmp))
\r
555 // Alway break if abs. path was detected; even if file was not found.
\r
556 break; // try-block
\r
559 // Search for the example file some standard places
\r
560 // 1) Look if the ini-var examplesdir is set and look there ...
\r
561 if (isset($_phpDocumentor_setting['examplesdir']))
\r
563 $tmp = realpath($_phpDocumentor_setting['examplesdir'] . PATH_DELIMITER . $original_path);
\r
564 if ($tmp && is_file($tmp))
\r
566 $path = $tmp; // Yo! found it :)
\r
567 break; // try-block
\r
571 // 2) Then try to look for an 'example/'-dir below the *currently* parsed file ...
\r
572 if (!empty($current_path))
\r
574 $tmp = realpath(dirname($current_path) . PATH_DELIMITER . 'examples' . PATH_DELIMITER . $fileName);
\r
575 if ($tmp && is_file($tmp))
\r
577 $path = $tmp; // Yo! found it :)
\r
578 break; // try-block
\r
582 // 3) Then try to look for the example file below the subdir PHPDOCUMENTOR_BASE/examples/ ...
\r
583 if (is_dir(PHPDOCUMENTOR_BASE . PATH_DELIMITER . 'examples'))
\r
585 $tmp = realpath(PHPDOCUMENTOR_BASE . PATH_DELIMITER . 'examples' . PATH_DELIMITER . $original_path);
\r
586 if ($tmp && is_file($tmp))
\r
588 $path = $tmp; // Yo! found it :)
\r
589 break; // try-block
\r
593 $tmp = realpath(PHPDOCUMENTOR_BASE . PATH_DELIMITER . $original_path);
\r
594 if ($tmp && is_file($tmp))
\r
596 $path = $tmp; // Yo! found it :)
\r
597 break; // try-block
\r
599 // If we reach this point, nothing was found and $path is false.
\r
604 addWarning(PDERROR_EXAMPLE_NOT_FOUND, $original_path);
\r
605 $this->path = false;
\r
608 $f = @fopen($path,'r');
\r
611 $example = fread($f,filesize($path));
\r
612 if (tokenizer_ext && !$isTutorial)
\r
614 $obj = new phpDocumentorTWordParser;
\r
615 $obj->setup($example);
\r
616 $this->setSource($obj->getFileSource());
\r
620 $this->setSource($example);
\r
627 * @param string|array source code
\r
628 * @param boolean in php 4.3.0, if this is a method this will be true
\r
629 * @param string class name if this is a method
\r
631 function setSource($source, $class = false)
\r
633 $this->_class = $class;
\r
634 $this->source = $source;
\r
639 * @uses phpDocumentor_HighlightParser Parses the tokenized source
\r
641 function arrayConvert(&$c)
\r
643 $source = $this->source;
\r
644 if ($this->end != '*')
\r
646 $source = array_slice($this->source,0,$this->end + $this->start - 1);
\r
648 $start = $this->start - 1;
\r
649 if ($start < 0) $start = 0;
\r
650 return $c->exampleProgramExample($source, true, true, $this->_class, $start);
\r
654 * Return the source for the example file, enclosed in
\r
655 * a <programlisting> tag to use in a tutorial
\r
658 function getProgramListing()
\r
660 $source = explode("\n", $this->source);
\r
661 $start = $this->start;
\r
662 if ($this->end != '*')
\r
664 $source = array_slice($source,$start - 1,$this->end - $start + 1);
\r
667 $source = array_slice($source,$start - 1);
\r
669 $source = join("\n", $source);
\r
671 "<programlisting role=\"php\">
\r
674 "\n]]>\n</programlisting>";
\r
679 * Represents the inheritdoc inline tag, used by classes/methods/vars to inherit
\r
680 * documentation from the parent class if possible
\r
681 * @tutorial tags.inlineinheritdoc.pkg
\r
682 * @package phpDocumentor
\r
683 * @subpackage InlineTags
\r
685 class parserInheritdocInlineTag extends parserInlineTag
\r
688 * always 'inheritdoc'
\r
691 var $inlinetype = 'inheritdoc';
\r
694 * Does nothing, overrides parent constructor
\r
696 function parserInheritdocInlineTag()
\r
702 addWarning(PDERROR_INHERITDOC_DONT_WORK_HERE);
\r
708 * Represents the inline {@}id} tag for tutorials
\r
709 * @tutorial tags.inlineid.pkg
\r
710 * @package phpDocumentor
\r
711 * @subpackage InlineTags
\r
713 class parserIdInlineTag extends parserInlineTag
\r
719 var $inlinetype = 'id';
\r
721 * package of the {@}id}
\r
724 var $package = 'default';
\r
726 * category of the {@}id}
\r
729 var $category = 'default';
\r
731 * subpackage of the {@}id}
\r
734 var $subpackage = '';
\r
736 * full name of the tutorial
\r
741 * section/subsection name
\r
747 * @param string package name
\r
748 * @param string subpackage name
\r
749 * @param string tutorial name
\r
750 * @param string section/subsection name
\r
751 * @param string category name
\r
753 function parserIdInlineTag($category,$package,$subpackage,$tutorial,$id = false)
\r
755 $this->package = $package;
\r
756 $this->subpackage = $subpackage;
\r
757 $this->tutorial = $tutorial;
\r
759 $this->category = $category;
\r
764 * @uses Converter::getTutorialId() retrieve converter-specific ID
\r
766 function Convert(&$c)
\r
768 if (!$this->id) return '';
\r
769 return $c->getTutorialId($this->package,$this->subpackage,$this->tutorial,$this->id,$this->category);
\r
774 * Represents {@}toc} for table of contents generation in tutorials
\r
775 * @tutorial tags.inlinetoc.pkg
\r
776 * @package phpDocumentor
\r
777 * @subpackage InlineTags
\r
779 class parserTocInlineTag extends parserInlineTag
\r
785 var $inlinetype = 'toc';
\r
787 * @var array format:
\r
789 * array(array('tagname' => section,
\r
790 * 'link' => returnsee link,
\r
791 * 'id' => anchor name,
\r
792 * 'title' => from title tag),...)
\r
798 * full path to tutorial, used in conversion
\r
802 var $_path = false;
\r
804 function parserTocInlineTag()
\r
806 parent::parserInlineTag('toc','');
\r
810 * @param array format:
\r
812 * array(array('tag' => {@link parserXMLDocBookTag},
\r
813 * 'id' => {@link parserIdInlineTag},
\r
814 * 'title' => {@link parserXMLDocBookTag title}),...)
\r
817 function setTOC($toc)
\r
825 function setPath($path)
\r
827 $this->_path = $path;
\r
831 * @uses Converter::formatTutorialTOC() passes an array of format:
\r
835 * 'tagname' => string name of tag,
\r
836 * 'link' => {@link tutorialLink} to the tutorial,
\r
837 * 'id' => converter specific tutorial ID from {@link Converter::getTutorialId()}
\r
838 * 'title' => title of the tutorial)
\r
841 * and returns the results as the table of contents
\r
842 * @uses Converter::getTutorialId() retrieve the tutorial ID for
\r
845 function Convert(&$c)
\r
848 if (isset($this->toc) && is_array($this->toc)) {
\r
849 foreach($this->toc as $i => $toc)
\r
851 if (isset($toc['title']))
\r
852 $toc['tag']->setTitle($toc['title']);
\r
854 $toc['tag']->setTitle(new parserStringWithInlineTags);
\r
855 $newtoc[$i]['tagname'] = $toc['tag']->name;
\r
856 $l = new tutorialLink;
\r
857 if (!isset($toc['title'])) $title = 'section '.$toc['id']->id;
\r
859 $title = $toc['title']->Convert($c);
\r
860 $l->addLink($toc['id']->id,$this->_path,basename($this->_path),$toc['id']->package, $toc['id']->subpackage, strip_tags($title));
\r
861 $newtoc[$i]['link'] = $c->returnSee($l);
\r
862 $newtoc[$i]['id'] = $c->getTutorialId($toc['id']->package, $toc['id']->subpackage, basename($this->_path), $toc['id']->id, $toc['id']->category);
\r
863 $newtoc[$i]['title'] = $title;
\r
866 return $c->formatTutorialTOC($newtoc);
\r