PageRenderTime 104ms CodeModel.GetById 61ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/inc/app/siteinvoice/lib/PEAR/PEAR/PackageFile/v1.php

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