PageRenderTime 169ms CodeModel.GetById 75ms app.highlight 61ms RepoModel.GetById 19ms app.codeStats 1ms

/manager/pear/PEAR/PackageFile/v1.php

http://punchcms.googlecode.com/
PHP | 1600 lines | 1154 code | 145 blank | 301 comment | 147 complexity | 0768d80af0867b3d0546a39b49a9b33d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * PEAR_PackageFile_v1, package.xml version 1.0
   4 *
   5 * PHP versions 4 and 5
   6 *
   7 * LICENSE: This source file is subject to version 3.0 of the PHP license
   8 * that is available through the world-wide-web at the following URI:
   9 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  10 * the PHP License and are unable to obtain it through the web, please
  11 * send a note to license@php.net so we can mail you a copy immediately.
  12 *
  13 * @category   pear
  14 * @package    PEAR
  15 * @author     Greg Beaver <cellog@php.net>
  16 * @copyright  1997-2006 The PHP Group
  17 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18 * @version    CVS: $Id: v1.php,v 1.69 2006/03/02 18:14:13 cellog Exp $
  19 * @link       http://pear.php.net/package/PEAR
  20 * @since      File available since Release 1.4.0a1
  21 */
  22/**
  23 * For error handling
  24 */
  25require_once 'PEAR/ErrorStack.php';
  26
  27/**
  28 * Error code if parsing is attempted with no xml extension
  29 */
  30define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
  31
  32/**
  33 * Error code if creating the xml parser resource fails
  34 */
  35define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
  36
  37/**
  38 * Error code used for all sax xml parsing errors
  39 */
  40define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
  41
  42/**
  43 * Error code used when there is no name
  44 */
  45define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
  46
  47/**
  48 * Error code when a package name is not valid
  49 */
  50define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
  51
  52/**
  53 * Error code used when no summary is parsed
  54 */
  55define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
  56
  57/**
  58 * Error code for summaries that are more than 1 line
  59 */
  60define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
  61
  62/**
  63 * Error code used when no description is present
  64 */
  65define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
  66
  67/**
  68 * Error code used when no license is present
  69 */
  70define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
  71
  72/**
  73 * Error code used when a <version> version number is not present
  74 */
  75define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
  76
  77/**
  78 * Error code used when a <version> version number is invalid
  79 */
  80define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
  81
  82/**
  83 * Error code when release state is missing
  84 */
  85define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
  86
  87/**
  88 * Error code when release state is invalid
  89 */
  90define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
  91
  92/**
  93 * Error code when release state is missing
  94 */
  95define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
  96
  97/**
  98 * Error code when release state is invalid
  99 */
 100define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
 101
 102/**
 103 * Error code when no release notes are found
 104 */
 105define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
 106
 107/**
 108 * Error code when no maintainers are found
 109 */
 110define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
 111
 112/**
 113 * Error code when a maintainer has no handle
 114 */
 115define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
 116
 117/**
 118 * Error code when a maintainer has no handle
 119 */
 120define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
 121
 122/**
 123 * Error code when a maintainer has no name
 124 */
 125define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
 126
 127/**
 128 * Error code when a maintainer has no email
 129 */
 130define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
 131
 132/**
 133 * Error code when a maintainer has no handle
 134 */
 135define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
 136
 137/**
 138 * Error code when a dependency is not a PHP dependency, but has no name
 139 */
 140define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
 141
 142/**
 143 * Error code when a dependency has no type (pkg, php, etc.)
 144 */
 145define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
 146
 147/**
 148 * Error code when a dependency has no relation (lt, ge, has, etc.)
 149 */
 150define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
 151
 152/**
 153 * Error code when a dependency is not a 'has' relation, but has no version
 154 */
 155define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
 156
 157/**
 158 * Error code when a dependency has an invalid relation
 159 */
 160define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
 161
 162/**
 163 * Error code when a dependency has an invalid type
 164 */
 165define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
 166
 167/**
 168 * Error code when a dependency has an invalid optional option
 169 */
 170define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31);
 171
 172/**
 173 * Error code when a dependency is a pkg dependency, and has an invalid package name
 174 */
 175define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32);
 176
 177/**
 178 * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel
 179 */
 180define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
 181
 182/**
 183 * Error code when rel="has" and version attribute is present.
 184 */
 185define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
 186
 187/**
 188 * Error code when type="php" and dependency name is present
 189 */
 190define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
 191
 192/**
 193 * Error code when a configure option has no name
 194 */
 195define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
 196
 197/**
 198 * Error code when a configure option has no name
 199 */
 200define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
 201
 202/**
 203 * Error code when a file in the filelist has an invalid role
 204 */
 205define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
 206
 207/**
 208 * Error code when a file in the filelist has no role
 209 */
 210define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
 211
 212/**
 213 * Error code when analyzing a php source file that has parse errors
 214 */
 215define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40);
 216
 217/**
 218 * Error code when analyzing a php source file reveals a source element
 219 * without a package name prefix
 220 */
 221define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
 222
 223/**
 224 * Error code when an unknown channel is specified
 225 */
 226define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
 227
 228/**
 229 * Error code when no files are found in the filelist
 230 */
 231define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
 232
 233/**
 234 * Error code when a file is not valid php according to _analyzeSourceCode()
 235 */
 236define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
 237
 238/**
 239 * Error code when the channel validator returns an error or warning
 240 */
 241define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
 242
 243/**
 244 * Error code when a php5 package is packaged in php4 (analysis doesn't work)
 245 */
 246define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
 247
 248/**
 249 * Error code when a file is listed in package.xml but does not exist
 250 */
 251define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
 252
 253/**
 254 * Error code when a <dep type="php" rel="not"... is encountered (use rel="ne")
 255 */
 256define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48);
 257
 258/**
 259 * Error code when a package.xml contains non-ISO-8859-1 characters
 260 */
 261define('PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS', 49);
 262
 263/**
 264 * Error code when a dependency is not a 'has' relation, but has no version
 265 */
 266define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50);
 267
 268/**
 269 * Error code when a package has no lead developer
 270 */
 271define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51);
 272
 273/**
 274 * Error code when a filename begins with "."
 275 */
 276define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52);
 277/**
 278 * package.xml encapsulator
 279 * @category   pear
 280 * @package    PEAR
 281 * @author     Greg Beaver <cellog@php.net>
 282 * @copyright  1997-2006 The PHP Group
 283 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 284 * @version    Release: 1.4.10
 285 * @link       http://pear.php.net/package/PEAR
 286 * @since      Class available since Release 1.4.0a1
 287 */
 288class PEAR_PackageFile_v1
 289{
 290    /**
 291     * @access private
 292     * @var PEAR_ErrorStack
 293     * @access private
 294     */
 295    var $_stack;
 296
 297    /**
 298     * A registry object, used to access the package name validation regex for non-standard channels
 299     * @var PEAR_Registry
 300     * @access private
 301     */
 302    var $_registry;
 303
 304    /**
 305     * An object that contains a log method that matches PEAR_Common::log's signature
 306     * @var object
 307     * @access private
 308     */
 309    var $_logger;
 310
 311    /**
 312     * Parsed package information
 313     * @var array
 314     * @access private
 315     */
 316    var $_packageInfo;
 317
 318    /**
 319     * path to package.xml
 320     * @var string
 321     * @access private
 322     */
 323    var $_packageFile;
 324
 325    /**
 326     * path to package .tgz or false if this is a local/extracted package.xml
 327     * @var string
 328     * @access private
 329     */
 330    var $_archiveFile;
 331
 332    /**
 333     * @var int
 334     * @access private
 335     */
 336    var $_isValid = 0;
 337
 338    /**
 339     * Determines whether this packagefile was initialized only with partial package info
 340     *
 341     * If this package file was constructed via parsing REST, it will only contain
 342     *
 343     * - package name
 344     * - channel name
 345     * - dependencies 
 346     * @var boolean
 347     * @access private
 348     */
 349    var $_incomplete = true;
 350
 351    /**
 352     * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack
 353     * @param string Name of Error Stack class to use.
 354     */
 355    function PEAR_PackageFile_v1()
 356    {
 357        $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1');
 358        $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
 359        $this->_isValid = 0;
 360    }
 361
 362    function installBinary($installer)
 363    {
 364        return false;
 365    }
 366
 367    function isExtension($name)
 368    {
 369        return false;
 370    }
 371
 372    function setConfig(&$config)
 373    {
 374        $this->_config = &$config;
 375        $this->_registry = &$config->getRegistry();
 376    }
 377
 378    function setRequestedGroup()
 379    {
 380        // placeholder
 381    }
 382
 383    /**
 384     * For saving in the registry.
 385     *
 386     * Set the last version that was installed
 387     * @param string
 388     */
 389    function setLastInstalledVersion($version)
 390    {
 391        $this->_packageInfo['_lastversion'] = $version;
 392    }
 393
 394    /**
 395     * @return string|false
 396     */
 397    function getLastInstalledVersion()
 398    {
 399        if (isset($this->_packageInfo['_lastversion'])) {
 400            return $this->_packageInfo['_lastversion'];
 401        }
 402        return false;
 403    }
 404
 405    function getInstalledBinary()
 406    {
 407        return false;
 408    }
 409
 410    function listPostinstallScripts()
 411    {
 412        return false;
 413    }
 414
 415    function initPostinstallScripts()
 416    {
 417        return false;
 418    }
 419
 420    function setLogger(&$logger)
 421    {
 422        if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
 423            return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
 424        }
 425        $this->_logger = &$logger;
 426    }
 427
 428    function setPackagefile($file, $archive = false)
 429    {
 430        $this->_packageFile = $file;
 431        $this->_archiveFile = $archive ? $archive : $file;
 432    }
 433
 434    function getPackageFile()
 435    {
 436        return isset($this->_packageFile) ? $this->_packageFile : false;
 437    }
 438
 439    function getPackageType()
 440    {
 441        return 'php';
 442    }
 443
 444    function getArchiveFile()
 445    {
 446        return $this->_archiveFile;
 447    }
 448
 449    function packageInfo($field)
 450    {
 451        if (!is_string($field) || empty($field) ||
 452            !isset($this->_packageInfo[$field])) {
 453            return false;
 454        }
 455        return $this->_packageInfo[$field];
 456    }
 457
 458    function setDirtree($path)
 459    {
 460        $this->_packageInfo['dirtree'][$path] = true;
 461    }
 462
 463    function getDirtree()
 464    {
 465        if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
 466            return $this->_packageInfo['dirtree'];
 467        }
 468        return false;
 469    }
 470
 471    function resetDirtree()
 472    {
 473        unset($this->_packageInfo['dirtree']);
 474    }
 475
 476    function fromArray($pinfo)
 477    {
 478        $this->_incomplete = false;
 479        $this->_packageInfo = $pinfo;
 480    }
 481
 482    function isIncomplete()
 483    {
 484        return $this->_incomplete;
 485    }
 486
 487    function getChannel()
 488    {
 489        return 'pear.php.net';
 490    }
 491
 492    function getUri()
 493    {
 494        return false;
 495    }
 496
 497    function getTime()
 498    {
 499        return false;
 500    }
 501
 502    function getExtends()
 503    {
 504        if (isset($this->_packageInfo['extends'])) {
 505            return $this->_packageInfo['extends'];
 506        }
 507        return false;
 508    }
 509
 510    /**
 511     * @return array
 512     */
 513    function toArray()
 514    {
 515        if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
 516            return false;
 517        }
 518        return $this->getArray();
 519    }
 520
 521    function getArray()
 522    {
 523        return $this->_packageInfo;
 524    }
 525
 526    function getName()
 527    {
 528        return $this->getPackage();
 529    }
 530
 531    function getPackage()
 532    {
 533        if (isset($this->_packageInfo['package'])) {
 534            return $this->_packageInfo['package'];
 535        }
 536        return false;
 537    }
 538
 539    /**
 540     * WARNING - don't use this unless you know what you are doing
 541     */
 542    function setRawPackage($package)
 543    {
 544        $this->_packageInfo['package'] = $package;
 545    }
 546
 547    function setPackage($package)
 548    {
 549        $this->_packageInfo['package'] = $package;
 550        $this->_isValid = false;
 551    }
 552
 553    function getVersion()
 554    {
 555        if (isset($this->_packageInfo['version'])) {
 556            return $this->_packageInfo['version'];
 557        }
 558        return false;
 559    }
 560
 561    function setVersion($version)
 562    {
 563        $this->_packageInfo['version'] = $version;
 564        $this->_isValid = false;
 565    }
 566
 567    function clearMaintainers()
 568    {
 569        unset($this->_packageInfo['maintainers']);
 570    }
 571
 572    function getMaintainers()
 573    {
 574        if (isset($this->_packageInfo['maintainers'])) {
 575            return $this->_packageInfo['maintainers'];
 576        }
 577        return false;
 578    }
 579
 580    /**
 581     * Adds a new maintainer - no checking of duplicates is performed, use
 582     * updatemaintainer for that purpose.
 583     */
 584    function addMaintainer($role, $handle, $name, $email)
 585    {
 586        $this->_packageInfo['maintainers'][] =
 587            array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name);
 588        $this->_isValid = false;
 589    }
 590
 591    function updateMaintainer($role, $handle, $name, $email)
 592    {
 593        $found = false;
 594        if (!isset($this->_packageInfo['maintainers']) ||
 595              !is_array($this->_packageInfo['maintainers'])) {
 596            return $this->addMaintainer($role, $handle, $name, $email);
 597        }
 598        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
 599            if ($maintainer['handle'] == $handle) {
 600                $found = $i;
 601                break;
 602            }
 603        }
 604        if ($found !== false) {
 605            unset($this->_packageInfo['maintainers'][$found]);
 606            $this->_packageInfo['maintainers'] =
 607                array_values($this->_packageInfo['maintainers']);
 608        }
 609        $this->addMaintainer($role, $handle, $name, $email);
 610    }
 611
 612    function deleteMaintainer($handle)
 613    {
 614        $found = false;
 615        foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
 616            if ($maintainer['handle'] == $handle) {
 617                $found = $i;
 618                break;
 619            }
 620        }
 621        if ($found !== false) {
 622            unset($this->_packageInfo['maintainers'][$found]);
 623            $this->_packageInfo['maintainers'] =
 624                array_values($this->_packageInfo['maintainers']);
 625            return true;
 626        }
 627        return false;
 628    }
 629
 630    function getState()
 631    {
 632        if (isset($this->_packageInfo['release_state'])) {
 633            return $this->_packageInfo['release_state'];
 634        }
 635        return false;
 636    }
 637
 638    function setRawState($state)
 639    {
 640        $this->_packageInfo['release_state'] = $state;
 641    }
 642
 643    function setState($state)
 644    {
 645        $this->_packageInfo['release_state'] = $state;
 646        $this->_isValid = false;
 647    }
 648
 649    function getDate()
 650    {
 651        if (isset($this->_packageInfo['release_date'])) {
 652            return $this->_packageInfo['release_date'];
 653        }
 654        return false;
 655    }
 656
 657    function setDate($date)
 658    {
 659        $this->_packageInfo['release_date'] = $date;
 660        $this->_isValid = false;
 661    }
 662
 663    function getLicense()
 664    {
 665        if (isset($this->_packageInfo['release_license'])) {
 666            return $this->_packageInfo['release_license'];
 667        }
 668        return false;
 669    }
 670
 671    function setLicense($date)
 672    {
 673        $this->_packageInfo['release_license'] = $date;
 674        $this->_isValid = false;
 675    }
 676
 677    function getSummary()
 678    {
 679        if (isset($this->_packageInfo['summary'])) {
 680            return $this->_packageInfo['summary'];
 681        }
 682        return false;
 683    }
 684
 685    function setSummary($summary)
 686    {
 687        $this->_packageInfo['summary'] = $summary;
 688        $this->_isValid = false;
 689    }
 690
 691    function getDescription()
 692    {
 693        if (isset($this->_packageInfo['description'])) {
 694            return $this->_packageInfo['description'];
 695        }
 696        return false;
 697    }
 698
 699    function setDescription($desc)
 700    {
 701        $this->_packageInfo['description'] = $desc;
 702        $this->_isValid = false;
 703    }
 704
 705    function getNotes()
 706    {
 707        if (isset($this->_packageInfo['release_notes'])) {
 708            return $this->_packageInfo['release_notes'];
 709        }
 710        return false;
 711    }
 712
 713    function setNotes($notes)
 714    {
 715        $this->_packageInfo['release_notes'] = $notes;
 716        $this->_isValid = false;
 717    }
 718
 719    function getDeps()
 720    {
 721        if (isset($this->_packageInfo['release_deps'])) {
 722            return $this->_packageInfo['release_deps'];
 723        }
 724        return false;
 725    }
 726
 727    /**
 728     * Reset dependencies prior to adding new ones
 729     */
 730    function clearDeps()
 731    {
 732        unset($this->_packageInfo['release_deps']);
 733    }
 734
 735    function addPhpDep($version, $rel)
 736    {
 737        $this->_isValid = false;
 738        $this->_packageInfo['release_deps'][] =
 739            array('type' => 'php',
 740                  'rel' => $rel,
 741                  'version' => $version);
 742    }
 743
 744    function addPackageDep($name, $version, $rel, $optional = 'no')
 745    {
 746        $this->_isValid = false;
 747        $dep =
 748            array('type' => 'pkg',
 749                  'name' => $name,
 750                  'rel' => $rel,
 751                  'optional' => $optional);
 752        if ($rel != 'has' && $rel != 'not') {
 753            $dep['version'] = $version;
 754        }
 755        $this->_packageInfo['release_deps'][] = $dep;
 756    }
 757
 758    function addExtensionDep($name, $version, $rel, $optional = 'no')
 759    {
 760        $this->_isValid = false;
 761        $this->_packageInfo['release_deps'][] =
 762            array('type' => 'ext',
 763                  'name' => $name,
 764                  'rel' => $rel,
 765                  'version' => $version,
 766                  'optional' => $optional);
 767    }
 768
 769    /**
 770     * WARNING - do not use this function directly unless you know what you're doing
 771     */
 772    function setDeps($deps)
 773    {
 774        $this->_packageInfo['release_deps'] = $deps;
 775    }
 776
 777    function hasDeps()
 778    {
 779        return isset($this->_packageInfo['release_deps']) &&
 780            count($this->_packageInfo['release_deps']);
 781    }
 782
 783    function getDependencyGroup($group)
 784    {
 785        return false;
 786    }
 787
 788    function isCompatible($pf)
 789    {
 790        return false;
 791    }
 792
 793    function isSubpackageOf($p)
 794    {
 795        return $p->isSubpackage($this);
 796    }
 797
 798    function isSubpackage($p)
 799    {
 800        return false;
 801    }
 802
 803    function dependsOn($package, $channel)
 804    {
 805        if (strtolower($channel) != 'pear.php.net') {
 806            return false;
 807        }
 808        if (!($deps = $this->getDeps())) {
 809            return false;
 810        }
 811        foreach ($deps as $dep) {
 812            if ($dep['type'] != 'pkg') {
 813                continue;
 814            }
 815            if (strtolower($dep['name']) == strtolower($package)) {
 816                return true;
 817            }
 818        }
 819        return false;
 820    }
 821
 822    function getConfigureOptions()
 823    {
 824        if (isset($this->_packageInfo['configure_options'])) {
 825            return $this->_packageInfo['configure_options'];
 826        }
 827        return false;
 828    }
 829
 830    function hasConfigureOptions()
 831    {
 832        return isset($this->_packageInfo['configure_options']) &&
 833            count($this->_packageInfo['configure_options']);
 834    }
 835
 836    function addConfigureOption($name, $prompt, $default = false)
 837    {
 838        $o = array('name' => $name, 'prompt' => $prompt);
 839        if ($default !== false) {
 840            $o['default'] = $default;
 841        }
 842        if (!isset($this->_packageInfo['configure_options'])) {
 843            $this->_packageInfo['configure_options'] = array();
 844        }
 845        $this->_packageInfo['configure_options'][] = $o;
 846    }
 847
 848    function clearConfigureOptions()
 849    {
 850        unset($this->_packageInfo['configure_options']);
 851    }
 852
 853    function getProvides()
 854    {
 855        if (isset($this->_packageInfo['provides'])) {
 856            return $this->_packageInfo['provides'];
 857        }
 858        return false;
 859    }
 860
 861    function addFile($dir, $file, $attrs)
 862    {
 863        $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
 864        if ($dir == '/' || $dir == '') {
 865            $dir = '';
 866        } else {
 867            $dir .= '/';
 868        }
 869        $file = $dir . $file;
 870        $file = preg_replace('![\\/]+!', '/', $file);
 871        $this->_packageInfo['filelist'][$file] = $attrs;
 872    }
 873
 874    function getInstallationFilelist()
 875    {
 876        return $this->getFilelist();
 877    }
 878
 879    function getFilelist()
 880    {
 881        if (isset($this->_packageInfo['filelist'])) {
 882            return $this->_packageInfo['filelist'];
 883        }
 884        return false;
 885    }
 886
 887    function setFileAttribute($file, $attr, $value)
 888    {
 889        $this->_packageInfo['filelist'][$file][$attr] = $value;
 890    }
 891
 892    function resetFilelist()
 893    {
 894        $this->_packageInfo['filelist'] = array();
 895    }
 896
 897    function setInstalledAs($file, $path)
 898    {
 899        if ($path) {
 900            return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
 901        }
 902        unset($this->_packageInfo['filelist'][$file]['installed_as']);
 903    }
 904
 905    function installedFile($file, $atts)
 906    {
 907        if (isset($this->_packageInfo['filelist'][$file])) {
 908            $this->_packageInfo['filelist'][$file] =
 909                array_merge($this->_packageInfo['filelist'][$file], $atts);
 910        } else {
 911            $this->_packageInfo['filelist'][$file] = $atts;
 912        }
 913    }
 914
 915    function getChangelog()
 916    {
 917        if (isset($this->_packageInfo['changelog'])) {
 918            return $this->_packageInfo['changelog'];
 919        }
 920        return false;
 921    }
 922
 923    function getPackagexmlVersion()
 924    {
 925        return '1.0';
 926    }
 927
 928    /**
 929     * Wrapper to {@link PEAR_ErrorStack::getErrors()}
 930     * @param boolean determines whether to purge the error stack after retrieving
 931     * @return array
 932     */
 933    function getValidationWarnings($purge = true)
 934    {
 935        return $this->_stack->getErrors($purge);
 936    }
 937
 938    // }}}
 939    /**
 940     * Validation error.  Also marks the object contents as invalid
 941     * @param error code
 942     * @param array error information
 943     * @access private
 944     */
 945    function _validateError($code, $params = array())
 946    {
 947        $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
 948        $this->_isValid = false;
 949    }
 950
 951    /**
 952     * Validation warning.  Does not mark the object contents invalid.
 953     * @param error code
 954     * @param array error information
 955     * @access private
 956     */
 957    function _validateWarning($code, $params = array())
 958    {
 959        $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
 960    }
 961
 962    /**
 963     * @param integer error code
 964     * @access protected
 965     */
 966    function _getErrorMessage()
 967    {
 968        return array(
 969                PEAR_PACKAGEFILE_ERROR_NO_NAME =>
 970                    'Missing Package Name',
 971                PEAR_PACKAGEFILE_ERROR_NO_SUMMARY =>
 972                    'No summary found',
 973                PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY =>
 974                    'Summary should be on one line',
 975                PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION =>
 976                    'Missing description',
 977                PEAR_PACKAGEFILE_ERROR_NO_LICENSE =>
 978                    'Missing license',
 979                PEAR_PACKAGEFILE_ERROR_NO_VERSION =>
 980                    'No release version found',
 981                PEAR_PACKAGEFILE_ERROR_NO_STATE =>
 982                    'No release state found',
 983                PEAR_PACKAGEFILE_ERROR_NO_DATE =>
 984                    'No release date found',
 985                PEAR_PACKAGEFILE_ERROR_NO_NOTES =>
 986                    'No release notes found',
 987                PEAR_PACKAGEFILE_ERROR_NO_LEAD =>
 988                    'Package must have at least one lead maintainer',
 989                PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS =>
 990                    'No maintainers found, at least one must be defined',
 991                PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE =>
 992                    'Maintainer %index% has no handle (user ID at channel server)',
 993                PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE =>
 994                    'Maintainer %index% has no role',
 995                PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME =>
 996                    'Maintainer %index% has no name',
 997                PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL =>
 998                    'Maintainer %index% has no email',
 999                PEAR_PACKAGEFILE_ERROR_NO_DEPNAME =>
1000                    'Dependency %index% is not a php dependency, and has no name',
1001                PEAR_PACKAGEFILE_ERROR_NO_DEPREL =>
1002                    'Dependency %index% has no relation (rel)',
1003                PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE =>
1004                    'Dependency %index% has no type',
1005                PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED =>
1006                    'PHP Dependency %index% has a name attribute of "%name%" which will be' .
1007                        ' ignored!',
1008                PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION =>
1009                    'Dependency %index% is not a rel="has" or rel="not" dependency, ' .
1010                        'and has no version',
1011                PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION =>
1012                    'Dependency %index% is a type="php" dependency, ' .
1013                        'and has no version',
1014                PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED =>
1015                    'Dependency %index% is a rel="%rel%" dependency, versioning is ignored',
1016                PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL =>
1017                    'Dependency %index% has invalid optional value "%opt%", should be yes or no',
1018                PEAR_PACKAGEFILE_PHP_NO_NOT =>
1019                    'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' .
1020                        ' to exclude specific versions',
1021                PEAR_PACKAGEFILE_ERROR_NO_CONFNAME =>
1022                    'Configure Option %index% has no name',
1023                PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT =>
1024                    'Configure Option %index% has no prompt',
1025                PEAR_PACKAGEFILE_ERROR_NO_FILES =>
1026                    'No files in <filelist> section of package.xml',
1027                PEAR_PACKAGEFILE_ERROR_NO_FILEROLE =>
1028                    'File "%file%" has no role, expecting one of "%roles%"',
1029                PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE =>
1030                    'File "%file%" has invalid role "%role%", expecting one of "%roles%"',
1031                PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME =>
1032                    'File "%file%" cannot start with ".", cannot package or install',
1033                PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE =>
1034                    'Parser error: invalid PHP found in file "%file%"',
1035                PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX =>
1036                    'in %file%: %type% "%name%" not prefixed with package name "%package%"',
1037                PEAR_PACKAGEFILE_ERROR_INVALID_FILE =>
1038                    'Parser error: invalid PHP file "%file%"',
1039                PEAR_PACKAGEFILE_ERROR_CHANNELVAL =>
1040                    'Channel validator error: field "%field%" - %reason%',
1041                PEAR_PACKAGEFILE_ERROR_PHP5 =>
1042                    'Error, PHP5 token encountered in %file%, analysis should be in PHP5',
1043                PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND =>
1044                    'File "%file%" in package.xml does not exist',
1045                PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS =>
1046                    'Package.xml contains non-ISO-8859-1 characters, and may not validate',
1047            );
1048    }
1049
1050    /**
1051     * Validate XML package definition file.
1052     *
1053     * @access public
1054     * @return boolean
1055     */
1056    function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
1057    {
1058        if (($this->_isValid & $state) == $state) {
1059            return true;
1060        }
1061        $this->_isValid = true;
1062        $info = $this->_packageInfo;
1063        if (empty($info['package'])) {
1064            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
1065            $this->_packageName = $pn = 'unknown';
1066        } else {
1067            $this->_packageName = $pn = $info['package'];
1068        }
1069
1070        if (empty($info['summary'])) {
1071            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
1072        } elseif (strpos(trim($info['summary']), "\n") !== false) {
1073            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY,
1074                array('summary' => $info['summary']));
1075        }
1076        if (empty($info['description'])) {
1077            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
1078        }
1079        if (empty($info['release_license'])) {
1080            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
1081        }
1082        if (empty($info['version'])) {
1083            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
1084        }
1085        if (empty($info['release_state'])) {
1086            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
1087        }
1088        if (empty($info['release_date'])) {
1089            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
1090        }
1091        if (empty($info['release_notes'])) {
1092            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
1093        }
1094        if (empty($info['maintainers'])) {
1095            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
1096        } else {
1097            $haslead = false;
1098            $i = 1;
1099            foreach ($info['maintainers'] as $m) {
1100                if (empty($m['handle'])) {
1101                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE,
1102                        array('index' => $i));
1103                }
1104                if (empty($m['role'])) {
1105                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE,
1106                        array('index' => $i, 'roles' => PEAR_Common::getUserRoles()));
1107                } elseif ($m['role'] == 'lead') {
1108                    $haslead = true;
1109                }
1110                if (empty($m['name'])) {
1111                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME,
1112                        array('index' => $i));
1113                }
1114                if (empty($m['email'])) {
1115                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL,
1116                        array('index' => $i));
1117                }
1118                $i++;
1119            }
1120            if (!$haslead) {
1121                $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
1122            }
1123        }
1124        if (!empty($info['release_deps'])) {
1125            $i = 1;
1126            foreach ($info['release_deps'] as $d) {
1127                if (!isset($d['type']) || empty($d['type'])) {
1128                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE,
1129                        array('index' => $i, 'types' => PEAR_Common::getDependencyTypes()));
1130                    continue;
1131                }
1132                if (!isset($d['rel']) || empty($d['rel'])) {
1133                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL,
1134                        array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations()));
1135                    continue;
1136                }
1137                if (!empty($d['optional'])) {
1138                    if (!in_array($d['optional'], array('yes', 'no'))) {
1139                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL,
1140                            array('index' => $i, 'opt' => $d['optional']));
1141                    }
1142                }
1143                if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) {
1144                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION,
1145                        array('index' => $i));
1146                } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) {
1147                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED,
1148                        array('index' => $i, 'rel' => $d['rel']));
1149                }
1150                if ($d['type'] == 'php' && !empty($d['name'])) {
1151                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED,
1152                        array('index' => $i, 'name' => $d['name']));
1153                } elseif ($d['type'] != 'php' && empty($d['name'])) {
1154                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME,
1155                        array('index' => $i));
1156                }
1157                if ($d['type'] == 'php' && empty($d['version'])) {
1158                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION,
1159                        array('index' => $i));
1160                }
1161                if (($d['rel'] == 'not') && ($d['type'] == 'php')) {
1162                    $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT,
1163                        array('index' => $i));
1164                }
1165                $i++;
1166            }
1167        }
1168        if (!empty($info['configure_options'])) {
1169            $i = 1;
1170            foreach ($info['configure_options'] as $c) {
1171                if (empty($c['name'])) {
1172                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME,
1173                        array('index' => $i));
1174                }
1175                if (empty($c['prompt'])) {
1176                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT,
1177                        array('index' => $i));
1178                }
1179                $i++;
1180            }
1181        }
1182        if (empty($info['filelist'])) {
1183            $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
1184            $errors[] = 'no files';
1185        } else {
1186            foreach ($info['filelist'] as $file => $fa) {
1187                if (empty($fa['role'])) {
1188                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE,
1189                        array('file' => $file, 'roles' => PEAR_Common::getFileRoles()));
1190                    continue;
1191                } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
1192                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE,
1193                        array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles()));
1194                }
1195                if ($file{0} == '.' && $file{1} == '/') {
1196                    $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
1197                        array('file' => $file));
1198                }
1199            }
1200        }
1201        if (isset($this->_registry) && $this->_isValid) {
1202            $chan = $this->_registry->getChannel('pear.php.net');
1203            if (PEAR::isError($chan)) {
1204                $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage());
1205                return $this->_isValid = 0;
1206            }
1207            $validator = $chan->getValidationObject();
1208            $validator->setPackageFile($this);
1209            $validator->validate($state);
1210            $failures = $validator->getFailures();
1211            foreach ($failures['errors'] as $error) {
1212                $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
1213            }
1214            foreach ($failures['warnings'] as $warning) {
1215                $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
1216            }
1217        }
1218        if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) {
1219            if ($this->_analyzePhpFiles()) {
1220                $this->_isValid = true;
1221            }
1222        }
1223        if ($this->_isValid) {
1224            return $this->_isValid = $state;
1225        }
1226        return $this->_isValid = 0;
1227    }
1228
1229    function _analyzePhpFiles()
1230    {
1231        if (!$this->_isValid) {
1232            return false;
1233        }
1234        if (!isset($this->_packageFile)) {
1235            return false;
1236        }
1237        $dir_prefix = dirname($this->_packageFile);
1238        $common = new PEAR_Common;
1239        $log = isset($this->_logger) ? array(&$this->_logger, 'log') :
1240            array($common, 'log');
1241        $info = $this->getFilelist();
1242        foreach ($info as $file => $fa) {
1243            if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
1244                $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND,
1245                    array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
1246                continue;
1247            }
1248            if ($fa['role'] == 'php' && $dir_prefix) {
1249                call_user_func_array($log, array(1, "Analyzing $file"));
1250                $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
1251                if ($srcinfo) {
1252                    $this->_buildProvidesArray($srcinfo);
1253                }
1254            }
1255        }
1256        $this->_packageName = $pn = $this->getPackage();
1257        $pnl = strlen($pn);
1258        if (isset($this->_packageInfo['provides'])) {
1259            foreach ((array) $this->_packageInfo['provides'] as $key => $what) {
1260                if (isset($what['explicit'])) {
1261                    // skip conformance checks if the provides entry is
1262                    // specified in the package.xml file
1263                    continue;
1264                }
1265                extract($what);
1266                if ($type == 'class') {
1267                    if (!strncasecmp($name, $pn, $pnl)) {
1268                        continue;
1269                    }
1270                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
1271                        array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
1272                } elseif ($type == 'function') {
1273                    if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
1274                        continue;
1275                    }
1276                    $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
1277                        array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
1278                }
1279            }
1280        }
1281        return $this->_isValid;
1282    }
1283
1284    /**
1285     * Get the default xml generator object
1286     *
1287     * @return PEAR_PackageFile_Generator_v1
1288     */
1289    function &getDefaultGenerator()
1290    {
1291        if (!class_exists('PEAR_PackageFile_Generator_v1')) {
1292            require_once 'PEAR/PackageFile/Generator/v1.php';
1293        }
1294        $a = &new PEAR_PackageFile_Generator_v1($this);
1295        return $a;
1296    }
1297
1298    /**
1299     * Get the contents of a file listed within the package.xml
1300     * @param string
1301     * @return string
1302     */
1303    function getFileContents($file)
1304    {
1305        if ($this->_archiveFile == $this->_packageFile) { // unpacked
1306            $dir = dirname($this->_packageFile);
1307            $file = $dir . DIRECTORY_SEPARATOR . $file;
1308            $file = str_replace(array('/', '\\'),
1309                array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
1310            if (file_exists($file) && is_readable($file)) {
1311                return implode('', file($file));
1312            }
1313        } else { // tgz
1314            if (!class_exists('Archive_Tar')) {
1315                require_once 'Archive/Tar.php';
1316            }
1317            $tar = &new Archive_Tar($this->_archiveFile);
1318            $tar->pushErrorHandling(PEAR_ERROR_RETURN);
1319            if ($file != 'package.xml' && $file != 'package2.xml') {
1320                $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
1321            }
1322            $file = $tar->extractInString($file);
1323            $tar->popErrorHandling();
1324            if (PEAR::isError($file)) {
1325                return PEAR::raiseError("Cannot locate file '$file' in archive");
1326            }
1327            return $file;
1328        }
1329    }
1330
1331    // {{{ analyzeSourceCode()
1332    /**
1333     * Analyze the source code of the given PHP file
1334     *
1335     * @param  string Filename of the PHP file
1336     * @return mixed
1337     * @access private
1338     */
1339    function _analyzeSourceCode($file)
1340    {
1341        if (!function_exists("token_get_all")) {
1342            return false;
1343        }
1344        if (!defined('T_DOC_COMMENT')) {
1345            define('T_DOC_COMMENT', T_COMMENT);
1346        }
1347        if (!defined('T_INTERFACE')) {
1348            define('T_INTERFACE', -1);
1349        }
1350        if (!defined('T_IMPLEMENTS')) {
1351            define('T_IMPLEMENTS', -1);
1352        }
1353        if (!$fp = @fopen($file, "r")) {
1354            return false;
1355        }
1356        if (function_exists('file_get_contents')) {
1357            fclose($fp);
1358            $contents = file_get_contents($file);
1359        } else {
1360            $contents = @fread($fp, filesize($file));
1361            fclose($fp);
1362        }
1363        $tokens = token_get_all($contents);
1364/*
1365        for ($i = 0; $i < sizeof($tokens); $i++) {
1366            @list($token, $data) = $tokens[$i];
1367            if (is_string($token)) {
1368                var_dump($token);
1369            } else {
1370                print token_name($token) . ' ';
1371                var_dump(rtrim($data));
1372            }
1373        }
1374*/
1375        $look_for = 0;
1376        $paren_level = 0;
1377        $bracket_level = 0;
1378        $brace_level = 0;
1379        $lastphpdoc = '';
1380        $current_class = '';
1381        $current_interface = '';
1382        $current_class_level = -1;
1383        $current_function = '';
1384        $current_function_level = -1;
1385        $declared_classes = array();
1386        $declared_interfaces = array();
1387        $declared_functions = array();
1388        $declared_methods = array();
1389        $used_classes = array();
1390        $used_functions = array();
1391        $extends = array();
1392        $implements = array();
1393        $nodeps = array();
1394        $inquote = false;
1395        $interface = false;
1396        for ($i = 0; $i < sizeof($tokens); $i++) {
1397            if (is_array($tokens[$i])) {
1398                list($token, $data) = $tokens[$i];
1399            } else {
1400                $token = $tokens[$i];
1401                $data = '';
1402            }
1403            if ($inquote) {
1404                if ($token != '"' && $token != T_END_HEREDOC) {
1405                    continue;
1406                } else {
1407                    $inquote = false;
1408                    continue;
1409                }
1410            }
1411            switch ($token) {
1412                case T_WHITESPACE :
1413                    continue;
1414                case ';':
1415                    if ($interface) {
1416                        $current_function = '';
1417                        $current_function_level = -1;
1418                    }
1419                    break;
1420                case '"':
1421                case T_START_HEREDOC:
1422                    $inquote = true;
1423                    break;
1424                case T_CURLY_OPEN:
1425                case T_DOLLAR_OPEN_CURLY_BRACES:
1426                case '{': $brace_level++; continue 2;
1427                case '}':
1428                    $brace_level--;
1429                    if ($current_class_level == $brace_level) {
1430                        $current_class = '';
1431                        $current_class_level = -1;
1432                    }
1433                    if ($current_function_level == $brace_level) {
1434                        $current_function = '';
1435                        $current_function_level = -1;
1436                    }
1437                    continue 2;
1438                case '[': $bracket_level++; continue 2;
1439                case ']': $bracket_level--; continue 2;
1440                case '(': $paren_level++;   continue 2;
1441                case ')': $paren_level--;   continue 2;
1442                case T_INTERFACE:
1443                    $interface = true;
1444                case T_CLASS:
1445                    if (($current_class_level != -1) || ($current_function_level != -1)) {
1446                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
1447                            array('file' => $file));
1448                        return false;
1449                    }
1450                case T_FUNCTION:
1451                case T_NEW:
1452                case T_EXTENDS:
1453                case T_IMPLEMENTS:
1454                    $look_for = $token;
1455                    continue 2;
1456                case T_STRING:
1457                    if (version_compare(zend_version(), '2.0', '<')) {
1458                        if (in_array(strtolower($data),
1459                            array('public', 'private', 'protected', 'abstract',
1460                                  'interface', 'implements', 'throw') 
1461                                 )) {
1462                            $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5,
1463                                array($file));
1464                        }
1465                    }
1466                    if ($look_for == T_CLASS) {
1467                        $current_class = $data;
1468                        $current_class_level = $brace_level;
1469                        $declared_classes[] = $current_class;
1470                    } elseif ($look_for == T_INTERFACE) {
1471                        $current_interface = $data;
1472                        $current_class_level = $brace_level;
1473                        $declared_interfaces[] = $current_interface;
1474                    } elseif ($look_for == T_IMPLEMENTS) {
1475                        $implements[$current_class] = $data;
1476                    } elseif ($look_for == T_EXTENDS) {
1477                        $extends[$current_class] = $data;
1478                    } elseif ($look_for == T_FUNCTION) {
1479                        if ($current_class) {
1480                            $current_function = "$current_class::$data";
1481                            $declared_methods[$current_class][] = $data;
1482                        } elseif ($current_interface) {
1483                            $current_function = "$current_interface::$data";
1484                            $declared_methods[$current_interface][] = $data;
1485                        } else {
1486                            $current_function = $data;
1487                            $declared_functions[] = $current_function;
1488                        }
1489                        $current_function_level = $brace_level;
1490                        $m = array();
1491                    } elseif ($look_for == T_NEW) {
1492                        $used_classes[$data] = true;
1493                    }
1494                    $look_for = 0;
1495                    continue 2;
1496                case T_VARIABLE:
1497                    $look_for = 0;
1498                    continue 2;
1499                case T_DOC_COMMENT:
1500                case T_COMMENT:
1501                    if (preg_match('!^/\*\*\s!', $data)) {
1502                        $lastphpdoc = $data;
1503                        if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
1504                            $nodeps = array_merge($nodeps, $m[1]);
1505                        }
1506                    }
1507                    continue 2;
1508                case T_DOUBLE_COLON:
1509                    if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
1510                        $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
1511                            array('file' => $file));
1512                        return false;
1513                    }
1514                    $class = $tokens[$i - 1][1];
1515                    if (strtolower($class) != 'parent') {
1516                        $used_classes[$class] = true;
1517                    }
1518                    continue 2;
1519            }
1520        }
1521        return array(
1522            "source_file" => $file,
1523            "declared_classes" => $declared_classes,
1524            "declared_interfaces" => $declared_interfaces,
1525            "declared_methods" => $declared_methods,
1526            "declared_functions" => $declared_functions,
1527            "used_classes" => array_diff(array_keys($used_classes), $nodeps),
1528            "inheritance" => $extends,
1529            "implements" => $implements,
1530            );
1531    }
1532
1533    /**
1534     * Build a "provides" array from data returned by
1535     * analyzeSourceCode().  The format of the built array is like
1536     * this:
1537     *
1538     *  array(
1539     *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
1540     *    ...
1541     *  )
1542     *
1543     *
1544     * @param array $srcinfo array with information about a source file
1545     * as returned by the analyzeSourceCode() method.
1546     *
1547     * @return void
1548     

Large files files are truncated, but you can click here to view the full file